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

Commit fc695af6 authored by Hemant Kumar's avatar Hemant Kumar
Browse files

usb: gadget: Add snapshot of USB QDSS Function driver



This change adds USB QDSS function driver which allows communication
between USB BAM and QDSS BAM for QDSS debug functionality over USB.
This snapshot is taken as of msm-4.14 commit <f6f026ce6fe6> ("Merge
"soc: qcom: sysmon-qmi: Fix duplicate BEFORE_POWERUP SSCTL events"").

Change-Id: If322e3a73b4e769d42a4bd6366ee62a0b39cd338
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent 3e70a303
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -232,6 +232,9 @@ config USB_F_AUDIO_SRC
config USB_F_ACC
	tristate

config USB_F_QDSS
	tristate

# this first set of drivers all depend on bulk-capable hardware.

config USB_CONFIGFS
@@ -557,6 +560,16 @@ config USB_CONFIGFS_F_CCID
	  allowing a userspace component to be able to provide the
	  implementation necessary to interface with the smartcard.

config USB_CONFIGFS_F_QDSS
	bool "USB QDSS function"
	select USB_F_QDSS
	depends on USB_CONFIGFS
	help
	  USB QDSS function driver to get hwtracing related data over
	  USB. USB QDSS function driver which allows communication
	  between USB BAM and QDSS BAM for QDSS debug functionality
	  over USB.

choice
	tristate "USB Gadget precomposed configurations"
	default USB_ETH
+2 −0
Original line number Diff line number Diff line
@@ -60,3 +60,5 @@ usb_f_audio_source-y := f_audio_source.o
obj-$(CONFIG_USB_F_AUDIO_SRC)   += usb_f_audio_source.o
usb_f_accessory-y               := f_accessory.o
obj-$(CONFIG_USB_F_ACC)         += usb_f_accessory.o
usb_f_qdss-y			:= f_qdss.o u_qdss.o
obj-$(CONFIG_USB_F_QDSS)	+= usb_f_qdss.o
+1214 −0

File added.

Preview size limit exceeded, changes collapsed.

+75 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
 */

#ifndef _F_QDSS_H
#define _F_QDSS_H

#include <linux/kernel.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/composite.h>
#include <linux/usb/usb_qdss.h>

enum qti_port_type {
	QTI_PORT_RMNET,
	QTI_PORT_DPL,
	QTI_NUM_PORTS
};

struct usb_qdss_bam_connect_info {
	u32 usb_bam_pipe_idx;
	u32 peer_pipe_idx;
	unsigned long usb_bam_handle;
	struct sps_mem_buffer *data_fifo;
	unsigned long qdss_bam_iova;
	phys_addr_t qdss_bam_phys;
	u32 qdss_bam_size;
};

struct gqdss {
	struct usb_function function;
	struct usb_ep *ctrl_out;
	struct usb_ep *ctrl_in;
	struct usb_ep *data;
	int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
	void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
};

/* struct f_qdss - USB qdss function driver private structure */
struct f_qdss {
	struct gqdss port;
	struct usb_qdss_bam_connect_info bam_info;
	struct usb_gadget *gadget;
	short int port_num;
	u8 ctrl_iface_id;
	u8 data_iface_id;
	int usb_connected;
	bool debug_inface_enabled;
	struct usb_request *endless_req;
	struct usb_qdss_ch ch;
	struct list_head ctrl_read_pool;
	struct list_head ctrl_write_pool;

	/* for mdm channel SW path */
	struct list_head data_write_pool;

	struct work_struct connect_w;
	struct work_struct disconnect_w;
	spinlock_t lock;
	unsigned int data_enabled:1;
	unsigned int ctrl_in_enabled:1;
	unsigned int ctrl_out_enabled:1;
	struct workqueue_struct *wq;
};

struct usb_qdss_opts {
	struct usb_function_instance func_inst;
	struct f_qdss *usb_qdss;
	char *channel_name;
};

int uninit_data(struct usb_ep *ep);
int set_qdss_data_connection(struct f_qdss *qdss, int enable);
#endif
+149 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
 */

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/usb_bam.h>
#include <linux/dma-mapping.h>

#include "f_qdss.h"
static int alloc_sps_req(struct usb_ep *data_ep)
{
	struct usb_request *req = NULL;
	struct f_qdss *qdss = data_ep->driver_data;
	u32 sps_params = 0;

	pr_debug("send_sps_req\n");

	req = usb_ep_alloc_request(data_ep, GFP_ATOMIC);
	if (!req) {
		pr_err("usb_ep_alloc_request failed\n");
		return -ENOMEM;
	}

	req->length = 32*1024;
	sps_params = MSM_SPS_MODE | MSM_DISABLE_WB |
			qdss->bam_info.usb_bam_pipe_idx;
	req->udc_priv = sps_params;
	qdss->endless_req = req;

	return 0;
}

static int init_data(struct usb_ep *ep);
int set_qdss_data_connection(struct f_qdss *qdss, int enable)
{
	enum usb_ctrl		usb_bam_type;
	int			res = 0;
	int			idx;
	struct usb_qdss_bam_connect_info bam_info;
	struct usb_gadget *gadget;
	struct device *dev;
	int ret;

	pr_debug("%s\n", __func__);

	if (!qdss) {
		pr_err("%s: qdss ptr is NULL\n", __func__);
		return -EINVAL;
	}

	gadget = qdss->gadget;
	usb_bam_type = usb_bam_get_bam_type(gadget->name);
	dev = gadget->dev.parent;

	bam_info = qdss->bam_info;
	/* There is only one qdss pipe, so the pipe number can be set to 0 */
	idx = usb_bam_get_connection_idx(usb_bam_type, QDSS_P_BAM,
		PEER_PERIPHERAL_TO_USB, 0);
	if (idx < 0) {
		pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
		return idx;
	}

	if (enable) {
		ret = get_qdss_bam_info(usb_bam_type, idx,
				&bam_info.qdss_bam_phys,
				&bam_info.qdss_bam_size);
		if (ret) {
			pr_err("%s(): failed to get qdss bam info err(%d)\n",
								__func__, ret);
			return ret;
		}

		bam_info.qdss_bam_iova = dma_map_resource(dev->parent,
				bam_info.qdss_bam_phys, bam_info.qdss_bam_size,
				DMA_BIDIRECTIONAL, 0);
		if (!bam_info.qdss_bam_iova) {
			pr_err("dma_map_resource failed\n");
			return -ENOMEM;
		}

		usb_bam_alloc_fifos(usb_bam_type, idx);
		bam_info.data_fifo =
			kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL);
		if (!bam_info.data_fifo) {
			usb_bam_free_fifos(usb_bam_type, idx);
			return -ENOMEM;
		}

		pr_debug("%s(): qdss_bam: iova:%lx p_addr:%lx size:%x\n",
				__func__, bam_info.qdss_bam_iova,
				(unsigned long)bam_info.qdss_bam_phys,
				bam_info.qdss_bam_size);

		get_bam2bam_connection_info(usb_bam_type, idx,
				&bam_info.usb_bam_pipe_idx,
				NULL, bam_info.data_fifo, NULL);

		alloc_sps_req(qdss->port.data);
		msm_data_fifo_config(qdss->port.data,
			bam_info.data_fifo->iova,
			bam_info.data_fifo->size,
			bam_info.usb_bam_pipe_idx);
		init_data(qdss->port.data);

		res = usb_bam_connect(usb_bam_type, idx,
					&(bam_info.usb_bam_pipe_idx),
					bam_info.qdss_bam_iova);
	} else {
		res = usb_bam_disconnect_pipe(usb_bam_type, idx);
		if (res)
			pr_err("usb_bam_disconnection error\n");
		dma_unmap_resource(dev->parent, bam_info.qdss_bam_iova,
				bam_info.qdss_bam_size, DMA_BIDIRECTIONAL, 0);
		usb_bam_free_fifos(usb_bam_type, idx);
		kfree(bam_info.data_fifo);
	}

	return res;
}

static int init_data(struct usb_ep *ep)
{
	struct f_qdss *qdss = ep->driver_data;
	int res = 0;

	pr_debug("%s\n", __func__);

	res = msm_ep_config(ep, qdss->endless_req);
	if (res)
		pr_err("msm_ep_config failed\n");

	return res;
}

int uninit_data(struct usb_ep *ep)
{
	int res = 0;

	pr_debug("%s\n", __func__);

	res = msm_ep_unconfig(ep);
	if (res)
		pr_err("msm_ep_unconfig failed\n");

	return res;
}
Loading