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

Commit aa196693 authored by Ravi Aravamudhan's avatar Ravi Aravamudhan
Browse files

diag: dci: Remote DCI channel discovery support



Diag driver on Apps opens the remote DCI channels on remote ASICs
irrespective of the remote side support. Add a handshaking
mechanism that closes the DCI channel if handshaking fails.

Change-Id: I92bb0c6f2c8363bc3fd45d3c60bd9e79e7a216f0
Signed-off-by: default avatarRavi Aravamudhan <aravamud@codeaurora.org>
parent 7e314d1f
Loading
Loading
Loading
Loading
+233 −18
Original line number Diff line number Diff line
@@ -49,6 +49,16 @@ unsigned int dci_max_clients = 10;
struct mutex dci_log_mask_mutex;
struct mutex dci_event_mask_mutex;

/*
 * DCI_HANDSHAKE_RETRY_TIME: Time to wait (in microseconds) before checking the
 * connection status again.
 *
 * DCI_HANDSHAKE_WAIT_TIME: Timeout (in milliseconds) to check for dci
 * connection status
 */
#define DCI_HANDSHAKE_RETRY_TIME	500000
#define DCI_HANDSHAKE_WAIT_TIME		200

spinlock_t ws_lock;
unsigned long ws_lock_flags;

@@ -71,6 +81,21 @@ struct dci_ops_tbl_t dci_ops_tbl[NUM_DCI_PROC] = {
#endif
};

struct dci_channel_status_t dci_channel_status[NUM_DCI_PROC] = {
	{
		.id = 0,
		.open = 0,
		.retry_count = 0
	},
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
	{
		.id = DIAGFWD_MDM_DCI,
		.open = 0,
		.retry_count = 0
	}
#endif
};

/* Number of milliseconds anticipated to process the DCI data */
#define DCI_WAKEUP_TIMEOUT 1

@@ -144,6 +169,56 @@ static void dci_check_drain_timer(void)
	}
}

#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
static void dci_handshake_work_fn(struct work_struct *work)
{
	int err = 0;
	int max_retries = 5;

	struct dci_channel_status_t *status = container_of(work,
						struct dci_channel_status_t,
						handshake_work);

	if (status->open) {
		pr_debug("diag: In %s, remote dci channel is open, index: %d\n",
			 __func__, status->id);
		return;
	}

	if (status->retry_count == max_retries) {
		status->retry_count = 0;
		pr_info("diag: dci channel connection handshake timed out, id: %d\n",
			status->id);
		err = diagfwd_bridge_close(TOKEN_TO_BRIDGE(status->id));
		if (err) {
			pr_err("diag: In %s, unable to close dci channel id: %d, err: %d\n",
			       __func__, status->id, err);
		}
		return;
	}
	status->retry_count++;
	/*
	 * Sleep for sometime to check for the connection status again. The
	 * value should be optimum to include a roundabout time for a small
	 * packet to the remote processor.
	 */
	usleep_range(DCI_HANDSHAKE_RETRY_TIME, DCI_HANDSHAKE_RETRY_TIME + 100);
	mod_timer(&status->wait_time,
		  jiffies + msecs_to_jiffies(DCI_HANDSHAKE_WAIT_TIME));
}

static void dci_chk_handshake(unsigned long data)
{
	int index = (int)data;

	if (index < 0 || index > NUM_DCI_PROC)
		return;

	queue_work(driver->diag_dci_wq,
		   &dci_channel_status[index].handshake_work);
}
#endif

