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

Commit 59ebcf71 authored by Pavankumar Kondeti's avatar Pavankumar Kondeti Committed by Gerrit - the friendly Code Review server
Browse files

USB: gadget: add BAM-DMUX transport for DPL function



A new logical BAM-DMUX channel is created for routing the DPL traffic.
Add BAM-DMUX transport support for the QDSS function driver that is
used for the DPL function. The QTI control transport is already
in place for the DPL function. Update the BAM-DMUX logical channel
assigned for DPL so that user space can query it via EP_LOOKUP
ioctl.

DPL function has only 1 IN endpoint. The BAM transport (u_bam) module
is modified not to access OUT endpoint structure when it is NULL. The
BAM and BAM2BAM ports allocation is separated to return the newly
created port index. Remove the hard coded BAM-DMUX channel numbers
in u_bam and i_ctrl_qti modules and directly use the enums defined
in the BAM-DMUX header file.

Change-Id: I35e53eeeed5e71d52fa23e9c8326ef218c7c2fe8
Signed-off-by: default avatarPavankumar Kondeti <pkondeti@codeaurora.org>
parent d4561841
Loading
Loading
Loading
Loading
+50 −3
Original line number Diff line number Diff line
@@ -24,11 +24,13 @@
#include "u_qdss.c"
#include "usb_gadget_xport.h"
#include "u_data_ipa.h"
#include "u_rmnet.h"

static unsigned int nr_qdss_ports;
static unsigned int no_data_bam_ports;
static unsigned int data_hsic_ports_no;
static unsigned int no_ipa_ports;
static unsigned int no_bam_dmux_ports;

