Loading drivers/char/diag/diag_dci.c +27 −23 Original line number Diff line number Diff line Loading @@ -190,6 +190,12 @@ static void dci_add_buffer_to_list(struct diag_dci_client_tbl *client, mutex_lock(&client->write_buf_mutex); list_add_tail(&buf->buf_track, &client->list_write_buf); /* * In the case of DCI, there can be multiple packets in one read. To * calculate the wakeup source reference count, we must account for each * packet in a single read. */ diag_ws_on_read(DIAG_WS_DCI, buf->data_len); mutex_lock(&buf->data_mutex); buf->in_busy = 1; buf->in_list = 1; Loading Loading @@ -470,7 +476,6 @@ end: /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); diag_dci_try_deactivate_wakeup_source(); return 0; } Loading @@ -491,7 +496,7 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, * process DCI data */ if (driver->num_dci_client == 0) { diag_dci_try_deactivate_wakeup_source(); diag_ws_reset(DIAG_WS_DCI); return 0; } Loading @@ -511,7 +516,7 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, if ((dci_pkt_len + 5) > (recd_bytes - read_bytes)) { pr_err("diag: Invalid length in %s, len: %d, dci_pkt_len: %d", __func__, recd_bytes, dci_pkt_len); diag_dci_try_deactivate_wakeup_source(); diag_ws_release(); return 0; } /* Loading @@ -520,8 +525,10 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, */ err = diag_process_single_dci_pkt(buf + 4, dci_pkt_len, smd_info->peripheral, DCI_LOCAL_PROC); if (err) if (err) { diag_ws_release(); break; } read_bytes += 5 + dci_pkt_len; buf += 5 + dci_pkt_len; /* advance to next DCI pkt */ } Loading @@ -529,7 +536,6 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); diag_dci_try_deactivate_wakeup_source(); return 0; } Loading Loading @@ -723,6 +729,7 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) return; } diag_ws_on_read(DIAG_WS_DCI, len); header = (struct diag_ctrl_dci_status *)temp; temp += sizeof(struct diag_ctrl_dci_status); read_len += sizeof(struct diag_ctrl_dci_status); Loading @@ -731,7 +738,7 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) if (read_len > len) { pr_err("diag: Invalid length len: %d in %s\n", len, __func__); return; goto err; } switch (*(uint8_t *)temp) { Loading @@ -747,7 +754,7 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) default: pr_err("diag: In %s, unknown peripheral, peripheral: %d\n", __func__, *(uint8_t *)temp); return; goto err; } temp += sizeof(uint8_t); read_len += sizeof(uint8_t); Loading @@ -758,6 +765,13 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) read_len += sizeof(uint8_t); diag_dci_notify_client(peripheral_mask, status, token); } err: /* * DCI control packets are not consumed by the clients. Mimic client * consumption by setting and clearing the wakeup source copy_count * explicitly. */ diag_ws_on_copy_fail(DIAG_WS_DCI); } void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, Loading Loading @@ -2574,21 +2588,6 @@ int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, uint8_t real_time) return 1; } void diag_dci_try_activate_wakeup_source() { spin_lock_irqsave(&ws_lock, ws_lock_flags); pm_wakeup_event(driver->diag_dev, DCI_WAKEUP_TIMEOUT); pm_stay_awake(driver->diag_dev); spin_unlock_irqrestore(&ws_lock, ws_lock_flags); } void diag_dci_try_deactivate_wakeup_source() { spin_lock_irqsave(&ws_lock, ws_lock_flags); pm_relax(driver->diag_dev); spin_unlock_irqrestore(&ws_lock, ws_lock_flags); } int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) { int i, err = 0; Loading Loading @@ -2810,7 +2809,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) smd_info->in_busy_1 = 0; mutex_unlock(&buf_entry->data_mutex); } diag_dci_try_deactivate_wakeup_source(); /* * These are buffers that can't be written to the client which * means that the copy cannot be completed. Make sure that we * remove those references in DCI wakeup source. */ diag_ws_on_copy_fail(DIAG_WS_DCI); } mutex_unlock(&entry->write_buf_mutex); Loading drivers/char/diag/diag_dci.h +0 −3 Original line number Diff line number Diff line Loading @@ -258,9 +258,6 @@ uint8_t diag_dci_get_cumulative_real_time(int token); int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, uint8_t real_time); int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc); /* Functions related to DCI wakeup sources */ void diag_dci_try_activate_wakeup_source(void); void diag_dci_try_deactivate_wakeup_source(void); int diag_dci_write_proc(int peripheral, int pkt_type, char *buf, int len); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE Loading drivers/char/diag/diag_debugfs.c +47 −0 Original line number Diff line number Diff line Loading @@ -288,6 +288,44 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, return bytes_written; } static ssize_t diag_dbgfs_read_power(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { char *buf; int ret; unsigned int buf_size; buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL); if (!buf) { pr_err("diag: %s, Error allocating memory\n", __func__); return -ENOMEM; } buf_size = ksize(buf); ret = scnprintf(buf, buf_size, "DCI reference count: %d\n" "DCI copy count: %d\n" "DCI Client Count: %d\n\n" "Memory Device reference count: %d\n" "Memory Device copy count: %d\n" "Logging mode: %d\n\n" "Wakeup source active count: %lu\n" "Wakeup source relax count: %lu\n\n", driver->dci_ws.ref_count, driver->dci_ws.copy_count, driver->num_dci_client, driver->md_ws.ref_count, driver->md_ws.copy_count, driver->logging_mode, driver->diag_dev->power.wakeup->active_count, driver->diag_dev->power.wakeup->relax_count); ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret); kfree(buf); return ret; } static ssize_t diag_dbgfs_read_workpending(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { Loading Loading @@ -786,6 +824,10 @@ const struct file_operations diag_dbgfs_dcistats_ops = { .read = diag_dbgfs_read_dcistats, }; const struct file_operations diag_dbgfs_power_ops = { .read = diag_dbgfs_read_power, }; int diag_debugfs_init(void) { struct dentry *entry = NULL; Loading Loading @@ -819,6 +861,11 @@ int diag_debugfs_init(void) if (!entry) goto err; entry = debugfs_create_file("power", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_power_ops); if (!entry) goto err; #ifdef CONFIG_DIAGFWD_BRIDGE_CODE entry = debugfs_create_file("bridge", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_bridge_ops); Loading drivers/char/diag/diagchar.h +22 −10 Original line number Diff line number Diff line Loading @@ -191,6 +191,9 @@ #define DIAG_NUM_PROC 1 #endif #define DIAG_WS_DCI 0 #define DIAG_WS_MD 1 /* Maximum number of pkt reg supported at initialization*/ extern int diag_max_reg; extern int diag_threshold_reg; Loading Loading @@ -254,14 +257,6 @@ struct diag_client_map { int pid; }; struct diag_nrt_wake_lock { int enabled; int ref_count; int copy_count; struct wake_lock read_lock; spinlock_t read_spinlock; }; struct real_time_vote_t { int client_id; uint16_t proc; Loading @@ -273,6 +268,12 @@ struct real_time_query_t { int proc; } __packed; struct diag_ws_ref_t { int ref_count; int copy_count; spinlock_t lock; }; /* This structure is defined in USB header file */ #ifndef CONFIG_DIAG_OVER_USB struct diag_request { Loading Loading @@ -314,8 +315,6 @@ struct diag_smd_info { struct diag_request *write_ptr_1; struct diag_request *write_ptr_2; struct diag_nrt_wake_lock nrt_lock; struct workqueue_struct *wq; struct work_struct diag_read_smd_work; Loading Loading @@ -475,6 +474,10 @@ struct diagchar_dev { int logging_process_id; struct task_struct *socket_process; struct task_struct *callback_process; /* Power related variables */ struct diag_ws_ref_t dci_ws; struct diag_ws_ref_t md_ws; spinlock_t ws_lock; #ifdef CONFIG_DIAGFWD_BRIDGE_CODE /* common for all bridges */ Loading Loading @@ -503,4 +506,13 @@ void diag_get_timestamp(char *time_str); int diag_find_polling_reg(int i); void check_drain_timer(void); void diag_ws_init(void); void diag_ws_on_notify(void); void diag_ws_on_read(int type, int pkt_len); void diag_ws_on_copy(int type); void diag_ws_on_copy_fail(int type); void diag_ws_on_copy_complete(int type); void diag_ws_reset(int type); void diag_ws_release(void); #endif drivers/char/diag/diagchar_core.c +195 −13 Original line number Diff line number Diff line Loading @@ -330,6 +330,7 @@ static int diagchar_close(struct inode *inode, struct file *file) diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN, ALL_PROC); diag_switch_logging(USB_MODE); diag_ws_reset(DIAG_WS_MD); } #endif /* DIAG over USB */ /* Delete the pkt response table entry for the exiting process */ Loading Loading @@ -492,6 +493,7 @@ int diag_copy_remote(char __user *buf, size_t count, int *pret, int *pnum_data) int ret = *pret; int num_data = *pnum_data; int remote_token; int copy_data = 0; unsigned long spin_lock_flags; struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES]; Loading Loading @@ -523,6 +525,9 @@ int diag_copy_remote(char __user *buf, size_t count, int *pret, int *pnum_data) hsic_buf_tbl[i].length); num_data++; diag_ws_on_copy(DIAG_WS_MD); copy_data = 1; /* Copy the negative token */ if (copy_to_user(buf+ret, &remote_token, 4)) { Loading Loading @@ -579,6 +584,8 @@ drop_hsic: driver->in_busy_smux = 0; } exit_stat = 0; if (copy_data) diag_ws_on_copy_complete(DIAG_WS_MD); exit: *pret = ret; *pnum_data = num_data; Loading Loading @@ -620,6 +627,7 @@ static int diag_copy_dci(char __user *buf, size_t count, goto drop; ret += buf_entry->data_len; total_data_len += buf_entry->data_len; diag_ws_on_copy(DIAG_WS_DCI); drop: buf_entry->in_busy = 0; buf_entry->data_len = 0; Loading Loading @@ -657,6 +665,13 @@ drop: /* Copy the total data length */ COPY_USER_SPACE_OR_EXIT(buf+8, total_data_len, 4); ret -= 4; /* * Flush any read that is currently pending on DCI data and * command channnels. This will ensure that the next read is not * missed. */ flush_workqueue(driver->diag_dci_wq); diag_ws_on_copy_complete(DIAG_WS_DCI); } else { pr_debug("diag: In %s, Trying to copy ZERO bytes, total_data_len: %d\n", __func__, total_data_len); Loading Loading @@ -1341,7 +1356,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, int num_data = 0, data_type; int remote_token; int exit_stat; int clear_read_wakelock; int copy_data = 0; unsigned long flags; for (i = 0; i < driver->num_clients; i++) Loading @@ -1360,7 +1375,6 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, mutex_lock(&driver->diagchar_mutex); clear_read_wakelock = 0; if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver-> logging_mode == MEMORY_DEVICE_MODE)) { remote_token = 0; Loading Loading @@ -1442,14 +1456,12 @@ drop: COPY_USER_SPACE_OR_EXIT(buf+ret, *(data->buf_in_1), data->write_ptr_1->length); if (!driver->real_time_mode) { process_lock_on_copy(&data->nrt_lock); clear_read_wakelock++; } spin_lock_irqsave(&data->in_busy_lock, flags); data->in_busy_1 = 0; spin_unlock_irqrestore(&data->in_busy_lock, flags); diag_ws_on_copy(DIAG_WS_MD); copy_data = 1; } if (data->in_busy_2 == 1) { num_data++; Loading @@ -1460,14 +1472,12 @@ drop: COPY_USER_SPACE_OR_EXIT(buf+ret, *(data->buf_in_2), data->write_ptr_2->length); if (!driver->real_time_mode) { process_lock_on_copy(&data->nrt_lock); clear_read_wakelock++; } spin_lock_irqsave(&data->in_busy_lock, flags); data->in_busy_2 = 0; spin_unlock_irqrestore(&data->in_busy_lock, flags); diag_ws_on_copy(DIAG_WS_MD); copy_data = 1; } } if (driver->supports_separate_cmdrsp) { Loading Loading @@ -1634,10 +1644,15 @@ drop: goto exit; } exit: if (clear_read_wakelock) { if (copy_data) { /* * Flush any work that is currently pending on the data * channels. This will ensure that the next read is not missed. */ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) process_lock_on_copy_complete( &driver->smd_data[i].nrt_lock); flush_workqueue(driver->smd_data[i].wq); wake_up(&driver->smd_wait_q); diag_ws_on_copy_complete(DIAG_WS_MD); } mutex_unlock(&driver->diagchar_mutex); return ret; Loading Loading @@ -2112,6 +2127,172 @@ fail_free_copy: return ret; } void diag_ws_init() { driver->dci_ws.ref_count = 0; driver->dci_ws.copy_count = 0; spin_lock_init(&driver->dci_ws.lock); driver->md_ws.ref_count = 0; driver->md_ws.copy_count = 0; spin_lock_init(&driver->md_ws.lock); spin_lock_init(&driver->ws_lock); } void diag_ws_on_notify() { /* * Do not deal with reference count here as there can be spurious * interrupts. */ pm_stay_awake(driver->diag_dev); } void diag_ws_on_read(int type, int pkt_len) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); if (pkt_len > 0) { ws_ref->ref_count++; } else { if (ws_ref->ref_count < 1) { ws_ref->ref_count = 0; ws_ref->copy_count = 0; } diag_ws_release(); } spin_unlock_irqrestore(&ws_ref->lock, flags); } void diag_ws_on_copy(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->copy_count++; spin_unlock_irqrestore(&ws_ref->lock, flags); } void diag_ws_on_copy_fail(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->ref_count--; spin_unlock_irqrestore(&ws_ref->lock, flags); diag_ws_release(); } void diag_ws_on_copy_complete(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->ref_count -= ws_ref->copy_count; if (ws_ref->ref_count < 1) ws_ref->ref_count = 0; ws_ref->copy_count = 0; spin_unlock_irqrestore(&ws_ref->lock, flags); diag_ws_release(); } void diag_ws_reset(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->ref_count = 0; ws_ref->copy_count = 0; spin_unlock_irqrestore(&ws_ref->lock, flags); diag_ws_release(); } void diag_ws_release() { unsigned long flags; spin_lock_irqsave(&driver->ws_lock, flags); if (driver->dci_ws.ref_count == 0 && driver->md_ws.ref_count == 0) pm_relax(driver->diag_dev); spin_unlock_irqrestore(&driver->ws_lock, flags); } static int diag_real_time_info_init(void) { int i; Loading Loading @@ -2352,6 +2533,7 @@ static int __init diagchar_init(void) init_waitqueue_head(&driver->wait_q); init_waitqueue_head(&driver->smd_wait_q); INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn); diag_ws_init(); ret = diag_real_time_info_init(); if (ret) goto fail; Loading Loading
drivers/char/diag/diag_dci.c +27 −23 Original line number Diff line number Diff line Loading @@ -190,6 +190,12 @@ static void dci_add_buffer_to_list(struct diag_dci_client_tbl *client, mutex_lock(&client->write_buf_mutex); list_add_tail(&buf->buf_track, &client->list_write_buf); /* * In the case of DCI, there can be multiple packets in one read. To * calculate the wakeup source reference count, we must account for each * packet in a single read. */ diag_ws_on_read(DIAG_WS_DCI, buf->data_len); mutex_lock(&buf->data_mutex); buf->in_busy = 1; buf->in_list = 1; Loading Loading @@ -470,7 +476,6 @@ end: /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); diag_dci_try_deactivate_wakeup_source(); return 0; } Loading @@ -491,7 +496,7 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, * process DCI data */ if (driver->num_dci_client == 0) { diag_dci_try_deactivate_wakeup_source(); diag_ws_reset(DIAG_WS_DCI); return 0; } Loading @@ -511,7 +516,7 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, if ((dci_pkt_len + 5) > (recd_bytes - read_bytes)) { pr_err("diag: Invalid length in %s, len: %d, dci_pkt_len: %d", __func__, recd_bytes, dci_pkt_len); diag_dci_try_deactivate_wakeup_source(); diag_ws_release(); return 0; } /* Loading @@ -520,8 +525,10 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, */ err = diag_process_single_dci_pkt(buf + 4, dci_pkt_len, smd_info->peripheral, DCI_LOCAL_PROC); if (err) if (err) { diag_ws_release(); break; } read_bytes += 5 + dci_pkt_len; buf += 5 + dci_pkt_len; /* advance to next DCI pkt */ } Loading @@ -529,7 +536,6 @@ int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf, /* wake up all sleeping DCI clients which have some data */ diag_dci_wakeup_clients(); dci_check_drain_timer(); diag_dci_try_deactivate_wakeup_source(); return 0; } Loading Loading @@ -723,6 +729,7 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) return; } diag_ws_on_read(DIAG_WS_DCI, len); header = (struct diag_ctrl_dci_status *)temp; temp += sizeof(struct diag_ctrl_dci_status); read_len += sizeof(struct diag_ctrl_dci_status); Loading @@ -731,7 +738,7 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) if (read_len > len) { pr_err("diag: Invalid length len: %d in %s\n", len, __func__); return; goto err; } switch (*(uint8_t *)temp) { Loading @@ -747,7 +754,7 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) default: pr_err("diag: In %s, unknown peripheral, peripheral: %d\n", __func__, *(uint8_t *)temp); return; goto err; } temp += sizeof(uint8_t); read_len += sizeof(uint8_t); Loading @@ -758,6 +765,13 @@ void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token) read_len += sizeof(uint8_t); diag_dci_notify_client(peripheral_mask, status, token); } err: /* * DCI control packets are not consumed by the clients. Mimic client * consumption by setting and clearing the wakeup source copy_count * explicitly. */ diag_ws_on_copy_fail(DIAG_WS_DCI); } void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, Loading Loading @@ -2574,21 +2588,6 @@ int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, uint8_t real_time) return 1; } void diag_dci_try_activate_wakeup_source() { spin_lock_irqsave(&ws_lock, ws_lock_flags); pm_wakeup_event(driver->diag_dev, DCI_WAKEUP_TIMEOUT); pm_stay_awake(driver->diag_dev); spin_unlock_irqrestore(&ws_lock, ws_lock_flags); } void diag_dci_try_deactivate_wakeup_source() { spin_lock_irqsave(&ws_lock, ws_lock_flags); pm_relax(driver->diag_dev); spin_unlock_irqrestore(&ws_lock, ws_lock_flags); } int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) { int i, err = 0; Loading Loading @@ -2810,7 +2809,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) smd_info->in_busy_1 = 0; mutex_unlock(&buf_entry->data_mutex); } diag_dci_try_deactivate_wakeup_source(); /* * These are buffers that can't be written to the client which * means that the copy cannot be completed. Make sure that we * remove those references in DCI wakeup source. */ diag_ws_on_copy_fail(DIAG_WS_DCI); } mutex_unlock(&entry->write_buf_mutex); Loading
drivers/char/diag/diag_dci.h +0 −3 Original line number Diff line number Diff line Loading @@ -258,9 +258,6 @@ uint8_t diag_dci_get_cumulative_real_time(int token); int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, uint8_t real_time); int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc); /* Functions related to DCI wakeup sources */ void diag_dci_try_activate_wakeup_source(void); void diag_dci_try_deactivate_wakeup_source(void); int diag_dci_write_proc(int peripheral, int pkt_type, char *buf, int len); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE Loading
drivers/char/diag/diag_debugfs.c +47 −0 Original line number Diff line number Diff line Loading @@ -288,6 +288,44 @@ static ssize_t diag_dbgfs_read_dcistats(struct file *file, return bytes_written; } static ssize_t diag_dbgfs_read_power(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { char *buf; int ret; unsigned int buf_size; buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL); if (!buf) { pr_err("diag: %s, Error allocating memory\n", __func__); return -ENOMEM; } buf_size = ksize(buf); ret = scnprintf(buf, buf_size, "DCI reference count: %d\n" "DCI copy count: %d\n" "DCI Client Count: %d\n\n" "Memory Device reference count: %d\n" "Memory Device copy count: %d\n" "Logging mode: %d\n\n" "Wakeup source active count: %lu\n" "Wakeup source relax count: %lu\n\n", driver->dci_ws.ref_count, driver->dci_ws.copy_count, driver->num_dci_client, driver->md_ws.ref_count, driver->md_ws.copy_count, driver->logging_mode, driver->diag_dev->power.wakeup->active_count, driver->diag_dev->power.wakeup->relax_count); ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret); kfree(buf); return ret; } static ssize_t diag_dbgfs_read_workpending(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { Loading Loading @@ -786,6 +824,10 @@ const struct file_operations diag_dbgfs_dcistats_ops = { .read = diag_dbgfs_read_dcistats, }; const struct file_operations diag_dbgfs_power_ops = { .read = diag_dbgfs_read_power, }; int diag_debugfs_init(void) { struct dentry *entry = NULL; Loading Loading @@ -819,6 +861,11 @@ int diag_debugfs_init(void) if (!entry) goto err; entry = debugfs_create_file("power", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_power_ops); if (!entry) goto err; #ifdef CONFIG_DIAGFWD_BRIDGE_CODE entry = debugfs_create_file("bridge", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_bridge_ops); Loading
drivers/char/diag/diagchar.h +22 −10 Original line number Diff line number Diff line Loading @@ -191,6 +191,9 @@ #define DIAG_NUM_PROC 1 #endif #define DIAG_WS_DCI 0 #define DIAG_WS_MD 1 /* Maximum number of pkt reg supported at initialization*/ extern int diag_max_reg; extern int diag_threshold_reg; Loading Loading @@ -254,14 +257,6 @@ struct diag_client_map { int pid; }; struct diag_nrt_wake_lock { int enabled; int ref_count; int copy_count; struct wake_lock read_lock; spinlock_t read_spinlock; }; struct real_time_vote_t { int client_id; uint16_t proc; Loading @@ -273,6 +268,12 @@ struct real_time_query_t { int proc; } __packed; struct diag_ws_ref_t { int ref_count; int copy_count; spinlock_t lock; }; /* This structure is defined in USB header file */ #ifndef CONFIG_DIAG_OVER_USB struct diag_request { Loading Loading @@ -314,8 +315,6 @@ struct diag_smd_info { struct diag_request *write_ptr_1; struct diag_request *write_ptr_2; struct diag_nrt_wake_lock nrt_lock; struct workqueue_struct *wq; struct work_struct diag_read_smd_work; Loading Loading @@ -475,6 +474,10 @@ struct diagchar_dev { int logging_process_id; struct task_struct *socket_process; struct task_struct *callback_process; /* Power related variables */ struct diag_ws_ref_t dci_ws; struct diag_ws_ref_t md_ws; spinlock_t ws_lock; #ifdef CONFIG_DIAGFWD_BRIDGE_CODE /* common for all bridges */ Loading Loading @@ -503,4 +506,13 @@ void diag_get_timestamp(char *time_str); int diag_find_polling_reg(int i); void check_drain_timer(void); void diag_ws_init(void); void diag_ws_on_notify(void); void diag_ws_on_read(int type, int pkt_len); void diag_ws_on_copy(int type); void diag_ws_on_copy_fail(int type); void diag_ws_on_copy_complete(int type); void diag_ws_reset(int type); void diag_ws_release(void); #endif
drivers/char/diag/diagchar_core.c +195 −13 Original line number Diff line number Diff line Loading @@ -330,6 +330,7 @@ static int diagchar_close(struct inode *inode, struct file *file) diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN, ALL_PROC); diag_switch_logging(USB_MODE); diag_ws_reset(DIAG_WS_MD); } #endif /* DIAG over USB */ /* Delete the pkt response table entry for the exiting process */ Loading Loading @@ -492,6 +493,7 @@ int diag_copy_remote(char __user *buf, size_t count, int *pret, int *pnum_data) int ret = *pret; int num_data = *pnum_data; int remote_token; int copy_data = 0; unsigned long spin_lock_flags; struct diag_write_device hsic_buf_tbl[NUM_HSIC_BUF_TBL_ENTRIES]; Loading Loading @@ -523,6 +525,9 @@ int diag_copy_remote(char __user *buf, size_t count, int *pret, int *pnum_data) hsic_buf_tbl[i].length); num_data++; diag_ws_on_copy(DIAG_WS_MD); copy_data = 1; /* Copy the negative token */ if (copy_to_user(buf+ret, &remote_token, 4)) { Loading Loading @@ -579,6 +584,8 @@ drop_hsic: driver->in_busy_smux = 0; } exit_stat = 0; if (copy_data) diag_ws_on_copy_complete(DIAG_WS_MD); exit: *pret = ret; *pnum_data = num_data; Loading Loading @@ -620,6 +627,7 @@ static int diag_copy_dci(char __user *buf, size_t count, goto drop; ret += buf_entry->data_len; total_data_len += buf_entry->data_len; diag_ws_on_copy(DIAG_WS_DCI); drop: buf_entry->in_busy = 0; buf_entry->data_len = 0; Loading Loading @@ -657,6 +665,13 @@ drop: /* Copy the total data length */ COPY_USER_SPACE_OR_EXIT(buf+8, total_data_len, 4); ret -= 4; /* * Flush any read that is currently pending on DCI data and * command channnels. This will ensure that the next read is not * missed. */ flush_workqueue(driver->diag_dci_wq); diag_ws_on_copy_complete(DIAG_WS_DCI); } else { pr_debug("diag: In %s, Trying to copy ZERO bytes, total_data_len: %d\n", __func__, total_data_len); Loading Loading @@ -1341,7 +1356,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, int num_data = 0, data_type; int remote_token; int exit_stat; int clear_read_wakelock; int copy_data = 0; unsigned long flags; for (i = 0; i < driver->num_clients; i++) Loading @@ -1360,7 +1375,6 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count, mutex_lock(&driver->diagchar_mutex); clear_read_wakelock = 0; if ((driver->data_ready[index] & USER_SPACE_DATA_TYPE) && (driver-> logging_mode == MEMORY_DEVICE_MODE)) { remote_token = 0; Loading Loading @@ -1442,14 +1456,12 @@ drop: COPY_USER_SPACE_OR_EXIT(buf+ret, *(data->buf_in_1), data->write_ptr_1->length); if (!driver->real_time_mode) { process_lock_on_copy(&data->nrt_lock); clear_read_wakelock++; } spin_lock_irqsave(&data->in_busy_lock, flags); data->in_busy_1 = 0; spin_unlock_irqrestore(&data->in_busy_lock, flags); diag_ws_on_copy(DIAG_WS_MD); copy_data = 1; } if (data->in_busy_2 == 1) { num_data++; Loading @@ -1460,14 +1472,12 @@ drop: COPY_USER_SPACE_OR_EXIT(buf+ret, *(data->buf_in_2), data->write_ptr_2->length); if (!driver->real_time_mode) { process_lock_on_copy(&data->nrt_lock); clear_read_wakelock++; } spin_lock_irqsave(&data->in_busy_lock, flags); data->in_busy_2 = 0; spin_unlock_irqrestore(&data->in_busy_lock, flags); diag_ws_on_copy(DIAG_WS_MD); copy_data = 1; } } if (driver->supports_separate_cmdrsp) { Loading Loading @@ -1634,10 +1644,15 @@ drop: goto exit; } exit: if (clear_read_wakelock) { if (copy_data) { /* * Flush any work that is currently pending on the data * channels. This will ensure that the next read is not missed. */ for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) process_lock_on_copy_complete( &driver->smd_data[i].nrt_lock); flush_workqueue(driver->smd_data[i].wq); wake_up(&driver->smd_wait_q); diag_ws_on_copy_complete(DIAG_WS_MD); } mutex_unlock(&driver->diagchar_mutex); return ret; Loading Loading @@ -2112,6 +2127,172 @@ fail_free_copy: return ret; } void diag_ws_init() { driver->dci_ws.ref_count = 0; driver->dci_ws.copy_count = 0; spin_lock_init(&driver->dci_ws.lock); driver->md_ws.ref_count = 0; driver->md_ws.copy_count = 0; spin_lock_init(&driver->md_ws.lock); spin_lock_init(&driver->ws_lock); } void diag_ws_on_notify() { /* * Do not deal with reference count here as there can be spurious * interrupts. */ pm_stay_awake(driver->diag_dev); } void diag_ws_on_read(int type, int pkt_len) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); if (pkt_len > 0) { ws_ref->ref_count++; } else { if (ws_ref->ref_count < 1) { ws_ref->ref_count = 0; ws_ref->copy_count = 0; } diag_ws_release(); } spin_unlock_irqrestore(&ws_ref->lock, flags); } void diag_ws_on_copy(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->copy_count++; spin_unlock_irqrestore(&ws_ref->lock, flags); } void diag_ws_on_copy_fail(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->ref_count--; spin_unlock_irqrestore(&ws_ref->lock, flags); diag_ws_release(); } void diag_ws_on_copy_complete(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->ref_count -= ws_ref->copy_count; if (ws_ref->ref_count < 1) ws_ref->ref_count = 0; ws_ref->copy_count = 0; spin_unlock_irqrestore(&ws_ref->lock, flags); diag_ws_release(); } void diag_ws_reset(int type) { unsigned long flags; struct diag_ws_ref_t *ws_ref = NULL; switch (type) { case DIAG_WS_DCI: ws_ref = &driver->dci_ws; break; case DIAG_WS_MD: ws_ref = &driver->md_ws; break; default: pr_err_ratelimited("diag: In %s, invalid type: %d\n", __func__, type); return; } spin_lock_irqsave(&ws_ref->lock, flags); ws_ref->ref_count = 0; ws_ref->copy_count = 0; spin_unlock_irqrestore(&ws_ref->lock, flags); diag_ws_release(); } void diag_ws_release() { unsigned long flags; spin_lock_irqsave(&driver->ws_lock, flags); if (driver->dci_ws.ref_count == 0 && driver->md_ws.ref_count == 0) pm_relax(driver->diag_dev); spin_unlock_irqrestore(&driver->ws_lock, flags); } static int diag_real_time_info_init(void) { int i; Loading Loading @@ -2352,6 +2533,7 @@ static int __init diagchar_init(void) init_waitqueue_head(&driver->wait_q); init_waitqueue_head(&driver->smd_wait_q); INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn); diag_ws_init(); ret = diag_real_time_info_init(); if (ret) goto fail; Loading