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

Commit c8ac2180 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: Enable DPL composition over ether tranpsort"

parents 691c77a7 34d6f9a4
Loading
Loading
Loading
Loading
+102 −9
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "usb_gadget_xport.h"
#include "u_data_ipa.h"
#include "u_rmnet.h"
#include "u_ether.h"

static unsigned int nr_qdss_ports;
static unsigned int no_data_bam_ports;
@@ -41,6 +42,7 @@ static struct qdss_ports {
	struct f_qdss			*port;
	struct gadget_ipa_port		ipa_port;
	struct grmnet			bam_dmux_port;
	struct gether			gether_port;
} qdss_ports[NR_QDSS_PORTS];


@@ -355,10 +357,14 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
	struct usb_gadget *gadget = c->cdev->gadget;
	struct f_qdss *qdss = func_to_qdss(f);
	struct usb_ep *ep;
	int iface;
	int iface, ret = -ENOTSUPP;
	struct eth_dev *edev;
	enum transport_type dxport;

	pr_debug("qdss_bind\n");

	dxport = qdss_ports[qdss->port_num].data_xport;

	if (!gadget_is_dualspeed(gadget) && !gadget_is_superspeed(gadget)) {
		pr_err("qdss_bind: full-speed is not supported\n");
		return -ENOTSUPP;
@@ -391,6 +397,14 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
		goto fail;
	}
	qdss->port.data = ep;

	/*
	 * Populate same for u_ether(gether_connect()) which uses
	 * gether_port struct
	 */
	if (dxport == USB_GADGET_XPORT_ETHER)
		qdss_ports[qdss->port_num].gether_port.in_ep = ep;

	ep->driver_data = qdss;

	if (qdss->debug_inface_enabled) {
@@ -444,11 +458,23 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f)
		}
	}

	if (dxport == USB_GADGET_XPORT_ETHER) {
		pr_debug("USB_GADGET_XPORT_ETHER\n");
		edev = gether_setup_name(c->cdev->gadget, NULL, NULL, NULL,
				QMULT_DEFAULT, "dpl_usb");
		if (IS_ERR(edev)) {
			pr_err("%s: gether_setup failed\n", __func__);
			ret = PTR_ERR(edev);
			goto fail;
		}
		qdss_ports[qdss->port_num].gether_port.ioport = edev;
	}

	return 0;
fail:
	clear_eps(f);
	clear_desc(gadget, f);
	return -ENOTSUPP;
	return ret;
}


@@ -456,6 +482,7 @@ static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
{
	struct f_qdss  *qdss = func_to_qdss(f);
	struct usb_gadget *gadget = c->cdev->gadget;
	int i;

	pr_debug("qdss_unbind\n");

@@ -463,11 +490,22 @@ static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)

	clear_eps(f);
	clear_desc(gadget, f);

	for (i = 0; i < nr_qdss_ports; i++) {
		if (qdss_ports[i].data_xport == USB_GADGET_XPORT_ETHER) {
			gether_cleanup(qdss_ports[i].gether_port.ioport);
			qdss_ports[i].gether_port.ioport = NULL;
		}
	}

}

static void qdss_eps_disable(struct usb_function *f)
{
	struct f_qdss  *qdss = func_to_qdss(f);
	enum transport_type dxport;

	dxport = qdss_ports[qdss->port_num].data_xport;

	pr_debug("qdss_eps_disable\n");

@@ -481,7 +519,14 @@ static void qdss_eps_disable(struct usb_function *f)
		qdss->ctrl_out_enabled = 0;
	}

	if (qdss->data_enabled) {
	/*
	 * In case of data transport is uether, endpoint will be disabled
	 * in gether_disconnect() too. This will lead to disabling of the
	 * same endpoint twice and will print a warning message.
	 * So for uether data transport disable endpoint only in
	 * gether_disconnect()
	 */
	if (qdss->data_enabled && (dxport != USB_GADGET_XPORT_ETHER)) {
		usb_ep_disable(qdss->port.data);
		qdss->data_enabled = 0;
	}
@@ -549,6 +594,10 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
		pr_debug("usb_qdss_disconnect_work: HSIC transport\n");
		ghsic_data_disconnect(&qdss->port, portno);
		break;
	case USB_GADGET_XPORT_ETHER:
		pr_debug("usb_qdss_disconnect_work: ETHER transport\n");
		gether_disconnect(&qdss_ports[portno].gether_port);
		break;
	case USB_GADGET_XPORT_NONE:
		break;
	default:
@@ -661,6 +710,7 @@ static void usb_qdss_connect_work(struct work_struct *work)
	unsigned char port_num;
	enum transport_type	dxport;
	enum transport_type     ctrl_xport;
	struct net_device *net;

	qdss = container_of(work, struct f_qdss, connect_w);
	dxport = qdss_ports[qdss->port_num].data_xport;
@@ -745,6 +795,15 @@ static void usb_qdss_connect_work(struct work_struct *work)
			return;
		}
		break;
	case USB_GADGET_XPORT_ETHER:
		pr_debug("usb_qdss_connect_work: ETHER transport\n");
		net = gether_connect(&qdss_ports[port_num].gether_port);
		if (IS_ERR(net)) {
			pr_err("%s: gether_connect failed: err:%ld\n", __func__,
				PTR_ERR(net));
			return;
		}
		break;
	case USB_GADGET_XPORT_NONE:
		break;
	default:
