root/arch/i386/pci/pchb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pchbmatch
  2. pchbattach
  3. pchb_print
  4. pchb_rnd
  5. pchb_amd64ht_attach

    1 /*      $OpenBSD: pchb.c,v 1.56 2007/06/01 22:45:17 biorn Exp $ */
    2 /*      $NetBSD: pchb.c,v 1.6 1997/06/06 23:29:16 thorpej Exp $ */
    3 
    4 /*
    5  * Copyright (c) 2000 Michael Shalayeff
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
   21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   23  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   26  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   27  * THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 /*-
   30  * Copyright (c) 1996 The NetBSD Foundation, Inc.
   31  * All rights reserved.
   32  *
   33  * This code is derived from software contributed to The NetBSD Foundation
   34  * by Jason R. Thorpe.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. All advertising materials mentioning features or use of this software
   45  *    must display the following acknowledgement:
   46  *        This product includes software developed by the NetBSD
   47  *        Foundation, Inc. and its contributors.
   48  * 4. Neither the name of The NetBSD Foundation nor the names of its
   49  *    contributors may be used to endorse or promote products derived
   50  *    from this software without specific prior written permission.
   51  *
   52  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   53  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   54  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   55  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   56  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   57  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   58  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   59  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   60  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   61  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   62  * POSSIBILITY OF SUCH DAMAGE.
   63  */
   64 
   65 #include <sys/param.h>
   66 #include <sys/systm.h>
   67 #include <sys/device.h>
   68 #include <sys/proc.h>
   69 #include <sys/timeout.h>
   70 
   71 #include <machine/bus.h>
   72 
   73 #include <dev/pci/pcivar.h>
   74 #include <dev/pci/pcireg.h>
   75 #include <dev/pci/pcidevs.h>
   76 
   77 #include <dev/rndvar.h>
   78 
   79 #include <dev/ic/i82802reg.h>
   80 
   81 #define PCISET_INTEL_BRIDGETYPE_MASK    0x3
   82 #define PCISET_INTEL_TYPE_COMPAT        0x1
   83 #define PCISET_INTEL_TYPE_AUX           0x2
   84 
   85 #define PCISET_INTEL_BUSCONFIG_REG      0x48
   86 #define PCISET_INTEL_BRIDGE_NUMBER(reg) (((reg) >> 8) & 0xff)
   87 #define PCISET_INTEL_PCI_BUS_NUMBER(reg)        (((reg) >> 16) & 0xff)
   88 
   89 #define PCISET_INTEL_SDRAMC_REG 0x74
   90 #define PCISET_INTEL_SDRAMC_IPDLT       (1 << 24)
   91 
   92 /* XXX should be in dev/ic/i82424{reg.var}.h */
   93 #define I82424_CPU_BCTL_REG             0x53
   94 #define I82424_PCI_BCTL_REG             0x54
   95 
   96 #define I82424_BCTL_CPUMEM_POSTEN       0x01
   97 #define I82424_BCTL_CPUPCI_POSTEN       0x02
   98 #define I82424_BCTL_PCIMEM_BURSTEN      0x01
   99 #define I82424_BCTL_PCI_BURSTEN         0x02
  100 
  101 /* XXX should be in dev/ic/amd64htreg.h */
  102 #define AMD64HT_LDT0_BUS        0x94
  103 #define AMD64HT_LDT0_TYPE       0x98
  104 #define AMD64HT_LDT1_BUS        0xb4
  105 #define AMD64HT_LDT1_TYPE       0xb8
  106 #define AMD64HT_LDT2_BUS        0xd4
  107 #define AMD64HT_LDT2_TYPE       0xd8
  108 
  109 #define AMD64HT_NUM_LDT         3
  110 
  111 #define AMD64HT_LDT_TYPE_MASK           0x0000001f
  112 #define  AMD64HT_LDT_INIT_COMPLETE      0x00000002
  113 #define  AMD64HT_LDT_NC                 0x00000004
  114 
  115 #define AMD64HT_LDT_SEC_BUS_NUM(reg)    (((reg) >> 8) & 0xff)
  116 
  117 struct pchb_softc {
  118         struct device sc_dev;
  119 
  120         bus_space_tag_t bt;
  121         bus_space_handle_t bh;
  122 
  123         /* rng stuff */
  124         int ax;
  125         int i;
  126         struct timeout sc_tmo;
  127 };
  128 
  129 int     pchbmatch(struct device *, void *, void *);
  130 void    pchbattach(struct device *, struct device *, void *);
  131 
  132 int     pchb_print(void *, const char *);
  133 
  134 struct cfattach pchb_ca = {
  135         sizeof(struct pchb_softc), pchbmatch, pchbattach
  136 };
  137 
  138 struct cfdriver pchb_cd = {
  139         NULL, "pchb", DV_DULL
  140 };
  141 
  142 void pchb_rnd(void *v);
  143 void    pchb_amd64ht_attach (struct device *, struct pci_attach_args *, int);
  144 
  145 const struct pci_matchid via_devices[] = {
  146         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_PWR },
  147         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596 },
  148         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596B_PM },
  149         { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB }
  150 };
  151 
  152 int
  153 pchbmatch(struct device *parent, void *match, void *aux)
  154 {
  155         struct pci_attach_args *pa = aux;
  156 
  157         /* XXX work around broken via82x866 chipsets */
  158         if (pci_matchbyid(pa, via_devices,
  159             sizeof(via_devices) / sizeof(via_devices[0])))
  160                 return (0);
  161 
  162         if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
  163             PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
  164                 return (1);
  165 
  166         return (0);
  167 }
  168 
  169 /*
  170  * The variable below is a bit vector representing the Serverworks
  171  * busses that have already been attached.  Bit 0 represents bus 0 and
  172  * so forth.  The initial value is 1 because we never actually want to
  173  * attach bus 0 since bus 0 is the mainbus.
  174  */
  175 u_int32_t rcc_bus_visited = 1;
  176 
  177 void
  178 pchbattach(struct device *parent, struct device *self, void *aux)
  179 {
  180         struct pchb_softc *sc = (struct pchb_softc *)self;
  181         struct pci_attach_args *pa = aux;
  182         struct pcibus_attach_args pba;
  183         struct timeval tv1, tv2;
  184         pcireg_t bcreg;
  185         u_char bdnum, pbnum;
  186         pcitag_t tag;
  187         int neednl = 1;
  188         int i, r;
  189 
  190         /*
  191          * Print out a description, and configure certain chipsets which
  192          * have auxiliary PCI buses.
  193          */
  194 
  195         switch (PCI_VENDOR(pa->pa_id)) {
  196 #ifdef PCIAGP
  197         case PCI_VENDOR_ALI:
  198         case PCI_VENDOR_SIS:
  199         case PCI_VENDOR_VIATECH:
  200                 pciagp_set_pchb(pa);
  201                 break;
  202 #endif
  203         case PCI_VENDOR_AMD:
  204                 switch (PCI_PRODUCT(pa->pa_id)) {
  205 #ifdef PCIAGP
  206                 case PCI_PRODUCT_AMD_SC751_SC:
  207                 case PCI_PRODUCT_AMD_762_PCHB:
  208                         pciagp_set_pchb(pa);
  209                         break;
  210 #endif
  211                 case PCI_PRODUCT_AMD_AMD64_HT:
  212                         neednl = 0;
  213                         printf("\n");
  214                         for (i = 0; i < AMD64HT_NUM_LDT; i++)
  215                                 pchb_amd64ht_attach(self, pa, i);
  216                         break;
  217                 }
  218                 break;
  219         case PCI_VENDOR_RCC:
  220                 bdnum = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44);
  221                 if (bdnum >= (sizeof(rcc_bus_visited) * 8) ||
  222                     (rcc_bus_visited & (1 << bdnum)))
  223                         break;
  224 
  225                 rcc_bus_visited |= 1 << bdnum;
  226 
  227                 /*
  228                  * This host bridge has a second PCI bus.
  229                  * Configure it.
  230                  */
  231                 neednl = 0;
  232                 pba.pba_busname = "pci";
  233                 pba.pba_iot = pa->pa_iot;
  234                 pba.pba_memt = pa->pa_memt;
  235                 pba.pba_dmat = pa->pa_dmat;
  236                 pba.pba_domain = pa->pa_domain;
  237                 pba.pba_bus = bdnum;
  238                 pba.pba_bridgetag = NULL;
  239                 pba.pba_pc = pa->pa_pc;
  240                 printf("\n");
  241                 config_found(self, &pba, pchb_print);
  242                 break;
  243         case PCI_VENDOR_INTEL:
  244 #ifdef PCIAGP
  245                 pciagp_set_pchb(pa);
  246 #endif
  247                 switch (PCI_PRODUCT(pa->pa_id)) {
  248                 case PCI_PRODUCT_INTEL_82443BX_AGP:     /* 82443BX AGP (PAC) */
  249                 case PCI_PRODUCT_INTEL_82443BX_NOAGP:   /* 82443BX Host-PCI (no AGP) */
  250                         /*
  251                          * An incorrect address may be driven on the
  252                          * DRAM bus, resulting in memory data being
  253                          * fetched from the wrong location.  This is
  254                          * the workaround.
  255                          */
  256                         if (PCI_REVISION(pa->pa_class) < 0x3) {
  257                                 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
  258                                     PCISET_INTEL_SDRAMC_REG);
  259                                 bcreg |= PCISET_INTEL_SDRAMC_IPDLT;
  260                                 pci_conf_write(pa->pa_pc, pa->pa_tag,
  261                                     PCISET_INTEL_SDRAMC_REG, bcreg);
  262                         }
  263                         break;
  264                 case PCI_PRODUCT_INTEL_PCI450_PB:
  265                         bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
  266                             PCISET_INTEL_BUSCONFIG_REG);
  267                         bdnum = PCISET_INTEL_BRIDGE_NUMBER(bcreg);
  268                         pbnum = PCISET_INTEL_PCI_BUS_NUMBER(bcreg);
  269                         switch (bdnum & PCISET_INTEL_BRIDGETYPE_MASK) {
  270                         default:
  271                                 printf(": bdnum=%x (reserved)", bdnum);
  272                                 break;
  273                         case PCISET_INTEL_TYPE_COMPAT:
  274                                 printf(": Compatibility PB (bus %d)", pbnum);
  275                                 break;
  276                         case PCISET_INTEL_TYPE_AUX:
  277                                 printf(": Auxiliary PB (bus %d)", pbnum);
  278                                 neednl = 0;
  279 
  280                                 /*
  281                                  * This host bridge has a second PCI bus.
  282                                  * Configure it.
  283                                  */
  284                                 pba.pba_busname = "pci";
  285                                 pba.pba_iot = pa->pa_iot;
  286                                 pba.pba_memt = pa->pa_memt;
  287                                 pba.pba_dmat = pa->pa_dmat;
  288                                 pba.pba_domain = pa->pa_domain;
  289                                 pba.pba_bus = pbnum;
  290                                 pba.pba_pc = pa->pa_pc;
  291                                 printf("\n");
  292                                 config_found(self, &pba, pchb_print);
  293                                 break;
  294                         }
  295                         break;
  296                 case PCI_PRODUCT_INTEL_82454NX:
  297                         pbnum = 0;
  298                         switch (pa->pa_device) {
  299                         case 18: /* PXB 0 bus A - primary bus */
  300                                 break;
  301                         case 19: /* PXB 0 bus B */
  302                                 /* read SUBA0 from MIOC */
  303                                 tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
  304                                 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
  305                                 pbnum = ((bcreg & 0x0000ff00) >> 8) + 1;
  306                                 break;
  307                         case 20: /* PXB 1 bus A */
  308                                 /* read BUSNO1 from MIOC */
  309                                 tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
  310                                 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
  311                                 pbnum = (bcreg & 0xff000000) >> 24;
  312                                 break;
  313                         case 21: /* PXB 1 bus B */
  314                                 /* read SUBA1 from MIOC */
  315                                 tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
  316                                 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd4);
  317                                 pbnum = (bcreg & 0x000000ff) + 1;
  318                                 break;
  319                         }
  320                         if (pbnum != 0) {
  321                                 pba.pba_busname = "pci";
  322                                 pba.pba_iot = pa->pa_iot;
  323                                 pba.pba_memt = pa->pa_memt;
  324                                 pba.pba_dmat = pa->pa_dmat;
  325                                 pba.pba_domain = pa->pa_domain;
  326                                 pba.pba_bus = pbnum;
  327                                 pba.pba_pc = pa->pa_pc;
  328                                 printf("\n");
  329                                 config_found(self, &pba, pchb_print);
  330                         }
  331                         break;
  332                 case PCI_PRODUCT_INTEL_CDC:
  333                         bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
  334                             I82424_CPU_BCTL_REG);
  335                         if (bcreg & I82424_BCTL_CPUPCI_POSTEN) {
  336                                 bcreg &= ~I82424_BCTL_CPUPCI_POSTEN;
  337                                 pci_conf_write(pa->pa_pc, pa->pa_tag,
  338                                     I82424_CPU_BCTL_REG, bcreg);
  339                                 printf(": disabled CPU-PCI write posting");
  340                         }
  341                         break;
  342                 case PCI_PRODUCT_INTEL_82810_MCH:
  343                 case PCI_PRODUCT_INTEL_82810_DC100_MCH:
  344                 case PCI_PRODUCT_INTEL_82810E_MCH:
  345                 case PCI_PRODUCT_INTEL_82815_DC100_HUB:
  346                 case PCI_PRODUCT_INTEL_82815_NOGRAPH_HUB:
  347                 case PCI_PRODUCT_INTEL_82815_FULL_HUB:
  348                 case PCI_PRODUCT_INTEL_82815_NOAGP_HUB:
  349                 case PCI_PRODUCT_INTEL_82820_MCH:
  350                 case PCI_PRODUCT_INTEL_82840_HB:
  351                 case PCI_PRODUCT_INTEL_82850_HB:
  352                 case PCI_PRODUCT_INTEL_82860_HB:
  353                 case PCI_PRODUCT_INTEL_82915G_HB:
  354                 case PCI_PRODUCT_INTEL_82925X_HB:
  355                 case PCI_PRODUCT_INTEL_82945GP_MCH:
  356                 case PCI_PRODUCT_INTEL_82955X_HB:
  357                         sc->bt = pa->pa_memt;
  358                         if (bus_space_map(sc->bt, I82802_IOBASE, I82802_IOSIZE,
  359                             0, &sc->bh))
  360                                 break;
  361 
  362                         /* probe and init rng */
  363                         if (!(bus_space_read_1(sc->bt, sc->bh,
  364                             I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT))
  365                                 break;
  366 
  367                         /* enable RNG */
  368                         bus_space_write_1(sc->bt, sc->bh, I82802_RNG_HWST,
  369                             bus_space_read_1(sc->bt, sc->bh, I82802_RNG_HWST) |
  370                             I82802_RNG_HWST_ENABLE);
  371 
  372                         /* see if we can read anything */
  373                         for (i = 1000; i-- &&
  374                             !(bus_space_read_1(sc->bt,sc->bh,I82802_RNG_RNGST)&
  375                               I82802_RNG_RNGST_DATAV);
  376                             DELAY(10));
  377 
  378                         if (!(bus_space_read_1(sc->bt, sc->bh,
  379                             I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV))
  380                                 break;
  381 
  382                         r = bus_space_read_1(sc->bt, sc->bh, I82802_RNG_DATA);
  383 
  384                         /* benchmark the RNG */
  385                         microtime(&tv1);
  386                         for (i = 8 * 1024; i--; ) {
  387                                 while(!(bus_space_read_1(sc->bt, sc->bh,
  388                                     I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV))
  389                                         ;
  390                                 r = bus_space_read_1(sc->bt, sc->bh,
  391                                     I82802_RNG_DATA);
  392                         }
  393                         microtime(&tv2);
  394 
  395                         timersub(&tv2, &tv1, &tv1);
  396                         if (tv1.tv_sec)
  397                                 tv1.tv_usec += 1000000 * tv1.tv_sec;
  398                         printf(": rng active");
  399                         if (tv1.tv_usec != 0)
  400                                 printf(", %dKb/sec",
  401                                     8 * 1000000 / tv1.tv_usec);
  402 
  403                         timeout_set(&sc->sc_tmo, pchb_rnd, sc);
  404                         sc->i = 4;
  405                         pchb_rnd(sc);
  406                         break;
  407                 default:
  408                         break;
  409                 }
  410         }
  411         if (neednl)
  412                 printf("\n");
  413 }
  414 
  415 int
  416 pchb_print(void *aux, const char *pnp)
  417 {
  418         struct pcibus_attach_args *pba = aux;
  419 
  420         if (pnp)
  421                 printf("%s at %s", pba->pba_busname, pnp);
  422         printf(" bus %d", pba->pba_bus);
  423         return (UNCONF);
  424 }
  425 
  426 /*
  427  * Should do FIPS testing as per:
  428  *      http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf
  429  */
  430 void
  431 pchb_rnd(void *v)
  432 {
  433         struct pchb_softc *sc = v;
  434 
  435         /*
  436          * Don't wait for data to be ready. If it's not there, we'll check
  437          * next time.
  438          */
  439         if ((bus_space_read_1(sc->bt, sc->bh, I82802_RNG_RNGST) &
  440             I82802_RNG_RNGST_DATAV)) {
  441 
  442                 sc->ax = (sc->ax << 8) |
  443                     bus_space_read_1(sc->bt, sc->bh, I82802_RNG_DATA);
  444 
  445                 if (!sc->i--) {
  446                         sc->i = 4;
  447                         add_true_randomness(sc->ax);
  448                 }
  449         }
  450 
  451         timeout_add(&sc->sc_tmo, 1);
  452 }
  453 
  454 void
  455 pchb_amd64ht_attach (struct device *self, struct pci_attach_args *pa, int i)
  456 {
  457         struct pcibus_attach_args pba;
  458         pcireg_t type, bus;
  459         int reg;
  460 
  461         reg = AMD64HT_LDT0_TYPE + i * 0x20;
  462         type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
  463         if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 ||
  464             (type & AMD64HT_LDT_NC) == 0)
  465                 return;
  466 
  467         reg = AMD64HT_LDT0_BUS + i * 0x20;
  468         bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
  469         if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) {
  470                 pba.pba_busname = "pci";
  471                 pba.pba_iot = pa->pa_iot;
  472                 pba.pba_memt = pa->pa_memt;
  473                 pba.pba_dmat = pa->pa_dmat;
  474                 pba.pba_domain = pa->pa_domain;
  475                 pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus);
  476                 pba.pba_pc = pa->pa_pc;
  477                 config_found(self, &pba, pchb_print);
  478         }
  479 }

/* [<][>][^][v][top][bottom][index][help] */