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

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

diag: Make fixes in memory device mode



When there are multiple clients voting for memory device mode, diag
driver is incorrectly picking the client for draining data. Also,
memory device client that is currently receiving data won't receive
data when a new memory device client comes up. This patch addresses
these issues.

Change-Id: I6c2b3f46a1ade60c58db9c35b551f490268cfbee
Signed-off-by: default avatarRavi Aravamudhan <aravamud@codeaurora.org>
parent 4c5e5900
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -404,6 +404,7 @@ struct diag_md_proc_info {
	int pid;
	struct task_struct *socket_process;
	struct task_struct *callback_process;
	struct task_struct *mdlog_process;
};

struct diag_feature_t {
@@ -419,13 +420,6 @@ struct diag_feature_t {
	uint8_t sent_feature_mask;
};

struct diag_mdlog_client_info {
	struct task_struct *client_process;
	int client_id;
	uint16_t notification_list;
	int signal_type;
};

struct diagchar_dev {

	/* State for the char driver */
@@ -537,7 +531,6 @@ struct diagchar_dev {
	int logging_mode;
	int mask_check;
	struct diag_md_proc_info md_proc[DIAG_NUM_PROC];
	struct diag_mdlog_client_info md_client_info;
	/* Power related variables */
	struct diag_ws_ref_t dci_ws;
	struct diag_ws_ref_t md_ws;
+82 −25
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ static uint16_t diag_get_next_delayed_rsp_id(void)
	return rsp_id;
}

static int diag_switch_logging(int requested_mode);
static int diag_switch_logging(const int requested_mode);

#define COPY_USER_SPACE_OR_EXIT(buf, data, length)		\
do {								\
@@ -371,12 +371,25 @@ static void diag_close_logging_process(int pid)
			continue;
		}
		found = 1;
		if (logging_proc->socket_process)
		DIAG_LOG(DIAG_DEBUG_USERSPACE, "found entry pid %d\n", pid);
		if (logging_proc->socket_process) {
			logging_proc->socket_process = NULL;
		if (logging_proc->callback_process)
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting socket proc %d to NULL, proc: %d",
				 driver->md_proc[i].pid, i);
		}
		if (logging_proc->callback_process) {
			logging_proc->callback_process = NULL;
		if (driver->md_client_info.client_process)
			driver->md_client_info.client_process = NULL;
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting callback proc %d to NULL, proc: %d",
				 driver->md_proc[i].pid, i);
		}
		if (logging_proc->mdlog_process) {
			logging_proc->mdlog_process = NULL;
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting mdlog proc %d to NULL, proc: %d",
				 driver->md_proc[i].pid, i);
		}
		diag_update_proc_vote(DIAG_PROC_MEMORY_DEVICE, VOTE_DOWN, i);
	}
	mutex_unlock(&driver->diagchar_mutex);
@@ -422,6 +435,8 @@ static void diag_close_logging_process(int pid)
			if (logging_proc->pid != pid)
				continue;
			logging_proc->pid = 0;
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting logging proc to 0\n");
		}
		mutex_unlock(&driver->diagchar_mutex);
	}
@@ -1104,13 +1119,14 @@ static int mask_request_validate(unsigned char mask_buf[])
	return 0;
}

