Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Sep 2017 01:09:05 -0700
From:      Mark Millard <markmi@dsl-only.net>
To:        freebsd-arm <freebsd-arm@freebsd.org>
Subject:   Part of why Pine64+ 2GB gets "uhub_attach: getting USB 2.0 HUB descriptor failed,error=USB_ERR_SHORT_XFER" (and so USB fails)
Message-ID:  <AF0AC3CE-5B33-4E28-B091-FCE9EAC87642@dsl-only.net>

next in thread | raw e-mail | index | archive | help
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=3DUSB_ERR_SHORT_XFER
device_attach: uhub0 attach returned 6
usbus0: Root HUB problem, error=3DUSB_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 =3D usbd_req_get_hub_descriptor(udev, NULL, =
&hubdesc20, 1);
                if (err) {
                        DPRINTFN(0, "getting USB 2.0 HUB descriptor =
failed,"
                            "error=3D%s\n", usbd_errstr(err));
                        goto error;
                }
                /* get number of ports */
                nports =3D 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 =3D (nports + 7 + (8 * 8)) / 8;

        req.bmRequestType =3D UT_READ_CLASS_DEVICE;
        req.bRequest =3D 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 =3D=3D (1 + 7 + (8 * 8)) / 8
i.e., len =3D=3D 9.

which eventually gets to /usr/src/sys/dev/usb/controller/ohci.c 's
ohci_roothub_exec :

. . .
        ohci_softc_t *sc =3D OHCI_BUS2SC(udev->bus);
. . .
#define C(x,y) ((x) | ((y) << 8))
. . .
        case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
                if ((value & 0xff) !=3D 0) {
                        err =3D USB_ERR_IOERROR;
                        goto done;
                }
                v =3D OREAD4(sc, OHCI_RH_DESCRIPTOR_A);

                sc->sc_hub_desc.hubd =3D ohci_hubd;
                sc->sc_hub_desc.hubd.bNbrPorts =3D 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 =3D =
OHCI_GET_POTPGT(v);
                v =3D OREAD4(sc, OHCI_RH_DESCRIPTOR_B);

                for (l =3D 0; l < sc->sc_noport; l++) {
                        if (v & 1) {
                                sc->sc_hub_desc.hubd.DeviceRemovable[l / =
8] |=3D (1 << (l % 8));
                        }
                        v >>=3D 1;
                }
                sc->sc_hub_desc.hubd.bDescLength =3D
                    8 + ((sc->sc_noport + 7) / 8);
                len =3D sc->sc_hub_desc.hubd.bDescLength;
                break;
. . .
done:
        *plength =3D len;
        *pptr =3D ptr;
        return (err);
}


Note that sc->sc_noport !=3D 1 is possible but
8 + ((1 + 7) / 8) =3D=3D 9 and so sc->sc_noport=3D=3D1
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 =3D UGETW(req->wLength);
. . .
                USB_BUS_LOCK(udev->bus);
                err =3D (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 =3D USB_ERR_SHORT_XFER;
                                goto done;
                        }
                        length =3D temp;
                }
=20
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=3D=3D0 .


As for what ofwdump reports relative to usb,
first the overall node list:

# ofwdump -a
Node 0x48:=20
  Node 0xe8: memory
  Node 0x120: cpus
    Node 0x14c: cpu@0
    Node 0x1b8: cpu@1
    Node 0x224: cpu@2
    Node 0x290: cpu@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@1c0f000
    Node 0x700: mmc@1c10000
    Node 0x804: mmc@1c11000
    Node 0x908: usb@01c19000
    Node 0xa0c: phy@01c19400
    Node 0xb54: usb@01c1b000
    Node 0xc44: usb@01c1b400
    Node 0xd24: clock@01c20000
    Node 0xde4: pinctrl@1c20800
      Node 0xed4: i2c1_pins
      Node 0xf3c: mmc0-pins
      Node 0xfc4: mmc1-pins
      Node 0x102c: mmc2-pins
      Node 0x10b4: uart0@0
      Node 0x110c: uart1_pins
      Node 0x1148: uart1_rts_cts_pins
      Node 0x118c: rmii_pins
      Node 0x1214: rgmii_pins
    Node 0x12d8: serial@1c28000
    Node 0x13bc: serial@1c28400
    Node 0x1480: serial@1c28800
    Node 0x1544: serial@1c28c00
    Node 0x1608: serial@1c29000
    Node 0x16cc: i2c@1c2ac00
    Node 0x1790: i2c@1c2b000
    Node 0x1874: i2c@1c2b400
    Node 0x1938: interrupt-controller@1c81000
    Node 0x19f8: rtc@1f00000
    Node 0x1a68: clock@1f01400
    Node 0x1b30: pinctrl@01f02c00
    Node 0x1c14: ethernet@01c30000
      Node 0x1d78: ethernet-phy@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@01c19000
