pci_subr.c revision 261790
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 261790 2014-02-12 04:30:37Z 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> 38261790Sjhb#include <sys/malloc.h> 39107546Simp#include <sys/rman.h> 40224069Sjhb#include <sys/systm.h> 4169783Smsmith 42223520Sjhb#include <dev/pci/pcireg.h> 43119285Simp#include <dev/pci/pcivar.h> 44119285Simp#include <dev/pci/pcib_private.h> 4569783Smsmith 4669783Smsmith/* 47107172Sjhb * Try to read the bus number of a host-PCI bridge using appropriate config 48107172Sjhb * registers. 49107172Sjhb */ 50107172Sjhbint 51107172Sjhbhost_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, 52119266Simp uint8_t *busnum) 53107172Sjhb{ 54119266Simp uint32_t id; 55107172Sjhb 56107172Sjhb id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); 57107248Sjhb if (id == 0xffffffff) 58107172Sjhb return (0); 59107172Sjhb 60107172Sjhb switch (id) { 61107172Sjhb case 0x12258086: 62107172Sjhb /* Intel 824?? */ 63107172Sjhb /* XXX This is a guess */ 64107172Sjhb /* *busnum = read_config(bus, slot, func, 0x41, 1); */ 65107172Sjhb *busnum = bus; 66107172Sjhb break; 67107172Sjhb case 0x84c48086: 68107172Sjhb /* Intel 82454KX/GX (Orion) */ 69107172Sjhb *busnum = read_config(bus, slot, func, 0x4a, 1); 70107172Sjhb break; 71107172Sjhb case 0x84ca8086: 72107172Sjhb /* 73107172Sjhb * For the 450nx chipset, there is a whole bundle of 74107172Sjhb * things pretending to be host bridges. The MIOC will 75107172Sjhb * be seen first and isn't really a pci bridge (the 76107172Sjhb * actual busses are attached to the PXB's). We need to 77107172Sjhb * read the registers of the MIOC to figure out the 78107172Sjhb * bus numbers for the PXB channels. 79107172Sjhb * 80107172Sjhb * Since the MIOC doesn't have a pci bus attached, we 81107172Sjhb * pretend it wasn't there. 82107172Sjhb */ 83107172Sjhb return (0); 84107172Sjhb case 0x84cb8086: 85107172Sjhb switch (slot) { 86107172Sjhb case 0x12: 87107172Sjhb /* Intel 82454NX PXB#0, Bus#A */ 88107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd0, 1); 89107172Sjhb break; 90107172Sjhb case 0x13: 91107172Sjhb /* Intel 82454NX PXB#0, Bus#B */ 92107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; 93107172Sjhb break; 94107172Sjhb case 0x14: 95107172Sjhb /* Intel 82454NX PXB#1, Bus#A */ 96107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd3, 1); 97107172Sjhb break; 98107172Sjhb case 0x15: 99107172Sjhb /* Intel 82454NX PXB#1, Bus#B */ 100107248Sjhb *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; 101107172Sjhb break; 102107172Sjhb } 103107172Sjhb break; 104107172Sjhb 105107172Sjhb /* ServerWorks -- vendor 0x1166 */ 106107172Sjhb case 0x00051166: 107107172Sjhb case 0x00061166: 108107172Sjhb case 0x00081166: 109107172Sjhb case 0x00091166: 110107172Sjhb case 0x00101166: 111107172Sjhb case 0x00111166: 112107172Sjhb case 0x00171166: 113107172Sjhb case 0x01011166: 114107172Sjhb case 0x010f1014: 115215820Sjhb case 0x01101166: 116107172Sjhb case 0x02011166: 117215820Sjhb case 0x02251166: 118107172Sjhb case 0x03021014: 119107172Sjhb *busnum = read_config(bus, slot, func, 0x44, 1); 120107172Sjhb break; 121144110Sjhb 122144110Sjhb /* Compaq/HP -- vendor 0x0e11 */ 123144110Sjhb case 0x60100e11: 124144110Sjhb *busnum = read_config(bus, slot, func, 0xc8, 1); 125144110Sjhb break; 126107172Sjhb default: 127107172Sjhb /* Don't know how to read bus number. */ 128107172Sjhb return 0; 129107172Sjhb } 130107172Sjhb 131107172Sjhb return 1; 132107172Sjhb} 133224069Sjhb 134224069Sjhb#ifdef NEW_PCIB 135224069Sjhb/* 136224069Sjhb * Return a pointer to a pretty name for a PCI device. If the device 137224069Sjhb * has a driver attached, the device's name is used, otherwise a name 138224069Sjhb * is generated from the device's PCI address. 139224069Sjhb */ 140224069Sjhbconst char * 141224069Sjhbpcib_child_name(device_t child) 142224069Sjhb{ 143224069Sjhb static char buf[64]; 144224069Sjhb 145224069Sjhb if (device_get_nameunit(child) != NULL) 146224069Sjhb return (device_get_nameunit(child)); 147224069Sjhb snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), 148224069Sjhb pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); 149224069Sjhb return (buf); 150224069Sjhb} 151224069Sjhb 152224069Sjhb/* 153224069Sjhb * Some Host-PCI bridge drivers know which resource ranges they can 154224069Sjhb * decode and should only allocate subranges to child PCI devices. 155261523Sjhb * This API provides a way to manage this. The bridge driver should 156224069Sjhb * initialize this structure during attach and call 157224069Sjhb * pcib_host_res_decodes() on each resource range it decodes. It can 158224069Sjhb * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper 159224069Sjhb * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This 160224069Sjhb * API assumes that resources for any decoded ranges can be safely 161224069Sjhb * allocated from the parent via bus_generic_alloc_resource(). 162224069Sjhb */ 163224069Sjhbint 164224069Sjhbpcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) 165224069Sjhb{ 166224069Sjhb 167224069Sjhb hr->hr_pcib = pcib; 168224069Sjhb resource_list_init(&hr->hr_rl); 169224069Sjhb return (0); 170224069Sjhb} 171224069Sjhb 172224069Sjhbint 173224069Sjhbpcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) 174224069Sjhb{ 175224069Sjhb 176224069Sjhb resource_list_free(&hr->hr_rl); 177224069Sjhb return (0); 178224069Sjhb} 179224069Sjhb 180224069Sjhbint 181224069Sjhbpcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, 182224069Sjhb u_long end, u_int flags) 183224069Sjhb{ 184224069Sjhb struct resource_list_entry *rle; 185224069Sjhb int rid; 186224069Sjhb 187224069Sjhb if (bootverbose) 188224069Sjhb device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", 189224069Sjhb type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, 190224069Sjhb end); 191224069Sjhb rid = resource_list_add_next(&hr->hr_rl, type, start, end, 192224069Sjhb end - start + 1); 193224069Sjhb if (flags & RF_PREFETCHABLE) { 194224069Sjhb KASSERT(type == SYS_RES_MEMORY, 195224069Sjhb ("only memory is prefetchable")); 196224069Sjhb rle = resource_list_find(&hr->hr_rl, type, rid); 197224069Sjhb rle->flags = RLE_PREFETCH; 198224069Sjhb } 199224069Sjhb return (0); 200224069Sjhb} 201224069Sjhb 202224069Sjhbstruct resource * 203224069Sjhbpcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, 204224069Sjhb int *rid, u_long start, u_long end, u_long count, u_int flags) 205224069Sjhb{ 206224069Sjhb struct resource_list_entry *rle; 207224069Sjhb struct resource *r; 208224069Sjhb u_long new_start, new_end; 209224069Sjhb 210224069Sjhb if (flags & RF_PREFETCHABLE) 211224069Sjhb KASSERT(type == SYS_RES_MEMORY, 212224069Sjhb ("only memory is prefetchable")); 213224069Sjhb 214224069Sjhb rle = resource_list_find(&hr->hr_rl, type, 0); 215224069Sjhb if (rle == NULL) { 216224069Sjhb /* 217224069Sjhb * No decoding ranges for this resource type, just pass 218224069Sjhb * the request up to the parent. 219224069Sjhb */ 220224069Sjhb return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 221224069Sjhb start, end, count, flags)); 222224069Sjhb } 223224069Sjhb 224224069Sjhbrestart: 225224069Sjhb /* Try to allocate from each decoded range. */ 226224069Sjhb for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 227224069Sjhb if (rle->type != type) 228224069Sjhb continue; 229224069Sjhb if (((flags & RF_PREFETCHABLE) != 0) != 230224069Sjhb ((rle->flags & RLE_PREFETCH) != 0)) 231224069Sjhb continue; 232224069Sjhb new_start = ulmax(start, rle->start); 233224069Sjhb new_end = ulmin(end, rle->end); 234224069Sjhb if (new_start > new_end || 235224069Sjhb new_start + count - 1 > new_end || 236224069Sjhb new_start + count < new_start) 237224069Sjhb continue; 238224069Sjhb r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 239224069Sjhb new_start, new_end, count, flags); 240224069Sjhb if (r != NULL) { 241224069Sjhb if (bootverbose) 242224069Sjhb device_printf(hr->hr_pcib, 243224069Sjhb "allocated type %d (%#lx-%#lx) for rid %x of %s\n", 244224069Sjhb type, rman_get_start(r), rman_get_end(r), 245224069Sjhb *rid, pcib_child_name(dev)); 246224069Sjhb return (r); 247224069Sjhb } 248224069Sjhb } 249224069Sjhb 250224069Sjhb /* 251224069Sjhb * If we failed to find a prefetch range for a memory 252224069Sjhb * resource, try again without prefetch. 253224069Sjhb */ 254224069Sjhb if (flags & RF_PREFETCHABLE) { 255224069Sjhb flags &= ~RF_PREFETCHABLE; 256224069Sjhb rle = resource_list_find(&hr->hr_rl, type, 0); 257224069Sjhb goto restart; 258224069Sjhb } 259224069Sjhb return (NULL); 260224069Sjhb} 261224069Sjhb 262224069Sjhbint 263224069Sjhbpcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, 264224069Sjhb struct resource *r, u_long start, u_long end) 265224069Sjhb{ 266224069Sjhb struct resource_list_entry *rle; 267224069Sjhb 268224069Sjhb rle = resource_list_find(&hr->hr_rl, type, 0); 269224069Sjhb if (rle == NULL) { 270224069Sjhb /* 271224069Sjhb * No decoding ranges for this resource type, just pass 272224069Sjhb * the request up to the parent. 273224069Sjhb */ 274224069Sjhb return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, 275224069Sjhb start, end)); 276224069Sjhb } 277224069Sjhb 278224069Sjhb /* Only allow adjustments that stay within a decoded range. */ 279224069Sjhb for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 280224069Sjhb if (rle->start <= start && rle->end >= end) 281224069Sjhb return (bus_generic_adjust_resource(hr->hr_pcib, dev, 282224069Sjhb type, r, start, end)); 283224069Sjhb } 284224069Sjhb return (ERANGE); 285224069Sjhb} 286261790Sjhb 287261790Sjhb#ifdef PCI_RES_BUS 288261790Sjhbstruct pci_domain { 289261790Sjhb int pd_domain; 290261790Sjhb struct rman pd_bus_rman; 291261790Sjhb TAILQ_ENTRY(pci_domain) pd_link; 292261790Sjhb}; 293261790Sjhb 294261790Sjhbstatic TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains); 295261790Sjhb 296261790Sjhb/* 297261790Sjhb * Each PCI domain maintains its own resource manager for PCI bus 298261790Sjhb * numbers in that domain. Domain objects are created on first use. 299261790Sjhb * Host to PCI bridge drivers and PCI-PCI bridge drivers should 300261790Sjhb * allocate their bus ranges from their domain. 301261790Sjhb */ 302261790Sjhbstatic struct pci_domain * 303261790Sjhbpci_find_domain(int domain) 304261790Sjhb{ 305261790Sjhb struct pci_domain *d; 306261790Sjhb char buf[64]; 307261790Sjhb int error; 308261790Sjhb 309261790Sjhb TAILQ_FOREACH(d, &domains, pd_link) { 310261790Sjhb if (d->pd_domain == domain) 311261790Sjhb return (d); 312261790Sjhb } 313261790Sjhb 314261790Sjhb snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain); 315261790Sjhb d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO); 316261790Sjhb d->pd_domain = domain; 317261790Sjhb d->pd_bus_rman.rm_start = 0; 318261790Sjhb d->pd_bus_rman.rm_end = PCI_BUSMAX; 319261790Sjhb d->pd_bus_rman.rm_type = RMAN_ARRAY; 320261790Sjhb strcpy((char *)(d + 1), buf); 321261790Sjhb d->pd_bus_rman.rm_descr = (char *)(d + 1); 322261790Sjhb error = rman_init(&d->pd_bus_rman); 323261790Sjhb if (error == 0) 324261790Sjhb error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX); 325261790Sjhb if (error) 326261790Sjhb panic("Failed to initialize PCI domain %d rman", domain); 327261790Sjhb TAILQ_INSERT_TAIL(&domains, d, pd_link); 328261790Sjhb return (d); 329261790Sjhb} 330261790Sjhb 331261790Sjhbstruct resource * 332261790Sjhbpci_domain_alloc_bus(int domain, device_t dev, int *rid, u_long start, 333261790Sjhb u_long end, u_long count, u_int flags) 334261790Sjhb{ 335261790Sjhb struct pci_domain *d; 336261790Sjhb struct resource *res; 337261790Sjhb 338261790Sjhb if (domain < 0 || domain > PCI_DOMAINMAX) 339261790Sjhb return (NULL); 340261790Sjhb d = pci_find_domain(domain); 341261790Sjhb res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags, 342261790Sjhb dev); 343261790Sjhb if (res == NULL) 344261790Sjhb return (NULL); 345261790Sjhb 346261790Sjhb rman_set_rid(res, *rid); 347261790Sjhb return (res); 348261790Sjhb} 349261790Sjhb 350261790Sjhbint 351261790Sjhbpci_domain_adjust_bus(int domain, device_t dev, struct resource *r, 352261790Sjhb u_long start, u_long end) 353261790Sjhb{ 354261790Sjhb#ifdef INVARIANTS 355261790Sjhb struct pci_domain *d; 356261790Sjhb#endif 357261790Sjhb 358261790Sjhb if (domain < 0 || domain > PCI_DOMAINMAX) 359261790Sjhb return (EINVAL); 360261790Sjhb#ifdef INVARIANTS 361261790Sjhb d = pci_find_domain(domain); 362261790Sjhb KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource")); 363261790Sjhb#endif 364261790Sjhb return (rman_adjust_resource(r, start, end)); 365261790Sjhb} 366261790Sjhb 367261790Sjhbint 368261790Sjhbpci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r) 369261790Sjhb{ 370261790Sjhb#ifdef INVARIANTS 371261790Sjhb struct pci_domain *d; 372261790Sjhb#endif 373261790Sjhb 374261790Sjhb if (domain < 0 || domain > PCI_DOMAINMAX) 375261790Sjhb return (EINVAL); 376261790Sjhb#ifdef INVARIANTS 377261790Sjhb d = pci_find_domain(domain); 378261790Sjhb KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource")); 379261790Sjhb#endif 380261790Sjhb return (rman_release_resource(r)); 381261790Sjhb} 382261790Sjhb#endif /* PCI_RES_BUS */ 383261790Sjhb 384224069Sjhb#endif /* NEW_PCIB */ 385