svn commit: r278936 - in head/sys/dev: cardbus pccbb

Adrian Chadd adrian at freebsd.org
Wed Feb 18 06:26:55 UTC 2015


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 <imp at freebsd.org> 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);
>  }
>
>


More information about the svn-src-all mailing list