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

Commit f965d067 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "coresight: add transferring small packets support for sw usb"

parents 03bfdef6 fd84f4e0
Loading
Loading
Loading
Loading
+147 −55
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/usb/usb_qdss.h>
#include <linux/time.h>

#include "coresight-byte-cntr.h"
#include "coresight-priv.h"
@@ -19,6 +20,7 @@
#define USB_BLK_SIZE 65536
#define USB_SG_NUM (USB_BLK_SIZE / PAGE_SIZE)
#define USB_BUF_NUM 255
#define USB_TIME_OUT (5 * HZ)

static struct tmc_drvdata *tmcdrvdata;

@@ -315,71 +317,158 @@ static int byte_cntr_register_chardev(struct byte_cntr *byte_cntr_data)
	return ret;
}

static int usb_transfer_small_packet(struct qdss_request *usb_req,
			struct byte_cntr *drvdata, size_t *small_size)
{
	int ret = 0;
	struct etr_buf *etr_buf = tmcdrvdata->etr_buf;
	size_t req_size, actual;
	long w_offset;

	w_offset = tmc_sg_get_rwp_offset(tmcdrvdata);
	req_size = ((w_offset < drvdata->offset) ? etr_buf->size : 0) +
				w_offset - drvdata->offset;
	req_size = (req_size < USB_BLK_SIZE) ? req_size : USB_BLK_SIZE;

	while (req_size > 0) {

		usb_req = devm_kzalloc(tmcdrvdata->dev, sizeof(*usb_req),
			GFP_KERNEL);
		if (!usb_req) {
			ret = -EFAULT;
			goto out;
		}

		actual = tmc_etr_buf_get_data(etr_buf, drvdata->offset,
					req_size, &usb_req->buf);
		usb_req->length = actual;
		drvdata->usb_req = usb_req;
		req_size -= actual;

		if ((drvdata->offset + actual) >= tmcdrvdata->size)
			drvdata->offset = 0;
		else
			drvdata->offset += actual;

		*small_size += actual;

		if (atomic_read(&drvdata->usb_free_buf) > 0) {
			ret = usb_qdss_write(tmcdrvdata->usbch, usb_req);

			if (ret) {
				devm_kfree(tmcdrvdata->dev, usb_req);
				usb_req = NULL;
				drvdata->usb_req = NULL;
				dev_err(tmcdrvdata->dev,
					"Write data failed:%d\n", ret);
				goto out;
			}

			atomic_dec(&drvdata->usb_free_buf);
		} else {
			dev_dbg(tmcdrvdata->dev,
			"Drop data, offset = %d, len = %d\n",
				drvdata->offset, req_size);
			devm_kfree(tmcdrvdata->dev, usb_req);
			drvdata->usb_req = NULL;
		}
	}

out:
	return ret;
}

