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

Commit 2b3eb6e3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull USB driver fixes from Greg KH:
 "Here's some USB driver fixes for 4.2-rc3.

  The ususal number of gadget driver fixes are in here, along with some
  new device ids and a build fix for the mn10300 arch which required
  some symbols to be renamed in the mos7720 driver.

  All have been in linux-next for a while with no reported issues"

* tag 'usb-4.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  USB: serial: Destroy serial_minors IDR on module exit
  usb: gadget: f_midi: fix error recovery path
  usb: phy: mxs: suspend to RAM causes NULL pointer dereference
  usb: gadget: udc: fix free_irq() after request_irq() failed
  usb: gadget: composite: Fix NULL pointer dereference
  usb: gadget: f_fs: do not set cancel function on synchronous {read,write}
  usb: f_mass_storage: limit number of reported LUNs
  usb: dwc3: core: avoid NULL pointer dereference
  usb: dwc2: embed storage for reg backup in struct dwc2_hsotg
  usb: dwc2: host: allocate qtd before atomic enqueue
  usb: dwc2: host: allocate qh before atomic enqueue
  usb: musb: host: rely on port_mode to call musb_start()
  USB: cp210x: add ID for Aruba Networks controllers
  USB: mos7720: rename registers
  USB: option: add 2020:4000 ID
parents 1ea2a01c 51f007e1
Loading
Loading
Loading
Loading
+15 −40
Original line number Original line Diff line number Diff line
@@ -72,17 +72,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
	dev_dbg(hsotg->dev, "%s\n", __func__);
	dev_dbg(hsotg->dev, "%s\n", __func__);


	/* Backup Host regs */
	/* Backup Host regs */
	hr = hsotg->hr_backup;
	hr = &hsotg->hr_backup;
	if (!hr) {
		hr = devm_kzalloc(hsotg->dev, sizeof(*hr), GFP_KERNEL);
		if (!hr) {
			dev_err(hsotg->dev, "%s: can't allocate host regs\n",
					__func__);
			return -ENOMEM;
		}

		hsotg->hr_backup = hr;
	}
	hr->hcfg = readl(hsotg->regs + HCFG);
	hr->hcfg = readl(hsotg->regs + HCFG);
	hr->haintmsk = readl(hsotg->regs + HAINTMSK);
	hr->haintmsk = readl(hsotg->regs + HAINTMSK);
	for (i = 0; i < hsotg->core_params->host_channels; ++i)
	for (i = 0; i < hsotg->core_params->host_channels; ++i)
@@ -90,6 +80,7 @@ static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)


	hr->hprt0 = readl(hsotg->regs + HPRT0);
	hr->hprt0 = readl(hsotg->regs + HPRT0);
	hr->hfir = readl(hsotg->regs + HFIR);
	hr->hfir = readl(hsotg->regs + HFIR);
	hr->valid = true;


	return 0;
	return 0;
}
}
@@ -109,12 +100,13 @@ static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
	dev_dbg(hsotg->dev, "%s\n", __func__);
	dev_dbg(hsotg->dev, "%s\n", __func__);


	/* Restore host regs */
	/* Restore host regs */
	hr = hsotg->hr_backup;
	hr = &hsotg->hr_backup;
	if (!hr) {
	if (!hr->valid) {
		dev_err(hsotg->dev, "%s: no host registers to restore\n",
		dev_err(hsotg->dev, "%s: no host registers to restore\n",
				__func__);
				__func__);
		return -EINVAL;
		return -EINVAL;
	}
	}
	hr->valid = false;


	writel(hr->hcfg, hsotg->regs + HCFG);
	writel(hr->hcfg, hsotg->regs + HCFG);
	writel(hr->haintmsk, hsotg->regs + HAINTMSK);
	writel(hr->haintmsk, hsotg->regs + HAINTMSK);
@@ -152,17 +144,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
	dev_dbg(hsotg->dev, "%s\n", __func__);
	dev_dbg(hsotg->dev, "%s\n", __func__);


	/* Backup dev regs */
	/* Backup dev regs */
	dr = hsotg->dr_backup;
	dr = &hsotg->dr_backup;
	if (!dr) {
		dr = devm_kzalloc(hsotg->dev, sizeof(*dr), GFP_KERNEL);
		if (!dr) {
			dev_err(hsotg->dev, "%s: can't allocate device regs\n",
					__func__);
			return -ENOMEM;
		}

		hsotg->dr_backup = dr;
	}


	dr->dcfg = readl(hsotg->regs + DCFG);
	dr->dcfg = readl(hsotg->regs + DCFG);
	dr->dctl = readl(hsotg->regs + DCTL);
	dr->dctl = readl(hsotg->regs + DCTL);