static int diag_switch_logging(int requested_mode)
static int diag_switch_logging(const int requested_mode)
{
	int i;
	int err = 0;
	int mux_mode = DIAG_USB_MODE; /* set the mode from diag_mux.h */
	int new_mode = USB_MODE;
	int current_mode = driver->logging_mode;
	int found = 0;

	switch (requested_mode) {
	case CALLBACK_MODE:
@@ -1130,30 +1146,39 @@ static int diag_switch_logging(int requested_mode)
		return -EINVAL;
	}

	DIAG_LOG(DIAG_DEBUG_USERSPACE,
		 "current: %d requested: %d translated: %d, pid: %d\n",
		 current_mode, requested_mode, new_mode, current->tgid);

	if (new_mode == current_mode) {
		if (requested_mode != MEMORY_DEVICE_MODE ||
		    driver->real_time_mode) {
			pr_info_ratelimited("diag: Already in logging mode change requested, mode: %d\n",
					    current_mode);
		}
		DIAG_LOG(DIAG_DEBUG_USERSPACE, "no mode change required\n");
		return 0;
	}

	mutex_lock(&driver->diagchar_mutex);
	if (requested_mode == MEMORY_DEVICE_MODE &&
	    driver->md_proc[DIAG_LOCAL_PROC].socket_process) {
		err = send_sig(SIGCONT,
			       driver->md_proc[DIAG_LOCAL_PROC].socket_process,
			       0);
		if (err) {
			pr_err("diag: In %s, error notifying socket process %d\n",
			       __func__, err);
		}
		driver->md_proc[DIAG_LOCAL_PROC].socket_process = NULL;
	/*
	 * When any mdlog process exits, or votes for USB mode, check if the
	 * process is the original requestor for the mode change. Don't allow
	 * any mdlog process to vote for mode change.
	 */
	if (current_mode == MEMORY_DEVICE_MODE && new_mode == USB_MODE) {
		for (i = 0; i < DIAG_NUM_PROC && !found; i++) {
			if (driver->md_proc[i].pid == current->tgid)
				found = 1;
		}

	if (new_mode == MEMORY_DEVICE_MODE)
		driver->md_client_info.client_process = current;
		if (!found) {
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "switch_logging denied pid: %d saved: %d\n",
				 current->tgid,
				 driver->md_proc[DIAG_LOCAL_PROC].pid);
			return 0;
		}
	}

	mutex_lock(&driver->diagchar_mutex);
	diag_ws_reset(DIAG_WS_MUX);
@@ -1162,11 +1187,16 @@ static int diag_switch_logging(int requested_mode)
		pr_err("diag: In %s, unable to switch mode from %d to %d\n",
		       __func__, current_mode, requested_mode);
		driver->logging_mode = current_mode;
		DIAG_LOG(DIAG_DEBUG_USERSPACE,
			 "error changing logging modes\n");
		goto fail;
	}
	driver->logging_mode = new_mode;
	pr_info("diag: Logging switched from %d to %d mode\n",
		current_mode, new_mode);
	DIAG_LOG(DIAG_DEBUG_USERSPACE,
		 "logging switched from %d to %d mode\n",
		 current_mode, new_mode);

	if (new_mode != MEMORY_DEVICE_MODE) {
		diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE,
@@ -1181,10 +1211,35 @@ static int diag_switch_logging(int requested_mode)
			   &driver->diag_real_time_work);
	}

	for (i = 0; i < DIAG_NUM_PROC; i++) {
	/*
	 * Set the pid and context for md_proc. For callback processes, the
	 * context will be set by DIAG_IOCTL_REGISTER_CALLBACK.
	 */
	for (i = 0; i < DIAG_NUM_PROC && new_mode == MEMORY_DEVICE_MODE; i++) {
		switch (requested_mode) {
		case SOCKET_MODE:
			driver->md_proc[i].pid = current->tgid;
		if (requested_mode == SOCKET_MODE)
			driver->md_proc[i].socket_process = current;
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting socket process to %d, proc: %d",
				 driver->md_proc[i].pid, i);
			break;
		case MEMORY_DEVICE_MODE:
			driver->md_proc[i].pid = current->tgid;
			driver->md_proc[i].mdlog_process = current;
			DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting mdlog process to %d, proc: %d",
				 driver->md_proc[i].pid, i);
			break;
		case CALLBACK_MODE:
			if (driver->md_proc[i].callback_process == current) {
				driver->md_proc[i].pid = current->tgid;
				DIAG_LOG(DIAG_DEBUG_USERSPACE,
				 "setting callback process to %d, proc: %d",
				 driver->md_proc[i].pid, i);
			}
			break;
		}
	}
fail:
	mutex_unlock(&driver->diagchar_mutex);
@@ -1464,10 +1519,12 @@ static int diag_ioctl_register_callback(unsigned long ioarg)
		return -EINVAL;
	}

	/*
	 * The IOCTL will just send the context for md_proc.
	 * The pid will be set by diag_switch_logging.
	 */
	mutex_lock(&driver->diagchar_mutex);
	driver->md_proc[reg.proc].pid = current->tgid;
	driver->md_proc[reg.proc].callback_process = current;
	driver->md_proc[reg.proc].socket_process = NULL;
	mutex_unlock(&driver->diagchar_mutex);

	return 0;
@@ -2848,8 +2905,8 @@ static int __init diagchar_init(void)
		driver->md_proc[i].pid = 0;
		driver->md_proc[i].callback_process = NULL;
		driver->md_proc[i].socket_process = NULL;
		driver->md_proc[i].mdlog_process = NULL;
	}
	driver->md_client_info.client_process = NULL;
	driver->mask_check = 0;
	driver->in_busy_pktdata = 0;
	driver->in_busy_dcipktdata = 0;
+27 −18
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

