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/i386/isa/pcibus.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 **
    3 ** $FreeBSD: src/sys/i386/isa/pcibus.c,v 1.27.2.3 1999/09/05 08:13:17 peter Exp $
    4 **
    5 **  pci bus subroutines for i386 architecture.
    6 **
    7 **  FreeBSD
    8 **
    9 **-------------------------------------------------------------------------
   10 **
   11 ** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
   12 **
   13 ** Redistribution and use in source and binary forms, with or without
   14 ** modification, are permitted provided that the following conditions
   15 ** are met:
   16 ** 1. Redistributions of source code must retain the above copyright
   17 **    notice, this list of conditions and the following disclaimer.
   18 ** 2. Redistributions in binary form must reproduce the above copyright
   19 **    notice, this list of conditions and the following disclaimer in the
   20 **    documentation and/or other materials provided with the distribution.
   21 ** 3. The name of the author may not be used to endorse or promote products
   22 **    derived from this software without specific prior written permission.
   23 **
   24 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   25 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   28 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   29 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   30 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   31 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   32 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   33 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34 **
   35 ***************************************************************************
   36 */
   37 
   38 #include "vector.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 
   44 #include <i386/isa/icu.h>
   45 #include <i386/isa/isa_device.h>
   46 
   47 #include <pci/pcivar.h>
   48 #include <pci/pcireg.h>
   49 #include <pci/pcibus.h>
   50 
   51 /*-----------------------------------------------------------------
   52 **
   53 **      The following functions are provided by the pci bios.
   54 **      They are used only by the pci configuration.
   55 **
   56 **      pcibus_setup():
   57 **              Probes for a pci system.
   58 **              Sets pci_maxdevice and pci_mechanism.
   59 **
   60 **      pcibus_tag():
   61 **              Creates a handle for pci configuration space access.
   62 **              This handle is given to the read/write functions.
   63 **
   64 **      pcibus_ftag():
   65 **              Creates a modified handle.
   66 **
   67 **      pcibus_read():
   68 **              Read a long word from the pci configuration space.
   69 **              Requires a tag (from pcitag) and the register
   70 **              number (should be a long word alligned one).
   71 **
   72 **      pcibus_write():
   73 **              Writes a long word to the pci configuration space.
   74 **              Requires a tag (from pcitag), the register number
   75 **              (should be a long word alligned one), and a value.
   76 **
   77 **      pcibus_regirq():
   78 **              Register an interupt handler for a pci device.
   79 **              Requires a tag (from pcitag), the register number
   80 **              (should be a long word alligned one), and a value.
   81 **
   82 **-----------------------------------------------------------------
   83 */
   84 
   85 static int
   86 pcibus_check (void);
   87 
   88 static void
   89 pcibus_setup (void);
   90 
   91 static pcici_t
   92 pcibus_tag (u_char bus, u_char device, u_char func);
   93 
   94 static pcici_t
   95 pcibus_ftag (pcici_t tag, u_char func);
   96 
   97 static int
   98 pcibus_bus (pcici_t tag);
   99 
  100 static int
  101 pcibus_device (pcici_t tag);
  102 
  103 static int
  104 pcibus_function (pcici_t tag);
  105 
  106 static u_long
  107 pcibus_read (pcici_t tag, u_long reg);
  108 
  109 static void
  110 pcibus_write (pcici_t tag, u_long reg, u_long data);
  111 
  112 static int
  113 pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned* maskptr);
  114 
  115 static int
  116 pcibus_ihandler_detach (int irq, inthand2_t *func);
  117 
  118 static int
  119 pcibus_imask_include (int irq, unsigned* maskptr);
  120 
  121 static int
  122 pcibus_imask_exclude (int irq, unsigned* maskptr);
  123 
  124 static struct pcibus i386pci = {
  125         "pci",
  126         pcibus_setup,
  127         pcibus_tag,
  128         pcibus_ftag,
  129         pcibus_bus,
  130         pcibus_device,
  131         pcibus_function,
  132         pcibus_read,
  133         pcibus_write,
  134         pcibus_ihandler_attach,
  135         pcibus_ihandler_detach,
  136         pcibus_imask_include,
  137         pcibus_imask_exclude,
  138 };
  139 
  140 /*
  141 **      Announce structure to generic driver
  142 */
  143 
  144 DATA_SET (pcibus_set, i386pci);
  145 
  146 /*--------------------------------------------------------------------
  147 **
  148 **      Determine configuration mode
  149 **
  150 **--------------------------------------------------------------------
  151 */
  152 
  153 
  154 #define CONF1_ADDR_PORT    0x0cf8
  155 #define CONF1_DATA_PORT    0x0cfc
  156 
  157 #define CONF1_ENABLE       0x80000000ul
  158 #define CONF1_ENABLE_CHK   0x80000000ul
  159 #define CONF1_ENABLE_MSK   0x7ff00000ul
  160 #define CONF1_ENABLE_CHK1  0xff000001ul
  161 #define CONF1_ENABLE_MSK1  0x80000001ul
  162 #define CONF1_ENABLE_RES1  0x80000000ul
  163 
  164 #define CONF2_ENABLE_PORT  0x0cf8
  165 #ifdef PC98
  166 #define CONF2_FORWARD_PORT 0x0cf9
  167 #else
  168 #define CONF2_FORWARD_PORT 0x0cfa
  169 #endif
  170 
  171 #define CONF2_ENABLE_CHK   0x0e
  172 #define CONF2_ENABLE_RES   0x0e
  173 
  174 static int
  175 pcibus_check (void)
  176 {
  177         u_char device;
  178 
  179         if (bootverbose) printf ("pcibus_check:\tdevice ");
  180 
  181         for (device = 0; device < pci_maxdevice; device++) {
  182                 unsigned long id;
  183                 if (bootverbose) 
  184                         printf ("%d ", device);
  185                 id = pcibus_read (pcibus_tag (0,device,0), 0);
  186                 if (id && id != 0xfffffffful) {
  187                         if (bootverbose) printf ("is there (id=%08lx)\n", id);
  188                         return 1;
  189                 }
  190         }
  191         if (bootverbose) 
  192                 printf ("-- nothing found\n");
  193         return 0;
  194 }
  195 
  196 static void
  197 pcibus_setup (void)
  198 {
  199         unsigned long mode1res,oldval1;
  200         unsigned char mode2res,oldval2;
  201 
  202         oldval1 = inl (CONF1_ADDR_PORT);
  203 
  204         if (bootverbose) {
  205                 printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", oldval1);
  206         }
  207 
  208         /*---------------------------------------
  209         **      Assume configuration mechanism 1 for now ...
  210         **---------------------------------------
  211         */
  212 
  213         if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
  214 
  215                 pci_mechanism = 1;
  216                 pci_maxdevice = 32;
  217 
  218                 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  219                 outb (CONF1_ADDR_PORT +3, 0);
  220                 mode1res = inl (CONF1_ADDR_PORT);
  221                 outl (CONF1_ADDR_PORT, oldval1);
  222 
  223                 if (bootverbose)
  224                     printf ("pcibus_setup(1a):\tmode1res=0x%08lx (0x%08lx)\n", 
  225                             mode1res, CONF1_ENABLE_CHK);
  226 
  227                 if (mode1res) {
  228                         if (pcibus_check()) 
  229                                 return;
  230                 };
  231 
  232                 outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  233                 mode1res = inl(CONF1_ADDR_PORT);
  234                 outl (CONF1_ADDR_PORT, oldval1);
  235 
  236                 if (bootverbose)
  237                     printf ("pcibus_setup(1b):\tmode1res=0x%08lx (0x%08lx)\n", 
  238                             mode1res, CONF1_ENABLE_CHK1);
  239 
  240                 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  241                         if (pcibus_check()) 
  242                                 return;
  243                 };
  244         }
  245 
  246         /*---------------------------------------
  247         **      Try configuration mechanism 2 ...
  248         **---------------------------------------
  249         */
  250 
  251         oldval2 = inb (CONF2_ENABLE_PORT);
  252 
  253         if (bootverbose) {
  254                 printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", oldval2);
  255         }
  256 
  257         if ((oldval2 & 0xf0) == 0) {
  258 
  259                 pci_mechanism = 2;
  260                 pci_maxdevice = 16;
  261                         
  262                 outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  263                 mode2res = inb(CONF2_ENABLE_PORT);
  264                 outb (CONF2_ENABLE_PORT, oldval2);
  265 
  266                 if (bootverbose)
  267                     printf ("pcibus_setup(2a):\tmode2res=0x%02x (0x%02x)\n", 
  268                             mode2res, CONF2_ENABLE_CHK);
  269 
  270                 if (mode2res == CONF2_ENABLE_RES) {
  271                     if (bootverbose)
  272                         printf ("pcibus_setup(2a):\tnow trying mechanism 2\n");
  273 
  274                         if (pcibus_check()) 
  275                                 return;
  276                 }
  277         }
  278 
  279         /*---------------------------------------
  280         **      No PCI bus host bridge found
  281         **---------------------------------------
  282         */
  283 
  284         pci_mechanism = 0;
  285         pci_maxdevice = 0;
  286 }
  287 
  288 /*--------------------------------------------------------------------
  289 **
  290 **      Build a pcitag from bus, device and function number
  291 **
  292 **--------------------------------------------------------------------
  293 */
  294 
  295 static pcici_t
  296 pcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
  297 {
  298         pcici_t tag;
  299 
  300         tag.cfg1 = 0;
  301         if (func   >=  8) return tag;
  302 
  303         switch (pci_mechanism) {
  304 
  305         case 1:
  306                 if (device < 32) {
  307                         tag.cfg1 = CONF1_ENABLE
  308                                 | (((u_long) bus   ) << 16ul)
  309                                 | (((u_long) device) << 11ul)
  310                                 | (((u_long) func  ) <<  8ul);
  311                 }
  312                 break;
  313         case 2:
  314                 if (device < 16) {
  315                         tag.cfg2.port    = 0xc000 | (device << 8ul);
  316                         tag.cfg2.enable  = 0xf0 | (func << 1ul);
  317                         tag.cfg2.forward = bus;
  318                 }
  319                 break;
  320         };
  321         return tag;
  322 }
  323 
  324 static pcici_t
  325 pcibus_ftag (pcici_t tag, u_char func)
  326 {
  327         switch (pci_mechanism) {
  328 
  329         case 1:
  330                 tag.cfg1 &= ~0x700ul;
  331                 tag.cfg1 |= (((u_long) func) << 8ul);
  332                 break;
  333         case 2:
  334                 tag.cfg2.enable  = 0xf0 | (func << 1ul);
  335                 break;
  336         };
  337         return tag;
  338 }
  339 
  340 static int
  341 pcibus_bus (pcici_t tag)
  342 {
  343         int bus;
  344 
  345         bus = 0;
  346         switch (pci_mechanism) {
  347         case 1:
  348                 bus = (tag.cfg1 >> 16) & 0xff;
  349                 break;
  350         case 2:
  351                 bus = tag.cfg2.forward;
  352                 break;
  353         }
  354         return (bus);
  355 }
  356 
  357 static int
  358 pcibus_device (pcici_t tag)
  359 {
  360         int device;
  361 
  362         device = 0;
  363         switch (pci_mechanism) {
  364         case 1:
  365                 device = (tag.cfg1 >> 11) & 0x1f;
  366                 break;
  367         case 2:
  368                 device = (tag.cfg2.port >> 8) & 0x3f;
  369                 break;
  370         }
  371         return (device);
  372 }
  373 
  374 static int
  375 pcibus_function (pcici_t tag)
  376 {
  377         int function;
  378 
  379         function = 0;
  380         switch (pci_mechanism) {
  381         case 1:
  382                 function = (tag.cfg1 >> 8) & 0x7;
  383                 break;
  384         case 2:
  385                 function = (tag.cfg2.enable >> 1) & 0x7;
  386                 break;
  387         }
  388         return (function);
  389 }
  390 
  391 
  392 /*--------------------------------------------------------------------
  393 **
  394 **      Read register from configuration space.
  395 **
  396 **--------------------------------------------------------------------
  397 */
  398 
  399 static u_long
  400 pcibus_read (pcici_t tag, u_long reg)
  401 {
  402         u_long addr, data = 0;
  403 
  404         if (!tag.cfg1) return (0xfffffffful);
  405 
  406         switch (pci_mechanism) {
  407 
  408         case 1:
  409                 addr = tag.cfg1 | (reg & 0xfc);
  410 #ifdef PCI_DEBUG
  411                 printf ("pci_conf_read(1): addr=%x ", addr);
  412 #endif
  413                 outl (CONF1_ADDR_PORT, addr);
  414                 data = inl (CONF1_DATA_PORT);
  415                 outl (CONF1_ADDR_PORT, 0   );
  416                 break;
  417 
  418         case 2:
  419                 addr = tag.cfg2.port | (reg & 0xfc);
  420 #ifdef PCI_DEBUG
  421                 printf ("pci_conf_read(2): addr=%x ", addr);
  422 #endif
  423                 outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
  424                 outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
  425 
  426                 data = inl ((u_short) addr);
  427 
  428                 outb (CONF2_ENABLE_PORT,  0);
  429                 outb (CONF2_FORWARD_PORT, 0);
  430                 break;
  431         };
  432 
  433 #ifdef PCI_DEBUG
  434         printf ("data=%x\n", data);
  435 #endif
  436 
  437         return (data);
  438 }
  439 
  440 /*--------------------------------------------------------------------
  441 **
  442 **      Write register into configuration space.
  443 **
  444 **--------------------------------------------------------------------
  445 */
  446 
  447 static void
  448 pcibus_write (pcici_t tag, u_long reg, u_long data)
  449 {
  450         u_long addr;
  451 
  452         if (!tag.cfg1) return;
  453 
  454         switch (pci_mechanism) {
  455 
  456         case 1:
  457                 addr = tag.cfg1 | (reg & 0xfc);
  458 #ifdef PCI_DEBUG
  459                 printf ("pci_conf_write(1): addr=%x data=%x\n",
  460                         addr, data);
  461 #endif
  462                 outl (CONF1_ADDR_PORT, addr);
  463                 outl (CONF1_DATA_PORT, data);
  464                 outl (CONF1_ADDR_PORT,   0 );
  465                 break;
  466 
  467         case 2:
  468                 addr = tag.cfg2.port | (reg & 0xfc);
  469 #ifdef PCI_DEBUG
  470                 printf ("pci_conf_write(2): addr=%x data=%x\n",
  471                         addr, data);
  472 #endif
  473                 outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
  474                 outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
  475 
  476                 outl ((u_short) addr, data);
  477 
  478                 outb (CONF2_ENABLE_PORT,  0);
  479                 outb (CONF2_FORWARD_PORT, 0);
  480                 break;
  481         };
  482 }
  483 
  484 /*-----------------------------------------------------------------------
  485 **
  486 **      Register an interupt handler for a pci device.
  487 **
  488 **-----------------------------------------------------------------------
  489 */
  490 
  491 static int
  492 pcibus_ihandler_attach (int irq, inthand2_t *func, int arg, unsigned * maskptr)
  493 {
  494         char buf[16];
  495         char *cp;
  496         int free_id, id, result;
  497 
  498         sprintf(buf, "pci irq%d", irq);
  499         for (cp = intrnames, free_id = 0, id = 0; id < NR_DEVICES; id++) {
  500                 if (strcmp(cp, buf) == 0)
  501                         break;
  502                 if (free_id <= 0 && strcmp(cp, "pci irqnn") == 0)
  503                         free_id = id;
  504                 while (*cp++ != '\0')
  505                         ;
  506         }
  507         if (id == NR_DEVICES) {
  508                 id = free_id;
  509                 if (id == 0) {
  510                         /*
  511                          * All pci irq counters are in use, perhaps because
  512                          * config is old so there aren't any.  Abuse the
  513                          * clk0 counter.
  514                          */
  515                         printf (
  516                 "pcibus_ihandler_attach: counting pci irq%d's as clk0 irqs\n",
  517                                 irq);
  518                 }
  519         }
  520         result = register_intr(
  521                 irq,                /* isa irq      */
  522                 id,                 /* device id    */
  523                 0,                  /* flags?       */
  524                 func,               /* handler      */
  525                 maskptr,            /* mask pointer */
  526                 arg);               /* handler arg  */
  527 
  528         if (result) {
  529                 printf ("@@@ pcibus_ihandler_attach: result=%d\n", result);
  530                 return (result);
  531         };
  532         update_intr_masks();
  533 
  534         INTREN ((1ul<<irq));
  535         return (0);
  536 }
  537 
  538 static int
  539 pcibus_ihandler_detach (int irq, inthand2_t *func)
  540 {
  541         int result;
  542 
  543         INTRDIS ((1ul<<irq));
  544 
  545         result = unregister_intr (irq, func);
  546 
  547         if (result)
  548                 printf ("@@@ pcibus_ihandler_detach: result=%d\n", result);
  549 
  550         update_intr_masks();
  551 
  552         return (result);
  553 }
  554 
  555 static int
  556 pcibus_imask_include (int irq, unsigned* maskptr)
  557 {
  558         unsigned mask;
  559 
  560         if (!maskptr) return (0);
  561 
  562         mask = 1ul << irq;
  563 
  564         if (*maskptr & mask)
  565                 return (-1);
  566 
  567         INTRMASK (*maskptr, mask);
  568         update_intr_masks();
  569 
  570         return (0);
  571 }
  572 
  573 static int
  574 pcibus_imask_exclude (int irq, unsigned* maskptr)
  575 {
  576         unsigned mask;
  577 
  578         if (!maskptr) return (0);
  579 
  580         mask = 1ul << irq;
  581 
  582         if (! (*maskptr & mask))
  583                 return (-1);
  584 
  585         *maskptr &= ~mask;
  586         update_intr_masks();
  587 
  588         return (0);
  589 }

Cache object: 74f664f9d7185bd6dbe236c3b8a945cc


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