@@ -195,7 +177,7 @@ static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
		dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i));
		dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i));
		dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i));
		dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i));
	}
	}

	dr->valid = true;
	return 0;
	return 0;
}
}


@@ -215,12 +197,13 @@ static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
	dev_dbg(hsotg->dev, "%s\n", __func__);
	dev_dbg(hsotg->dev, "%s\n", __func__);


	/* Restore dev regs */
	/* Restore dev regs */
	dr = hsotg->dr_backup;
	dr = &hsotg->dr_backup;
	if (!dr) {
	if (!dr->valid) {
		dev_err(hsotg->dev, "%s: no device registers to restore\n",
		dev_err(hsotg->dev, "%s: no device registers to restore\n",
				__func__);
				__func__);
		return -EINVAL;
		return -EINVAL;
	}
	}
	dr->valid = false;


	writel(dr->dcfg, hsotg->regs + DCFG);
	writel(dr->dcfg, hsotg->regs + DCFG);
	writel(dr->dctl, hsotg->regs + DCTL);
	writel(dr->dctl, hsotg->regs + DCTL);
@@ -268,17 +251,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
	int i;
	int i;


	/* Backup global regs */
	/* Backup global regs */
	gr = hsotg->gr_backup;
	gr = &hsotg->gr_backup;
	if (!gr) {
		gr = devm_kzalloc(hsotg->dev, sizeof(*gr), GFP_KERNEL);
		if (!gr) {
			dev_err(hsotg->dev, "%s: can't allocate global regs\n",
					__func__);
			return -ENOMEM;
		}

		hsotg->gr_backup = gr;
	}


	gr->gotgctl = readl(hsotg->regs + GOTGCTL);
	gr->gotgctl = readl(hsotg->regs + GOTGCTL);
	gr->gintmsk = readl(hsotg->regs + GINTMSK);
	gr->gintmsk = readl(hsotg->regs + GINTMSK);
@@ -291,6 +264,7 @@ static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
	for (i = 0; i < MAX_EPS_CHANNELS; i++)
	for (i = 0; i < MAX_EPS_CHANNELS; i++)
		gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i));
		gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i));


	gr->valid = true;
	return 0;
	return 0;
}
}


@@ -309,12 +283,13 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
	dev_dbg(hsotg->dev, "%s\n", __func__);
	dev_dbg(hsotg->dev, "%s\n", __func__);


	/* Restore global regs */
	/* Restore global regs */
	gr = hsotg->gr_backup;
	gr = &hsotg->gr_backup;
	if (!gr) {
	if (!gr->valid) {
		dev_err(hsotg->dev, "%s: no global registers to restore\n",
		dev_err(hsotg->dev, "%s: no global registers to restore\n",
				__func__);
				__func__);
		return -EINVAL;
		return -EINVAL;
	}
	}
	gr->valid = false;


	writel(0xffffffff, hsotg->regs + GINTSTS);
	writel(0xffffffff, hsotg->regs + GINTSTS);
	writel(gr->gotgctl, hsotg->regs + GOTGCTL);
	writel(gr->gotgctl, hsotg->regs + GOTGCTL);
+6 −3
Original line number Original line Diff line number Diff line
@@ -492,6 +492,7 @@ struct dwc2_gregs_backup {
	u32 gdfifocfg;
	u32 gdfifocfg;
	u32 dtxfsiz[MAX_EPS_CHANNELS];
	u32 dtxfsiz[MAX_EPS_CHANNELS];
	u32 gpwrdn;
	u32 gpwrdn;
	bool valid;
};
};


