diag: Add fixes for DCI

1) Fix an issue where after running a DCI app and exiting it,
 second app does not receive any DCI data. Issue was due to
 incorrect state of a flag used by SMD channel.

2) Add a mutex around shared data structures like cumulative masks.
Multiple clients may want to change DCI mask at the same time, so
mutex will prevent any corruption

3) Add support for health commands. The client request how many logs
were dropped and received.

Change-Id: Ica12b3c93aa4dda9b04aa13cd5a9f8dbc412148c
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
This commit is contained in:
Shalabh Jain 2012-10-23 12:51:30 -07:00 committed by Stephen Boyd
parent d133044a50
commit 1a9d9888b7
4 changed files with 83 additions and 33 deletions

View file

@ -35,6 +35,8 @@ unsigned int dci_max_reg = 100;
unsigned int dci_max_clients = 10;
unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
struct mutex dci_log_mask_mutex;
struct mutex dci_event_mask_mutex;
#define DCI_CHK_CAPACITY(entry, new_data_len) \
((entry->data_len + new_data_len > entry->total_capacity) ? 1 : 0) \
@ -91,14 +93,15 @@ static void diag_smd_dci_send_req(int proc_num)
read_bytes += 5 + dci_pkt_len;
buf += 5 + dci_pkt_len; /* advance to next DCI pkt */
}
driver->in_busy_dci = 1;
/* wake up all sleeping DCI clients which have some data */
for (i = 0; i < MAX_DCI_CLIENTS; i++)
if (driver->dci_client_tbl[i].client &&
driver->dci_client_tbl[i].data_len)
driver->dci_client_tbl[i].data_len) {
driver->in_busy_dci = 1;
diag_update_sleeping_process(
driver->dci_client_tbl[i].client->tgid,
DCI_DATA_TYPE);
}
}
}
@ -224,6 +227,8 @@ void extract_dci_events(unsigned char *buf)
dropped_events++;
return;
}
driver->dci_client_tbl[i].
received_events++;
*(int *)(entry->dci_data+
entry->data_len) = DCI_EVENT_TYPE;
memcpy(entry->dci_data+
@ -281,6 +286,7 @@ void extract_dci_log(unsigned char *buf)
dropped_logs++;
return;
}
driver->dci_client_tbl[i].received_logs++;
*(int *)(entry->dci_data+entry->data_len) =
DCI_LOG_TYPE;
memcpy(entry->dci_data+entry->data_len+4, buf+4,
@ -378,14 +384,6 @@ int diag_register_dci_transaction(int uid)
}
}
mutex_lock(&driver->dci_mutex);
if (new_dci_client)
driver->num_dci_client++;
if (driver->num_dci_client > MAX_DCI_CLIENTS) {
pr_info("diag: Max DCI Client limit reached\n");
driver->num_dci_client--;
mutex_unlock(&driver->dci_mutex);
return ret;
}
/* Make an entry in kernel DCI table */
driver->dci_tag++;
for (i = 0; i < dci_max_reg; i++) {
@ -483,7 +481,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
temp += 4;
head_log_mask_ptr = driver->dci_client_tbl[i].dci_log_mask;
pr_info("diag: head of dci log mask %p\n", head_log_mask_ptr);
pr_debug("diag: head of dci log mask %p\n", head_log_mask_ptr);
count = 0; /* iterator for extracting log codes */
while (count < num_codes) {
log_code = *(uint16_t *)temp;
@ -500,11 +498,11 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
while (log_mask_ptr) {
if (*log_mask_ptr == equip_id) {
found = 1;
pr_info("diag: find equip id = %x at %p\n",
pr_debug("diag: find equip id = %x at %p\n",
equip_id, log_mask_ptr);
break;
} else {
pr_info("diag: did not find equip id = %x at %p\n",
pr_debug("diag: did not find equip id = %x at %p\n",
equip_id, log_mask_ptr);
log_mask_ptr += 514;
}
@ -583,9 +581,11 @@ void update_dci_cumulative_event_mask(int client_index)
uint8_t *update_ptr = dci_cumulative_event_mask;
uint8_t *event_mask_ptr;
mutex_lock(&dci_event_mask_mutex);
event_mask_ptr = driver->dci_client_tbl[client_index].dci_event_mask;
for (i = 0; i < DCI_EVENT_MASK_SIZE; i++)
*(update_ptr+i) |= *(event_mask_ptr+i);
mutex_unlock(&dci_event_mask_mutex);
}
void diag_send_dci_event_mask(smd_channel_t *ch)
@ -631,6 +631,7 @@ void update_dci_cumulative_log_mask(int client_index)
uint8_t *log_mask_ptr =
driver->dci_client_tbl[client_index].dci_log_mask;
mutex_lock(&dci_log_mask_mutex);
*update_ptr = 0; /* add first equip id */
/* skip the first equip id */
update_ptr++; log_mask_ptr++;
@ -644,6 +645,7 @@ void update_dci_cumulative_log_mask(int client_index)
update_ptr++;
log_mask_ptr++;
}
mutex_unlock(&dci_log_mask_mutex);
}
void diag_send_dci_log_mask(smd_channel_t *ch)
@ -743,6 +745,8 @@ int diag_dci_init(void)
driver->num_dci_client = 0;
driver->in_busy_dci = 0;
mutex_init(&driver->dci_mutex);
mutex_init(&dci_log_mask_mutex);
mutex_init(&dci_event_mask_mutex);
if (driver->buf_in_dci == NULL) {
driver->buf_in_dci = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
if (driver->buf_in_dci == NULL)

View file

@ -53,6 +53,17 @@ struct diag_dci_client_tbl {
int total_capacity;
int dropped_logs;
int dropped_events;
int received_logs;
int received_events;
};
/* This is used for DCI health stats */
struct diag_dci_health_stats {
int dropped_logs;
int dropped_events;
int received_logs;
int received_events;
int reset_status;
};
enum {

View file

@ -241,17 +241,23 @@ static int diagchar_close(struct inode *inode, struct file *file)
int i = 0;
struct diagchar_priv *diagpriv_data = file->private_data;
pr_debug("diag: process exit %s\n", current->comm);
if (!(file->private_data)) {
pr_alert("diag: Invalid file pointer");
return -ENOMEM;
}
/* clean up any DCI registrations for this client
/* clean up any DCI registrations, if this is a DCI client
* This will specially help in case of ungraceful exit of any DCI client
* This call will remove any pending registrations of such client
*/
diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].client &&
driver->dci_client_tbl[i].client->tgid ==
current->tgid) {
diagchar_ioctl(NULL, DIAG_IOCTL_DCI_DEINIT, 0);
break;
}
}
/* If the exiting process is the socket process */
if (driver->socket_process &&
(driver->socket_process->tgid == current->tgid)) {
@ -372,7 +378,9 @@ long diagchar_ioctl(struct file *filp,
int success = -1;
void *temp_buf;
uint16_t support_list = 0;
struct diag_dci_client_tbl *notify_params;
struct diag_dci_client_tbl *params =
kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
struct diag_dci_health_stats stats;
int status;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
@ -446,8 +454,12 @@ long diagchar_ioctl(struct file *filp,
return DIAG_DCI_NO_REG;
if (driver->num_dci_client >= MAX_DCI_CLIENTS)
return DIAG_DCI_NO_REG;
notify_params = (struct diag_dci_client_tbl *) ioarg;
if (copy_from_user(params, (void *)ioarg,
sizeof(struct diag_dci_client_tbl)))
return -EFAULT;
mutex_lock(&driver->dci_mutex);
if (!(driver->num_dci_client))
driver->in_busy_dci = 0;
driver->num_dci_client++;
pr_debug("diag: id = %d\n", driver->dci_client_id);
driver->dci_client_id++;
@ -455,9 +467,9 @@ long diagchar_ioctl(struct file *filp,
if (driver->dci_client_tbl[i].client == NULL) {
driver->dci_client_tbl[i].client = current;
driver->dci_client_tbl[i].list =
notify_params->list;
params->list;
driver->dci_client_tbl[i].signal_type =
notify_params->signal_type;
params->signal_type;
create_dci_log_mask_tbl(driver->
dci_client_tbl[i].dci_log_mask);
create_dci_event_mask_tbl(driver->
@ -469,6 +481,8 @@ long diagchar_ioctl(struct file *filp,
IN_BUF_SIZE;
driver->dci_client_tbl[i].dropped_logs = 0;
driver->dci_client_tbl[i].dropped_events = 0;
driver->dci_client_tbl[i].received_logs = 0;
driver->dci_client_tbl[i].received_events = 0;
break;
}
}
@ -478,32 +492,52 @@ long diagchar_ioctl(struct file *filp,
success = -1;
/* Delete this process from DCI table */
mutex_lock(&driver->dci_mutex);
for (i = 0; i < dci_max_reg; i++) {
if (driver->req_tracking_tbl[i].pid == current->tgid) {
pr_debug("diag: delete %d\n", current->tgid);
for (i = 0; i < dci_max_reg; i++)
if (driver->req_tracking_tbl[i].pid == current->tgid)
driver->req_tracking_tbl[i].pid = 0;
success = i;
}
}
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
if (driver->dci_client_tbl[i].client == current) {
if (driver->dci_client_tbl[i].client &&
driver->dci_client_tbl[i].client->tgid ==
current->tgid) {
driver->dci_client_tbl[i].client = NULL;
success = i;
break;
}
}
/* if any registrations were deleted successfully OR a valid
client_id was sent in DEINIT call , then its DCI client */
if (success >= 0 || ioarg)
if (success >= 0)
driver->num_dci_client--;
driver->num_dci_client--;
mutex_unlock(&driver->dci_mutex);
pr_debug("diag: complete deleting registrations\n");
return success;
} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
if (driver->ch_dci)
support_list = support_list | DIAG_CON_MPSS;
*(uint16_t *)ioarg = support_list;
return DIAG_DCI_NO_ERROR;
} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
if (copy_from_user(&stats, (void *)ioarg,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
params = &(driver->dci_client_tbl[i]);
if (params->client &&
params->client->tgid == current->tgid) {
stats.dropped_logs = params->dropped_logs;
stats.dropped_events = params->dropped_events;
stats.received_logs = params->received_logs;
stats.received_events = params->received_events;
if (stats.reset_status) {
params->dropped_logs = 0;
params->dropped_events = 0;
params->received_logs = 0;
params->received_events = 0;
}
break;
}
}
if (copy_to_user((void *)ioarg, &stats,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
return DIAG_DCI_NO_ERROR;
} else if (iocmd == DIAG_IOCTL_LSM_DEINIT) {
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)

View file

@ -42,6 +42,7 @@
#define DIAG_IOCTL_DCI_SUPPORT 22
#define DIAG_IOCTL_DCI_REG 23
#define DIAG_IOCTL_DCI_STREAM_INIT 24
#define DIAG_IOCTL_DCI_HEALTH_STATS 25
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062