ChangeSet 1.1713.7.2, 2004/04/02 09:56:28-08:00, [EMAIL PROTECTED]

[PATCH] USB: ehci updates:  CONFIG_PCI, integrated TT

Generalize the driver a bit:

 - PCI-specific handling is restricted to a small chunk of
   init code.  Non-PCI implementations are in the pipeline.

 - Merge support from ARC International (Craig Nadler) for
   their integrated root hub transaction translators (on PCI).
   Other implementations should be similar.


 drivers/usb/host/Kconfig    |   11 +++++++++
 drivers/usb/host/ehci-dbg.c |    6 +++--
 drivers/usb/host/ehci-hcd.c |   50 ++++++++++++++++++++++++++++++++++++--------
 drivers/usb/host/ehci-hub.c |   18 ++++++++++++++-
 drivers/usb/host/ehci-q.c   |   15 ++++++++++---
 drivers/usb/host/ehci.h     |   40 +++++++++++++++++++++++++++++++++++
 include/linux/pci_ids.h     |    3 ++
 7 files changed, 127 insertions(+), 16 deletions(-)


diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
--- a/drivers/usb/host/Kconfig  Wed Apr 14 14:34:12 2004
+++ b/drivers/usb/host/Kconfig  Wed Apr 14 14:34:12 2004
@@ -38,6 +38,17 @@
          EHCI or USB 2.0 transaction translator implementations.
          It should work for ISO-OUT transfers, like audio.
 
+config USB_EHCI_ROOT_HUB_TT
+       bool "Root Hub Transaction Translators (EXPERIMENTAL)"
+       depends on USB_EHCI_HCD && EXPERIMENTAL
+       ---help---
+         Some EHCI chips have vendor-specific extensions to integrate
+         transaction translators, so that no OHCI or UHCI companion
+         controller is needed.  It's safe to say "y" even if your
+         controller doesn't support this feature.
+
+         This supports the EHCI implementation from ARC International.
+
 config USB_OHCI_HCD
        tristate "OHCI HCD support"
        depends on USB
diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c       Wed Apr 14 14:34:12 2004
+++ b/drivers/usb/host/ehci-dbg.c       Wed Apr 14 14:34:12 2004
@@ -628,8 +628,10 @@
        /* Capability Registers */
        i = HC_VERSION(readl (&ehci->caps->hc_capbase));
        temp = scnprintf (next, size,
-               "PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION 
")\n",
-               pci_name(to_pci_dev(hcd->self.controller)),
+               "bus %s device %s\n"
+               "EHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
+               hcd->self.controller->bus->name,
+               hcd->self.controller->bus_id,
                i >> 8, i & 0x0ff, ehci->hcd.state);
        size -= temp;
        next += temp;
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c       Wed Apr 14 14:34:12 2004
+++ b/drivers/usb/host/ehci-hcd.c       Wed Apr 14 14:34:12 2004
@@ -279,6 +279,8 @@
        spin_unlock_irqrestore (&ehci->lock, flags);
 }
 
+#ifdef CONFIG_PCI
+
 /* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
  * off the controller (maybe it can boot from highspeed USB disks).
  */
@@ -307,6 +309,8 @@
        return 0;
 }
 
+#endif
+
 static int
 ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
 {
@@ -335,8 +339,12 @@
        dbg_hcs_params (ehci, "reset");
        dbg_hcc_params (ehci, "reset");
 
+#ifdef CONFIG_PCI
        /* EHCI 0.96 and later may have "extended capabilities" */
-       temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+       if (hcd->self.controller->bus == &pci_bus_type)
+               temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+       else
+               temp = 0;
        while (temp) {
                u32             cap;
 
@@ -356,6 +364,7 @@
                }
                temp = (cap >> 8) & 0xff;
        }
+#endif
 
        /* cache this readonly data; minimize PCI reads */
        ehci->hcs_params = readl (&ehci->caps->hcs_params);
@@ -372,7 +381,7 @@
        struct usb_bus          *bus;
        int                     retval;
        u32                     hcc_params;