/**
/**
@@ -521,6 +522,7 @@ struct dwc2_dregs_backup {
	u32 doepctl[MAX_EPS_CHANNELS];
	u32 doepctl[MAX_EPS_CHANNELS];
	u32 doeptsiz[MAX_EPS_CHANNELS];
	u32 doeptsiz[MAX_EPS_CHANNELS];
	u32 doepdma[MAX_EPS_CHANNELS];
	u32 doepdma[MAX_EPS_CHANNELS];
	bool valid;
};
};


/**
/**
@@ -538,6 +540,7 @@ struct dwc2_hregs_backup {
	u32 hcintmsk[MAX_EPS_CHANNELS];
	u32 hcintmsk[MAX_EPS_CHANNELS];
	u32 hprt0;
	u32 hprt0;
	u32 hfir;
	u32 hfir;
	bool valid;
};
};


/**
/**
@@ -705,9 +708,9 @@ struct dwc2_hsotg {
	struct work_struct wf_otg;
	struct work_struct wf_otg;
	struct timer_list wkp_timer;
	struct timer_list wkp_timer;
	enum dwc2_lx_state lx_state;
	enum dwc2_lx_state lx_state;
	struct dwc2_gregs_backup *gr_backup;
	struct dwc2_gregs_backup gr_backup;
	struct dwc2_dregs_backup *dr_backup;
	struct dwc2_dregs_backup dr_backup;
	struct dwc2_hregs_backup *hr_backup;
	struct dwc2_hregs_backup hr_backup;


	struct dentry *debug_root;
	struct dentry *debug_root;
	struct debugfs_regset32 *regset;
	struct debugfs_regset32 *regset;
+42 −13
Original line number Original line Diff line number Diff line
@@ -359,10 +359,9 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)


/* Caller must hold driver lock */
/* Caller must hold driver lock */
static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
				struct dwc2_hcd_urb *urb, void **ep_handle,
				struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
				gfp_t mem_flags)
				struct dwc2_qtd *qtd)
{
{
	struct dwc2_qtd *qtd;
	u32 intr_mask;
	u32 intr_mask;
	int retval;
	int retval;
	int dev_speed;
	int dev_speed;
@@ -386,18 +385,15 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
			return -ENODEV;
			return -ENODEV;
	}
	}


	qtd = kzalloc(sizeof(*qtd), mem_flags);
	if (!qtd)
	if (!qtd)
		return -ENOMEM;
		return -EINVAL;


	dwc2_hcd_qtd_init(qtd, urb);
	dwc2_hcd_qtd_init(qtd, urb);
	retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
	retval = dwc2_hcd_qtd_add(hsotg, qtd, qh);
				  mem_flags);
	if (retval) {
	if (retval) {
		dev_err(hsotg->dev,
		dev_err(hsotg->dev,
			"DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
			"DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
			retval);
			retval);
		kfree(qtd);
		return retval;
		return retval;
	}
	}


@@ -2445,6 +2441,9 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
	u32 tflags = 0;
	u32 tflags = 0;
	void *buf;
	void *buf;
	unsigned long flags;
	unsigned long flags;
	struct dwc2_qh *qh;
	bool qh_allocated = false;
	struct dwc2_qtd *qtd;


	if (dbg_urb(urb)) {
	if (dbg_urb(urb)) {
		dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
		dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
@@ -2523,15 +2522,32 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
						 urb->iso_frame_desc[i].length);
						 urb->iso_frame_desc[i].length);


	urb->hcpriv = dwc2_urb;
	urb->hcpriv = dwc2_urb;
	qh = (struct dwc2_qh *) ep->hcpriv;
	/* Create QH for the endpoint if it doesn't exist */
	if (!qh) {
		qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags);
		if (!qh) {
			retval = -ENOMEM;
			goto fail0;
		}
		ep->hcpriv = qh;
		qh_allocated = true;
	}

	qtd = kzalloc(sizeof(*qtd), mem_flags);
	if (!qtd) {
		retval = -ENOMEM;
		goto fail1;
	}


	spin_lock_irqsave(&hsotg->lock, flags);
	spin_lock_irqsave(&hsotg->lock, flags);
	retval = usb_hcd_link_urb_to_ep(hcd, urb);
	retval = usb_hcd_link_urb_to_ep(hcd, urb);
	if (retval)
	if (retval)
		goto fail1;
		goto fail2;


	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, qh, qtd);
	if (retval)
	if (retval)
		goto fail2;
		goto fail3;


	if (alloc_bandwidth) {
	if (alloc_bandwidth) {
		dwc2_allocate_bus_bandwidth(hcd,
		dwc2_allocate_bus_bandwidth(hcd,
@@ -2543,12 +2559,25 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,


	return 0;
	return 0;


fail2:
fail3:
	dwc2_urb->priv = NULL;
	dwc2_urb->priv = NULL;
	usb_hcd_unlink_urb_from_ep(hcd, urb);
	usb_hcd_unlink_urb_from_ep(hcd, urb);
fail1:
fail2:
	spin_unlock_irqrestore(&hsotg->lock, flags);
	spin_unlock_irqrestore(&hsotg->lock, flags);
	urb->hcpriv = NULL;
	urb->hcpriv = NULL;
	kfree(qtd);
fail1:
	if (qh_allocated) {
		struct dwc2_qtd *qtd2, *qtd2_tmp;

		ep->hcpriv = NULL;
		dwc2_hcd_qh_unlink(hsotg, qh);
		/* Free each QTD in the QH's QTD list */
		list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list,
							 qtd_list_entry)
			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh);
		dwc2_hcd_qh_free(hsotg, qh);
	}
fail0:
fail0:
	kfree(dwc2_urb);
	kfree(dwc2_urb);


+4 −1
Original line number Original line Diff line number Diff line
@@ -463,6 +463,9 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
/* Schedule Queue Functions */
/* Schedule Queue Functions */
/* Implemented in hcd_queue.c */
/* Implemented in hcd_queue.c */
extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
					  struct dwc2_hcd_urb *urb,
					  gfp_t mem_flags);
extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
@@ -471,7 +474,7 @@ extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,


extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
			    struct dwc2_qh **qh, gfp_t mem_flags);
			    struct dwc2_qh *qh);


