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

Cache object: 528476496b96f46fd118fc7324917b74


[ 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.