-       u8                      tempbyte;
+       u8                      sbrn = 0;
 
        init_timer (&ehci->watchdog);
        ehci->watchdog.function = ehci_watchdog;
@@ -406,6 +415,29 @@
        writel (INTR_MASK, &ehci->regs->intr_enable);
        writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
+#ifdef CONFIG_PCI
+       if (hcd->self.controller->bus == &pci_bus_type) {
+               struct pci_dev          *pdev;
+
+               pdev = to_pci_dev(hcd->self.controller);
+
+               /* Serial Bus Release Number is at PCI 0x60 offset */
+               pci_read_config_byte(pdev, 0x60, &sbrn);
+
+               /* help hc dma work well with cachelines */
+               pci_set_mwi (pdev);
+
+               /* chip-specific init */
+               switch (pdev->vendor) {
+               case PCI_VENDOR_ID_ARC:
+                       if (pdev->device == PCI_DEVICE_ID_ARC_EHCI)
+                               ehci->is_arc_rh_tt = 1;
+                       break;
+               }
+
+       }
+#endif
+
        /*
         * dedicate a qh for the async ring head, since we couldn't unlink
         * a 'real' qh without stopping the async schedule [4.8].  use it
@@ -443,9 +475,6 @@
 #endif
        }
 
-       /* help hc dma work well with cachelines */
-       pci_set_mwi (to_pci_dev(ehci->hcd.self.controller));
-
        /* clear interrupt enables, set irq latency */
        temp = readl (&ehci->regs->command) & 0x0fff;
        if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
@@ -493,12 +522,10 @@
        writel (FLAG_CF, &ehci->regs->configured_flag);
        readl (&ehci->regs->command);   /* unblock posted write */
 
