USB fixes for 3.12-rc3
Here are a number of USB driver fixes for 3.12-rc3. These are all for host controller issues that have been reported, and there's a fix for an annoying error message that gets printed every time you remove a USB 3 device from the system that's been bugging me for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.21 (GNU/Linux) iEYEABECAAYFAlJIhsIACgkQMUfUDdst+ynPjACgiw9TMpwWtAu/gbRNGJnGthR2 a+8AoJMrVPGqr0g0ypn8d35sHMnbUTAU =AZ3S -----END PGP SIGNATURE----- Merge tag 'usb-3.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a number of USB driver fixes for 3.12-rc3. These are all for host controller issues that have been reported, and there's a fix for an annoying error message that gets printed every time you remove a USB 3 device from the system that's been bugging me for a while" * tag 'usb-3.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: dwc3: add support for Merrifield USB: fsl/ehci: fix failure of checking PHY_CLK_VALID during reinitialization USB: Fix breakage in ffs_fs_mount() fsl/usb: Resolve PHY_CLK_VLD instability issue for ULPI phy usb/core/devio.c: Don't reject control message to endpoint with wrong direction bit usb: chipidea: USB_CHIPIDEA should depend on HAS_DMA usb: chipidea: udc: free pending TD at removal procedure usb: chipidea: imx: Add usb_phy_shutdown at probe's error path usb: chipidea: Fix memleak for ci->hw_bank.regmap when removal usb: chipidea: udc: fix the oops after rmmod gadget USB: fix PM config symbol in uhci-hcd, ehci-hcd, and xhci-hcd USB: OHCI: accept very late isochronous URBs USB: UHCI: accept very late isochronous URBs USB: iMX21: accept very late isochronous URBs usbcore: check usb device's state before sending a Set SEL control transfer xhci: Fix race between ep halt and URB cancellation usb: Fix xHCI host issues on remote wakeup. xhci: Ensure a command structure points to the correct trb on the command ring xhci: Fix oops happening after address device timeout
This commit is contained in:
commit
30ceb4ec33
21 changed files with 201 additions and 107 deletions
|
@ -1,6 +1,6 @@
|
||||||
config USB_CHIPIDEA
|
config USB_CHIPIDEA
|
||||||
tristate "ChipIdea Highspeed Dual Role Controller"
|
tristate "ChipIdea Highspeed Dual Role Controller"
|
||||||
depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)
|
depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA
|
||||||
help
|
help
|
||||||
Say Y here if your system has a dual role high speed USB
|
Say Y here if your system has a dual role high speed USB
|
||||||
controller based on ChipIdea silicon IP. Currently, only the
|
controller based on ChipIdea silicon IP. Currently, only the
|
||||||
|
|
|
@ -131,7 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n",
|
dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n",
|
||||||
ret);
|
ret);
|
||||||
goto err_clk;
|
goto err_phy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Can't register ci_hdrc platform device, err=%d\n",
|
"Can't register ci_hdrc platform device, err=%d\n",
|
||||||
ret);
|
ret);
|
||||||
goto err_clk;
|
goto err_phy;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->usbmisc_data) {
|
if (data->usbmisc_data) {
|
||||||
|
@ -164,6 +164,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
disable_device:
|
disable_device:
|
||||||
ci_hdrc_remove_device(data->ci_pdev);
|
ci_hdrc_remove_device(data->ci_pdev);
|
||||||
|
err_phy:
|
||||||
|
if (data->phy)
|
||||||
|
usb_phy_shutdown(data->phy);
|
||||||
err_clk:
|
err_clk:
|
||||||
clk_disable_unprepare(data->clk);
|
clk_disable_unprepare(data->clk);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -605,6 +605,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
|
||||||
dbg_remove_files(ci);
|
dbg_remove_files(ci);
|
||||||
free_irq(ci->irq, ci);
|
free_irq(ci->irq, ci);
|
||||||
ci_role_destroy(ci);
|
ci_role_destroy(ci);
|
||||||
|
kfree(ci->hw_bank.regmap);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1600,6 +1600,8 @@ static void destroy_eps(struct ci_hdrc *ci)
|
||||||
for (i = 0; i < ci->hw_ep_max; i++) {
|
for (i = 0; i < ci->hw_ep_max; i++) {
|
||||||
struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
|
struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
|
||||||
|
|
||||||
|
if (hwep->pending_td)
|
||||||
|
free_pending_td(hwep);
|
||||||
dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma);
|
dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1667,13 +1669,13 @@ static int ci_udc_stop(struct usb_gadget *gadget,
|
||||||
if (ci->platdata->notify_event)
|
if (ci->platdata->notify_event)
|
||||||
ci->platdata->notify_event(ci,
|
ci->platdata->notify_event(ci,
|
||||||
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
||||||
ci->driver = NULL;
|
|
||||||
spin_unlock_irqrestore(&ci->lock, flags);
|
spin_unlock_irqrestore(&ci->lock, flags);
|
||||||
_gadget_stop_activity(&ci->gadget);
|
_gadget_stop_activity(&ci->gadget);
|
||||||
spin_lock_irqsave(&ci->lock, flags);
|
spin_lock_irqsave(&ci->lock, flags);
|
||||||
pm_runtime_put(&ci->gadget.dev);
|
pm_runtime_put(&ci->gadget.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->driver = NULL;
|
||||||
spin_unlock_irqrestore(&ci->lock, flags);
|
spin_unlock_irqrestore(&ci->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -742,6 +742,22 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
|
||||||
if ((index & ~USB_DIR_IN) == 0)
|
if ((index & ~USB_DIR_IN) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
ret = findintfep(ps->dev, index);
|
ret = findintfep(ps->dev, index);
|
||||||
|
if (ret < 0) {
|
||||||
|
/*
|
||||||
|
* Some not fully compliant Win apps seem to get
|
||||||
|
* index wrong and have the endpoint number here
|
||||||
|
* rather than the endpoint address (with the
|
||||||
|
* correct direction). Win does let this through,
|
||||||
|
* so we'll not reject it here but leave it to
|
||||||
|
* the device to not break KVM. But we warn.
|
||||||
|
*/
|
||||||
|
ret = findintfep(ps->dev, index ^ 0x80);
|
||||||
|
if (ret >= 0)
|
||||||
|
dev_info(&ps->dev->dev,
|
||||||
|
"%s: process %i (%s) requesting ep %02x but needs %02x\n",
|
||||||
|
__func__, task_pid_nr(current),
|
||||||
|
current->comm, index, index ^ 0x80);
|
||||||
|
}
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
ret = checkintf(ps, ret);
|
ret = checkintf(ps, ret);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3426,6 +3426,9 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
|
||||||
unsigned long long u2_pel;
|
unsigned long long u2_pel;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (udev->state != USB_STATE_CONFIGURED)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Convert SEL and PEL stored in ns to us */
|
/* Convert SEL and PEL stored in ns to us */
|
||||||
u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
|
u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
|
||||||
u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
|
u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
|
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
|
||||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||||||
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
||||||
|
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
|
||||||
|
|
||||||
struct dwc3_pci {
|
struct dwc3_pci {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -189,6 +190,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
|
||||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
||||||
},
|
},
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
|
||||||
{ } /* Terminating Entry */
|
{ } /* Terminating Entry */
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
||||||
|
|
|
@ -1034,37 +1034,19 @@ struct ffs_sb_fill_data {
|
||||||
struct ffs_file_perms perms;
|
struct ffs_file_perms perms;
|
||||||
umode_t root_mode;
|
umode_t root_mode;
|
||||||
const char *dev_name;
|
const char *dev_name;
|
||||||
union {
|
|
||||||
/* set by ffs_fs_mount(), read by ffs_sb_fill() */
|
|
||||||
void *private_data;
|
|
||||||
/* set by ffs_sb_fill(), read by ffs_fs_mount */
|
|
||||||
struct ffs_data *ffs_data;
|
struct ffs_data *ffs_data;
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
|
static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
|
||||||
{
|
{
|
||||||
struct ffs_sb_fill_data *data = _data;
|
struct ffs_sb_fill_data *data = _data;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct ffs_data *ffs;
|
struct ffs_data *ffs = data->ffs_data;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
/* Initialise data */
|
|
||||||
ffs = ffs_data_new();
|
|
||||||
if (unlikely(!ffs))
|
|
||||||
goto Enomem;
|
|
||||||
|
|
||||||
ffs->sb = sb;
|
ffs->sb = sb;
|
||||||
ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL);
|
data->ffs_data = NULL;
|
||||||
if (unlikely(!ffs->dev_name))
|
|
||||||
goto Enomem;
|
|
||||||
ffs->file_perms = data->perms;
|
|
||||||
ffs->private_data = data->private_data;
|
|
||||||
|
|
||||||
/* used by the caller of this function */
|
|
||||||
data->ffs_data = ffs;
|
|
||||||
|
|
||||||
sb->s_fs_info = ffs;
|
sb->s_fs_info = ffs;
|
||||||
sb->s_blocksize = PAGE_CACHE_SIZE;
|
sb->s_blocksize = PAGE_CACHE_SIZE;
|
||||||
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
|
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
|
||||||
|
@ -1080,17 +1062,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
|
||||||
&data->perms);
|
&data->perms);
|
||||||
sb->s_root = d_make_root(inode);
|
sb->s_root = d_make_root(inode);
|
||||||
if (unlikely(!sb->s_root))
|
if (unlikely(!sb->s_root))
|
||||||
goto Enomem;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* EP0 file */
|
/* EP0 file */
|
||||||
if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
|
if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
|
||||||
&ffs_ep0_operations, NULL)))
|
&ffs_ep0_operations, NULL)))
|
||||||
goto Enomem;
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Enomem:
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
||||||
|
@ -1193,6 +1172,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
|
||||||
struct dentry *rv;
|
struct dentry *rv;
|
||||||
int ret;
|
int ret;
|
||||||
void *ffs_dev;
|
void *ffs_dev;
|
||||||
|
struct ffs_data *ffs;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
|
@ -1200,18 +1180,30 @@ ffs_fs_mount(struct file_system_type *t, int flags,
|
||||||
if (unlikely(ret < 0))
|
if (unlikely(ret < 0))
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
ffs = ffs_data_new();
|
||||||
|
if (unlikely(!ffs))
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
ffs->file_perms = data.perms;
|
||||||
|
|
||||||
|
ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
|
||||||
|
if (unlikely(!ffs->dev_name)) {
|
||||||
|
ffs_data_put(ffs);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
ffs_dev = functionfs_acquire_dev_callback(dev_name);
|
ffs_dev = functionfs_acquire_dev_callback(dev_name);
|
||||||
if (IS_ERR(ffs_dev))
|
if (IS_ERR(ffs_dev)) {
|
||||||
return ffs_dev;
|
ffs_data_put(ffs);
|
||||||
|
return ERR_CAST(ffs_dev);
|
||||||
|
}
|
||||||
|
ffs->private_data = ffs_dev;
|
||||||
|
data.ffs_data = ffs;
|
||||||
|
|
||||||
data.dev_name = dev_name;
|
|
||||||
data.private_data = ffs_dev;
|
|
||||||
rv = mount_nodev(t, flags, &data, ffs_sb_fill);
|
rv = mount_nodev(t, flags, &data, ffs_sb_fill);
|
||||||
|
if (IS_ERR(rv) && data.ffs_data) {
|
||||||
/* data.ffs_data is set by ffs_sb_fill */
|
|
||||||
if (IS_ERR(rv))
|
|
||||||
functionfs_release_dev_callback(data.ffs_data);
|
functionfs_release_dev_callback(data.ffs_data);
|
||||||
|
ffs_data_put(data.ffs_data);
|
||||||
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable USB controller, 83xx or 8536 */
|
/* Enable USB controller, 83xx or 8536 */
|
||||||
if (pdata->have_sysif_regs)
|
if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6)
|
||||||
setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
|
setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
|
||||||
|
|
||||||
/* Don't need to set host mode here. It will be done by tdi_reset() */
|
/* Don't need to set host mode here. It will be done by tdi_reset() */
|
||||||
|
@ -232,15 +232,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
|
||||||
case FSL_USB2_PHY_ULPI:
|
case FSL_USB2_PHY_ULPI:
|
||||||
if (pdata->have_sysif_regs && pdata->controller_ver) {
|
if (pdata->have_sysif_regs && pdata->controller_ver) {
|
||||||
/* controller version 1.6 or above */
|
/* controller version 1.6 or above */
|
||||||
|
clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
|
||||||
setbits32(non_ehci + FSL_SOC_USB_CTRL,
|
setbits32(non_ehci + FSL_SOC_USB_CTRL,
|
||||||
ULPI_PHY_CLK_SEL);
|
ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN);
|
||||||
/*
|
|
||||||
* Due to controller issue of PHY_CLK_VALID in ULPI
|
|
||||||
* mode, we set USB_CTRL_USB_EN before checking
|
|
||||||
* PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work.
|
|
||||||
*/
|
|
||||||
clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
|
|
||||||
UTMI_PHY_EN, USB_CTRL_USB_EN);
|
|
||||||
}
|
}
|
||||||
portsc |= PORT_PTS_ULPI;
|
portsc |= PORT_PTS_ULPI;
|
||||||
break;
|
break;
|
||||||
|
@ -270,8 +264,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
|
||||||
if (pdata->have_sysif_regs && pdata->controller_ver &&
|
if (pdata->have_sysif_regs && pdata->controller_ver &&
|
||||||
(phy_mode == FSL_USB2_PHY_ULPI)) {
|
(phy_mode == FSL_USB2_PHY_ULPI)) {
|
||||||
/* check PHY_CLK_VALID to get phy clk valid */
|
/* check PHY_CLK_VALID to get phy clk valid */
|
||||||
if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
|
if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
|
||||||
PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
|
PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) ||
|
||||||
|
in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) {
|
||||||
printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
|
printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,7 +361,7 @@ static struct pci_driver ehci_pci_driver = {
|
||||||
.remove = usb_hcd_pci_remove,
|
.remove = usb_hcd_pci_remove,
|
||||||
.shutdown = usb_hcd_pci_shutdown,
|
.shutdown = usb_hcd_pci_shutdown,
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
.driver = {
|
.driver = {
|
||||||
.pm = &usb_hcd_pci_pm_ops
|
.pm = &usb_hcd_pci_pm_ops
|
||||||
},
|
},
|
||||||
|
|
|
@ -824,13 +824,13 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
|
||||||
i = DIV_ROUND_UP(wrap_frame(
|
i = DIV_ROUND_UP(wrap_frame(
|
||||||
cur_frame - urb->start_frame),
|
cur_frame - urb->start_frame),
|
||||||
urb->interval);
|
urb->interval);
|
||||||
if (urb->transfer_flags & URB_ISO_ASAP) {
|
|
||||||
|
/* Treat underruns as if URB_ISO_ASAP was set */
|
||||||
|
if ((urb->transfer_flags & URB_ISO_ASAP) ||
|
||||||
|
i >= urb->number_of_packets) {
|
||||||
urb->start_frame = wrap_frame(urb->start_frame
|
urb->start_frame = wrap_frame(urb->start_frame
|
||||||
+ i * urb->interval);
|
+ i * urb->interval);
|
||||||
i = 0;
|
i = 0;
|
||||||
} else if (i >= urb->number_of_packets) {
|
|
||||||
ret = -EXDEV;
|
|
||||||
goto alloc_dmem_failed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,31 +216,26 @@ static int ohci_urb_enqueue (
|
||||||
frame &= ~(ed->interval - 1);
|
frame &= ~(ed->interval - 1);
|
||||||
frame |= ed->branch;
|
frame |= ed->branch;
|
||||||
urb->start_frame = frame;
|
urb->start_frame = frame;
|
||||||
|
ed->last_iso = frame + ed->interval * (size - 1);
|
||||||
}
|
}
|
||||||
} else if (ed->type == PIPE_ISOCHRONOUS) {
|
} else if (ed->type == PIPE_ISOCHRONOUS) {
|
||||||
u16 next = ohci_frame_no(ohci) + 1;
|
u16 next = ohci_frame_no(ohci) + 1;
|
||||||
u16 frame = ed->last_iso + ed->interval;
|
u16 frame = ed->last_iso + ed->interval;
|
||||||
|
u16 length = ed->interval * (size - 1);
|
||||||
|
|
||||||
/* Behind the scheduling threshold? */
|
/* Behind the scheduling threshold? */
|
||||||
if (unlikely(tick_before(frame, next))) {
|
if (unlikely(tick_before(frame, next))) {
|
||||||
|
|
||||||
/* USB_ISO_ASAP: Round up to the first available slot */
|
/* URB_ISO_ASAP: Round up to the first available slot */
|
||||||
if (urb->transfer_flags & URB_ISO_ASAP) {
|
if (urb->transfer_flags & URB_ISO_ASAP) {
|
||||||
frame += (next - frame + ed->interval - 1) &
|
frame += (next - frame + ed->interval - 1) &
|
||||||
-ed->interval;
|
-ed->interval;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not ASAP: Use the next slot in the stream. If
|
* Not ASAP: Use the next slot in the stream,
|
||||||
* the entire URB falls before the threshold, fail.
|
* no matter what.
|
||||||
*/
|
*/
|
||||||
} else {
|
} else {
|
||||||
if (tick_before(frame + ed->interval *
|
|
||||||
(urb->number_of_packets - 1), next)) {
|
|
||||||
retval = -EXDEV;
|
|
||||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some OHCI hardware doesn't handle late TDs
|
* Some OHCI hardware doesn't handle late TDs
|
||||||
* correctly. After retiring them it proceeds
|
* correctly. After retiring them it proceeds
|
||||||
|
@ -251,9 +246,16 @@ static int ohci_urb_enqueue (
|
||||||
urb_priv->td_cnt = DIV_ROUND_UP(
|
urb_priv->td_cnt = DIV_ROUND_UP(
|
||||||
(u16) (next - frame),
|
(u16) (next - frame),
|
||||||
ed->interval);
|
ed->interval);
|
||||||
|
if (urb_priv->td_cnt >= urb_priv->length) {
|
||||||
|
++urb_priv->td_cnt; /* Mark it */
|
||||||
|
ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n",
|
||||||
|
urb, frame, length,
|
||||||
|
next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
urb->start_frame = frame;
|
urb->start_frame = frame;
|
||||||
|
ed->last_iso = frame + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill the TDs and link them to the ed; and
|
/* fill the TDs and link them to the ed; and
|
||||||
|
|
|
@ -42,8 +42,12 @@ __releases(ohci->lock)
|
||||||
__acquires(ohci->lock)
|
__acquires(ohci->lock)
|
||||||
{
|
{
|
||||||
struct device *dev = ohci_to_hcd(ohci)->self.controller;
|
struct device *dev = ohci_to_hcd(ohci)->self.controller;
|
||||||
|
struct usb_host_endpoint *ep = urb->ep;
|
||||||
|
struct urb_priv *urb_priv;
|
||||||
|
|
||||||
// ASSERT (urb->hcpriv != 0);
|
// ASSERT (urb->hcpriv != 0);
|
||||||
|
|
||||||
|
restart:
|
||||||
urb_free_priv (ohci, urb->hcpriv);
|
urb_free_priv (ohci, urb->hcpriv);
|
||||||
urb->hcpriv = NULL;
|
urb->hcpriv = NULL;
|
||||||
if (likely(status == -EINPROGRESS))
|
if (likely(status == -EINPROGRESS))
|
||||||
|
@ -80,6 +84,21 @@ __acquires(ohci->lock)
|
||||||
ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE);
|
ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE);
|
||||||
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
|
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An isochronous URB that is sumitted too late won't have any TDs
|
||||||
|
* (marked by the fact that the td_cnt value is larger than the
|
||||||
|
* actual number of TDs). If the next URB on this endpoint is like
|
||||||
|
* that, give it back now.
|
||||||
|
*/
|
||||||
|
if (!list_empty(&ep->urb_list)) {
|
||||||
|
urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
|
||||||
|
urb_priv = urb->hcpriv;
|
||||||
|
if (urb_priv->td_cnt > urb_priv->length) {
|
||||||
|
status = 0;
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -546,7 +565,6 @@ td_fill (struct ohci_hcd *ohci, u32 info,
|
||||||
td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
|
td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
|
||||||
*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
|
*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,
|
||||||
(data & 0x0FFF) | 0xE000);
|
(data & 0x0FFF) | 0xE000);
|
||||||
td->ed->last_iso = info & 0xffff;
|
|
||||||
} else {
|
} else {
|
||||||
td->hwCBP = cpu_to_hc32 (ohci, data);
|
td->hwCBP = cpu_to_hc32 (ohci, data);
|
||||||
}
|
}
|
||||||
|
@ -996,7 +1014,7 @@ rescan_this:
|
||||||
urb_priv->td_cnt++;
|
urb_priv->td_cnt++;
|
||||||
|
|
||||||
/* if URB is done, clean up */
|
/* if URB is done, clean up */
|
||||||
if (urb_priv->td_cnt == urb_priv->length) {
|
if (urb_priv->td_cnt >= urb_priv->length) {
|
||||||
modified = completed = 1;
|
modified = completed = 1;
|
||||||
finish_urb(ohci, urb, 0);
|
finish_urb(ohci, urb, 0);
|
||||||
}
|
}
|
||||||
|
@ -1086,7 +1104,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)
|
||||||
urb_priv->td_cnt++;
|
urb_priv->td_cnt++;
|
||||||
|
|
||||||
/* If all this urb's TDs are done, call complete() */
|
/* If all this urb's TDs are done, call complete() */
|
||||||
if (urb_priv->td_cnt == urb_priv->length)
|
if (urb_priv->td_cnt >= urb_priv->length)
|
||||||
finish_urb(ohci, urb, status);
|
finish_urb(ohci, urb, status);
|
||||||
|
|
||||||
/* clean schedule: unlink EDs that are no longer busy */
|
/* clean schedule: unlink EDs that are no longer busy */
|
||||||
|
|
|
@ -293,7 +293,7 @@ static struct pci_driver uhci_pci_driver = {
|
||||||
.remove = usb_hcd_pci_remove,
|
.remove = usb_hcd_pci_remove,
|
||||||
.shutdown = uhci_shutdown,
|
.shutdown = uhci_shutdown,
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
.driver = {
|
.driver = {
|
||||||
.pm = &usb_hcd_pci_pm_ops
|
.pm = &usb_hcd_pci_pm_ops
|
||||||
},
|
},
|
||||||
|
|
|
@ -1303,7 +1303,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fell behind? */
|
/* Fell behind? */
|
||||||
if (uhci_frame_before_eq(frame, next)) {
|
if (!uhci_frame_before_eq(next, frame)) {
|
||||||
|
|
||||||
/* USB_ISO_ASAP: Round up to the first available slot */
|
/* USB_ISO_ASAP: Round up to the first available slot */
|
||||||
if (urb->transfer_flags & URB_ISO_ASAP)
|
if (urb->transfer_flags & URB_ISO_ASAP)
|
||||||
|
@ -1311,13 +1311,17 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
|
||||||
-qh->period;
|
-qh->period;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not ASAP: Use the next slot in the stream. If
|
* Not ASAP: Use the next slot in the stream,
|
||||||
* the entire URB falls before the threshold, fail.
|
* no matter what.
|
||||||
*/
|
*/
|
||||||
else if (!uhci_frame_before_eq(next,
|
else if (!uhci_frame_before_eq(next,
|
||||||
frame + (urb->number_of_packets - 1) *
|
frame + (urb->number_of_packets - 1) *
|
||||||
qh->period))
|
qh->period))
|
||||||
return -EXDEV;
|
dev_dbg(uhci_dev(uhci), "iso underrun %p (%u+%u < %u)\n",
|
||||||
|
urb, frame,
|
||||||
|
(urb->number_of_packets - 1) *
|
||||||
|
qh->period,
|
||||||
|
next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
|
||||||
if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
|
if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
|
||||||
xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
|
xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
|
||||||
}
|
}
|
||||||
cmd->command_trb = xhci->cmd_ring->enqueue;
|
cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
|
||||||
list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
|
list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
|
||||||
xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
|
xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
|
||||||
xhci_ring_cmd_db(xhci);
|
xhci_ring_cmd_db(xhci);
|
||||||
|
@ -552,11 +552,15 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
|
||||||
* - Mark a port as being done with device resume,
|
* - Mark a port as being done with device resume,
|
||||||
* and ring the endpoint doorbells.
|
* and ring the endpoint doorbells.
|
||||||
* - Stop the Synopsys redriver Compliance Mode polling.
|
* - Stop the Synopsys redriver Compliance Mode polling.
|
||||||
|
* - Drop and reacquire the xHCI lock, in order to wait for port resume.
|
||||||
*/
|
*/
|
||||||
static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
||||||
struct xhci_bus_state *bus_state,
|
struct xhci_bus_state *bus_state,
|
||||||
__le32 __iomem **port_array,
|
__le32 __iomem **port_array,
|
||||||
u16 wIndex, u32 raw_port_status)
|
u16 wIndex, u32 raw_port_status,
|
||||||
|
unsigned long flags)
|
||||||
|
__releases(&xhci->lock)
|
||||||
|
__acquires(&xhci->lock)
|
||||||
{
|
{
|
||||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
u32 status = 0;
|
u32 status = 0;
|
||||||
|
@ -591,21 +595,42 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
||||||
return 0xffffffff;
|
return 0xffffffff;
|
||||||
if (time_after_eq(jiffies,
|
if (time_after_eq(jiffies,
|
||||||
bus_state->resume_done[wIndex])) {
|
bus_state->resume_done[wIndex])) {
|
||||||
|
int time_left;
|
||||||
|
|
||||||
xhci_dbg(xhci, "Resume USB2 port %d\n",
|
xhci_dbg(xhci, "Resume USB2 port %d\n",
|
||||||
wIndex + 1);
|
wIndex + 1);
|
||||||
bus_state->resume_done[wIndex] = 0;
|
bus_state->resume_done[wIndex] = 0;
|
||||||
clear_bit(wIndex, &bus_state->resuming_ports);
|
clear_bit(wIndex, &bus_state->resuming_ports);
|
||||||
|
|
||||||
|
set_bit(wIndex, &bus_state->rexit_ports);
|
||||||
xhci_set_link_state(xhci, port_array, wIndex,
|
xhci_set_link_state(xhci, port_array, wIndex,
|
||||||
XDEV_U0);
|
XDEV_U0);
|
||||||
xhci_dbg(xhci, "set port %d resume\n",
|
|
||||||
wIndex + 1);
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
time_left = wait_for_completion_timeout(
|
||||||
wIndex + 1);
|
&bus_state->rexit_done[wIndex],
|
||||||
|
msecs_to_jiffies(
|
||||||
|
XHCI_MAX_REXIT_TIMEOUT));
|
||||||
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
|
|
||||||
|
if (time_left) {
|
||||||
|
slot_id = xhci_find_slot_id_by_port(hcd,
|
||||||
|
xhci, wIndex + 1);
|
||||||
if (!slot_id) {
|
if (!slot_id) {
|
||||||
xhci_dbg(xhci, "slot_id is zero\n");
|
xhci_dbg(xhci, "slot_id is zero\n");
|
||||||
return 0xffffffff;
|
return 0xffffffff;
|
||||||
}
|
}
|
||||||
xhci_ring_device(xhci, slot_id);
|
xhci_ring_device(xhci, slot_id);
|
||||||
|
} else {
|
||||||
|
int port_status = xhci_readl(xhci,
|
||||||
|
port_array[wIndex]);
|
||||||
|
xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n",
|
||||||
|
XHCI_MAX_REXIT_TIMEOUT,
|
||||||
|
port_status);
|
||||||
|
status |= USB_PORT_STAT_SUSPEND;
|
||||||
|
clear_bit(wIndex, &bus_state->rexit_ports);
|
||||||
|
}
|
||||||
|
|
||||||
bus_state->port_c_suspend |= 1 << wIndex;
|
bus_state->port_c_suspend |= 1 << wIndex;
|
||||||
bus_state->suspended_ports &= ~(1 << wIndex);
|
bus_state->suspended_ports &= ~(1 << wIndex);
|
||||||
} else {
|
} else {
|
||||||
|
@ -728,7 +753,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
status = xhci_get_port_status(hcd, bus_state, port_array,
|
status = xhci_get_port_status(hcd, bus_state, port_array,
|
||||||
wIndex, temp);
|
wIndex, temp, flags);
|
||||||
if (status == 0xffffffff)
|
if (status == 0xffffffff)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
|
|
@ -2428,6 +2428,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||||||
for (i = 0; i < USB_MAXCHILDREN; ++i) {
|
for (i = 0; i < USB_MAXCHILDREN; ++i) {
|
||||||
xhci->bus_state[0].resume_done[i] = 0;
|
xhci->bus_state[0].resume_done[i] = 0;
|
||||||
xhci->bus_state[1].resume_done[i] = 0;
|
xhci->bus_state[1].resume_done[i] = 0;
|
||||||
|
/* Only the USB 2.0 completions will ever be used. */
|
||||||
|
init_completion(&xhci->bus_state[1].rexit_done[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scratchpad_alloc(xhci, flags))
|
if (scratchpad_alloc(xhci, flags))
|
||||||
|
|
|
@ -351,7 +351,7 @@ static struct pci_driver xhci_pci_driver = {
|
||||||
/* suspend and resume implemented later */
|
/* suspend and resume implemented later */
|
||||||
|
|
||||||
.shutdown = usb_hcd_pci_shutdown,
|
.shutdown = usb_hcd_pci_shutdown,
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM
|
||||||
.driver = {
|
.driver = {
|
||||||
.pm = &usb_hcd_pci_pm_ops
|
.pm = &usb_hcd_pci_pm_ops
|
||||||
},
|
},
|
||||||
|
|
|
@ -123,6 +123,16 @@ static int enqueue_is_link_trb(struct xhci_ring *ring)
|
||||||
return TRB_TYPE_LINK_LE32(link->control);
|
return TRB_TYPE_LINK_LE32(link->control);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring)
|
||||||
|
{
|
||||||
|
/* Enqueue pointer can be left pointing to the link TRB,
|
||||||
|
* we must handle that
|
||||||
|
*/
|
||||||
|
if (TRB_TYPE_LINK_LE32(ring->enqueue->link.control))
|
||||||
|
return ring->enq_seg->next->trbs;
|
||||||
|
return ring->enqueue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Updates trb to point to the next TRB in the ring, and updates seg if the next
|
/* Updates trb to point to the next TRB in the ring, and updates seg if the next
|
||||||
* TRB is in a new segment. This does not skip over link TRBs, and it does not
|
* TRB is in a new segment. This does not skip over link TRBs, and it does not
|
||||||
* effect the ring dequeue or enqueue pointers.
|
* effect the ring dequeue or enqueue pointers.
|
||||||
|
@ -859,8 +869,12 @@ remove_finished_td:
|
||||||
/* Otherwise ring the doorbell(s) to restart queued transfers */
|
/* Otherwise ring the doorbell(s) to restart queued transfers */
|
||||||
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
|
ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear stopped_td and stopped_trb if endpoint is not halted */
|
||||||
|
if (!(ep->ep_state & EP_HALTED)) {
|
||||||
ep->stopped_td = NULL;
|
ep->stopped_td = NULL;
|
||||||
ep->stopped_trb = NULL;
|
ep->stopped_trb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop the lock and complete the URBs in the cancelled TD list.
|
* Drop the lock and complete the URBs in the cancelled TD list.
|
||||||
|
@ -1414,6 +1428,12 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||||||
inc_deq(xhci, xhci->cmd_ring);
|
inc_deq(xhci, xhci->cmd_ring);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* There is no command to handle if we get a stop event when the
|
||||||
|
* command ring is empty, event->cmd_trb points to the next
|
||||||
|
* unset command
|
||||||
|
*/
|
||||||
|
if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
|
switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])
|
||||||
|
@ -1743,6 +1763,19 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if xhci-hub.c is waiting on RExit to U0 transition (or
|
||||||
|
* RExit to a disconnect state). If so, let the the driver know it's
|
||||||
|
* out of the RExit state.
|
||||||
|
*/
|
||||||
|
if (!DEV_SUPERSPEED(temp) &&
|
||||||
|
test_and_clear_bit(faked_port_index,
|
||||||
|
&bus_state->rexit_ports)) {
|
||||||
|
complete(&bus_state->rexit_done[faked_port_index]);
|
||||||
|
bogus_port_status = true;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (hcd->speed != HCD_USB3)
|
if (hcd->speed != HCD_USB3)
|
||||||
xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
|
xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
|
||||||
PORT_PLC);
|
PORT_PLC);
|
||||||
|
|
|
@ -2598,15 +2598,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||||
if (command) {
|
if (command) {
|
||||||
cmd_completion = command->completion;
|
cmd_completion = command->completion;
|
||||||
cmd_status = &command->status;
|
cmd_status = &command->status;
|
||||||
command->command_trb = xhci->cmd_ring->enqueue;
|
command->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
|
||||||
|
|
||||||
/* Enqueue pointer can be left pointing to the link TRB,
|
|
||||||
* we must handle that
|
|
||||||
*/
|
|
||||||
if (TRB_TYPE_LINK_LE32(command->command_trb->link.control))
|
|
||||||
command->command_trb =
|
|
||||||
xhci->cmd_ring->enq_seg->next->trbs;
|
|
||||||
|
|
||||||
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
|
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
|
||||||
} else {
|
} else {
|
||||||
cmd_completion = &virt_dev->cmd_completion;
|
cmd_completion = &virt_dev->cmd_completion;
|
||||||
|
@ -2614,7 +2606,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
||||||
}
|
}
|
||||||
init_completion(cmd_completion);
|
init_completion(cmd_completion);
|
||||||
|
|
||||||
cmd_trb = xhci->cmd_ring->dequeue;
|
cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
|
||||||
if (!ctx_change)
|
if (!ctx_change)
|
||||||
ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
|
ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
|
||||||
udev->slot_id, must_succeed);
|
udev->slot_id, must_succeed);
|
||||||
|
@ -3439,14 +3431,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
|
|
||||||
/* Attempt to submit the Reset Device command to the command ring */
|
/* Attempt to submit the Reset Device command to the command ring */
|
||||||
spin_lock_irqsave(&xhci->lock, flags);
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
|
reset_device_cmd->command_trb = xhci_find_next_enqueue(xhci->cmd_ring);
|
||||||
|
|
||||||
/* Enqueue pointer can be left pointing to the link TRB,
|
|
||||||
* we must handle that
|
|
||||||
*/
|
|
||||||
if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control))
|
|
||||||
reset_device_cmd->command_trb =
|
|
||||||
xhci->cmd_ring->enq_seg->next->trbs;
|
|
||||||
|
|
||||||
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
|
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
|
||||||
ret = xhci_queue_reset_device(xhci, slot_id);
|
ret = xhci_queue_reset_device(xhci, slot_id);
|
||||||
|
@ -3650,7 +3635,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
union xhci_trb *cmd_trb;
|
union xhci_trb *cmd_trb;
|
||||||
|
|
||||||
spin_lock_irqsave(&xhci->lock, flags);
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
cmd_trb = xhci->cmd_ring->dequeue;
|
cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
|
||||||
ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
|
ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||||
|
@ -3785,7 +3770,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||||
slot_ctx->dev_info >> 27);
|
slot_ctx->dev_info >> 27);
|
||||||
|
|
||||||
spin_lock_irqsave(&xhci->lock, flags);
|
spin_lock_irqsave(&xhci->lock, flags);
|
||||||
cmd_trb = xhci->cmd_ring->dequeue;
|
cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring);
|
||||||
ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
|
ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma,
|
||||||
udev->slot_id);
|
udev->slot_id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -1412,8 +1412,18 @@ struct xhci_bus_state {
|
||||||
unsigned long resume_done[USB_MAXCHILDREN];
|
unsigned long resume_done[USB_MAXCHILDREN];
|
||||||
/* which ports have started to resume */
|
/* which ports have started to resume */
|
||||||
unsigned long resuming_ports;
|
unsigned long resuming_ports;
|
||||||
|
/* Which ports are waiting on RExit to U0 transition. */
|
||||||
|
unsigned long rexit_ports;
|
||||||
|
struct completion rexit_done[USB_MAXCHILDREN];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It can take up to 20 ms to transition from RExit to U0 on the
|
||||||
|
* Intel Lynx Point LP xHCI host.
|
||||||
|
*/
|
||||||
|
#define XHCI_MAX_REXIT_TIMEOUT (20 * 1000)
|
||||||
|
|
||||||
static inline unsigned int hcd_index(struct usb_hcd *hcd)
|
static inline unsigned int hcd_index(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
if (hcd->speed == HCD_USB3)
|
if (hcd->speed == HCD_USB3)
|
||||||
|
@ -1840,6 +1850,7 @@ int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command,
|
||||||
union xhci_trb *cmd_trb);
|
union xhci_trb *cmd_trb);
|
||||||
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
|
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
|
||||||
unsigned int ep_index, unsigned int stream_id);
|
unsigned int ep_index, unsigned int stream_id);
|
||||||
|
union xhci_trb *xhci_find_next_enqueue(struct xhci_ring *ring);
|
||||||
|
|
||||||
/* xHCI roothub code */
|
/* xHCI roothub code */
|
||||||
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||||
|
|
Loading…
Reference in a new issue