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

Commit 47d3f671 authored by Gustavo Solaira's avatar Gustavo Solaira Committed by Gerrit - the friendly Code Review server
Browse files

diag: Read the HSIC data in a work queue



Add a new work queue to process the HSIC diag
data instead of processing it in the interrupt
context.

Change-Id: I8c546cd608c662d1c3133194f70af4953d734b08
Signed-off-by: default avatarGustavo Solaira <gustavos@codeaurora.org>
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent 8df961c7
Loading
Loading
Loading
Loading
+87 −4
Original line number Diff line number Diff line
@@ -50,10 +50,65 @@ struct diag_hsic_info diag_hsic[NUM_HSIC_DEV] = {
	}
};

static int hsic_buf_tbl_push(struct diag_hsic_info *ch, void *buf, int len)
{
	unsigned long flags;
	struct diag_hsic_buf_tbl_t *item;

	item = kzalloc(sizeof(struct diag_hsic_buf_tbl_t), GFP_ATOMIC);
	if (!item)
		return -ENOMEM;
	kmemleak_not_leak(item);

	spin_lock_irqsave(&ch->lock, flags);
	item->buf = buf;
	item->len = len;
	list_add_tail(&item->link, &ch->buf_tbl);
	spin_unlock_irqrestore(&ch->lock, flags);

	return 0;
}

static struct diag_hsic_buf_tbl_t *hsic_buf_tbl_pop(struct diag_hsic_info *ch)
{
	unsigned long flags;
	struct diag_hsic_buf_tbl_t *item = NULL;

	if (!ch || list_empty(&ch->buf_tbl))
		return NULL;

	spin_lock_irqsave(&ch->lock, flags);
	item = list_first_entry(&ch->buf_tbl, struct diag_hsic_buf_tbl_t, link);
	list_del(&item->link);
	spin_unlock_irqrestore(&ch->lock, flags);

	return item;
}

static void hsic_buf_tbl_clear(struct diag_hsic_info *ch)
{
	unsigned long flags;
	struct list_head *start, *temp;
	struct diag_hsic_buf_tbl_t *item = NULL;

	if (!ch)
		return;

	/* At this point, the channel should already by closed */
	spin_lock_irqsave(&ch->lock, flags);
	list_for_each_safe(start, temp, &ch->buf_tbl) {
		item = list_entry(start, struct diag_hsic_buf_tbl_t,
				  link);
		list_del(&item->link);
		kfree(item);

	}
	spin_unlock_irqrestore(&ch->lock, flags);
}

static void diag_hsic_read_complete(void *ctxt, char *buf, int len,
				    int actual_size)
{
	int err = 0;
	int index = (int)(uintptr_t)ctxt;
	struct diag_hsic_info *ch = NULL;

@@ -69,11 +124,14 @@ static void diag_hsic_read_complete(void *ctxt, char *buf, int len,
	 * completes. Also, actual size can be negative error codes - do not
	 * pass on the buffer.
	 */
	if (!ch->opened || actual_size <= 0)
	if (!ch->opened || !buf || actual_size <= 0)
		goto fail;
	err = diag_remote_dev_read_done(ch->dev_id, buf, actual_size);
	if (err)
	if (hsic_buf_tbl_push(ch, buf, actual_size)) {
		pr_err_ratelimited("diag: In %s, OOM! Drop incoming packet\n",
				   __func__);
		goto fail;
	}
	queue_work(ch->hsic_wq, &ch->read_complete_work);
	return;

fail:
@@ -183,6 +241,7 @@ static int hsic_open(int id)
	diagmem_init(driver, ch->mempool);
	/* Notify the bridge that the channel is open */
	diag_remote_dev_open(ch->dev_id);
	INIT_LIST_HEAD(&ch->buf_tbl);
	queue_work(ch->hsic_wq, &(ch->read_work));
	return 0;
}
@@ -220,6 +279,7 @@ static int hsic_close(int id)
	diag_bridge_close(ch->id);
	diagmem_exit(driver, ch->mempool);
	diag_remote_dev_close(ch->dev_id);
	hsic_buf_tbl_clear(ch);
	return 0;
}

@@ -261,6 +321,27 @@ static void hsic_read_work_fn(struct work_struct *work)
		queue_work(ch->hsic_wq, &ch->read_work);
}

static void hsic_read_complete_work_fn(struct work_struct *work)
{
	struct diag_hsic_info *ch = container_of(work, struct diag_hsic_info,
						 read_complete_work);
	struct diag_hsic_buf_tbl_t *item;

	item = hsic_buf_tbl_pop(ch);
	if (item) {
		if (diag_remote_dev_read_done(ch->dev_id, item->buf, item->len))
			goto fail;
	}

	kfree(item);
	return;

fail:
	diagmem_free(driver, item->buf, ch->mempool);
	queue_work(ch->hsic_wq, &ch->read_work);
	kfree(item);
}

static int diag_hsic_probe(struct platform_device *pdev)
{
	unsigned long flags;
@@ -406,6 +487,8 @@ int diag_hsic_init(void)
		ch = &diag_hsic[i];
		spin_lock_init(&ch->lock);
		INIT_WORK(&(ch->read_work), hsic_read_work_fn);
		INIT_WORK(&(ch->read_complete_work),
			  hsic_read_complete_work_fn);
		INIT_WORK(&(ch->open_work), hsic_open_work_fn);
		INIT_WORK(&(ch->close_work), hsic_close_work_fn);
		strlcpy(wq_name, "DIAG_HSIC_", sizeof(wq_name));
+11 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2014, 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2014, 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -12,6 +12,8 @@

#ifndef DIAGFWD_HSIC_H
#define DIAGFWD_HSIC_H

#include <linux/list.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <linux/usb/usbdiag.h>
#endif
@@ -23,6 +25,12 @@

#define DIAG_HSIC_NAME_SZ	24

struct diag_hsic_buf_tbl_t {
	struct list_head link;
	unsigned char *buf;
	int len;
};

struct diag_hsic_info {
	int id;
	int dev_id;
@@ -32,10 +40,12 @@ struct diag_hsic_info {
	uint8_t suspended;
	char name[DIAG_HSIC_NAME_SZ];
	struct work_struct read_work;
	struct work_struct read_complete_work;
	struct work_struct open_work;
	struct work_struct close_work;
	struct workqueue_struct *hsic_wq;
	spinlock_t lock;
	struct list_head buf_tbl;
};

extern struct diag_hsic_info diag_hsic[NUM_HSIC_DEV];