static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type)
{
	if (!buffer || buffer->data)
@@ -719,39 +794,34 @@ static int diag_dci_remove_req_entry(unsigned char *buf, int len,
	return 0;
}

void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token)
static void dci_process_ctrl_status(unsigned char *buf, int len, int token)
{

	struct diag_ctrl_dci_status *header = NULL;
	unsigned char *temp = buf;
	uint32_t ctrl_pkt_id = 0, read_len = 0;
	uint32_t read_len = 0;
	uint8_t i;
	int peripheral_mask, status;

	if (!buf) {
		pr_err("diag: Invalid buffer in %s\n", __func__);
	if (!buf || (len < sizeof(struct diag_ctrl_dci_status))) {
		pr_err("diag: In %s, invalid buf %p or length: %d\n",
		       __func__, buf, len);
		return;
	}

	/* Skip the Control packet command code */
	temp += sizeof(uint8_t);
	ctrl_pkt_id = *(uint32_t *)temp;
	if (ctrl_pkt_id != DIAG_CTRL_MSG_DCI_CONNECTION_STATUS) {
		pr_alert("diag: Unknown control packet through DCI channel : %d\n",
								ctrl_pkt_id);
	if (!VALID_DCI_TOKEN(token)) {
		pr_err("diag: In %s, invalid DCI token %d\n", __func__, 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);

	for (i = 0; i < header->count; i++) {
		if (read_len > len) {
			pr_err("diag: Invalid length len: %d in %s\n", len,
								__func__);
			goto err;
			pr_err("diag: In %s, Invalid length len: %d\n",
			       __func__, len);
			return;
		}

		switch (*(uint8_t *)temp) {
@@ -770,7 +840,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);
			goto err;
			return;
		}
		temp += sizeof(uint8_t);
		read_len += sizeof(uint8_t);
@@ -781,6 +851,70 @@ 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);
	}
}

static void dci_process_ctrl_handshake_pkt(unsigned char *buf, int len,
					   int token)
{
	struct diag_ctrl_dci_handshake_pkt *header = NULL;
	unsigned char *temp = buf;
	int err = 0;

	if (!buf || (len < sizeof(struct diag_ctrl_dci_handshake_pkt)))
		return;

	if (!VALID_DCI_TOKEN(token))
		return;

	header = (struct diag_ctrl_dci_handshake_pkt *)temp;
	if (header->magic == DCI_MAGIC) {
		dci_channel_status[token].open = 1;
		err = dci_ops_tbl[token].send_log_mask(token);
		if (err) {
			pr_err("diag: In %s, unable to send log mask to token: %d, err: %d\n",
			       __func__, token, err);
		}
		err = dci_ops_tbl[token].send_event_mask(token);
		if (err) {
			pr_err("diag: In %s, unable to send event mask to token: %d, err: %d\n",
			       __func__, token, err);
		}
	}
}

void extract_dci_ctrl_pkt(unsigned char *buf, int len, int token)
{
	unsigned char *temp = buf;
	uint32_t ctrl_pkt_id;

	diag_ws_on_read(DIAG_WS_DCI, len);
	if (!buf) {
		pr_err("diag: Invalid buffer in %s\n", __func__);
		goto err;
	}

	if (len < (sizeof(uint8_t) + sizeof(uint32_t))) {
		pr_err("diag: In %s, invalid length %d\n", __func__, len);
		goto err;
	}

	/* Skip the Control packet command code */
	temp += sizeof(uint8_t);
	len -= sizeof(uint8_t);
	ctrl_pkt_id = *(uint32_t *)temp;
	switch (ctrl_pkt_id) {
	case DIAG_CTRL_MSG_DCI_CONNECTION_STATUS:
		dci_process_ctrl_status(temp, len, token);
		break;
	case DIAG_CTRL_MSG_DCI_HANDSHAKE_PKT:
		dci_process_ctrl_handshake_pkt(temp, len, token);
		break;
	default:
		pr_debug("diag: In %s, unknown control pkt %d\n",
			 __func__, ctrl_pkt_id);
		break;
	}

err:
	/*
	 * DCI control packets are not consumed by the clients. Mimic client
@@ -1395,6 +1529,70 @@ static int diag_send_dci_pkt_remote(unsigned char *data, int len, int tag,
}
#endif

#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
int diag_dci_send_handshake_pkt(int index)
{
	int err = 0;
	int token = BRIDGE_TO_TOKEN(index);
	int write_len = 0;
	struct diag_ctrl_dci_handshake_pkt ctrl_pkt;
	unsigned char *buf = NULL;
	struct diag_dci_header_t dci_header;

	if (!VALID_DCI_TOKEN(token)) {
		pr_err("diag: In %s, invalid DCI token %d\n", __func__, token);
		return -EINVAL;
	}

	buf = dci_get_buffer_from_bridge(token);
	if (!buf) {
		pr_err("diag: In %s, unable to get dci buffers to write data\n",
			__func__);
		return -EAGAIN;
	}

	dci_header.start = CONTROL_CHAR;
	dci_header.version = 1;
	/* Include the cmd code (uint8_t) in the length */
	dci_header.length = sizeof(ctrl_pkt) + sizeof(uint8_t);
	dci_header.cmd_code = DCI_CONTROL_PKT_CODE;
	memcpy(buf, &dci_header, sizeof(dci_header));
	write_len += sizeof(dci_header);

	ctrl_pkt.ctrl_pkt_id = DIAG_CTRL_MSG_DCI_HANDSHAKE_PKT;
	/*
	 *  The control packet data length accounts for the version (uint32_t)
	 *  of the packet and the magic number (uint32_t).
	 */
	ctrl_pkt.ctrl_pkt_data_len = 2 * sizeof(uint32_t);
	ctrl_pkt.version = 1;
	ctrl_pkt.magic = DCI_MAGIC;
	memcpy(buf + write_len, &ctrl_pkt, sizeof(ctrl_pkt));
	write_len += sizeof(ctrl_pkt);

	*(uint8_t *)(buf + write_len) = CONTROL_CHAR;
	write_len += sizeof(uint8_t);

	err = diag_dci_write_bridge(token, buf, write_len);
	if (err) {
		pr_err("diag: error writing ack packet to remote proc, token: %d, err: %d\n",
		       token, err);
		diagmem_free(driver, buf, dci_ops_tbl[token].mempool);
		return err;
	}

	mod_timer(&(dci_channel_status[token].wait_time),
		  jiffies + msecs_to_jiffies(DCI_HANDSHAKE_WAIT_TIME));

	return 0;
}
#else
int diag_dci_send_handshake_pkt(int index)
{
	return 0;
}
#endif

static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header,
				     unsigned char *req_buf, int req_len,
				     int tag)
