Re: ehci at full speed only

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux