pci_subr.c revision 261523
1191005Sdelphij/*- 231899Ssef * Copyright (c) 2011 Advanced Computing Technologies LLC 331899Ssef * Written by: John H. Baldwin <jhb@FreeBSD.org> 431899Ssef * All rights reserved. 531899Ssef * 631899Ssef * Redistribution and use in source and binary forms, with or without 731899Ssef * modification, are permitted provided that the following conditions 831899Ssef * are met: 931899Ssef * 1. Redistributions of source code must retain the above copyright 1031899Ssef * notice, this list of conditions and the following disclaimer. 1131899Ssef * 2. Redistributions in binary form must reproduce the above copyright 1231899Ssef * notice, this list of conditions and the following disclaimer in the 1331899Ssef * documentation and/or other materials provided with the distribution. 1431899Ssef * 1531899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1631899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1731899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1831899Ssef * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1931899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2031899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2131899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2231899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2331899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2431899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2531899Ssef * SUCH DAMAGE. 2631899Ssef */ 2731899Ssef 2831899Ssef#include <sys/cdefs.h> 2931899Ssef__FBSDID("$FreeBSD: head/sys/dev/pci/pci_subr.c 261523 2014-02-05 19:23:05Z jhb $"); 3031899Ssef 3131899Ssef/* 32119852Scharnier * Support APIs for Host to PCI bridge drivers and drivers that 33119852Scharnier * provide PCI domains. 3432275Scharnier */ 3531899Ssef 3631567Ssef#include <sys/param.h> 3731567Ssef#include <sys/bus.h> 3831567Ssef#include <sys/rman.h> 3931567Ssef#include <sys/systm.h> 4031567Ssef 4185301Sdes#include <dev/pci/pcireg.h> 42123916Scracauer#include <dev/pci/pcivar.h> 43104581Smike#include <dev/pci/pcib_private.h> 44123916Scracauer 45168569Sdelphij/* 46191005Sdelphij * Try to read the bus number of a host-PCI bridge using appropriate config 4785301Sdes * registers. 48132306Salfred */ 4932275Scharnierint 5032275Scharnierhost_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, 5132275Scharnier uint8_t *busnum) 5232275Scharnier{ 5331567Ssef uint32_t id; 5431567Ssef 5531567Ssef id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); 56101423Smdodd if (id == 0xffffffff) 5731579Speter return (0); 5831567Ssef 59101282Smdodd switch (id) { 6087703Smarkm case 0x12258086: 6131567Ssef /* Intel 824?? */ 62171645Smarcel /* XXX This is a guess */ 6331567Ssef /* *busnum = read_config(bus, slot, func, 0x41, 1); */ 64144177Salfred *busnum = bus; 6532275Scharnier break; 6632275Scharnier case 0x84c48086: 67144177Salfred /* Intel 82454KX/GX (Orion) */ 68153963Sbrian *busnum = read_config(bus, slot, func, 0x4a, 1); 69153963Sbrian break; 70144177Salfred case 0x84ca8086: 7131567Ssef /* 7231567Ssef * For the 450nx chipset, there is a whole bundle of 7338897Ssef * things pretending to be host bridges. The MIOC will 7438897Ssef * be seen first and isn't really a pci bridge (the 7538897Ssef * actual busses are attached to the PXB's). We need to 7638897Ssef * read the registers of the MIOC to figure out the 7731567Ssef * bus numbers for the PXB channels. 78144177Salfred * 79144177Salfred * Since the MIOC doesn't have a pci bus attached, we 80144177Salfred * pretend it wasn't there. 8131567Ssef */ 82130394Sdwmalone return (0); 83144177Salfred case 0x84cb8086: 84179051Sjhb switch (slot) { 85179051Sjhb case 0x12: 86130394Sdwmalone /* Intel 82454NX PXB#0, Bus#A */ 8739908Ssef *busnum = read_config(bus, 0x10, func, 0xd0, 1); 88144177Salfred break; 89144177Salfred case 0x13: 90144177Salfred /* Intel 82454NX PXB#0, Bus#B */ 91144177Salfred *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; 9239908Ssef break; 93106716Smarcel case 0x14: 94144177Salfred /* Intel 82454NX PXB#1, Bus#A */ 95106716Smarcel *busnum = read_config(bus, 0x10, func, 0xd3, 1); 96154047Sgrehan break; 97154047Sgrehan case 0x15: 98154047Sgrehan /* Intel 82454NX PXB#1, Bus#B */ 99154047Sgrehan *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; 100101320Sjake break; 101144177Salfred } 102101320Sjake break; 103188628Simp 104188628Simp /* ServerWorks -- vendor 0x1166 */ 105188628Simp case 0x00051166: 106188628Simp case 0x00061166: 107188628Simp case 0x00081166: 108144177Salfred case 0x00091166: 10931567Ssef case 0x00101166: 11031567Ssef case 0x00111166: 11131567Ssef case 0x00171166: 11231567Ssef case 0x01011166: 113168569Sdelphij case 0x010f1014: 11431567Ssef case 0x01101166: 11531567Ssef case 0x02011166: 11631567Ssef case 0x02251166: 117144177Salfred case 0x03021014: 118144177Salfred *busnum = read_config(bus, slot, func, 0x44, 1); 119144177Salfred break; 120144177Salfred 121168569Sdelphij /* Compaq/HP -- vendor 0x0e11 */ 122168569Sdelphij case 0x60100e11: 123168569Sdelphij *busnum = read_config(bus, slot, func, 0xc8, 1); 124168569Sdelphij break; 12531567Ssef default: 126168569Sdelphij /* Don't know how to read bus number. */ 127168569Sdelphij return 0; 128168569Sdelphij } 129168569Sdelphij 130168569Sdelphij return 1; 131168569Sdelphij} 132168569Sdelphij 13331567Ssef#ifdef NEW_PCIB 134144177Salfred/* 135144177Salfred * Return a pointer to a pretty name for a PCI device. If the device 136144177Salfred * has a driver attached, the device's name is used, otherwise a name 13731567Ssef * is generated from the device's PCI address. 138144177Salfred */ 139144177Salfredconst char * 140144177Salfredpcib_child_name(device_t child) 141144177Salfred{ 142144177Salfred static char buf[64]; 143144177Salfred 14431567Ssef if (device_get_nameunit(child) != NULL) 14531567Ssef return (device_get_nameunit(child)); 146132306Salfred snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), 147132306Salfred pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); 148132306Salfred return (buf); 149132306Salfred} 150132306Salfred 151132306Salfred/* 152132306Salfred * Some Host-PCI bridge drivers know which resource ranges they can 153132306Salfred * decode and should only allocate subranges to child PCI devices. 154132306Salfred * This API provides a way to manage this. The bridge driver should 155132306Salfred * initialize this structure during attach and call 156132306Salfred * pcib_host_res_decodes() on each resource range it decodes. It can 157132306Salfred * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper 158132306Salfred * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This 159132306Salfred * API assumes that resources for any decoded ranges can be safely 160132306Salfred * allocated from the parent via bus_generic_alloc_resource(). 161132306Salfred */ 162132306Salfredint 16332275Scharnierpcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) 164144177Salfred{ 165144177Salfred 166144177Salfred hr->hr_pcib = pcib; 167144177Salfred resource_list_init(&hr->hr_rl); 168191005Sdelphij return (0); 169191005Sdelphij} 170144177Salfred 171144177Salfredint 172171055Sdelphijpcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) 173144178Salfred{ 174144177Salfred 175144177Salfred resource_list_free(&hr->hr_rl); 17631567Ssef return (0); 177144178Salfred} 178144178Salfred 179144178Salfredint 180144177Salfredpcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, 181144177Salfred u_long end, u_int flags) 182144177Salfred{ 183144177Salfred struct resource_list_entry *rle; 184144177Salfred int rid; 185168569Sdelphij 186144177Salfred if (bootverbose) 187153963Sbrian device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", 188168569Sdelphij type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, 189168569Sdelphij end); 190168569Sdelphij rid = resource_list_add_next(&hr->hr_rl, type, start, end, 191153963Sbrian end - start + 1); 192144177Salfred if (flags & RF_PREFETCHABLE) { 193144177Salfred KASSERT(type == SYS_RES_MEMORY, 194144177Salfred ("only memory is prefetchable")); 195171055Sdelphij rle = resource_list_find(&hr->hr_rl, type, rid); 196171055Sdelphij rle->flags = RLE_PREFETCH; 197171055Sdelphij } 198171055Sdelphij return (0); 199171055Sdelphij} 200144177Salfred 201144177Salfredstruct resource * 202144177Salfredpcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, 203144177Salfred int *rid, u_long start, u_long end, u_long count, u_int flags) 204144177Salfred{ 205144177Salfred struct resource_list_entry *rle; 206144177Salfred struct resource *r; 207144177Salfred u_long new_start, new_end; 208144177Salfred 209144177Salfred if (flags & RF_PREFETCHABLE) 210144177Salfred KASSERT(type == SYS_RES_MEMORY, 211144177Salfred ("only memory is prefetchable")); 212144177Salfred 213144177Salfred rle = resource_list_find(&hr->hr_rl, type, 0); 214144177Salfred if (rle == NULL) { 215144177Salfred /* 216144177Salfred * No decoding ranges for this resource type, just pass 217144177Salfred * the request up to the parent. 218144177Salfred */ 219153963Sbrian return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 220153963Sbrian start, end, count, flags)); 221153963Sbrian } 222144177Salfred 223144177Salfredrestart: 224144177Salfred /* Try to allocate from each decoded range. */ 225144177Salfred for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 226144177Salfred if (rle->type != type) 227144177Salfred continue; 228144177Salfred if (((flags & RF_PREFETCHABLE) != 0) != 22931567Ssef ((rle->flags & RLE_PREFETCH) != 0)) 230144177Salfred continue; 231144177Salfred new_start = ulmax(start, rle->start); 232144177Salfred new_end = ulmin(end, rle->end); 233144177Salfred if (new_start > new_end || 23431567Ssef new_start + count - 1 > new_end || 235144177Salfred new_start + count < new_start) 236144177Salfred continue; 237144177Salfred r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 238144177Salfred new_start, new_end, count, flags); 23932275Scharnier if (r != NULL) { 240144177Salfred if (bootverbose) 241144177Salfred device_printf(hr->hr_pcib, 242144177Salfred "allocated type %d (%#lx-%#lx) for rid %x of %s\n", 243144177Salfred type, rman_get_start(r), rman_get_end(r), 244144177Salfred *rid, pcib_child_name(dev)); 245144177Salfred return (r); 24631567Ssef } 247144177Salfred } 248144177Salfred 249144177Salfred /* 250144177Salfred * If we failed to find a prefetch range for a memory 251144177Salfred * resource, try again without prefetch. 252144177Salfred */ 253144177Salfred if (flags & RF_PREFETCHABLE) { 254168569Sdelphij flags &= ~RF_PREFETCHABLE; 255144177Salfred rle = resource_list_find(&hr->hr_rl, type, 0); 256144177Salfred goto restart; 257144177Salfred } 258144177Salfred return (NULL); 25931567Ssef} 26031567Ssef 261144177Salfredint 262144177Salfredpcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, 263144177Salfred struct resource *r, u_long start, u_long end) 264144177Salfred{ 26531567Ssef struct resource_list_entry *rle; 266101283Smdodd 267168569Sdelphij rle = resource_list_find(&hr->hr_rl, type, 0); 268168569Sdelphij if (rle == NULL) { 269144178Salfred /* 270144177Salfred * No decoding ranges for this resource type, just pass 271144177Salfred * the request up to the parent. 272144177Salfred */ 273144177Salfred return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, 274144177Salfred start, end)); 27531567Ssef } 276144177Salfred 277101285Smdodd /* Only allow adjustments that stay within a decoded range. */ 278144177Salfred for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 279158630Spav if (rle->start <= start && rle->end >= end) 280168569Sdelphij return (bus_generic_adjust_resource(hr->hr_pcib, dev, 28131567Ssef type, r, start, end)); 282168569Sdelphij } 283168569Sdelphij return (ERANGE); 284168569Sdelphij} 285168569Sdelphij#endif /* NEW_PCIB */ 286168569Sdelphij