The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cardbus/cardbus_cis.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000,2001 Jonathan Chen.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions, and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in
   13  *    the documentation and/or other materials provided with the
   14  *    distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/5.3/sys/dev/cardbus/cardbus_cis.c 128131 2004-04-11 19:22:25Z imp $");
   32 
   33 /*
   34  * CIS Handling for the Cardbus Bus
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 
   42 #include <sys/bus.h>
   43 #include <machine/bus.h>
   44 #include <machine/resource.h>
   45 #include <sys/rman.h>
   46 #include <sys/endian.h>
   47 
   48 #include <sys/pciio.h>
   49 #include <dev/pci/pcivar.h>
   50 #include <dev/pci/pcireg.h>
   51 
   52 #include <dev/pccard/pccardvar.h>
   53 #include <dev/pccard/pccard_cis.h>
   54 
   55 #include <dev/cardbus/cardbusreg.h>
   56 #include <dev/cardbus/cardbusvar.h>
   57 #include <dev/cardbus/cardbus_cis.h>
   58 
   59 extern int cardbus_cis_debug;
   60 
   61 #define DPRINTF(a) if (cardbus_cis_debug) printf a
   62 #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
   63 
   64 struct tuple_callbacks;
   65 
   66 typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
   67                  uint8_t *tupledata, uint32_t start, uint32_t *off,
   68                  struct tuple_callbacks *info);
   69 
   70 struct tuple_callbacks {
   71         int     id;
   72         char    *name;
   73         tuple_cb *func;
   74 };
   75 
   76 static int decode_tuple_generic(device_t cbdev, device_t child, int id,
   77     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   78     struct tuple_callbacks *info);
   79 static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
   80     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   81     struct tuple_callbacks *info);
   82 static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
   83     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   84     struct tuple_callbacks *info);
   85 static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
   86     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   87     struct tuple_callbacks *info);
   88 static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
   89     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   90     struct tuple_callbacks *info);
   91 static int decode_tuple_funce(device_t cbdev, device_t child, int id,
   92     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   93     struct tuple_callbacks *info);
   94 static int decode_tuple_bar(device_t cbdev, device_t child, int id,
   95     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   96     struct tuple_callbacks *info);
   97 static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
   98     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   99     struct tuple_callbacks *info);
  100 static int decode_tuple_end(device_t cbdev, device_t child, int id,
  101     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  102     struct tuple_callbacks *info);
  103 
  104 static int      cardbus_read_tuple_conf(device_t cbdev, device_t child,
  105                     uint32_t start, uint32_t *off, int *tupleid, int *len,
  106                     uint8_t *tupledata);
  107 static int      cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
  108                     uint32_t start, uint32_t *off, int *tupleid, int *len,
  109                     uint8_t *tupledata);
  110 static int      cardbus_read_tuple(device_t cbdev, device_t child,
  111                     struct resource *res, uint32_t start, uint32_t *off,
  112                     int *tupleid, int *len, uint8_t *tupledata);
  113 static void     cardbus_read_tuple_finish(device_t cbdev, device_t child,
  114                     int rid, struct resource *res);
  115 static struct resource  *cardbus_read_tuple_init(device_t cbdev, device_t child,
  116                     uint32_t *start, int *rid);
  117 static int      decode_tuple(device_t cbdev, device_t child, int tupleid,
  118                     int len, uint8_t *tupledata, uint32_t start,
  119                     uint32_t *off, struct tuple_callbacks *callbacks);
  120 static int      cardbus_parse_cis(device_t cbdev, device_t child,
  121                     struct tuple_callbacks *callbacks);
  122 static int      barsort(const void *a, const void *b);
  123 static int      cardbus_alloc_resources(device_t cbdev, device_t child);
  124 static void     cardbus_add_map(device_t cbdev, device_t child, int reg);
  125 static void     cardbus_pickup_maps(device_t cbdev, device_t child);
  126 
  127 
  128 #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
  129 
  130 static char *funcnames[] = {
  131         "Multi-Functioned",
  132         "Memory",
  133         "Serial Port",
  134         "Parallel Port",
  135         "Fixed Disk",
  136         "Video Adaptor",
  137         "Network Adaptor",
  138         "AIMS",
  139         "SCSI",
  140         "Security"
  141 };
  142 
  143 /*
  144  * Handler functions for various CIS tuples
  145  */
  146 
  147 static int
  148 decode_tuple_generic(device_t cbdev, device_t child, int id,
  149     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  150     struct tuple_callbacks *info)
  151 {
  152         int i;
  153 
  154         if (cardbus_cis_debug) {
  155                 if (info)
  156                         printf("TUPLE: %s [%d]:", info->name, len);
  157                 else
  158                         printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
  159 
  160                 for (i = 0; i < len; i++) {
  161                         if (i % 0x10 == 0 && len > 0x10)
  162                                 printf("\n       0x%02x:", i);
  163                         printf(" %02x", tupledata[i]);
  164                 }
  165                 printf("\n");
  166         }
  167         return (0);
  168 }
  169 
  170 static int
  171 decode_tuple_linktarget(device_t cbdev, device_t child, int id,
  172     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  173     struct tuple_callbacks *info)
  174 {
  175         int i;
  176 
  177         if (cardbus_cis_debug) {
  178                 printf("TUPLE: %s [%d]:", info->name, len);
  179 
  180                 for (i = 0; i < len; i++) {
  181                         if (i % 0x10 == 0 && len > 0x10)
  182                                 printf("\n       0x%02x:", i);
  183                         printf(" %02x", tupledata[i]);
  184                 }
  185                 printf("\n");
  186         }
  187         if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
  188             tupledata[2] != 'S') {
  189                 printf("Invalid data for CIS Link Target!\n");
  190                 decode_tuple_generic(cbdev, child, id, len, tupledata,
  191                     start, off, info);
  192                 return (EINVAL);
  193         }
  194         return (0);
  195 }
  196 
  197 static int
  198 decode_tuple_vers_1(device_t cbdev, device_t child, int id,
  199     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  200     struct tuple_callbacks *info)
  201 {
  202         int i;
  203 
  204         if (cardbus_cis_debug) {
  205                 printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
  206                 printf("Product name: ");
  207                 for (i = 2; i < len; i++) {
  208                         if (tupledata[i] == '\0')
  209                                 printf(" | ");
  210                         else if (tupledata[i] == 0xff)
  211                                 break;
  212                         else
  213                                 printf("%c", tupledata[i]);
  214                 }
  215                 printf("\n");
  216         }
  217         return (0);
  218 }
  219 
  220 static int
  221 decode_tuple_funcid(device_t cbdev, device_t child, int id,
  222     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  223     struct tuple_callbacks *info)
  224 {
  225         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  226         int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
  227         int i;
  228 
  229         if (cardbus_cis_debug) {
  230                 printf("Functions: ");
  231                 for (i = 0; i < len; i++) {
  232                         if (tupledata[i] < numnames)
  233                                 printf("%s", funcnames[tupledata[i]]);
  234                         else
  235                                 printf("Unknown(%d)", tupledata[i]);
  236                         if (i < len-1)
  237                                 printf(", ");
  238                 }
  239                 printf("\n");
  240         }
  241         if (len > 0)
  242                 dinfo->funcid = tupledata[0];           /* use first in list */
  243         return (0);
  244 }
  245 
  246 static int
  247 decode_tuple_manfid(device_t cbdev, device_t child, int id,
  248     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  249     struct tuple_callbacks *info)
  250 {
  251         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  252         int i;
  253 
  254         if (cardbus_cis_debug) {
  255                 printf("Manufacturer ID: ");
  256                 for (i = 0; i < len; i++)
  257                         printf("%02x", tupledata[i]);
  258                 printf("\n");
  259         }
  260 
  261         if (len == 5) {
  262                 dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
  263                 dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
  264         }
  265         return (0);
  266 }
  267 
  268 static int
  269 decode_tuple_funce(device_t cbdev, device_t child, int id,
  270     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  271     struct tuple_callbacks *info)
  272 {
  273         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  274         int type, i;
  275 
  276         if (cardbus_cis_debug) {
  277                 printf("Function Extension: ");
  278                 for (i = 0; i < len; i++)
  279                         printf("%02x", tupledata[i]);
  280                 printf("\n");
  281         }
  282         if (len < 2)                    /* too short */
  283                 return (0);
  284         type = tupledata[0];            /* XXX <32 always? */
  285         switch (dinfo->funcid) {
  286         case TPL_FUNC_SERIAL:
  287                 if (type == TPL_FUNCE_SER_UART) {       /* NB: len known > 1 */
  288                         dinfo->funce.sio.type = tupledata[1] & 0x1f;
  289                 }
  290                 dinfo->fepresent |= 1<<type;
  291                 break;
  292         case TPL_FUNC_LAN:
  293                 switch (type) {
  294                 case TPL_FUNCE_LAN_TECH:
  295                         dinfo->funce.lan.tech = tupledata[1];   /* XXX mask? */
  296                         break;
  297 #if 0
  298                 case TPL_FUNCE_LAN_SPEED:
  299                         for (i = 0; i < 3; i++) {
  300                                 if (dinfo->funce.lan.speed[i] == 0) {
  301                                         if (len > 4) {
  302                                                 dinfo->funce.lan.speed[i] =
  303                                                         ...;
  304                                         }
  305                                         break;
  306                                 }
  307                         }
  308                         break;
  309 #endif
  310                 case TPL_FUNCE_LAN_MEDIA:
  311                         for (i = 0; i < 4 && dinfo->funce.lan.media[i]; i++) {
  312                                 if (dinfo->funce.lan.media[i] == 0) {
  313                                         /* NB: len known > 1 */
  314                                         dinfo->funce.lan.media[i] =
  315                                                 tupledata[1];   /*XXX? mask */
  316                                         break;
  317                                 }
  318                         }
  319                         break;
  320                 case TPL_FUNCE_LAN_NID:
  321                         if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
  322                                 /* ignore, warning? */
  323                                 return (0);
  324                         }
  325                         bcopy(tupledata + 2, dinfo->funce.lan.nid,
  326                             tupledata[1]);
  327                         break;
  328                 case TPL_FUNCE_LAN_CONN:
  329                         dinfo->funce.lan.contype = tupledata[1];/*XXX mask? */
  330                         break;
  331                 }
  332                 dinfo->fepresent |= 1<<type;
  333                 break;
  334         }
  335         return (0);
  336 }
  337 
  338 static int
  339 decode_tuple_bar(device_t cbdev, device_t child, int id,
  340     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  341     struct tuple_callbacks *info)
  342 {
  343         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  344         int type;
  345         uint8_t reg;
  346         uint32_t bar, pci_bar;
  347 
  348         if (len != 6) {
  349                 device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
  350                 return (EINVAL);
  351         }
  352 
  353         reg = *tupledata;
  354         len = le32toh(*(uint32_t*)(tupledata + 2));
  355         if (reg & TPL_BAR_REG_AS) {
  356                 type = SYS_RES_IOPORT;
  357         } else {
  358                 type = SYS_RES_MEMORY;
  359         }
  360 
  361         bar = reg & TPL_BAR_REG_ASI_MASK;
  362         if (bar == 0) {
  363                 device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
  364                 return (EINVAL);        /* XXX Return an error? */
  365         } else if (bar == 7) {
  366                 /* XXX Should we try to map in Option ROMs? */
  367                 return (0);
  368         }
  369 
  370         /* Convert from BAR type to BAR offset */
  371         bar = CARDBUS_BASE0_REG + (bar - 1) * 4;
  372 
  373         if (type == SYS_RES_MEMORY) {
  374                 if (reg & TPL_BAR_REG_PREFETCHABLE)
  375                         dinfo->mprefetchable |= BARBIT(bar);
  376 #if 0
  377                 /*
  378                  * XXX: It appears from a careful reading of the spec
  379                  * that we're not supposed to honor this when the bridge
  380                  * is not on the main system bus.  PCI spec doesn't appear
  381                  * to allow for memory ranges not listed in the bridge's
  382                  * decode range to be decoded.  The PC Card spec seems to
  383                  * indicate that this should only be done on x86 based
  384                  * machines, which seems to imply that on non-x86 machines
  385                  * the adddresses can be anywhere.  This further implies that
  386                  * since the hardware can do it on non-x86 machines, it should
  387                  * be able to do it on x86 machines.  Therefore, we can and
  388                  * should ignore this hint.  Furthermore, the PC Card spec
  389                  * recommends always allocating memory above 1MB, contradicting
  390                  * the other part of the PC Card spec.
  391                  *
  392                  * NetBSD ignores this bit, but it also ignores the
  393                  * prefetchable bit too, so that's not an indication of
  394                  * correctness.
  395                  */
  396                 if (reg & TPL_BAR_REG_BELOW1MB)
  397                         dinfo->mbelow1mb |= BARBIT(bar);
  398 #endif
  399         }
  400 
  401         /*
  402          * Sanity check the BAR length reported in the CIS with the length
  403          * encoded in the PCI BAR.  The latter seems to be more reliable.
  404          * XXX - This probably belongs elsewhere.
  405          */
  406         pci_write_config(child, bar, 0xffffffff, 4);
  407         pci_bar = pci_read_config(child, bar, 4);
  408         if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) {
  409                 if (type == SYS_RES_MEMORY) {
  410                         pci_bar &= ~0xf;
  411                 } else {
  412                         pci_bar &= ~0x3;
  413                 }
  414                 len = 1 << (ffs(pci_bar) - 1);
  415         }
  416 
  417         DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
  418             (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
  419             (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
  420             " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
  421             ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : ""));
  422 
  423         resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
  424 
  425         /*
  426          * Mark the appropriate bit in the PCI command register so that
  427          * device drivers will know which type of BARs can be used.
  428          */
  429         pci_enable_io(child, type);
  430         return (0);
  431 }
  432 
  433 static int
  434 decode_tuple_unhandled(device_t cbdev, device_t child, int id,
  435     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  436     struct tuple_callbacks *info)
  437 {
  438         /* Make this message suck less XXX */
  439         printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
  440         return (-1);
  441 }
  442 
  443 static int
  444 decode_tuple_end(device_t cbdev, device_t child, int id,
  445     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  446     struct tuple_callbacks *info)
  447 {
  448         if (cardbus_cis_debug) {
  449                 printf("CIS reading done\n");
  450         }
  451         return (0);
  452 }
  453 
  454 /*
  455  * Functions to read the a tuple from the card
  456  */
  457 
  458 static int
  459 cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
  460     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  461 {
  462         int i, j;
  463         uint32_t e;
  464         uint32_t loc;
  465 
  466         loc = start + *off;
  467 
  468         e = pci_read_config(child, loc - loc % 4, 4);
  469         for (j = loc % 4; j > 0; j--)
  470                 e >>= 8;
  471         *len = 0;
  472         for (i = loc, j = -2; j < *len; j++, i++) {
  473                 if (i % 4 == 0)
  474                         e = pci_read_config(child, i, 4);
  475                 if (j == -2)
  476                         *tupleid = 0xff & e;
  477                 else if (j == -1)
  478                         *len = 0xff & e;
  479                 else
  480                         tupledata[j] = 0xff & e;
  481                 e >>= 8;
  482         }
  483         *off += *len + 2;
  484         return (0);
  485 }
  486 
  487 static int
  488 cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
  489     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  490 {
  491         bus_space_tag_t bt;
  492         bus_space_handle_t bh;
  493         int ret;
  494 
  495         bt = rman_get_bustag(res);
  496         bh = rman_get_bushandle(res);
  497 
  498         *tupleid = bus_space_read_1(bt, bh, start + *off);
  499         *len = bus_space_read_1(bt, bh, start + *off + 1);
  500         bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
  501         ret = 0;
  502         *off += *len + 2;
  503         return (ret);
  504 }
  505 
  506 static int
  507 cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
  508     uint32_t start, uint32_t *off, int *tupleid, int *len,
  509     uint8_t *tupledata)
  510 {
  511         if (res == (struct resource*)~0UL) {
  512                 return (cardbus_read_tuple_conf(cbdev, child, start, off,
  513                     tupleid, len, tupledata));
  514         } else {
  515                 return (cardbus_read_tuple_mem(cbdev, res, start, off,
  516                     tupleid, len, tupledata));
  517         }
  518 }
  519 
  520 static void
  521 cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
  522     struct resource *res)
  523 {
  524         if (res != (struct resource*)~0UL) {
  525                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  526                 pci_write_config(child, rid, 0, 4);
  527                 PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
  528         }
  529 }
  530 
  531 static struct resource *
  532 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
  533     int *rid)
  534 {
  535         uint32_t testval;
  536         uint32_t size;
  537         struct resource *res;
  538 
  539         switch (CARDBUS_CIS_SPACE(*start)) {
  540         case CARDBUS_CIS_ASI_TUPLE:
  541                 /* CIS in PCI config space need no initialization */
  542                 return ((struct resource*)~0UL);
  543         case CARDBUS_CIS_ASI_BAR0:
  544         case CARDBUS_CIS_ASI_BAR1:
  545         case CARDBUS_CIS_ASI_BAR2:
  546         case CARDBUS_CIS_ASI_BAR3:
  547         case CARDBUS_CIS_ASI_BAR4:
  548         case CARDBUS_CIS_ASI_BAR5:
  549                 *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
  550                 break;
  551         case CARDBUS_CIS_ASI_ROM:
  552                 *rid = CARDBUS_ROM_REG;
  553 #if 0
  554                 /*
  555                  * This mask doesn't contain the bit that actually enables
  556                  * the Option ROM.
  557                  */
  558                 pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
  559 #endif
  560                 break;
  561         default:
  562                 device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
  563                     CARDBUS_CIS_SPACE(*start));
  564                 return (NULL);
  565         }
  566 
  567         /* figure out how much space we need */
  568         pci_write_config(child, *rid, 0xffffffff, 4);
  569         testval = pci_read_config(child, *rid, 4);
  570 
  571         /*
  572          * This bit has a different meaning depending if we are dealing
  573          * with a normal BAR or an Option ROM BAR.
  574          */
  575         if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
  576                 device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
  577                 return (NULL);
  578         }
  579 
  580         size = CARDBUS_MAPREG_MEM_SIZE(testval);
  581         /* XXX Is this some kind of hack? */
  582         if (size < 4096)
  583                 size = 4096;
  584         /* allocate the memory space to read CIS */
  585         res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
  586             rman_make_alignment_flags(size) | RF_ACTIVE);
  587         if (res == NULL) {
  588                 device_printf(cbdev, "Unable to allocate resource "
  589                     "to read CIS.\n");
  590                 return (NULL);
  591         }
  592         pci_write_config(child, *rid,
  593             rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)?
  594                 CARDBUS_ROM_ENABLE : 0),
  595             4);
  596         PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
  597 
  598         /* Flip to the right ROM image if CIS is in ROM */
  599         if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
  600                 bus_space_tag_t bt;
  601                 bus_space_handle_t bh;
  602                 uint32_t imagesize;
  603                 uint32_t imagebase = 0;
  604                 uint32_t pcidata;
  605                 uint16_t romsig;
  606                 int romnum = 0;
  607                 int imagenum;
  608 
  609                 bt = rman_get_bustag(res);
  610                 bh = rman_get_bushandle(res);
  611 
  612                 imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
  613                 for (romnum = 0;; romnum++) {
  614                         romsig = bus_space_read_2(bt, bh,
  615                             imagebase + CARDBUS_EXROM_SIGNATURE);
  616                         if (romsig != 0xaa55) {
  617                                 device_printf(cbdev, "Bad header in rom %d: "
  618                                     "[%x] %04x\n", romnum, imagebase +
  619                                     CARDBUS_EXROM_SIGNATURE, romsig);
  620                                 bus_release_resource(cbdev, SYS_RES_MEMORY,
  621                                     *rid, res);
  622                                 *rid = 0;
  623                                 return (NULL);
  624                         }
  625 
  626                         /*
  627                          * If this was the Option ROM image that we were
  628                          * looking for, then we are done.
  629                          */
  630                         if (romnum == imagenum)
  631                                 break;
  632 
  633                         /* Find out where the next Option ROM image is */
  634                         pcidata = imagebase + bus_space_read_2(bt, bh,
  635                             imagebase + CARDBUS_EXROM_DATA_PTR);
  636                         imagesize = bus_space_read_2(bt, bh,
  637                             pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
  638 
  639                         if (imagesize == 0) {
  640                                 /*
  641                                  * XXX some ROMs seem to have this as zero,
  642                                  * can we assume this means 1 block?
  643                                  */
  644                                 device_printf(cbdev, "Warning, size of Option "
  645                                     "ROM image %d is 0 bytes, assuming 512 "
  646                                     "bytes.\n", romnum);
  647                                 imagesize = 1;
  648                         }
  649 
  650                         /* Image size is in 512 byte units */
  651                         imagesize <<= 9;
  652 
  653                         if ((bus_space_read_1(bt, bh, pcidata +
  654                             CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
  655                                 device_printf(cbdev, "Cannot find CIS in "
  656                                     "Option ROM\n");
  657                                 bus_release_resource(cbdev, SYS_RES_MEMORY,
  658                                     *rid, res);
  659                                 *rid = 0;
  660                                 return (NULL);
  661                         }
  662                         imagebase += imagesize;
  663                 }
  664                 *start = imagebase + CARDBUS_CIS_ADDR(*start);
  665         } else {
  666                 *start = CARDBUS_CIS_ADDR(*start);
  667         }
  668 
  669         return (res);
  670 }
  671 
  672 /*
  673  * Dispatch the right handler function per tuple
  674  */
  675 
  676 static int
  677 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
  678     uint8_t *tupledata, uint32_t start, uint32_t *off,
  679     struct tuple_callbacks *callbacks)
  680 {
  681         int i;
  682         for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
  683                 if (tupleid == callbacks[i].id)
  684                         return (callbacks[i].func(cbdev, child, tupleid, len,
  685                             tupledata, start, off, &callbacks[i]));
  686         }
  687         return (callbacks[i].func(cbdev, child, tupleid, len,
  688             tupledata, start, off, NULL));
  689 }
  690 
  691 static int
  692 cardbus_parse_cis(device_t cbdev, device_t child,
  693     struct tuple_callbacks *callbacks)
  694 {
  695         uint8_t tupledata[MAXTUPLESIZE];
  696         int tupleid;
  697         int len;
  698         int expect_linktarget;
  699         uint32_t start, off;
  700         struct resource *res;
  701         int rid;
  702 
  703         bzero(tupledata, MAXTUPLESIZE);
  704         expect_linktarget = TRUE;
  705         if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0)
  706                 return (ENXIO);
  707         off = 0;
  708         res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
  709         if (res == NULL)
  710                 return (ENXIO);
  711 
  712         do {
  713                 if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
  714                     &tupleid, &len, tupledata)) {
  715                         device_printf(cbdev, "Failed to read CIS.\n");
  716                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  717                         return (ENXIO);
  718                 }
  719 
  720                 if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
  721                         device_printf(cbdev, "Expecting link target, got 0x%x\n",
  722                             tupleid);
  723                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  724                         return (EINVAL);
  725                 }
  726                 expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
  727                     tupledata, start, &off, callbacks);
  728                 if (expect_linktarget != 0) {
  729                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  730                         return (expect_linktarget);
  731                 }
  732         } while (tupleid != CISTPL_END);
  733         cardbus_read_tuple_finish(cbdev, child, rid, res);
  734         return (0);
  735 }
  736 
  737 static void
  738 cardbus_do_res(struct resource_list_entry *rle, device_t child, uint32_t start)
  739 {
  740         rle->start = start;
  741         rle->end = start + rle->count - 1;
  742         pci_write_config(child, rle->rid, rle->start, 4);
  743 }
  744 
  745 static int
  746 barsort(const void *a, const void *b)
  747 {
  748         return ((*(const struct resource_list_entry * const *)b)->count -
  749             (*(const struct resource_list_entry * const *)a)->count);
  750 }
  751 
  752 static int
  753 cardbus_alloc_resources(device_t cbdev, device_t child)
  754 {
  755         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  756         int count;
  757         struct resource_list_entry *rle;
  758         struct resource_list_entry **barlist;
  759         int tmp;
  760         uint32_t mem_psize = 0, mem_nsize = 0, io_size = 0;
  761         struct resource *res;
  762         uint32_t start,end;
  763         int rid, flags;
  764 
  765         count = 0;
  766         SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
  767                 count++;
  768         }
  769         if (count == 0)
  770                 return (0);
  771         barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF,
  772             M_WAITOK);
  773         count = 0;
  774         SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
  775                 barlist[count] = rle;
  776                 if (rle->type == SYS_RES_IOPORT) {
  777                         io_size += rle->count;
  778                 } else if (rle->type == SYS_RES_MEMORY) {
  779                         if (dinfo->mprefetchable & BARBIT(rle->rid))
  780                                 mem_psize += rle->count;
  781                         else
  782                                 mem_nsize += rle->count;
  783                 }
  784                 count++;
  785         }
  786 
  787         /*
  788          * We want to allocate the largest resource first, so that our
  789          * allocated memory is packed.
  790          */
  791         qsort(barlist, count, sizeof(struct resource_list_entry*), barsort);
  792 
  793         /* Allocate prefetchable memory */
  794         flags = 0;
  795         for (tmp = 0; tmp < count; tmp++) {
  796                 rle = barlist[tmp];
  797                 if (rle->res == NULL &&
  798                     rle->type == SYS_RES_MEMORY &&
  799                     dinfo->mprefetchable & BARBIT(rle->rid)) {
  800                         flags = rman_make_alignment_flags(rle->count);
  801                         break;
  802                 }
  803         }
  804         if (flags > 0) { /* If any prefetchable memory is requested... */
  805                 /*
  806                  * First we allocate one big space for all resources of this
  807                  * type.  We do this because our parent, pccbb, needs to open
  808                  * a window to forward all addresses within the window, and
  809                  * it would be best if nobody else has resources allocated
  810                  * within the window.
  811                  * (XXX: Perhaps there might be a better way to do this?)
  812                  */
  813                 rid = 0;
  814                 res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
  815                     (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL,
  816                     mem_psize, flags);
  817                 if (res == NULL) {
  818                         device_printf(cbdev,
  819                             "Can't get memory for prefetch mem\n");
  820                         free(barlist, M_DEVBUF);
  821                         return (EIO);
  822                 }
  823                 start = rman_get_start(res);
  824                 end = rman_get_end(res);
  825                 DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end));
  826                 /*
  827                  * Now that we know the region is free, release it and hand it
  828                  * out piece by piece.
  829                  */
  830                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  831                 for (tmp = 0; tmp < count; tmp++) {
  832                         rle = barlist[tmp];
  833                         if (rle->type == SYS_RES_MEMORY &&
  834                             dinfo->mprefetchable & BARBIT(rle->rid)) {
  835                                 cardbus_do_res(rle, child, start);
  836                                 start += rle->count;
  837                         }
  838                 }
  839         }
  840 
  841         /* Allocate non-prefetchable memory */
  842         flags = 0;
  843         for (tmp = 0; tmp < count; tmp++) {
  844                 rle = barlist[tmp];
  845                 if (rle->type == SYS_RES_MEMORY &&
  846                     (dinfo->mprefetchable & BARBIT(rle->rid)) == 0) {
  847                         flags = rman_make_alignment_flags(rle->count);
  848                         break;
  849                 }
  850         }
  851         if (flags > 0) { /* If any non-prefetchable memory is requested... */
  852                 /*
  853                  * First we allocate one big space for all resources of this
  854                  * type.  We do this because our parent, pccbb, needs to open
  855                  * a window to forward all addresses within the window, and
  856                  * it would be best if nobody else has resources allocated
  857                  * within the window.
  858                  * (XXX: Perhaps there might be a better way to do this?)
  859                  */
  860                 rid = 0;
  861                 res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
  862                     ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL,
  863                     mem_nsize, flags);
  864                 if (res == NULL) {
  865                         device_printf(cbdev,
  866                             "Can't get memory for non-prefetch mem\n");
  867                         free(barlist, M_DEVBUF);
  868                         return (EIO);
  869                 }
  870                 start = rman_get_start(res);
  871                 end = rman_get_end(res);
  872                 DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n",
  873                     start, end));
  874                 /*
  875                  * Now that we know the region is free, release it and hand it
  876                  * out piece by piece.
  877                  */
  878                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  879                 for (tmp = 0; tmp < count; tmp++) {
  880                         rle = barlist[tmp];
  881                         if (rle->type == SYS_RES_MEMORY &&
  882                             (dinfo->mprefetchable & BARBIT(rle->rid)) == 0) {
  883                                 cardbus_do_res(rle, child, start);
  884                                 start += rle->count;
  885                         }
  886                 }
  887         }
  888 
  889         /* Allocate IO ports */
  890         flags = 0;
  891         for (tmp = 0; tmp < count; tmp++) {
  892                 rle = barlist[tmp];
  893                 if (rle->type == SYS_RES_IOPORT) {
  894                         flags = rman_make_alignment_flags(rle->count);
  895                         break;
  896                 }
  897         }
  898         if (flags > 0) { /* If any IO port is requested... */
  899                 /*
  900                  * First we allocate one big space for all resources of this
  901                  * type.  We do this because our parent, pccbb, needs to open
  902                  * a window to forward all addresses within the window, and
  903                  * it would be best if nobody else has resources allocated
  904                  * within the window.
  905                  * (XXX: Perhaps there might be a better way to do this?)
  906                  */
  907                 rid = 0;
  908                 res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0,
  909                     (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags);
  910                 if (res == NULL) {
  911                         device_printf(cbdev,
  912                             "Can't get memory for IO ports\n");
  913                         free(barlist, M_DEVBUF);
  914                         return (EIO);
  915                 }
  916                 start = rman_get_start(res);
  917                 end = rman_get_end(res);
  918                 DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end));
  919                 /*
  920                  * Now that we know the region is free, release it and hand it
  921                  * out piece by piece.
  922                  */
  923                 bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res);
  924                 for (tmp = 0; tmp < count; tmp++) {
  925                         rle = barlist[tmp];
  926                         if (rle->type == SYS_RES_IOPORT) {
  927                                 cardbus_do_res(rle, child, start);
  928                                 start += rle->count;
  929                         }
  930                 }
  931         }
  932 
  933         /* Allocate IRQ */
  934         rid = 0;
  935         res = bus_alloc_resource_any(cbdev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
  936         if (res == NULL) {
  937                 device_printf(cbdev, "Can't get memory for irq\n");
  938                 free(barlist, M_DEVBUF);
  939                 return (EIO);
  940         }
  941         start = rman_get_start(res);
  942         end = rman_get_end(res);
  943         bus_release_resource(cbdev, SYS_RES_IRQ, rid, res);
  944         resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid, start, end,
  945             1);
  946         dinfo->pci.cfg.intline = rman_get_start(res);
  947         pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1);
  948 
  949         free(barlist, M_DEVBUF);
  950         return (0);
  951 }
  952 
  953 /*
  954  * Adding a memory/io resource (sans CIS)
  955  */
  956 
  957 static void
  958 cardbus_add_map(device_t cbdev, device_t child, int reg)
  959 {
  960         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  961         struct resource_list_entry *rle;
  962         uint32_t size;
  963         uint32_t testval;
  964         int type;
  965 
  966         SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
  967                 if (rle->rid == reg)
  968                         return;
  969         }
  970 
  971         if (reg == CARDBUS_ROM_REG)
  972                 testval = CARDBUS_ROM_ADDRMASK;
  973         else
  974                 testval = ~0;
  975 
  976         pci_write_config(child, reg, testval, 4);
  977         testval = pci_read_config(child, reg, 4);
  978 
  979         if (testval == ~0 || testval == 0)
  980                 return;
  981 
  982         if ((testval & 1) == 0)
  983                 type = SYS_RES_MEMORY;
  984         else
  985                 type = SYS_RES_IOPORT;
  986 
  987         size = CARDBUS_MAPREG_MEM_SIZE(testval);
  988         device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n",
  989             reg, size);
  990         resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size);
  991 }
  992 
  993 static void
  994 cardbus_pickup_maps(device_t cbdev, device_t child)
  995 {
  996         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  997         int reg;
  998 
  999         /*
 1000          * Try to pick up any resources that was not specified in CIS.
 1001          * Maybe this isn't any longer necessary now that we have fixed
 1002          * CIS parsing and we should filter things here?  XXX
 1003          */
 1004         for (reg = 0; reg < dinfo->pci.cfg.nummaps; reg++)
 1005                 cardbus_add_map(cbdev, child, PCIR_BAR(reg));
 1006 }
 1007 
 1008 int
 1009 cardbus_do_cis(device_t cbdev, device_t child)
 1010 {
 1011         int ret;
 1012         struct tuple_callbacks init_callbacks[] = {
 1013                 MAKETUPLE(LONGLINK_CB,          unhandled),
 1014                 MAKETUPLE(INDIRECT,             unhandled),
 1015                 MAKETUPLE(LONGLINK_MFC,         unhandled),
 1016                 MAKETUPLE(BAR,                  bar),
 1017                 MAKETUPLE(LONGLINK_A,           unhandled),
 1018                 MAKETUPLE(LONGLINK_C,           unhandled),
 1019                 MAKETUPLE(LINKTARGET,           linktarget),
 1020                 MAKETUPLE(VERS_1,               vers_1),
 1021                 MAKETUPLE(MANFID,               manfid),
 1022                 MAKETUPLE(FUNCID,               funcid),
 1023                 MAKETUPLE(FUNCE,                funce),
 1024                 MAKETUPLE(END,                  end),
 1025                 MAKETUPLE(GENERIC,              generic),
 1026         };
 1027 
 1028         ret = cardbus_parse_cis(cbdev, child, init_callbacks);
 1029         if (ret < 0)
 1030                 return (ret);
 1031         cardbus_pickup_maps(cbdev, child);
 1032         return (cardbus_alloc_resources(cbdev, child));
 1033 }

Cache object: 66489b1af72dfcf90f2ac56f3b3f802c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.