sb_zbpci.c revision 202089
1/*- 2 * Copyright (c) 2009 Neelkanth Natu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/param.h> 28#include <sys/types.h> 29#include <sys/kernel.h> 30#include <sys/systm.h> 31#include <sys/module.h> 32#include <sys/bus.h> 33#include <sys/pcpu.h> 34#include <sys/smp.h> 35 36#include <vm/vm.h> 37#include <vm/vm_param.h> 38#include <vm/vm_kern.h> 39#include <vm/vm_extern.h> 40#include <vm/pmap.h> 41 42#include <dev/pci/pcireg.h> 43#include <dev/pci/pcivar.h> 44#include <dev/pci/pcib_private.h> 45 46#include <machine/pmap.h> 47#include <machine/resource.h> 48 49#include "pcib_if.h" 50 51#include "sb_scd.h" 52 53__FBSDID("$FreeBSD: head/sys/mips/sibyte/sb_zbpci.c 202089 2010-01-11 17:14:10Z imp $"); 54 55static struct { 56 vm_offset_t vaddr; 57 vm_paddr_t paddr; 58} zbpci_config_space[MAXCPU]; 59 60static const vm_paddr_t CFG_PADDR_BASE = 0xFE000000; 61 62static int 63zbpci_probe(device_t dev) 64{ 65 66 device_set_desc(dev, "Broadcom/Sibyte PCI I/O Bridge"); 67 return (0); 68} 69 70static int 71zbpci_attach(device_t dev) 72{ 73 int n, rid, size; 74 vm_offset_t va; 75 struct resource *res; 76 77 /* 78 * Reserve the the physical memory that is used to read/write to the 79 * pci config space but don't activate it. We are using a page worth 80 * of KVA as a window over this region. 81 */ 82 rid = 0; 83 size = (PCI_BUSMAX + 1) * (PCI_SLOTMAX + 1) * (PCI_FUNCMAX + 1) * 256; 84 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, CFG_PADDR_BASE, 85 CFG_PADDR_BASE + size - 1, size, 0); 86 if (res == NULL) { 87 panic("Cannot allocate resource for config space accesses."); 88 } 89 90 /* 91 * Allocate KVA for accessing PCI config space. 92 */ 93 va = kmem_alloc_nofault(kernel_map, PAGE_SIZE * mp_ncpus); 94 if (va == 0) { 95 device_printf(dev, "Cannot allocate virtual addresses for " 96 "config space access.\n"); 97 return (ENOMEM); 98 } 99 100 for (n = 0; n < mp_ncpus; ++n) { 101 zbpci_config_space[n].vaddr = va + n * PAGE_SIZE; 102 } 103 104 /* 105 * Sibyte has the PCI bus hierarchy rooted at bus 0 and HT-PCI 106 * hierarchy rooted at bus 1. 107 */ 108 if (device_add_child(dev, "pci", 0) == NULL) { 109 panic("zbpci_attach: could not add pci bus 0.\n"); 110 } 111 112 if (device_add_child(dev, "pci", 1) == NULL) { 113 panic("zbpci_attach: could not add pci bus 1.\n"); 114 } 115 116 if (bootverbose) { 117 device_printf(dev, "attached.\n"); 118 } 119 120 return (bus_generic_attach(dev)); 121} 122 123static int 124zbpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 125{ 126 127 switch (which) { 128 case PCIB_IVAR_DOMAIN: 129 *result = 0; /* single PCI domain */ 130 return (0); 131 case PCIB_IVAR_BUS: 132 *result = device_get_unit(child); /* PCI bus 0 or 1 */ 133 return (0); 134 default: 135 return (ENOENT); 136 } 137} 138 139/* 140 * We rely on the CFE to have configured the intline correctly to point to 141 * one of PCI-A/PCI-B/PCI-C/PCI-D in the interupt mapper. 142 */ 143static int 144zbpci_route_interrupt(device_t pcib, device_t dev, int pin) 145{ 146 147 return (PCI_INVALID_IRQ); 148} 149 150/* 151 * This function is expected to be called in a critical section since it 152 * changes the per-cpu pci config space va-to-pa mappings. 153 */ 154static vm_offset_t 155zbpci_config_space_va(int bus, int slot, int func, int reg, int bytes) 156{ 157 int cpu; 158 vm_offset_t va_page; 159 vm_paddr_t pa, pa_page; 160 161 if (bus <= PCI_BUSMAX && slot <= PCI_SLOTMAX && func <= PCI_FUNCMAX && 162 reg <= PCI_REGMAX && (bytes == 1 || bytes == 2 || bytes == 4) && 163 ((reg & (bytes - 1)) == 0)) { 164 cpu = PCPU_GET(cpuid); 165 va_page = zbpci_config_space[cpu].vaddr; 166 pa = CFG_PADDR_BASE | 167 (bus << 16) | (slot << 11) | (func << 8) | reg; 168 pa_page = pa & ~(PAGE_SIZE - 1); 169 if (zbpci_config_space[cpu].paddr != pa_page) { 170 pmap_kremove(va_page); 171 pmap_kenter(va_page, pa_page); 172 zbpci_config_space[cpu].paddr = pa_page; 173 } 174 return (va_page + (pa - pa_page)); 175 } else { 176 return (0); 177 } 178} 179 180static uint32_t 181zbpci_read_config(device_t dev, u_int b, u_int s, u_int f, u_int r, int w) 182{ 183 uint32_t data; 184 vm_offset_t va; 185 186 critical_enter(); 187 188 va = zbpci_config_space_va(b, s, f, r, w); 189 if (va == 0) { 190 panic("zbpci_read_config: invalid %d/%d/%d[%d] %d\n", 191 b, s, f, r, w); 192 } 193 194 switch (w) { 195 case 4: 196 data = *(uint32_t *)va; 197 break; 198 case 2: 199 data = *(uint16_t *)va; 200 break; 201 case 1: 202 data = *(uint8_t *)va; 203 break; 204 default: 205 panic("zbpci_read_config: invalid width %d\n", w); 206 } 207 208 critical_exit(); 209 210 return (data); 211} 212 213static void 214zbpci_write_config(device_t d, u_int b, u_int s, u_int f, u_int r, 215 uint32_t data, int w) 216{ 217 vm_offset_t va; 218 219 critical_enter(); 220 221 va = zbpci_config_space_va(b, s, f, r, w); 222 if (va == 0) { 223 panic("zbpci_write_config: invalid %d/%d/%d[%d] %d/%d\n", 224 b, s, f, r, data, w); 225 } 226 227 switch (w) { 228 case 4: 229 *(uint32_t *)va = data; 230 break; 231 case 2: 232 *(uint16_t *)va = data; 233 break; 234 case 1: 235 *(uint8_t *)va = data; 236 break; 237 default: 238 panic("zbpci_write_config: invalid width %d\n", w); 239 } 240 241 critical_exit(); 242} 243 244static device_method_t zbpci_methods[] ={ 245 /* Device interface */ 246 DEVMETHOD(device_probe, zbpci_probe), 247 DEVMETHOD(device_attach, zbpci_attach), 248 DEVMETHOD(device_detach, bus_generic_detach), 249 DEVMETHOD(device_shutdown, bus_generic_shutdown), 250 DEVMETHOD(device_suspend, bus_generic_suspend), 251 DEVMETHOD(device_resume, bus_generic_resume), 252 253 /* Bus interface */ 254 DEVMETHOD(bus_read_ivar, zbpci_read_ivar), 255 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 256 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 257 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 258 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 259 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 260 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 261 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 262 DEVMETHOD(bus_add_child, bus_generic_add_child), 263 264 /* pcib interface */ 265 DEVMETHOD(pcib_maxslots, pcib_maxslots), 266 DEVMETHOD(pcib_read_config, zbpci_read_config), 267 DEVMETHOD(pcib_write_config, zbpci_write_config), 268 DEVMETHOD(pcib_route_interrupt, zbpci_route_interrupt), 269 270 { 0, 0 } 271}; 272 273/* 274 * The "zbpci" class inherits from the "pcib" base class. Therefore in 275 * addition to drivers that belong to the "zbpci" class we will also 276 * consider drivers belonging to the "pcib" when probing children of 277 * "zbpci". 278 */ 279DECLARE_CLASS(pcib_driver); 280DEFINE_CLASS_1(zbpci, zbpci_driver, zbpci_methods, 0, pcib_driver); 281 282static devclass_t zbpci_devclass; 283 284DRIVER_MODULE(zbpci, zbbus, zbpci_driver, zbpci_devclass, 0, 0); 285