USB fixes for 4.2-rc4
Here's a few USB and PHY fixes for 4.2-rc4. Nothing major, the shortlog has the full details. All of these have been in linux-next successfully. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlW0QPkACgkQMUfUDdst+ym+bQCgj/ka2wRF+7+zr3EyZpn0TJc2 a7wAn3lwAjE0AZOZhg7qS3HcoMi9Q1GV =hLdX -----END PGP SIGNATURE----- Merge tag 'usb-4.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here's a few USB and PHY fixes for 4.2-rc4. Nothing major, the shortlog has the full details. All of these have been in linux-next successfully" * tag 'usb-4.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (21 commits) USB: OHCI: fix bad #define in ohci-tmio.c cdc-acm: Destroy acm_minors IDR on module exit usb-storage: Add ignore-device quirk for gm12u320 based usb mini projectors usb-storage: ignore ZTE MF 823 card reader in mode 0x1225 USB: OHCI: Fix race between ED unlink and URB submission usb: core: lpm: set lpm_capable for root hub device xhci: do not report PLC when link is in internal resume state xhci: prevent bus_suspend if SS port resuming in phase 1 xhci: report U3 when link is in resume state xhci: Calculate old endpoints correctly on device reset usb: xhci: Bugfix for NULL pointer deference in xhci_endpoint_init() function xhci: Workaround to get D3 working in Intel xHCI xhci: call BIOS workaround to enable runtime suspend on Intel Braswell usb: dwc3: Reset the transfer resource index on SET_INTERFACE usb: gadget: udc: core: Fix argument of dma_map_single for IOMMU usb: gadget: mv_udc_core: fix phy_regs I/O memory leak usb: ulpi: ulpi_init should be executed in subsys_initcall phy: berlin-usb: fix divider for BG2 phy: berlin-usb: fix divider for BG2CD phy/pxa: add HAS_IOMEM dependency ...
This commit is contained in:
commit
26ae19a388
20 changed files with 169 additions and 160 deletions
|
@ -56,6 +56,7 @@ config PHY_EXYNOS_MIPI_VIDEO
|
|||
|
||||
config PHY_PXA_28NM_HSIC
|
||||
tristate "Marvell USB HSIC 28nm PHY Driver"
|
||||
depends on HAS_IOMEM
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Marvell USB HSIC PHY driver for Marvell
|
||||
|
@ -66,6 +67,7 @@ config PHY_PXA_28NM_HSIC
|
|||
|
||||
config PHY_PXA_28NM_USB2
|
||||
tristate "Marvell USB 2.0 28nm PHY Driver"
|
||||
depends on HAS_IOMEM
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Marvell USB 2.0 PHY driver for Marvell
|
||||
|
|
|
@ -105,9 +105,9 @@
|
|||
|
||||
static const u32 phy_berlin_pll_dividers[] = {
|
||||
/* Berlin 2 */
|
||||
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
|
||||
/* Berlin 2CD */
|
||||
CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
|
||||
/* Berlin 2CD/Q */
|
||||
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
|
||||
};
|
||||
|
||||
struct phy_berlin_usb_priv {
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/phy/omap_control_phy.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define PLL_STATUS 0x00000004
|
||||
#define PLL_GO 0x00000008
|
||||
|
@ -83,10 +82,6 @@ struct ti_pipe3 {
|
|||
struct clk *refclk;
|
||||
struct clk *div_clk;
|
||||
struct pipe3_dpll_map *dpll_map;
|
||||
bool enabled;
|
||||
spinlock_t lock; /* serialize clock enable/disable */
|
||||
/* the below flag is needed specifically for SATA */
|
||||
bool refclk_enabled;
|
||||
};
|
||||
|
||||
static struct pipe3_dpll_map dpll_map_usb[] = {
|
||||
|
@ -137,6 +132,9 @@ static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy);
|
||||
static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy);
|
||||
|
||||
static int ti_pipe3_power_off(struct phy *x)
|
||||
{
|
||||
struct ti_pipe3 *phy = phy_get_drvdata(x);
|
||||
|
@ -217,6 +215,7 @@ static int ti_pipe3_init(struct phy *x)
|
|||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
ti_pipe3_enable_clocks(phy);
|
||||
/*
|
||||
* Set pcie_pcs register to 0x96 for proper functioning of phy
|
||||
* as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table
|
||||
|
@ -250,33 +249,35 @@ static int ti_pipe3_exit(struct phy *x)
|
|||
u32 val;
|
||||
unsigned long timeout;
|
||||
|
||||
/* SATA DPLL can't be powered down due to Errata i783 and PCIe
|
||||
* does not have internal DPLL
|
||||
*/
|
||||
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") ||
|
||||
of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie"))
|
||||
/* SATA DPLL can't be powered down due to Errata i783 */
|
||||
if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
|
||||
return 0;
|
||||
|
||||
/* Put DPLL in IDLE mode */
|
||||
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
|
||||
val |= PLL_IDLE;
|
||||
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
|
||||
/* PCIe doesn't have internal DPLL */
|
||||
if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) {
|
||||
/* Put DPLL in IDLE mode */
|
||||
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
|
||||
val |= PLL_IDLE;
|
||||
ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
|
||||
|
||||
/* wait for LDO and Oscillator to power down */
|
||||
timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
|
||||
do {
|
||||
cpu_relax();
|
||||
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
|
||||
if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
|
||||
break;
|
||||
} while (!time_after(jiffies, timeout));
|
||||
/* wait for LDO and Oscillator to power down */
|
||||
timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
|
||||
do {
|
||||
cpu_relax();
|
||||
val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
|
||||
if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
|
||||
break;
|
||||
} while (!time_after(jiffies, timeout));
|
||||
|
||||
if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
|
||||
dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
|
||||
val);
|
||||
return -EBUSY;
|
||||
if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
|
||||
dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
|
||||
val);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
ti_pipe3_disable_clocks(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static struct phy_ops ops = {
|
||||
|
@ -306,7 +307,6 @@ static int ti_pipe3_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
phy->dev = &pdev->dev;
|
||||
spin_lock_init(&phy->lock);
|
||||
|
||||
if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
|
||||
match = of_match_device(ti_pipe3_id_table, &pdev->dev);
|
||||
|
@ -402,6 +402,10 @@ static int ti_pipe3_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, phy);
|
||||
pm_runtime_enable(phy->dev);
|
||||
/* Prevent auto-disable of refclk for SATA PHY due to Errata i783 */
|
||||
if (of_device_is_compatible(node, "ti,phy-pipe3-sata"))
|
||||
if (!IS_ERR(phy->refclk))
|
||||
clk_prepare_enable(phy->refclk);
|
||||
|
||||
generic_phy = devm_phy_create(phy->dev, NULL, &ops);
|
||||
if (IS_ERR(generic_phy))
|
||||
|
@ -413,63 +417,33 @@ static int ti_pipe3_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
pm_runtime_get(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_pipe3_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (!pm_runtime_suspended(&pdev->dev))
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
|
||||
static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
|
||||
{
|
||||
if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!IS_ERR(phy->refclk)) {
|
||||
ret = clk_prepare_enable(phy->refclk);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
phy->refclk_enabled = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
|
||||
{
|
||||
if (!IS_ERR(phy->refclk))
|
||||
clk_disable_unprepare(phy->refclk);
|
||||
|
||||
phy->refclk_enabled = false;
|
||||
}
|
||||
|
||||
static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&phy->lock, flags);
|
||||
if (phy->enabled)
|
||||
goto err1;
|
||||
|
||||
ret = ti_pipe3_enable_refclk(phy);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
if (!IS_ERR(phy->wkupclk)) {
|
||||
ret = clk_prepare_enable(phy->wkupclk);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
|
||||
goto err2;
|
||||
goto disable_refclk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,96 +451,33 @@ static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
|
|||
ret = clk_prepare_enable(phy->div_clk);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "Failed to enable div_clk %d\n", ret);
|
||||
goto err3;
|
||||
goto disable_wkupclk;
|
||||
}
|
||||
}
|
||||
|
||||
phy->enabled = true;
|
||||
spin_unlock_irqrestore(&phy->lock, flags);
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
disable_wkupclk:
|
||||
if (!IS_ERR(phy->wkupclk))
|
||||
clk_disable_unprepare(phy->wkupclk);
|
||||
|
||||
err2:
|
||||
disable_refclk:
|
||||
if (!IS_ERR(phy->refclk))
|
||||
clk_disable_unprepare(phy->refclk);
|
||||
|
||||
ti_pipe3_disable_refclk(phy);
|
||||
err1:
|
||||
spin_unlock_irqrestore(&phy->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&phy->lock, flags);
|
||||
if (!phy->enabled) {
|
||||
spin_unlock_irqrestore(&phy->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IS_ERR(phy->wkupclk))
|
||||
clk_disable_unprepare(phy->wkupclk);
|
||||
/* Don't disable refclk for SATA PHY due to Errata i783 */
|
||||
if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
|
||||
ti_pipe3_disable_refclk(phy);
|
||||
if (!IS_ERR(phy->refclk))
|
||||
clk_disable_unprepare(phy->refclk);
|
||||
if (!IS_ERR(phy->div_clk))
|
||||
clk_disable_unprepare(phy->div_clk);
|
||||
phy->enabled = false;
|
||||
spin_unlock_irqrestore(&phy->lock, flags);
|
||||
}
|
||||
|
||||
static int ti_pipe3_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct ti_pipe3 *phy = dev_get_drvdata(dev);
|
||||
|
||||
ti_pipe3_disable_clocks(phy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_pipe3_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct ti_pipe3 *phy = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
ret = ti_pipe3_enable_clocks(phy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ti_pipe3_suspend(struct device *dev)
|
||||
{
|
||||
struct ti_pipe3 *phy = dev_get_drvdata(dev);
|
||||
|
||||
ti_pipe3_disable_clocks(phy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_pipe3_resume(struct device *dev)
|
||||
{
|
||||
struct ti_pipe3 *phy = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = ti_pipe3_enable_clocks(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops ti_pipe3_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
|
||||
ti_pipe3_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id ti_pipe3_id_table[] = {
|
||||
{
|
||||
.compatible = "ti,phy-usb3",
|
||||
|
@ -592,7 +503,6 @@ static struct platform_driver ti_pipe3_driver = {
|
|||
.remove = ti_pipe3_remove,
|
||||
.driver = {
|
||||
.name = "ti-pipe3",
|
||||
.pm = &ti_pipe3_pm_ops,
|
||||
.of_match_table = ti_pipe3_id_table,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1944,6 +1944,7 @@ static void __exit acm_exit(void)
|
|||
usb_deregister(&acm_driver);
|
||||
tty_unregister_driver(acm_tty_driver);
|
||||
put_tty_driver(acm_tty_driver);
|
||||
idr_destroy(&acm_minors);
|
||||
}
|
||||
|
||||
module_init(acm_init);
|
||||
|
|
|
@ -242,7 +242,7 @@ static int __init ulpi_init(void)
|
|||
{
|
||||
return bus_register(&ulpi_bus);
|
||||
}
|
||||
module_init(ulpi_init);
|
||||
subsys_initcall(ulpi_init);
|
||||
|
||||
static void __exit ulpi_exit(void)
|
||||
{
|
||||
|
|
|
@ -1022,9 +1022,12 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||
dev_name(&usb_dev->dev), retval);
|
||||
return (retval < 0) ? retval : -EMSGSIZE;
|
||||
}
|
||||
if (usb_dev->speed == USB_SPEED_SUPER) {
|
||||
|
||||
if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
|
||||
retval = usb_get_bos_descriptor(usb_dev);
|
||||
if (retval < 0) {
|
||||
if (!retval) {
|
||||
usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
|
||||
} else if (usb_dev->speed == USB_SPEED_SUPER) {
|
||||
mutex_unlock(&usb_bus_list_lock);
|
||||
dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
|
||||
dev_name(&usb_dev->dev), retval);
|
||||
|
|
|
@ -122,7 +122,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
|
|||
return usb_get_intfdata(hdev->actconfig->interface[0]);
|
||||
}
|
||||
|
||||
static int usb_device_supports_lpm(struct usb_device *udev)
|
||||
int usb_device_supports_lpm(struct usb_device *udev)
|
||||
{
|
||||
/* USB 2.1 (and greater) devices indicate LPM support through
|
||||
* their USB 2.0 Extended Capabilities BOS descriptor.
|
||||
|
|
|
@ -65,6 +65,7 @@ extern int usb_hub_init(void);
|
|||
extern void usb_hub_cleanup(void);
|
||||
extern int usb_major_init(void);
|
||||
extern void usb_major_cleanup(void);
|
||||
extern int usb_device_supports_lpm(struct usb_device *udev);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
|
|
|
@ -727,6 +727,10 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
|
||||
ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
|
||||
break;
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
|
||||
dwc->start_config_issued = false;
|
||||
/* Fall through */
|
||||
default:
|
||||
dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
|
|
|
@ -2167,7 +2167,7 @@ static int mv_udc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
udc->phy_regs = ioremap(r->start, resource_size(r));
|
||||
udc->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
|
||||
if (udc->phy_regs == NULL) {
|
||||
dev_err(&pdev->dev, "failed to map phy I/O memory\n");
|
||||
return -EBUSY;
|
||||
|
|
|
@ -60,13 +60,15 @@ static DEFINE_MUTEX(udc_lock);
|
|||
int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
struct device *dev = gadget->dev.parent;
|
||||
|
||||
if (req->length == 0)
|
||||
return 0;
|
||||
|
||||
if (req->num_sgs) {
|
||||
int mapped;
|
||||
|
||||
mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
|
||||
mapped = dma_map_sg(dev, req->sg, req->num_sgs,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
if (mapped == 0) {
|
||||
dev_err(&gadget->dev, "failed to map SGs\n");
|
||||
|
@ -75,11 +77,11 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
|
|||
|
||||
req->num_mapped_sgs = mapped;
|
||||
} else {
|
||||
req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
|
||||
req->dma = dma_map_single(dev, req->buf, req->length,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
|
||||
if (dma_mapping_error(&gadget->dev, req->dma)) {
|
||||
dev_err(&gadget->dev, "failed to map buffer\n");
|
||||
if (dma_mapping_error(dev, req->dma)) {
|
||||
dev_err(dev, "failed to map buffer\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
@ -95,12 +97,12 @@ void usb_gadget_unmap_request(struct usb_gadget *gadget,
|
|||
return;
|
||||
|
||||
if (req->num_mapped_sgs) {
|
||||
dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
|
||||
dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
|
||||
req->num_mapped_sgs = 0;
|
||||
} else {
|
||||
dma_unmap_single(&gadget->dev, req->dma, req->length,
|
||||
dma_unmap_single(gadget->dev.parent, req->dma, req->length,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -981,10 +981,6 @@ static void finish_unlinks(struct ohci_hcd *ohci)
|
|||
int completed, modified;
|
||||
__hc32 *prev;
|
||||
|
||||
/* Is this ED already invisible to the hardware? */
|
||||
if (ed->state == ED_IDLE)
|
||||
goto ed_idle;
|
||||
|
||||
/* only take off EDs that the HC isn't using, accounting for
|
||||
* frame counter wraps and EDs with partially retired TDs
|
||||
*/
|
||||
|
@ -1012,12 +1008,10 @@ static void finish_unlinks(struct ohci_hcd *ohci)
|
|||
}
|
||||
|
||||
/* ED's now officially unlinked, hc doesn't see */
|
||||
ed->state = ED_IDLE;
|
||||
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
|
||||
ed->hwNextED = 0;
|
||||
wmb();
|
||||
ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
|
||||
ed_idle:
|
||||
|
||||
/* reentrancy: if we drop the schedule lock, someone might
|
||||
* have modified this list. normally it's just prepending
|
||||
|
@ -1088,6 +1082,7 @@ static void finish_unlinks(struct ohci_hcd *ohci)
|
|||
if (list_empty(&ed->td_list)) {
|
||||
*last = ed->ed_next;
|
||||
ed->ed_next = NULL;
|
||||
ed->state = ED_IDLE;
|
||||
list_del(&ed->in_use_list);
|
||||
} else if (ohci->rh_state == OHCI_RH_RUNNING) {
|
||||
*last = ed->ed_next;
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
#define CCR_PM_CKRNEN 0x0002
|
||||
#define CCR_PM_USBPW1 0x0004
|
||||
#define CCR_PM_USBPW2 0x0008
|
||||
#define CCR_PM_USBPW3 0x0008
|
||||
#define CCR_PM_USBPW3 0x0010
|
||||
#define CCR_PM_PMEE 0x0100
|
||||
#define CCR_PM_PMES 0x8000
|
||||
|
||||
|
|
|
@ -484,10 +484,13 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
|
|||
u32 pls = status_reg & PORT_PLS_MASK;
|
||||
|
||||
/* resume state is a xHCI internal state.
|
||||
* Do not report it to usb core.
|
||||
* Do not report it to usb core, instead, pretend to be U3,
|
||||
* thus usb core knows it's not ready for transfer
|
||||
*/
|
||||
if (pls == XDEV_RESUME)
|
||||
if (pls == XDEV_RESUME) {
|
||||
*status |= USB_SS_PORT_LS_U3;
|
||||
return;
|
||||
}
|
||||
|
||||
/* When the CAS bit is set then warm reset
|
||||
* should be performed on port
|
||||
|
@ -588,7 +591,14 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
|
|||
status |= USB_PORT_STAT_C_RESET << 16;
|
||||
/* USB3.0 only */
|
||||
if (hcd->speed == HCD_USB3) {
|
||||
if ((raw_port_status & PORT_PLC))
|
||||
/* Port link change with port in resume state should not be
|
||||
* reported to usbcore, as this is an internal state to be
|
||||
* handled by xhci driver. Reporting PLC to usbcore may
|
||||
* cause usbcore clearing PLC first and port change event
|
||||
* irq won't be generated.
|
||||
*/
|
||||
if ((raw_port_status & PORT_PLC) &&
|
||||
(raw_port_status & PORT_PLS_MASK) != XDEV_RESUME)
|
||||
status |= USB_PORT_STAT_C_LINK_STATE << 16;
|
||||
if ((raw_port_status & PORT_WRC))
|
||||
status |= USB_PORT_STAT_C_BH_RESET << 16;
|
||||
|
@ -1120,10 +1130,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
if (bus_state->resuming_ports) {
|
||||
if (bus_state->resuming_ports || /* USB2 */
|
||||
bus_state->port_remote_wakeup) { /* USB3 */
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "suspend failed because "
|
||||
"a port is resuming\n");
|
||||
xhci_dbg(xhci, "suspend failed because a port is resuming\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1427,10 +1427,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
/* Attempt to use the ring cache */
|
||||
if (virt_dev->num_rings_cached == 0)
|
||||
return -ENOMEM;
|
||||
virt_dev->num_rings_cached--;
|
||||
virt_dev->eps[ep_index].new_ring =
|
||||
virt_dev->ring_cache[virt_dev->num_rings_cached];
|
||||
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
|
||||
virt_dev->num_rings_cached--;
|
||||
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
|
||||
1, type);
|
||||
}
|
||||
|
|
|
@ -23,10 +23,15 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "xhci.h"
|
||||
#include "xhci-trace.h"
|
||||
|
||||
#define PORT2_SSIC_CONFIG_REG2 0x883c
|
||||
#define PROG_DONE (1 << 30)
|
||||
#define SSIC_PORT_UNUSED (1 << 31)
|
||||
|
||||
/* Device for a quirk */
|
||||
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
|
||||
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
|
||||
|
@ -176,20 +181,63 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|||
}
|
||||
|
||||
/*
|
||||
* In some Intel xHCI controllers, in order to get D3 working,
|
||||
* through a vendor specific SSIC CONFIG register at offset 0x883c,
|
||||
* SSIC PORT need to be marked as "unused" before putting xHCI
|
||||
* into D3. After D3 exit, the SSIC port need to be marked as "used".
|
||||
* Without this change, xHCI might not enter D3 state.
|
||||
* Make sure PME works on some Intel xHCI controllers by writing 1 to clear
|
||||
* the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
|
||||
*/
|
||||
static void xhci_pme_quirk(struct xhci_hcd *xhci)
|
||||
static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
u32 val;
|
||||
void __iomem *reg;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
|
||||
|
||||
reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
|
||||
|
||||
/* Notify SSIC that SSIC profile programming is not done */
|
||||
val = readl(reg) & ~PROG_DONE;
|
||||
writel(val, reg);
|
||||
|
||||
/* Mark SSIC port as unused(suspend) or used(resume) */
|
||||
val = readl(reg);
|
||||
if (suspend)
|
||||
val |= SSIC_PORT_UNUSED;
|
||||
else
|
||||
val &= ~SSIC_PORT_UNUSED;
|
||||
writel(val, reg);
|
||||
|
||||
/* Notify SSIC that SSIC profile programming is done */
|
||||
val = readl(reg) | PROG_DONE;
|
||||
writel(val, reg);
|
||||
readl(reg);
|
||||
}
|
||||
|
||||
reg = (void __iomem *) xhci->cap_regs + 0x80a4;
|
||||
val = readl(reg);
|
||||
writel(val | BIT(28), reg);
|
||||
readl(reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
|
||||
{
|
||||
static const u8 intel_dsm_uuid[] = {
|
||||
0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
|
||||
0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
|
||||
};
|
||||
acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL);
|
||||
}
|
||||
#else
|
||||
static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int xhci_pci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
|
@ -263,6 +311,9 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
HCC_MAX_PSA(xhci->hcc_params) >= 4)
|
||||
xhci->shared_hcd->can_do_streams = 1;
|
||||
|
||||
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
|
||||
xhci_pme_acpi_rtd3_enable(dev);
|
||||
|
||||
/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
|
||||
pm_runtime_put_noidle(&dev->dev);
|
||||
|
||||
|
@ -307,7 +358,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
|||
pdev->no_d3cold = true;
|
||||
|
||||
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
|
||||
xhci_pme_quirk(xhci);
|
||||
xhci_pme_quirk(hcd, true);
|
||||
|
||||
return xhci_suspend(xhci, do_wakeup);
|
||||
}
|
||||
|
@ -340,7 +391,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
|||
usb_enable_intel_xhci_ports(pdev);
|
||||
|
||||
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
|
||||
xhci_pme_quirk(xhci);
|
||||
xhci_pme_quirk(hcd, false);
|
||||
|
||||
retval = xhci_resume(xhci, hibernated);
|
||||
return retval;
|
||||
|
|
|
@ -1546,6 +1546,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
usb_hcd_resume_root_hub(hcd);
|
||||
}
|
||||
|
||||
if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
|
||||
bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
|
||||
|
||||
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
|
||||
xhci_dbg(xhci, "port resume event for port %d\n", port_id);
|
||||
|
||||
|
|
|
@ -3453,6 +3453,9 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (virt_dev->tt_info)
|
||||
old_active_eps = virt_dev->tt_info->active_eps;
|
||||
|
||||
if (virt_dev->udev != udev) {
|
||||
/* If the virt_dev and the udev does not match, this virt_dev
|
||||
* may belong to another udev.
|
||||
|
|
|
@ -285,6 +285,7 @@ struct xhci_op_regs {
|
|||
#define XDEV_U0 (0x0 << 5)
|
||||
#define XDEV_U2 (0x2 << 5)
|
||||
#define XDEV_U3 (0x3 << 5)
|
||||
#define XDEV_INACTIVE (0x6 << 5)
|
||||
#define XDEV_RESUME (0xf << 5)
|
||||
/* true: port has power (see HCC_PPC) */
|
||||
#define PORT_POWER (1 << 9)
|
||||
|
|
|
@ -2065,6 +2065,18 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
|
|||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_READ_DISC_INFO ),
|
||||
|
||||
/* Reported by Oliver Neukum <oneukum@suse.com>
|
||||
* This device morphes spontaneously into another device if the access
|
||||
* pattern of Windows isn't followed. Thus writable media would be dirty
|
||||
* if the initial instance is used. So the device is limited to its
|
||||
* virtual CD.
|
||||
* And yes, the concept that BCD goes up to 9 is not heeded */
|
||||
UNUSUAL_DEV( 0x19d2, 0x1225, 0x0000, 0xffff,
|
||||
"ZTE,Incorporated",
|
||||
"ZTE WCDMA Technologies MSM",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_SINGLE_LUN ),
|
||||
|
||||
/* Reported by Sven Geggus <sven-usbst@geggus.net>
|
||||
* This encrypted pen drive returns bogus data for the initial READ(10).
|
||||
*/
|
||||
|
@ -2074,6 +2086,17 @@ UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200,
|
|||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_INITIAL_READ10 ),
|
||||
|
||||
/* Reported by Hans de Goede <hdegoede@redhat.com>
|
||||
* These are mini projectors using USB for both power and video data transport
|
||||
* The usb-storage interface is a virtual windows driver CD, which the gm12u320
|
||||
* driver automatically converts into framebuffer & kms dri device nodes.
|
||||
*/
|
||||
UNUSUAL_DEV( 0x1de1, 0xc102, 0x0000, 0xffff,
|
||||
"Grain-media Technology Corp.",
|
||||
"USB3.0 Device GM12U320",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_DEVICE ),
|
||||
|
||||
/* Patch by Richard Schütz <r.schtz@t-online.de>
|
||||
* This external hard drive enclosure uses a JMicron chip which
|
||||
* needs the US_FL_IGNORE_RESIDUE flag to work properly. */
|
||||
|
|
Loading…
Reference in a new issue