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 3634ff71eeSJohn Baldwin #include <sys/param.h> 370dbe859dSJohn Baldwin #include <sys/bus.h> 380dbe859dSJohn Baldwin #include <sys/rman.h> 3934ff71eeSJohn 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 } 13234ff71eeSJohn Baldwin 13334ff71eeSJohn Baldwin #ifdef NEW_PCIB 13434ff71eeSJohn Baldwin /* 13534ff71eeSJohn Baldwin * Return a pointer to a pretty name for a PCI device. If the device 13634ff71eeSJohn Baldwin * has a driver attached, the device's name is used, otherwise a name 13734ff71eeSJohn Baldwin * is generated from the device's PCI address. 13834ff71eeSJohn Baldwin */ 13934ff71eeSJohn Baldwin const char * 14034ff71eeSJohn Baldwin pcib_child_name(device_t child) 14134ff71eeSJohn Baldwin { 14234ff71eeSJohn Baldwin static char buf[64]; 14334ff71eeSJohn Baldwin 14434ff71eeSJohn Baldwin if (device_get_nameunit(child) != NULL) 14534ff71eeSJohn Baldwin return (device_get_nameunit(child)); 14634ff71eeSJohn Baldwin snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), 14734ff71eeSJohn Baldwin pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); 14834ff71eeSJohn Baldwin return (buf); 14934ff71eeSJohn Baldwin } 15034ff71eeSJohn Baldwin 15134ff71eeSJohn Baldwin /* 15234ff71eeSJohn Baldwin * Some Host-PCI bridge drivers know which resource ranges they can 15334ff71eeSJohn Baldwin * decode and should only allocate subranges to child PCI devices. 154*e0c34b57SJohn Baldwin * This API provides a way to manage this. The bridge driver should 15534ff71eeSJohn Baldwin * initialize this structure during attach and call 15634ff71eeSJohn Baldwin * pcib_host_res_decodes() on each resource range it decodes. It can 15734ff71eeSJohn Baldwin * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper 15834ff71eeSJohn Baldwin * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This 15934ff71eeSJohn Baldwin * API assumes that resources for any decoded ranges can be safely 16034ff71eeSJohn Baldwin * allocated from the parent via bus_generic_alloc_resource(). 16134ff71eeSJohn Baldwin */ 16234ff71eeSJohn Baldwin int 16334ff71eeSJohn Baldwin pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) 16434ff71eeSJohn Baldwin { 16534ff71eeSJohn Baldwin 16634ff71eeSJohn Baldwin hr->hr_pcib = pcib; 16734ff71eeSJohn Baldwin resource_list_init(&hr->hr_rl); 16834ff71eeSJohn Baldwin return (0); 16934ff71eeSJohn Baldwin } 17034ff71eeSJohn Baldwin 17134ff71eeSJohn Baldwin int 17234ff71eeSJohn Baldwin pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) 17334ff71eeSJohn Baldwin { 17434ff71eeSJohn Baldwin 17534ff71eeSJohn Baldwin resource_list_free(&hr->hr_rl); 17634ff71eeSJohn Baldwin return (0); 17734ff71eeSJohn Baldwin } 17834ff71eeSJohn Baldwin 17934ff71eeSJohn Baldwin int 18034ff71eeSJohn Baldwin pcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, 18134ff71eeSJohn Baldwin u_long end, u_int flags) 18234ff71eeSJohn Baldwin { 18334ff71eeSJohn Baldwin struct resource_list_entry *rle; 18434ff71eeSJohn Baldwin int rid; 18534ff71eeSJohn Baldwin 18634ff71eeSJohn Baldwin if (bootverbose) 18734ff71eeSJohn Baldwin device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", 18834ff71eeSJohn Baldwin type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, 18934ff71eeSJohn Baldwin end); 19034ff71eeSJohn Baldwin rid = resource_list_add_next(&hr->hr_rl, type, start, end, 19134ff71eeSJohn Baldwin end - start + 1); 19234ff71eeSJohn Baldwin if (flags & RF_PREFETCHABLE) { 19334ff71eeSJohn Baldwin KASSERT(type == SYS_RES_MEMORY, 19434ff71eeSJohn Baldwin ("only memory is prefetchable")); 19534ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, rid); 19634ff71eeSJohn Baldwin rle->flags = RLE_PREFETCH; 19734ff71eeSJohn Baldwin } 19834ff71eeSJohn Baldwin return (0); 19934ff71eeSJohn Baldwin } 20034ff71eeSJohn Baldwin 20134ff71eeSJohn Baldwin struct resource * 20234ff71eeSJohn Baldwin pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, 20334ff71eeSJohn Baldwin int *rid, u_long start, u_long end, u_long count, u_int flags) 20434ff71eeSJohn Baldwin { 20534ff71eeSJohn Baldwin struct resource_list_entry *rle; 20634ff71eeSJohn Baldwin struct resource *r; 20734ff71eeSJohn Baldwin u_long new_start, new_end; 20834ff71eeSJohn Baldwin 20934ff71eeSJohn Baldwin if (flags & RF_PREFETCHABLE) 21034ff71eeSJohn Baldwin KASSERT(type == SYS_RES_MEMORY, 21134ff71eeSJohn Baldwin ("only memory is prefetchable")); 21234ff71eeSJohn Baldwin 21334ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, 0); 21434ff71eeSJohn Baldwin if (rle == NULL) { 21534ff71eeSJohn Baldwin /* 21634ff71eeSJohn Baldwin * No decoding ranges for this resource type, just pass 21734ff71eeSJohn Baldwin * the request up to the parent. 21834ff71eeSJohn Baldwin */ 21934ff71eeSJohn Baldwin return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 22034ff71eeSJohn Baldwin start, end, count, flags)); 22134ff71eeSJohn Baldwin } 22234ff71eeSJohn Baldwin 22334ff71eeSJohn Baldwin restart: 22434ff71eeSJohn Baldwin /* Try to allocate from each decoded range. */ 22534ff71eeSJohn Baldwin for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 22634ff71eeSJohn Baldwin if (rle->type != type) 22734ff71eeSJohn Baldwin continue; 22834ff71eeSJohn Baldwin if (((flags & RF_PREFETCHABLE) != 0) != 22934ff71eeSJohn Baldwin ((rle->flags & RLE_PREFETCH) != 0)) 23034ff71eeSJohn Baldwin continue; 23134ff71eeSJohn Baldwin new_start = ulmax(start, rle->start); 23234ff71eeSJohn Baldwin new_end = ulmin(end, rle->end); 23334ff71eeSJohn Baldwin if (new_start > new_end || 23434ff71eeSJohn Baldwin new_start + count - 1 > new_end || 23534ff71eeSJohn Baldwin new_start + count < new_start) 23634ff71eeSJohn Baldwin continue; 23734ff71eeSJohn Baldwin r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, 23834ff71eeSJohn Baldwin new_start, new_end, count, flags); 23934ff71eeSJohn Baldwin if (r != NULL) { 24034ff71eeSJohn Baldwin if (bootverbose) 24134ff71eeSJohn Baldwin device_printf(hr->hr_pcib, 24234ff71eeSJohn Baldwin "allocated type %d (%#lx-%#lx) for rid %x of %s\n", 24334ff71eeSJohn Baldwin type, rman_get_start(r), rman_get_end(r), 24434ff71eeSJohn Baldwin *rid, pcib_child_name(dev)); 24534ff71eeSJohn Baldwin return (r); 24634ff71eeSJohn Baldwin } 24734ff71eeSJohn Baldwin } 24834ff71eeSJohn Baldwin 24934ff71eeSJohn Baldwin /* 25034ff71eeSJohn Baldwin * If we failed to find a prefetch range for a memory 25134ff71eeSJohn Baldwin * resource, try again without prefetch. 25234ff71eeSJohn Baldwin */ 25334ff71eeSJohn Baldwin if (flags & RF_PREFETCHABLE) { 25434ff71eeSJohn Baldwin flags &= ~RF_PREFETCHABLE; 25534ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, 0); 25634ff71eeSJohn Baldwin goto restart; 25734ff71eeSJohn Baldwin } 25834ff71eeSJohn Baldwin return (NULL); 25934ff71eeSJohn Baldwin } 26034ff71eeSJohn Baldwin 26134ff71eeSJohn Baldwin int 26234ff71eeSJohn Baldwin pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, 26334ff71eeSJohn Baldwin struct resource *r, u_long start, u_long end) 26434ff71eeSJohn Baldwin { 26534ff71eeSJohn Baldwin struct resource_list_entry *rle; 26634ff71eeSJohn Baldwin 26734ff71eeSJohn Baldwin rle = resource_list_find(&hr->hr_rl, type, 0); 26834ff71eeSJohn Baldwin if (rle == NULL) { 26934ff71eeSJohn Baldwin /* 27034ff71eeSJohn Baldwin * No decoding ranges for this resource type, just pass 27134ff71eeSJohn Baldwin * the request up to the parent. 27234ff71eeSJohn Baldwin */ 27334ff71eeSJohn Baldwin return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, 27434ff71eeSJohn Baldwin start, end)); 27534ff71eeSJohn Baldwin } 27634ff71eeSJohn Baldwin 27734ff71eeSJohn Baldwin /* Only allow adjustments that stay within a decoded range. */ 27834ff71eeSJohn Baldwin for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { 27934ff71eeSJohn Baldwin if (rle->start <= start && rle->end >= end) 28034ff71eeSJohn Baldwin return (bus_generic_adjust_resource(hr->hr_pcib, dev, 28134ff71eeSJohn Baldwin type, r, start, end)); 28234ff71eeSJohn Baldwin } 28334ff71eeSJohn Baldwin return (ERANGE); 28434ff71eeSJohn Baldwin } 28534ff71eeSJohn Baldwin #endif /* NEW_PCIB */ 286