Home | History | Annotate | Line # | Download | only in pci
      1  1.3   msaitoh /*	$NetBSD: pci_bus_fixup.c,v 1.3 2019/03/01 09:25:59 msaitoh Exp $	*/
      2  1.1  jmcneill 
      3  1.1  jmcneill /*
      4  1.1  jmcneill  * Copyright (c) 1999, by UCHIYAMA Yasushi
      5  1.1  jmcneill  * All rights reserved.
      6  1.1  jmcneill  *
      7  1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8  1.1  jmcneill  * modification, are permitted provided that the following conditions
      9  1.1  jmcneill  * are met:
     10  1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12  1.1  jmcneill  * 2. The name of the developer may NOT be used to endorse or promote products
     13  1.1  jmcneill  *    derived from this software without specific prior written permission.
     14  1.1  jmcneill  *
     15  1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  1.1  jmcneill  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  1.1  jmcneill  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  1.1  jmcneill  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  1.1  jmcneill  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  1.1  jmcneill  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  1.1  jmcneill  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  1.1  jmcneill  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  1.1  jmcneill  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  1.1  jmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  1.1  jmcneill  * SUCH DAMAGE.
     26  1.1  jmcneill  */
     27  1.1  jmcneill 
     28  1.1  jmcneill /*
     29  1.1  jmcneill  * PCI bus renumbering support.
     30  1.1  jmcneill  */
     31  1.1  jmcneill 
     32  1.1  jmcneill #include <sys/cdefs.h>
     33  1.3   msaitoh __KERNEL_RCSID(0, "$NetBSD: pci_bus_fixup.c,v 1.3 2019/03/01 09:25:59 msaitoh Exp $");
     34  1.1  jmcneill 
     35  1.1  jmcneill #include <sys/param.h>
     36  1.1  jmcneill #include <sys/systm.h>
     37  1.1  jmcneill #include <sys/kernel.h>
     38  1.1  jmcneill 
     39  1.2    dyoung #include <sys/bus.h>
     40  1.1  jmcneill 
     41  1.1  jmcneill #include <dev/pci/pcireg.h>
     42  1.1  jmcneill #include <dev/pci/pcivar.h>
     43  1.1  jmcneill #include <dev/pci/pcidevs.h>
     44  1.1  jmcneill #include <dev/pci/ppbreg.h>
     45  1.1  jmcneill 
     46  1.1  jmcneill #include <x86/pci/pci_bus_fixup.h>
     47  1.1  jmcneill 
     48  1.1  jmcneill /* this array lists the parent for each bus number */
     49  1.1  jmcneill int pci_bus_parent[256];
     50  1.1  jmcneill 
     51  1.1  jmcneill /* this array lists the pcitag to program each bridge */
     52  1.1  jmcneill pcitag_t pci_bus_tag[256];
     53  1.1  jmcneill 
     54  1.1  jmcneill static void pci_bridge_reset(pci_chipset_tag_t, pcitag_t, void *);
     55  1.1  jmcneill 
     56  1.1  jmcneill int
     57  1.1  jmcneill pci_bus_fixup(pci_chipset_tag_t pc, int bus)
     58  1.1  jmcneill {
     59  1.1  jmcneill 	static int bus_total;
     60  1.1  jmcneill 	static int bridge_cnt;
     61  1.1  jmcneill 	int device, maxdevs, function, nfuncs, bridge, bus_max, bus_sub;
     62  1.1  jmcneill 	const struct pci_quirkdata *qd;
     63  1.1  jmcneill 	pcireg_t reg;
     64  1.1  jmcneill 	pcitag_t tag;
     65  1.1  jmcneill 
     66  1.1  jmcneill 	bus_max = bus;
     67  1.1  jmcneill 	bus_sub = 0;
     68  1.1  jmcneill 
     69  1.1  jmcneill 	if (++bus_total > 256)
     70  1.1  jmcneill 		panic("pci_bus_fixup: more than 256 PCI busses?");
     71  1.1  jmcneill 
     72  1.1  jmcneill 	/* Reset bridge configuration on this bus */
     73  1.1  jmcneill 	pci_bridge_foreach(pc, bus, bus, pci_bridge_reset, 0);
     74  1.1  jmcneill 
     75  1.1  jmcneill 	maxdevs = pci_bus_maxdevs(pc, bus);
     76  1.1  jmcneill 
     77  1.1  jmcneill 	for (device = 0; device < maxdevs; device++) {
     78  1.1  jmcneill 		tag = pci_make_tag(pc, bus, device, 0);
     79  1.1  jmcneill 		reg = pci_conf_read(pc, tag, PCI_ID_REG);
     80  1.1  jmcneill 
     81  1.1  jmcneill 		/* Invalid vendor ID value? */
     82  1.1  jmcneill 		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
     83  1.1  jmcneill 			continue;
     84  1.1  jmcneill 		/* XXX Not invalid, but we've done this ~forever. */
     85  1.1  jmcneill 		if (PCI_VENDOR(reg) == 0)
     86  1.1  jmcneill 			continue;
     87  1.1  jmcneill 
     88  1.1  jmcneill 		qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
     89  1.1  jmcneill 
     90  1.1  jmcneill 		reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
     91  1.1  jmcneill 		if (PCI_HDRTYPE_MULTIFN(reg) ||
     92  1.1  jmcneill 		    (qd != NULL &&
     93  1.1  jmcneill 		     (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
     94  1.1  jmcneill 			nfuncs = 8;
     95  1.1  jmcneill 		else
     96  1.1  jmcneill 			nfuncs = 1;
     97  1.1  jmcneill 
     98  1.1  jmcneill 		for (function = 0; function < nfuncs; function++) {
     99  1.1  jmcneill 			tag = pci_make_tag(pc, bus, device, function);
    100  1.1  jmcneill 			reg = pci_conf_read(pc, tag, PCI_ID_REG);
    101  1.1  jmcneill 
    102  1.1  jmcneill 			/* Invalid vendor ID value? */
    103  1.1  jmcneill 			if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
    104  1.1  jmcneill 				continue;
    105  1.1  jmcneill 			/* XXX Not invalid, but we've done this ~forever. */
    106  1.1  jmcneill 			if (PCI_VENDOR(reg) == 0)
    107  1.1  jmcneill 				continue;
    108  1.1  jmcneill 
    109  1.1  jmcneill 			aprint_debug("PCI fixup examining %02x:%02x\n",
    110  1.1  jmcneill 			       PCI_VENDOR(reg), PCI_PRODUCT(reg));
    111  1.1  jmcneill 
    112  1.1  jmcneill 			reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
    113  1.1  jmcneill 			if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
    114  1.1  jmcneill 			    (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
    115  1.1  jmcneill 			     PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
    116  1.1  jmcneill 				/* Assign the bridge #. */
    117  1.1  jmcneill 				bridge = bridge_cnt++;
    118  1.1  jmcneill 
    119  1.1  jmcneill 				/* Assign the bridge's secondary bus #. */
    120  1.1  jmcneill 				bus_max++;
    121  1.1  jmcneill 
    122  1.3   msaitoh 				reg = pci_conf_read(pc, tag,
    123  1.3   msaitoh 				    PCI_BRIDGE_BUS_REG);
    124  1.1  jmcneill 				reg &= 0xff000000;
    125  1.1  jmcneill 				reg |= bus | (bus_max << 8) | (0xff << 16);
    126  1.3   msaitoh 				pci_conf_write(pc, tag, PCI_BRIDGE_BUS_REG,
    127  1.3   msaitoh 				    reg);
    128  1.1  jmcneill 
    129  1.1  jmcneill 				/* Scan subordinate bus. */
    130  1.1  jmcneill 				bus_sub = pci_bus_fixup(pc, bus_max);
    131  1.1  jmcneill 
    132  1.1  jmcneill 				/* Configure the bridge. */
    133  1.1  jmcneill 				reg &= 0xff000000;
    134  1.1  jmcneill 				reg |= bus | (bus_max << 8) | (bus_sub << 16);
    135  1.3   msaitoh 				pci_conf_write(pc, tag, PCI_BRIDGE_BUS_REG,
    136  1.3   msaitoh 				    reg);
    137  1.1  jmcneill 
    138  1.1  jmcneill 				/* record relationship */
    139  1.1  jmcneill 				pci_bus_parent[bus_max]=bus;
    140  1.1  jmcneill 
    141  1.1  jmcneill 				pci_bus_tag[bus_max]=tag;
    142  1.1  jmcneill 
    143  1.1  jmcneill 				aprint_debug("PCI bridge %d: primary %d, "
    144  1.1  jmcneill 				    "secondary %d, subordinate %d\n",
    145  1.1  jmcneill 				    bridge, bus, bus_max, bus_sub);
    146  1.1  jmcneill 
    147  1.1  jmcneill 				/* Next bridge's secondary bus #. */
    148  1.1  jmcneill 				bus_max = (bus_sub > bus_max) ?
    149  1.1  jmcneill 				    bus_sub : bus_max;
    150  1.1  jmcneill 			}
    151  1.1  jmcneill 		}
    152  1.1  jmcneill 	}
    153  1.1  jmcneill 
    154  1.1  jmcneill 	return (bus_max);	/* last # of subordinate bus */
    155  1.1  jmcneill }
    156  1.1  jmcneill 
    157  1.1  jmcneill /* Reset bus-bridge configuration */
    158  1.1  jmcneill void
    159  1.1  jmcneill pci_bridge_reset(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
    160  1.1  jmcneill {
    161  1.1  jmcneill 	pcireg_t reg;
    162  1.1  jmcneill 
    163  1.3   msaitoh 	reg = pci_conf_read(pc, tag, PCI_BRIDGE_BUS_REG);
    164  1.1  jmcneill 	reg &= 0xff000000;
    165  1.1  jmcneill 	reg |= 0x00ffffff;	/* max bus # */
    166  1.3   msaitoh 	pci_conf_write(pc, tag, PCI_BRIDGE_BUS_REG, reg);
    167  1.1  jmcneill }
    168