pci_subr.c revision 224069
169783Smsmith/*- 2223520Sjhb * Copyright (c) 2011 Advanced Computing Technologies LLC 3223520Sjhb * Written by: John H. Baldwin <jhb@FreeBSD.org> 469783Smsmith * All rights reserved. 569783Smsmith * 669783Smsmith * Redistribution and use in source and binary forms, with or without 769783Smsmith * modification, are permitted provided that the following conditions 869783Smsmith * are met: 969783Smsmith * 1. Redistributions of source code must retain the above copyright 1069783Smsmith * notice, this list of conditions and the following disclaimer. 1169783Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1269783Smsmith * notice, this list of conditions and the following disclaimer in the 1369783Smsmith * documentation and/or other materials provided with the distribution. 1469783Smsmith * 1569783Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1669783Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1769783Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1869783Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1969783Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2069783Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2169783Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2269783Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2369783Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2469783Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2569783Smsmith * SUCH DAMAGE. 2669783Smsmith */ 2769783Smsmith 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/pci/pci_subr.c 224069 2011-07-15 21:08:58Z jhb $"); 30119418Sobrien 3169783Smsmith/* 32223520Sjhb * Support APIs for Host to PCI bridge drivers and drivers that 33223520Sjhb * provide PCI domains. 3469783Smsmith */ 3569783Smsmith 36224069Sjhb#include <sys/param.h> 37221393Sjhb#include <sys/bus.h> 38107546Simp#include <sys/rman.h> 39224069Sjhb#include <sys/systm.h> 4069783Smsmith 41223520Sjhb#include <dev/pci/pcireg.h> 42119285Simp#include <dev/pci/pcivar.h> 43119285Simp#include <dev/pci/pcib_private.h> 4469783Smsmith 4569783Smsmith/* 46107172Sjhb * Try to read the bus number of a host-PCI bridge using appropriate config 47107172Sjhb * registers. 48107172Sjhb */ 49107172Sjhbint 50107172Sjhbhost_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, 51119266Simp uint8_t *busnum) 52107172Sjhb{ 53119266Simp uint32_t id; 54107172Sjhb 55107172Sjhb id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); 56107248Sjhb if (id == 0xffffffff) 57107172Sjhb return (0); 58107172Sjhb 59107172Sjhb switch (id) { 60107172Sjhb case 0x12258086: 61107172Sjhb /* Intel 824?? */ 62107172Sjhb /* XXX This is a guess */ 63107172Sjhb /* *busnum = read_config(bus, slot, func, 0x41, 1); */ 64107172Sjhb *busnum = bus; 65107172Sjhb break; 66107172Sjhb case 0x84c48086: 67107172Sjhb /* Intel 82454KX/GX (Orion) */ 68107172Sjhb *busnum = read_config(bus, slot, func, 0x4a, 1); 69107172Sjhb break; 70107172Sjhb case 0x84ca8086: 71107172Sjhb /* 72107172Sjhb * For the 450nx chipset, there is a whole bundle of 73107172Sjhb * things pretending to be host bridges. The MIOC will 74107172Sjhb * be seen first and isn't really a pci bridge (the 75107172Sjhb * actual busses are attached to the PXB's). We need to 76107172Sjhb * read the registers of the MIOC to figure out the 77107172Sjhb * bus numbers for the PXB channels. 78107172Sjhb * 79107172Sjhb * Since the MIOC doesn't have a pci bus attached, we 80107172Sjhb * pretend it wasn't there. 81107172Sjhb */ 82107172Sjhb return (0); 83107172Sjhb case 0x84cb8086: 84107172Sjhb switch (slot) { 85107172Sjhb case 0x12: 86107172Sjhb /* Intel 82454NX PXB#0, Bus#A */ 87107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd0, 1); 88107172Sjhb break; 89107172Sjhb case 0x13: 90107172Sjhb /* Intel 82454NX PXB#0, Bus#B */ 91107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; 92107172Sjhb break; 93107172Sjhb case 0x14: 94107172Sjhb /* Intel 82454NX PXB#1, Bus#A */ 95107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd3, 1); 96107172Sjhb break; 97107172Sjhb case 0x15: 98107172Sjhb /* Intel 82454NX PXB#1, Bus#B */ 99107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; 100107172Sjhb break; 101107172Sjhb } 102107172Sjhb break; 103107172Sjhb 104107172Sjhb /* ServerWorks -- vendor 0x1166 */ 105107172Sjhb case 0x00051166: 106107172Sjhb case 0x00061166: 107107172Sjhb case 0x00081166: 108107172Sjhb case 0x00091166: 109107172Sjhb case 0x00101166: 110107172Sjhb case 0x00111166: 111107172Sjhb case 0x00171166: 112107172Sjhb case 0x01011166: 113107172Sjhb case 0x010f1014: 114215820Sjhb case 0x01101166: 115107172Sjhb case 0x02011166: 116215820Sjhb case 0x02251166: 117107172Sjhb case 0x03021014: 118107172Sjhb *busnum = read_config(bus, slot, func, 0x44, 1); 119107172Sjhb break; 120144110Sjhb 121144110Sjhb /* Compaq/HP -- vendor 0x0e11 */ 122144110Sjhb case 0x60100e11: 123144110Sjhb *busnum = read_config(bus, slot, func, 0xc8, 1); 124144110Sjhb break; 125107172Sjhb default: 126107172Sjhb /* Don't know how to read bus number. */ 127107172Sjhb return 0; 128107172Sjhb } 129107172Sjhb 130107172Sjhb return 1; 131107172Sjhb} 132224069Sjhb 133224069Sjhb#ifdef NEW_PCIB 134224069Sjhb/* 135224069Sjhb * Return a pointer to a pretty name for a PCI device. If the device 136224069Sjhb * has a driver attached, the device's name is used, otherwise a name 137224069Sjhb * is generated from the device's PCI address. 138224069Sjhb */ 139224069Sjhbconst char * 140224069Sjhbpcib_child_name(device_t child) 141224069Sjhb{ 142224069Sjhb static char buf[64]; 143224069Sjhb 144224069Sjhb if (device_get_nameunit(child) != NULL) 145224069Sjhb return (device_get_nameunit(child)); 146224069Sjhb snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), 147224069Sjhb pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); 148224069Sjhb return (buf); 149224069Sjhb} 150224069Sjhb 151224069Sjhb/* 152224069Sjhb * Some Host-PCI bridge drivers know which resource ranges they can 153224069Sjhb * decode and should only allocate subranges to child PCI devices. 154224069Sjhb * This API provides a way to manage this. The bridge drive should 155224069Sjhb * initialize this structure during attach and call 156224069Sjhb * pcib_host_res_decodes() on each resource range it decodes. It can 157224069Sjhb * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper 158224069Sjhb * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This 159224069Sjhb * API assumes that resources for any decoded ranges can be safely 160224069Sjhb * allocated from the parent via bus_generic_alloc_resource(). 161224069Sjhb */ 162224069Sjhbint 163224069Sjhbpcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) 164224069Sjhb{ 165224069Sjhb 166224069Sjhb hr->hr_pcib = pcib; 167224069Sjhb resource_list_init(&hr->hr_rl); 168224069Sjhb return (0); 169224069Sjhb} 170224069Sjhb 171224069Sjhbint 172224069Sjhbpcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) 173224069Sjhb{ 174224069Sjhb 175224069Sjhb resource_list_free(&hr->hr_rl); 176224069Sjhb return (0); 177224069Sjhb} 178224069Sjhb 179224069Sjhbint 180224069Sjhbpcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, 181224069Sjhb u_long end, u_int flags) 182224069Sjhb{ 183224069Sjhb struct resource_list_entry *rle; 184224069Sjhb int rid; 185224069Sjhb 186224069Sjhb if (bootverbose) 187224069Sjhb device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", 188224069Sjhb type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, 189224069Sjhb end); 190224069Sjhb rid = resource_list_add_next(&hr->hr_rl, type, start, end, 191224069Sjhb end - start + 1); 192224069Sjhb if (flags & RF_PREFETCHABLE) { 193224069Sjhb KASSERT(type == SYS_RES_MEMORY, 194224069Sjhb ("only memory is prefetchable")); 195224069Sjhb rle = resource_list_find(&hr->hr_rl, type, rid); 196224069Sjhb rle->flags = RLE_PREFETCH; 197224069Sjhb } 198224069Sjhb return (0); 199224069Sjhb} 200224069Sjhb 201224069Sjhbstruct resource * 202224069Sjhbpcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, 203224069Sjhb int *rid, u_long start, u_long end, u_long count, u_int flags) 204224069Sjhb{ 205224069Sjhb struct resource_list_entry *rle; 206224069Sjhb struct resource *r; 207224069Sjhb u_long new_start, new_end; 208224069Sjhb 209224069Sjhb if (flags & RF_PREFETCHABLE) 210224069Sjhb KASSERT(type == SYS_RES_MEMORY, 211224069Sjhb ("only memory is prefetchable")); 212224069Sjhb 213224069Sjhb rle = resource_list_find(&hr->hr_rl, type, 0); 214224069Sjhb if (rle == NULL) { 215224069Sjhb /* 216224069Sjhb * No decoding ranges for this resource type, just pass 217224069Sjhb * the request up to the parent. 218224069Sjhb */ 219224069Sjhb return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 220224069Sjhb start, end, count, flags)); 221224069Sjhb } 222224069Sjhb 223224069Sjhbrestart: 224224069Sjhb /* Try to allocate from each decoded range. */ 225224069Sjhb for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 226224069Sjhb if (rle->type != type) 227224069Sjhb continue; 228224069Sjhb if (((flags & RF_PREFETCHABLE) != 0) != 229224069Sjhb ((rle->flags & RLE_PREFETCH) != 0)) 230224069Sjhb continue; 231224069Sjhb new_start = ulmax(start, rle->start); 232224069Sjhb new_end = ulmin(end, rle->end); 233224069Sjhb if (new_start > new_end || 234224069Sjhb new_start + count - 1 > new_end || 235224069Sjhb new_start + count < new_start) 236224069Sjhb continue; 237224069Sjhb r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 238224069Sjhb new_start, new_end, count, flags); 239224069Sjhb if (r != NULL) { 240224069Sjhb if (bootverbose) 241224069Sjhb device_printf(hr->hr_pcib, 242224069Sjhb "allocated type %d (%#lx-%#lx) for rid %x of %s\n", 243224069Sjhb type, rman_get_start(r), rman_get_end(r), 244224069Sjhb *rid, pcib_child_name(dev)); 245224069Sjhb return (r); 246224069Sjhb } 247224069Sjhb } 248224069Sjhb 249224069Sjhb /* 250224069Sjhb * If we failed to find a prefetch range for a memory 251224069Sjhb * resource, try again without prefetch. 252224069Sjhb */ 253224069Sjhb if (flags & RF_PREFETCHABLE) { 254224069Sjhb flags &= ~RF_PREFETCHABLE; 255224069Sjhb rle = resource_list_find(&hr->hr_rl, type, 0); 256224069Sjhb goto restart; 257224069Sjhb } 258224069Sjhb return (NULL); 259224069Sjhb} 260224069Sjhb 261224069Sjhbint 262224069Sjhbpcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, 263224069Sjhb struct resource *r, u_long start, u_long end) 264224069Sjhb{ 265224069Sjhb struct resource_list_entry *rle; 266224069Sjhb 267224069Sjhb rle = resource_list_find(&hr->hr_rl, type, 0); 268224069Sjhb if (rle == NULL) { 269224069Sjhb /* 270224069Sjhb * No decoding ranges for this resource type, just pass 271224069Sjhb * the request up to the parent. 272224069Sjhb */ 273224069Sjhb return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, 274224069Sjhb start, end)); 275224069Sjhb } 276224069Sjhb 277224069Sjhb /* Only allow adjustments that stay within a decoded range. */ 278224069Sjhb for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 279224069Sjhb if (rle->start <= start && rle->end >= end) 280224069Sjhb return (bus_generic_adjust_resource(hr->hr_pcib, dev, 281224069Sjhb type, r, start, end)); 282224069Sjhb } 283224069Sjhb return (ERANGE); 284224069Sjhb} 285224069Sjhb#endif /* NEW_PCIB */ 286