@@ -786,6 +845,13 @@ static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			goto fail;
		}

		/*
		 * In case of data transport is uether, endpoint will be enabled
		 * in gether_connect() too. This will lead to enabling of the
		 * same endpoint twice and will print a warning message.
		 * So for uether data transport disable endpoint only in
		 * gether_connect()
		 */
		if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA ||
				dxport == USB_GADGET_XPORT_BAM_DMUX) {
			qdss->usb_connected = 1;
@@ -793,9 +859,11 @@ static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
			return 0;
		}

		if (dxport != USB_GADGET_XPORT_ETHER) {
			ret = usb_ep_enable(qdss->port.data);
			if (ret)
				goto fail;
		}

		qdss->port.data->driver_data = qdss;
		qdss->data_enabled = 1;
@@ -843,7 +911,8 @@ static int qdss_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
		}
	}
	if (qdss->usb_connected && (ch->app_conn ||
		(dxport == USB_GADGET_XPORT_HSIC))) {
		(dxport == USB_GADGET_XPORT_HSIC) ||
		(dxport == USB_GADGET_XPORT_ETHER))) {
		queue_work(qdss->wq, &qdss->connect_w);
	}
	return 0;
@@ -863,6 +932,10 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno)
	struct usb_qdss_ch *ch;
	unsigned long flags;
	char *name;
	enum transport_type dxport;
	struct usb_function *f;

	dxport = qdss_ports[portno].data_xport;

	pr_debug("qdss_bind_config\n");
	if (portno >= nr_qdss_ports) {
@@ -887,10 +960,14 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno)
		}
	}

	if (qdss_ports[portno].data_xport == USB_GADGET_XPORT_BAM2BAM)
	if (qdss_ports[portno].data_xport == USB_GADGET_XPORT_BAM2BAM) {
		name = kasprintf(GFP_ATOMIC, "qdss");
	else
	} else if (dxport == USB_GADGET_XPORT_ETHER) {
		pr_debug("qdss_bind_config: USB_GADGET_XPORT_ETHER\n");
		name = kasprintf(GFP_KERNEL, "qdss_dpl");
	} else {
		name = kasprintf(GFP_ATOMIC, "qdss%d", portno);
	}

	if (!name)
		return -ENOMEM;
@@ -911,6 +988,7 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno)
		spin_unlock_irqrestore(&qdss_lock, flags);
		qdss->wq = create_singlethread_workqueue(name);
		if (!qdss->wq) {
			kfree(name);
			kfree(qdss);
			return -ENOMEM;
		}
@@ -934,6 +1012,17 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno)
	qdss->port.function.name = name;
	qdss->port.function.fs_descriptors = qdss_hs_desc;
	qdss->port.function.hs_descriptors = qdss_hs_desc;
	/*
	 * Populate the gether_port->usb_function which is needed by
	 * u_ether transport when the interface is brought 'down' by calling
	 * eth_stop()
	 */
	if (dxport == USB_GADGET_XPORT_ETHER) {
		f = &qdss_ports[portno].gether_port.func;
		f->fs_descriptors = qdss_hs_data_only_desc;
		f->hs_descriptors = qdss_hs_data_only_desc;
		f->ss_descriptors = qdss_ss_data_only_desc;
	}
	qdss->port.function.strings = qdss_strings;
	qdss->port.function.bind = qdss_bind;
	qdss->port.function.unbind = qdss_unbind;
@@ -948,6 +1037,7 @@ static int qdss_bind_config(struct usb_configuration *c, unsigned char portno)
	if (status) {
		pr_err("qdss usb_add_function failed\n");
		ch->priv_usb = NULL;
		kfree(name);
		kfree(qdss);
	}

