ofw_pci.c revision 111119
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 111119 2003-02-19 05:47:46Z imp $ 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/cache.h> 50#include <machine/iommureg.h> 51#include <machine/ofw_bus.h> 52#include <machine/ver.h> 53 54#include "pcib_if.h" 55 56u_int8_t pci_bus_cnt; 57phandle_t *pci_bus_map; 58int pci_bus_map_sz; 59 60#define OPQ_NO_SWIZZLE 1 61static struct ofw_pci_quirk { 62 char *opq_model; 63 int opq_quirks; 64} ofw_pci_quirks[] = { 65 { "SUNW,Ultra-4", OPQ_NO_SWIZZLE }, 66 { "SUNW,Ultra-1-Engine", OPQ_NO_SWIZZLE }, 67}; 68#define OPQ_NENT (sizeof(ofw_pci_quirks) / sizeof(ofw_pci_quirks[0])) 69 70static int pci_quirks; 71 72#define OFW_PCI_PCIBUS "pci" 73#define PCI_BUS_MAP_INC 10 74 75int 76ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, 77 u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate) 78{ 79 struct ofw_pci_register preg; 80 u_int32_t pintr, intr; 81 char type[32]; 82 83 if (pintsz != sizeof(u_int32_t)) 84 return (-1); 85 bcopy(pintptr, &pintr, sizeof(pintr)); 86 if ((pci_quirks & OPQ_NO_SWIZZLE) == 0 && pregsz >= sizeof(preg) && 87 OF_getprop(node, "device_type", type, sizeof(type)) != -1 && 88 strcmp(type, OFW_PCI_PCIBUS) == 0 && pintr >= 1 && pintr <= 4) { 89 /* 90 * Handle a quirk found on some Netra t1 models: there exist 91 * PCI bridges without interrupt maps, where we apparently must 92 * do the PCI swizzle and continue to map on at the parent. 93 */ 94 bcopy(pregptr, &preg, sizeof(preg)); 95 intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr + 3) % 96 4 + 1; 97 *rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK); 98 bcopy(&intr, *rintr, sizeof(intr)); 99 *terminate = 0; 100 return (sizeof(intr)); 101 } 102 return (-1); 103} 104 105u_int32_t 106ofw_pci_route_intr(phandle_t node, u_int32_t ign) 107{ 108 u_int32_t rv; 109 110 rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback); 111 if (rv == ORIR_NOTFOUND) 112 return (255); 113 /* 114 * Some machines (notably the SPARCengine Ultra AX) have no mappings 115 * at all, but use complete interrupt vector number including the IGN. 116 * Catch this case and remove the IGN. 117 */ 118 if (rv > ign) 119 rv -= ign; 120 return (rv); 121} 122 123u_int8_t 124ofw_pci_alloc_busno(phandle_t node) 125{ 126 phandle_t *om; 127 int osz; 128 u_int8_t n; 129 130 n = pci_bus_cnt++; 131 /* Establish a mapping between bus numbers and device nodes. */ 132 if (n >= pci_bus_map_sz) { 133 osz = pci_bus_map_sz; 134 om = pci_bus_map; 135 pci_bus_map_sz = n + PCI_BUS_MAP_INC; 136 pci_bus_map = malloc(sizeof(*pci_bus_map) * pci_bus_map_sz, 137 M_DEVBUF, M_WAITOK | M_ZERO); 138 if (om != NULL) { 139 bcopy(om, pci_bus_map, sizeof(*om) * osz); 140 free(om, M_DEVBUF); 141 } 142 } 143 pci_bus_map[n] = node; 144 return (n); 145} 146 147/* 148 * Initialize bridge bus numbers for bridges that implement the primary, 149 * secondary and subordinate bus number registers. 150 */ 151void 152ofw_pci_binit(device_t busdev, struct ofw_pci_bdesc *obd) 153{ 154 155#ifdef OFW_PCI_DEBUG 156 printf("PCI-PCI bridge at %u/%u/%u: setting bus #s to %u/%u/%u\n", 157 obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus, 158 obd->obd_secbus, obd->obd_subbus); 159#endif /* OFW_PCI_DEBUG */ 160 PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 161 PCIR_PRIBUS_1, obd->obd_bus, 1); 162 PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 163 PCIR_SECBUS_1, obd->obd_secbus, 1); 164 PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 165 PCIR_SUBBUS_1, obd->obd_subbus, 1); 166} 167 168/* 169 * Walk the PCI bus hierarchy, starting with the root PCI bus and descending 170 * through bridges, and initialize the interrupt line and latency timer 171 * configuration registers of attached devices using firmware information, 172 * as well as the the bus numbers and ranges of the bridges. 173 */ 174void 175ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, 176 struct ofw_pci_bdesc *obd) 177{ 178 struct ofw_pci_register pcir; 179 struct ofw_pci_bdesc subobd, *tobd; 180 phandle_t node; 181 char type[32]; 182 int i, intr, freemap; 183 u_int slot, busno, func, sub, lat; 184 u_int8_t clnsz; 185 186 /* Initialize the quirk list. */ 187 for (i = 0; i < OPQ_NENT; i++) { 188 if (strcmp(sparc64_model, ofw_pci_quirks[i].opq_model) == 0) { 189 pci_quirks = ofw_pci_quirks[i].opq_quirks; 190 break; 191 } 192 } 193 194 if ((node = OF_child(bushdl)) == 0) 195 return; 196 freemap = 0; 197 busno = obd->obd_secbus; 198 /* 199 * Compute the value to write into the cache line size register. 200 * The role of the streaming cache is unclear in write invalidate 201 * transfers, so it is made sure that it's line size is always reached. 202 */ 203 clnsz = imax(cache.ec_linesize, STRBUF_LINESZ); 204 KASSERT((clnsz / STRBUF_LINESZ) * STRBUF_LINESZ == clnsz && 205 (clnsz / cache.ec_linesize) * cache.ec_linesize == clnsz && 206 (clnsz / 4) * 4 == clnsz, ("bogus cache line size %d", clnsz)); 207 208 do { 209 if (node == -1) 210 panic("ofw_pci_init_intr: OF_child failed"); 211 if (OF_getprop(node, "device_type", type, sizeof(type)) == -1) 212 type[0] = '\0'; 213 else 214 type[sizeof(type) - 1] = '\0'; 215 if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 216 panic("ofw_pci_init: OF_getprop failed"); 217 slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); 218 func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); 219 if (strcmp(type, OFW_PCI_PCIBUS) == 0) { 220 /* 221 * This is a pci-pci bridge, initalize the bus number and 222 * recurse to initialize the child bus. The hierarchy is 223 * usually at most 2 levels deep, so recursion is 224 * feasible. 225 */ 226 subobd.obd_bus = busno; 227 subobd.obd_slot = slot; 228 subobd.obd_func = func; 229 sub = ofw_pci_alloc_busno(node); 230 subobd.obd_secbus = subobd.obd_subbus = sub; 231 /* Assume this bridge is mostly standard conforming. */ 232 subobd.obd_init = ofw_pci_binit; 233 subobd.obd_super = obd; 234 /* 235 * Need to change all subordinate bus registers of the 236 * bridges above this one now so that configuration 237 * transactions will get through. 238 */ 239 for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) { 240 tobd->obd_subbus = sub; 241 tobd->obd_init(dev, tobd); 242 } 243 subobd.obd_init(dev, &subobd); 244#ifdef OFW_PCI_DEBUG 245 device_printf(dev, "%s: descending to " 246 "subordinate PCI bus\n", __func__); 247#endif /* OFW_PCI_DEBUG */ 248 ofw_pci_init(dev, node, ign, &subobd); 249 } else { 250 /* 251 * Initialize the latency timer register for 252 * busmaster devices to work properly. This is another 253 * task which the firmware does not always perform. 254 * The Min_Gnt register can be used to compute it's 255 * recommended value: it contains the desired latency 256 * in units of 1/4 us. To calculate the correct latency 257 * timer value, a bus clock of 33 and no wait states 258 * should be assumed. 259 */ 260 lat = PCIB_READ_CONFIG(dev, busno, slot, func, 261 PCIR_MINGNT, 1) * 33 / 4; 262 if (lat != 0) { 263#ifdef OFW_PCI_DEBUG 264 printf("device %d/%d/%d: latency timer %d -> " 265 "%d\n", busno, slot, func, 266 PCIB_READ_CONFIG(dev, busno, slot, func, 267 PCIR_LATTIMER, 1), lat); 268#endif /* OFW_PCI_DEBUG */ 269 PCIB_WRITE_CONFIG(dev, busno, slot, func, 270 PCIR_LATTIMER, imin(lat, 255), 1); 271 } 272 PCIB_WRITE_CONFIG(dev, busno, slot, func, 273 PCIR_CACHELNSZ, clnsz / 4, 1); 274 275 /* Initialize the intline registers. */ 276 if ((intr = ofw_pci_route_intr(node, ign)) != 255) { 277#ifdef OFW_PCI_DEBUG 278 device_printf(dev, "%s: mapping intr for " 279 "%d/%d/%d to %d (preset was %d)\n", 280 __func__, busno, slot, func, intr, 281 (int)PCIB_READ_CONFIG(dev, busno, slot, 282 func, PCIR_INTLINE, 1)); 283#endif /* OFW_PCI_DEBUG */ 284 PCIB_WRITE_CONFIG(dev, busno, slot, func, 285 PCIR_INTLINE, intr, 1); 286 } else { 287#ifdef OFW_PCI_DEBUG 288 device_printf(dev, "%s: no interrupt " 289 "mapping found for %d/%d/%d (preset %d)\n", 290 __func__, busno, slot, func, 291 (int)PCIB_READ_CONFIG(dev, busno, slot, 292 func, PCIR_INTLINE, 1)); 293#endif /* OFW_PCI_DEBUG */ 294 /* 295 * The firmware initializes to 0 instead of 296 * 255. 297 */ 298 PCIB_WRITE_CONFIG(dev, busno, slot, func, 299 PCIR_INTLINE, 255, 1); 300 } 301 } 302 } while ((node = OF_peer(node)) != 0); 303} 304 305phandle_t 306ofw_pci_find_node(int bus, int slot, int func) 307{ 308 phandle_t node, bnode; 309 struct ofw_pci_register pcir; 310 311 /* 312 * Retrieve the bus node from the mapping that was created on 313 * initialization. The bus numbers the firmware uses cannot be trusted, 314 * so they might have needed to be changed and this is necessary. 315 */ 316 if (bus >= pci_bus_map_sz) 317 return (0); 318 bnode = pci_bus_map[bus]; 319 if (bnode == 0) 320 return (0); 321 for (node = OF_child(bnode); node != 0 && node != -1; 322 node = OF_peer(node)) { 323 if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 324 continue; 325 if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot && 326 OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func) 327 return (node); 328 } 329 return (0); 330} 331 332phandle_t 333ofw_pci_node(device_t dev) 334{ 335 336 return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev), 337 pci_get_function(dev))); 338} 339