Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e1facfd authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "diag: dci: Remove the cap on number of delayed rsp registrations"

parents 8262f049 ae7170ba
Loading
Loading
Loading
Loading
+131 −67
Original line number Diff line number Diff line
@@ -433,15 +433,96 @@ static inline int __diag_dci_query_event_mask(struct diag_dci_client_tbl *entry,
	return ((*event_mask_ptr & byte_mask) == byte_mask) ? 1 : 0;
}

static struct dci_pkt_req_entry_t *diag_register_dci_transaction(int uid)
{
	struct dci_pkt_req_entry_t *entry = NULL;
	entry = kzalloc(sizeof(struct dci_pkt_req_entry_t), GFP_KERNEL);
	if (!entry)
		return NULL;

	mutex_lock(&driver->dci_mutex);
	driver->dci_tag++;
	entry->pid = current->tgid;
	entry->uid = uid;
	entry->tag = driver->dci_tag;
	list_add_tail(&entry->track, &driver->dci_req_list);
	mutex_unlock(&driver->dci_mutex);

	return entry;
}

static struct dci_pkt_req_entry_t *diag_dci_get_request_entry(int tag)
{
	struct list_head *start, *temp;
	struct dci_pkt_req_entry_t *entry = NULL;
	list_for_each_safe(start, temp, &driver->dci_req_list) {
		entry = list_entry(start, struct dci_pkt_req_entry_t, track);
		if (entry->tag == tag)
			return entry;
	}
	return NULL;
}

static int diag_dci_remove_req_entry(unsigned char *buf, int len,
				     struct dci_pkt_req_entry_t *entry)
{
	uint16_t rsp_count = 0, delayed_rsp_id = 0;
	if (!buf || len <= 0 || !entry) {
		pr_err("diag: In %s, invalid input buf: %p, len: %d, entry: %p\n",
			__func__, buf, len, entry);
		return -EIO;
	}

	/* It is an immediate response, delete it from the table */
	if (*buf != 0x80) {
		list_del(&entry->track);
		kfree(entry);
		return 1;
	}

	/* It is a delayed response. Check if the length is valid */
	if (len < MIN_DELAYED_RSP_LEN) {
		pr_err("diag: Invalid delayed rsp packet length %d\n", len);
		return -EINVAL;
	}

	/*
	 * If the delayed response id field (uint16_t at byte 8) is 0 then
	 * there is only one response and we can remove the request entry.
	 */
	delayed_rsp_id = *(uint16_t *)(buf + 8);
	if (delayed_rsp_id == 0) {
		list_del(&entry->track);
		kfree(entry);
		return 1;
	}

	/*
	 * Check the response count field (uint16 at byte 10). The request
	 * entry can be deleted it it is the last response in the sequence.
	 * It is the last response in the sequence if the response count
	 * is 1 or if the signed bit gets dropped.
	 */
	rsp_count = *(uint16_t *)(buf + 10);
	if (rsp_count > 0 && rsp_count < 0x1000) {
		list_del(&entry->track);
		kfree(entry);
		return 1;
	}

	return 0;
}

