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/pci/pci_compat.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) 1997, Stefan Esser <se@freebsd.org>
    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 unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  *
   28  */
   29 
   30 #include "pci.h"
   31 #if NPCI > 0
   32 
   33 /* for compatibility to FreeBSD-2.2 version of PCI code */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/malloc.h>
   38 #include <sys/linker_set.h>
   39 
   40 #include <vm/vm.h>
   41 #include <vm/pmap.h>
   42 #include <sys/interrupt.h>
   43 
   44 #include <pci/pcireg.h>
   45 #include <pci/pcivar.h>
   46 
   47 #ifdef RESOURCE_CHECK
   48 #include <sys/drvresource.h>
   49 #endif
   50 
   51 #ifdef APIC_IO
   52 #include <machine/smp.h>
   53 #endif
   54 
   55 #ifdef PCI_COMPAT
   56 
   57 /* ------------------------------------------------------------------------- */
   58 
   59 static int
   60 pci_mapno(pcicfgregs *cfg, int reg)
   61 {
   62         int i, nummaps;
   63         pcimap *map;
   64 
   65         nummaps = cfg->nummaps;
   66         map = cfg->map;
   67 
   68         for (i = 0; i < nummaps; i++)
   69                 if (map[i].reg == reg)
   70                         return (i);
   71         return (-1);
   72 }
   73 
   74 static int
   75 pci_porten(pcicfgregs *cfg)
   76 {
   77         return ((cfg->cmdreg & PCIM_CMD_PORTEN) != 0);
   78 }
   79 
   80 static int
   81 pci_isportmap(pcicfgregs *cfg, int map)
   82 
   83 {
   84         return ((unsigned)map < cfg->nummaps 
   85                 && (cfg->map[map].type & PCI_MAPPORT) != 0);
   86 }
   87 
   88 static int
   89 pci_memen(pcicfgregs *cfg)
   90 {
   91         return ((cfg->cmdreg & PCIM_CMD_MEMEN) != 0);
   92 }
   93 
   94 static int
   95 pci_ismemmap(pcicfgregs *cfg, int map)
   96 {
   97         return ((unsigned)map < cfg->nummaps 
   98                 && (cfg->map[map].type & PCI_MAPMEM) != 0);
   99 }
  100 
  101 /* ------------------------------------------------------------------------- */
  102 
  103 u_long
  104 pci_conf_read(pcici_t tag, u_long reg)
  105 {
  106         return (pci_cfgread(tag, reg, 4));
  107 }
  108 
  109 void
  110 pci_conf_write(pcici_t tag, u_long reg, u_long data)
  111 {
  112         pci_cfgwrite(tag, reg, data, 4);
  113 }
  114 
  115 int pci_map_port(pcici_t cfg, u_long reg, pci_port_t* pa)
  116 {
  117         int map;
  118 
  119         map = pci_mapno(cfg, reg);
  120         if (pci_porten(cfg) && pci_isportmap(cfg, map)) {
  121                 u_int32_t iobase;
  122                 u_int32_t iosize;
  123 
  124                 iobase = cfg->map[map].base;
  125                 iosize = 1 << cfg->map[map].ln2size;
  126 #ifdef RESOURCE_CHECK
  127                 if (resource_claim(cfg, REST_PORT, RESF_NONE, 
  128                                    iobase, iobase + iosize -1) == 0)
  129 #endif /* RESOURCE_CHECK */
  130                 {
  131                         *pa = iobase;
  132                         return (1);
  133                 }
  134         }
  135         return (0);
  136 }
  137 
  138 int pci_map_mem(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
  139 {
  140         int map;
  141 
  142         map = pci_mapno(cfg, reg);
  143         if (pci_memen(cfg) && pci_ismemmap(cfg, map)) {
  144                 u_int32_t paddr;
  145                 u_int32_t psize;
  146 
  147                 paddr = cfg->map[map].base;
  148                 psize = 1 << cfg->map[map].ln2size;
  149 #ifdef RESOURCE_CHECK
  150                 if (resource_claim(cfg, REST_MEM, RESF_NONE, 
  151                                    paddr, paddr + psize -1) == 0)
  152 #endif /* RESOURCE_CHECK */
  153                 {
  154                         u_int32_t poffs;
  155                         vm_offset_t vaddr;
  156 
  157                         poffs = paddr - trunc_page(paddr);
  158 #ifdef __i386__
  159                         vaddr = (vm_offset_t)pmap_mapdev(paddr-poffs, psize+poffs);
  160 #endif
  161 #ifdef __alpha__
  162                         vaddr = paddr-poffs;
  163 #endif
  164                         if (vaddr != NULL) {
  165                                 vaddr += poffs;
  166                                 *va = vaddr;
  167                                 *pa = paddr;
  168                                 return (1);
  169                         }
  170                 }
  171         }
  172         return (0);
  173 }
  174 
  175 int 
  176 pci_map_dense(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
  177 {
  178         if(pci_map_mem(cfg, reg, va, pa)){
  179 #ifdef __alpha__
  180                 vm_offset_t dense;
  181 
  182                 if(dense = pci_cvt_to_dense(*pa)){
  183                         *pa = dense;
  184                         *va = ALPHA_PHYS_TO_K0SEG(*pa);
  185                         return (1);
  186                 }
  187 #endif
  188 #ifdef __i386__
  189                 return(1);
  190 #endif
  191         }
  192         return (0);
  193 }
  194 
  195 int 
  196 pci_map_bwx(pcici_t cfg, u_long reg, vm_offset_t* va, vm_offset_t* pa)
  197 {
  198         if(pci_map_mem(cfg, reg, va, pa)){
  199 #ifdef __alpha__
  200                 vm_offset_t bwx;
  201 
  202                 if(bwx = pci_cvt_to_bwx(*pa)){
  203                         *pa = bwx;
  204                         *va = ALPHA_PHYS_TO_K0SEG(*pa);
  205                         return (1);
  206                 }
  207 #endif
  208 #ifdef __i386__
  209                 return(1);
  210 #endif
  211         }
  212         return (0);
  213 }
  214 
  215 int
  216 pci_map_int(pcici_t cfg, pci_inthand_t *handler, void *arg, intrmask_t *maskptr)
  217 {
  218         return (pci_map_int_right(cfg, handler, arg, maskptr, 0));
  219 }
  220 
  221 int
  222 pci_map_int_right(pcici_t cfg, pci_inthand_t *handler, void *arg,
  223                   intrmask_t *maskptr, u_int flags)
  224 {
  225         int error;
  226 #ifdef APIC_IO
  227         int nextpin, muxcnt;
  228 #endif
  229         if (cfg->intpin != 0) {
  230                 int irq = cfg->intline;
  231                 void *dev_instance = (void *)-1; /* XXX use cfg->devdata  */
  232                 void *idesc;
  233 
  234                 idesc = intr_create(dev_instance, irq, handler, arg, maskptr,
  235                                     flags);
  236                 error = intr_connect(idesc);
  237                 if (error != 0)
  238                         return 0;
  239 #ifdef APIC_IO
  240                 nextpin = next_apic_irq(irq);
  241                 
  242                 if (nextpin < 0)
  243                         return 1;
  244 
  245                 /* 
  246                  * Attempt handling of some broken mp tables.
  247                  *
  248                  * It's OK to yell (since the mp tables are broken).
  249                  * 
  250                  * Hanging in the boot is not OK
  251                  */
  252 
  253                 muxcnt = 2;
  254                 nextpin = next_apic_irq(nextpin);
  255                 while (muxcnt < 5 && nextpin >= 0) {
  256                         muxcnt++;
  257                         nextpin = next_apic_irq(nextpin);
  258                 }
  259                 if (muxcnt >= 5) {
  260                         printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n");
  261                         return 0;
  262                 }
  263                 
  264                 printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt);
  265 
  266                 nextpin = next_apic_irq(irq);
  267                 while (nextpin >= 0) {
  268                         idesc = intr_create(dev_instance, nextpin, handler,
  269                                             arg, maskptr, flags);
  270                         error = intr_connect(idesc);
  271                         if (error != 0)
  272                                 return 0;
  273                         printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq);
  274                         nextpin = next_apic_irq(nextpin);
  275                 }
  276 #endif
  277         }
  278         return (1);
  279 }
  280 
  281 int
  282 pci_unmap_int(pcici_t cfg)
  283 {
  284         return (0); /* not supported, yet, since cfg doesn't know about idesc */
  285 }
  286 
  287 pcici_t
  288 pci_get_parent_from_tag(pcici_t tag)
  289 {
  290         return (pcici_t)pci_devlist_get_parent(tag);
  291 }
  292 
  293 int
  294 pci_get_bus_from_tag(pcici_t tag)
  295 {
  296         return tag->bus;
  297 }
  298 
  299 /* ------------------------------------------------------------------------- */
  300 
  301 /*
  302  * Preliminary support for "wired" PCI devices.
  303  * This code supports currently only devices on PCI bus 0, since the
  304  * mapping from PCI BIOS bus numbers to configuration file bus numbers 
  305  * is not yet maintained, whenever a PCI to PCI bridge is found.
  306  * The "bus" field of "pciwirecfg" correlates an PCI bus with the bridge 
  307  * it is attached to. The "biosbus" field is to be updated for each bus,
  308  * whose bridge is probed. An entry with bus != 0 and biosbus == 0 is
  309  * invalid and will be skipped in the search for a wired unit, but not
  310  * in the test for a free unit number.
  311  */
  312 
  313 typedef struct {
  314         char            *name;
  315         int             unit;
  316         u_int8_t        bus;
  317         u_int8_t        slot;
  318         u_int8_t        func;
  319         u_int8_t        biosbus;
  320 } pciwirecfg;
  321 
  322 static pciwirecfg pci_wireddevs[] = {
  323         /* driver,      unit,   bus,    slot,   func,   BIOS bus */
  324 #ifdef PCI_DEBUG
  325         { "ncr",        2,      1,      4,      0,      0       },
  326         { "ed",         2,      1,      5,      0,      0       },
  327 #endif /* PCI_DEBUG */
  328         /* do not delete the end marker that follows this comment !!! */
  329         { NULL }
  330 };
  331 
  332 /* return unit number of wired device, or -1 if no match */
  333 
  334 static int
  335 pci_wiredunit(pcicfgregs *cfg, char *name)
  336 {
  337         pciwirecfg *p;
  338 
  339         p = pci_wireddevs;
  340         while (p->name != NULL) {
  341                 if (p->bus == cfg->bus
  342                     && p->slot == cfg->slot
  343                     && p->func == cfg->func
  344                     && strcmp(p->name, name) == 0)
  345                         return (p->unit);
  346                 p++;
  347         }
  348         return (-1);
  349 }
  350 
  351 /* return free unit number equal or greater to the one supplied as parameter */
  352 
  353 static int
  354 pci_freeunit(pcicfgregs *cfg, char *name, int unit)
  355 {
  356         pciwirecfg *p;
  357 
  358         p = pci_wireddevs;
  359         while (p->name != NULL) {
  360                 if (p->unit == unit && strcmp(p->name, name) == 0) {
  361                         p = pci_wireddevs;
  362                         unit++;
  363                 } else {
  364                         p++;
  365                 }
  366         }
  367         return (unit);
  368 }
  369 
  370 static const char *drvname;
  371 
  372 static const char*
  373 pci_probedrv(pcicfgregs *cfg, struct pci_device *dvp)
  374 {
  375         if (dvp && dvp->pd_probe) {
  376                 pcidi_t type = (cfg->device << 16) + cfg->vendor;
  377                 return (dvp->pd_probe(cfg, type));
  378         }
  379         return (NULL);
  380 }
  381 
  382 static struct pci_lkm *pci_lkm_head;
  383 
  384 static struct pci_device*
  385 pci_finddrv(pcicfgregs *cfg)
  386 {
  387         struct pci_device **dvpp;
  388         struct pci_device *dvp = NULL;
  389         struct pci_lkm *lkm;
  390 
  391         drvname = NULL;
  392         lkm = pci_lkm_head;
  393         while (drvname == NULL && lkm != NULL) {
  394                 dvp = lkm->dvp;
  395                 drvname = pci_probedrv(cfg, dvp);
  396                 lkm = lkm->next;
  397         }
  398 
  399         /*
  400          * it wasn't a loaded driver, look in the linked in ones
  401          */
  402         dvpp = (struct pci_device **)pcidevice_set.ls_items;
  403         while (drvname == NULL && (dvp = *dvpp++) != NULL)
  404                 drvname = pci_probedrv(cfg, dvp);
  405 
  406         /*
  407          * It wasn't one of the linked in drivers either, so try the defaults.
  408          */
  409         if (drvname == NULL) {
  410                 dvp = &chipset_device;
  411                 if ((drvname = pci_probedrv(cfg, dvp)) == NULL)
  412                         dvp = NULL;;
  413         }
  414         return (dvp);
  415 }
  416 
  417 static void
  418 pci_drvmessage(pcicfgregs *cfg, char *name, int unit)
  419 {
  420         if (drvname == NULL || *drvname == '\0')
  421                 return;
  422         printf("%s%d: <%s> rev 0x%02x", name, unit, drvname, cfg->revid);
  423         if (cfg->intpin != 0)
  424                 printf(" int %c irq %d", cfg->intpin + 'a' -1, cfg->intline);
  425         printf(" on pci%d.%d.%d\n", cfg->bus, cfg->slot, cfg->func);
  426 }
  427 
  428 
  429 void
  430 pci_drvattach(struct pci_devinfo *dinfo)
  431 {
  432         struct pci_device *dvp;
  433         pcicfgregs *cfg;
  434 
  435         cfg = &dinfo->cfg;
  436         dvp = pci_finddrv(cfg);
  437         if (dvp != NULL) {
  438                 int unit;
  439 
  440                 unit = pci_wiredunit(cfg, dvp->pd_name);
  441                 if (unit < 0) {
  442                         unit = pci_freeunit(cfg, dvp->pd_name, *dvp->pd_count);
  443                         *dvp->pd_count = unit +1;
  444                 }
  445                 pci_drvmessage(cfg, dvp->pd_name, unit);
  446                 if (dvp->pd_attach)
  447                         dvp->pd_attach(cfg, unit);
  448 
  449                 dinfo->device = dvp;
  450 
  451                 /*
  452                  * XXX KDM for some devices, dvp->pd_name winds up NULL.
  453                  * I haven't investigated enough to figure out why this
  454                  * would happen.
  455                  */
  456                 if (dvp->pd_name != NULL)
  457                         strncpy(dinfo->conf.pd_name, dvp->pd_name,
  458                                 sizeof(dinfo->conf.pd_name));
  459                 else
  460                         strncpy(dinfo->conf.pd_name, "????",
  461                                 sizeof(dinfo->conf.pd_name));
  462                 dinfo->conf.pd_name[sizeof(dinfo->conf.pd_name) - 1] = 0;
  463 
  464                 dinfo->conf.pd_unit = unit;
  465 
  466         }
  467 }
  468 
  469 /* ------------------------------------------------------------------------- */
  470 
  471 static void
  472 pci_rescan(void)
  473 {
  474         /* XXX do nothing, currently, soon to come ... */
  475 }
  476 
  477 int pci_register_lkm (struct pci_device *dvp, int if_revision)
  478 {
  479         struct pci_lkm *lkm;
  480 
  481         if (if_revision != 0) {
  482                 return (-1);
  483         }
  484         if (dvp == NULL || dvp->pd_probe == NULL || dvp->pd_attach == NULL) {
  485                 return (-1);
  486         }
  487         lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK);
  488         if (lkm == NULL) {
  489                 return (-1);
  490         }
  491 
  492         lkm->dvp = dvp;
  493         lkm->next = pci_lkm_head;
  494         pci_lkm_head = lkm;
  495         pci_rescan();
  496         return (0);
  497 }
  498 
  499 void
  500 pci_configure(void)
  501 {
  502         pci_probe(NULL);
  503 }
  504 
  505 /* ------------------------------------------------------------------------- */
  506 
  507 #endif /* PCI_COMPAT */
  508 #endif /* NPCI > 0 */

Cache object: 0280e7aa485c456e95506e0b4f041310


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