Hm! Can you dump the config space when this happens, just locally?
I'd like to see what the device id and sub ids are. (That'll tell me if the thing hit a power-on bug, which there has actually been a reset power-on "bug" in atheros hardware since.. well, forever.) -adrian On 17 February 2015 at 21:53, Warner Losh <[email protected]> wrote: > Author: imp > Date: Wed Feb 18 05:53:04 2015 > New Revision: 278936 > URL: https://svnweb.freebsd.org/changeset/base/278936 > > Log: > On my Lenovo T400, a Atheros 2413 has a problem powering up > sometimes. It will power up wrong and identify itself badly: > > cardbus0: <network, ethernet> at device 0.0 (no driver attached) > cardbus0: <simple comms, UART> at device 0.1 (no driver attached) > cardbus0: <old, non-VGA display device> at device 0.2 (no driver attached) > cardbus0: <old, non-VGA display device> at device 0.3 (no driver attached) > cardbus0: <old, non-VGA display device> at device 0.4 (no driver attached) > cardbus0: <old, non-VGA display device> at device 0.5 (no driver attached) > cardbus0: <old, non-VGA display device> at device 0.6 (no driver attached) > cardbus0: <old, non-VGA display device> at device 0.7 (no driver attached) > > All the higher numbered functions (.2 and above) have a config space > of all 0's. This smells a bit like a special debug mode, but the > current atheros driver doesn't cope. It is unclear if this card is > just a flake, or if we're doing something wrong in the power-up > sequence. > > Put a work around into the code that tests for this rather unusual > condition. If we power a CardBus device up, and the device says it is > multi-function, and any of the functions have a 0 device ID, try the > power-up sequence again. > > Modified: > head/sys/dev/cardbus/cardbus.c > head/sys/dev/pccbb/pccbb.c > > Modified: head/sys/dev/cardbus/cardbus.c > ============================================================================== > --- head/sys/dev/cardbus/cardbus.c Wed Feb 18 05:20:52 2015 > (r278935) > +++ head/sys/dev/cardbus/cardbus.c Wed Feb 18 05:53:04 2015 > (r278936) > @@ -122,6 +122,7 @@ cardbus_detach(device_t cbdev) > cardbus_detach_card(cbdev); > #ifdef PCI_RES_BUS > sc = device_get_softc(cbdev); > + device_printf(cbdev, "Freeing up the allocatd bus\n"); > (void)bus_release_resource(cbdev, PCI_RES_BUS, 0, sc->sc_bus); > #endif > return (0); > @@ -180,6 +181,7 @@ cardbus_attach_card(device_t cbdev) > > sc = device_get_softc(cbdev); > cardbus_detach_card(cbdev); /* detach existing cards */ > + POWER_DISABLE_SOCKET(brdev, cbdev); /* Turn the socket off first */ > POWER_ENABLE_SOCKET(brdev, cbdev); > domain = pcib_get_domain(cbdev); > bus = pcib_get_bus(cbdev); > > Modified: head/sys/dev/pccbb/pccbb.c > ============================================================================== > --- head/sys/dev/pccbb/pccbb.c Wed Feb 18 05:20:52 2015 (r278935) > +++ head/sys/dev/pccbb/pccbb.c Wed Feb 18 05:53:04 2015 (r278936) > @@ -155,7 +155,7 @@ SYSCTL_INT(_hw_cbb, OID_AUTO, debug, CTL > static void cbb_insert(struct cbb_softc *sc); > static void cbb_removal(struct cbb_softc *sc); > static uint32_t cbb_detect_voltage(device_t brdev); > -static void cbb_cardbus_reset_power(device_t brdev, device_t child, int > on); > +static int cbb_cardbus_reset_power(device_t brdev, device_t child, int > on); > static int cbb_cardbus_io_open(device_t brdev, int win, uint32_t start, > uint32_t end); > static int cbb_cardbus_mem_open(device_t brdev, int win, > @@ -958,12 +958,12 @@ cbb_do_power(device_t brdev) > /* CardBus power functions */ > /************************************************************************/ > > -static void > +static int > cbb_cardbus_reset_power(device_t brdev, device_t child, int on) > { > struct cbb_softc *sc = device_get_softc(brdev); > - uint32_t b; > - int delay, count; > + uint32_t b, h; > + int delay, count, zero_seen, func; > > /* > * Asserting reset for 20ms is necessary for most bridges. For some > @@ -1002,30 +1002,61 @@ cbb_cardbus_reset_power(device_t brdev, > 0xfffffffful && --count >= 0); > if (count < 0) > device_printf(brdev, "Warning: Bus reset timeout\n"); > + > + /* > + * Some cards (so far just an atheros card I have) seem to > + * come out of reset in a funky state. They report they are > + * multi-function cards, but have nonsense for some of the > + * higher functions. So if the card claims to be MFDEV, and > + * any of the higher functions' ID is 0, then we've hit the > + * bug and we'll try again. > + */ > + h = PCIB_READ_CONFIG(brdev, b, 0, 0, PCIR_HDRTYPE, 1); > + if ((h & PCIM_MFDEV) == 0) > + return 0; > + zero_seen = 0; > + for (func = 1; func < 8; func++) { > + h = PCIB_READ_CONFIG(brdev, b, 0, func, > + PCIR_DEVVENDOR, 4); > + if (h == 0) > + zero_seen++; > + } > + if (!zero_seen) > + return 0; > + return (EINVAL); > } > + return 0; > +} > + > +static int > +cbb_cardbus_power_disable_socket(device_t brdev, device_t child) > +{ > + cbb_power(brdev, CARD_OFF); > + cbb_cardbus_reset_power(brdev, child, 0); > + return (0); > } > > static int > cbb_cardbus_power_enable_socket(device_t brdev, device_t child) > { > struct cbb_softc *sc = device_get_softc(brdev); > - int err; > + int err, count; > > if (!CBB_CARD_PRESENT(cbb_get(sc, CBB_SOCKET_STATE))) > return (ENODEV); > > - err = cbb_do_power(brdev); > - if (err) > - return (err); > - cbb_cardbus_reset_power(brdev, child, 1); > - return (0); > -} > - > -static int > -cbb_cardbus_power_disable_socket(device_t brdev, device_t child) > -{ > - cbb_power(brdev, CARD_OFF); > - cbb_cardbus_reset_power(brdev, child, 0); > + count = 10; > + do { > + err = cbb_do_power(brdev); > + if (err) > + return (err); > + err = cbb_cardbus_reset_power(brdev, child, 1); > + if (err) { > + device_printf(brdev, "Reset failed, trying again.\n"); > + cbb_cardbus_power_disable_socket(brdev, child); > + pause("cbbErr1", hz / 10); /* wait 100ms */ > + } > + } while (err != 0 && count-- > 0); > return (0); > } > > _______________________________________________ [email protected] mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "[email protected]"