void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
									int len)
{
	int i = 0, index = -1, cmd_code_len = 1;
	int curr_client_pid = 0, write_len;
	int cmd_code_len = 1;
	int curr_client_pid = 0, write_len, *tag = NULL;
	struct diag_dci_client_tbl *entry = NULL;
	void *temp_buf = NULL;
	uint8_t recv_pkt_cmd_code;
	uint8_t recv_pkt_cmd_code, delete_flag = 0;
	struct diag_dci_buffer_t *rsp_buf = NULL;
	struct dci_pkt_req_entry_t *req_entry = NULL;

	recv_pkt_cmd_code = *(uint8_t *)(buf+4);
	if (recv_pkt_cmd_code != DCI_PKT_RSP_CODE)
@@ -460,22 +541,22 @@ void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
		return;
	}
	pr_debug("diag: len = %d\n", write_len);
	/* look up DCI client with tag */
	for (i = 0; i < dci_max_reg; i++) {
		if (driver->req_tracking_tbl[i].tag ==
					 *(int *)(buf+(4+cmd_code_len))) {
			*(int *)(buf+4+cmd_code_len) =
					driver->req_tracking_tbl[i].uid;
			curr_client_pid =
					 driver->req_tracking_tbl[i].pid;
			index = i;
			break;
		}
	}
	if (index == -1) {

	tag = (int *)(buf + (4 + cmd_code_len)); /* Retrieve the Tag field */
	req_entry = diag_dci_get_request_entry(*tag);
	if (!req_entry) {
		pr_err("diag: No matching PID for DCI data\n");
		return;
	}
	*tag = req_entry->uid; /* Replace the tag field with UID */
	curr_client_pid = req_entry->pid;

	/* Remove the headers and send only the response to this function */
	delete_flag = diag_dci_remove_req_entry(buf + 8 + cmd_code_len,
						len - (8 + cmd_code_len),
						req_entry);
	if (delete_flag < 0)
		return;

	entry = __diag_dci_get_client_entry(curr_client_pid);
	if (!entry) {
@@ -486,9 +567,14 @@ void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
	rsp_buf = entry->buffers[smd_info->peripheral].buf_cmd;

	mutex_lock(&rsp_buf->data_mutex);
	if ((rsp_buf->data_len + 8 + write_len) > rsp_buf->capacity) {
	/*
	 * Check if we can fit the data in the rsp buffer. The total length of
	 * the rsp is the rsp length (write_len) + DCI_PKT_RSP_TYPE header (int)
	 * + field for length (int) + delete_flag (uint8_t)
	 */
	if ((rsp_buf->data_len + 9 + write_len) > rsp_buf->capacity) {
		pr_alert("diag: create capacity for pkt rsp\n");
		rsp_buf->capacity += 8 + write_len;
		rsp_buf->capacity += 9 + write_len;
		temp_buf = krealloc(rsp_buf->data, rsp_buf->capacity,
				    GFP_KERNEL);
		if (!temp_buf) {
@@ -503,16 +589,14 @@ void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
	rsp_buf->data_len += sizeof(int);
	*(int *)(rsp_buf->data + rsp_buf->data_len) = write_len;
	rsp_buf->data_len += sizeof(int);
	*(uint8_t *)(rsp_buf->data + rsp_buf->data_len) = delete_flag;
	rsp_buf->data_len += sizeof(uint8_t);
	memcpy(rsp_buf->data+rsp_buf->data_len, buf+4+cmd_code_len, write_len);
	rsp_buf->data_len += write_len;
	rsp_buf->data_source = smd_info->peripheral;
	smd_info->in_busy_1 = 1;
	mutex_unlock(&rsp_buf->data_mutex);

	/* delete immediate response entry */
	if (smd_info->buf_in_1[8+cmd_code_len] != 0x80)
		driver->req_tracking_tbl[index].pid = 0;

	/*
	 * Add directly to the list for writing responses to the
	 * userspace as these shouldn't be buffered and shouldn't wait
@@ -841,8 +925,8 @@ void diag_dci_notify_client(int peripheral_mask, int data)
	}
}

int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
					 int len, int index)
static int diag_send_dci_pkt(struct diag_master_table entry,
			     unsigned char *buf, int len, int tag)
{
	int i, status = 0;
	unsigned int read_len = 0;
@@ -867,8 +951,7 @@ int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
	driver->apps_dci_buf[1] = 1; /* version */
	*(uint16_t *)(driver->apps_dci_buf + 2) = len + 4 + 1; /* length */
	driver->apps_dci_buf[4] = DCI_PKT_RSP_CODE;
	*(int *)(driver->apps_dci_buf + 5) =
		driver->req_tracking_tbl[index].tag;
	*(int *)(driver->apps_dci_buf + 5) = tag;
	for (i = 0; i < len; i++)
		driver->apps_dci_buf[i+9] = *(buf+i);
	read_len += len;
@@ -900,43 +983,18 @@ int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
	return status;
}

int diag_register_dci_transaction(int uid)
{
	int i, new_dci_client = 1, ret = -1;

	for (i = 0; i < dci_max_reg; i++) {
		if (driver->req_tracking_tbl[i].pid == current->tgid) {
			new_dci_client = 0;
			break;
		}
	}
	mutex_lock(&driver->dci_mutex);
	/* Make an entry in kernel DCI table */
	driver->dci_tag++;
	for (i = 0; i < dci_max_reg; i++) {
		if (driver->req_tracking_tbl[i].pid == 0) {
			driver->req_tracking_tbl[i].pid = current->tgid;
			driver->req_tracking_tbl[i].uid = uid;
			driver->req_tracking_tbl[i].tag = driver->dci_tag;
			ret = i;
			break;
		}
	}
	mutex_unlock(&driver->dci_mutex);
	return ret;
}

int diag_process_dci_transaction(unsigned char *buf, int len)
{
	unsigned char *temp = buf;
	uint16_t subsys_cmd_code, log_code, item_num;
	int subsys_id, cmd_code, ret = -1, index = -1, found = 0;
	int subsys_id, cmd_code, ret = -1, found = 0;
	struct diag_master_table entry;
	int count, set_mask, num_codes, bit_index, event_id, offset = 0, i;
	unsigned int byte_index, read_len = 0;
	uint8_t equip_id, *log_mask_ptr, *head_log_mask_ptr, byte_mask;
	uint8_t *event_mask_ptr;
	struct diag_dci_client_tbl *dci_entry = NULL;
	struct dci_pkt_req_entry_t *req_entry = NULL;

	if (!temp) {
		pr_err("diag: Invalid buffer in %s\n", __func__);
@@ -951,8 +1009,8 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
			return -EIO;
		}
		/* enter this UID into kernel table and return index */
		index = diag_register_dci_transaction(*(int *)temp);
		if (index < 0) {
		req_entry = diag_register_dci_transaction(*(int *)temp);
		if (!req_entry) {
			pr_alert("diag: registering new DCI transaction failed\n");
			return DIAG_DCI_NO_REG;
		}
@@ -981,8 +1039,8 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
					entry.subsys_id == subsys_id &&
					entry.cmd_code_lo <= subsys_cmd_code &&
					entry.cmd_code_hi >= subsys_cmd_code) {
					ret = diag_send_dci_pkt(entry, buf,
								len, index);
					ret = diag_send_dci_pkt(entry, buf, len,
								req_entry->tag);
				} else if (entry.cmd_code == 255
					  && cmd_code == 75) {
					if (entry.subsys_id == subsys_id &&
@@ -991,7 +1049,8 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
						entry.cmd_code_hi >=
						subsys_cmd_code) {
						ret = diag_send_dci_pkt(entry,
							buf, len, index);
								buf, len,
								req_entry->tag);
					}
				} else if (entry.cmd_code == 255 &&
					entry.subsys_id == 255) {
@@ -999,7 +1058,8 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
						entry.cmd_code_hi >=
							cmd_code) {
						ret = diag_send_dci_pkt(entry,
							buf, len, index);
								buf, len,
								req_entry->tag);
					}
				}
			}
@@ -1518,18 +1578,13 @@ int diag_dci_init(void)
		}
	}

	if (driver->req_tracking_tbl == NULL) {
		driver->req_tracking_tbl = kzalloc(dci_max_reg *
			sizeof(struct dci_pkt_req_tracking_tbl), GFP_KERNEL);
		if (driver->req_tracking_tbl == NULL)
			goto err;
	}
	if (driver->apps_dci_buf == NULL) {
		driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
		if (driver->apps_dci_buf == NULL)
			goto err;
	}
	INIT_LIST_HEAD(&driver->dci_client_list);
	INIT_LIST_HEAD(&driver->dci_req_list);

	driver->diag_dci_wq = create_singlethread_workqueue("diag_dci_wq");
	INIT_WORK(&dci_data_drain_work, dci_data_drain_work_fn);
