Part of why Pine64+ 2GB gets "uhub_attach: getting USB 2.0 HUB descriptor failed,error=USB_ERR_SHORT_XFER" (and so USB fails)
Mark Millard
markmi at dsl-only.net
Sun Sep 17 08:09:09 UTC 2017
For booting a Pine64+ 2GB it reports:
usbus0: 12Mbps Full Speed USB v1.0
ugen0.1: <Generic OHCI root HUB> at usbus0
uhub0: <Generic OHCI root HUB, class 9/0, rev 1.00/1.00, addr 1> on usbus0
uhub_attach: getting USB 2.0 HUB descriptor failed,error=USB_ERR_SHORT_XFER
device_attach: uhub0 attach returned 6
usbus0: Root HUB problem, error=USB_ERR_NO_ROOT_HUB
/usr/src/sys/dev/usb/usb_hub.c has:
. . .
switch (udev->speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
/* assuming that there is one port */
err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1);
if (err) {
DPRINTFN(0, "getting USB 2.0 HUB descriptor failed,"
"error=%s\n", usbd_errstr(err));
goto error;
}
/* get number of ports */
nports = hubdesc20.bNbrPorts;
. . .
(The 1 in usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1)
being the assumed "one port".)
where /usr/src/sys/dev/usb/usb_request.c 's
usbd_req_get_hub_descriptor is:
usb_error_t
usbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx,
struct usb_hub_descriptor *hd, uint8_t nports)
{
struct usb_device_request req;
uint16_t len = (nports + 7 + (8 * 8)) / 8;
req.bmRequestType = UT_READ_CLASS_DEVICE;
req.bRequest = UR_GET_DESCRIPTOR;
USETW2(req.wValue, UDESC_HUB, 0);
USETW(req.wIndex, 0);
USETW(req.wLength, len);
return (usbd_do_request(udev, mtx, &req, hd));
}
Note that len == (1 + 7 + (8 * 8)) / 8
i.e., len == 9.
which eventually gets to /usr/src/sys/dev/usb/controller/ohci.c 's
ohci_roothub_exec :
. . .
ohci_softc_t *sc = OHCI_BUS2SC(udev->bus);
. . .
#define C(x,y) ((x) | ((y) << 8))
. . .
case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
if ((value & 0xff) != 0) {
err = USB_ERR_IOERROR;
goto done;
}
v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
sc->sc_hub_desc.hubd = ohci_hubd;
sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport;
USETW(sc->sc_hub_desc.hubd.wHubCharacteristics,
(v & OHCI_NPS ? UHD_PWR_NO_SWITCH :
v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL)
/* XXX overcurrent */
);
sc->sc_hub_desc.hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v);
v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B);
for (l = 0; l < sc->sc_noport; l++) {
if (v & 1) {
sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] |= (1 << (l % 8));
}
v >>= 1;
}
sc->sc_hub_desc.hubd.bDescLength =
8 + ((sc->sc_noport + 7) / 8);
len = sc->sc_hub_desc.hubd.bDescLength;
break;
. . .
done:
*plength = len;
*pptr = ptr;
return (err);
}
Note that sc->sc_noport != 1 is possible but
8 + ((1 + 7) / 8) == 9 and so sc->sc_noport==1
would match.
In the middle between is usbd_do_request which is a
macro for usbd_do_request_flags with 4 specific
final arguments. The code that gets to
ohci_roothub_exec is:
. . .
uint16_t length;
uint16_t temp;
. . .
length = UGETW(req->wLength);
. . .
USB_BUS_LOCK(udev->bus);
err = (hr_func) (udev, req, &desc, &temp);
USB_BUS_UNLOCK(udev->bus);
if (err)
goto done;
if (length > temp) {
if (!(flags & USB_SHORT_XFER_OK)) {
err = USB_ERR_SHORT_XFER;
goto done;
}
length = temp;
}
which is where the USB_ERR_SHORT_XFER comes from
as far as I can tell.
length > temp then means that:
9 > 8 + ((sc->sc_noport + 7) / 8)
which means that sc->sc_noport==0 .
As for what ofwdump reports relative to usb,
first the overall node list:
# ofwdump -a
Node 0x48:
Node 0xe8: memory
Node 0x120: cpus
Node 0x14c: cpu at 0
Node 0x1b8: cpu at 1
Node 0x224: cpu at 2
Node 0x290: cpu at 3
Node 0x300: osc24M_clk
Node 0x380: osc32k_clk
Node 0x400: internal-osc-clk
Node 0x498: psci
Node 0x4d4: timer
Node 0x53c: soc
Node 0x588: mmc at 1c0f000
Node 0x700: mmc at 1c10000
Node 0x804: mmc at 1c11000
Node 0x908: usb at 01c19000
Node 0xa0c: phy at 01c19400
Node 0xb54: usb at 01c1b000
Node 0xc44: usb at 01c1b400
Node 0xd24: clock at 01c20000
Node 0xde4: pinctrl at 1c20800
Node 0xed4: i2c1_pins
Node 0xf3c: mmc0-pins
Node 0xfc4: mmc1-pins
Node 0x102c: mmc2-pins
Node 0x10b4: uart0 at 0
Node 0x110c: uart1_pins
Node 0x1148: uart1_rts_cts_pins
Node 0x118c: rmii_pins
Node 0x1214: rgmii_pins
Node 0x12d8: serial at 1c28000
Node 0x13bc: serial at 1c28400
Node 0x1480: serial at 1c28800
Node 0x1544: serial at 1c28c00
Node 0x1608: serial at 1c29000
Node 0x16cc: i2c at 1c2ac00
Node 0x1790: i2c at 1c2b000
Node 0x1874: i2c at 1c2b400
Node 0x1938: interrupt-controller at 1c81000
Node 0x19f8: rtc at 1f00000
Node 0x1a68: clock at 1f01400
Node 0x1b30: pinctrl at 01f02c00
Node 0x1c14: ethernet at 01c30000
Node 0x1d78: ethernet-phy at 1
Node 0x1dc8: aliases
Node 0x1e1c: chosen
Node 0x1e8c: vcc3v3
Note: Later lines starting with "( " and ending
with " )" are my hand translation to text when
multiple '\0' bytes were present, with a space
for each separating '\0' byte.
Now the usb specific nodes:
# ofwdump -p /soc/usb at 01c19000
Node 0x908: usb at 01c19000
compatible:
61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 38 69 2d 61 33 33 2d
6d 75 73 62 00
'allwinner,sun8i-a33-musb'
reg:
01 c1 90 00 00 00 04 00
clocks:
00 00 00 02 00 00 00 29
resets:
00 00 00 02 00 00 00 12
interrupts:
00 00 00 00 00 00 00 47 00 00 00 04
interrupt-names:
6d 63 00
'mc'
phys:
00 00 00 06 00 00 00 00
phy-names:
75 73 62 00
'usb'
extcon:
00 00 00 06 00 00 00 00
status:
6f 6b 61 79 00
'okay'
dr_mode:
68 6f 73 74 00
'host'
# ofwdump -p /soc/phy at 01c19400
Node 0xa0c: phy at 01c19400
compatible:
61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 35 30 69 2d 61 36 34
2d 75 73 62 2d 70 68 79 00
'allwinner,sun50i-a64-usb-phy'
reg:
01 c1 94 00 00 00 00 14 01 c1 a8 00 00 00 00 04 01 c1 b8 00
00 00 00 04
reg-names:
70 68 79 5f 63 74 72 6c 00 70 6d 75 30 00 70 6d 75 31 00
( phy_ctrl pmu0 pmu1 )
clocks:
00 00 00 02 00 00 00 56 00 00 00 02 00 00 00 57
clock-names:
75 73 62 30 5f 70 68 79 00 75 73 62 31 5f 70 68 79 00
( usb0_phy usb1_phy )
resets:
00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 01
reset-names:
75 73 62 30 5f 72 65 73 65 74 00 75 73 62 31 5f 72 65 73 65
74 00
( usb0_reset usb1_reset )
status:
6f 6b 61 79 00
'okay'
#phy-cells:
00 00 00 01
linux,phandle:
00 00 00 06
phandle:
00 00 00 06
# ofwdump -p /soc/usb at 01c1b000
Node 0xb54: usb at 01c1b000
compatible:
61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 35 30 69 2d 61 36 34
2d 65 68 63 69 00 67 65 6e 65 72 69 63 2d 65 68 63 69 00
( allwinner,sun50i-a64-ehci generic-ehci )
reg:
01 c1 b0 00 00 00 01 00
interrupts:
00 00 00 00 00 00 00 4a 00 00 00 04
clocks:
00 00 00 02 00 00 00 2d 00 00 00 02 00 00 00 2b 00 00 00 02
00 00 00 5d
resets:
00 00 00 02 00 00 00 16 00 00 00 02 00 00 00 14
phys:
00 00 00 06 00 00 00 01
phy-names:
75 73 62 00
'usb'
status:
6f 6b 61 79 00
'okay'
# ofwdump -p /soc/usb at 01c1b400
Node 0xc44: usb at 01c1b400
compatible:
61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 35 30 69 2d 61 36 34
2d 6f 68 63 69 00 67 65 6e 65 72 69 63 2d 6f 68 63 69 00
( allwinner,sun50i-a64-ohci generic-ohci )
reg:
01 c1 b4 00 00 00 01 00
interrupts:
00 00 00 00 00 00 00 4b 00 00 00 04
clocks:
00 00 00 02 00 00 00 2d 00 00 00 02 00 00 00 5d
resets:
00 00 00 02 00 00 00 16
phys:
00 00 00 06 00 00 00 01
phy-names:
75 73 62 00
'usb'
status:
6f 6b 61 79 00
'okay'
(Not that I know what to make of it or if it
matches what is expected/required by FreeBSD.)
===
Mark Millard
markmi at dsl-only.net
More information about the freebsd-arm
mailing list