On 9 Feb 2009, Syed Ismail wrote: > Hi > I am running ehci on a mx31 ads high speed port. There is no uhci or > ohci enabled. Some of our boards have problems running at high speed. > These boards, when made to operate at full speed by using a 1.1 > external hub, work fine. Since, the only use of the usb port is to > transfer a maximum of 4 MB of data, our needs would be met with full > speed itself. > The glue for ehci has been provided by freescale in their BSP. > > Can anyone suggest a way whereby i can configure devices to run only > at full speed, even if they are high speed devices. By googling, i > found that this can by done by sysfs interface, by writing the port > number in a companion file. But, CONFIG_USB_EHCI_ROOT_HUB_TT is > enabled and so the companion file is not created.By looking at code, > I think companion file will get created if i disable this option. But > will this work, as there is no uhci or ohci? What exactly are > companion controllers. > > Is there a way i can make changes in ehci itself so that it will work > only in full speed or low speed mode. Please help. Here's an old experimental patch I wrote to add support for the "companion" file for controllers using the ARC/TDI technology. It needs to be cleaned up, and it undoubtedly needs some adjusting before it will apply to recent kernels. Alan Stern Index: usb-2.6/drivers/usb/host/ehci.h =================================================================== --- usb-2.6.orig/drivers/usb/host/ehci.h +++ usb-2.6/drivers/usb/host/ehci.h @@ -678,6 +678,13 @@ struct ehci_fstn { * needed (mostly in root hub code). */ +/* Additions to the PORTSC registers */ +#define PORT_PSPD_FULL (0<<26) +#define PORT_PSPD_LOW (1<<26) +#define PORT_PSPD_HIGH (2<<26) +#define PORT_PSPD_MASK (3<<26) /* port speed */ +#define PORT_PFSC (1<<24) /* port force full-speed connect */ + #define ehci_is_TDI(e) ((e)->is_tdi_rh_tt) /* Returns the speed of a device attached to a port on the root hub. */ @@ -685,12 +692,12 @@ static inline unsigned int ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) { if (ehci_is_TDI(ehci)) { - switch ((portsc>>26)&3) { - case 0: + switch (portsc & PORT_PSPD_MASK) { + case PORT_PSPD_FULL: return 0; - case 1: + case PORT_PSPD_LOW: return (1<<USB_PORT_FEAT_LOWSPEED); - case 2: + case PORT_PSPD_HIGH: default: return (1<<USB_PORT_FEAT_HIGHSPEED); } @@ -698,11 +705,19 @@ ehci_port_speed(struct ehci_hcd *ehci, u return (1<<USB_PORT_FEAT_HIGHSPEED); } +/* Which bit controls whether a connection will be high-speed? */ +static inline u32 ehci_port_owner_bit(struct ehci_hcd *ehci) +{ + return ehci_is_TDI(ehci) ? PORT_PFSC : PORT_OWNER; +} + + #else #define ehci_is_TDI(e) (0) #define ehci_port_speed(ehci, portsc) (1<<USB_PORT_FEAT_HIGHSPEED) +#define ehci_port_owner_bit(ehci) PORT_OWNER #endif /*-------------------------------------------------------------------------*/ Index: usb-2.6/drivers/usb/host/ehci-hub.c =================================================================== --- usb-2.6.orig/drivers/usb/host/ehci-hub.c +++ usb-2.6/drivers/usb/host/ehci-hub.c @@ -309,13 +309,15 @@ static ssize_t show_companion(struct dev } /* - * Sets the owner of a port + * Sets the connect-speed (i.e., owner) of a port */ -static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) +static void set_port_speed(struct ehci_hcd *ehci, int portnum, bool high_speed) { u32 __iomem *status_reg; u32 port_status; int try; + u32 owner_bit = ehci_port_owner_bit(ehci); + u32 new_owner = (high_speed ? 0 : owner_bit); status_reg = &ehci->regs->port_status[portnum]; @@ -327,12 +329,17 @@ static void set_owner(struct ehci_hcd *e for (try = 4; try > 0; --try) { spin_lock_irq(&ehci->lock); port_status = ehci_readl(ehci, status_reg); - if ((port_status & PORT_OWNER) == new_owner - || (port_status & (PORT_OWNER | PORT_CONNECT)) - == 0) + if ((port_status & owner_bit) == new_owner + + /* If PORT_OWNER isn't set and the port is + * disconnected then stop (we can't set + * it unless a device is attached). + */ + || ((port_status & (PORT_OWNER | PORT_CONNECT)) + == 0 && !ehci_is_TDI(ehci))) { try = 0; - else { - port_status ^= PORT_OWNER; + } else { + port_status ^= owner_bit; port_status &= ~(PORT_PE | PORT_RWC_BITS); ehci_writel(ehci, port_status, status_reg); } @@ -352,24 +359,24 @@ static ssize_t store_companion(struct de const char *buf, size_t count) { struct ehci_hcd *ehci; - int portnum, new_owner; + int portnum; + bool high_speed = false; ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - new_owner = PORT_OWNER; /* Owned by companion */ if (sscanf(buf, "%d", &portnum) != 1) return -EINVAL; if (portnum < 0) { portnum = - portnum; - new_owner = 0; /* Owned by EHCI */ + high_speed = true; } if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) return -ENOENT; portnum--; - if (new_owner) - set_bit(portnum, &ehci->companion_ports); - else + if (high_speed) clear_bit(portnum, &ehci->companion_ports); - set_owner(ehci, portnum, new_owner); + else + set_bit(portnum, &ehci->companion_ports); + set_port_speed(ehci, portnum, high_speed); return count; } static DEVICE_ATTR(companion, 0644, show_companion, store_companion); @@ -378,18 +385,13 @@ static inline void create_companion_file { int i; - /* with integrated TT there is no companion! */ - if (!ehci_is_TDI(ehci)) - i = device_create_file(ehci_to_hcd(ehci)->self.dev, - &dev_attr_companion); + i = device_create_file(ehci_to_hcd(ehci)->self.dev, + &dev_attr_companion); } static inline void remove_companion_file(struct ehci_hcd *ehci) { - /* with integrated TT there is no companion! */ - if (!ehci_is_TDI(ehci)) - device_remove_file(ehci_to_hcd(ehci)->self.dev, - &dev_attr_companion); + device_remove_file(ehci_to_hcd(ehci)->self.dev, &dev_attr_companion); } @@ -420,7 +422,7 @@ static int check_reset_complete ( // what happens if HCS_N_CC(params) == 0 ? port_status |= PORT_OWNER; - port_status &= ~PORT_RWC_BITS; + port_status &= ~(PORT_RWC_BITS | PORT_CONNECT); ehci_writel(ehci, port_status, status_reg); } else @@ -737,7 +739,8 @@ static int ehci_hub_control ( /* transfer dedicated ports to the companion hc */ if ((temp & PORT_CONNECT) && - test_bit(wIndex, &ehci->companion_ports)) { + test_bit(wIndex, &ehci->companion_ports) && + !ehci_is_TDI(ehci)) { temp &= ~PORT_RWC_BITS; temp |= PORT_OWNER; ehci_writel(ehci, temp, status_reg); @@ -745,6 +748,16 @@ static int ehci_hub_control ( temp = ehci_readl(ehci, status_reg); } + /* un-relinquish a disconnected port */ + if (!(temp & PORT_CONNECT) && + !test_bit(wIndex, &ehci->companion_ports) && + ehci_is_TDI(ehci) && + (temp & ehci_port_owner_bit(ehci))) { + temp &= ~(PORT_RWC_BITS | ehci_port_owner_bit(ehci)); + ehci_writel(ehci, temp, status_reg); + temp = ehci_readl(ehci, status_reg); + } + /* * Even if OWNER is set, there's no harm letting khubd * see the wPortStatus values (they should all be 0 except @@ -873,8 +886,5 @@ static void ehci_relinquish_port(struct { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - if (ehci_is_TDI(ehci)) - return; - set_owner(ehci, --portnum, PORT_OWNER); + set_port_speed(ehci, --portnum, false); } - -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html