/* Unlinks and frees a QTD */
/* Unlinks and frees a QTD */
static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
+12 −37
Original line number Original line Diff line number Diff line
@@ -191,7 +191,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
 *
 *
 * Return: Pointer to the newly allocated QH, or NULL on error
 * Return: Pointer to the newly allocated QH, or NULL on error
 */
 */
static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
					  struct dwc2_hcd_urb *urb,
					  struct dwc2_hcd_urb *urb,
					  gfp_t mem_flags)
					  gfp_t mem_flags)
{
{
@@ -767,57 +767,32 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
 *
 *
 * @hsotg:        The DWC HCD structure
 * @hsotg:        The DWC HCD structure
 * @qtd:          The QTD to add
 * @qtd:          The QTD to add
 * @qh:           Out parameter to return queue head
 * @qh:           Queue head to add qtd to
 * @atomic_alloc: Flag to do atomic alloc if needed
 *
 *
 * Return: 0 if successful, negative error code otherwise
 * Return: 0 if successful, negative error code otherwise
 *
 *
 * Finds the correct QH to place the QTD into. If it does not find a QH, it
 * If the QH to which the QTD is added is not currently scheduled, it is placed
 * will create a new QH. If the QH to which the QTD is added is not currently
 * into the proper schedule based on its EP type.
 * scheduled, it is placed into the proper schedule based on its EP type.
 */
 */
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
		     struct dwc2_qh **qh, gfp_t mem_flags)
		     struct dwc2_qh *qh)
{
{
	struct dwc2_hcd_urb *urb = qtd->urb;
	int allocated = 0;
	int retval;
	int retval;


	/*
	if (unlikely(!qh)) {
	 * Get the QH which holds the QTD-list to insert to. Create QH if it
		dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
	 * doesn't exist.
		retval = -EINVAL;
	 */
		goto fail;
	if (*qh == NULL) {
		*qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
		if (*qh == NULL)
			return -ENOMEM;
		allocated = 1;
	}
	}


	retval = dwc2_hcd_qh_add(hsotg, *qh);
	retval = dwc2_hcd_qh_add(hsotg, qh);
	if (retval)
	if (retval)
		goto fail;
		goto fail;


	qtd->qh = *qh;
	qtd->qh = qh;
	list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
	list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);


	return 0;
	return 0;

fail:
fail:
	if (allocated) {
		struct dwc2_qtd *qtd2, *qtd2_tmp;
		struct dwc2_qh *qh_tmp = *qh;

		*qh = NULL;
		dwc2_hcd_qh_unlink(hsotg, qh_tmp);

		/* Free each QTD in the QH's QTD list */
		list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
					 qtd_list_entry)
			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);

		dwc2_hcd_qh_free(hsotg, qh_tmp);
	}

	return retval;
	return retval;
}
}
Loading