Various USB improvements
Subsystems (2)
cover Various USB improvements
This series adds a few USB improvements for Marek:
- Support for interupt transfers
- Faster start-up and proper shutdown of ASIX USB adapter
- Basic 64-bit controller support (used by x86)
- Fix detection of empty USB media readers
- Clean up after device configuration failure
Michael Spang (1):
usb: usbeth: smsc95xx: remove EEPROM loaded check
Milind Choudhary (1):
usb: Clean up newly allocated device nodes in case of configuration
failure
Patrick Georgi (1):
usb: ehci: Support interrupt transfers via periodic list
Simon Glass (2):
usb: net: asix: Do a fast init if link already established
x86: Enable USB features for coreboot
Vincent Palatin (6):
usb: ehci: Add 64-bit controller support
usb: ehci: generic PCI support
usb: ehci: Fix aliasing issue in EHCI interrupt code
usb: ehci: Add timeout on interrupt endpoint operations
usb: properly detect empty mass storage media reader
usb: Add multiple controllers support for EHCI PCI
common/usb.c | 12 ++ common/usb_hub.c | 2 + common/usb_storage.c | 10 ++ drivers/usb/eth/asix.c | 40 +++++- drivers/usb/eth/smsc95xx.c | 4 - drivers/usb/host/ehci-hcd.c | 312 ++++++++++++++++++++++++++++++++++++++++++- drivers/usb/host/ehci-pci.c | 55 +++++++- drivers/usb/host/ehci.h | 6 +- include/configs/coreboot.h | 17 +++ include/usb.h | 1 + include/usb_ether.h | 1 + 11 files changed, 437 insertions(+), 23 deletions(-)
Signature · 1 line
1.7.7.3
PATCH 1/11 usb: net: asix: Do a fast init if link already established
The Asix driver takes the link down during init() and then brings it back up. This commit changes this so that if a link has already been established successfully we simply check that the link is still good.
Also fix up asix_halt() to actually halt RX on the interface. Previously this was not done, so the device would continue to operate evern when halted, violating a U-Boot requirement.
This reduces the delay between successive network commands.
--- drivers/usb/eth/asix.c | 40 ++++++++++++++++++++++++++++++++-------- include/usb_ether.h | 1 + 2 files changed, 33 insertions(+), 8 deletions(-)
drivers/usb/eth/asix.c +32 -8
@@ -84,6 +84,7 @@#define AX_DEFAULT_RX_CTL \ (AX_RX_CTL_SO | AX_RX_CTL_AB) +#define AX_DISABLE_RX_CTL AX_RX_CTL_AB/* GPIO 2 toggles */ #define AX_GPIO_GPO2EN 0x10/* GPIO2 Output enable */
@@ -410,17 +411,16 @@ static int asix_basic_reset(struct ueth_data *dev)return 0 ; } -/* -* Asix callbacks -*/ -static int asix_init (struct eth_device *eth,bd_t *bd) +static int full_init (struct eth_device *eth) { -struct ueth_data *dev = (struct ueth_data *)eth->priv; -int timeout =0 ; -#define TIMEOUT_RESOLUTION 50/* ms */ -int link_detected; +struct ueth_data *dev = (struct ueth_data *)eth->priv;debug ("** %s()\n" , __func__); +if (asix_basic_reset (dev)) + goto out_err; + +if (asix_write_rx_ctl (dev,AX_DEFAULT_RX_CTL ) <0 ) + goto out_err; dev->phy_id =asix_get_phy_addr (dev);if (dev->phy_id <0 )
@@ -446,6 +446,25 @@ static int asix_init(struct eth_device *eth, bd_t *bd)debug ("Write IPG,IPG1,IPG2 failed\n" ); goto out_err; } +return 0 ; +out_err: +return -1 ; +} + +/* +* Asix callbacks +*/ +static int asix_init (struct eth_device *eth,bd_t *bd) +{ +struct ueth_data *dev = (struct ueth_data *)eth->priv; +int timeout =0 ; +#define TIMEOUT_RESOLUTION 50/* ms */ +int link_detected; + +debug ("** %s()\n" , __func__); + +if (!dev->has_been_running &&full_init (eth)) +return -1 ;if (asix_write_rx_ctl (dev,AX_DEFAULT_RX_CTL ) <0 ) goto out_err;
@@ -467,6 +486,7 @@ static int asix_init(struct eth_device *eth, bd_t *bd)printf ("unable to connect.\n" ); goto out_err; } + dev->has_been_running =1 ;return 0 ; out_err:
@@ -571,7 +591,11 @@ static int asix_recv(struct eth_device *eth)static void asix_halt (struct eth_device *eth) { +struct ueth_data *dev = (struct ueth_data *)eth->priv; + +/* Disable packet reception */ debug ("** %s()\n" , __func__); + (void )asix_write_rx_ctl (dev,AX_DISABLE_RX_CTL ); }/*
include/usb_ether.h +1 -0
@@ -49,6 +49,7 @@ struct ueth_data {unsigned char subclass;/* as in overview */ unsigned char protocol;/* .............. */ unsigned char irqinterval;/* Intervall for IRQ Pipe */ +char has_been_running;/* PHY already inited */ /* driver private */ void *dev_priv;
Signature · 1 line
1.7.7.3
PATCH 1/11 usb: net: asix: Do a fast init if link already established
Dear Simon Glass,
Quoted 10 lines
The Asix driver takes the link down during
init()and then brings it back up. This commit changes this so that if a link has already been established successfully we simply check that the link is still good.Also fix up
asix_halt()to actually halt RX on the interface. Previously this was not done, so the device would continue to operate evern when halted, violating a U-Boot requirement.This reduces the delay between successive network commands.
Signed-off-by Simon Glass <[email protected]>
Joe, this is yours. Gimme a go/no-go and an Ack ;-)
Best regards,
Marek Vasut
PATCH 1/11 usb: net: asix: Do a fast init if link already established
In reply to Simon GlassHi Simon,
Quoted 103 lines · Simon Glass
The Asix driver takes the link down during
init()and then brings it back up. This commit changes this so that if a link has already been established successfully we simply check that the link is still good.Also fix up
asix_halt()to actually halt RX on the interface. Previously this was not done, so the device would continue to operate evern when halted, violating a U-Boot requirement.This reduces the delay between successive network commands.
Signed-off-by Simon Glass <[email protected]>--- drivers/usb/eth/asix.c | 40 ++++++++++++++++++++++++++++++++-------- include/usb_ether.h | 1 + 2 files changed, 33 insertions(+), 8 deletions(-)drivers/usb/eth/asix.c +32
-8@@ -84,6 +84,7 @@#define AX_DEFAULT_RX_CTL \ (AX_RX_CTL_SO | AX_RX_CTL_AB) +#define AX_DISABLE_RX_CTL AX_RX_CTL_AB/* GPIO 2 toggles */ #define AX_GPIO_GPO2EN 0x10/* GPIO2 Output enable */ @@ -410,17 +411,16 @@ static int asix_basic_reset(struct ueth_data *dev)return 0 ; } -/* -* Asix callbacks -*/ -static int asix_init (struct eth_device *eth,bd_t *bd) +static int full_init (struct eth_device *eth) { -struct ueth_data *dev = (struct ueth_data *)eth->priv; -int timeout =0 ; -#define TIMEOUT_RESOLUTION 50/* ms */ -int link_detected; +struct ueth_data *dev = (struct ueth_data *)eth->priv;debug ("** %s()\n" , __func__); +if (asix_basic_reset (dev)) + goto out_err; + +if (asix_write_rx_ctl (dev,AX_DEFAULT_RX_CTL ) <0 ) + goto out_err; dev->phy_id =asix_get_phy_addr (dev);if (dev->phy_id <0 )@@ -446,6 +446,25 @@ static int asix_init(struct eth_device *eth, bd_t *bd)debug ("Write IPG,IPG1,IPG2 failed\n" ); goto out_err; } +return 0 ; +out_err: +return -1 ; +} + +/* +* Asix callbacks +*/ +static int asix_init (struct eth_device *eth,bd_t *bd) +{ +struct ueth_data *dev = (struct ueth_data *)eth->priv; +int timeout =0 ; +#define TIMEOUT_RESOLUTION 50/* ms */ +int link_detected; + +debug ("** %s()\n" , __func__); + +if (!dev->has_been_running &&full_init (eth)) +return -1 ;if (asix_write_rx_ctl (dev,AX_DEFAULT_RX_CTL ) <0 ) goto out_err;@@ -467,6 +486,7 @@ static int asix_init(struct eth_device *eth, bd_t *bd)printf ("unable to connect.\n" ); goto out_err; } + dev->has_been_running =1 ;return 0 ; out_err:@@ -571,7 +591,11 @@ static int asix_recv(struct eth_device *eth)static void asix_halt (struct eth_device *eth) { +struct ueth_data *dev = (struct ueth_data *)eth->priv; + +/* Disable packet reception */ debug ("** %s()\n" , __func__); + (void )asix_write_rx_ctl (dev,AX_DISABLE_RX_CTL ); }/* include/usb_ether.h +0
-0
include/usb_ether.h struct ueth_data { · line 55
Quoted 7 lines
include/usb_ether.h +1
-0@@ -49,6 +49,7 @@ struct ueth_data {unsigned char subclass;/* as in overview */ unsigned char protocol;/* .............. */ unsigned char irqinterval;/* Intervall for IRQ Pipe */ +char has_been_running;/* PHY already inited */ /* driver private */ void *dev_priv;
PATCH 2/11 usb: ehci: Add 64-bit controller support
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
On EHCI controller with 64-bit address space support, we must initialize properly the high word for the PCI bus master accesses.
--- drivers/usb/host/ehci-hcd.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/usb/host/ehci-hcd.c +3 -0
@@ -870,6 +870,9 @@ int usb_lowlevel_init(int index, void **controller)if (ehci_hcd_init (index, &ehcic[index].hccr, &ehcic[index].hcor))return -1 ;#endif +/* Set the high address word (aka segment) for 64-bit controller */ +if (ehci_readl (&ehcic[index].hccr->cr_hccparams) &1 ) +ehci_writel (ehcic[index].hcor->or_ctrldssegment,0 ); qh_list = &ehcic[index].qh_list;
Signature · 1 line
1.7.7.3
Marek Vasut
AppliedPATCH 2/11 usb: ehci: Add 64-bit controller support
Dear Simon Glass,
Quoted 16 lines
From: Vincent Palatin <[email protected]>
On EHCI controller with 64-bit address space support, we must initialize properly the high word for the PCI bus master accesses.
Signed-off-by Vincent Palatin <[email protected]>Signed-off-by Simon Glass <[email protected]>--- drivers/usb/host/ehci-hcd.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)drivers/usb/host/ehci-hcd.c +0
-0
drivers/usb/host/ehci-hcd.c int usb_lowlevel_init(int index, void **controller) · line 877
Quoted 8 lines
drivers/usb/host/ehci-hcd.c +3
-0@@ -870,6 +870,9 @@ int usb_lowlevel_init(int index, void **controller)if (ehci_hcd_init (index, &ehcic[index].hccr, &ehcic[index].hcor))return -1 ;#endif +/* Set the high address word (aka segment) for 64-bit controller */ +if (ehci_readl (&ehcic[index].hccr->cr_hccparams) &1 ) +ehci_writel (ehcic[index].hcor->or_ctrldssegment,0 ); qh_list = &ehcic[index].qh_list;
Applied, thanks
Best regards,
Marek Vasut
PATCH 3/11 usb: ehci: generic PCI support
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
Instead of hardcoding the PCI IDs on the USB controller, use the PCI class to detect them.
Ensure the busmaster bit is properly set in the PCI configuration.
--- drivers/usb/host/ehci-pci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-)
drivers/usb/host/ehci-pci.c +37 -0
@@ -32,6 +32,34 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; +#else +static pci_dev_t ehci_find_class(void) +{ + int bus; + int devnum; + pci_dev_t bdf; + uint32_t class; + + for (bus = 0; bus < pci_last_busno(); bus++) { + for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) { + pci_read_config_dword(PCI_BDF(bus, devnum, 0), + PCI_CLASS_REVISION, &class); + if (class >> 16 == 0xffff) + continue; + + for (bdf = PCI_BDF(bus, devnum, 0); + bdf <= PCI_BDF(bus, devnum, + PCI_MAX_PCI_FUNCTIONS - 1); + bdf += PCI_BDF(0, 0, 1)) { + pci_read_config_dword(bdf, PCI_CLASS_REVISION, + &class); + if (class >> 8 == 0x0c0320) + return bdf; + } + } + } + return -1; +} #endif /*
@@ -41,8 +69,13 @@ static struct pci_device_id ehci_pci_ids[] = {int ehci_hcd_init (int index,struct ehci_hccr **hccr,struct ehci_hcor **hcor) {pci_dev_t pdev; +uint32_t cmd; +#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE ); +#else + pdev =ehci_find_class (); +#endif if (pdev ==-1 ) {printf ("EHCI host controller not found\n" );return -1 ;
@@ -57,6 +90,10 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) (uint32_t )*hccr, (uint32_t )*hcor, (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); +/* enable busmaster */ +pci_read_config_dword (pdev,PCI_COMMAND , &cmd); + cmd |=PCI_COMMAND_MASTER ; +pci_write_config_dword (pdev,PCI_COMMAND , cmd);return 0 ; }
Signature · 1 line
1.7.7.3
PATCH 3/11 usb: ehci: generic PCI support
Dear Simon Glass,
Quoted 32 lines
From: Vincent Palatin <[email protected]>
Instead of hardcoding the PCI IDs on the USB controller, use the PCI class to detect them.
Ensure the busmaster bit is properly set in the PCI configuration.
Signed-off-by Simon Glass <[email protected]>--- drivers/usb/host/ehci-pci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-)drivers/usb/host/ehci-pci.c +12
-0@@ -32,6 +32,34 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; +#else +static pci_dev_t ehci_find_class(void) +{ + int bus; + int devnum; + pci_dev_t bdf; + uint32_t class; + + for (bus = 0; bus < pci_last_busno(); bus++) { + for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) { + pci_read_config_dword(PCI_BDF(bus, devnum, 0), + PCI_CLASS_REVISION, &class);
drivers/usb/host/ehci-pci.c static struct pci_device_id ehci_pci_ids[] = { · line 56
Quoted 10 lines
drivers/usb/host/ehci-pci.c +10
-0+if (class >>16 ==0xffff ) +continue ; + +for (bdf =PCI_BDF (bus, devnum,0 ); + bdf <=PCI_BDF (bus, devnum, +PCI_MAX_PCI_FUNCTIONS -1 ); + bdf +=PCI_BDF (0 ,0 ,1 )) { +pci_read_config_dword (bdf,PCI_CLASS_REVISION , + &class); +if (class >>8 ==0x0c0320 )
Can we at least describe this magic please?
drivers/usb/host/ehci-pci.c static struct pci_device_id ehci_pci_ids[] = { · line 61
Quoted 5 lines
drivers/usb/host/ehci-pci.c +5
-0+return bdf; + } + } + } +return -1 ;
Let's try to use errno.h please. It won't be consistent for a while, but we'll get there.
Quoted 19 lines
drivers/usb/host/ehci-pci.c +6
-0+}#endif /* @@ -41,8 +69,13 @@ static struct pci_device_id ehci_pci_ids[] = {int ehci_hcd_init (int index,struct ehci_hccr **hccr,struct ehci_hcor **hcor) {pci_dev_t pdev; +uint32_t cmd; +#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE ); +#else + pdev =ehci_find_class (); +#endif if (pdev ==-1 ) {printf ("EHCI host controller not found\n" );return -1 ;
drivers/usb/host/ehci-pci.c int ehci_hcd_init(int index, struct ehci_hccr **hccr, · line 98
Quoted 9 lines
drivers/usb/host/ehci-pci.c +4
-0@@ -57,6 +90,10 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) (uint32_t)*hccr, (uint32_t)*hcor, (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); +/* enable busmaster */ +pci_read_config_dword (pdev,PCI_COMMAND , &cmd); + cmd |=PCI_COMMAND_MASTER ; +pci_write_config_dword (pdev,PCI_COMMAND , cmd);return 0 ; }
Best regards,
Marek Vasut
PATCH 3/11 usb: ehci: generic PCI support
Quoted 38 lines · Marek Vasut
Dear Simon Glass,
Quoted 36 lines
From: Vincent Palatin <[email protected]>
Instead of hardcoding the PCI IDs on the USB controller, use the PCI class to detect them.
Ensure the busmaster bit is properly set in the PCI configuration.
Signed-off-by Simon Glass <[email protected]>--- drivers/usb/host/ehci-pci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-)drivers/usb/host/ehci-pci.c +16
-0@@ -32,6 +32,34 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; +#else +static pci_dev_t ehci_find_class(void) +{ + int bus; + int devnum; + pci_dev_t bdf; + uint32_t class; + + for (bus = 0; bus < pci_last_busno(); bus++) { + for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) { + pci_read_config_dword(PCI_BDF(bus, devnum, 0), + PCI_CLASS_REVISION, &class); + if (class >> 16 == 0xffff) + continue; + + for (bdf = PCI_BDF(bus, devnum, 0);
Quoted 8 lines
drivers/usb/host/ehci-pci.c static struct pci_device_id ehci_pci_ids[] = { · line 56
Quoted 6 lines
drivers/usb/host/ehci-pci.c +6
-0+ bdf <=PCI_BDF (bus, devnum, +PCI_MAX_PCI_FUNCTIONS -1 ); + bdf += PCI_BDF(0, 0, 1)) { +pci_read_config_dword (bdf,PCI_CLASS_REVISION , + &class); +if (class >>8 ==0x0c0320 )Can we at least describe this magic please?
The PCI class word is something like that :
class = [31:24] class code [23:16] subclass [15:8] Prog if [7:0] Revision ID For this use case :
class code = 0x0C (Serial bus controller)
subclass = 0x03 (USB controller)
Program interface = 0x20 (EHCI)
This is available in include/pci_ids.h as "#definePCI_CLASS_SERIAL_USB_EHCI 0x0c0320"
so just replacing the numeric constant by this define should be ok ?
Quoted 40 lines
drivers/usb/host/ehci-pci.c static struct pci_device_id ehci_pci_ids[] = { · line 61
Quoted 5 lines
drivers/usb/host/ehci-pci.c +5
-0+return bdf; + } + } + } +return -1 ;Let's try to use
errno.hplease. It won't be consistent for a while, but we'll get there.Quoted 19 lines
drivers/usb/host/ehci-pci.c +6
-0+}#endif /* @@ -41,8 +69,13 @@ static struct pci_device_id ehci_pci_ids[] = {int ehci_hcd_init (int index,struct ehci_hccr **hccr,struct ehci_hcor **hcor) {pci_dev_t pdev; +uint32_t cmd; +#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE ); +#else + pdev =ehci_find_class (); +#endif if (pdev ==-1 ) {printf ("EHCI host controller not found\n" );return -1 ;drivers/usb/host/ehci-pci.c int ehci_hcd_init(int index, struct ehci_hccr **hccr, · line 98
Quoted 9 lines
drivers/usb/host/ehci-pci.c +4
-0@@ -57,6 +90,10 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) (uint32_t)*hccr, (uint32_t)*hcor, (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); +/* enable busmaster */ +pci_read_config_dword (pdev,PCI_COMMAND , &cmd); + cmd |=PCI_COMMAND_MASTER ; +pci_write_config_dword (pdev,PCI_COMMAND , cmd);return 0 ; }Best regards,
Marek Vasut
PATCH 3/11 usb: ehci: generic PCI support
Dear Vincent Palatin,
Quoted 61 lines · Marek Vasut
Quoted 44 lines
Dear Simon Glass,
Quoted 42 lines
From: Vincent Palatin <[email protected]>
Instead of hardcoding the PCI IDs on the USB controller, use the PCI class to detect them.
Ensure the busmaster bit is properly set in the PCI configuration.
Signed-off-by Simon Glass <[email protected]>---
drivers/usb/host/ehci-pci.c | 37+++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-)
drivers/usb/host/ehci-pci.c +10
-0@@ -32,6 +32,34 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; +#else +static pci_dev_t ehci_find_class(void) +{ + int bus; + int devnum; + pci_dev_t bdf; + uint32_t class; + + for (bus = 0; bus < pci_last_busno(); bus++) { + for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++){ + pci_read_config_dword(PCI_BDF(bus, devnum, 0),
+PCI_CLASS_REVISION,
&class); + if (class >> 16 ==0xffff)drivers/usb/host/ehci-pci.c +4
-0+continue ; + + for (bdf = PCI_BDF(bus, devnum, 0); + bdf <= PCI_BDF(bus, devnum,Quoted 8 lines
Quoted 6 lines
+
PCI_MAX_PCI_FUNCTIONS-
1); + bdf +=PCI_BDF(0, 0, 1)) { +
pci_read_config_dword(bdf,PCI_CLASS_REVISION, +
&class);
+ if (class >> 8 ==0x0c0320)Can we at least describe this magic please?
The PCI class word is something like that :
class = [31:24] class code [23:16] subclass [15:8] Prog if [7:0] Revision ID For this use case :
class code =0x0C(Serial bus controller)
subclass =0x03(USB controller)
Program interface =0x20(EHCI)
Quoted 3 lines
This is available in
include/pci_ids.has "#definePCI_CLASS_SERIAL_USB_EHCI0x0c0320"
so just replacing the numeric constant by this define should be ok ?
Of course :)
PATCH 3/11 usb: ehci: generic PCI support
In reply to Marek VasutHi Marek,
Quoted 38 lines · Marek Vasut
Dear Simon Glass,
Quoted 36 lines
From: Vincent Palatin <[email protected]>
Instead of hardcoding the PCI IDs on the USB controller, use the PCI class to detect them.
Ensure the busmaster bit is properly set in the PCI configuration.
Signed-off-by Simon Glass <[email protected]>--- drivers/usb/host/ehci-pci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 files changed, 37 insertions(+), 0 deletions(-)drivers/usb/host/ehci-pci.c +16
-0@@ -32,6 +32,34 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; +#else +static pci_dev_t ehci_find_class(void) +{ + int bus; + int devnum; + pci_dev_t bdf; + uint32_t class; + + for (bus = 0; bus < pci_last_busno(); bus++) { + for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) { + pci_read_config_dword(PCI_BDF(bus, devnum, 0), + PCI_CLASS_REVISION, &class); + if (class >> 16 == 0xffff) + continue; + + for (bdf = PCI_BDF(bus, devnum, 0);
Quoted 8 lines
drivers/usb/host/ehci-pci.c static struct pci_device_id ehci_pci_ids[] = { · line 56
Quoted 6 lines
drivers/usb/host/ehci-pci.c +6
-0+ bdf <=PCI_BDF (bus, devnum, +PCI_MAX_PCI_FUNCTIONS -1 ); + bdf += PCI_BDF(0, 0, 1)) { +pci_read_config_dword (bdf,PCI_CLASS_REVISION , + &class); +if (class >>8 ==0x0c0320 )Can we at least describe this magic please?
Changed to PCI_CLASS_SERIAL_USB_EHCI.
Quoted 9 lines
drivers/usb/host/ehci-pci.c static struct pci_device_id ehci_pci_ids[] = { · line 61
Quoted 6 lines
drivers/usb/host/ehci-pci.c +5
-0+return bdf; + } + } + } +return -1 ;Let's try to use
errno.hplease. It won't be consistent for a while, but we'll get there.
Yes, although pci_find_devices() doesn't, so I will just check for < 0 below.
Quoted 23 lines
Quoted 23 lines
drivers/usb/host/ehci-pci.c +6
-0+}#endif /* @@ -41,8 +69,13 @@ static struct pci_device_id ehci_pci_ids[] = {int ehci_hcd_init (int index,struct ehci_hccr **hccr,struct ehci_hcor **hcor) {pci_dev_t pdev; +uint32_t cmd; +#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE ); +#else + pdev =ehci_find_class (); +#endif if (pdev ==-1 ) {printf ("EHCI host controller not found\n" );return -1 ;@@ -57,6 +90,10 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) (uint32_t)*hccr, (uint32_t)*hcor, (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
Quoted 9 lines
drivers/usb/host/ehci-pci.c int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) · line 98
Quoted 6 lines
drivers/usb/host/ehci-pci.c +4
-0+/* enable busmaster */ +pci_read_config_dword (pdev,PCI_COMMAND , &cmd); + cmd |=PCI_COMMAND_MASTER ; +pci_write_config_dword (pdev,PCI_COMMAND , cmd);return 0 ; }Best regards,
Marek Vasut
Regards,
Simon
PATCH v3 2/7 usb: ehci: generic PCI support
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
Instead of hardcoding the PCI IDs on the USB controller, use the PCI class to detect them.
Ensure the busmaster bit is properly set in the PCI configuration.
---
Changes in v3:
- Check the last PCI bus (this was unfortunately omitted in v2)
Changes in v2:
- Use errno where possible
- Use PCI_CLASS_SERIAL_USB_EHCI instead of the number
drivers/usb/host/ehci-pci.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 40 insertions(+), 1 deletions(-)
drivers/usb/host/ehci-pci.c +40 -1
@@ -19,6 +19,7 @@*/ #include <common.h> +#include <errno.h> #include <pci.h> #include <usb.h>
@@ -32,6 +33,35 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; +#else +static pci_dev_t ehci_find_class(void) +{ + int bus; + int devnum; + pci_dev_t bdf; + uint32_t class; + + for (bus = 0; bus <= pci_last_busno(); bus++) { + for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) { + pci_read_config_dword(PCI_BDF(bus, devnum, 0), + PCI_CLASS_REVISION, &class); + if (class >> 16 == 0xffff) + continue; + + for (bdf = PCI_BDF(bus, devnum, 0); + bdf <= PCI_BDF(bus, devnum, + PCI_MAX_PCI_FUNCTIONS - 1); + bdf += PCI_BDF(0, 0, 1)) { + pci_read_config_dword(bdf, PCI_CLASS_REVISION, + &class); + if (class >> 8 == PCI_CLASS_SERIAL_USB_EHCI) + return bdf; + } + } + } + + return -ENODEV; +} #endif /*
@@ -41,9 +71,14 @@ static struct pci_device_id ehci_pci_ids[] = {int ehci_hcd_init (int index,struct ehci_hccr **hccr,struct ehci_hcor **hcor) {pci_dev_t pdev; +uint32_t cmd; +#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE ); -if (pdev ==-1 ) { +#else + pdev =ehci_find_class (); +#endif +if (pdev <0 ) {printf ("EHCI host controller not found\n" );return -1 ; }
@@ -57,6 +92,10 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) (uint32_t )*hccr, (uint32_t )*hcor, (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); +/* enable busmaster */ +pci_read_config_dword (pdev,PCI_COMMAND , &cmd); + cmd |=PCI_COMMAND_MASTER ; +pci_write_config_dword (pdev,PCI_COMMAND , cmd);return 0 ; }
Signature · 1 line
1.7.7.3
PATCH 4/11 usb: ehci: Support interrupt transfers via periodic list
In reply to Simon GlassFrom: Patrick Georgi <[email protected]>
Interrupt transfers aren't meant to be used from the async list (the EHCI spec indicates trouble with low/full-speed intr on async).
Build a periodic list instead, and provide an API to make use of it. Then, use that API from the existing interrupt transfer API.
This provides support for USB keyboards using EHCI.
--- drivers/usb/host/ehci-hcd.c | 295 ++++++++++++++++++++++++++++++++++++++++++- drivers/usb/host/ehci.h | 6 +- 2 files changed, 296 insertions(+), 5 deletions(-)
drivers/usb/host/ehci-hcd.c +291 -4
@@ -27,6 +27,7 @@#include <asm/io.h> #include <malloc.h> #include <watchdog.h> +#include <linux/compiler.h> #include "ehci.h"
@@ -39,7 +40,10 @@ static struct ehci_ctrl {struct ehci_hcor *hcor;int rootdev;uint16_t portreset; - struct QH qh_list __attribute__((aligned(USB_DMA_MINALIGN))); +struct QH qh_list__aligned(USB_DMA_MINALIGN) ; +struct QH periodic_queue__aligned(USB_DMA_MINALIGN) ; +uint32_t *periodic_list; +int ntds; } ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT ];#define ALIGN_END_ADDR (type, ptr, size) \
@@ -858,6 +862,7 @@ int usb_lowlevel_init(int index, void **controller)uint32_t reg;uint32_t cmd;struct QH *qh_list; +struct QH *periodic;if (ehci_hcd_init (index, &ehcic[index].hccr, &ehcic[index].hcor))return -1 ;
@@ -887,6 +892,38 @@ int usb_lowlevel_init(int index, void **controller) qh_list->qh_overlay.qt_token =cpu_to_hc32 (QT_TOKEN_STATUS (QT_TOKEN_STATUS_HALTED )); +/* Set async. queue head pointer. */ +ehci_writel (&ehcic[index].hcor->or_asynclistaddr, (uint32_t )qh_list); + +/* +* Set up periodic list +* Step 1: Parent QH for all periodic transfers. +*/ + periodic = &ehcic[index].periodic_queue; +memset (periodic,0 ,sizeof (*periodic)); + periodic->qh_link =cpu_to_hc32 (QH_LINK_TERMINATE ); + periodic->qh_overlay.qt_next =cpu_to_hc32 (QT_NEXT_TERMINATE ); + periodic->qh_overlay.qt_altnext =cpu_to_hc32 (QT_NEXT_TERMINATE ); + +/* +* Step 2: Setup frame-list: Every microframe, USB tries the same list. +* In particular, device specifications on polling frequency +* are disregarded. Keyboards seem to send NAK/NYet reliably +* when polled with an empty buffer. +* +* Split Transactions will be spread across microframes using +* S-mask and C-mask. +*/ + ehcic[index].periodic_list =memalign (4096 ,1024 *4 ); +int i; +for (i =0 ; i <1024 ; i++) + ehcic[index].periodic_list[i] = (uint32_t )periodic + |QH_LINK_TYPE_QH ; + +/* Set periodic list base address */ +ehci_writel (&ehcic[index].hcor->or_periodiclistbase, + (uint32_t )ehcic[index].periodic_list); + reg =ehci_readl (&ehcic[index].hccr->cr_hcsparams); descriptor.hub.bNbrPorts =HCS_N_PORTS (reg);debug ("Register %x NbrPorts %d\n" , reg, descriptor.hub.bNbrPorts);
@@ -956,10 +993,243 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,return ehci_submit_async (dev, pipe, buffer, length, setup); } +struct int_queue { +struct QH *first; +struct QH *current; +struct QH *last; +struct qTD *tds; +}; + +#define NEXT_QH (qh) (struct QH *)((qh)->qh_link & ~0x1f) + +static int +enable_periodic (struct ehci_ctrl *ctrl) +{ +uint32_t cmd; +struct ehci_hcor *hcor = ctrl->hcor; + + cmd =ehci_readl (&hcor->or_usbcmd); + cmd |=CMD_PSE ; +ehci_writel (&hcor->or_usbcmd, cmd); + +int ret =handshake ((uint32_t *)&hcor->or_usbsts, +STD_PSS ,STD_PSS ,100 *1000 ); +if (ret <0 ) { +printf ("EHCI failed: timeout when enabling periodic list\n" ); +return -1 ; + } +udelay (1000 ); +return 0 ; +} + +static int +disable_periodic (struct ehci_ctrl *ctrl) +{ +uint32_t cmd; +struct ehci_hcor *hcor = ctrl->hcor; + + cmd =ehci_readl (&hcor->or_usbcmd); + cmd &= ~CMD_PSE ; +ehci_writel (&hcor->or_usbcmd, cmd); + +int ret =handshake ((uint32_t *)&hcor->or_usbsts, +STD_PSS ,0 ,100 *1000 ); +if (ret <0 ) { +printf ("EHCI failed: timeout when enabling periodic list\n" ); +return -1 ; + } +return 0 ; +} + +int periodic_schedules; + +struct int_queue * +create_int_queue (struct usb_device *dev,unsigned long pipe,int queuesize, +int elementsize,void *buffer) +{ +int i; +struct ehci_ctrl *ctrl = dev->controller; +struct int_queue *result =NULL ; +debug ("Enter create_int_queue\n" ); +if (usb_pipetype (pipe) !=PIPE_INTERRUPT ) { +debug ("non-interrupt pipe (type=%lu)" ,usb_pipetype (pipe)); +return NULL ; + } + +/* limit to 4 full pages worth of data - +* we can safely fit them in a single TD, +* no matter the alignment +*/ +if (elementsize >=16384 ) { +debug ("too large elements for interrupt transfers\n" ); +return NULL ; + } + + result =malloc (sizeof (*result)); +if (!result) { +debug ("ehci intr queue: out of memory\n" ); + goto fail1; + } + result->first =memalign (32 ,sizeof (struct QH ) * queuesize); +if (!result->first) { +debug ("ehci intr queue: out of memory\n" ); + goto fail2; + } + result->current = result->first; + result->last = result->first + elementsize -1 ; + result->tds =memalign (32 ,sizeof (struct qTD ) * queuesize); +if (!result->tds) { +debug ("ehci intr queue: out of memory\n" ); + goto fail3; + } +memset (result->first,0 ,sizeof (struct QH ) * queuesize); +memset (result->tds,0 ,sizeof (struct qTD ) * queuesize); + +for (i =0 ; i < queuesize; i++) { +struct QH *qh = result->first + i; +struct qTD *td = result->tds + i; +void **buf = &qh->buffer; + + qh->qh_link = (uint32_t )(qh+1 ) |QH_LINK_TYPE_QH ; +if (i == queuesize -1 ) + qh->qh_link =QH_LINK_TERMINATE ; + + qh->qh_overlay.qt_next = (uint32_t )td; + qh->qh_endpt1 = (0 <<28 ) |/* No NAK reload (ehci 4.9) */ + (usb_maxpacket (dev, pipe) <<16 ) |/* MPS */ + (1 <<14 ) |/* TODO: Data Toggle Control */ +QH_ENDPT1_EPS (ehci_encode_speed (dev->speed)) | + (usb_pipeendpoint (pipe) <<8 ) |/* Endpoint Number */ + (usb_pipedevice (pipe) <<0 ); + qh->qh_endpt2 = (1 <<30 );/* 1 Tx per mframe */ +if (dev->speed ==USB_SPEED_LOW || + dev->speed ==USB_SPEED_FULL ) { +debug ("TT: port: %d, hub address: %d\n" , + dev->portnr, dev->parent->devnum); + qh->qh_endpt2 |= (dev->portnr <<23 ) | + (dev->parent->devnum <<16 ) | + (0x1c <<8 ) |/* C-mask: microframes 2-4 */ + (1 <<0 );/* S-mask: microframe 0 */ + } + + td->qt_next =QT_NEXT_TERMINATE ; + td->qt_altnext =QT_NEXT_TERMINATE ; +debug ("communication direction is '%s'\n" , +usb_pipein (pipe) ?"in" :"out" ); + td->qt_token = (elementsize <<16 ) | + ((usb_pipein (pipe) ?1 :0 ) <<8 ) |/* IN/OUT token */ +0x80 ;/* active */ + td->qt_buffer[0 ] = (uint32_t )buffer + i * elementsize; + td->qt_buffer[1 ] = (td->qt_buffer[0 ] +0x1000 ) & ~0xfff ; + td->qt_buffer[2 ] = (td->qt_buffer[0 ] +0x2000 ) & ~0xfff ; + td->qt_buffer[3 ] = (td->qt_buffer[0 ] +0x3000 ) & ~0xfff ; + td->qt_buffer[4 ] = (td->qt_buffer[0 ] +0x4000 ) & ~0xfff ; + + *buf = buffer + i * elementsize; + } + +if (disable_periodic (ctrl) <0 ) { +debug ("FATAL: periodic should never fail, but did" ); + goto fail3; + } + +/* hook up to periodic list */ +struct QH *list = &ctrl->periodic_queue; + result->last->qh_link = list->qh_link; + list->qh_link = (uint32_t )result->first |QH_LINK_TYPE_QH ; + +if (enable_periodic (ctrl) <0 ) { +debug ("FATAL: periodic should never fail, but did" ); + goto fail3; + } + periodic_schedules++; + +debug ("Exit create_int_queue\n" ); +return result; +fail3: +if (result->tds) +free (result->tds); +fail2: +if (result->first) +free (result->first); +if (result) +free (result); +fail1: +return NULL ; +} + +/* TODO: requeue depleted buffers */ +void * +poll_int_queue (struct usb_device *dev,struct int_queue *queue) +{ +struct QH *cur = queue->current; +/* depleted queue */ +if (cur ==NULL ) { +debug ("Exit poll_int_queue with completed queue\n" ); +return NULL ; + } +/* still active */ +if (cur->qh_overlay.qt_token &0x80 ) { +debug ("Exit poll_int_queue with no completed intr transfer. " +"token is %x\n" , cur->qh_overlay.qt_token); +return NULL ; + } +/* TODO: Handle failures */ +if (!(cur->qh_link &QH_LINK_TERMINATE )) + queue->current++; +else + queue->current =NULL ; +debug ("Exit poll_int_queue with completed intr transfer. " +"token is %x at %p (first at %p)\n" , cur->qh_overlay.qt_token, + &cur->qh_overlay.qt_token, queue->first); +return cur->buffer; +} + +/* Do not free buffers associated with QHs, they're owned by someone else */ +int +destroy_int_queue (struct usb_device *dev,struct int_queue *queue) +{ +struct ehci_ctrl *ctrl = dev->controller; +int result =-1 ; + +if (disable_periodic (ctrl) <0 ) { +debug ("FATAL: periodic should never fail, but did" ); + goto out; + } + periodic_schedules--; + +struct QH *cur = &ctrl->periodic_queue; +while (!(cur->qh_link &QH_LINK_TERMINATE )) { +debug ("considering %p, with qh_link %x\n" , cur, cur->qh_link); +if (NEXT_QH (cur) == queue->first) { +debug ("found candidate. removing from chain\n" ); + cur->qh_link = queue->last->qh_link; + result =0 ; + goto out; + } + cur =NEXT_QH (cur); + } + +if (periodic_schedules >0 ) +if (enable_periodic (ctrl) <0 ) { +debug ("FATAL: periodic should never fail, but did" ); + result =-1 ; + } + +out: +free (queue->tds); +free (queue->first); +free (queue); +return result; +} +int submit_int_msg (struct usb_device *dev,unsigned long pipe,void *buffer,int length,int interval) { +void *backbuffer; +struct int_queue *queue; +debug ("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d" , dev, pipe, buffer, length, interval);
@@ -975,9 +1245,26 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,* not require more than a single qTD. */ if (length >usb_maxpacket (dev, pipe)) { -printf ("%s: Interrupt transfers requiring several transactions " -"are not supported.\n" , __func__); +printf ("%s: Interrupt transfers requiring several " +"transactions are not supported.\n" , __func__);return -1 ; } -return ehci_submit_async (dev, pipe, buffer, length,NULL ); + + queue =create_int_queue (dev, pipe,1 , length, buffer); + +/* TODO: pick some useful timeout rule */ +while ((backbuffer =poll_int_queue (dev, queue)) ==NULL ) + ; + +if (backbuffer != buffer) { +debug ("got wrong buffer back (%x instead of %x)\n" , + (uint32_t )backbuffer, (uint32_t )buffer); +return -1 ; + } + +if (destroy_int_queue (dev, queue) ==-1 ) +return -1 ; + +/* everything worked out fine */ +return 0 ; }
drivers/usb/host/ehci.h +5 -1
@@ -69,6 +69,7 @@ struct ehci_hcor {#define CMD_RUN (1 << 0)/* start/stop HC */ uint32_t or_usbsts;#define STS_ASS (1 << 15) +#define STD_PSS (1 << 14)#define STS_HALT (1 << 12)uint32_t or_usbintr;#define INTR_UE (1 << 0)/* USB interrupt enable */
@@ -245,7 +246,10 @@ struct QH {* Add dummy fill value to make the size of this struct * aligned to 32 bytes */ -uint8_t fill[16 ]; +union { +uint8_t fill[16 ]; +void *buffer; + }; };/* Low level init functions */
Signature · 1 line
1.7.7.3
PATCH 4/11 usb: ehci: Support interrupt transfers via periodic list
Dear Simon Glass,
Quoted 5 lines
From: Patrick Georgi <[email protected]>
Interrupt transfers aren't meant to be used from the async list (the EHCI spec indicates trouble with low/full-speed intr on async).
Quoted 7 lines
Build a periodic list instead, and provide an API to make use of it. Then, use that API from the existing interrupt transfer API.
This provides support for USB keyboards using EHCI.
Signed-off-by Patrick Georgi <[email protected]>Signed-off-by Simon Glass <[email protected]>
[...]
Looks good in general. Clear up those ToDos please. Also, some while() cycles are endless, make use of some timeout please.
Best regards,
Marek Vasut
PATCH 4/11 usb: ehci: Support interrupt transfers via periodic list
Hi,
Quoted 10 lines · Marek Vasut
Dear Simon Glass,
Quoted 8 lines
From: Patrick Georgi <[email protected]>
Interrupt transfers aren't meant to be used from the async list (the EHCI spec indicates trouble with low/full-speed intr on async).
Build a periodic list instead, and provide an API to make use of it. Then, use that API from the existing interrupt transfer API.
Quoted 8 lines
Quoted 4 lines
This provides support for USB keyboards using EHCI.
Signed-off-by Patrick Georgi <[email protected]>Signed-off-by Simon Glass <[email protected]>[...]
Looks good in general. Clear up those ToDos please. Also, some
while()cycles are endless, make use of some timeout please.
Not much ability to do anything other than remove them...
The timeouts come in the next patch - should I squash them?
Regards,
Simon
Quoted 3 lines
Best regards,
Marek Vasut
PATCH 4/11 usb: ehci: Support interrupt transfers via periodic list
Dear Simon Glass,
Quoted 18 lines
Hi,
Quoted 15 lines · Marek Vasut
Dear Simon Glass,
Quoted 12 lines
From: Patrick Georgi <[email protected]>
Interrupt transfers aren't meant to be used from the async list (the EHCI spec indicates trouble with low/full-speed intr on async).
Build a periodic list instead, and provide an API to make use of it. Then, use that API from the existing interrupt transfer API.
This provides support for USB keyboards using EHCI.
Signed-off-by Patrick Georgi <[email protected]>Signed-off-by Simon Glass <[email protected]>
Quoted 8 lines
Quoted 4 lines
[...]
Looks good in general. Clear up those ToDos please. Also, some
while()cycles are endless, make use of some timeout please.Not much ability to do anything other than remove them...
The timeouts come in the next patch - should I squash them?
Yeah, squash them. Was there any reason to split them ?
Best regards,
Marek Vasut
PATCH 4/11 usb: ehci: Support interrupt transfers via periodic list
Hi Marek,
Quoted 22 lines · Marek Vasut
Dear Simon Glass,
Quoted 20 lines
Hi,
Quoted 17 lines · Marek Vasut
Dear Simon Glass,
Quoted 12 lines
From: Patrick Georgi <[email protected]>
Interrupt transfers aren't meant to be used from the async list (the EHCI spec indicates trouble with low/full-speed intr on async).
Build a periodic list instead, and provide an API to make use of it. Then, use that API from the existing interrupt transfer API.
This provides support for USB keyboards using EHCI.
Signed-off-by Patrick Georgi <[email protected]>Signed-off-by Simon Glass <[email protected]>[...]
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Looks good in general. Clear up those ToDos please. Also, some
while()cycles are endless, make use of some timeout please.Not much ability to do anything other than remove them...
The timeouts come in the next patch - should I squash them?
Yeah, squash them. Was there any reason to split them ?
Not really - just a bug fix that we did. Will squash.
Regards,
Simon
Quoted 3 lines
Best regards,
Marek Vasut
PATCH 5/11 usb: ehci: Fix aliasing issue in EHCI interrupt code
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
The interrupt endpoint handling code stores the buffer pointer in the QH padding field. We need to make it the size of a pointer to avoid strict aliasing issue with the compiler.
--- drivers/usb/host/ehci.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/usb/host/ehci.h +1 -1
@@ -247,7 +247,7 @@ struct QH {* aligned to 32 bytes */ union { -uint8_t fill[16 ]; +uint32_t fill[4 ];void *buffer; }; };
Signature · 1 line
1.7.7.3
PATCH 6/11 usb: ehci: Add timeout on interrupt endpoint operations
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
Ensure we cannot get stuck in the keyboard scanning if something wrong happens (USB device unplugged or fatal I/O error)
--- drivers/usb/host/ehci-hcd.c | 18 ++++++++++++++++-- 1 files changed, 16 insertions(+), 2 deletions(-)
drivers/usb/host/ehci-hcd.c +16 -2
@@ -1191,6 +1191,7 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue) {struct ehci_ctrl *ctrl = dev->controller;int result =-1 ; +unsigned long timeout;if (disable_periodic (ctrl) <0 ) {debug ("FATAL: periodic should never fail, but did" );
@@ -1199,6 +1200,7 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue) periodic_schedules--;struct QH *cur = &ctrl->periodic_queue; + timeout =get_timer (0 ) +500 ;/* abort after 500ms */ while (!(cur->qh_link &QH_LINK_TERMINATE )) {debug ("considering %p, with qh_link %x\n" , cur, cur->qh_link);if (NEXT_QH (cur) == queue->first) {
@@ -1208,6 +1210,11 @@ destroy_int_queue(struct usb_device *dev, struct int_queue *queue) goto out; } cur =NEXT_QH (cur); +if (get_timer (0 ) > timeout) { +printf ("Timeout destroying interrupt endpoint queue\n" ); + result =-1 ; +break ; + } }if (periodic_schedules >0 )
@@ -1229,6 +1236,8 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, {void *backbuffer;struct int_queue *queue; +unsigned long timeout; +int result =0 ;debug ("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d" , dev, pipe, buffer, length, interval);
@@ -1253,8 +1262,13 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, queue =create_int_queue (dev, pipe,1 , length, buffer);/* TODO: pick some useful timeout rule */ + timeout =get_timer (0 ) +USB_TIMEOUT_MS (pipe);while ((backbuffer =poll_int_queue (dev, queue)) ==NULL ) - ; +if (get_timer (0 ) > timeout) { +printf ("Timeout poll on interrupt endpoint\n" ); + result =-1 ; +break ; + }if (backbuffer != buffer) { debug("got wrong buffer back (%x instead of %x)\n",
@@ -1266,5 +1280,5 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,return -1 ;/* everything worked out fine */ -return 0 ; +return result; }
Signature · 1 line
1.7.7.3
PATCH 6/11 usb: ehci: Add timeout on interrupt endpoint operations
Dear Simon Glass,
Quoted 9 lines
From: Vincent Palatin <[email protected]>
Ensure we cannot get stuck in the keyboard scanning if something wrong happens (USB device unplugged or fatal I/O error)
Signed-off-by Vincent Palatin <[email protected]>Signed-off-by Simon Glass <[email protected]>---
I like it. Let's use errno.h and rebase on top of u-boot-usb.git ... I just pushed it.
Best regards,
Marek Vasut
PATCH 6/11 usb: ehci: Add timeout on interrupt endpoint operations
Hi Marek,
Quoted 7 lines · Marek Vasut
Dear Simon Glass,
Quoted 5 lines
From: Vincent Palatin <[email protected]>
Ensure we cannot get stuck in the keyboard scanning if something wrong happens (USB device unplugged or fatal I/O error)
Quoted 7 lines
Quoted 4 lines
Signed-off-by Vincent Palatin <[email protected]>Signed-off-by Simon Glass <[email protected]>---
I like it. Let's use
errno.hand rebase on top of u-boot-usb.git ... I just pushed it.
OK I have had a crack at that and will resend.
Regards,
Simon
Quoted 3 lines
Best regards,
Marek Vasut
PATCH 7/11 usb: usbeth: smsc95xx: remove EEPROM loaded check
In reply to Simon GlassFrom: Michael Spang <[email protected]>
[port of Linux kernel commit bcd218be5aeb by Steve Glendinning]
The eeprom read & write commands currently check the E2P_CMD_LOADED_ bit is set before allowing any operations. This prevents any reading or writing unless a correctly programmed EEPROM is installed.
--- drivers/usb/eth/smsc95xx.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-)
drivers/usb/eth/smsc95xx.c +0 -4
@@ -265,10 +265,6 @@ static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) do { smsc95xx_read_reg(dev, E2P_CMD, &val); - if (!(val & E2P_CMD_LOADED_)) { - debug("No EEPROM present\n"); - return -1; - } if (!(val & E2P_CMD_BUSY_)) return 0; udelay(40);
Signature · 1 line
1.7.7.3
PATCH 7/11 usb: usbeth: smsc95xx: remove EEPROM loaded check
Dear Simon Glass,
Quoted 10 lines
From: Michael Spang <[email protected]>
[port of Linux kernel commit
bcd218be5aebby Steve Glendinning]The eeprom read & write commands currently check the
E2P_CMD_LOADED_bit is set before allowing any operations. This prevents any reading or writing unless a correctly programmed EEPROM is installed.Signed-off-by Michael Spang <[email protected]>Signed-off-by Simon Glass <[email protected]>
Quoted 19 lines
--- drivers/usb/eth/smsc95xx.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-)drivers/usb/eth/smsc95xx.c +0
-4@@ -265,10 +265,6 @@ static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) do {smsc95xx_read_reg (dev,E2P_CMD , &val); -if (!(val &E2P_CMD_LOADED_ )) { -debug ("No EEPROM present\n" ); -return -1 ; - }if (!(val &E2P_CMD_BUSY_ ))return 0 ;
Quoted 1 line
udelay(40);
Best regards,
Marek Vasut
PATCH 8/11 usb: Clean up newly allocated device nodes in case of configuration failure
In reply to Simon GlassFrom: Milind Choudhary <[email protected]>
If probe of a newly connected device fails for some reason, clean up the allocated entry in usb_dev array.
--- common/usb.c | 12 ++++++++++++ common/usb_hub.c | 2 ++ include/usb.h | 1 + 3 files changed, 15 insertions(+), 0 deletions(-)
common/usb.c +12 -0
@@ -805,6 +805,18 @@ struct usb_device *usb_alloc_new_device(void *controller)return &usb_dev[dev_index -1 ]; } +/* +* Free the newly created device node. +* Called in error cases where configuring a newly attached +* device fails for some reason. +*/ +void usb_free_device (void ) +{ + dev_index--; +USB_PRINTF ("Freeing device node: %d\n" , dev_index); +memset (&usb_dev[dev_index],0 ,sizeof (struct usb_device )); + usb_dev[dev_index].devnum =-1 ; +}/* * By the time we get here, the device has gotten a new device ID
common/usb_hub.c +2 -0
@@ -259,6 +259,8 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port)/* Run it through the hoops (find a driver, etc) */ if (usb_new_device (usb)) {/* Woops, disable the port */ +usb_free_device (); + dev->children[port] =NULL ;USB_HUB_PRINTF ("hub: disabling port %d\n" , port +1 );usb_clear_port_feature (dev, port +1 ,USB_PORT_FEAT_ENABLE ); }
include/usb.h +1 -0
@@ -392,5 +392,6 @@ int hub_port_reset(struct usb_device *dev, int port,struct usb_device *usb_alloc_new_device (void *controller);int usb_new_device (struct usb_device *dev); +void usb_free_device (void );#endif /*_USB_H_ */
Signature · 1 line
1.7.7.3
Marek Vasut
AppliedPATCH 8/11 usb: Clean up newly allocated device nodes in case of configuration failure
Dear Simon Glass,
Quoted 4 lines
From: Milind Choudhary <[email protected]>
If probe of a newly connected device fails for some reason, clean up the allocated entry in
usb_devarray.
Applied, thanks
Quoted 49 lines
Signed-off-by Milind Choudhary <[email protected]>Signed-off-by Simon Glass <[email protected]>--- common/usb.c | 12 ++++++++++++ common/usb_hub.c | 2 ++ include/usb.h | 1 + 3 files changed, 15 insertions(+), 0 deletions(-)common/usb.c +12
-0@@ -805,6 +805,18 @@ struct usb_device *usb_alloc_new_device(void *controller) return &usb_dev[dev_index - 1]; } +/* +* Free the newly created device node. +* Called in error cases where configuring a newly attached +* device fails for some reason. +*/ +void usb_free_device (void ) +{ + dev_index--; +USB_PRINTF ("Freeing device node: %d\n" , dev_index); +memset (&usb_dev[dev_index],0 ,sizeof (struct usb_device )); + usb_dev[dev_index].devnum =-1 ; +}/* * By the time we get here, the device has gotten a new device ID common/usb_hub.c +2
-0@@ -259,6 +259,8 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Run it through the hoops (find a driver, etc) */if (usb_new_device (usb)) {/* Woops, disable the port */ +usb_free_device (); + dev->children[port] =NULL ;USB_HUB_PRINTF ("hub: disabling port %d\n" , port +1 );usb_clear_port_feature (dev, port +1 ,USB_PORT_FEAT_ENABLE ); }include/usb.h +0
-0
include/usb.h int hub_port_reset(struct usb_device *dev, int port, · line 397
Quoted 6 lines
include/usb.h +1
-0@@ -392,5 +392,6 @@ int hub_port_reset(struct usb_device *dev, int port,struct usb_device *usb_alloc_new_device (void *controller);int usb_new_device (struct usb_device *dev); +void usb_free_device (void );#endif /*_USB_H_ */
Best regards,
Marek Vasut
PATCH 9/11 usb: properly detect empty mass storage media reader
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
When a USB card reader is empty, it will return "Not Ready - medium not present" as Key Code Qualifier. In that situation, it's useless waiting for the full timeout since the result won't change until the user inserts a card.
--- common/usb_storage.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
common/usb_storage.c +10 -0
@@ -970,6 +970,16 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss)return 0 ; }usb_request_sense (srb, ss); +/* +* Check the Key Code Qualifier, if it matches +* "Not Ready - medium not present" +* (the sense Key equals 0x2 and the ASC is 0x3a) +* return immediately as the medium being absent won't change +* unless there is a user action. +*/ +if ((srb->sense_buf[2 ] ==0x02 ) && + (srb->sense_buf[12 ] ==0x3a )) +return -1 ;mdelay (100 ); }while (retries--);
Signature · 1 line
1.7.7.3
Marek Vasut
AppliedPATCH 9/11 usb: properly detect empty mass storage media reader
Dear Simon Glass,
Quoted 6 lines
From: Vincent Palatin <[email protected]>
When a USB card reader is empty, it will return "Not Ready - medium not present" as Key Code Qualifier. In that situation, it's useless waiting for the full timeout since the result won't change until the user inserts a card.
Applied, thanks!
Quoted 17 lines
Signed-off-by Vincent Palatin <[email protected]>Signed-off-by Vadim Bendebury <[email protected]>Signed-off-by Simon Glass <[email protected]>--- common/usb_storage.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)common/usb_storage.c +2
-0@@ -970,6 +970,16 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss) return 0; }usb_request_sense (srb, ss); +/* +* Check the Key Code Qualifier, if it matches
common/usb_storage.c static int usb_test_unit_ready(ccb *srb, struct · line 984
Quoted 10 lines
common/usb_storage.c +8
-0+* "Not Ready - medium not present" +* (the sense Key equals 0x2 and the ASC is 0x3a) +* return immediately as the medium being absent won't change +* unless there is a user action. +*/ +if ((srb->sense_buf[2 ] ==0x02 ) && + (srb->sense_buf[12 ] ==0x3a )) +return -1 ;mdelay (100 ); }while (retries--);
Best regards,
Marek Vasut
PATCH 10/11 usb: Add multiple controllers support for EHCI PCI
In reply to Simon GlassFrom: Vincent Palatin <[email protected]>
Use the ability to have several active EHCI controller on a system in the PCI EHCI controller implementation.
--- drivers/usb/host/ehci-pci.c | 24 +++++++++++++++--------- 1 files changed, 15 insertions(+), 9 deletions(-)
drivers/usb/host/ehci-pci.c +15 -9
@@ -33,7 +33,7 @@ static struct pci_device_id ehci_pci_ids[] = { {0, 0} };#else -static pci_dev_t ehci_find_class (void ) +static pci_dev_t ehci_find_class (int index) {int bus;int devnum;
@@ -53,7 +53,7 @@ static pci_dev_t ehci_find_class(void) bdf += PCI_BDF(0, 0, 1)) {pci_read_config_dword (bdf,PCI_CLASS_REVISION , &class); -if (class >>8 ==0x0c0320 ) +if ((class >>8 ==0x0c0320 ) && !index--)return bdf; } }
@@ -66,34 +66,40 @@ static pci_dev_t ehci_find_class(void)* Create the appropriate control structures to manage * a new EHCI host controller. */ -int ehci_hcd_init (int index,struct ehci_hccr **hccr,struct ehci_hcor **hcor) +int ehci_hcd_init (int index,struct ehci_hccr **ret_hccr, +struct ehci_hcor **ret_hcor) {pci_dev_t pdev;uint32_t cmd; +struct ehci_hccr *hccr; +struct ehci_hcor *hcor;#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE );#else - pdev =ehci_find_class (); + pdev =ehci_find_class (index);#endif if (pdev ==-1 ) {printf ("EHCI host controller not found\n" );return -1 ; } - *hccr = (struct ehci_hccr *)pci_map_bar (pdev, + hccr = (struct ehci_hccr *)pci_map_bar (pdev,PCI_BASE_ADDRESS_0 ,PCI_REGION_MEM ); - *hcor = (struct ehci_hcor *)((uint32_t ) *hccr + -HC_LENGTH (ehci_readl (&(*hccr)->cr_capbase))); + hcor = (struct ehci_hcor *)((uint32_t ) hccr + +HC_LENGTH (ehci_readl (&hccr->cr_capbase)));debug ("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n" , - (uint32_t )*hccr, (uint32_t )*hcor, - (uint32_t )HC_LENGTH (ehci_readl (&(*hccr)->cr_capbase))); + (uint32_t )hccr, (uint32_t )hcor, + (uint32_t )HC_LENGTH (ehci_readl (&hccr->cr_capbase)));/* enable busmaster */ pci_read_config_dword (pdev,PCI_COMMAND , &cmd); cmd |=PCI_COMMAND_MASTER ;pci_write_config_dword (pdev,PCI_COMMAND , cmd); + + *ret_hccr = hccr; + *ret_hcor = hcor;return 0 ; }
Signature · 1 line
1.7.7.3
PATCH 11/11 x86: Enable USB features for coreboot
In reply to Simon GlassEnable PCI EHCI, storage, keyboard and Ethernet for USB.
--- include/configs/coreboot.h | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-)
include/configs/coreboot.h +17 -0
@@ -267,6 +267,23 @@*/ #define CONFIG_PCI +/*----------------------------------------------------------------------- +* USB configuration +*/ +#define CONFIG_USB_EHCI +#define CONFIG_USB_EHCI_PCI +#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 12 +#define CONFIG_USB_MAX_CONTROLLER_COUNT 2 +#define CONFIG_USB_STORAGE +#define CONFIG_USB_KEYBOARD +#define CONFIG_SYS_USB_EVENT_POLL + +#define CONFIG_USB_HOST_ETHER +#define CONFIG_USB_ETHER_ASIX +#define CONFIG_USB_ETHER_SMSC95XX + +#define CONFIG_CMD_USB +#define CONFIG_EXTRA_ENV_SETTINGS \ CONFIG_STD_DEVICES_SETTINGS
Signature · 1 line
1.7.7.3