mv_pci.c revision 260327
1185089Sraj/*- 2209131Sraj * Copyright (c) 2008 MARVELL INTERNATIONAL LTD. 3209131Sraj * Copyright (c) 2010 The FreeBSD Foundation 4240489Sgber * Copyright (c) 2010-2012 Semihalf 5185089Sraj * All rights reserved. 6185089Sraj * 7185089Sraj * Developed by Semihalf. 8185089Sraj * 9209131Sraj * Portions of this software were developed by Semihalf 10209131Sraj * under sponsorship from the FreeBSD Foundation. 11209131Sraj * 12185089Sraj * Redistribution and use in source and binary forms, with or without 13185089Sraj * modification, are permitted provided that the following conditions 14185089Sraj * are met: 15185089Sraj * 1. Redistributions of source code must retain the above copyright 16185089Sraj * notice, this list of conditions and the following disclaimer. 17185089Sraj * 2. Redistributions in binary form must reproduce the above copyright 18185089Sraj * notice, this list of conditions and the following disclaimer in the 19185089Sraj * documentation and/or other materials provided with the distribution. 20185089Sraj * 3. Neither the name of MARVELL nor the names of contributors 21185089Sraj * may be used to endorse or promote products derived from this software 22185089Sraj * without specific prior written permission. 23185089Sraj * 24185089Sraj * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25185089Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26185089Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27185089Sraj * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 28185089Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29185089Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30185089Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31185089Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32185089Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33185089Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34185089Sraj * SUCH DAMAGE. 35185089Sraj */ 36185089Sraj 37185089Sraj/* 38185089Sraj * Marvell integrated PCI/PCI-Express controller driver. 39185089Sraj */ 40185089Sraj 41185089Sraj#include <sys/cdefs.h> 42185089Sraj__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 260327 2014-01-05 18:46:58Z nwhitehorn $"); 43185089Sraj 44185089Sraj#include <sys/param.h> 45185089Sraj#include <sys/systm.h> 46185089Sraj#include <sys/kernel.h> 47185089Sraj#include <sys/lock.h> 48185089Sraj#include <sys/malloc.h> 49185089Sraj#include <sys/module.h> 50185089Sraj#include <sys/mutex.h> 51185089Sraj#include <sys/queue.h> 52185089Sraj#include <sys/bus.h> 53185089Sraj#include <sys/rman.h> 54185089Sraj#include <sys/endian.h> 55185089Sraj 56260327Snwhitehorn#include <machine/fdt.h> 57240493Sgber#include <machine/intr.h> 58240493Sgber 59185089Sraj#include <vm/vm.h> 60185089Sraj#include <vm/pmap.h> 61185089Sraj 62209131Sraj#include <dev/fdt/fdt_common.h> 63209131Sraj#include <dev/ofw/ofw_bus.h> 64259484Snwhitehorn#include <dev/ofw/ofw_pci.h> 65209131Sraj#include <dev/ofw/ofw_bus_subr.h> 66185089Sraj#include <dev/pci/pcivar.h> 67185089Sraj#include <dev/pci/pcireg.h> 68185089Sraj#include <dev/pci/pcib_private.h> 69185089Sraj 70209131Sraj#include "ofw_bus_if.h" 71185089Sraj#include "pcib_if.h" 72185089Sraj 73185089Sraj#include <machine/resource.h> 74185089Sraj#include <machine/bus.h> 75185089Sraj 76185089Sraj#include <arm/mv/mvreg.h> 77185089Sraj#include <arm/mv/mvvar.h> 78209131Sraj#include <arm/mv/mvwin.h> 79185089Sraj 80240493Sgber#ifdef DEBUG 81240493Sgber#define debugf(fmt, args...) do { printf(fmt,##args); } while (0) 82240493Sgber#else 83240493Sgber#define debugf(fmt, args...) 84240493Sgber#endif 85240493Sgber 86258780Seadler#define PCI_CFG_ENA (1U << 31) 87185089Sraj#define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16) 88185089Sraj#define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11) 89185089Sraj#define PCI_CFG_FUN(fun) (((fun) & 0x7) << 8) 90185089Sraj#define PCI_CFG_PCIE_REG(reg) ((reg) & 0xfc) 91185089Sraj 92185089Sraj#define PCI_REG_CFG_ADDR 0x0C78 93185089Sraj#define PCI_REG_CFG_DATA 0x0C7C 94185089Sraj 95185089Sraj#define PCIE_REG_CFG_ADDR 0x18F8 96185089Sraj#define PCIE_REG_CFG_DATA 0x18FC 97185089Sraj#define PCIE_REG_CONTROL 0x1A00 98185089Sraj#define PCIE_CTRL_LINK1X 0x00000001 99185089Sraj#define PCIE_REG_STATUS 0x1A04 100185089Sraj#define PCIE_REG_IRQ_MASK 0x1910 101185089Sraj 102240489Sgber#define PCIE_CONTROL_ROOT_CMPLX (1 << 1) 103240489Sgber#define PCIE_CONTROL_HOT_RESET (1 << 24) 104185089Sraj 105240489Sgber#define PCIE_LINK_TIMEOUT 1000000 106185089Sraj 107240489Sgber#define PCIE_STATUS_LINK_DOWN 1 108240489Sgber#define PCIE_STATUS_DEV_OFFS 16 109185089Sraj 110240489Sgber/* Minimum PCI Memory and I/O allocations taken from PCI spec (in bytes) */ 111240489Sgber#define PCI_MIN_IO_ALLOC 4 112240489Sgber#define PCI_MIN_MEM_ALLOC 16 113240489Sgber 114240489Sgber#define BITS_PER_UINT32 (NBBY * sizeof(uint32_t)) 115240489Sgber 116209131Srajstruct mv_pcib_softc { 117185089Sraj device_t sc_dev; 118185089Sraj 119209131Sraj struct rman sc_mem_rman; 120209131Sraj bus_addr_t sc_mem_base; 121209131Sraj bus_addr_t sc_mem_size; 122240489Sgber uint32_t sc_mem_map[MV_PCI_MEM_SLICE_SIZE / 123240489Sgber (PCI_MIN_MEM_ALLOC * BITS_PER_UINT32)]; 124240489Sgber int sc_win_target; 125209131Sraj int sc_mem_win_attr; 126185089Sraj 127209131Sraj struct rman sc_io_rman; 128209131Sraj bus_addr_t sc_io_base; 129209131Sraj bus_addr_t sc_io_size; 130240489Sgber uint32_t sc_io_map[MV_PCI_IO_SLICE_SIZE / 131240489Sgber (PCI_MIN_IO_ALLOC * BITS_PER_UINT32)]; 132209131Sraj int sc_io_win_attr; 133185089Sraj 134185089Sraj struct resource *sc_res; 135185089Sraj bus_space_handle_t sc_bsh; 136185089Sraj bus_space_tag_t sc_bst; 137185089Sraj int sc_rid; 138185089Sraj 139240493Sgber struct mtx sc_msi_mtx; 140240493Sgber uint32_t sc_msi_bitmap; 141240493Sgber 142185089Sraj int sc_busnr; /* Host bridge bus number */ 143185089Sraj int sc_devnr; /* Host bridge device number */ 144209131Sraj int sc_type; 145240489Sgber int sc_mode; /* Endpoint / Root Complex */ 146185089Sraj 147259484Snwhitehorn struct ofw_bus_iinfo sc_pci_iinfo; 148185089Sraj}; 149185089Sraj 150209131Sraj/* Local forward prototypes */ 151209131Srajstatic int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *); 152209131Srajstatic void mv_pcib_hw_cfginit(void); 153209131Srajstatic uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int, 154209131Sraj u_int, u_int, int); 155209131Srajstatic void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int, 156209131Sraj u_int, u_int, uint32_t, int); 157209131Srajstatic int mv_pcib_init(struct mv_pcib_softc *, int, int); 158209131Srajstatic int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int); 159209131Srajstatic void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int); 160209131Srajstatic inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t); 161240489Sgberstatic void mv_pcib_enable(struct mv_pcib_softc *, uint32_t); 162240489Sgberstatic int mv_pcib_mem_init(struct mv_pcib_softc *); 163185089Sraj 164209131Sraj/* Forward prototypes */ 165209131Srajstatic int mv_pcib_probe(device_t); 166209131Srajstatic int mv_pcib_attach(device_t); 167209131Sraj 168209131Srajstatic struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *, 169185089Sraj u_long, u_long, u_long, u_int); 170209131Srajstatic int mv_pcib_release_resource(device_t, device_t, int, int, 171185089Sraj struct resource *); 172209131Srajstatic int mv_pcib_read_ivar(device_t, device_t, int, uintptr_t *); 173209131Srajstatic int mv_pcib_write_ivar(device_t, device_t, int, uintptr_t); 174185089Sraj 175209131Srajstatic int mv_pcib_maxslots(device_t); 176209131Srajstatic uint32_t mv_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int); 177209131Srajstatic void mv_pcib_write_config(device_t, u_int, u_int, u_int, u_int, 178185089Sraj uint32_t, int); 179209131Srajstatic int mv_pcib_route_interrupt(device_t, device_t, int); 180240493Sgber#if defined(SOC_MV_ARMADAXP) 181240493Sgberstatic int mv_pcib_alloc_msi(device_t, device_t, int, int, int *); 182240493Sgberstatic int mv_pcib_map_msi(device_t, device_t, int, uint64_t *, uint32_t *); 183240493Sgberstatic int mv_pcib_release_msi(device_t, device_t, int, int *); 184240493Sgber#endif 185185089Sraj 186185089Sraj/* 187185089Sraj * Bus interface definitions. 188185089Sraj */ 189209131Srajstatic device_method_t mv_pcib_methods[] = { 190185089Sraj /* Device interface */ 191209131Sraj DEVMETHOD(device_probe, mv_pcib_probe), 192209131Sraj DEVMETHOD(device_attach, mv_pcib_attach), 193185089Sraj 194185089Sraj /* Bus interface */ 195209131Sraj DEVMETHOD(bus_read_ivar, mv_pcib_read_ivar), 196209131Sraj DEVMETHOD(bus_write_ivar, mv_pcib_write_ivar), 197209131Sraj DEVMETHOD(bus_alloc_resource, mv_pcib_alloc_resource), 198209131Sraj DEVMETHOD(bus_release_resource, mv_pcib_release_resource), 199185089Sraj DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 200185089Sraj DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 201185089Sraj DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 202185089Sraj DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 203185089Sraj 204185089Sraj /* pcib interface */ 205209131Sraj DEVMETHOD(pcib_maxslots, mv_pcib_maxslots), 206209131Sraj DEVMETHOD(pcib_read_config, mv_pcib_read_config), 207209131Sraj DEVMETHOD(pcib_write_config, mv_pcib_write_config), 208209131Sraj DEVMETHOD(pcib_route_interrupt, mv_pcib_route_interrupt), 209240493Sgber 210240493Sgber#if defined(SOC_MV_ARMADAXP) 211240493Sgber DEVMETHOD(pcib_alloc_msi, mv_pcib_alloc_msi), 212240493Sgber DEVMETHOD(pcib_release_msi, mv_pcib_release_msi), 213240493Sgber DEVMETHOD(pcib_map_msi, mv_pcib_map_msi), 214240493Sgber#endif 215240493Sgber 216209131Sraj /* OFW bus interface */ 217209131Sraj DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 218209131Sraj DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 219209131Sraj DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 220209131Sraj DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 221209131Sraj DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 222209131Sraj 223227843Smarius DEVMETHOD_END 224185089Sraj}; 225185089Sraj 226209131Srajstatic driver_t mv_pcib_driver = { 227185089Sraj "pcib", 228209131Sraj mv_pcib_methods, 229209131Sraj sizeof(struct mv_pcib_softc), 230185089Sraj}; 231185089Sraj 232185089Srajdevclass_t pcib_devclass; 233185089Sraj 234257702SnwhitehornDRIVER_MODULE(pcib, nexus, mv_pcib_driver, pcib_devclass, 0, 0); 235185089Sraj 236185089Srajstatic struct mtx pcicfg_mtx; 237185089Sraj 238185089Srajstatic int 239209131Srajmv_pcib_probe(device_t self) 240185089Sraj{ 241218228Smarcel phandle_t node; 242185089Sraj 243218228Smarcel node = ofw_bus_get_node(self); 244218228Smarcel if (!fdt_is_type(node, "pci")) 245209131Sraj return (ENXIO); 246218228Smarcel 247259484Snwhitehorn if (!(ofw_bus_is_compatible(self, "mrvl,pcie") || 248259484Snwhitehorn ofw_bus_is_compatible(self, "mrvl,pci"))) 249209131Sraj return (ENXIO); 250185089Sraj 251209131Sraj device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller"); 252209131Sraj return (BUS_PROBE_DEFAULT); 253185089Sraj} 254185089Sraj 255185089Srajstatic int 256209131Srajmv_pcib_attach(device_t self) 257185089Sraj{ 258209131Sraj struct mv_pcib_softc *sc; 259209131Sraj phandle_t node, parnode; 260240489Sgber uint32_t val, unit; 261209131Sraj int err; 262185089Sraj 263185089Sraj sc = device_get_softc(self); 264209131Sraj sc->sc_dev = self; 265240489Sgber unit = fdt_get_unit(self); 266185089Sraj 267240489Sgber 268218228Smarcel node = ofw_bus_get_node(self); 269218228Smarcel parnode = OF_parent(node); 270218228Smarcel if (fdt_is_compatible(node, "mrvl,pcie")) { 271209131Sraj sc->sc_type = MV_TYPE_PCIE; 272240489Sgber sc->sc_win_target = MV_WIN_PCIE_TARGET(unit); 273240489Sgber sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR(unit); 274240489Sgber sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR(unit); 275218228Smarcel } else if (fdt_is_compatible(node, "mrvl,pci")) { 276209131Sraj sc->sc_type = MV_TYPE_PCI; 277240489Sgber sc->sc_win_target = MV_WIN_PCI_TARGET; 278209131Sraj sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR; 279209131Sraj sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR; 280209131Sraj } else 281185089Sraj return (ENXIO); 282185089Sraj 283209131Sraj /* 284209131Sraj * Retrieve our mem-mapped registers range. 285209131Sraj */ 286185089Sraj sc->sc_rid = 0; 287185089Sraj sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid, 288185089Sraj RF_ACTIVE); 289185089Sraj if (sc->sc_res == NULL) { 290209131Sraj device_printf(self, "could not map memory\n"); 291185089Sraj return (ENXIO); 292185089Sraj } 293185089Sraj sc->sc_bst = rman_get_bustag(sc->sc_res); 294185089Sraj sc->sc_bsh = rman_get_bushandle(sc->sc_res); 295185089Sraj 296240489Sgber val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_CONTROL); 297240489Sgber sc->sc_mode = (val & PCIE_CONTROL_ROOT_CMPLX ? MV_MODE_ROOT : 298240489Sgber MV_MODE_ENDPOINT); 299240489Sgber 300209131Sraj /* 301240489Sgber * Get PCI interrupt info. 302240489Sgber */ 303259484Snwhitehorn if (sc->sc_mode == MV_MODE_ROOT) 304259484Snwhitehorn ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(pcell_t)); 305240489Sgber 306240489Sgber /* 307209131Sraj * Configure decode windows for PCI(E) access. 308209131Sraj */ 309209131Sraj if (mv_pcib_decode_win(node, sc) != 0) 310209131Sraj return (ENXIO); 311209131Sraj 312209131Sraj mv_pcib_hw_cfginit(); 313209131Sraj 314209131Sraj /* 315240489Sgber * Enable PCIE device. 316209131Sraj */ 317240489Sgber mv_pcib_enable(sc, unit); 318185089Sraj 319240489Sgber /* 320240489Sgber * Memory management. 321240489Sgber */ 322240489Sgber err = mv_pcib_mem_init(sc); 323240489Sgber if (err) 324240489Sgber return (err); 325185089Sraj 326240489Sgber if (sc->sc_mode == MV_MODE_ROOT) { 327240489Sgber err = mv_pcib_init(sc, sc->sc_busnr, 328240489Sgber mv_pcib_maxslots(sc->sc_dev)); 329240489Sgber if (err) 330240489Sgber goto error; 331240489Sgber 332240489Sgber device_add_child(self, "pci", -1); 333240489Sgber } else { 334240489Sgber sc->sc_devnr = 1; 335240489Sgber bus_space_write_4(sc->sc_bst, sc->sc_bsh, 336240489Sgber PCIE_REG_STATUS, 1 << PCIE_STATUS_DEV_OFFS); 337240489Sgber device_add_child(self, "pci_ep", -1); 338240489Sgber } 339240489Sgber 340240493Sgber mtx_init(&sc->sc_msi_mtx, "msi_mtx", NULL, MTX_DEF); 341240489Sgber return (bus_generic_attach(self)); 342240489Sgber 343240489Sgbererror: 344240489Sgber /* XXX SYS_RES_ should be released here */ 345240489Sgber rman_fini(&sc->sc_mem_rman); 346240489Sgber rman_fini(&sc->sc_io_rman); 347240489Sgber 348240489Sgber return (err); 349240489Sgber} 350240489Sgber 351240489Sgberstatic void 352240489Sgbermv_pcib_enable(struct mv_pcib_softc *sc, uint32_t unit) 353240489Sgber{ 354240489Sgber uint32_t val; 355240489Sgber#if !defined(SOC_MV_ARMADAXP) 356240489Sgber int timeout; 357240489Sgber 358240489Sgber /* 359240489Sgber * Check if PCIE device is enabled. 360240489Sgber */ 361240489Sgber if (read_cpu_ctrl(CPU_CONTROL) & CPU_CONTROL_PCIE_DISABLE(unit)) { 362240489Sgber write_cpu_ctrl(CPU_CONTROL, read_cpu_ctrl(CPU_CONTROL) & 363240489Sgber ~(CPU_CONTROL_PCIE_DISABLE(unit))); 364240489Sgber 365240489Sgber timeout = PCIE_LINK_TIMEOUT; 366240489Sgber val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 367240489Sgber PCIE_REG_STATUS); 368240489Sgber while (((val & PCIE_STATUS_LINK_DOWN) == 1) && (timeout > 0)) { 369240489Sgber DELAY(1000); 370240489Sgber timeout -= 1000; 371240489Sgber val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 372240489Sgber PCIE_REG_STATUS); 373240489Sgber } 374240489Sgber } 375240489Sgber#endif 376240489Sgber 377240489Sgber 378240489Sgber if (sc->sc_mode == MV_MODE_ROOT) { 379240489Sgber /* 380240489Sgber * Enable PCI bridge. 381240489Sgber */ 382240489Sgber val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND); 383240489Sgber val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | 384240489Sgber PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; 385240489Sgber bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND, val); 386240489Sgber } 387240489Sgber} 388240489Sgber 389240489Sgberstatic int 390240489Sgbermv_pcib_mem_init(struct mv_pcib_softc *sc) 391240489Sgber{ 392240489Sgber int err; 393240489Sgber 394240489Sgber /* 395240489Sgber * Memory management. 396240489Sgber */ 397209131Sraj sc->sc_mem_rman.rm_type = RMAN_ARRAY; 398209131Sraj err = rman_init(&sc->sc_mem_rman); 399186932Sraj if (err) 400186932Sraj return (err); 401186932Sraj 402209131Sraj sc->sc_io_rman.rm_type = RMAN_ARRAY; 403209131Sraj err = rman_init(&sc->sc_io_rman); 404186932Sraj if (err) { 405209131Sraj rman_fini(&sc->sc_mem_rman); 406186932Sraj return (err); 407186932Sraj } 408186932Sraj 409209131Sraj err = rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base, 410209131Sraj sc->sc_mem_base + sc->sc_mem_size - 1); 411186932Sraj if (err) 412186932Sraj goto error; 413186932Sraj 414209131Sraj err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base, 415209131Sraj sc->sc_io_base + sc->sc_io_size - 1); 416186932Sraj if (err) 417186932Sraj goto error; 418186932Sraj 419240489Sgber return (0); 420185089Sraj 421186932Srajerror: 422209131Sraj rman_fini(&sc->sc_mem_rman); 423209131Sraj rman_fini(&sc->sc_io_rman); 424240489Sgber 425186932Sraj return (err); 426185089Sraj} 427185089Sraj 428240489Sgberstatic inline uint32_t 429240489Sgberpcib_bit_get(uint32_t *map, uint32_t bit) 430240489Sgber{ 431240489Sgber uint32_t n = bit / BITS_PER_UINT32; 432240489Sgber 433240489Sgber bit = bit % BITS_PER_UINT32; 434240489Sgber return (map[n] & (1 << bit)); 435240489Sgber} 436240489Sgber 437240489Sgberstatic inline void 438240489Sgberpcib_bit_set(uint32_t *map, uint32_t bit) 439240489Sgber{ 440240489Sgber uint32_t n = bit / BITS_PER_UINT32; 441240489Sgber 442240489Sgber bit = bit % BITS_PER_UINT32; 443240489Sgber map[n] |= (1 << bit); 444240489Sgber} 445240489Sgber 446240489Sgberstatic inline uint32_t 447240489Sgberpcib_map_check(uint32_t *map, uint32_t start, uint32_t bits) 448240489Sgber{ 449240489Sgber uint32_t i; 450240489Sgber 451240489Sgber for (i = start; i < start + bits; i++) 452240489Sgber if (pcib_bit_get(map, i)) 453240489Sgber return (0); 454240489Sgber 455240489Sgber return (1); 456240489Sgber} 457240489Sgber 458240489Sgberstatic inline void 459240489Sgberpcib_map_set(uint32_t *map, uint32_t start, uint32_t bits) 460240489Sgber{ 461240489Sgber uint32_t i; 462240489Sgber 463240489Sgber for (i = start; i < start + bits; i++) 464240489Sgber pcib_bit_set(map, i); 465240489Sgber} 466240489Sgber 467240489Sgber/* 468240489Sgber * The idea of this allocator is taken from ARM No-Cache memory 469240489Sgber * management code (sys/arm/arm/vm_machdep.c). 470240489Sgber */ 471240489Sgberstatic bus_addr_t 472240489Sgberpcib_alloc(struct mv_pcib_softc *sc, uint32_t smask) 473240489Sgber{ 474240489Sgber uint32_t bits, bits_limit, i, *map, min_alloc, size; 475240489Sgber bus_addr_t addr = 0; 476240489Sgber bus_addr_t base; 477240489Sgber 478240489Sgber if (smask & 1) { 479240489Sgber base = sc->sc_io_base; 480240489Sgber min_alloc = PCI_MIN_IO_ALLOC; 481240489Sgber bits_limit = sc->sc_io_size / min_alloc; 482240489Sgber map = sc->sc_io_map; 483240489Sgber smask &= ~0x3; 484240489Sgber } else { 485240489Sgber base = sc->sc_mem_base; 486240489Sgber min_alloc = PCI_MIN_MEM_ALLOC; 487240489Sgber bits_limit = sc->sc_mem_size / min_alloc; 488240489Sgber map = sc->sc_mem_map; 489240489Sgber smask &= ~0xF; 490240489Sgber } 491240489Sgber 492240489Sgber size = ~smask + 1; 493240489Sgber bits = size / min_alloc; 494240489Sgber 495240489Sgber for (i = 0; i + bits <= bits_limit; i += bits) 496240489Sgber if (pcib_map_check(map, i, bits)) { 497240489Sgber pcib_map_set(map, i, bits); 498240489Sgber addr = base + (i * min_alloc); 499240489Sgber return (addr); 500240489Sgber } 501240489Sgber 502240489Sgber return (addr); 503240489Sgber} 504240489Sgber 505185089Srajstatic int 506209131Srajmv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func, 507185089Sraj int barno) 508185089Sraj{ 509240489Sgber uint32_t addr, bar; 510185089Sraj int reg, width; 511185089Sraj 512185089Sraj reg = PCIR_BAR(barno); 513240489Sgber 514240489Sgber /* 515240489Sgber * Need to init the BAR register with 0xffffffff before correct 516240489Sgber * value can be read. 517240489Sgber */ 518240489Sgber mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4); 519209131Sraj bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4); 520185089Sraj if (bar == 0) 521185089Sraj return (1); 522185089Sraj 523185089Sraj /* Calculate BAR size: 64 or 32 bit (in 32-bit units) */ 524185089Sraj width = ((bar & 7) == 4) ? 2 : 1; 525185089Sraj 526240489Sgber addr = pcib_alloc(sc, bar); 527240489Sgber if (!addr) 528185089Sraj return (-1); 529185089Sraj 530185089Sraj if (bootverbose) 531240489Sgber printf("PCI %u:%u:%u: reg %x: smask=%08x: addr=%08x\n", 532240489Sgber bus, slot, func, reg, bar, addr); 533185089Sraj 534209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4); 535185089Sraj if (width == 2) 536209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4, 537185089Sraj 0, 4); 538185089Sraj 539185089Sraj return (width); 540185089Sraj} 541185089Sraj 542185089Srajstatic void 543209131Srajmv_pcib_init_bridge(struct mv_pcib_softc *sc, int bus, int slot, int func) 544185089Sraj{ 545185089Sraj bus_addr_t io_base, mem_base; 546185089Sraj uint32_t io_limit, mem_limit; 547185089Sraj int secbus; 548185089Sraj 549209131Sraj io_base = sc->sc_io_base; 550209131Sraj io_limit = io_base + sc->sc_io_size - 1; 551209131Sraj mem_base = sc->sc_mem_base; 552209131Sraj mem_limit = mem_base + sc->sc_mem_size - 1; 553185089Sraj 554185089Sraj /* Configure I/O decode registers */ 555209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1, 556185639Sraj io_base >> 8, 1); 557209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1, 558185639Sraj io_base >> 16, 2); 559209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1, 560185089Sraj io_limit >> 8, 1); 561209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1, 562185089Sraj io_limit >> 16, 2); 563185089Sraj 564185089Sraj /* Configure memory decode registers */ 565209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1, 566185089Sraj mem_base >> 16, 2); 567209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1, 568185089Sraj mem_limit >> 16, 2); 569185089Sraj 570185089Sraj /* Disable memory prefetch decode */ 571209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1, 572185089Sraj 0x10, 2); 573209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1, 574185089Sraj 0x0, 4); 575209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1, 576185089Sraj 0xF, 2); 577209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1, 578185089Sraj 0x0, 4); 579185089Sraj 580209131Sraj secbus = mv_pcib_read_config(sc->sc_dev, bus, slot, func, 581185089Sraj PCIR_SECBUS_1, 1); 582185089Sraj 583185089Sraj /* Configure buses behind the bridge */ 584209131Sraj mv_pcib_init(sc, secbus, PCI_SLOTMAX); 585185089Sraj} 586185089Sraj 587185089Srajstatic int 588209131Srajmv_pcib_init(struct mv_pcib_softc *sc, int bus, int maxslot) 589185089Sraj{ 590185089Sraj int slot, func, maxfunc, error; 591185089Sraj uint8_t hdrtype, command, class, subclass; 592185089Sraj 593185089Sraj for (slot = 0; slot <= maxslot; slot++) { 594185089Sraj maxfunc = 0; 595185089Sraj for (func = 0; func <= maxfunc; func++) { 596209131Sraj hdrtype = mv_pcib_read_config(sc->sc_dev, bus, slot, 597185089Sraj func, PCIR_HDRTYPE, 1); 598185089Sraj 599185089Sraj if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 600185089Sraj continue; 601185089Sraj 602185089Sraj if (func == 0 && (hdrtype & PCIM_MFDEV)) 603185089Sraj maxfunc = PCI_FUNCMAX; 604185089Sraj 605209131Sraj command = mv_pcib_read_config(sc->sc_dev, bus, slot, 606185089Sraj func, PCIR_COMMAND, 1); 607185089Sraj command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); 608209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, 609185089Sraj PCIR_COMMAND, command, 1); 610185089Sraj 611209131Sraj error = mv_pcib_init_all_bars(sc, bus, slot, func, 612185089Sraj hdrtype); 613185089Sraj 614185089Sraj if (error) 615185089Sraj return (error); 616185089Sraj 617185089Sraj command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | 618185089Sraj PCIM_CMD_PORTEN; 619209131Sraj mv_pcib_write_config(sc->sc_dev, bus, slot, func, 620185089Sraj PCIR_COMMAND, command, 1); 621185089Sraj 622185089Sraj /* Handle PCI-PCI bridges */ 623209131Sraj class = mv_pcib_read_config(sc->sc_dev, bus, slot, 624185089Sraj func, PCIR_CLASS, 1); 625209131Sraj subclass = mv_pcib_read_config(sc->sc_dev, bus, slot, 626185089Sraj func, PCIR_SUBCLASS, 1); 627185089Sraj 628185089Sraj if (class != PCIC_BRIDGE || 629185089Sraj subclass != PCIS_BRIDGE_PCI) 630185089Sraj continue; 631185089Sraj 632209131Sraj mv_pcib_init_bridge(sc, bus, slot, func); 633185089Sraj } 634185089Sraj } 635185089Sraj 636185089Sraj /* Enable all ABCD interrupts */ 637185089Sraj pcib_write_irq_mask(sc, (0xF << 24)); 638185089Sraj 639185089Sraj return (0); 640185089Sraj} 641185089Sraj 642209131Srajstatic int 643209131Srajmv_pcib_init_all_bars(struct mv_pcib_softc *sc, int bus, int slot, 644209131Sraj int func, int hdrtype) 645209131Sraj{ 646209131Sraj int maxbar, bar, i; 647209131Sraj 648209131Sraj maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6; 649209131Sraj bar = 0; 650209131Sraj 651209131Sraj /* Program the base address registers */ 652209131Sraj while (bar < maxbar) { 653209131Sraj i = mv_pcib_init_bar(sc, bus, slot, func, bar); 654209131Sraj bar += i; 655209131Sraj if (i < 0) { 656209131Sraj device_printf(sc->sc_dev, 657209131Sraj "PCI IO/Memory space exhausted\n"); 658209131Sraj return (ENOMEM); 659209131Sraj } 660209131Sraj } 661209131Sraj 662209131Sraj return (0); 663209131Sraj} 664209131Sraj 665185089Srajstatic struct resource * 666209131Srajmv_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 667185089Sraj u_long start, u_long end, u_long count, u_int flags) 668185089Sraj{ 669209131Sraj struct mv_pcib_softc *sc = device_get_softc(dev); 670186932Sraj struct rman *rm = NULL; 671186932Sraj struct resource *res; 672185089Sraj 673186932Sraj switch (type) { 674186932Sraj case SYS_RES_IOPORT: 675209131Sraj rm = &sc->sc_io_rman; 676186932Sraj break; 677186932Sraj case SYS_RES_MEMORY: 678209131Sraj rm = &sc->sc_mem_rman; 679186932Sraj break; 680186932Sraj default: 681240489Sgber return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 682186932Sraj type, rid, start, end, count, flags)); 683186932Sraj }; 684186932Sraj 685240489Sgber if ((start == 0UL) && (end == ~0UL)) { 686240489Sgber start = sc->sc_mem_base; 687240489Sgber end = sc->sc_mem_base + sc->sc_mem_size - 1; 688240489Sgber count = sc->sc_mem_size; 689240489Sgber } 690240489Sgber 691240489Sgber if ((start < sc->sc_mem_base) || (start + count - 1 != end) || 692240489Sgber (end > sc->sc_mem_base + sc->sc_mem_size - 1)) 693240489Sgber return (NULL); 694240489Sgber 695186932Sraj res = rman_reserve_resource(rm, start, end, count, flags, child); 696186932Sraj if (res == NULL) 697186932Sraj return (NULL); 698186932Sraj 699186932Sraj rman_set_rid(res, *rid); 700209131Sraj rman_set_bustag(res, fdtbus_bs_tag); 701186932Sraj rman_set_bushandle(res, start); 702186932Sraj 703186932Sraj if (flags & RF_ACTIVE) 704186932Sraj if (bus_activate_resource(child, type, *rid, res)) { 705186932Sraj rman_release_resource(res); 706186932Sraj return (NULL); 707186932Sraj } 708186932Sraj 709186932Sraj return (res); 710185089Sraj} 711185089Sraj 712185089Srajstatic int 713209131Srajmv_pcib_release_resource(device_t dev, device_t child, int type, int rid, 714185089Sraj struct resource *res) 715185089Sraj{ 716185089Sraj 717186932Sraj if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) 718186932Sraj return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 719186932Sraj type, rid, res)); 720186932Sraj 721186932Sraj return (rman_release_resource(res)); 722185089Sraj} 723185089Sraj 724185089Srajstatic int 725209131Srajmv_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 726185089Sraj{ 727209131Sraj struct mv_pcib_softc *sc = device_get_softc(dev); 728185089Sraj 729185089Sraj switch (which) { 730185089Sraj case PCIB_IVAR_BUS: 731185089Sraj *result = sc->sc_busnr; 732185089Sraj return (0); 733185089Sraj case PCIB_IVAR_DOMAIN: 734185089Sraj *result = device_get_unit(dev); 735185089Sraj return (0); 736185089Sraj } 737185089Sraj 738185089Sraj return (ENOENT); 739185089Sraj} 740185089Sraj 741185089Srajstatic int 742209131Srajmv_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 743185089Sraj{ 744209131Sraj struct mv_pcib_softc *sc = device_get_softc(dev); 745185089Sraj 746185089Sraj switch (which) { 747185089Sraj case PCIB_IVAR_BUS: 748185089Sraj sc->sc_busnr = value; 749185089Sraj return (0); 750185089Sraj } 751185089Sraj 752185089Sraj return (ENOENT); 753185089Sraj} 754209131Sraj 755209131Srajstatic inline void 756209131Srajpcib_write_irq_mask(struct mv_pcib_softc *sc, uint32_t mask) 757209131Sraj{ 758209131Sraj 759209131Sraj if (!sc->sc_type != MV_TYPE_PCI) 760209131Sraj return; 761209131Sraj 762209131Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_IRQ_MASK, mask); 763209131Sraj} 764209131Sraj 765209131Srajstatic void 766209131Srajmv_pcib_hw_cfginit(void) 767209131Sraj{ 768209131Sraj static int opened = 0; 769209131Sraj 770209131Sraj if (opened) 771209131Sraj return; 772209131Sraj 773209131Sraj mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN); 774209131Sraj opened = 1; 775209131Sraj} 776209131Sraj 777209131Srajstatic uint32_t 778209131Srajmv_pcib_hw_cfgread(struct mv_pcib_softc *sc, u_int bus, u_int slot, 779209131Sraj u_int func, u_int reg, int bytes) 780209131Sraj{ 781209131Sraj uint32_t addr, data, ca, cd; 782209131Sraj 783209131Sraj ca = (sc->sc_type != MV_TYPE_PCI) ? 784209131Sraj PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; 785209131Sraj cd = (sc->sc_type != MV_TYPE_PCI) ? 786209131Sraj PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; 787209131Sraj addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | 788209131Sraj PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); 789209131Sraj 790209131Sraj mtx_lock_spin(&pcicfg_mtx); 791209131Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); 792209131Sraj 793209131Sraj data = ~0; 794209131Sraj switch (bytes) { 795209131Sraj case 1: 796209131Sraj data = bus_space_read_1(sc->sc_bst, sc->sc_bsh, 797209131Sraj cd + (reg & 3)); 798209131Sraj break; 799209131Sraj case 2: 800209131Sraj data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh, 801209131Sraj cd + (reg & 2))); 802209131Sraj break; 803209131Sraj case 4: 804209131Sraj data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh, 805209131Sraj cd)); 806209131Sraj break; 807209131Sraj } 808209131Sraj mtx_unlock_spin(&pcicfg_mtx); 809209131Sraj return (data); 810209131Sraj} 811209131Sraj 812209131Srajstatic void 813209131Srajmv_pcib_hw_cfgwrite(struct mv_pcib_softc *sc, u_int bus, u_int slot, 814209131Sraj u_int func, u_int reg, uint32_t data, int bytes) 815209131Sraj{ 816209131Sraj uint32_t addr, ca, cd; 817209131Sraj 818209131Sraj ca = (sc->sc_type != MV_TYPE_PCI) ? 819209131Sraj PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR; 820209131Sraj cd = (sc->sc_type != MV_TYPE_PCI) ? 821209131Sraj PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA; 822209131Sraj addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | 823209131Sraj PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg); 824209131Sraj 825209131Sraj mtx_lock_spin(&pcicfg_mtx); 826209131Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr); 827209131Sraj 828209131Sraj switch (bytes) { 829209131Sraj case 1: 830209131Sraj bus_space_write_1(sc->sc_bst, sc->sc_bsh, 831209131Sraj cd + (reg & 3), data); 832209131Sraj break; 833209131Sraj case 2: 834209131Sraj bus_space_write_2(sc->sc_bst, sc->sc_bsh, 835209131Sraj cd + (reg & 2), htole16(data)); 836209131Sraj break; 837209131Sraj case 4: 838209131Sraj bus_space_write_4(sc->sc_bst, sc->sc_bsh, 839209131Sraj cd, htole32(data)); 840209131Sraj break; 841209131Sraj } 842209131Sraj mtx_unlock_spin(&pcicfg_mtx); 843209131Sraj} 844209131Sraj 845209131Srajstatic int 846209131Srajmv_pcib_maxslots(device_t dev) 847209131Sraj{ 848209131Sraj struct mv_pcib_softc *sc = device_get_softc(dev); 849209131Sraj 850209131Sraj return ((sc->sc_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX); 851209131Sraj} 852209131Sraj 853209131Srajstatic uint32_t 854209131Srajmv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, 855209131Sraj u_int reg, int bytes) 856209131Sraj{ 857209131Sraj struct mv_pcib_softc *sc = device_get_softc(dev); 858209131Sraj 859240489Sgber /* Return ~0 if link is inactive or trying to read from Root */ 860240489Sgber if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) & 861240489Sgber PCIE_STATUS_LINK_DOWN) || (slot == 0)) 862209131Sraj return (~0U); 863209131Sraj 864209131Sraj return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes)); 865209131Sraj} 866209131Sraj 867209131Srajstatic void 868209131Srajmv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, 869209131Sraj u_int reg, uint32_t val, int bytes) 870209131Sraj{ 871209131Sraj struct mv_pcib_softc *sc = device_get_softc(dev); 872209131Sraj 873240489Sgber /* Return if link is inactive or trying to write to Root */ 874240489Sgber if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) & 875240489Sgber PCIE_STATUS_LINK_DOWN) || (slot == 0)) 876209131Sraj return; 877209131Sraj 878209131Sraj mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes); 879209131Sraj} 880209131Sraj 881209131Srajstatic int 882259484Snwhitehornmv_pcib_route_interrupt(device_t bus, device_t dev, int pin) 883209131Sraj{ 884209131Sraj struct mv_pcib_softc *sc; 885259484Snwhitehorn struct ofw_pci_register reg; 886259484Snwhitehorn uint32_t pintr, mintr; 887259484Snwhitehorn phandle_t iparent; 888209131Sraj 889259484Snwhitehorn sc = device_get_softc(bus); 890259484Snwhitehorn pintr = pin; 891209131Sraj 892259484Snwhitehorn /* Fabricate imap information in case this isn't an OFW device */ 893259484Snwhitehorn bzero(®, sizeof(reg)); 894259484Snwhitehorn reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | 895259484Snwhitehorn (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | 896259484Snwhitehorn (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); 897209131Sraj 898259484Snwhitehorn if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, 899259484Snwhitehorn sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), 900259516Snwhitehorn &iparent)) 901259484Snwhitehorn return (ofw_bus_map_intr(dev, iparent, mintr)); 902259484Snwhitehorn 903259484Snwhitehorn /* Maybe it's a real interrupt, not an intpin */ 904259484Snwhitehorn if (pin > 4) 905259484Snwhitehorn return (pin); 906259484Snwhitehorn 907259484Snwhitehorn device_printf(bus, "could not route pin %d for device %d.%d\n", 908209131Sraj pin, pci_get_slot(dev), pci_get_function(dev)); 909209131Sraj return (PCI_INVALID_IRQ); 910209131Sraj} 911209131Sraj 912209131Srajstatic int 913209131Srajmv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc) 914209131Sraj{ 915209131Sraj struct fdt_pci_range io_space, mem_space; 916209131Sraj device_t dev; 917209131Sraj int error; 918209131Sraj 919209131Sraj dev = sc->sc_dev; 920209131Sraj 921209131Sraj if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) { 922209131Sraj device_printf(dev, "could not retrieve 'ranges' data\n"); 923209131Sraj return (error); 924209131Sraj } 925209131Sraj 926209131Sraj /* Configure CPU decoding windows */ 927240489Sgber error = decode_win_cpu_set(sc->sc_win_target, 928240489Sgber sc->sc_io_win_attr, io_space.base_parent, io_space.len, ~0); 929209131Sraj if (error < 0) { 930209131Sraj device_printf(dev, "could not set up CPU decode " 931209131Sraj "window for PCI IO\n"); 932209131Sraj return (ENXIO); 933209131Sraj } 934240489Sgber error = decode_win_cpu_set(sc->sc_win_target, 935240489Sgber sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len, 936240489Sgber mem_space.base_parent); 937209131Sraj if (error < 0) { 938209131Sraj device_printf(dev, "could not set up CPU decode " 939209131Sraj "windows for PCI MEM\n"); 940209131Sraj return (ENXIO); 941209131Sraj } 942209131Sraj 943209131Sraj sc->sc_io_base = io_space.base_parent; 944209131Sraj sc->sc_io_size = io_space.len; 945209131Sraj 946209131Sraj sc->sc_mem_base = mem_space.base_parent; 947209131Sraj sc->sc_mem_size = mem_space.len; 948209131Sraj 949209131Sraj return (0); 950209131Sraj} 951209131Sraj 952240493Sgber#if defined(SOC_MV_ARMADAXP) 953240493Sgberstatic int 954240493Sgbermv_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, 955240493Sgber uint32_t *data) 956240493Sgber{ 957240493Sgber struct mv_pcib_softc *sc; 958240493Sgber 959240493Sgber sc = device_get_softc(dev); 960240493Sgber irq = irq - MSI_IRQ; 961240493Sgber 962240493Sgber /* validate parameters */ 963240493Sgber if (isclr(&sc->sc_msi_bitmap, irq)) { 964240493Sgber device_printf(dev, "invalid MSI 0x%x\n", irq); 965240493Sgber return (EINVAL); 966240493Sgber } 967240493Sgber 968240493Sgber mv_msi_data(irq, addr, data); 969240493Sgber 970240493Sgber debugf("%s: irq: %d addr: %jx data: %x\n", 971240493Sgber __func__, irq, *addr, *data); 972240493Sgber 973240493Sgber return (0); 974240493Sgber} 975240493Sgber 976240493Sgberstatic int 977240493Sgbermv_pcib_alloc_msi(device_t dev, device_t child, int count, 978240493Sgber int maxcount __unused, int *irqs) 979240493Sgber{ 980240493Sgber struct mv_pcib_softc *sc; 981240493Sgber u_int start = 0, i; 982240493Sgber 983240493Sgber if (powerof2(count) == 0 || count > MSI_IRQ_NUM) 984240493Sgber return (EINVAL); 985240493Sgber 986240493Sgber sc = device_get_softc(dev); 987240493Sgber mtx_lock(&sc->sc_msi_mtx); 988240493Sgber 989240493Sgber for (start = 0; (start + count) < MSI_IRQ_NUM; start++) { 990240493Sgber for (i = start; i < start + count; i++) { 991240493Sgber if (isset(&sc->sc_msi_bitmap, i)) 992240493Sgber break; 993240493Sgber } 994240493Sgber if (i == start + count) 995240493Sgber break; 996240493Sgber } 997240493Sgber 998240493Sgber if ((start + count) == MSI_IRQ_NUM) { 999240493Sgber mtx_unlock(&sc->sc_msi_mtx); 1000240493Sgber return (ENXIO); 1001240493Sgber } 1002240493Sgber 1003240493Sgber for (i = start; i < start + count; i++) { 1004240493Sgber setbit(&sc->sc_msi_bitmap, i); 1005240493Sgber irqs[i] = MSI_IRQ + i; 1006240493Sgber } 1007240493Sgber debugf("%s: start: %x count: %x\n", __func__, start, count); 1008240493Sgber 1009240493Sgber mtx_unlock(&sc->sc_msi_mtx); 1010240493Sgber return (0); 1011240493Sgber} 1012240493Sgber 1013240493Sgberstatic int 1014240493Sgbermv_pcib_release_msi(device_t dev, device_t child, int count, int *irqs) 1015240493Sgber{ 1016240493Sgber struct mv_pcib_softc *sc; 1017240493Sgber u_int i; 1018240493Sgber 1019240493Sgber sc = device_get_softc(dev); 1020240493Sgber mtx_lock(&sc->sc_msi_mtx); 1021240493Sgber 1022240493Sgber for (i = 0; i < count; i++) 1023240493Sgber clrbit(&sc->sc_msi_bitmap, irqs[i] - MSI_IRQ); 1024240493Sgber 1025240493Sgber mtx_unlock(&sc->sc_msi_mtx); 1026240493Sgber return (0); 1027240493Sgber} 1028240493Sgber#endif 1029