10dbe859dSJohn Baldwin /*- 20dbe859dSJohn Baldwin * Copyright (c) 2011 Advanced Computing Technologies LLC 30dbe859dSJohn Baldwin * Written by: John H. Baldwin <jhb@FreeBSD.org> 40dbe859dSJohn Baldwin * All rights reserved. 50dbe859dSJohn Baldwin * 60dbe859dSJohn Baldwin * Redistribution and use in source and binary forms, with or without 70dbe859dSJohn Baldwin * modification, are permitted provided that the following conditions 80dbe859dSJohn Baldwin * are met: 90dbe859dSJohn Baldwin * 1. Redistributions of source code must retain the above copyright 100dbe859dSJohn Baldwin * notice, this list of conditions and the following disclaimer. 110dbe859dSJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 120dbe859dSJohn Baldwin * notice, this list of conditions and the following disclaimer in the 130dbe859dSJohn Baldwin * documentation and/or other materials provided with the distribution. 140dbe859dSJohn Baldwin * 150dbe859dSJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 160dbe859dSJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 170dbe859dSJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 180dbe859dSJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 190dbe859dSJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 200dbe859dSJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 210dbe859dSJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 220dbe859dSJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 230dbe859dSJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 240dbe859dSJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 250dbe859dSJohn Baldwin * SUCH DAMAGE. 260dbe859dSJohn Baldwin */ 270dbe859dSJohn Baldwin 280dbe859dSJohn Baldwin #include <sys/cdefs.h> 290dbe859dSJohn Baldwin __FBSDID("$FreeBSD$"); 300dbe859dSJohn Baldwin 310dbe859dSJohn Baldwin /* 320dbe859dSJohn Baldwin * Support APIs for Host to PCI bridge drivers and drivers that 330dbe859dSJohn Baldwin * provide PCI domains. 340dbe859dSJohn Baldwin */ 350dbe859dSJohn Baldwin 36*34ff71eeSJohn Baldwin #include <sys/param.h> 370dbe859dSJohn Baldwin #include <sys/bus.h> 380dbe859dSJohn Baldwin #include <sys/rman.h> 39*34ff71eeSJohn Baldwin #include <sys/systm.h> 400dbe859dSJohn Baldwin 410dbe859dSJohn Baldwin #include <dev/pci/pcireg.h> 420dbe859dSJohn Baldwin #include <dev/pci/pcivar.h> 430dbe859dSJohn Baldwin #include <dev/pci/pcib_private.h> 440dbe859dSJohn Baldwin 450dbe859dSJohn Baldwin /* 460dbe859dSJohn Baldwin * Try to read the bus number of a host-PCI bridge using appropriate config 470dbe859dSJohn Baldwin * registers. 480dbe859dSJohn Baldwin */ 490dbe859dSJohn Baldwin int 500dbe859dSJohn Baldwin host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, 510dbe859dSJohn Baldwin uint8_t *busnum) 520dbe859dSJohn Baldwin { 530dbe859dSJohn Baldwin uint32_t id; 540dbe859dSJohn Baldwin 550dbe859dSJohn Baldwin id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); 560dbe859dSJohn Baldwin if (id == 0xffffffff) 570dbe859dSJohn Baldwin return (0); 580dbe859dSJohn Baldwin 590dbe859dSJohn Baldwin switch (id) { 600dbe859dSJohn Baldwin case 0x12258086: 610dbe859dSJohn Baldwin /* Intel 824?? */ 620dbe859dSJohn Baldwin /* XXX This is a guess */ 630dbe859dSJohn Baldwin /* *busnum = read_config(bus, slot, func, 0x41, 1); */ 640dbe859dSJohn Baldwin *busnum = bus; 650dbe859dSJohn Baldwin break; 660dbe859dSJohn Baldwin case 0x84c48086: 670dbe859dSJohn Baldwin /* Intel 82454KX/GX (Orion) */ 680dbe859dSJohn Baldwin *busnum = read_config(bus, slot, func, 0x4a, 1); 690dbe859dSJohn Baldwin break; 700dbe859dSJohn Baldwin case 0x84ca8086: 710dbe859dSJohn Baldwin /* 720dbe859dSJohn Baldwin * For the 450nx chipset, there is a whole bundle of 730dbe859dSJohn Baldwin * things pretending to be host bridges. The MIOC will 740dbe859dSJohn Baldwin * be seen first and isn't really a pci bridge (the 750dbe859dSJohn Baldwin * actual busses are attached to the PXB's). We need to 760dbe859dSJohn Baldwin * read the registers of the MIOC to figure out the 770dbe859dSJohn Baldwin * bus numbers for the PXB channels. 780dbe859dSJohn Baldwin * 790dbe859dSJohn Baldwin * Since the MIOC doesn't have a pci bus attached, we 800dbe859dSJohn Baldwin * pretend it wasn't there. 810dbe859dSJohn Baldwin */ 820dbe859dSJohn Baldwin return (0); 830dbe859dSJohn Baldwin case 0x84cb8086: 840dbe859dSJohn Baldwin switch (slot) { 850dbe859dSJohn Baldwin case 0x12: 860dbe859dSJohn Baldwin /* Intel 82454NX PXB#0, Bus#A */ 870dbe859dSJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd0, 1); 880dbe859dSJohn Baldwin break; 890dbe859dSJohn Baldwin case 0x13: 900dbe859dSJohn Baldwin /* Intel 82454NX PXB#0, Bus#B */ 910dbe859dSJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; 920dbe859dSJohn Baldwin break; 930dbe859dSJohn Baldwin case 0x14: 940dbe859dSJohn Baldwin /* Intel 82454NX PXB#1, Bus#A */ 950dbe859dSJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd3, 1); 960dbe859dSJohn Baldwin break; 970dbe859dSJohn Baldwin case 0x15: 980dbe859dSJohn Baldwin /* Intel 82454NX PXB#1, Bus#B */ 990dbe859dSJohn Baldwin *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; 1000dbe859dSJohn Baldwin break; 1010dbe859dSJohn Baldwin } 1020dbe859dSJohn Baldwin break; 1030dbe859dSJohn Baldwin 1040dbe859dSJohn Baldwin /* ServerWorks -- vendor 0x1166 */ 1050dbe859dSJohn Baldwin case 0x00051166: 1060dbe859dSJohn Baldwin case 0x00061166: 1070dbe859dSJohn Baldwin case 0x00081166: 1080dbe859dSJohn Baldwin case 0x00091166: 1090dbe859dSJohn Baldwin case 0x00101166: 1100dbe859dSJohn Baldwin case 0x00111166: 1110dbe859dSJohn Baldwin case 0x00171166: 1120dbe859dSJohn Baldwin case 0x01011166: 1130dbe859dSJohn Baldwin case 0x010f1014: 1140dbe859dSJohn Baldwin case 0x01101166: 1150dbe859dSJohn Baldwin case 0x02011166: 1160dbe859dSJohn Baldwin case 0x02251166: 1170dbe859dSJohn Baldwin case 0x03021014: 1180dbe859dSJohn Baldwin *busnum = read_config(bus, slot, func, 0x44, 1); 1190dbe859dSJohn Baldwin break; 1200dbe859dSJohn Baldwin 1210dbe859dSJohn Baldwin /* Compaq/HP -- vendor 0x0e11 */ 1220dbe859dSJohn Baldwin case 0x60100e11: 1230dbe859dSJohn Baldwin *busnum = read_config(bus, slot, func, 0xc8, 1); 1240dbe859dSJohn Baldwin break; 1250dbe859dSJohn Baldwin default: 1260dbe859dSJohn Baldwin /* Don't know how to read bus number. */ 1270dbe859dSJohn Baldwin return 0; 1280dbe859dSJohn Baldwin } 1290dbe859dSJohn Baldwin 1300dbe859dSJohn Baldwin return 1; 1310dbe859dSJohn Baldwin } 132*34ff71eeSJohn Baldwin 133*34ff71eeSJohn Baldwin #ifdef NEW_PCIB 134*34ff71eeSJohn Baldwin /* 135*34ff71eeSJohn Baldwin * Return a pointer to a pretty name for a PCI device. If the device 136*34ff71eeSJohn Baldwin * has a driver attached, the device's name is used, otherwise a name 137*34ff71eeSJohn Baldwin * is generated from the device's PCI address. 138*34ff71eeSJohn Baldwin */ 139*34ff71eeSJohn Baldwin const char * 140*34ff71eeSJohn Baldwin pcib_child_name(device_t child) 141*34ff71eeSJohn Baldwin { 142*34ff71eeSJohn Baldwin static char buf[64]; 143*34ff71eeSJohn Baldwin 144*34ff71eeSJohn Baldwin if (device_get_nameunit(child) != NULL) 145*34ff71eeSJohn Baldwin return (device_get_nameunit(child)); 146*34ff71eeSJohn Baldwin snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), 147*34ff71eeSJohn Baldwin pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); 148*34ff71eeSJohn Baldwin return (buf); 149*34ff71eeSJohn Baldwin } 150*34ff71eeSJohn Baldwin 151*34ff71eeSJohn Baldwin /* 152*34ff71eeSJohn Baldwin * Some Host-PCI bridge drivers know which resource ranges they can 153*34ff71eeSJohn Baldwin * decode and should only allocate subranges to child PCI devices. 154*34ff71eeSJohn Baldwin * This API provides a way to manage this. The bridge drive should 155*34ff71eeSJohn Baldwin * initialize this structure during attach and call 156*34ff71eeSJohn Baldwin * pcib_host_res_decodes() on each resource range it decodes. It can 157*34ff71eeSJohn Baldwin * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper 158*34ff71eeSJohn Baldwin * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This 159*34ff71eeSJohn Baldwin * API assumes that resources for any decoded ranges can be safely 160*34ff71eeSJohn Baldwin * allocated from the parent via bus_generic_alloc_resource(). 161*34ff71eeSJohn Baldwin */ 162*34ff71eeSJohn Baldwin int 163*34ff71eeSJohn Baldwin pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) 164*34ff71eeSJohn Baldwin { 165*34ff71eeSJohn Baldwin 166*34ff71eeSJohn Baldwin hr->hr_pcib = pcib; 167*34ff71eeSJohn Baldwin resource_list_init(&hr->hr_rl); 168*34ff71eeSJohn Baldwin return (0); 169*34ff71eeSJohn Baldwin } 170*34ff71eeSJohn Baldwin 171*34ff71eeSJohn Baldwin int 172*34ff71eeSJohn Baldwin pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) 173*34ff71eeSJohn Baldwin { 174*34ff71eeSJohn Baldwin 175*34ff71eeSJohn Baldwin resource_list_free(&hr->hr_rl); 176*34ff71eeSJohn Baldwin return (0); 177*34ff71eeSJohn Baldwin } 178*34ff71eeSJohn Baldwin 179*34ff71eeSJohn Baldwin int 180*34ff71eeSJohn Baldwin pcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, 181*34ff71eeSJohn Baldwin u_long end, u_int flags) 182*34ff71eeSJohn Baldwin { 183*34ff71eeSJohn Baldwin struct resource_list_entry *rle; 184*34ff71eeSJohn Baldwin int rid; 185*34ff71eeSJohn Baldwin 186*34ff71eeSJohn Baldwin if (bootverbose) 187*34ff71eeSJohn Baldwin device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", 188*34ff71eeSJohn Baldwin type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, 189*34ff71eeSJohn Baldwin end); 190*34ff71eeSJohn Baldwin rid = resource_list_add_next(&hr->hr_rl, type, start, end, 191*34ff71eeSJohn Baldwin end - start + 1); 192*34ff71eeSJohn Baldwin if (flags & RF_PREFETCHABLE) { 193*34ff71eeSJohn Baldwin KASSERT(type == SYS_RES_MEMORY, 194*34ff71eeSJohn Baldwin ("only memory is prefetchable")); 195*34ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, rid); 196*34ff71eeSJohn Baldwin rle->flags = RLE_PREFETCH; 197*34ff71eeSJohn Baldwin } 198*34ff71eeSJohn Baldwin return (0); 199*34ff71eeSJohn Baldwin } 200*34ff71eeSJohn Baldwin 201*34ff71eeSJohn Baldwin struct resource * 202*34ff71eeSJohn Baldwin pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, 203*34ff71eeSJohn Baldwin int *rid, u_long start, u_long end, u_long count, u_int flags) 204*34ff71eeSJohn Baldwin { 205*34ff71eeSJohn Baldwin struct resource_list_entry *rle; 206*34ff71eeSJohn Baldwin struct resource *r; 207*34ff71eeSJohn Baldwin u_long new_start, new_end; 208*34ff71eeSJohn Baldwin 209*34ff71eeSJohn Baldwin if (flags & RF_PREFETCHABLE) 210*34ff71eeSJohn Baldwin KASSERT(type == SYS_RES_MEMORY, 211*34ff71eeSJohn Baldwin ("only memory is prefetchable")); 212*34ff71eeSJohn Baldwin 213*34ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, 0); 214*34ff71eeSJohn Baldwin if (rle == NULL) { 215*34ff71eeSJohn Baldwin /* 216*34ff71eeSJohn Baldwin * No decoding ranges for this resource type, just pass 217*34ff71eeSJohn Baldwin * the request up to the parent. 218*34ff71eeSJohn Baldwin */ 219*34ff71eeSJohn Baldwin return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 220*34ff71eeSJohn Baldwin start, end, count, flags)); 221*34ff71eeSJohn Baldwin } 222*34ff71eeSJohn Baldwin 223*34ff71eeSJohn Baldwin restart: 224*34ff71eeSJohn Baldwin /* Try to allocate from each decoded range. */ 225*34ff71eeSJohn Baldwin for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 226*34ff71eeSJohn Baldwin if (rle->type != type) 227*34ff71eeSJohn Baldwin continue; 228*34ff71eeSJohn Baldwin if (((flags & RF_PREFETCHABLE) != 0) != 229*34ff71eeSJohn Baldwin ((rle->flags & RLE_PREFETCH) != 0)) 230*34ff71eeSJohn Baldwin continue; 231*34ff71eeSJohn Baldwin new_start = ulmax(start, rle->start); 232*34ff71eeSJohn Baldwin new_end = ulmin(end, rle->end); 233*34ff71eeSJohn Baldwin if (new_start > new_end || 234*34ff71eeSJohn Baldwin new_start + count - 1 > new_end || 235*34ff71eeSJohn Baldwin new_start + count < new_start) 236*34ff71eeSJohn Baldwin continue; 237*34ff71eeSJohn Baldwin r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 238*34ff71eeSJohn Baldwin new_start, new_end, count, flags); 239*34ff71eeSJohn Baldwin if (r != NULL) { 240*34ff71eeSJohn Baldwin if (bootverbose) 241*34ff71eeSJohn Baldwin device_printf(hr->hr_pcib, 242*34ff71eeSJohn Baldwin "allocated type %d (%#lx-%#lx) for rid %x of %s\n", 243*34ff71eeSJohn Baldwin type, rman_get_start(r), rman_get_end(r), 244*34ff71eeSJohn Baldwin *rid, pcib_child_name(dev)); 245*34ff71eeSJohn Baldwin return (r); 246*34ff71eeSJohn Baldwin } 247*34ff71eeSJohn Baldwin } 248*34ff71eeSJohn Baldwin 249*34ff71eeSJohn Baldwin /* 250*34ff71eeSJohn Baldwin * If we failed to find a prefetch range for a memory 251*34ff71eeSJohn Baldwin * resource, try again without prefetch. 252*34ff71eeSJohn Baldwin */ 253*34ff71eeSJohn Baldwin if (flags & RF_PREFETCHABLE) { 254*34ff71eeSJohn Baldwin flags &= ~RF_PREFETCHABLE; 255*34ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, 0); 256*34ff71eeSJohn Baldwin goto restart; 257*34ff71eeSJohn Baldwin } 258*34ff71eeSJohn Baldwin return (NULL); 259*34ff71eeSJohn Baldwin } 260*34ff71eeSJohn Baldwin 261*34ff71eeSJohn Baldwin int 262*34ff71eeSJohn Baldwin pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, 263*34ff71eeSJohn Baldwin struct resource *r, u_long start, u_long end) 264*34ff71eeSJohn Baldwin { 265*34ff71eeSJohn Baldwin struct resource_list_entry *rle; 266*34ff71eeSJohn Baldwin 267*34ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, 0); 268*34ff71eeSJohn Baldwin if (rle == NULL) { 269*34ff71eeSJohn Baldwin /* 270*34ff71eeSJohn Baldwin * No decoding ranges for this resource type, just pass 271*34ff71eeSJohn Baldwin * the request up to the parent. 272*34ff71eeSJohn Baldwin */ 273*34ff71eeSJohn Baldwin return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, 274*34ff71eeSJohn Baldwin start, end)); 275*34ff71eeSJohn Baldwin } 276*34ff71eeSJohn Baldwin 277*34ff71eeSJohn Baldwin /* Only allow adjustments that stay within a decoded range. */ 278*34ff71eeSJohn Baldwin for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 279*34ff71eeSJohn Baldwin if (rle->start <= start && rle->end >= end) 280*34ff71eeSJohn Baldwin return (bus_generic_adjust_resource(hr->hr_pcib, dev, 281*34ff71eeSJohn Baldwin type, r, start, end)); 282*34ff71eeSJohn Baldwin } 283*34ff71eeSJohn Baldwin return (ERANGE); 284*34ff71eeSJohn Baldwin } 285*34ff71eeSJohn Baldwin #endif /* NEW_PCIB */ 286