@@ -1239,6 +1329,9 @@ static int qdss_init_port(const char *ctrl_name, const char *data_name,
		no_bam_dmux_ports++;
		pr_debug("USB_GADGET_XPORT_BAM_DMUX %u\n", no_bam_dmux_ports);
		break;
	case USB_GADGET_XPORT_ETHER:
		pr_debug("%s USB_GADGET_XPORT_ETHER\n", __func__);
		break;
	case USB_GADGET_XPORT_NONE:
		break;
	default:
+107 −72
Original line number Diff line number Diff line
@@ -549,16 +549,29 @@ static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
	int	status;

	spin_lock(&dev->req_lock);
	/*
	 * u_ether driver always assumes that it has both in and out endpoints
	 * and calls alloc_requests on both the endpoints, without checking if
	 * the endpoint exits or not. In case of DPL, there is only one in_ep
	 * and hence while trying to allocate meomory for out_ep, there will be
	 * a NULL pointer exception. So to avoid this, allocate memory only if
	 * the endpoints exists
	 */
	if (link->in_ep) {
		status = prealloc(&dev->tx_reqs, link->in_ep, n * tx_qmult,
				dev->sg_enabled,
				dev->header_len);
		if (status < 0)
			goto fail;
	}

	if (link->out_ep) {
		status = prealloc(&dev->rx_reqs, link->out_ep, n,
				dev->sg_enabled,
				dev->header_len);
		if (status < 0)
			goto fail;
	}
	goto done;
fail:
	DBG(dev, "can't alloc requests\n");
@@ -1376,23 +1389,31 @@ static int eth_stop(struct net_device *net)
		 * their own pace; the network stack can handle old packets.
		 * For the moment we leave this here, since it works.
		 */
		if (link->in_ep) {
			in = link->in_ep->desc;
		out = link->out_ep->desc;
			usb_ep_disable(link->in_ep);
		usb_ep_disable(link->out_ep);
		if (netif_carrier_ok(net)) {
			if (config_ep_by_speed(dev->gadget, &link->func,
					       link->in_ep) ||
			    config_ep_by_speed(dev->gadget, &link->func,
					       link->out_ep)) {
			if (netif_carrier_ok(net) &&
				(config_ep_by_speed(dev->gadget, &link->func,
					link->in_ep))) {
				link->in_ep->desc = NULL;
				link->out_ep->desc = NULL;
				return -EINVAL;
			}
			DBG(dev, "host still using in/out endpoints\n");
			DBG(dev, "host still using in endpoint\n");
			link->in_ep->desc = in;
			link->out_ep->desc = out;
			usb_ep_enable(link->in_ep);
		}

		if (link->out_ep) {
			out = link->out_ep->desc;
			usb_ep_disable(link->out_ep);
			if ((netif_carrier_ok(net)) &&
				(config_ep_by_speed(dev->gadget, &link->func,
					link->out_ep))) {
				link->out_ep->desc = NULL;
				return -EINVAL;
			}
			DBG(dev, "host still using out endpoint\n");
			link->out_ep->desc = out;
			usb_ep_enable(link->out_ep);
		}
	}
@@ -2043,6 +2064,13 @@ struct net_device *gether_connect(struct gether *link)
		}
	}

	if (!link->in_ep && !link->out_ep) {
		WARN_ON(1);
		result = -ENOTSUPP;
		goto fail0;
	}

	if (link->in_ep) {
		link->in_ep->driver_data = dev;
		result = usb_ep_enable(link->in_ep);
		if (result != 0) {
@@ -2050,7 +2078,9 @@ struct net_device *gether_connect(struct gether *link)
				link->in_ep->name, result);
			goto fail0;
		}
	}

	if (link->out_ep) {
		link->out_ep->driver_data = dev;
		result = usb_ep_enable(link->out_ep);
		if (result != 0) {
@@ -2058,6 +2088,7 @@ struct net_device *gether_connect(struct gether *link)
				link->out_ep->name, result);
			goto fail1;
		}
	}

	dev->header_len = link->header_len;
	dev->unwrap = link->unwrap;
@@ -2150,6 +2181,7 @@ void gether_disconnect(struct gether *link)
	 * of all pending i/o.  then free the request objects
	 * and forget about the endpoints.
	 */
	if (link->in_ep) {
		usb_ep_disable(link->in_ep);
		spin_lock(&dev->req_lock);
		while (!list_empty(&dev->tx_reqs)) {
@@ -2182,7 +2214,9 @@ void gether_disconnect(struct gether *link)

		link->in_ep->driver_data = NULL;
		link->in_ep->desc = NULL;
	}

	if (link->out_ep) {
		usb_ep_disable(link->out_ep);
		spin_lock(&dev->req_lock);
		while (!list_empty(&dev->rx_reqs)) {
@@ -2203,6 +2237,7 @@ void gether_disconnect(struct gether *link)

		link->out_ep->driver_data = NULL;
		link->out_ep->desc = NULL;
	}

	pr_debug("%s(): tx_throttle count= %lu", __func__,
					dev->tx_throttle);