static void usb_read_work_fn(struct work_struct *work)
{
	int ret, i, seq = 0;
	struct qdss_request *usb_req = NULL;
	struct etr_buf *etr_buf = tmcdrvdata->etr_buf;
	size_t actual, req_size;
	size_t actual, req_size, req_sg_num, small_size = 0;
	char *buf;
	struct byte_cntr *drvdata =
		container_of(work, struct byte_cntr, read_work);


	while (tmcdrvdata->enable
		&& tmcdrvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
		if (!atomic_read(&drvdata->irq_cnt)) {
			ret = wait_event_interruptible(drvdata->usb_wait_wq,
			ret =  wait_event_interruptible_timeout(
				drvdata->usb_wait_wq,
				atomic_read(&drvdata->irq_cnt) > 0
				|| !tmcdrvdata->enable || tmcdrvdata->out_mode
				!= TMC_ETR_OUT_MODE_USB
				|| !drvdata->read_active);
				|| !drvdata->read_active, USB_TIME_OUT);
			if (ret == -ERESTARTSYS || !tmcdrvdata->enable
			|| tmcdrvdata->out_mode != TMC_ETR_OUT_MODE_USB
			|| !drvdata->read_active)
				break;

			if (ret == 0) {
				ret = usb_transfer_small_packet(usb_req,
						drvdata, &small_size);
				if (ret && ret != -EAGAIN)
					return;
				continue;
			}
		}

		req_size = USB_BLK_SIZE;
		req_size = USB_BLK_SIZE - small_size;
		small_size = 0;

		if (req_size > 0) {
			seq++;
		usb_req = devm_kzalloc(tmcdrvdata->dev, sizeof(*usb_req),
					GFP_KERNEL);
			req_sg_num = (req_size - 1) / PAGE_SIZE + 1;
			usb_req = devm_kzalloc(tmcdrvdata->dev,
						sizeof(*usb_req), GFP_KERNEL);
			if (!usb_req)
				return;
			usb_req->sg = devm_kzalloc(tmcdrvdata->dev,
			sizeof(*(usb_req->sg)) * USB_SG_NUM, GFP_KERNEL);
					sizeof(*(usb_req->sg)) * req_sg_num,
					GFP_KERNEL);
			if (!usb_req->sg) {
			devm_kfree(tmcdrvdata->dev, usb_req->sg);
				devm_kfree(tmcdrvdata->dev, usb_req);
				usb_req = NULL;
				return;
			}
		usb_req->length = USB_BLK_SIZE;
		drvdata->usb_req = usb_req;
		for (i = 0; i < USB_SG_NUM; i++) {
			actual = tmc_etr_buf_get_data(etr_buf, drvdata->offset,

			for (i = 0; i < req_sg_num; i++) {
				actual = tmc_etr_buf_get_data(etr_buf,
							drvdata->offset,
							PAGE_SIZE, &buf);

				if (actual <= 0) {
				devm_kfree(tmcdrvdata->dev, usb_req->sg);
					devm_kfree(tmcdrvdata->dev,
							usb_req->sg);
					devm_kfree(tmcdrvdata->dev, usb_req);
					usb_req = NULL;
					dev_err(tmcdrvdata->dev, "No data in ETR\n");
					return;
				}

				sg_set_buf(&usb_req->sg[i], buf, actual);

				if (i == 0)
					usb_req->buf = buf;
			req_size -= actual;
			if ((drvdata->offset + actual) >= tmcdrvdata->size)
				if (i == req_sg_num - 1)
					sg_mark_end(&usb_req->sg[i]);

				if ((drvdata->offset + actual) >=
					tmcdrvdata->size)
					drvdata->offset = 0;
				else
					drvdata->offset += actual;
			if (i == USB_SG_NUM - 1)
				sg_mark_end(&usb_req->sg[i]);
			}

			usb_req->length = req_size;
			drvdata->usb_req = usb_req;
			usb_req->num_sgs = i;

			if (atomic_read(&drvdata->usb_free_buf) > 0) {
				ret = usb_qdss_write(tmcdrvdata->usbch,
						drvdata->usb_req);
				if (ret) {
				devm_kfree(tmcdrvdata->dev, usb_req->sg);
					devm_kfree(tmcdrvdata->dev,
							usb_req->sg);
					devm_kfree(tmcdrvdata->dev, usb_req);
					usb_req = NULL;
					drvdata->usb_req = NULL;
@@ -400,6 +489,8 @@ static void usb_read_work_fn(struct work_struct *work)
				devm_kfree(tmcdrvdata->dev, usb_req);
				drvdata->usb_req = NULL;
			}
		}

		if (atomic_read(&drvdata->irq_cnt) > 0)
			atomic_dec(&drvdata->irq_cnt);
	}
@@ -412,6 +503,7 @@ static void usb_write_done(struct byte_cntr *drvdata,
	atomic_inc(&drvdata->usb_free_buf);
	if (d_req->status)
		pr_err_ratelimited("USB write failed err:%d\n", d_req->status);
	if (d_req->sg)
		devm_kfree(tmcdrvdata->dev, d_req->sg);
	devm_kfree(tmcdrvdata->dev, d_req);
}
+14 −0
Original line number Diff line number Diff line
@@ -215,6 +215,20 @@ void tmc_free_sg_table(struct tmc_sg_table *sg_table)
	tmc_free_data_pages(sg_table);
}

long tmc_sg_get_rwp_offset(struct tmc_drvdata *drvdata)
{
	struct etr_buf *etr_buf = drvdata->etr_buf;
	struct etr_sg_table *etr_table = etr_buf->private;
	struct tmc_sg_table *table = etr_table->sg_table;
	u64 rwp;
	long w_offset;

	rwp = tmc_read_rwp(drvdata);
	w_offset = tmc_sg_get_data_page_offset(table, rwp);

	return w_offset;
}

/*
 * Alloc pages for the table. Since this will be used by the device,
 * allocate the pages closer to the device (i.e, dev_to_node(dev)
+1 −1
Original line number Diff line number Diff line
@@ -325,7 +325,7 @@ ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
ssize_t tmc_etr_buf_get_data(struct etr_buf *etr_buf,
				u64 offset, size_t len, char **bufpp);
int tmc_etr_switch_mode(struct tmc_drvdata *drvdata, const char *out_mode);

long tmc_sg_get_rwp_offset(struct tmc_drvdata *drvdata);

#define TMC_REG_PAIR(name, lo_off, hi_off)				\
static inline u64							\