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]"

Reply via email to