@@ -1549,7 +1604,6 @@ int diag_dci_init(void)
	return DIAG_DCI_NO_ERROR;
err:
	pr_err("diag: Could not initialize diag DCI buffers");
	kfree(driver->req_tracking_tbl);
	kfree(driver->apps_dci_buf);
	for (i = 0; i < NUM_SMD_DCI_CHANNELS; i++)
		diag_smd_destructor(&driver->smd_dci[i]);
@@ -1582,7 +1636,6 @@ void diag_dci_exit(void)

		platform_driver_unregister(&msm_diag_dci_cmd_driver);
	}
	kfree(driver->req_tracking_tbl);
	kfree(driver->apps_dci_buf);
	mutex_destroy(&driver->dci_mutex);
	mutex_destroy(&dci_log_mask_mutex);
@@ -1843,6 +1896,8 @@ int diag_dci_deinit_client()
	struct diag_dci_buf_peripheral_t *proc_buf = NULL;
	struct diag_dci_client_tbl *entry = diag_dci_get_client_entry();
	struct diag_dci_buffer_t *buf_entry, *temp;
	struct list_head *start, *req_temp;
	struct dci_pkt_req_entry_t *req_entry = NULL;
	struct diag_smd_info *smd_info = NULL;

	if (!entry)
@@ -1876,6 +1931,15 @@ int diag_dci_deinit_client()
		return ret;
	}

	list_for_each_safe(start, req_temp, &driver->dci_req_list) {
		req_entry = list_entry(start, struct dci_pkt_req_entry_t,
				       track);
		if (req_entry->pid == current->tgid) {
			list_del(&req_entry->track);
			kfree(req_entry);
		}
	}

	/* Clean up any buffer that is pending write */
	mutex_lock(&entry->write_buf_mutex);
	list_for_each_entry_safe(buf_entry, temp, &entry->list_write_buf,
+5 −4
Original line number Diff line number Diff line
@@ -49,17 +49,20 @@
#define DCI_MAX_LOG_CODES		16
#define DCI_MAX_ITEMS_PER_LOG_CODE	512

#define MIN_DELAYED_RSP_LEN		12

extern unsigned int dci_max_reg;
extern unsigned int dci_max_clients;
extern unsigned char dci_cumulative_log_mask[DCI_LOG_MASK_SIZE];
extern unsigned char dci_cumulative_event_mask[DCI_EVENT_MASK_SIZE];
extern struct mutex dci_health_mutex;

struct dci_pkt_req_tracking_tbl {
struct dci_pkt_req_entry_t {
	int pid;
	int uid;
	int tag;
};
	struct list_head track;
} __packed;

struct diag_dci_reg_tbl_t {
	uint32_t client_id;
@@ -160,8 +163,6 @@ void diag_process_apps_dci_read_data(int data_type, void *buf, int recd_bytes);
int diag_process_smd_dci_read_data(struct diag_smd_info *smd_info, void *buf,
								int recd_bytes);
int diag_process_dci_transaction(unsigned char *buf, int len);
int diag_send_dci_pkt(struct diag_master_table entry, unsigned char *buf,
							 int len, int index);
void extract_dci_pkt_rsp(struct diag_smd_info *smd_info, unsigned char *buf,
								int len);
struct diag_dci_client_tbl *diag_dci_get_client_entry(void);
+1 −1
Original line number Diff line number Diff line
@@ -314,7 +314,7 @@ struct diagchar_dev {
	/* Whether or not the peripheral supports STM */
	int peripheral_supports_stm[NUM_SMD_CONTROL_CHANNELS];
	/* DCI related variables */
	struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
	struct list_head dci_req_list;
	struct list_head dci_client_list;
	int dci_tag;
	int dci_client_id;