I would like to submit a patch that adds support for EHCI
root hubs with a transaction translator. The root hub on ARC
International's EHCI controller has a built in transaction
translator. This allows the EHCI controller to communicate
with low and full speed devices without the use of a USB1.1
companion controller. The code changes where structured to
allow for support of other EHCI controllers with root hub TTs
to be cleanly added later.
    You should find two attachments to this email. The first
is a description of the code changes needed for support of
root hubs with TTs and the second is the patch file for the
2.6.5-rc1 version of the Linux kernel.

Best Regards,

Craig Nadler
Sr. Software Engineer
ARC International
Email: [EMAIL PROTECTED]
<http://www.arc.com/
ARC EHCI Root Hub TT Support
============================


     The root hub on the ARC EHCI controller has a built in transaction
translator (or TT). This allows the EHCI controller to communicate with low
and full speed devices without the use of a USB version 1.1 companion
controller. This document lists the changes needed for the EHCI driver in the
Linux 2.6.2 kernel to support a root hub with a TT. The code changes where
structured to allow for support of other EHCI controllers with root hub TTs to
be cleanly added later.
     The sections of the source code that have been changes are shown below
the description of the changes. USB_EHCI_ROOT_HUB_TT is a #defined flag which
enables support for root hubs with a TT. USB_ARC_EHCI_HCD is a #defined flag
which enables support for the ARC EHCI controllers to use a root hub with a
TT.






drivers/usb/host/Kconfig
========================

        A configuration option was added to the EHCI driver for support of
root hubs with built in transaction translators. To enable this select the
"Root hub with built in transaction translator support" option, then select
one or more EHCI controllers from the list of controllers which support root
hubs with transaction translators. Currently "ARC EHCI (built in transaction
translator) support" is the only EHCI controller on the list.

===============================================================================

config USB_EHCI_ROOT_HUB_TT
        bool "Root hub with built in transaction translator support"
        depends on USB && USB_EHCI_HCD

config USB_ARC_EHCI_HCD
        bool "ARC EHCI (built in transaction translator) support"
        depends on USB && USB_EHCI_HCD && USB_EHCI_ROOT_HUB_TT

===============================================================================





drivers/usb/host/ehci-hub.c
===========================

     After a device is connected to the root hub the EHCI driver will reset
the port unless it is a low speed device. Low speed devices are handled off to
a companion controller. If support for root hub TTs is enabled then low speed
devices will not be handled off to a companion controller if the EHCI
controller has a root hub TT.

===============================================================================

                case USB_PORT_FEAT_RESET:
                        /* line status bits may report this as low speed */
                        if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
                           /* If EHCI has a transaction translator built */
                           /* into the root hub then don't hand off low  */
                           /* speed devices.                             */
                           && (!EHCI_Root_Hub_TT(ehci))
#endif
                           && PORT_USB11 (temp)) {
                                ehci_dbg (ehci,
                                        "port %d low speed --> companion\n",
                                        wIndex + 1);
                                temp |= PORT_OWNER;
                        } else {
                                ehci_vdbg (ehci, "port %d reset\n", wIndex + 
1);
                                temp |= PORT_RESET;
                                temp &= ~PORT_PE;

                                /*
                                 * caller must wait, then call GetPortStatus
                                 * usb 2.0 spec says 50 ms resets on root
                                 */
                                ehci->reset_done [wIndex] = jiffies
                                        + ((50 /* msec */ * HZ) / 1000);
                        }
                        writel (temp, &ehci->regs->port_status [wIndex]);
                        break;

===============================================================================

     If a port on the root hub can't be enabled after a port reset then the
EHCI driver assumes that the port is either connected to a full speed device
or broken. In either case the default action is for the Linux EHCI driver to
hand the port off to the companion controller.
      If support for root hub TTs is enabled then EHCI_Root_Hub_TT will be
called to check if the EHCI controller has a root hub TT. If the root hub does
have a TT then the EHCI driver will not try to hand off control of the port
even if it can't be enabled. Instead an error message will be printed to the
system log indicating that a port is malfunctioning.

===============================================================================

        /* if reset finished and it's still not enabled -- handoff */
        if (!(port_status & PORT_PE)) {
#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
                if (EHCI_Root_Hub_TT(ehci)) {
                        ehci_dbg (ehci,
                                "Failed to enable port %d on root hub TT\n",
                                index+1);
                        return port_status;
                }       
#endif
                ehci_dbg (ehci, "port %d full speed --> companion\n",
                        index + 1);

                // what happens if HCS_N_CC(params) == 0 ?
                port_status |= PORT_OWNER;
                writel (port_status, &ehci->regs->port_status [index]);

        } else
                ehci_dbg (ehci, "port %d high speed\n", index + 1);

