sb_zbpci.c revision 203796
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/rman.h> 34#include <sys/pcpu.h> 35#include <sys/smp.h> 36 37#include <vm/vm.h> 38#include <vm/vm_param.h> 39#include <vm/vm_kern.h> 40#include <vm/vm_extern.h> 41#include <vm/pmap.h> 42 43#include <dev/pci/pcireg.h> 44#include <dev/pci/pcivar.h> 45#include <dev/pci/pcib_private.h> 46 47#include <machine/pmap.h> 48#include <machine/resource.h> 49#include <machine/bus.h> 50 51#include "pcib_if.h" 52 53#include "sb_scd.h" 54 55__FBSDID("$FreeBSD: head/sys/mips/sibyte/sb_zbpci.c 203796 2010-02-12 02:59:49Z neel $"); 56 57static struct { 58 vm_offset_t vaddr; 59 vm_paddr_t paddr; 60} zbpci_config_space[MAXCPU]; 61 62static const vm_paddr_t CFG_PADDR_BASE = 0xFE000000; 63static const u_long PCI_IOSPACE_ADDR = 0xFC000000; 64static const u_long PCI_IOSPACE_SIZE = 0x02000000; 65 66static struct rman port_rman; 67 68static int 69zbpci_probe(device_t dev) 70{ 71 72 device_set_desc(dev, "Broadcom/Sibyte PCI I/O Bridge"); 73 return (0); 74} 75 76static int 77zbpci_attach(device_t dev) 78{ 79 int n, rid, size; 80 vm_offset_t va; 81 struct resource *res; 82 83 /* 84 * Reserve the physical memory window used to map PCI I/O space. 85 */ 86 rid = 0; 87 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 88 PCI_IOSPACE_ADDR, 89 PCI_IOSPACE_ADDR + PCI_IOSPACE_SIZE - 1, 90 PCI_IOSPACE_SIZE, 0); 91 if (res == NULL) 92 panic("Cannot allocate resource for PCI I/O space mapping."); 93 94 port_rman.rm_start = 0; 95 port_rman.rm_end = PCI_IOSPACE_SIZE - 1; 96 port_rman.rm_type = RMAN_ARRAY; 97 port_rman.rm_descr = "PCI I/O ports"; 98 if (rman_init(&port_rman) != 0 || 99 rman_manage_region(&port_rman, 0, PCI_IOSPACE_SIZE - 1) != 0) 100 panic("%s: port_rman", __func__); 101 102 /* 103 * Reserve the the physical memory that is used to read/write to the 104 * pci config space but don't activate it. We are using a page worth 105 * of KVA as a window over this region. 106 */ 107 rid = 1; 108 size = (PCI_BUSMAX + 1) * (PCI_SLOTMAX + 1) * (PCI_FUNCMAX + 1) * 256; 109 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, CFG_PADDR_BASE, 110 CFG_PADDR_BASE + size - 1, size, 0); 111 if (res == NULL) 112 panic("Cannot allocate resource for config space accesses."); 113 114 /* 115 * Allocate KVA for accessing PCI config space. 116 */ 117 va = kmem_alloc_nofault(kernel_map, PAGE_SIZE * mp_ncpus); 118 if (va == 0) { 119 device_printf(dev, "Cannot allocate virtual addresses for " 120 "config space access.\n"); 121 return (ENOMEM); 122 } 123 124 for (n = 0; n < mp_ncpus; ++n) 125 zbpci_config_space[n].vaddr = va + n * PAGE_SIZE; 126 127 /* 128 * Sibyte has the PCI bus hierarchy rooted at bus 0 and HT-PCI 129 * hierarchy rooted at bus 1. 130 */ 131 if (device_add_child(dev, "pci", 0) == NULL) 132 panic("zbpci_attach: could not add pci bus 0.\n"); 133 134 if (device_add_child(dev, "pci", 1) == NULL) 135 panic("zbpci_attach: could not add pci bus 1.\n"); 136 137 if (bootverbose) 138 device_printf(dev, "attached.\n"); 139 140 return (bus_generic_attach(dev)); 141} 142 143static struct resource * 144zbpci_alloc_resource(device_t bus, device_t child, int type, int *rid, 145 u_long start, u_long end, u_long count, u_int flags) 146{ 147 struct resource *res; 148 149 /* 150 * Handle PCI I/O port resources here and pass everything else to nexus. 151 */ 152 if (type != SYS_RES_IOPORT) { 153 res = bus_generic_alloc_resource(bus, child, type, rid, 154 start, end, count, flags); 155 return (res); 156 } 157 158 res = rman_reserve_resource(&port_rman, start, end, count, 159 flags, child); 160 if (res == NULL) 161 return (NULL); 162 163 rman_set_rid(res, *rid); 164 165 /* Activate the resource is requested */ 166 if (flags & RF_ACTIVE) { 167 if (bus_activate_resource(child, type, *rid, res) != 0) { 168 rman_release_resource(res); 169 return (NULL); 170 } 171 } 172 173 return (res); 174} 175 176static int 177zbpci_activate_resource(device_t bus, device_t child, int type, int rid, 178 struct resource *res) 179{ 180 void *vaddr; 181 u_long paddr, psize; 182 183 if (type != SYS_RES_IOPORT) { 184 return (bus_generic_activate_resource(bus, child, type, 185 rid, res)); 186 } 187 188 /* 189 * Map the I/O space resource through the memory window starting 190 * at PCI_IOSPACE_ADDR. 191 */ 192 paddr = rman_get_start(res) + PCI_IOSPACE_ADDR; 193 psize = rman_get_size(res); 194 vaddr = pmap_mapdev(paddr, psize); 195 196 rman_set_virtual(res, vaddr); 197 rman_set_bustag(res, mips_bus_space_generic); 198 rman_set_bushandle(res, (bus_space_handle_t)vaddr); 199 200 return (rman_activate_resource(res)); 201} 202 203static int 204zbpci_release_resource(device_t bus, device_t child, int type, int rid, 205 struct resource *r) 206{ 207 int error; 208 209 if (type != SYS_RES_IOPORT) 210 return (bus_generic_release_resource(bus, child, type, rid, r)); 211 212 if (rman_get_flags(r) & RF_ACTIVE) { 213 error = bus_deactivate_resource(child, type, rid, r); 214 if (error) 215 return (error); 216 } 217 218 return (rman_release_resource(r)); 219} 220 221static int 222zbpci_deactivate_resource(device_t bus, device_t child, int type, int rid, 223 struct resource *r) 224{ 225 vm_offset_t va; 226 227 if (type != SYS_RES_IOPORT) { 228 return (bus_generic_deactivate_resource(bus, child, type, 229 rid, r)); 230 } 231 232 va = (vm_offset_t)rman_get_virtual(r); 233 pmap_unmapdev(va, rman_get_size(r)); 234 235 return (rman_deactivate_resource(r)); 236} 237 238static int 239zbpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 240{ 241 242 switch (which) { 243 case PCIB_IVAR_DOMAIN: 244 *result = 0; /* single PCI domain */ 245 return (0); 246 case PCIB_IVAR_BUS: 247 *result = device_get_unit(child); /* PCI bus 0 or 1 */ 248 return (0); 249 default: 250 return (ENOENT); 251 } 252} 253 254/* 255 * We rely on the CFE to have configured the intline correctly to point to 256 * one of PCI-A/PCI-B/PCI-C/PCI-D in the interupt mapper. 257 */ 258static int 259zbpci_route_interrupt(device_t pcib, device_t dev, int pin) 260{ 261 262 return (PCI_INVALID_IRQ); 263} 264 265/* 266 * This function is expected to be called in a critical section since it 267 * changes the per-cpu pci config space va-to-pa mappings. 268 */ 269static vm_offset_t 270zbpci_config_space_va(int bus, int slot, int func, int reg, int bytes) 271{ 272 int cpu; 273 vm_offset_t va_page; 274 vm_paddr_t pa, pa_page; 275 276 if (bus <= PCI_BUSMAX && slot <= PCI_SLOTMAX && func <= PCI_FUNCMAX && 277 reg <= PCI_REGMAX && (bytes == 1 || bytes == 2 || bytes == 4) && 278 ((reg & (bytes - 1)) == 0)) { 279 cpu = PCPU_GET(cpuid); 280 va_page = zbpci_config_space[cpu].vaddr; 281 pa = CFG_PADDR_BASE | 282 (bus << 16) | (slot << 11) | (func << 8) | reg; 283 pa_page = pa & ~(PAGE_SIZE - 1); 284 if (zbpci_config_space[cpu].paddr != pa_page) { 285 pmap_kremove(va_page); 286 pmap_kenter(va_page, pa_page); 287 zbpci_config_space[cpu].paddr = pa_page; 288 } 289 return (va_page + (pa - pa_page)); 290 } else { 291 return (0); 292 } 293} 294 295static uint32_t 296zbpci_read_config(device_t dev, u_int b, u_int s, u_int f, u_int r, int w) 297{ 298 uint32_t data; 299 vm_offset_t va; 300 301 critical_enter(); 302 303 va = zbpci_config_space_va(b, s, f, r, w); 304 if (va == 0) { 305 panic("zbpci_read_config: invalid %d/%d/%d[%d] %d\n", 306 b, s, f, r, w); 307 } 308 309 switch (w) { 310 case 4: 311 data = *(uint32_t *)va; 312 break; 313 case 2: 314 data = *(uint16_t *)va; 315 break; 316 case 1: 317 data = *(uint8_t *)va; 318 break; 319 default: 320 panic("zbpci_read_config: invalid width %d\n", w); 321 } 322 323 critical_exit(); 324 325 return (data); 326} 327 328static void 329zbpci_write_config(device_t d, u_int b, u_int s, u_int f, u_int r, 330 uint32_t data, int w) 331{ 332 vm_offset_t va; 333 334 critical_enter(); 335 336 va = zbpci_config_space_va(b, s, f, r, w); 337 if (va == 0) { 338 panic("zbpci_write_config: invalid %d/%d/%d[%d] %d/%d\n", 339 b, s, f, r, data, w); 340 } 341 342 switch (w) { 343 case 4: 344 *(uint32_t *)va = data; 345 break; 346 case 2: 347 *(uint16_t *)va = data; 348 break; 349 case 1: 350 *(uint8_t *)va = data; 351 break; 352 default: 353 panic("zbpci_write_config: invalid width %d\n", w); 354 } 355 356 critical_exit(); 357} 358 359static device_method_t zbpci_methods[] ={ 360 /* Device interface */ 361 DEVMETHOD(device_probe, zbpci_probe), 362 DEVMETHOD(device_attach, zbpci_attach), 363 DEVMETHOD(device_detach, bus_generic_detach), 364 DEVMETHOD(device_shutdown, bus_generic_shutdown), 365 DEVMETHOD(device_suspend, bus_generic_suspend), 366 DEVMETHOD(device_resume, bus_generic_resume), 367 368 /* Bus interface */ 369 DEVMETHOD(bus_read_ivar, zbpci_read_ivar), 370 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 371 DEVMETHOD(bus_alloc_resource, zbpci_alloc_resource), 372 DEVMETHOD(bus_activate_resource, zbpci_activate_resource), 373 DEVMETHOD(bus_deactivate_resource, zbpci_deactivate_resource), 374 DEVMETHOD(bus_release_resource, zbpci_release_resource), 375 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 376 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 377 DEVMETHOD(bus_add_child, bus_generic_add_child), 378 379 /* pcib interface */ 380 DEVMETHOD(pcib_maxslots, pcib_maxslots), 381 DEVMETHOD(pcib_read_config, zbpci_read_config), 382 DEVMETHOD(pcib_write_config, zbpci_write_config), 383 DEVMETHOD(pcib_route_interrupt, zbpci_route_interrupt), 384 385 { 0, 0 } 386}; 387 388/* 389 * The "zbpci" class inherits from the "pcib" base class. Therefore in 390 * addition to drivers that belong to the "zbpci" class we will also 391 * consider drivers belonging to the "pcib" when probing children of 392 * "zbpci". 393 */ 394DECLARE_CLASS(pcib_driver); 395DEFINE_CLASS_1(zbpci, zbpci_driver, zbpci_methods, 0, pcib_driver); 396 397static devclass_t zbpci_devclass; 398 399DRIVER_MODULE(zbpci, zbbus, zbpci_driver, zbpci_devclass, 0, 0); 400