Commit e81a7018 authored by Peter Chen's avatar Peter Chen Committed by Felipe Balbi
Browse files

usb: dwc3: allocate gadget structure dynamically



The current code uses commit fac32347 ("usb: udc: allow adding
and removing the same gadget device") as the workaround to let
the gadget device is re-used, but it is not allowed from driver
core point. In this commit, we allocate gadget structure dynamically,
and free it at its release function. Since the gadget device's
driver_data has already occupied by usb_composite_dev structure, we have
to use gadget device's platform data to store dwc3 structure.

Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarPeter Chen <peter.chen@nxp.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent 6b777892
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1080,7 +1080,7 @@ struct dwc3 {
	struct dwc3_event_buffer *ev_buf;
	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];

	struct usb_gadget	gadget;
	struct usb_gadget	*gadget;
	struct usb_gadget_driver *gadget_driver;

	struct clk_bulk_data	*clks;
+13 −13
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,

		direction = !dwc->ep0_expect_in;
		dwc->delayed_status = false;
		usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
		usb_gadget_set_state(dwc->gadget, USB_STATE_CONFIGURED);

		if (dwc->ep0state == EP0_STATUS_PHASE)
			__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
@@ -325,7 +325,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
		/*
		 * LTM will be set once we know how to set this in HW.
		 */
		usb_status |= dwc->gadget.is_selfpowered;
		usb_status |= dwc->gadget->is_selfpowered;

		if ((dwc->speed == DWC3_DSTS_SUPERSPEED) ||
		    (dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
@@ -450,7 +450,7 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,

	wValue = le16_to_cpu(ctrl->wValue);
	wIndex = le16_to_cpu(ctrl->wIndex);
	state = dwc->gadget.state;
	state = dwc->gadget->state;

	switch (wValue) {
	case USB_DEVICE_REMOTE_WAKEUP:
@@ -564,7 +564,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,

static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
	enum usb_device_state state = dwc->gadget.state;
	enum usb_device_state state = dwc->gadget->state;
	u32 addr;
	u32 reg;

@@ -585,9 +585,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
	dwc3_writel(dwc->regs, DWC3_DCFG, reg);

	if (addr)
		usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
		usb_gadget_set_state(dwc->gadget, USB_STATE_ADDRESS);
	else
		usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
		usb_gadget_set_state(dwc->gadget, USB_STATE_DEFAULT);

	return 0;
}
@@ -597,14 +597,14 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
	int ret;

	spin_unlock(&dwc->lock);
	ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
	ret = dwc->gadget_driver->setup(dwc->gadget, ctrl);
	spin_lock(&dwc->lock);
	return ret;
}

static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
	enum usb_device_state state = dwc->gadget.state;
	enum usb_device_state state = dwc->gadget->state;
	u32 cfg;
	int ret;
	u32 reg;
@@ -627,7 +627,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
			 * to change the state on the next usb_ep_queue()
			 */
			if (ret == 0)
				usb_gadget_set_state(&dwc->gadget,
				usb_gadget_set_state(dwc->gadget,
						USB_STATE_CONFIGURED);

			/*
@@ -646,7 +646,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
	case USB_STATE_CONFIGURED:
		ret = dwc3_ep0_delegate_req(dwc, ctrl);
		if (!cfg && !ret)
			usb_gadget_set_state(&dwc->gadget,
			usb_gadget_set_state(dwc->gadget,
					USB_STATE_ADDRESS);
		break;
	default:
@@ -702,7 +702,7 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
	struct dwc3_ep	*dep;
	enum usb_device_state state = dwc->gadget.state;
	enum usb_device_state state = dwc->gadget->state;
	u16		wLength;

	if (state == USB_STATE_DEFAULT)
@@ -746,7 +746,7 @@ static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ct
	if (wIndex || wLength)
		return -EINVAL;

	dwc->gadget.isoch_delay = wValue;
	dwc->gadget->isoch_delay = wValue;

	return 0;
}
@@ -1118,7 +1118,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
			 */
			if (!list_empty(&dep->pending_list)) {
				dwc->delayed_status = false;
				usb_gadget_set_state(&dwc->gadget,
				usb_gadget_set_state(dwc->gadget,
						     USB_STATE_CONFIGURED);
				dwc3_ep0_do_control_status(dwc, event);
			}
+63 −45
Original line number Diff line number Diff line
@@ -291,7 +291,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
	 *
	 * DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section 3.2.2
	 */
	if (dwc->gadget.speed <= USB_SPEED_HIGH) {
	if (dwc->gadget->speed <= USB_SPEED_HIGH) {
		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
		if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
			saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
@@ -423,7 +423,7 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
	 */
	if (dep->direction &&
	    !DWC3_VER_IS_PRIOR(DWC3, 260A) &&
	    (dwc->gadget.speed >= USB_SPEED_SUPER))
	    (dwc->gadget->speed >= USB_SPEED_SUPER))
		cmd |= DWC3_DEPCMD_CLEARPENDIN;

	memset(&params, 0, sizeof(params));
@@ -563,7 +563,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));

	/* Burst size is only needed in SuperSpeed mode */
	if (dwc->gadget.speed >= USB_SPEED_SUPER) {
	if (dwc->gadget->speed >= USB_SPEED_SUPER) {
		u32 burst = dep->endpoint.maxburst;

		params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
@@ -950,7 +950,7 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
		unsigned int is_last)
{
	struct dwc3		*dwc = dep->dwc;
	struct usb_gadget	*gadget = &dwc->gadget;
	struct usb_gadget	*gadget = dwc->gadget;
	enum usb_device_speed	speed = gadget->speed;

	trb->size = DWC3_TRB_SIZE_LENGTH(length);
@@ -1542,12 +1542,12 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
	if (!dwc->dis_start_transfer_quirk &&
	    (DWC3_VER_IS_PRIOR(DWC31, 170A) ||
	     DWC3_VER_TYPE_IS_WITHIN(DWC31, 170A, EA01, EA06))) {
		if (dwc->gadget.speed <= USB_SPEED_HIGH && dep->direction)
		if (dwc->gadget->speed <= USB_SPEED_HIGH && dep->direction)
			return dwc3_gadget_start_isoc_quirk(dep);
	}

	if (desc->bInterval <= 14 &&
	    dwc->gadget.speed >= USB_SPEED_HIGH) {
	    dwc->gadget->speed >= USB_SPEED_HIGH) {
		u32 frame = __dwc3_gadget_get_frame(dwc);
		bool rollover = frame <
				(dep->frame_number & DWC3_FRNUMBER_MASK);
@@ -2256,7 +2256,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
	spin_lock_irqsave(&dwc->lock, flags);
	if (dwc->gadget_driver) {
		dev_err(dwc->dev, "%s is already bound to %s\n",
				dwc->gadget.name,
				dwc->gadget->name,
				dwc->gadget_driver->driver.name);
		ret = -EBUSY;
		goto err1;
@@ -2428,7 +2428,7 @@ static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep)
	dep->endpoint.maxburst = 1;
	dep->endpoint.ops = &dwc3_gadget_ep0_ops;
	if (!dep->direction)
		dwc->gadget.ep0 = &dep->endpoint;
		dwc->gadget->ep0 = &dep->endpoint;

	dep->endpoint.caps.type_control = true;

@@ -2474,7 +2474,7 @@ static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep)
	dep->endpoint.max_streams = 15;
	dep->endpoint.ops = &dwc3_gadget_ep_ops;
	list_add_tail(&dep->endpoint.ep_list,
			&dwc->gadget.ep_list);
			&dwc->gadget->ep_list);
	dep->endpoint.caps.type_iso = true;
	dep->endpoint.caps.type_bulk = true;
	dep->endpoint.caps.type_int = true;
@@ -2523,7 +2523,7 @@ static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep)
	dep->endpoint.max_streams = 15;
	dep->endpoint.ops = &dwc3_gadget_ep_ops;
	list_add_tail(&dep->endpoint.ep_list,
			&dwc->gadget.ep_list);
			&dwc->gadget->ep_list);
	dep->endpoint.caps.type_iso = true;
	dep->endpoint.caps.type_bulk = true;
	dep->endpoint.caps.type_int = true;
@@ -2584,7 +2584,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
{
	u8				epnum;

	INIT_LIST_HEAD(&dwc->gadget.ep_list);
	INIT_LIST_HEAD(&dwc->gadget->ep_list);

	for (epnum = 0; epnum < total; epnum++) {
		int			ret;
@@ -3051,7 +3051,7 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)
{
	if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->disconnect(&dwc->gadget);
		dwc->gadget_driver->disconnect(dwc->gadget);
		spin_lock(&dwc->lock);
	}
}
@@ -3060,7 +3060,7 @@ static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
	if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->suspend(&dwc->gadget);
		dwc->gadget_driver->suspend(dwc->gadget);
		spin_lock(&dwc->lock);
	}
}
@@ -3069,7 +3069,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
{
	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->resume(&dwc->gadget);
		dwc->gadget_driver->resume(dwc->gadget);
		spin_lock(&dwc->lock);
	}
}
@@ -3079,9 +3079,9 @@ static void dwc3_reset_gadget(struct dwc3 *dwc)
	if (!dwc->gadget_driver)
		return;

	if (dwc->gadget.speed != USB_SPEED_UNKNOWN) {
	if (dwc->gadget->speed != USB_SPEED_UNKNOWN) {
		spin_unlock(&dwc->lock);
		usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver);
		usb_gadget_udc_reset(dwc->gadget, dwc->gadget_driver);
		spin_lock(&dwc->lock);
	}
}
@@ -3182,9 +3182,9 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)

	dwc3_disconnect_gadget(dwc);

	dwc->gadget.speed = USB_SPEED_UNKNOWN;
	dwc->gadget->speed = USB_SPEED_UNKNOWN;
	dwc->setup_packet_pending = false;
	usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
	usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);

	dwc->connected = false;
}
@@ -3263,8 +3263,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
	switch (speed) {
	case DWC3_DSTS_SUPERSPEED_PLUS:
		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
		dwc->gadget.ep0->maxpacket = 512;
		dwc->gadget.speed = USB_SPEED_SUPER_PLUS;
		dwc->gadget->ep0->maxpacket = 512;
		dwc->gadget->speed = USB_SPEED_SUPER_PLUS;
		break;
	case DWC3_DSTS_SUPERSPEED:
		/*
@@ -3284,27 +3284,27 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
			dwc3_gadget_reset_interrupt(dwc);

		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
		dwc->gadget.ep0->maxpacket = 512;
		dwc->gadget.speed = USB_SPEED_SUPER;
		dwc->gadget->ep0->maxpacket = 512;
		dwc->gadget->speed = USB_SPEED_SUPER;
		break;
	case DWC3_DSTS_HIGHSPEED:
		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
		dwc->gadget.ep0->maxpacket = 64;
		dwc->gadget.speed = USB_SPEED_HIGH;
		dwc->gadget->ep0->maxpacket = 64;
		dwc->gadget->speed = USB_SPEED_HIGH;
		break;
	case DWC3_DSTS_FULLSPEED:
		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
		dwc->gadget.ep0->maxpacket = 64;
		dwc->gadget.speed = USB_SPEED_FULL;
		dwc->gadget->ep0->maxpacket = 64;
		dwc->gadget->speed = USB_SPEED_FULL;
		break;
	case DWC3_DSTS_LOWSPEED:
		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
		dwc->gadget.ep0->maxpacket = 8;
		dwc->gadget.speed = USB_SPEED_LOW;
		dwc->gadget->ep0->maxpacket = 8;
		dwc->gadget->speed = USB_SPEED_LOW;
		break;
	}

	dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket;
	dwc->eps[1]->endpoint.maxpacket = dwc->gadget->ep0->maxpacket;

	/* Enable USB2 LPM Capability */

@@ -3372,7 +3372,7 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)

	if (dwc->gadget_driver && dwc->gadget_driver->resume) {
		spin_unlock(&dwc->lock);
		dwc->gadget_driver->resume(&dwc->gadget);
		dwc->gadget_driver->resume(dwc->gadget);
		spin_lock(&dwc->lock);
	}
}
@@ -3543,7 +3543,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
			 * Ignore suspend event until the gadget enters into
			 * USB_STATE_CONFIGURED state.
			 */
			if (dwc->gadget.state >= USB_STATE_CONFIGURED)
			if (dwc->gadget->state >= USB_STATE_CONFIGURED)
				dwc3_gadget_suspend_interrupt(dwc,
						event->event_info);
		}
