Commit 90221170 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'for-usb-next-2012-03-13' of...

Merge tag 'for-usb-next-2012-03-13' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-next

Hi Greg,

Here's my final pull request for 3.4.  All the patches have been under
review for some time (months in some cases).  The ring expansion patches
in particular have been tested by both me and Paul Zimmerman from
Synopsis.

They add support for:
 - Dynamic ring expansion
 - New USB 2.1 link PM errata (BESL)
 - xHCI host controller support for the Synopsis DesignWare 3 IP

The dynamic ring expansion patches finally make test 10 of the host-side
test pass, instead of failing due to no room on the endpoint ring for
the larger transfers.  I would have hoped that the ring expansion
patchset would make the Point Grey USB 3.0 camera work, but sadly it
fails to respond to a control transfer on my test system.  This doesn't
seem to be a driver bug, but it could be a device or host bug.

Felipe has tested the patches to add a platform device to the xHCI
driver on the Synopsis DesignWare 3 IP in the TI OMAP5 board.

Please pull.

Thanks,
Sarah Sharp
parents f7a0d426 3429e91a
......@@ -27,6 +27,10 @@ config USB_XHCI_HCD
To compile this driver as a module, choose M here: the
module will be called xhci-hcd.
config USB_XHCI_PLATFORM
tristate
depends on USB_XHCI_HCD
config USB_XHCI_HCD_DEBUGGING
bool "Debugging for the xHCI host controller"
depends on USB_XHCI_HCD
......
......@@ -15,6 +15,10 @@ xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
xhci-hcd-y += xhci-plat.o
endif
obj-$(CONFIG_USB_WHCI_HCD) += whci/
obj-$(CONFIG_PCI) += pci-quirks.o
......
This diff is collapsed.
/*
* xhci-plat.c - xHCI host controller driver platform Bus Glue.
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* A lot of code borrowed from the Linux xHCI driver.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "xhci.h"
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
/*
* As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
xhci->quirks |= XHCI_BROKEN_MSI;
}
/* called during probe() after chip reset completes */
static int xhci_plat_setup(struct usb_hcd *hcd)
{
return xhci_gen_setup(hcd, xhci_plat_quirks);
}
static const struct hc_driver xhci_plat_xhci_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd *),
/*
* generic hardware linkage
*/
.irq = xhci_irq,
.flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
/*
* basic lifecycle operations
*/
.reset = xhci_plat_setup,
.start = xhci_run,
.stop = xhci_stop,
.shutdown = xhci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.alloc_streams = xhci_alloc_streams,
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.update_hub_device = xhci_update_hub_device,
.reset_device = xhci_discover_or_reset_device,
/*
* scheduling support
*/
.get_frame_number = xhci_get_frame,
/* Root hub support */
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
};
static int xhci_plat_probe(struct platform_device *pdev)
{
const struct hc_driver *driver;
struct xhci_hcd *xhci;
struct resource *res;
struct usb_hcd *hcd;
int ret;
int irq;
if (usb_disabled())
return -ENODEV;
driver = &xhci_plat_xhci_driver;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
dev_dbg(&pdev->dev, "controller already in use\n");
ret = -EBUSY;
goto put_hcd;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
dev_dbg(&pdev->dev, "error mapping memory\n");
ret = -EFAULT;
goto release_mem_region;
}
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto unmap_registers;
/* USB 2.0 roothub is stored in the platform_device now. */
hcd = dev_get_drvdata(&pdev->dev);
xhci = hcd_to_xhci(hcd);
xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
dev_name(&pdev->dev), hcd);
if (!xhci->shared_hcd) {
ret = -ENOMEM;
goto dealloc_usb2_hcd;
}
/*
* Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
* is called by usb_add_hcd().
*/
*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
if (ret)
goto put_usb3_hcd;
return 0;
put_usb3_hcd:
usb_put_hcd(xhci->shared_hcd);
dealloc_usb2_hcd:
usb_remove_hcd(hcd);
unmap_registers:
iounmap(hcd->regs);
release_mem_region:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
put_hcd:
usb_put_hcd(hcd);
return ret;
}
static int xhci_plat_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
usb_put_hcd(hcd);
kfree(xhci);
return 0;
}
static struct platform_driver usb_xhci_driver = {
.probe = xhci_plat_probe,
.remove = xhci_plat_remove,
.driver = {
.name = "xhci-hcd",
},
};
MODULE_ALIAS("platform:xhci-hcd");
int xhci_register_plat(void)
{
return platform_driver_register(&usb_xhci_driver);
}
void xhci_unregister_plat(void)
{
platform_driver_unregister(&usb_xhci_driver);
}
This diff is collapsed.
......@@ -729,6 +729,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
ring->enq_seg = ring->deq_seg;
ring->enqueue = ring->dequeue;
ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
/*
* Ring is now zeroed, so the HW should look for change of ownership
* when the cycle bit is set to 1.
......@@ -3614,26 +3615,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
/* Calculate HIRD/BESL for USB2 PORTPMSC*/
static int xhci_calculate_hird_besl(int u2del, bool use_besl)
static int xhci_calculate_hird_besl(struct xhci_hcd *xhci,
struct usb_device *udev)
{
int hird;
int u2del, besl, besl_host;
int besl_device = 0;
u32 field;
u2del = HCS_U2_LATENCY(xhci->hcs_params3);
field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
if (use_besl) {
for (hird = 0; hird < 16; hird++) {
if (xhci_besl_encoding[hird] >= u2del)
if (field & USB_BESL_SUPPORT) {
for (besl_host = 0; besl_host < 16; besl_host++) {
if (xhci_besl_encoding[besl_host] >= u2del)
break;
}
/* Use baseline BESL value as default */
if (field & USB_BESL_BASELINE_VALID)
besl_device = USB_GET_BESL_BASELINE(field);
else if (field & USB_BESL_DEEP_VALID)
besl_device = USB_GET_BESL_DEEP(field);
} else {
if (u2del <= 50)
hird = 0;
besl_host = 0;
else
hird = (u2del - 51) / 75 + 1;
if (hird > 15)
hird = 15;
besl_host = (u2del - 51) / 75 + 1;
}
return hird;
besl = besl_host + besl_device;
if (besl > 15)
besl = 15;
return besl;
}
static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
......@@ -3646,7 +3659,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
u32 temp, dev_id;
unsigned int port_num;
unsigned long flags;
int u2del, hird;
int hird;
int ret;
if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
......@@ -3692,12 +3705,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
* HIRD or BESL shoule be used. See USB2.0 LPM errata.
*/
pm_addr = port_array[port_num] + 1;
u2del = HCS_U2_LATENCY(xhci->hcs_params3);
if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
hird = xhci_calculate_hird_besl(u2del, 1);
else
hird = xhci_calculate_hird_besl(u2del, 0);
hird = xhci_calculate_hird_besl(xhci, udev);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr);
......@@ -3776,7 +3784,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
u32 temp;
unsigned int port_num;
unsigned long flags;
int u2del, hird;
int hird;
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable)
......@@ -3799,11 +3807,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
enable ? "enable" : "disable", port_num);
u2del = HCS_U2_LATENCY(xhci->hcs_params3);
if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
hird = xhci_calculate_hird_besl(u2del, 1);
else
hird = xhci_calculate_hird_besl(u2del, 0);
hird = xhci_calculate_hird_besl(xhci, udev);
if (enable) {
temp &= ~PORT_HIRD_MASK;
......@@ -3964,7 +3968,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
int retval;
u32 temp;
hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
if (usb_hcd_is_primary_hcd(hcd)) {
xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
......@@ -4059,6 +4064,11 @@ static int __init xhci_hcd_init(void)
printk(KERN_DEBUG "Problem registering PCI driver.");
return retval;
}
retval = xhci_register_plat();
if (retval < 0) {
printk(KERN_DEBUG "Problem registering platform driver.");
goto unreg_pci;
}
/*
* Check the compiler generated sizes of structures that must be laid
* out in specific ways for hardware access.
......@@ -4078,11 +4088,15 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
return 0;
unreg_pci:
xhci_unregister_pci();
return retval;
}
module_init(xhci_hcd_init);
static void __exit xhci_hcd_cleanup(void)
{
xhci_unregister_pci();
xhci_unregister_plat();
}
module_exit(xhci_hcd_cleanup);
......@@ -1223,10 +1223,7 @@ union xhci_trb {
/* Allow two commands + a link TRB, along with any reserved command TRBs */
#define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3)
#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16)
/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE).
* Change this if you change TRBS_PER_SEGMENT!
*/
#define SEGMENT_SHIFT 10
#define SEGMENT_SHIFT (__ffs(SEGMENT_SIZE))
/* TRB buffer pointers can't cross 64KB boundaries */
#define TRB_MAX_BUFF_SHIFT 16
#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT)
......@@ -1253,8 +1250,19 @@ struct xhci_dequeue_state {
int new_cycle_state;
};
enum xhci_ring_type {
TYPE_CTRL = 0,
TYPE_ISOC,
TYPE_BULK,
TYPE_INTR,
TYPE_STREAM,
TYPE_COMMAND,
TYPE_EVENT,
};
struct xhci_ring {
struct xhci_segment *first_seg;
struct xhci_segment *last_seg;
union xhci_trb *enqueue;
struct xhci_segment *enq_seg;
unsigned int enq_updates;
......@@ -1269,6 +1277,10 @@ struct xhci_ring {
*/
u32 cycle_state;
unsigned int stream_id;
unsigned int num_segs;
unsigned int num_trbs_free;
unsigned int num_trbs_free_temp;
enum xhci_ring_type type;
bool last_td_was_short;
};
......@@ -1610,6 +1622,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags);
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs, gfp_t flags);
void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
unsigned int ep_index);
......@@ -1649,6 +1663,17 @@ static inline int xhci_register_pci(void) { return 0; }
static inline void xhci_unregister_pci(void) {}
#endif
#if defined(CONFIG_USB_XHCI_PLATFORM) \
|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
int xhci_register_plat(void);
void xhci_unregister_plat(void);
#else
static inline int xhci_register_plat(void)
{ return 0; }
static inline void xhci_unregister_plat(void)
{ }
#endif
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
void xhci_quiesce(struct xhci_hcd *xhci);
......
......@@ -789,6 +789,11 @@ struct usb_ext_cap_descriptor { /* Link Power Management */
__u8 bDevCapabilityType;
__le32 bmAttributes;
#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */
#define USB_BESL_SUPPORT (1 << 2) /* supports BESL */
#define USB_BESL_BASELINE_VALID (1 << 3) /* Baseline BESL valid*/
#define USB_BESL_DEEP_VALID (1 << 4) /* Deep BESL valid */
#define USB_GET_BESL_BASELINE(p) (((p) & (0xf << 8)) >> 8)
#define USB_GET_BESL_DEEP(p) (((p) & (0xf << 12)) >> 12)
} __attribute__((packed));
#define USB_DT_USB_EXT_CAP_SIZE 7
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment