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