static struct qdss_ports {
	enum transport_type		data_xport;
@@ -38,6 +40,7 @@ static struct qdss_ports {
	unsigned	char		port_num;
	struct f_qdss			*port;
	struct gadget_ipa_port		ipa_port;
	struct grmnet			bam_dmux_port;
} qdss_ports[NR_QDSS_PORTS];


@@ -539,6 +542,10 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
		gp = &qdss_ports[qdss->port_num].ipa_port;
		ipa_data_disconnect(gp, qdss->port_num);
		break;
	case USB_GADGET_XPORT_BAM_DMUX:
		gbam_disconnect(&qdss_ports[qdss->port_num].bam_dmux_port,
				portno, USB_GADGET_XPORT_BAM);
		break;
	case USB_GADGET_XPORT_HSIC:
		pr_debug("usb_qdss_disconnect_work: HSIC transport\n");
		ghsic_data_disconnect(&qdss->port, portno);
@@ -582,6 +589,7 @@ static void qdss_disable(struct usb_function *f)
	qdss->usb_connected = 0;
	switch (dxport) {
	case USB_GADGET_XPORT_BAM2BAM_IPA:
	case USB_GADGET_XPORT_BAM_DMUX:
		spin_unlock_irqrestore(&qdss->lock, flags);
		usb_qdss_disconnect_work(&qdss->disconnect_w);
		return;
@@ -717,6 +725,16 @@ static void usb_qdss_connect_work(struct work_struct *work)
		}
		qdss->data_enabled = 1;
		break;
	case USB_GADGET_XPORT_BAM_DMUX:
		qdss_ports[qdss->port_num].bam_dmux_port.gadget =
						qdss->cdev->gadget;
		qdss_ports[qdss->port_num].bam_dmux_port.in =
						qdss->port.data;
		status = gbam_connect(&qdss_ports[qdss->port_num].bam_dmux_port,
				port_num, USB_GADGET_XPORT_BAM, 0, 0);
		if (status)
			pr_err("BAM_DMUX connect failed with %d\n", status);
		break;
	case USB_GADGET_XPORT_HSIC:
		pr_debug("usb_qdss_connect_work: HSIC transport\n");
		status = ghsic_data_connect(&qdss->port, port_num);
@@ -770,7 +788,8 @@ static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			goto fail;
		}

		if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA) {
		if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA ||
				dxport == USB_GADGET_XPORT_BAM_DMUX) {
			qdss->usb_connected = 1;
			usb_qdss_connect_work(&qdss->connect_w);
			return 0;
@@ -1163,6 +1182,9 @@ static int qdss_init_port(const char *ctrl_name, const char *data_name,
		return -EINVAL;
	}

	pr_debug("ctrl name = %s data_name %s port_name %s\n",
			ctrl_name, data_name, port_name);

	pr_debug("%s: port#:%d, data port: %s\n",
		__func__, nr_qdss_ports, data_name);

@@ -1211,6 +1233,11 @@ static int qdss_init_port(const char *ctrl_name, const char *data_name,
		qdss_port->data_xport_num = data_hsic_ports_no;
		data_hsic_ports_no++;
		break;
	case USB_GADGET_XPORT_BAM_DMUX:
		qdss_port->data_xport_num = no_bam_dmux_ports;
		no_bam_dmux_ports++;
		pr_debug("USB_GADGET_XPORT_BAM_DMUX %u\n", no_bam_dmux_ports);
		break;
	case USB_GADGET_XPORT_NONE:
		break;
	default:
@@ -1230,6 +1257,7 @@ fail_probe:
	no_data_bam_ports = 0;
	data_hsic_ports_no = 0;
	no_ipa_ports = 0;
	no_bam_dmux_ports = 0;
	return ret;
}

@@ -1238,9 +1266,9 @@ static int qdss_gport_setup(void)
	int	port_idx;
	int	i;

	pr_debug("%s: bam ports: %u data hsic ports: %u nr_qdss_ports: %u ipa_ports:%u\n",
	pr_debug("%s: bam ports: %u data hsic ports: %u ipa_ports:%u bam_dmux_port:%u nr_qdss_ports:%u\n",
			__func__, no_data_bam_ports, data_hsic_ports_no,
			nr_qdss_ports, no_ipa_ports);
			no_ipa_ports, no_bam_dmux_ports, nr_qdss_ports);

	if (data_hsic_ports_no) {
		pr_debug("%s: go to setup hsic data\n", __func__);
@@ -1279,5 +1307,24 @@ static int qdss_gport_setup(void)
		}
	}

	if (no_bam_dmux_ports) {
		port_idx = gbam_setup(no_bam_dmux_ports);
		if (port_idx < 0) {
			pr_err("%s(): gbam_setup failed with %d\n",
					__func__, port_idx);
			return port_idx;
		}

		for (i = 0; i < no_bam_dmux_ports; i++) {
			if (qdss_ports[i].data_xport ==
					USB_GADGET_XPORT_BAM_DMUX) {
				qdss_ports[i].data_xport_num = port_idx;
				pr_debug("%s: BAM-DMUX data_xport_num = %d\n",
					__func__, qdss_ports[i].data_xport_num);
				port_idx++;
			}
		}
	}

	return 0;
}
+9 −4
Original line number Diff line number Diff line
@@ -318,10 +318,15 @@ static int rmnet_gport_setup(void)
		no_data_hsic_ports, no_data_hsuart_ports, no_ctrl_smd_ports,
		no_ctrl_hsic_ports, no_ctrl_hsuart_ports, nr_rmnet_ports);

	if (no_data_bam_ports || no_data_bam2bam_ports) {
		ret = gbam_setup(no_data_bam_ports,
				 no_data_bam2bam_ports);
		if (ret)
	if (no_data_bam_ports) {
		ret = gbam_setup(no_data_bam_ports);
		if (ret < 0)
			return ret;
	}

	if (no_data_bam2bam_ports) {
		ret = gbam2bam_setup(no_data_bam2bam_ports);
		if (ret < 0)
			return ret;
	}

+99 −37
Original line number Diff line number Diff line
@@ -31,16 +31,20 @@
#include "usb_gadget_xport.h"
#include "u_rmnet.h"

#define BAM_N_PORTS	 1
#define BAM_N_PORTS	 2
#define BAM2BAM_N_PORTS	 4

static struct workqueue_struct *gbam_wq;
static int n_bam_ports;
static int n_bam2bam_ports;
static unsigned n_tx_req_queued;
static unsigned bam_ch_ids[] = { 8 };

static const char *bam_ch_names[] = { "bam_dmux_ch_8" };
static unsigned bam_ch_ids[BAM_N_PORTS] = {
	BAM_DMUX_USB_RMNET_0,
	BAM_DMUX_USB_DPL
};

static char bam_ch_names[BAM_N_PORTS][BAM_DMUX_CH_NAME_MAX_LEN];

static const enum ipa_client_type usb_prod[BAM2BAM_N_PORTS] = {
	IPA_CLIENT_USB_PROD, IPA_CLIENT_USB2_PROD,
@@ -788,7 +792,7 @@ static void gbam_start_rx(struct gbam_port *port)
	struct sk_buff			*skb;

	spin_lock_irqsave(&port->port_lock_ul, flags);
	if (!port->port_usb) {
	if (!port->port_usb || !port->port_usb->out) {
		spin_unlock_irqrestore(&port->port_lock_ul, flags);
		return;
	}
@@ -1030,7 +1034,7 @@ static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
static int _gbam_start_io(struct gbam_port *port, bool in)
{
	unsigned long		flags;
	int			ret;
	int			ret = 0;
	struct usb_ep		*ep;
	struct list_head	*idle;
	unsigned		queue_size;
@@ -1055,6 +1059,8 @@ static int _gbam_start_io(struct gbam_port *port, bool in)
		ep_complete = gbam_epin_complete;
	} else {
		ep = port->port_usb->out;
		if (!ep)
			goto out;
		idle = &port->data_ch.rx_idle;
		queue_size = bam_mux_rx_q_size;
		ep_complete = gbam_epout_complete;
@@ -1062,6 +1068,7 @@ static int _gbam_start_io(struct gbam_port *port, bool in)

	ret = gbam_alloc_requests(ep, idle, queue_size, ep_complete,
			GFP_ATOMIC);
out:
	spin_unlock_irqrestore(spinlock, flags);
	if (ret)
		pr_err("%s: allocation failed\n", __func__);
@@ -1248,6 +1255,7 @@ static void gbam_connect_work(struct work_struct *w)
				__func__, d->id, ret);
		return;
	}

	set_bit(BAM_CH_OPENED, &d->flags);

	gbam_start_io(port);
@@ -1800,6 +1808,8 @@ static int gbam_port_alloc(int portno)

	bam_ports[portno].port = port;

	scnprintf(bam_ch_names[portno], BAM_DMUX_CH_NAME_MAX_LEN,
			"bam_dmux_ch_%d", bam_ch_ids[portno]);
	pdrv = &bam_ports[portno].pdrv;
	pdrv->probe = gbam_data_ch_probe;
	pdrv->remove = gbam_data_ch_remove;
@@ -1969,6 +1979,9 @@ static void gbam_debugfs_init(void)
{
	struct dentry *dfile;

	if (gbam_dent)
		return;

	gbam_dent = debugfs_create_dir("usb_rmnet", 0);
	if (!gbam_dent || IS_ERR(gbam_dent))
		return;
@@ -2060,6 +2073,7 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
	spin_unlock_irqrestore(&port->port_lock_ul, flags_ul);

	/* disable endpoints */
	if (gr->out)
		usb_ep_disable(gr->out);
	usb_ep_disable(gr->in);

@@ -2068,17 +2082,17 @@ void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans)
	 * disable.
	 */
	if (d->trans == USB_GADGET_XPORT_BAM2BAM ||
		d->trans == USB_GADGET_XPORT_BAM2BAM_IPA ||
		d->trans == USB_GADGET_XPORT_BAM) {
		d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {

		if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
			gr->in->endless = false;

		if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM)
		if (d->src_pipe_type == USB_BAM_PIPE_BAM2BAM && gr->out)
			gr->out->endless = false;
	}

	gr->in->driver_data = NULL;
	if (gr->out)
		gr->out->driver_data = NULL;

	if (trans == USB_GADGET_XPORT_BAM ||
@@ -2102,6 +2116,7 @@ int gbam_connect(struct grmnet *gr, u8 port_num,
	unsigned long		flags, flags_ul;

	pr_debug("%s: grmnet:%p port#%d\n", __func__, gr, port_num);

	if (!gr) {
		pr_err("%s: grmnet port is null\n", __func__);
		return -ENODEV;
@@ -2197,8 +2212,7 @@ int gbam_connect(struct grmnet *gr, u8 port_num,
	 * USB Endpoint.
	 */
	if (d->trans == USB_GADGET_XPORT_BAM2BAM ||
		d->trans == USB_GADGET_XPORT_BAM2BAM_IPA ||
		d->trans == USB_GADGET_XPORT_BAM) {
		d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {

		if (d->dst_pipe_type == USB_BAM_PIPE_BAM2BAM)
			port->port_usb->in->endless = true;
@@ -2215,6 +2229,12 @@ int gbam_connect(struct grmnet *gr, u8 port_num,
	}
	gr->in->driver_data = port;

	/*
	 * DPL traffic is routed through BAM-DMUX on some targets.
	 * DPL function has only 1 IN endpoint. Add out endpoint
	 * checks for BAM-DMUX transport.
	 */
	if (gr->out) {
		ret = usb_ep_enable(gr->out);
		if (ret) {
			pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
@@ -2223,6 +2243,7 @@ int gbam_connect(struct grmnet *gr, u8 port_num,
			goto exit;
		}
		gr->out->driver_data = port;
	}

	port->last_event = U_BAM_CONNECT_E;
	/*
@@ -2239,30 +2260,34 @@ exit:
	return ret;
}

int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port)
int gbam_setup(unsigned int no_bam_port)
{
	int	i;
	int	ret;
	int	bam_port_start = n_bam_ports;
	int	total_bam_ports = bam_port_start + no_bam_port;

	pr_debug("%s: requested BAM ports:%d and BAM2BAM ports:%d\n",
			  __func__, no_bam_port, no_bam2bam_port);
	pr_debug("%s: requested BAM ports:%d\n", __func__, no_bam_port);

	if ((!no_bam_port && !no_bam2bam_port) || no_bam_port > BAM_N_PORTS
		|| no_bam2bam_port > BAM2BAM_N_PORTS) {
		pr_err("%s: Invalid num of ports count:%d,%d\n",
				__func__, no_bam_port, no_bam2bam_port);
	if (!no_bam_port || total_bam_ports > BAM_N_PORTS) {
		pr_err("%s: Invalid num of ports count:%d\n",
				__func__, no_bam_port);
		return -EINVAL;
	}

	gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
	if (!gbam_wq) {
		gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND |
					WQ_MEM_RECLAIM, 1);
		if (!gbam_wq) {
			pr_err("%s: Unable to create workqueue gbam_wq\n",
					__func__);
			return -ENOMEM;
		}
	}

	for (i = 0; i < no_bam_port; i++) {
	for (i = bam_port_start; i < (bam_port_start + no_bam_port); i++) {
		n_bam_ports++;
		pr_debug("gbam_port_alloc called for %d\n", i);
		ret = gbam_port_alloc(i);
		if (ret) {
			n_bam_ports--;
@@ -2271,22 +2296,59 @@ int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port)
		}
	}

	for (i = 0; i < no_bam2bam_port; i++) {
	gbam_debugfs_init();

	return bam_port_start;

free_bam_ports:
	for (i = 0; i < n_bam_ports; i++)
		gbam_port_free(i);
	destroy_workqueue(gbam_wq);

	return ret;
}

int gbam2bam_setup(unsigned int no_bam2bam_port)
{
	int	i;
	int	ret;
	int	bam2bam_port_start = n_bam2bam_ports;
	int	total_bam2bam_ports = bam2bam_port_start + no_bam2bam_port;

	pr_debug("%s: requested BAM2BAM ports:%d\n", __func__, no_bam2bam_port);

	if (!no_bam2bam_port || total_bam2bam_ports > BAM2BAM_N_PORTS) {
		pr_err("%s: Invalid num of ports count:%d\n",
				__func__, no_bam2bam_port);
		return -EINVAL;
	}

	if (!gbam_wq) {
		gbam_wq = alloc_workqueue("k_gbam", WQ_UNBOUND |
					WQ_MEM_RECLAIM, 1);
		if (!gbam_wq) {
			pr_err("%s: Unable to create workqueue gbam_wq\n",
					__func__);
			return -ENOMEM;
		}
	}

	for (i = bam2bam_port_start; i < (bam2bam_port_start +
				no_bam2bam_port); i++) {
		n_bam2bam_ports++;
		ret = gbam2bam_port_alloc(i);
		if (ret) {
			n_bam2bam_ports--;
			pr_err("%s: Unable to alloc port:%d\n", __func__, i);
			goto free_bam_ports;
			goto free_bam2bam_ports;
		}
	}

	gbam_debugfs_init();
	return 0;

free_bam_ports:
	for (i = 0; i < n_bam_ports; i++)
		gbam_port_free(i);
	return bam2bam_port_start;

free_bam2bam_ports:
	for (i = 0; i < n_bam2bam_ports; i++)
		gbam2bam_port_free(i);
	destroy_workqueue(gbam_wq);
+8 −9
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/poll.h>
#include <linux/usb/usb_ctrl_qti.h>

#include <soc/qcom/bam_dmux.h>

#include "u_rmnet.h"
#include "usb_gadget_xport.h"
@@ -169,7 +170,6 @@ gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
	qti_ctrl_queue_notify(port);
}

#define BAM_DMUX_CHANNEL_ID 8
int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
			enum transport_type dxport, enum gadget_type gtype)
{
@@ -192,22 +192,21 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,

	spin_lock_irqsave(&port->lock, flags);
	port->gtype = gtype;
	if (dxport == USB_GADGET_XPORT_BAM) {
	if (dxport == USB_GADGET_XPORT_BAM ||
			dxport == USB_GADGET_XPORT_BAM_DMUX) {
		/*
		 * BAM-DMUX data transport is used for RMNET
		 * BAM-DMUX data transport is used for RMNET and DPL
		 * on some targets where IPA is not available.
		 * Set endpoint type as BAM-DMUX and interface
		 * id as channel number. This information is
		 * sent to user space via EP_LOOKUP ioctl.
		 *
		 * The BAM data transport driver supports only
		 * 1 BAM channel and the number is fixed so far
		 * on all targets. This number needs to be same
		 * as the bam_ch_ids defined in u_bam.c.
		 *
		 */

		port->ep_type = DATA_EP_TYPE_BAM_DMUX;
		port->intf = BAM_DMUX_CHANNEL_ID;
		port->intf = (gtype == USB_GADGET_RMNET) ?
			BAM_DMUX_USB_RMNET_0 :
			BAM_DMUX_USB_DPL;
		port->ipa_prod_idx = 0;
		port->ipa_cons_idx = 0;
	} else {
+2 −1
Original line number Diff line number Diff line
@@ -58,7 +58,8 @@ enum ctrl_client {
	NR_CTRL_CLIENTS
};

int gbam_setup(unsigned int no_bam_port, unsigned int no_bam2bam_port);
int gbam_setup(unsigned int no_bam_port);
int gbam2bam_setup(unsigned int no_bam2bam_port);
void gbam_cleanup(void);
int gbam_connect(struct grmnet *gr, u8 port_num,
	enum transport_type trans, u8 src_connection_idx,
Loading