Node 0x908: usb@01c19000
  compatible:
    61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 38 69 2d 61 33 33 2d=20
    6d 75 73 62 00=20
    'allwinner,sun8i-a33-musb'
  reg:
    01 c1 90 00 00 00 04 00=20
  clocks:
    00 00 00 02 00 00 00 29=20
  resets:
    00 00 00 02 00 00 00 12=20
  interrupts:
    00 00 00 00 00 00 00 47 00 00 00 04=20
  interrupt-names:
    6d 63 00=20
    'mc'
  phys:
    00 00 00 06 00 00 00 00=20
  phy-names:
    75 73 62 00=20
    'usb'
  extcon:
    00 00 00 06 00 00 00 00=20
  status:
    6f 6b 61 79 00=20
    'okay'
  dr_mode:
    68 6f 73 74 00=20
    'host'

# ofwdump -p /soc/phy@01c19400
Node 0xa0c: phy@01c19400
  compatible:
    61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 35 30 69 2d 61 36 34=20
    2d 75 73 62 2d 70 68 79 00=20
    '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=20
    00 00 00 04=20
  reg-names:
    70 68 79 5f 63 74 72 6c 00 70 6d 75 30 00 70 6d 75 31 00=20
( phy_ctrl pmu0 pmu1 )
  clocks:
    00 00 00 02 00 00 00 56 00 00 00 02 00 00 00 57=20
  clock-names:
    75 73 62 30 5f 70 68 79 00 75 73 62 31 5f 70 68 79 00=20
( usb0_phy usb1_phy )
  resets:
    00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 01=20
  reset-names:
    75 73 62 30 5f 72 65 73 65 74 00 75 73 62 31 5f 72 65 73 65=20
    74 00=20
( usb0_reset usb1_reset )
  status:
    6f 6b 61 79 00=20
    'okay'
  #phy-cells:
    00 00 00 01=20
  linux,phandle:
    00 00 00 06=20
  phandle:
    00 00 00 06

# ofwdump -p /soc/usb@01c1b000
Node 0xb54: usb@01c1b000
  compatible:
    61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 35 30 69 2d 61 36 34=20
    2d 65 68 63 69 00 67 65 6e 65 72 69 63 2d 65 68 63 69 00=20
( allwinner,sun50i-a64-ehci generic-ehci )
  reg:
    01 c1 b0 00 00 00 01 00=20
  interrupts:
    00 00 00 00 00 00 00 4a 00 00 00 04=20
  clocks:
    00 00 00 02 00 00 00 2d 00 00 00 02 00 00 00 2b 00 00 00 02=20
    00 00 00 5d=20
  resets:
    00 00 00 02 00 00 00 16 00 00 00 02 00 00 00 14=20
  phys:
    00 00 00 06 00 00 00 01=20
  phy-names:
    75 73 62 00=20
    'usb'
  status:
    6f 6b 61 79 00=20
    'okay'

# ofwdump -p /soc/usb@01c1b400
Node 0xc44: usb@01c1b400
  compatible:
    61 6c 6c 77 69 6e 6e 65 72 2c 73 75 6e 35 30 69 2d 61 36 34=20
    2d 6f 68 63 69 00 67 65 6e 65 72 69 63 2d 6f 68 63 69 00=20
( allwinner,sun50i-a64-ohci generic-ohci )
 reg:
    01 c1 b4 00 00 00 01 00=20
  interrupts:
    00 00 00 00 00 00 00 4b 00 00 00 04=20
  clocks:
    00 00 00 02 00 00 00 2d 00 00 00 02 00 00 00 5d=20
  resets:
    00 00 00 02 00 00 00 16=20
  phys:
    00 00 00 06 00 00 00 01=20
  phy-names:
    75 73 62 00=20
    'usb'
  status:
    6f 6b 61 79 00=20
    'okay'

(Not that I know what to make of it or if it
matches what is expected/required by FreeBSD.)

=3D=3D=3D
Mark Millard
markmi at dsl-only.net




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?AF0AC3CE-5B33-4E28-B091-FCE9EAC87642>