-        /* PCI Serial Bus Release Number is at 0x60 offset */
-       pci_read_config_byte(to_pci_dev(hcd->self.controller), 0x60, &tempbyte);
        temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
        ehci_info (ehci,
                "USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
-               ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
+               ((sbrn & 0xf0)>>4), (sbrn & 0x0f),
                temp >> 8, temp & 0xff, DRIVER_VERSION);
 
        /*
@@ -995,7 +1022,9 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* EHCI spec says PCI is required. */
+/* EHCI 1.0 doesn't require PCI */
+
+#ifdef CONFIG_PCI
 
 /* PCI driver selection metadata; PCI hotplugging uses this */
 static const struct pci_device_id pci_ids [] = { {
@@ -1020,6 +1049,9 @@
        .resume =       usb_hcd_pci_resume,
 #endif
 };
+
+#endif /* PCI */
+
 
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
--- a/drivers/usb/host/ehci-hub.c       Wed Apr 14 14:34:12 2004
+++ b/drivers/usb/host/ehci-hub.c       Wed Apr 14 14:34:12 2004
@@ -40,6 +40,15 @@
 
        /* if reset finished and it's still not enabled -- handoff */
        if (!(port_status & PORT_PE)) {
+
+               /* with integrated TT, there's nobody to hand it to! */
+               if (ehci_is_ARC(ehci)) {
+                       ehci_dbg (ehci,
+                               "Failed to enable port %d on root hub TT\n",
+                               index+1);
+                       return port_status;
+               }
+
                ehci_dbg (ehci, "port %d full speed --> companion\n",
                        index + 1);
 
@@ -257,7 +266,8 @@
                if (!(temp & PORT_OWNER)) {
                        if (temp & PORT_CONNECT) {
                                status |= 1 << USB_PORT_FEAT_CONNECTION;
-                               status |= 1 << USB_PORT_FEAT_HIGHSPEED;
+                               // status may be from integrated TT
+                               status |= ehci_port_speed(ehci, temp);
                        }
                        if (temp & PORT_PE)
                                status |= 1 << USB_PORT_FEAT_ENABLE;
@@ -307,8 +317,12 @@
                                        &ehci->regs->port_status [wIndex]);
                        break;
                case USB_PORT_FEAT_RESET:
-                       /* line status bits may report this as low speed */
+                       /* line status bits may report this as low speed,
+                        * which can be fine if this root hub has a
+                        * transaction translator built in.
+                        */
                        if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+                                       && !ehci_is_ARC(ehci)
                                        && PORT_USB11 (temp)) {
                                ehci_dbg (ehci,
                                        "port %d low speed --> companion\n",
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c Wed Apr 14 14:34:12 2004
+++ b/drivers/usb/host/ehci-q.c Wed Apr 14 14:34:12 2004
@@ -165,7 +165,10 @@
                /* if async CSPLIT failed, try cleaning out the TT buffer */
                } else if (urb->dev->tt && !usb_pipeint (urb->pipe)
                                && ((token & QTD_STS_MMF) != 0
-                                       || QTD_CERR(token) == 0)) {
+                                       || QTD_CERR(token) == 0)
+                               && (!ehci_is_ARC(ehci)
+                                       || urb->dev->tt->hub !=
+                                               ehci->hcd.self.root_hub)) {
 #ifdef DEBUG
                        struct usb_device *tt = urb->dev->tt->hub;
                        dev_dbg (&tt->dev,
@@ -576,7 +579,7 @@
 // when each interface/altsetting is established.  Unlink
 // any previous qh and cancel its urbs first; endpoints are
 // implicitly reset then (data toggle too).
-// That'd mean updating how usbcore talks to HCDs. (2.5?)
+// That'd mean updating how usbcore talks to HCDs. (2.7?)
 
 
 /*
@@ -674,7 +677,13 @@
 
                info2 |= (EHCI_TUNE_MULT_TT << 30);
                info2 |= urb->dev->ttport << 23;
-               info2 |= urb->dev->tt->hub->devnum << 16;
+
+               /* set the address of the TT; for ARC's integrated
+                * root hub tt, leave it zeroed.
+                */
+               if (!ehci_is_ARC(ehci)
+                               || urb->dev->tt->hub != ehci->hcd.self.root_hub)
+                       info2 |= urb->dev->tt->hub->devnum << 16;
 
                /* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
 
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h   Wed Apr 14 14:34:12 2004
+++ b/drivers/usb/host/ehci.h   Wed Apr 14 14:34:12 2004
@@ -85,6 +85,8 @@
        unsigned long           actions;
        unsigned                stamp;
 
+       unsigned                is_arc_rh_tt:1; /* ARC roothub with TT */
+
        /* irq statistics */
 #ifdef EHCI_STATS
        struct ehci_stats       stats;
@@ -549,6 +551,44 @@
        dma_addr_t              fstn_dma;
        union ehci_shadow       fstn_next;      /* ptr to periodic q entry */
 } __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature.  Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+#define        ehci_is_ARC(e)                  ((e)->is_arc_rh_tt)
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+{
+       if (ehci_is_ARC(ehci)) {
+               switch ((portsc>>26)&3) {
+               case 0:
+                       return 0;
+               case 1:
+                       return (1<<USB_PORT_FEAT_LOWSPEED);
+               case 2:
+               default:
+                       return (1<<USB_PORT_FEAT_HIGHSPEED);
+               }
+       }
+       return (1<<USB_PORT_FEAT_HIGHSPEED);
+}
+
+#else
+
+#define        ehci_is_ARC(e)                  (0)
+
+#define        ehci_port_speed(ehci, portsc)   (1<<USB_PORT_FEAT_HIGHSPEED)
+#endif
 
 /*-------------------------------------------------------------------------*/
 
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h   Wed Apr 14 14:34:12 2004
+++ b/include/linux/pci_ids.h   Wed Apr 14 14:34:12 2004
@@ -1870,6 +1870,9 @@
 #define PCI_DEVICE_ID_ALTIMA_AC9100    0x03ea
 #define PCI_DEVICE_ID_ALTIMA_AC1003    0x03eb
 
+#define PCI_VENDOR_ID_ARC               0x192E
+#define PCI_DEVICE_ID_ARC_EHCI          0x0101
+
 #define PCI_VENDOR_ID_SYMPHONY         0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101     0x0001
 



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id70&alloc_id638&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to