===============================================================================

     By default the Linux EHCI driver assumes that any devices that have not
been handled off to a companion controller are high speed devices. If support
for root hub TTs is enabled then EHCI_Root_Hub_Port_Speed will be called to
determine the speed of a device connected to the root hub.

===============================================================================

#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
                                status |= EHCI_Root_Hub_Port_Speed(ehci, temp);
#else
                                status |= 1 << USB_PORT_FEAT_HIGHSPEED;
#endif

===============================================================================






drivers/usb/host/ehci-q.c
=========================

     The Linux USB stack uses '1' as the address for the root hub. If the root
hub on an EHCI controller does not have a TT then no packets are ever sent to
it so the address doesn't matter. If support for root hub TTs is enabled then
split packages will be sent to the root hub. The address can be changed from
'1' to '0' in those packages if that EHCI controller uses '0' as the address
for the root hub.

===============================================================================

#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
                /* The Linux USB stack uses '1' as the address for the root
                 * hub. If the root hub on an EHCI controller does not have
                 * a TT then no packets are ever sent to it so the address
                 * doesn't matter. If support for root hub TTs is enabled
                 * then split packages will be sent to the root hub. The
                 * address can be changed from '1' to '0' in those packages
                 * if that EHCI controller uses '0' as the address for the
                 * root hub.
                 */
                if (EHCI_Root_Hub_TT(ehci) && urb->dev->tt->hub->devnum == 
1)
                        info2 |= EHCI_Root_Hub_Devnum(ehci);
                else
                        info2 |= urb->dev->tt->hub->devnum << 16;
#else
                info2 |= urb->dev->tt->hub->devnum << 16;
#endif

===============================================================================






drivers/usb/host/ehci.h
=======================

     A framework has been added to ehci.h to support various EHCI controllers
that have a root hub with a TT. The framework supplies three inline functions
to the EHCI driver:

EHCI_Root_Hub_Devnum - Sets the device number of the root hub.

EHCI_Root_Hub_TT - Detects if an EHCI controller has a TT built into the root
                   hub.

EHCI_Root_Hub_Port_Speed - Returns the speed of a device attached to a port on
                           the root hub.

     To support an addition EHCI controller a case must be added to the switch 
statements in each of the three functions to detect and handle that controller.

===============================================================================

#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
/* This section is for EHCI controllers which have a Transaction Translator
 * built into the root hub. This is a non-standard feature so each controller
 * will need to add code to the following inline functions.
 */

/* Sets the device number of the root hub. */
static inline unsigned int EHCI_Root_Hub_Devnum(struct ehci_hcd *ehci) {
        struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller);

        switch (pdev->vendor) {
#ifdef CONFIG_USB_ARC_EHCI_HCD
        case PCI_VENDOR_ID_ARC:
                if (pdev->device == PCI_DEVICE_ID_ARC_EHCI) return 0;
#endif
        default:
                return 1;
        }
}

/* Detects if an EHCI controller has a Transaction Translator built into the
 * root hub.
 */
static inline unsigned int EHCI_Root_Hub_TT(struct ehci_hcd *ehci) {
        struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller);

        printk(KERN_INFO "PCI vendor=%x device=%x\n",
                pdev->vendor, pdev->device);
        switch (pdev->vendor) {
#ifdef CONFIG_USB_ARC_EHCI_HCD
        case PCI_VENDOR_ID_ARC:
                if (pdev->device == PCI_DEVICE_ID_ARC_EHCI) {
                        printk(KERN_INFO "Found ARC EHCI\n");
                        return 1;
                }
#endif
        default:
                return 0;
        }
}

/* Returns the speed of a device attached to a port on the root hub. */
static inline unsigned int EHCI_Root_Hub_Port_Speed(
        struct ehci_hcd *ehci,
        unsigned int    portsc
) {
        struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller);

        switch (pdev->vendor) {
#ifdef CONFIG_USB_ARC_EHCI_HCD
        case PCI_VENDOR_ID_ARC:
                if (pdev->device == PCI_DEVICE_ID_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);
                        }
                }
#endif
        default:
                return (1<<USB_PORT_FEAT_HIGHSPEED);
        }
}
#endif

===============================================================================






include/linux/pci_ids.h
=======================

     ARC's PCI vendor ID and the device ID for the EHCI controller have been
added the list in include/linux/pci_ids.h.

===============================================================================

#define PCI_VENDOR_ID_ARC               0x192E
#define PCI_DEVICE_ID_ARC_EHCI          0x0101

===============================================================================



Attachment: patch-arc-usb
Description: Binary data

Reply via email to