@@ -2355,11 +2553,26 @@ static int diag_dci_init_local(void)
}

#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
static void diag_dci_init_handshake_remote(void)
{
	int i;
	struct dci_channel_status_t *temp = NULL;

	for (i = DCI_REMOTE_BASE; i < NUM_DCI_PROC; i++) {
		temp = &dci_channel_status[i];
		temp->id = i;
		setup_timer(&temp->wait_time, dci_chk_handshake, i);
		INIT_WORK(&temp->handshake_work, dci_handshake_work_fn);
	}
}

static int diag_dci_init_remote(void)
{
	int i;
	struct dci_ops_tbl_t *temp = NULL;

	diagmem_init(driver, POOL_TYPE_MDM_DCI_WRITE);

	for (i = DCI_REMOTE_BASE; i < DCI_REMOTE_LAST; i++) {
		temp = &dci_ops_tbl[i];
		create_dci_log_mask_tbl(temp->log_mask_composite,
@@ -2377,6 +2590,9 @@ static int diag_dci_init_remote(void)
	partial_pkt.read_len = 0;
	partial_pkt.remaining = 0;
	partial_pkt.processing = 0;

	diag_dci_init_handshake_remote();

	return 0;
}
#else
@@ -2635,7 +2851,6 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry)
		break;
	case DCI_MDM_PROC:
		new_entry->num_buffers = 1;
		diagmem_init(driver, POOL_TYPE_MDM_DCI_WRITE);
		break;
	}
	new_entry->real_time = MODE_REALTIME;
+11 −0
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@ extern unsigned int dci_max_clients;
#define BRIDGE_TO_TOKEN(x)	(x - DIAGFWD_MDM_DCI + DCI_REMOTE_BASE)
#define TOKEN_TO_BRIDGE(x)	(dci_ops_tbl[x].ctx)

#define DCI_MAGIC		(0xAABB1122)

struct dci_pkt_req_entry_t {
	int client_id;
	int uid;
@@ -197,6 +199,14 @@ struct dci_ops_tbl_t {
	uint16_t peripheral_status;
} __packed;

struct dci_channel_status_t {
	int id;
	int open;
	int retry_count;
	struct timer_list wait_time;
	struct work_struct handshake_work;
} __packed;

extern struct dci_ops_tbl_t dci_ops_tbl[NUM_DCI_PROC];

enum {
@@ -274,6 +284,7 @@ int diag_send_dci_event_mask_remote(int token);
unsigned char *dci_get_buffer_from_bridge(int token);
int diag_dci_write_bridge(int token, unsigned char *buf, int len);
int diag_dci_write_done_bridge(int index, unsigned char *buf, int len);
int diag_dci_send_handshake_pkt(int index);
#endif

#endif
+10 −0
Original line number Diff line number Diff line
@@ -179,6 +179,9 @@ int diag_remote_dev_open(int id)
	bridge_info[id].inited = 1;
	if (bridge_info[id].type == DIAG_DATA_TYPE)
		return diag_mux_queue_read(BRIDGE_TO_MUX(id));
	else if (bridge_info[id].type == DIAG_DCI_TYPE)
		return diag_dci_send_handshake_pkt(bridge_info[id].id);

	return 0;
}

@@ -258,6 +261,13 @@ void diagfwd_bridge_exit()
	diag_smux_exit();
}

int diagfwd_bridge_close(int id)
{
	if (id < 0 || id >= NUM_REMOTE_DEV)
		return -EINVAL;
	return bridge_info[id].dev_ops->close(bridge_info[id].ctxt);
}

int diagfwd_bridge_write(int id, unsigned char *buf, int len)
{
	if (id < 0 || id >= NUM_REMOTE_DEV)
+1 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ struct diagfwd_bridge_info {
extern struct diagfwd_bridge_info bridge_info[NUM_REMOTE_DEV];
int diagfwd_bridge_init(void);
void diagfwd_bridge_exit(void);
int diagfwd_bridge_close(int id);
int diagfwd_bridge_write(int id, unsigned char *buf, int len);
uint16_t diag_get_remote_device_mask(void);

+8 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#define DIAG_CTRL_MSG_LOG_RANGE_REPORT		23
#define DIAG_CTRL_MSG_SSID_RANGE_REPORT		24
#define DIAG_CTRL_MSG_BUILD_MASK_REPORT		25
#define DIAG_CTRL_MSG_DCI_HANDSHAKE_PKT		29

/*
 * Feature Mask Definitions: Feature mask is used to sepcify Diag features
@@ -166,6 +167,13 @@ struct diag_ctrl_dci_status {
	uint8_t count;
} __packed;

struct diag_ctrl_dci_handshake_pkt {
	uint32_t ctrl_pkt_id;
	uint32_t ctrl_pkt_data_len;
	uint32_t version;
	uint32_t magic;
} __packed;

struct diag_ctrl_last_event_report {
	uint32_t pkt_id;
	uint32_t len;
Loading