@@ -3718,6 +3718,13 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
	return irq;
}

static void dwc_gadget_release(struct device *dev)
{
	struct usb_gadget *gadget = container_of(dev, struct usb_gadget, dev);

	kfree(gadget);
}

/**
 * dwc3_gadget_init - initializes gadget related registers
 * @dwc: pointer to our controller context structure
@@ -3728,6 +3735,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
{
	int ret;
	int irq;
	struct device *dev;

	irq = dwc3_gadget_get_irq(dwc);
	if (irq < 0) {
@@ -3760,12 +3768,21 @@ int dwc3_gadget_init(struct dwc3 *dwc)
	}

	init_completion(&dwc->ep0_in_setup);
	dwc->gadget = kzalloc(sizeof(struct usb_gadget), GFP_KERNEL);
	if (!dwc->gadget) {
		ret = -ENOMEM;
		goto err3;
	}

	dwc->gadget.ops			= &dwc3_gadget_ops;
	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
	dwc->gadget.sg_supported	= true;
	dwc->gadget.name		= "dwc3-gadget";
	dwc->gadget.lpm_capable		= true;

	usb_initialize_gadget(dwc->dev, dwc->gadget, dwc_gadget_release);
	dev				= &dwc->gadget->dev;
	dev->platform_data		= dwc;
	dwc->gadget->ops		= &dwc3_gadget_ops;
	dwc->gadget->speed		= USB_SPEED_UNKNOWN;
	dwc->gadget->sg_supported	= true;
	dwc->gadget->name		= "dwc3-gadget";
	dwc->gadget->lpm_capable	= true;

	/*
	 * FIXME We might be setting max_speed to <SUPER, however versions
@@ -3788,7 +3805,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
		dev_info(dwc->dev, "changing max_speed on rev %08x\n",
				dwc->revision);

	dwc->gadget.max_speed		= dwc->maximum_speed;
	dwc->gadget->max_speed		= dwc->maximum_speed;

	/*
	 * REVISIT: Here we should clear all pending IRQs to be
@@ -3797,21 +3814,22 @@ int dwc3_gadget_init(struct dwc3 *dwc)

	ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
	if (ret)
		goto err3;
		goto err4;

	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
	ret = usb_add_gadget(dwc->gadget);
	if (ret) {
		dev_err(dwc->dev, "failed to register udc\n");
		goto err4;
		dev_err(dwc->dev, "failed to add gadget\n");
		goto err5;
	}

	dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed);
	dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed);

	return 0;

err4:
err5:
	dwc3_gadget_free_endpoints(dwc);

err4:
	usb_put_gadget(dwc->gadget);
err3:
	dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
			dwc->bounce_addr);
@@ -3831,7 +3849,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)

void dwc3_gadget_exit(struct dwc3 *dwc)
{
	usb_del_gadget_udc(&dwc->gadget);
	usb_del_gadget_udc(dwc->gadget);
	dwc3_gadget_free_endpoints(dwc);
	dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
			  dwc->bounce_addr);
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@

struct dwc3;
#define to_dwc3_ep(ep)		(container_of(ep, struct dwc3_ep, endpoint))
#define gadget_to_dwc(g)	(container_of(g, struct dwc3, gadget))
#define gadget_to_dwc(g)	(dev_get_platdata(&g->dev))

/* DEPCFG parameter 1 */
#define DWC3_DEPCFG_INT_NUM(n)		(((n) & 0x1f) << 0)