/* tracks which peripheral is undergoing SSR */
static uint16_t reg_dirty;
static void diag_notify_md_client(uint8_t peripheral, int data);

static void diag_mask_update_work_fn(struct work_struct *work)
{
@@ -48,6 +49,7 @@ void diag_cntl_channel_open(struct diagfwd_info *p_info)
		return;
	driver->mask_update |= PERIPHERAL_MASK(p_info->peripheral);
	queue_work(driver->cntl_wq, &driver->mask_update_work);
	diag_notify_md_client(p_info->peripheral, DIAG_STATUS_OPEN);
}

void diag_cntl_channel_close(struct diagfwd_info *p_info)
@@ -67,6 +69,8 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info)
	driver->stm_state[peripheral] = DISABLE_STM;
	driver->stm_state_requested[peripheral] = DISABLE_STM;
	reg_dirty ^= PERIPHERAL_MASK(peripheral);
	diag_notify_md_client(peripheral, DIAG_STATUS_CLOSED);

	flush_workqueue(driver->cntl_wq);
}

@@ -98,37 +102,42 @@ static void diag_stm_update_work_fn(struct work_struct *work)
	}
}

void diag_notify_md_client(uint16_t peripheral_mask, int data)
void diag_notify_md_client(uint8_t peripheral, int data)
{
	int stat;
	int stat = 0;
	struct siginfo info;

	if (driver->logging_mode != MEMORY_DEVICE_MODE)
		return;

	memset(&info, 0, sizeof(struct siginfo));
	info.si_code = SI_QUEUE;
	info.si_int = (peripheral_mask | data);
	info.si_int = (PERIPHERAL_MASK(peripheral) | data);
	info.si_signo = SIGCONT;
	stat = send_sig_info(info.si_signo,
		&info, driver->md_client_info.client_process);
	if (driver->md_proc[DIAG_LOCAL_PROC].mdlog_process) {
		stat = send_sig_info(info.si_signo, &info,
			driver->md_proc[DIAG_LOCAL_PROC].mdlog_process);
		if (stat)
			pr_err("diag: Err sending signal to memory device client, signal data: 0x%x, stat: %d\n",
			       info.si_int, stat);
	}

}

static void process_pd_status(uint8_t *buf, uint32_t len,
				uint8_t peripheral) {
	struct diag_ctrl_msg_pd_status *pd_msg =
				(struct diag_ctrl_msg_pd_status *)buf;
	uint16_t pd;
	uint8_t status;
			      uint8_t peripheral)
{
	struct diag_ctrl_msg_pd_status *pd_msg = NULL;
	uint32_t pd;
	int status = DIAG_STATUS_CLOSED;

	if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
	if (!buf || peripheral >= NUM_PERIPHERALS || len < sizeof(*pd_msg))
		return;

	pd_msg = (struct diag_ctrl_msg_pd_status *)buf;
	pd = pd_msg->pd_id;
	status = pd_msg->status;
	if (driver->logging_mode == MEMORY_DEVICE_MODE) {
		diag_notify_md_client(PERIPHERAL_MASK(peripheral), status);
	}
	status = (pd_msg->status == 0) ? DIAG_STATUS_OPEN : DIAG_STATUS_CLOSED;
	diag_notify_md_client(peripheral, status);
}

static void enable_stm_feature(uint8_t peripheral)
+0 −1
Original line number Diff line number Diff line
@@ -277,5 +277,4 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
				    struct diag_buffering_mode_t *params);
int diag_send_buffering_wm_values(uint8_t peripheral,
				  struct diag_buffering_mode_t *params);
void diag_notify_md_client(uint16_t peripheral_mask, int data);
#endif
+0 −8
Original line number Diff line number Diff line
@@ -76,10 +76,6 @@ static void diagfwd_cntl_open(struct diagfwd_info *fwd_info)
{
	if (!fwd_info)
		return;
	if (driver->logging_mode == MEMORY_DEVICE_MODE) {
		diag_notify_md_client(PERIPHERAL_MASK(fwd_info->peripheral),
							  DIAG_STATUS_OPEN);
	}
	diag_cntl_channel_open(fwd_info);
}

@@ -87,10 +83,6 @@ static void diagfwd_cntl_close(struct diagfwd_info *fwd_info)
{
	if (!fwd_info)
		return;
	if (driver->logging_mode == MEMORY_DEVICE_MODE) {
		diag_notify_md_client(PERIPHERAL_MASK(fwd_info->peripheral),
							  DIAG_STATUS_CLOSED);
	}
	diag_cntl_channel_close(fwd_info);
}