mv_pci.c revision 209131
1217044Snwhitehorn/*- 2217044Snwhitehorn * Copyright (c) 2008 MARVELL INTERNATIONAL LTD. 3217044Snwhitehorn * Copyright (c) 2010 The FreeBSD Foundation 4217044Snwhitehorn * All rights reserved. 5217044Snwhitehorn * 6217044Snwhitehorn * Developed by Semihalf. 7217044Snwhitehorn * 8217044Snwhitehorn * Portions of this software were developed by Semihalf 9217044Snwhitehorn * under sponsorship from the FreeBSD Foundation. 10217044Snwhitehorn * 11217044Snwhitehorn * Redistribution and use in source and binary forms, with or without 12217044Snwhitehorn * modification, are permitted provided that the following conditions 13217044Snwhitehorn * are met: 14217044Snwhitehorn * 1. Redistributions of source code must retain the above copyright 15217044Snwhitehorn * notice, this list of conditions and the following disclaimer. 16217044Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 17217044Snwhitehorn * notice, this list of conditions and the following disclaimer in the 18217044Snwhitehorn * documentation and/or other materials provided with the distribution. 19217044Snwhitehorn * 3. Neither the name of MARVELL nor the names of contributors 20217044Snwhitehorn * may be used to endorse or promote products derived from this software 21217044Snwhitehorn * without specific prior written permission. 22217044Snwhitehorn * 23217044Snwhitehorn * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24217044Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25217044Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26217044Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27217044Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28217044Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29217044Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30217044Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31217044Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32217044Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33217044Snwhitehorn * SUCH DAMAGE. 34217044Snwhitehorn */ 35217044Snwhitehorn 36217044Snwhitehorn/* 37217044Snwhitehorn * Marvell integrated PCI/PCI-Express controller driver. 38217044Snwhitehorn */ 39217044Snwhitehorn 40217044Snwhitehorn#include <sys/cdefs.h> 41217044Snwhitehorn__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 209131 2010-06-13 13:28:53Z raj $"); 42217044Snwhitehorn 43217044Snwhitehorn#include <sys/param.h> 44217044Snwhitehorn#include <sys/systm.h> 45217044Snwhitehorn#include <sys/kernel.h> 46217044Snwhitehorn#include <sys/lock.h> 47217044Snwhitehorn#include <sys/malloc.h> 48217044Snwhitehorn#include <sys/module.h> 49217044Snwhitehorn#include <sys/mutex.h> 50217044Snwhitehorn#include <sys/queue.h> 51217044Snwhitehorn#include <sys/bus.h> 52217044Snwhitehorn#include <sys/rman.h> 53217044Snwhitehorn#include <sys/endian.h> 54217044Snwhitehorn 55217044Snwhitehorn#include <vm/vm.h> 56217044Snwhitehorn#include <vm/pmap.h> 57217044Snwhitehorn 58217044Snwhitehorn#include <dev/fdt/fdt_common.h> 59217044Snwhitehorn#include <dev/ofw/ofw_bus.h> 60217044Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 61217044Snwhitehorn#include <dev/pci/pcivar.h> 62217044Snwhitehorn#include <dev/pci/pcireg.h> 63217044Snwhitehorn#include <dev/pci/pcib_private.h> 64217044Snwhitehorn 65217044Snwhitehorn#include "ofw_bus_if.h" 66217044Snwhitehorn#include "pcib_if.h" 67217044Snwhitehorn 68217044Snwhitehorn#include <machine/resource.h> 69217044Snwhitehorn#include <machine/bus.h> 70217044Snwhitehorn 71217044Snwhitehorn#include <arm/mv/mvreg.h> 72217044Snwhitehorn#include <arm/mv/mvvar.h> 73217044Snwhitehorn#include <arm/mv/mvwin.h> 74217044Snwhitehorn 75217044Snwhitehorn#define PCI_CFG_ENA (1 << 31) 76217044Snwhitehorn#define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) 77217044Snwhitehorn#define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) 78217044Snwhitehorn#define PCI_CFG_FUN(fun) (((fun) & 0x7) << 8) 79217044Snwhitehorn#define PCI_CFG_PCIE_REG(reg) ((reg) & 0xfc) 80217044Snwhitehorn 81217044Snwhitehorn#define PCI_REG_CFG_ADDR 0x0C78 82217044Snwhitehorn#define PCI_REG_CFG_DATA 0x0C7C 83217044Snwhitehorn#define PCI_REG_P2P_CONF 0x1D14 84217044Snwhitehorn 85217044Snwhitehorn#define PCIE_REG_CFG_ADDR 0x18F8 86217044Snwhitehorn#define PCIE_REG_CFG_DATA 0x18FC 87217044Snwhitehorn#define PCIE_REG_CONTROL 0x1A00 88217044Snwhitehorn#define PCIE_CTRL_LINK1X 0x00000001 89217044Snwhitehorn#define PCIE_REG_STATUS 0x1A04 90217044Snwhitehorn#define PCIE_REG_IRQ_MASK 0x1910 91217044Snwhitehorn 92217044Snwhitehorn#define STATUS_LINK_DOWN 1 93217044Snwhitehorn#define STATUS_BUS_OFFS 8 94217044Snwhitehorn#define STATUS_BUS_MASK (0xFF << STATUS_BUS_OFFS) 95217044Snwhitehorn#define STATUS_DEV_OFFS 16 96217044Snwhitehorn#define STATUS_DEV_MASK (0x1F << STATUS_DEV_OFFS) 97217044Snwhitehorn 98217044Snwhitehorn#define P2P_CONF_BUS_OFFS 16 99217044Snwhitehorn#define P2P_CONF_BUS_MASK (0xFF << P2P_CONF_BUS_OFFS) 100217044Snwhitehorn#define P2P_CONF_DEV_OFFS 24 101217044Snwhitehorn#define P2P_CONF_DEV_MASK (0x1F << P2P_CONF_DEV_OFFS) 102217044Snwhitehorn 103217044Snwhitehorn#define PCI_VENDORID_MRVL 0x11AB 104217044Snwhitehorn 105217044Snwhitehornstruct mv_pcib_softc { 106217044Snwhitehorn device_t sc_dev; 107217044Snwhitehorn 108217044Snwhitehorn struct rman sc_mem_rman; 109217044Snwhitehorn bus_addr_t sc_mem_base; 110217044Snwhitehorn bus_addr_t sc_mem_size; 111217044Snwhitehorn bus_addr_t sc_mem_alloc; /* Next allocation. */ 112217044Snwhitehorn int sc_mem_win_target; 113217044Snwhitehorn int sc_mem_win_attr; 114217044Snwhitehorn 115217044Snwhitehorn struct rman sc_io_rman; 116217044Snwhitehorn bus_addr_t sc_io_base; 117217044Snwhitehorn bus_addr_t sc_io_size; 118217044Snwhitehorn bus_addr_t sc_io_alloc; /* Next allocation. */ 119217044Snwhitehorn int sc_io_win_target; 120217044Snwhitehorn int sc_io_win_attr; 121217044Snwhitehorn 122217044Snwhitehorn struct resource *sc_res; 123217044Snwhitehorn bus_space_handle_t sc_bsh; 124217044Snwhitehorn bus_space_tag_t sc_bst; 125217044Snwhitehorn int sc_rid; 126217044Snwhitehorn 127217044Snwhitehorn int sc_busnr; /* Host bridge bus number */ 128217044Snwhitehorn int sc_devnr; /* Host bridge device number */ 129217044Snwhitehorn int sc_type; 130217044Snwhitehorn 131217044Snwhitehorn struct fdt_pci_intr sc_intr_info; 132217044Snwhitehorn}; 133217044Snwhitehorn 134217044Snwhitehorn/* Local forward prototypes */ 135217044Snwhitehornstatic int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *); 136217044Snwhitehornstatic void mv_pcib_hw_cfginit(void); 137217044Snwhitehornstatic uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int, 138217044Snwhitehorn u_int, u_int, int); 139217044Snwhitehornstatic void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int, 140217044Snwhitehorn u_int, u_int, uint32_t, int); 141217044Snwhitehornstatic int mv_pcib_init(struct mv_pcib_softc *, int, int); 142217044Snwhitehornstatic int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int); 143217044Snwhitehornstatic void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int); 144217044Snwhitehornstatic int mv_pcib_intr_info(phandle_t, struct mv_pcib_softc *); 145217044Snwhitehornstatic inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t); 146217044Snwhitehorn 147217044Snwhitehorn 148217044Snwhitehorn/* Forward prototypes */ 149217044Snwhitehornstatic int mv_pcib_probe(device_t); 150217044Snwhitehornstatic int mv_pcib_attach(device_t); 151217044Snwhitehorn 152217044Snwhitehornstatic struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *, 153217044Snwhitehorn u_long, u_long, u_long, u_int); 154217044Snwhitehornstatic int mv_pcib_release_resource(device_t, device_t, int, int, 155217044Snwhitehorn struct resource *); 156217044Snwhitehornstatic int mv_pcib_read_ivar(device_t, device_t, int, uintptr_t *); 157217044Snwhitehornstatic int mv_pcib_write_ivar(device_t, device_t, int, uintptr_t); 158217044Snwhitehorn 159217044Snwhitehornstatic int mv_pcib_maxslots(device_t); 160217044Snwhitehornstatic uint32_t mv_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int); 161217044Snwhitehornstatic void mv_pcib_write_config(device_t, u_int, u_int, u_int, u_int, 162217044Snwhitehorn uint32_t, int); 163217044Snwhitehornstatic int mv_pcib_route_interrupt(device_t, device_t, int); 164217044Snwhitehorn 165217044Snwhitehorn/* 166217044Snwhitehorn * Bus interface definitions. 167217044Snwhitehorn */ 168217044Snwhitehornstatic device_method_t mv_pcib_methods[] = { 169217044Snwhitehorn /* Device interface */ 170217044Snwhitehorn DEVMETHOD(device_probe, mv_pcib_probe), 171217044Snwhitehorn DEVMETHOD(device_attach, mv_pcib_attach), 172217044Snwhitehorn 173217044Snwhitehorn /* Bus interface */ 174217044Snwhitehorn DEVMETHOD(bus_print_child, bus_generic_print_child), 175217044Snwhitehorn DEVMETHOD(bus_read_ivar, mv_pcib_read_ivar), 176217044Snwhitehorn DEVMETHOD(bus_write_ivar, mv_pcib_write_ivar), 177217044Snwhitehorn DEVMETHOD(bus_alloc_resource, mv_pcib_alloc_resource), 178217044Snwhitehorn DEVMETHOD(bus_release_resource, mv_pcib_release_resource), 179217044Snwhitehorn DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 180217044Snwhitehorn DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 181217044Snwhitehorn DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 182217044Snwhitehorn DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 183217044Snwhitehorn 184217044Snwhitehorn /* pcib interface */ 185217044Snwhitehorn DEVMETHOD(pcib_maxslots, mv_pcib_maxslots), 186217044Snwhitehorn DEVMETHOD(pcib_read_config, mv_pcib_read_config), 187217044Snwhitehorn DEVMETHOD(pcib_write_config, mv_pcib_write_config), 188217044Snwhitehorn DEVMETHOD(pcib_route_interrupt, mv_pcib_route_interrupt), 189217044Snwhitehorn 190217044Snwhitehorn /* OFW bus interface */ 191217044Snwhitehorn DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 192217044Snwhitehorn DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 193217044Snwhitehorn DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 194217044Snwhitehorn DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 195217044Snwhitehorn DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 196217044Snwhitehorn 197217044Snwhitehorn { 0, 0 } 198217044Snwhitehorn}; 199217044Snwhitehorn 200217044Snwhitehornstatic driver_t mv_pcib_driver = { 201217044Snwhitehorn "pcib", 202217044Snwhitehorn mv_pcib_methods, 203217044Snwhitehorn sizeof(struct mv_pcib_softc), 204217044Snwhitehorn}; 205217044Snwhitehorn 206217044Snwhitehorndevclass_t pcib_devclass; 207217044Snwhitehorn 208217044SnwhitehornDRIVER_MODULE(pcib, fdtbus, mv_pcib_driver, pcib_devclass, 0, 0); 209217044Snwhitehorn 210217044Snwhitehornstatic struct mtx pcicfg_mtx; 211217044Snwhitehorn 212217044Snwhitehornstatic int 213217044Snwhitehornmv_pcib_probe(device_t self) 214217044Snwhitehorn{ 215217044Snwhitehorn phandle_t parnode; 216217044Snwhitehorn 217217044Snwhitehorn /* 218217044Snwhitehorn * The PCI subnode does not have the 'compatible' property, so we need 219217044Snwhitehorn * to check in the parent PCI node. However the parent is not 220217044Snwhitehorn * represented by a separate ofw_bus child, and therefore 221217044Snwhitehorn * ofw_bus_is_compatible() cannot be used, but direct fdt equivalent. 222217044Snwhitehorn */ 223217044Snwhitehorn parnode = OF_parent(ofw_bus_get_node(self)); 224217044Snwhitehorn if (parnode == 0) 225217044Snwhitehorn return (ENXIO); 226217044Snwhitehorn if (!(fdt_is_compatible(parnode, "mrvl,pcie") || 227217044Snwhitehorn fdt_is_compatible(parnode, "mrvl,pci"))) 228217044Snwhitehorn return (ENXIO); 229217044Snwhitehorn 230217044Snwhitehorn device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller"); 231217044Snwhitehorn 232217044Snwhitehorn return (BUS_PROBE_DEFAULT); 233217044Snwhitehorn} 234217044Snwhitehorn 235217044Snwhitehornstatic int 236217044Snwhitehornmv_pcib_attach(device_t self) 237217044Snwhitehorn{ 238217044Snwhitehorn struct mv_pcib_softc *sc; 239217044Snwhitehorn phandle_t node, parnode; 240217044Snwhitehorn uint32_t val; 241217044Snwhitehorn int err; 242217044Snwhitehorn 243217044Snwhitehorn sc = device_get_softc(self); 244217044Snwhitehorn sc->sc_dev = self; 245217044Snwhitehorn 246217044Snwhitehorn parnode = OF_parent(ofw_bus_get_node(self)); 247217044Snwhitehorn if (fdt_is_compatible(parnode, "mrvl,pcie")) { 248217044Snwhitehorn sc->sc_type = MV_TYPE_PCIE; 249217044Snwhitehorn sc->sc_mem_win_target = MV_WIN_PCIE_MEM_TARGET; 250217044Snwhitehorn sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR; 251217044Snwhitehorn sc->sc_io_win_target = MV_WIN_PCIE_IO_TARGET; 252217044Snwhitehorn sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR; 253217044Snwhitehorn#ifdef SOC_MV_ORION 254217044Snwhitehorn } else if (fdt_is_compatible(parnode, "mrvl,pci")) { 255217044Snwhitehorn sc->sc_type = MV_TYPE_PCI; 256217044Snwhitehorn sc->sc_mem_win_target = MV_WIN_PCI_MEM_TARGET; 257217044Snwhitehorn sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR; 258217044Snwhitehorn sc->sc_io_win_target = MV_WIN_PCI_IO_TARGET; 259217044Snwhitehorn sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR; 260217044Snwhitehorn#endif 261217044Snwhitehorn } else 262217044Snwhitehorn return (ENXIO); 263217044Snwhitehorn 264217044Snwhitehorn node = ofw_bus_get_node(self); 265217044Snwhitehorn 266217044Snwhitehorn /* 267217044Snwhitehorn * Get PCI interrupt info. 268217044Snwhitehorn */ 269217044Snwhitehorn if (mv_pcib_intr_info(node, sc) != 0) { 270217044Snwhitehorn device_printf(self, "could not retrieve interrupt info\n"); 271217044Snwhitehorn return (ENXIO); 272217044Snwhitehorn } 273217044Snwhitehorn 274217044Snwhitehorn /* 275217044Snwhitehorn * Retrieve our mem-mapped registers range. 276217044Snwhitehorn */ 277217044Snwhitehorn sc->sc_rid = 0; 278217044Snwhitehorn sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid, 279217044Snwhitehorn RF_ACTIVE); 280217044Snwhitehorn if (sc->sc_res == NULL) { 281217044Snwhitehorn device_printf(self, "could not map memory\n"); 282217044Snwhitehorn return (ENXIO); 283217044Snwhitehorn } 284217044Snwhitehorn sc->sc_bst = rman_get_bustag(sc->sc_res); 285217044Snwhitehorn sc->sc_bsh = rman_get_bushandle(sc->sc_res); 286217044Snwhitehorn 287217044Snwhitehorn /* 288217044Snwhitehorn * Configure decode windows for PCI(E) access. 289217044Snwhitehorn */ 290217044Snwhitehorn if (mv_pcib_decode_win(node, sc) != 0) 291217044Snwhitehorn return (ENXIO); 292217044Snwhitehorn 293217044Snwhitehorn mv_pcib_hw_cfginit(); 294217044Snwhitehorn 295217044Snwhitehorn /* 296217044Snwhitehorn * Enable PCI bridge. 297217044Snwhitehorn */ 298217044Snwhitehorn val = mv_pcib_hw_cfgread(sc, sc->sc_busnr, sc->sc_devnr, 0, 299217044Snwhitehorn PCIR_COMMAND, 2); 300217044Snwhitehorn val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | 301217044Snwhitehorn PCIM_CMD_PORTEN; 302217044Snwhitehorn mv_pcib_hw_cfgwrite(sc, sc->sc_busnr, sc->sc_devnr, 0, 303217044Snwhitehorn PCIR_COMMAND, val, 2); 304217044Snwhitehorn 305217044Snwhitehorn sc->sc_mem_alloc = sc->sc_mem_base; 306217044Snwhitehorn sc->sc_io_alloc = sc->sc_io_base; 307217044Snwhitehorn 308217044Snwhitehorn sc->sc_mem_rman.rm_type = RMAN_ARRAY; 309217044Snwhitehorn err = rman_init(&sc->sc_mem_rman); 310217044Snwhitehorn if (err) 311217044Snwhitehorn return (err); 312217044Snwhitehorn 313217044Snwhitehorn sc->sc_io_rman.rm_type = RMAN_ARRAY; 314217044Snwhitehorn err = rman_init(&sc->sc_io_rman); 315217044Snwhitehorn if (err) { 316217044Snwhitehorn rman_fini(&sc->sc_mem_rman); 317217044Snwhitehorn return (err); 318217044Snwhitehorn } 319217044Snwhitehorn 320217044Snwhitehorn err = rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base, 321217044Snwhitehorn sc->sc_mem_base + sc->sc_mem_size - 1); 322217044Snwhitehorn if (err) 323217044Snwhitehorn goto error; 324217044Snwhitehorn 325217044Snwhitehorn err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base, 326217044Snwhitehorn sc->sc_io_base + sc->sc_io_size - 1); 327217044Snwhitehorn if (err) 328217044Snwhitehorn goto error; 329217044Snwhitehorn 330217044Snwhitehorn err = mv_pcib_init(sc, sc->sc_busnr, mv_pcib_maxslots(sc->sc_dev)); 331217044Snwhitehorn if (err) 332217044Snwhitehorn goto error; 333217044Snwhitehorn 334217044Snwhitehorn device_add_child(self, "pci", -1); 335217044Snwhitehorn return (bus_generic_attach(self)); 336217044Snwhitehorn 337217044Snwhitehornerror: 338217044Snwhitehorn /* XXX SYS_RES_ should be released here */ 339217044Snwhitehorn rman_fini(&sc->sc_mem_rman); 340217044Snwhitehorn rman_fini(&sc->sc_io_rman); 341217044Snwhitehorn return (err); 342217044Snwhitehorn} 343217044Snwhitehorn 344217044Snwhitehornstatic int 345217044Snwhitehornmv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func, 346217044Snwhitehorn int barno) 347217044Snwhitehorn{ 348217044Snwhitehorn bus_addr_t *allocp, limit; 349217044Snwhitehorn uint32_t addr, bar, mask, size; 350217044Snwhitehorn int reg, width; 351217044Snwhitehorn 352217044Snwhitehorn reg = PCIR_BAR(barno); 353217044Snwhitehorn bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4); 354217044Snwhitehorn if (bar == 0) 355217044Snwhitehorn return (1); 356 357 /* Calculate BAR size: 64 or 32 bit (in 32-bit units) */ 358 width = ((bar & 7) == 4) ? 2 : 1; 359 360 mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4); 361 size = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4); 362 363 /* Get BAR type and size */ 364 if (bar & 1) { 365 /* I/O port */ 366 allocp = &sc->sc_io_alloc; 367 limit = sc->sc_io_base + sc->sc_io_size; 368 size &= ~0x3; 369 if ((size & 0xffff0000) == 0) 370 size |= 0xffff0000; 371 } else { 372 /* Memory */ 373 allocp = &sc->sc_mem_alloc; 374 limit = sc->sc_mem_base + sc->sc_mem_size; 375 size &= ~0xF; 376 } 377 mask = ~size; 378 size = mask + 1; 379 380 /* Sanity check (must be a power of 2) */ 381 if (size & mask) 382 return (width); 383 384 addr = (*allocp + mask) & ~mask; 385 if ((*allocp = addr + size) > limit) 386 return (-1); 387 388 if (bootverbose) 389 printf("PCI %u:%u:%u: reg %x: size=%08x: addr=%08x\n", 390 bus, slot, func, reg, size, addr); 391 392 mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4); 393 if (width == 2) 394 mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4, 395 0, 4); 396 397 return (width); 398} 399 400static void 401mv_pcib_init_bridge(struct mv_pcib_softc *sc, int bus, int slot, int func) 402{ 403 bus_addr_t io_base, mem_base; 404 uint32_t io_limit, mem_limit; 405 int secbus; 406 407 io_base = sc->sc_io_base; 408 io_limit = io_base + sc->sc_io_size - 1; 409 mem_base = sc->sc_mem_base; 410 mem_limit = mem_base + sc->sc_mem_size - 1; 411 412 /* Configure I/O decode registers */ 413 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1, 414 io_base >> 8, 1); 415 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1, 416 io_base >> 16, 2); 417 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1, 418 io_limit >> 8, 1); 419 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1, 420 io_limit >> 16, 2); 421 422 /* Configure memory decode registers */ 423 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1, 424 mem_base >> 16, 2); 425 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1, 426 mem_limit >> 16, 2); 427 428 /* Disable memory prefetch decode */ 429 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1, 430 0x10, 2); 431 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1, 432 0x0, 4); 433 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1, 434 0xF, 2); 435 mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1, 436 0x0, 4); 437 438 secbus = mv_pcib_read_config(sc->sc_dev, bus, slot, func, 439 PCIR_SECBUS_1, 1); 440 441 /* Configure buses behind the bridge */ 442 mv_pcib_init(sc, secbus, PCI_SLOTMAX); 443} 444 445static int 446mv_pcib_init(struct mv_pcib_softc *sc, int bus, int maxslot) 447{ 448 int slot, func, maxfunc, error; 449 uint8_t hdrtype, command, class, subclass; 450 451 for (slot = 0; slot <= maxslot; slot++) { 452 maxfunc = 0; 453 for (func = 0; func <= maxfunc; func++) { 454 hdrtype = mv_pcib_read_config(sc->sc_dev, bus, slot, 455 func, PCIR_HDRTYPE, 1); 456 457 if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 458 continue; 459 460 if (func == 0 && (hdrtype & PCIM_MFDEV)) 461 maxfunc = PCI_FUNCMAX; 462 463 command = mv_pcib_read_config(sc->sc_dev, bus, slot, 464 func, PCIR_COMMAND, 1); 465 command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); 466 mv_pcib_write_config(sc->sc_dev, bus, slot, func, 467 PCIR_COMMAND, command, 1); 468 469 error = mv_pcib_init_all_bars(sc, bus, slot, func, 470 hdrtype); 471 472 if (error) 473 return (error); 474 475 command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | 476 PCIM_CMD_PORTEN; 477 mv_pcib_write_config(sc->sc_dev, bus, slot, func, 478 PCIR_COMMAND, command, 1); 479 480 /* Handle PCI-PCI bridges */ 481 class = mv_pcib_read_config(sc->sc_dev, bus, slot, 482 func, PCIR_CLASS, 1); 483 subclass = mv_pcib_read_config(sc->sc_dev, bus, slot, 484 func, PCIR_SUBCLASS, 1); 485 486 if (class != PCIC_BRIDGE || 487 subclass != PCIS_BRIDGE_PCI) 488 continue; 489 490 mv_pcib_init_bridge(sc, bus, slot, func); 491 } 492 } 493 494 /* Enable all ABCD interrupts */ 495 pcib_write_irq_mask(sc, (0xF << 24)); 496 497 return (0); 498} 499 500static int 501mv_pcib_init_all_bars(struct mv_pcib_softc *sc, int bus, int slot, 502 int func, int hdrtype) 503{ 504 int maxbar, bar, i; 505 506 maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6; 507 bar = 0; 508 509 /* Program the base address registers */ 510 while (bar < maxbar) { 511 i = mv_pcib_init_bar(sc, bus, slot, func, bar); 512 bar += i; 513 if (i < 0) { 514 device_printf(sc->sc_dev, 515 "PCI IO/Memory space exhausted\n"); 516 return (ENOMEM); 517 } 518 } 519 520 return (0); 521} 522 523static struct resource * 524mv_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 525 u_long start, u_long end, u_long count, u_int flags) 526{ 527 struct mv_pcib_softc *sc = device_get_softc(dev); 528 struct rman *rm = NULL; 529 struct resource *res; 530 531 switch (type) { 532 case SYS_RES_IOPORT: 533 rm = &sc->sc_io_rman; 534 break; 535 case SYS_RES_MEMORY: 536 rm = &sc->sc_mem_rman; 537 break; 538 default: 539 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 540 type, rid, start, end, count, flags)); 541 }; 542 543 res = rman_reserve_resource(rm, start, end, count, flags, child); 544 if (res == NULL) 545 return (NULL); 546 547 rman_set_rid(res, *rid); 548 rman_set_bustag(res, fdtbus_bs_tag); 549 rman_set_bushandle(res, start); 550 551 if (flags & RF_ACTIVE) 552 if (bus_activate_resource(child, type, *rid, res)) { 553 rman_release_resource(res); 554 return (NULL); 555 } 556 557 return (res); 558} 559 560static int 561mv_pcib_release_resource(device_t dev, device_t child, int type, int rid, 562 struct resource *res) 563{ 564 565 if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) 566 return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 567 type, rid, res)); 568 569 return (rman_release_resource(res)); 570} 571 572static int 573mv_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 574{ 575 struct mv_pcib_softc *sc = device_get_softc(dev); 576 577 switch (which) { 578 case PCIB_IVAR_BUS: 579 *result = sc->sc_busnr; 580 return (0); 581 case PCIB_IVAR_DOMAIN: 582 *result = device_get_unit(dev); 583 return (0); 584 } 585 586 return (ENOENT); 587} 588 589static int 590mv_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 591{ 592 struct mv_pcib_softc *sc = device_get_softc(dev); 593 594 switch (which) { 595 case PCIB_IVAR_BUS: 596 sc->sc_busnr = value; 597 return (0); 598 } 599 600 return (ENOENT); 601} 602 603static inline void 604pcib_write_irq_mask(struct mv_pcib_softc *sc, uint32_t mask) 605{ 606 607 if (!sc->sc_type != MV_TYPE_PCI) 608 return; 609 610 bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_IRQ_MASK, mask); 611} 612 613static void 614mv_pcib_hw_cfginit(void) 615{ 616 static int opened = 0; 617 618 if (opened) 619 return; 620 621 mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 622 opened = 1; 623} 624 625static uint32_t 626mv_pcib_hw_cfgread(struct mv_pcib_softc *sc, u_int bus, u_int slot, 627 u_int func, u_int reg, int bytes) 628{ 629 uint32_t addr, data, ca, cd; 630 631 ca = (sc->sc_type != MV_TYPE_PCI) ? 632 PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; 633 cd = (sc->sc_type != MV_TYPE_PCI) ? 634 PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; 635 addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | 636 PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); 637 638 mtx_lock_spin(&pcicfg_mtx); 639 bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); 640 641 data = ~0; 642 switch (bytes) { 643 case 1: 644 data = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 645 cd + (reg & 3)); 646 break; 647 case 2: 648 data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh, 649 cd + (reg & 2))); 650 break; 651 case 4: 652 data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, 653 cd)); 654 break; 655 } 656 mtx_unlock_spin(&pcicfg_mtx); 657 return (data); 658} 659 660static void 661mv_pcib_hw_cfgwrite(struct mv_pcib_softc *sc, u_int bus, u_int slot, 662 u_int func, u_int reg, uint32_t data, int bytes) 663{ 664 uint32_t addr, ca, cd; 665 666 ca = (sc->sc_type != MV_TYPE_PCI) ? 667 PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; 668 cd = (sc->sc_type != MV_TYPE_PCI) ? 669 PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; 670 addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | 671 PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); 672 673 mtx_lock_spin(&pcicfg_mtx); 674 bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); 675 676 switch (bytes) { 677 case 1: 678 bus_space_write_1(sc->sc_bst, sc->sc_bsh, 679 cd + (reg & 3), data); 680 break; 681 case 2: 682 bus_space_write_2(sc->sc_bst, sc->sc_bsh, 683 cd + (reg & 2), htole16(data)); 684 break; 685 case 4: 686 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 687 cd, htole32(data)); 688 break; 689 } 690 mtx_unlock_spin(&pcicfg_mtx); 691} 692 693static int 694mv_pcib_maxslots(device_t dev) 695{ 696 struct mv_pcib_softc *sc = device_get_softc(dev); 697 698 return ((sc->sc_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX); 699} 700 701static uint32_t 702mv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 703 u_int reg, int bytes) 704{ 705 struct mv_pcib_softc *sc = device_get_softc(dev); 706 707 /* Skip self */ 708 if (bus == sc->sc_busnr && slot == sc->sc_devnr) 709 return (~0U); 710 711 return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes)); 712} 713 714static void 715mv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 716 u_int reg, uint32_t val, int bytes) 717{ 718 struct mv_pcib_softc *sc = device_get_softc(dev); 719 720 /* Skip self */ 721 if (bus == sc->sc_busnr && slot == sc->sc_devnr) 722 return; 723 724 mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes); 725} 726 727static int 728mv_pcib_route_interrupt(device_t pcib, device_t dev, int pin) 729{ 730 struct mv_pcib_softc *sc; 731 int err, interrupt; 732 733 sc = device_get_softc(pcib); 734 735 err = fdt_pci_route_intr(pci_get_bus(dev), pci_get_slot(dev), 736 pci_get_function(dev), pin, &sc->sc_intr_info, &interrupt); 737 if (err == 0) 738 return (interrupt); 739 740 device_printf(pcib, "could not route pin %d for device %d.%d\n", 741 pin, pci_get_slot(dev), pci_get_function(dev)); 742 return (PCI_INVALID_IRQ); 743} 744 745static int 746mv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc) 747{ 748 struct fdt_pci_range io_space, mem_space; 749 device_t dev; 750 int error; 751 752 dev = sc->sc_dev; 753 754 if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) { 755 device_printf(dev, "could not retrieve 'ranges' data\n"); 756 return (error); 757 } 758 759 /* Configure CPU decoding windows */ 760 error = decode_win_cpu_set(sc->sc_io_win_target, 761 sc->sc_io_win_attr, io_space.base_parent, io_space.len, -1); 762 if (error < 0) { 763 device_printf(dev, "could not set up CPU decode " 764 "window for PCI IO\n"); 765 return (ENXIO); 766 } 767 error = decode_win_cpu_set(sc->sc_mem_win_target, 768 sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len, -1); 769 if (error < 0) { 770 device_printf(dev, "could not set up CPU decode " 771 "windows for PCI MEM\n"); 772 return (ENXIO); 773 } 774 775 sc->sc_io_base = io_space.base_parent; 776 sc->sc_io_size = io_space.len; 777 778 sc->sc_mem_base = mem_space.base_parent; 779 sc->sc_mem_size = mem_space.len; 780 781 return (0); 782} 783 784static int 785mv_pcib_intr_info(phandle_t node, struct mv_pcib_softc *sc) 786{ 787 int error; 788 789 if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0) 790 return (error); 791 792 return (0); 793} 794 795#if 0 796 control = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 797 PCIE_REG_CONTROL); 798 799 /* 800 * If this PCI-E port (controller) is configured (by the 801 * underlying firmware) with lane width other than 1x, there 802 * are auxiliary resources defined for aggregating more width 803 * on our lane. Skip all such entries as they are not 804 * standalone ports and must not have a device object 805 * instantiated. 806 */ 807 if ((control & PCIE_CTRL_LINK1X) == 0) 808 while (info->op_base && 809 info->op_type == MV_TYPE_PCIE_AGGR_LANE) 810 info++; 811 812 mv_pcib_add_child(driver, parent, sc); 813#endif 814