ofw_pci.c revision 90613
1/* 2 * Copyright (c) 1999, 2000 Matthew R. Green 3 * All rights reserved. 4 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following 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 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 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 BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp 30 * 31 * $FreeBSD: head/sys/sparc64/pci/ofw_pci.c 90613 2002-02-13 15:44:58Z tmm $ 32 */ 33 34#include "opt_ofw_pci.h" 35 36#include <sys/param.h> 37#include <sys/kernel.h> 38#include <sys/systm.h> 39#include <sys/bus.h> 40 41#include <dev/pci/pcivar.h> 42#include <dev/pci/pcireg.h> 43 44#include <dev/ofw/ofw_pci.h> 45#include <dev/ofw/openfirm.h> 46 47#include <sparc64/pci/ofw_pci.h> 48 49#include <machine/ofw_bus.h> 50 51#include "pcib_if.h" 52 53/* 54 * Find the interrupt-map properties for a node. This might not be a property 55 * of the parent, because there may be bridges in between, so go up through the 56 * tree to find it. 57 * This seems to be only needed for PCI systems, so it has not been moved to 58 * ofw_bus.c 59 */ 60int 61ofw_pci_find_imap(phandle_t node, struct ofw_pci_imap **imap, 62 struct ofw_pci_imap_msk *imapmsk) 63{ 64 int nimap; 65 66 nimap = -1; 67 while ((node = OF_parent(node)) != 0) { 68 if ((nimap = OF_getprop_alloc(node, "interrupt-map", 69 sizeof(**imap), (void **)imap)) == -1 || 70 OF_getprop(node, "interrupt-map-mask", 71 imapmsk, sizeof(*imapmsk)) == -1) { 72 if (*imap != NULL) { 73 free(*imap, M_OFWPROP); 74 *imap = NULL; 75 } 76 nimap = -1; 77 } else 78 break; 79 } 80 return (nimap); 81} 82 83/* 84 * Route an interrupt using the firmware nodes. Returns 255 for interrupts 85 * that cannot be routed (suitable for the PCI code). 86 */ 87int 88ofw_pci_route_intr2(int intr, struct ofw_pci_register *pcir, 89 struct ofw_pci_imap *imap, int nimap, struct ofw_pci_imap_msk *imapmsk) 90{ 91 char regm[12]; 92 int cintr; 93 94 cintr = ofw_bus_route_intr(intr, pcir, sizeof(*pcir), 12, 1, imap, 95 nimap, imapmsk, regm); 96 if (cintr == -1) 97 return (255); 98 else 99 return (cintr); 100} 101 102int 103ofw_pci_route_intr(phandle_t node, struct ofw_pci_register *pcir, 104 struct ofw_pci_imap *intrmap, int nintrmap, 105 struct ofw_pci_imap_msk *intrmapmsk) 106{ 107 int intr; 108 109 if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1) 110 return (255); 111 112 return (ofw_pci_route_intr2(intr, pcir, intrmap, nintrmap, intrmapmsk)); 113} 114 115#define OFW_PCI_PCIBUS "pci" 116/* 117 * Walk the PCI bus hierarchy, starting with the root PCI bus and descending 118 * through bridges, and initialize the interrupt line configuration registers 119 * of attached devices using firmware information. 120 */ 121void 122ofw_pci_init_intr(device_t dev, phandle_t bus, struct ofw_pci_imap *intrmap, 123 int nintrmap, struct ofw_pci_imap_msk *intrmapmsk) 124{ 125 struct ofw_pci_imap_msk lintrmapmsk; 126 struct ofw_pci_register pcir; 127 phandle_t node; 128 char type[32]; 129 int intr; 130 int freemap; 131 132 if ((node = OF_child(bus)) == 0) 133 return; 134 freemap = 0; 135 do { 136 if (node == -1) 137 panic("ofw_pci_init_intr: OF_child failed"); 138 if (OF_getprop(node, "device_type", type, sizeof(type)) == -1) 139 type[0] = '\0'; 140 else 141 type[sizeof(type) - 1] = '\0'; 142 if (strcmp(type, OFW_PCI_PCIBUS) == 0) { 143 /* 144 * This is a pci-pci bridge, recurse to initialize the 145 * child bus. The hierarchy is usually at most 2 levels 146 * deep, so recursion is feasible. 147 */ 148#ifdef OFW_PCI_DEBUG 149 device_printf(dev, __func__": descending to " 150 "subordinate PCI bus\n"); 151#endif 152 ofw_pci_init_intr(dev, node, NULL, 0, NULL); 153 } else { 154 if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 155 panic("ofw_pci_route_intr: OF_getprop failed"); 156 /* 157 * If we didn't get interrupt map properties passed, 158 * try to find them now. On some systems, buses that 159 * have no non-bridge children have no such properties, 160 * so only try to find them at need. 161 */ 162 if (intrmap == NULL) { 163 nintrmap = OF_getprop_alloc(bus, 164 "interrupt-map", sizeof(*intrmap), 165 (void **)&intrmap); 166 if (nintrmap == -1 || 167 OF_getprop(bus, "interrupt-map-mask", 168 &lintrmapmsk, sizeof(lintrmapmsk)) == -1) { 169 printf("ofw_pci_init_intr: could not get " 170 "interrupt map properties\n"); 171 if (nintrmap != -1) 172 free(intrmap, M_OFWPROP); 173 return; 174 } 175 intrmapmsk = &lintrmapmsk; 176 freemap = 1; 177 } 178 if ((intr = ofw_pci_route_intr(node, &pcir, intrmap, 179 nintrmap, intrmapmsk)) != 255) { 180#ifdef OFW_PCI_DEBUG 181 device_printf(dev, __func__": mapping intr for " 182 "%d/%d/%d to %d (preset was %d)\n", 183 OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 184 OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 185 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 186 intr, 187 (int)PCIB_READ_CONFIG(dev, 188 OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 189 OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 190 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 191 PCIR_INTLINE, 1)); 192 193#endif /* OFW_PCI_DEBUG */ 194 PCIB_WRITE_CONFIG(dev, 195 OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 196 OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 197 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 198 PCIR_INTLINE, intr, 1); 199 } else { 200#ifdef OFW_PCI_DEBUG 201 device_printf(dev, __func__": no interrupt " 202 "mapping found for %d/%d/%d (preset %d)\n", 203 OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 204 OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 205 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 206 (int)PCIB_READ_CONFIG(dev, 207 OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 208 OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 209 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 210 PCIR_INTLINE, 1)); 211#endif /* OFW_PCI_DEBUG */ 212 /* The firmware initializes to 0 instead 255 */ 213 PCIB_WRITE_CONFIG(dev, 214 OFW_PCI_PHYS_HI_BUS(pcir.phys_hi), 215 OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi), 216 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi), 217 PCIR_INTLINE, 255, 1); 218 } 219 } 220 } while ((node = OF_peer(node)) != 0); 221 if (freemap) 222 free(intrmap, M_OFWPROP); 223} 224 225phandle_t 226ofw_pci_find_node(int bus, int slot, int func) 227{ 228 phandle_t node, bnode, parent; 229 struct ofw_pci_register pcir; 230 int br[2]; 231 char name[16]; 232 233 /* 1. Try to find the bus in question. */ 234 bnode = 0; 235 name[sizeof(name) - 1] = '\0'; 236 parent = OF_peer(0); 237 node = OF_child(parent); 238 while (node != 0 && node != -1) { 239 if (OF_getprop(node, "name", name, sizeof(name) - 1) != -1 && 240 strcmp(name, "pci") == 0 && 241 OF_getprop(node, "bus-range", br, sizeof(br)) != -1) { 242 /* Found the bus? */ 243 if (bus == br[0]) { 244 bnode = node; 245 break; 246 } 247 /* Need to descend? */ 248 if (bus > br[0] && bus <= br[1]) { 249 parent = node; 250 node = OF_child(node); 251 continue; 252 } 253 } 254 node = OF_peer(node); 255 } 256 if (bnode == 0) 257 return (0); 258 for (node = OF_child(bnode); node != 0 && node != -1; 259 node = OF_peer(node)) { 260 if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 261 continue; 262 if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot && 263 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func) { 264 if (OFW_PCI_PHYS_HI_BUS(pcir.phys_hi) != bus) 265 panic("ofw_pci_find_node: bus number mismatch"); 266 return (node); 267 } 268 } 269 return (0); 270} 271