ofw_pci.c revision 107472
150724Scg/* 250724Scg * Copyright (c) 1999, 2000 Matthew R. Green 350724Scg * All rights reserved. 450724Scg * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 550724Scg * 650724Scg * Redistribution and use in source and binary forms, with or without 750724Scg * modification, are permitted provided that the following conditions 850724Scg * are met: 950724Scg * 1. Redistributions of source code must retain the above copyright 1050724Scg * notice, this list of conditions and the following disclaimer. 1150724Scg * 2. Redistributions in binary form must reproduce the above copyright 1250724Scg * notice, this list of conditions and the following disclaimer in the 1350724Scg * documentation and/or other materials provided with the distribution. 1450724Scg * 3. The name of the author may not be used to endorse or promote products 1550724Scg * derived from this software without specific prior written permission. 1650724Scg * 1750724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1850724Scg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1950724Scg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2050724Scg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2150724Scg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2250724Scg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2350724Scg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2450724Scg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2550724Scg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2650733Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2750724Scg * SUCH DAMAGE. 2850724Scg * 2950724Scg * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp 3050724Scg * 3150724Scg * $FreeBSD: head/sys/sparc64/pci/ofw_pci.c 107472 2002-12-01 23:06:14Z tmm $ 3250724Scg */ 3350724Scg 3450724Scg#include "opt_ofw_pci.h" 3550724Scg 3650724Scg#include <sys/param.h> 3750724Scg#include <sys/kernel.h> 3850724Scg#include <sys/systm.h> 3950724Scg#include <sys/bus.h> 4050724Scg 4150724Scg#include <dev/pci/pcivar.h> 4250724Scg#include <dev/pci/pcireg.h> 4350724Scg 4450724Scg#include <dev/ofw/ofw_pci.h> 4550724Scg#include <dev/ofw/openfirm.h> 4650724Scg 4750724Scg#include <sparc64/pci/ofw_pci.h> 4850724Scg 4950724Scg#include <machine/ofw_bus.h> 5050724Scg#include <machine/ver.h> 5150724Scg 5250724Scg#include "pcib_if.h" 5350724Scg 5450724Scgu_int8_t pci_bus_cnt; 5550724Scgphandle_t *pci_bus_map; 5650724Scgint pci_bus_map_sz; 5750724Scg 5850724Scg#define OPQ_NO_SWIZZLE 1 5950724Scgstatic struct ofw_pci_quirk { 6050724Scg char *opq_model; 6150724Scg int opq_quirks; 6250724Scg} ofw_pci_quirks[] = { 6350724Scg { "SUNW,Ultra-4", OPQ_NO_SWIZZLE }, 6450724Scg { "SUNW,Ultra-1-Engine", OPQ_NO_SWIZZLE }, 6550724Scg}; 6650724Scg#define OPQ_NENT (sizeof(ofw_pci_quirks) / sizeof(ofw_pci_quirks[0])) 6750724Scg 6850724Scgstatic int pci_quirks; 6950724Scg 7050724Scg#define OFW_PCI_PCIBUS "pci" 7150724Scg#define PCI_BUS_MAP_INC 10 7250724Scg 7350724Scgint 7450724Scgofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz, 7550724Scg u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate) 7650724Scg{ 7750724Scg struct ofw_pci_register preg; 7850724Scg u_int32_t pintr, intr; 7950724Scg char type[32]; 8050724Scg 8150724Scg if (pintsz != sizeof(u_int32_t)) 8250724Scg return (-1); 8350724Scg bcopy(pintptr, &pintr, sizeof(pintr)); 8450724Scg if ((pci_quirks & OPQ_NO_SWIZZLE) == 0 && pregsz >= sizeof(preg) && 8550724Scg OF_getprop(node, "device_type", type, sizeof(type)) != -1 && 8650724Scg strcmp(type, OFW_PCI_PCIBUS) == 0 && pintr >= 1 && pintr <= 4) { 8750724Scg /* 8850724Scg * Handle a quirk found on some Netra t1 models: there exist 8950724Scg * PCI bridges without interrupt maps, where we apparently must 9050724Scg * do the PCI swizzle and continue to map on at the parent. 9150724Scg */ 9250724Scg bcopy(pregptr, &preg, sizeof(preg)); 9350724Scg intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr + 3) % 9450724Scg 4 + 1; 9550724Scg *rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK); 9650724Scg bcopy(&intr, *rintr, sizeof(intr)); 9750724Scg *terminate = 0; 9850724Scg return (sizeof(intr)); 9950724Scg } 10050724Scg return (-1); 10150724Scg} 10250724Scg 10350724Scgu_int32_t 10450724Scgofw_pci_route_intr(phandle_t node, u_int32_t ign) 10550724Scg{ 10650724Scg u_int32_t rv; 10750724Scg 10850724Scg rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback); 10953205Scg if (rv == ORIR_NOTFOUND) 11050724Scg return (255); 11150923Scg /* 11250724Scg * Some machines (notably the SPARCengine Ultra AX) have no mappings 11353205Scg * at all, but use complete interrupt vector number including the IGN. 11453205Scg * Catch this case and remove the IGN. 11553205Scg */ 11653205Scg if (rv > ign) 11753205Scg rv -= ign; 11853205Scg return (rv); 11953205Scg} 12050923Scg 12150923Scgu_int8_t 12250923Scgofw_pci_alloc_busno(phandle_t node) 12350923Scg{ 12450923Scg phandle_t *om; 12550923Scg int osz; 12650923Scg u_int8_t n; 12752713Stanimura 12852713Stanimura n = pci_bus_cnt++; 12950724Scg /* Establish a mapping between bus numbers and device nodes. */ 13051769Scg if (n >= pci_bus_map_sz) { 13150724Scg osz = pci_bus_map_sz; 13250724Scg om = pci_bus_map; 13350724Scg pci_bus_map_sz = n + PCI_BUS_MAP_INC; 13450724Scg pci_bus_map = malloc(sizeof(*pci_bus_map) * pci_bus_map_sz, 13553205Scg M_DEVBUF, M_WAITOK | M_ZERO); 13650724Scg if (om != NULL) { 13750724Scg bcopy(om, pci_bus_map, sizeof(*om) * osz); 13853205Scg free(om, M_DEVBUF); 13950724Scg } 14050724Scg } 14150724Scg pci_bus_map[n] = node; 14250724Scg return (n); 14350724Scg} 14450724Scg 14550724Scg/* 14650724Scg * Initialize bridge bus numbers for bridges that implement the primary, 14751769Scg * secondary and subordinate bus number registers. 14850724Scg */ 14950724Scgvoid 15050724Scgofw_pci_binit(device_t busdev, struct ofw_pci_bdesc *obd) 15150724Scg{ 15250724Scg 15350724Scg#ifdef OFW_PCI_DEBUG 15450724Scg printf("PCI-PCI bridge at %u/%u/%u: setting bus #s to %u/%u/%u\n", 15550724Scg obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus, 15650724Scg obd->obd_secbus, obd->obd_subbus); 15750724Scg#endif /* OFW_PCI_DEBUG */ 15850724Scg PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 15950724Scg PCIR_PRIBUS_1, obd->obd_bus, 1); 16050724Scg PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 16150724Scg PCIR_SECBUS_1, obd->obd_secbus, 1); 16250724Scg PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func, 16350724Scg PCIR_SUBBUS_1, obd->obd_subbus, 1); 16450724Scg} 16550724Scg 16650724Scg/* 16753205Scg * Walk the PCI bus hierarchy, starting with the root PCI bus and descending 16850724Scg * through bridges, and initialize the interrupt line and latency timer 16950724Scg * configuration registers of attached devices using firmware information, 17050724Scg * as well as the the bus numbers and ranges of the bridges. 17153205Scg */ 17250724Scgvoid 17350724Scgofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign, 17450724Scg struct ofw_pci_bdesc *obd) 17550724Scg{ 17650724Scg struct ofw_pci_register pcir; 17750724Scg struct ofw_pci_bdesc subobd, *tobd; 17850724Scg phandle_t node; 17951769Scg char type[32]; 18050724Scg int i, intr, freemap; 18150724Scg u_int slot, busno, func, sub, lat; 18250724Scg 18350724Scg /* Initialize the quirk list. */ 18453205Scg for (i = 0; i < OPQ_NENT; i++) { 18550724Scg if (strcmp(sparc64_model, ofw_pci_quirks[i].opq_model) == 0) { 18653205Scg pci_quirks = ofw_pci_quirks[i].opq_quirks; 18750724Scg break; 18850724Scg } 18950724Scg } 19050724Scg 19150724Scg if ((node = OF_child(bushdl)) == 0) 19250724Scg return; 19350724Scg freemap = 0; 19450724Scg busno = obd->obd_secbus; 19550724Scg do { 19650724Scg if (node == -1) 19751769Scg panic("ofw_pci_init_intr: OF_child failed"); 19850724Scg if (OF_getprop(node, "device_type", type, sizeof(type)) == -1) 19950724Scg type[0] = '\0'; 20050724Scg else 20150724Scg type[sizeof(type) - 1] = '\0'; 20250724Scg if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 20350724Scg panic("ofw_pci_init: OF_getprop failed"); 20450724Scg slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); 20550724Scg func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); 20650724Scg if (strcmp(type, OFW_PCI_PCIBUS) == 0) { 20750724Scg /* 20850724Scg * This is a pci-pci bridge, initalize the bus number and 20950724Scg * recurse to initialize the child bus. The hierarchy is 21050724Scg * usually at most 2 levels deep, so recursion is 21150724Scg * feasible. 21250724Scg */ 21350724Scg subobd.obd_bus = busno; 21450724Scg subobd.obd_slot = slot; 21550724Scg subobd.obd_func = func; 21650724Scg sub = ofw_pci_alloc_busno(node); 21753205Scg subobd.obd_secbus = subobd.obd_subbus = sub; 21850724Scg /* Assume this bridge is mostly standard conforming. */ 21950724Scg subobd.obd_init = ofw_pci_binit; 22050724Scg subobd.obd_super = obd; 22153205Scg /* 22250724Scg * Need to change all subordinate bus registers of the 22350724Scg * bridges above this one now so that configuration 22450724Scg * transactions will get through. 22550724Scg */ 22650724Scg for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) { 22750724Scg tobd->obd_subbus = sub; 22850724Scg tobd->obd_init(dev, tobd); 22951769Scg } 23050724Scg subobd.obd_init(dev, &subobd); 23150724Scg#ifdef OFW_PCI_DEBUG 23250724Scg device_printf(dev, "%s: descending to " 23350724Scg "subordinate PCI bus\n", __func__); 23450724Scg#endif /* OFW_PCI_DEBUG */ 23553205Scg ofw_pci_init(dev, node, ign, &subobd); 23650724Scg } else { 23750724Scg /* 23853205Scg * Initialize the latency timer register for 23950724Scg * busmaster devices to work properly. This is another 24050724Scg * task which the firmware does not always perform. 24150724Scg * The Min_Gnt register can be used to compute it's 24250724Scg * recommended value: it contains the desired latency 24350724Scg * in units of 1/4 us. To calculate the correct latency 24450724Scg * timer value, a bus clock of 33 and no wait states 24550923Scg * should be assumed. 24650724Scg */ 24751769Scg lat = PCIB_READ_CONFIG(dev, busno, slot, func, 24850724Scg PCIR_MINGNT, 1) * 33 / 4; 24950724Scg if (lat != 0) { 25050724Scg#ifdef OFW_PCI_DEBUG 25150724Scg printf("device %d/%d/%d: latency timer %d -> " 25253205Scg "%d\n", busno, slot, func, 25350724Scg PCIB_READ_CONFIG(dev, busno, slot, func, 25453205Scg PCIR_LATTIMER, 1), lat); 25550724Scg#endif /* OFW_PCI_DEBUG */ 25650724Scg PCIB_WRITE_CONFIG(dev, busno, slot, func, 25750724Scg PCIR_LATTIMER, imin(lat, 255), 1); 25850724Scg } 25950724Scg 26050724Scg /* Initialize the intline registers. */ 26150724Scg if ((intr = ofw_pci_route_intr(node, ign)) != 255) { 26250724Scg#ifdef OFW_PCI_DEBUG 26351769Scg device_printf(dev, "%s: mapping intr for " 26450724Scg "%d/%d/%d to %d (preset was %d)\n", 26551769Scg __func__, busno, slot, func, intr, 26650724Scg (int)PCIB_READ_CONFIG(dev, busno, slot, 26750724Scg func, PCIR_INTLINE, 1)); 26850724Scg#endif /* OFW_PCI_DEBUG */ 26950724Scg PCIB_WRITE_CONFIG(dev, busno, slot, func, 27053205Scg PCIR_INTLINE, intr, 1); 27150724Scg } else { 27253205Scg#ifdef OFW_PCI_DEBUG 27350724Scg device_printf(dev, "%s: no interrupt " 27450724Scg "mapping found for %d/%d/%d (preset %d)\n", 27550724Scg __func__, busno, slot, func, 27650724Scg (int)PCIB_READ_CONFIG(dev, busno, slot, 27750724Scg func, PCIR_INTLINE, 1)); 27850724Scg#endif /* OFW_PCI_DEBUG */ 27950724Scg /* 28051769Scg * The firmware initializes to 0 instead of 28150724Scg * 255. 28251769Scg */ 28350724Scg PCIB_WRITE_CONFIG(dev, busno, slot, func, 28450724Scg PCIR_INTLINE, 255, 1); 28550724Scg } 28650724Scg } 28750724Scg } while ((node = OF_peer(node)) != 0); 28850724Scg} 28950724Scg 29050724Scgphandle_t 29150724Scgofw_pci_find_node(int bus, int slot, int func) 29250724Scg{ 29350724Scg phandle_t node, bnode; 29450724Scg struct ofw_pci_register pcir; 29550724Scg 29650724Scg /* 29750724Scg * Retrieve the bus node from the mapping that was created on 29850724Scg * initialization. The bus numbers the firmware uses cannot be trusted, 29950724Scg * so they might have needed to be changed and this is necessary. 30050724Scg */ 30150724Scg if (bus >= pci_bus_map_sz) 30250724Scg return (0); 30350724Scg bnode = pci_bus_map[bus]; 30450724Scg if (bnode == 0) 30550724Scg return (0); 30650724Scg for (node = OF_child(bnode); node != 0 && node != -1; 30750724Scg node = OF_peer(node)) { 30850724Scg if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1) 30950724Scg continue; 31050724Scg if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot && 31150724Scg OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func) 31250724Scg return (node); 31350724Scg } 31450724Scg return (0); 31550724Scg} 31650724Scg 31750724Scgphandle_t 31850724Scgofw_pci_node(device_t dev) 31950724Scg{ 32050724Scg 32150724Scg return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev), 32250724Scg pci_get_function(dev))); 32350724Scg} 32450724Scg