1221254Sadrian/*- 2221254Sadrian * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3221254Sadrian * Copyright (c) 2011, Luiz Otavio O Souza. 4221254Sadrian * All rights reserved. 5221254Sadrian * 6221254Sadrian * Redistribution and use in source and binary forms, with or without 7221254Sadrian * modification, are permitted provided that the following conditions 8221254Sadrian * are met: 9221254Sadrian * 1. Redistributions of source code must retain the above copyright 10221254Sadrian * notice unmodified, this list of conditions, and the following 11221254Sadrian * disclaimer. 12221254Sadrian * 2. Redistributions in binary form must reproduce the above copyright 13221254Sadrian * notice, this list of conditions and the following disclaimer in the 14221254Sadrian * documentation and/or other materials provided with the distribution. 15221254Sadrian * 16221254Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17221254Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18221254Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19221254Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20221254Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21221254Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22221254Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23221254Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24221254Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25221254Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26221254Sadrian * SUCH DAMAGE. 27221254Sadrian */ 28221254Sadrian 29221254Sadrian#include <sys/cdefs.h> 30221254Sadrian__FBSDID("$FreeBSD$"); 31221254Sadrian 32234485Sadrian#include "opt_ar71xx.h" 33234485Sadrian 34221254Sadrian#include <sys/param.h> 35221254Sadrian#include <sys/systm.h> 36221254Sadrian 37221254Sadrian#include <sys/bus.h> 38221254Sadrian#include <sys/interrupt.h> 39221254Sadrian#include <sys/malloc.h> 40221254Sadrian#include <sys/kernel.h> 41221254Sadrian#include <sys/module.h> 42221254Sadrian#include <sys/rman.h> 43221254Sadrian 44221254Sadrian#include <vm/vm.h> 45221254Sadrian#include <vm/pmap.h> 46221254Sadrian#include <vm/vm_extern.h> 47221254Sadrian 48221254Sadrian#include <machine/bus.h> 49221254Sadrian#include <machine/cpu.h> 50221254Sadrian#include <machine/intr_machdep.h> 51221254Sadrian#include <machine/pmap.h> 52221254Sadrian 53221254Sadrian#include <dev/pci/pcivar.h> 54221254Sadrian#include <dev/pci/pcireg.h> 55221254Sadrian 56221254Sadrian#include <dev/pci/pcib_private.h> 57221254Sadrian#include "pcib_if.h" 58221254Sadrian 59221254Sadrian#include <mips/atheros/ar71xxreg.h> 60221254Sadrian#include <mips/atheros/ar724xreg.h> 61221254Sadrian#include <mips/atheros/ar71xx_setup.h> 62221307Sadrian#include <mips/atheros/ar71xx_pci_bus_space.h> 63221254Sadrian 64221254Sadrian#include <mips/atheros/ar71xx_cpudef.h> 65221254Sadrian 66234485Sadrian#ifdef AR71XX_ATH_EEPROM 67234485Sadrian#include <mips/atheros/ar71xx_fixup.h> 68234485Sadrian#endif /* AR71XX_ATH_EEPROM */ 69234485Sadrian 70221255Sadrian#undef AR724X_PCI_DEBUG 71221254Sadrian#ifdef AR724X_PCI_DEBUG 72221254Sadrian#define dprintf printf 73221254Sadrian#else 74221254Sadrian#define dprintf(x, arg...) 75221254Sadrian#endif 76221254Sadrian 77221254Sadrianstruct ar71xx_pci_softc { 78221254Sadrian device_t sc_dev; 79221254Sadrian 80221254Sadrian int sc_busno; 81221254Sadrian struct rman sc_mem_rman; 82221254Sadrian struct rman sc_irq_rman; 83221254Sadrian 84221254Sadrian struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; 85221254Sadrian mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; 86221254Sadrian struct resource *sc_irq; 87221254Sadrian void *sc_ih; 88221254Sadrian}; 89221254Sadrian 90221254Sadrianstatic int ar724x_pci_setup_intr(device_t, device_t, struct resource *, int, 91221254Sadrian driver_filter_t *, driver_intr_t *, void *, void **); 92221254Sadrianstatic int ar724x_pci_teardown_intr(device_t, device_t, struct resource *, 93221254Sadrian void *); 94221254Sadrianstatic int ar724x_pci_intr(void *); 95221254Sadrian 96221254Sadrianstatic void 97221254Sadrianar724x_pci_write(uint32_t reg, uint32_t offset, uint32_t data, int bytes) 98221254Sadrian{ 99221254Sadrian uint32_t val, mask, shift; 100221254Sadrian 101221254Sadrian /* Register access is 32-bit aligned */ 102229765Sadrian shift = (offset & 3) * 8; 103221254Sadrian if (bytes % 4) 104221254Sadrian mask = (1 << (bytes * 8)) - 1; 105221254Sadrian else 106221254Sadrian mask = 0xffffffff; 107221254Sadrian 108221254Sadrian val = ATH_READ_REG(reg + (offset & ~3)); 109221254Sadrian val &= ~(mask << shift); 110221254Sadrian val |= ((data & mask) << shift); 111221254Sadrian ATH_WRITE_REG(reg + (offset & ~3), val); 112221254Sadrian 113221254Sadrian dprintf("%s: %#x/%#x addr=%#x, data=%#x(%#x), bytes=%d\n", __func__, 114221254Sadrian reg, reg + (offset & ~3), offset, data, val, bytes); 115221254Sadrian} 116221254Sadrian 117221254Sadrianstatic uint32_t 118221254Sadrianar724x_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 119221254Sadrian u_int reg, int bytes) 120221254Sadrian{ 121221307Sadrian uint32_t data, shift, mask; 122221254Sadrian 123221254Sadrian /* Register access is 32-bit aligned */ 124221254Sadrian shift = (reg & 3) * 8; 125221254Sadrian if (shift) 126221254Sadrian mask = (1 << shift) - 1; 127221254Sadrian else 128221254Sadrian mask = 0xffffffff; 129221254Sadrian 130221254Sadrian dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 131221254Sadrian func, reg, bytes); 132221254Sadrian 133221307Sadrian if ((bus == 0) && (slot == 0) && (func == 0)) 134221254Sadrian data = ATH_READ_REG(AR724X_PCI_CFG_BASE + (reg & ~3)); 135221307Sadrian else 136221254Sadrian data = -1; 137221254Sadrian 138221254Sadrian /* Get request bytes from 32-bit word */ 139221254Sadrian data = (data >> shift) & mask; 140221254Sadrian 141221254Sadrian dprintf("%s: read 0x%x\n", __func__, data); 142221254Sadrian 143221254Sadrian return (data); 144221254Sadrian} 145221254Sadrian 146221254Sadrianstatic void 147221254Sadrianar724x_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 148221254Sadrian u_int reg, uint32_t data, int bytes) 149221254Sadrian{ 150221254Sadrian 151221254Sadrian dprintf("%s: tag (%x, %x, %x) reg %d(%d): %x\n", __func__, bus, slot, 152221254Sadrian func, reg, bytes, data); 153221254Sadrian 154221254Sadrian if ((bus != 0) || (slot != 0) || (func != 0)) 155221254Sadrian return; 156221254Sadrian 157221254Sadrian /* 158221307Sadrian * WAR for BAR issue on AR7240 - We are unable to access the PCI device 159221307Sadrian * space if we set the BAR with proper base address. 160221254Sadrian */ 161221307Sadrian if (reg == PCIR_BAR(0) && bytes == 4 && ar71xx_soc == AR71XX_SOC_AR7240) 162221307Sadrian ar724x_pci_write(AR724X_PCI_CFG_BASE, reg, 0xffff, bytes); 163221307Sadrian else 164221307Sadrian ar724x_pci_write(AR724X_PCI_CFG_BASE, reg, data, bytes); 165221254Sadrian} 166221254Sadrian 167221254Sadrianstatic void 168221254Sadrianar724x_pci_mask_irq(void *source) 169221254Sadrian{ 170221254Sadrian uint32_t reg; 171221254Sadrian unsigned int irq = (unsigned int)source; 172221254Sadrian 173221254Sadrian /* XXX - Only one interrupt ? Only one device ? */ 174221254Sadrian if (irq != AR71XX_PCI_IRQ_START) 175221254Sadrian return; 176221254Sadrian 177221254Sadrian /* Update the interrupt mask reg */ 178221254Sadrian reg = ATH_READ_REG(AR724X_PCI_INTR_MASK); 179221254Sadrian ATH_WRITE_REG(AR724X_PCI_INTR_MASK, 180221254Sadrian reg & ~AR724X_PCI_INTR_DEV0); 181221254Sadrian 182221254Sadrian /* Clear any pending interrupt */ 183221254Sadrian reg = ATH_READ_REG(AR724X_PCI_INTR_STATUS); 184221254Sadrian ATH_WRITE_REG(AR724X_PCI_INTR_STATUS, 185221254Sadrian reg | AR724X_PCI_INTR_DEV0); 186221254Sadrian} 187221254Sadrian 188221254Sadrianstatic void 189221254Sadrianar724x_pci_unmask_irq(void *source) 190221254Sadrian{ 191221254Sadrian uint32_t reg; 192221254Sadrian unsigned int irq = (unsigned int)source; 193221254Sadrian 194221254Sadrian /* XXX */ 195221254Sadrian if (irq != AR71XX_PCI_IRQ_START) 196221254Sadrian return; 197221254Sadrian 198221254Sadrian /* Update the interrupt mask reg */ 199221254Sadrian reg = ATH_READ_REG(AR724X_PCI_INTR_MASK); 200221254Sadrian ATH_WRITE_REG(AR724X_PCI_INTR_MASK, 201221254Sadrian reg | AR724X_PCI_INTR_DEV0); 202221254Sadrian} 203221254Sadrian 204221254Sadrianstatic int 205221254Sadrianar724x_pci_setup(device_t dev) 206221254Sadrian{ 207221254Sadrian uint32_t reg; 208221254Sadrian 209221254Sadrian /* setup COMMAND register */ 210221254Sadrian reg = PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_SERRESPEN | 211221254Sadrian PCIM_CMD_BACKTOBACK | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN; 212221254Sadrian 213221254Sadrian ar724x_pci_write(AR724X_PCI_CRP_BASE, PCIR_COMMAND, reg, 2); 214221254Sadrian ar724x_pci_write(AR724X_PCI_CRP_BASE, 0x20, 0x1ff01000, 4); 215221254Sadrian ar724x_pci_write(AR724X_PCI_CRP_BASE, 0x24, 0x1ff01000, 4); 216221254Sadrian 217221254Sadrian reg = ATH_READ_REG(AR724X_PCI_RESET); 218221254Sadrian if (reg != 0x7) { 219221254Sadrian DELAY(100000); 220221254Sadrian ATH_WRITE_REG(AR724X_PCI_RESET, 0); 221221254Sadrian DELAY(100); 222221254Sadrian ATH_WRITE_REG(AR724X_PCI_RESET, 4); 223221254Sadrian DELAY(100000); 224221254Sadrian } 225221254Sadrian 226221254Sadrian if (ar71xx_soc == AR71XX_SOC_AR7240) 227221254Sadrian reg = AR724X_PCI_APP_LTSSM_ENABLE; 228221254Sadrian else 229221254Sadrian reg = 0x1ffc1; 230221254Sadrian ATH_WRITE_REG(AR724X_PCI_APP, reg); 231221307Sadrian /* Flush write */ 232221307Sadrian (void) ATH_READ_REG(AR724X_PCI_APP); 233221307Sadrian 234221254Sadrian DELAY(1000); 235221254Sadrian 236221254Sadrian reg = ATH_READ_REG(AR724X_PCI_RESET); 237221254Sadrian if ((reg & AR724X_PCI_RESET_LINK_UP) == 0) { 238221254Sadrian device_printf(dev, "no PCIe controller found\n"); 239221254Sadrian return (ENXIO); 240221254Sadrian } 241221254Sadrian 242221254Sadrian if (ar71xx_soc == AR71XX_SOC_AR7241 || 243221254Sadrian ar71xx_soc == AR71XX_SOC_AR7242) { 244221254Sadrian reg = ATH_READ_REG(AR724X_PCI_APP); 245221254Sadrian reg |= (1 << 16); 246221254Sadrian ATH_WRITE_REG(AR724X_PCI_APP, reg); 247221254Sadrian } 248221254Sadrian 249221254Sadrian return (0); 250221254Sadrian} 251221254Sadrian 252234485Sadrian#ifdef AR71XX_ATH_EEPROM 253221254Sadrian#define AR5416_EEPROM_MAGIC 0xa55a 254221254Sadrian 255221254Sadrian/* 256221254Sadrian * XXX - This should not be here ! And this looks like Atheros (if_ath) only. 257221254Sadrian */ 258221254Sadrianstatic void 259234485Sadrianar724x_pci_fixup(device_t dev, long flash_addr, int len) 260221254Sadrian{ 261234485Sadrian uint32_t bar0, reg, val; 262234485Sadrian uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); 263221254Sadrian 264234485Sadrian if (cal_data[0] != AR5416_EEPROM_MAGIC) { 265234485Sadrian device_printf(dev, "%s: Invalid calibration data from 0x%x\n", 266234485Sadrian __func__, (uintptr_t) flash_addr); 267221254Sadrian return; 268221254Sadrian } 269221254Sadrian 270221254Sadrian /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ 271221254Sadrian bar0 = ar724x_pci_read_config(dev, 0, 0, 0, PCIR_BAR(0), 4); 272221254Sadrian 273239706Sadrian /* Write temporary BAR0 to map the NIC into a fixed location */ 274239706Sadrian ar724x_pci_write_config(dev, 0, 0, 0, PCIR_BAR(0), 275239706Sadrian AR71XX_PCI_MEM_BASE, 4); 276239706Sadrian 277221254Sadrian val = ar724x_pci_read_config(dev, 0, 0, 0, PCIR_COMMAND, 2); 278221254Sadrian val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 279221254Sadrian ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, val, 2); 280221254Sadrian 281221254Sadrian /* set pointer to first reg address */ 282234485Sadrian cal_data += 3; 283234485Sadrian while (*cal_data != 0xffff) { 284234485Sadrian reg = *cal_data++; 285234485Sadrian val = *cal_data++; 286234485Sadrian val |= (*cal_data++) << 16; 287221254Sadrian 288234485Sadrian if (bootverbose) 289234485Sadrian printf(" 0x%08x=0x%04x\n", reg, val); 290234485Sadrian 291221254Sadrian /* Write eeprom fixup data to device memory */ 292221254Sadrian ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); 293221254Sadrian DELAY(100); 294221254Sadrian } 295221254Sadrian 296221254Sadrian val = ar724x_pci_read_config(dev, 0, 0, 0, PCIR_COMMAND, 2); 297221254Sadrian val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 298221254Sadrian ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, val, 2); 299221254Sadrian 300221254Sadrian /* Write the saved bar(0) address */ 301221254Sadrian ar724x_pci_write_config(dev, 0, 0, 0, PCIR_BAR(0), bar0, 4); 302221254Sadrian} 303221254Sadrian#undef AR5416_EEPROM_MAGIC 304221254Sadrian 305234485Sadrian/* 306234485Sadrian * XXX This is (mostly) duplicated with ar71xx_pci.c. 307234485Sadrian * It should at some point be fixed. 308234485Sadrian */ 309234485Sadrianstatic void 310234485Sadrianar724x_pci_slot_fixup(device_t dev) 311234485Sadrian{ 312234485Sadrian long int flash_addr; 313234485Sadrian char buf[64]; 314234485Sadrian int size; 315234485Sadrian 316234485Sadrian /* 317234485Sadrian * Check whether the given slot has a hint to poke. 318234485Sadrian */ 319234485Sadrian if (bootverbose) 320234485Sadrian device_printf(dev, "%s: checking dev %s, %d/%d/%d\n", 321234485Sadrian __func__, device_get_nameunit(dev), 0, 0, 0); 322234485Sadrian 323234485Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", 324234485Sadrian 0, 0, 0); 325234485Sadrian 326234485Sadrian if (resource_long_value(device_get_name(dev), device_get_unit(dev), 327234485Sadrian buf, &flash_addr) == 0) { 328234485Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size", 329234485Sadrian 0, 0, 0); 330234485Sadrian if (resource_int_value(device_get_name(dev), 331234485Sadrian device_get_unit(dev), buf, &size) != 0) { 332234485Sadrian device_printf(dev, 333234485Sadrian "%s: missing hint '%s', aborting EEPROM\n", 334234485Sadrian __func__, buf); 335234485Sadrian return; 336234485Sadrian } 337234485Sadrian 338234485Sadrian 339234485Sadrian device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n", 340234485Sadrian flash_addr, 0, 0, 0); 341234485Sadrian ar724x_pci_fixup(dev, flash_addr, size); 342234485Sadrian ar71xx_pci_slot_create_eeprom_firmware(dev, 0, 0, 0, 343234485Sadrian flash_addr, size); 344234485Sadrian } 345234485Sadrian} 346234485Sadrian#endif /* AR71XX_ATH_EEPROM */ 347234485Sadrian 348221254Sadrianstatic int 349221254Sadrianar724x_pci_probe(device_t dev) 350221254Sadrian{ 351221254Sadrian 352221254Sadrian return (0); 353221254Sadrian} 354221254Sadrian 355221254Sadrianstatic int 356221254Sadrianar724x_pci_attach(device_t dev) 357221254Sadrian{ 358221254Sadrian struct ar71xx_pci_softc *sc = device_get_softc(dev); 359221254Sadrian int busno = 0; 360221254Sadrian int rid = 0; 361221254Sadrian 362221254Sadrian sc->sc_mem_rman.rm_type = RMAN_ARRAY; 363221254Sadrian sc->sc_mem_rman.rm_descr = "ar724x PCI memory window"; 364221254Sadrian if (rman_init(&sc->sc_mem_rman) != 0 || 365221254Sadrian rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, 366221254Sadrian AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { 367221254Sadrian panic("ar724x_pci_attach: failed to set up I/O rman"); 368221254Sadrian } 369221254Sadrian 370221254Sadrian sc->sc_irq_rman.rm_type = RMAN_ARRAY; 371221254Sadrian sc->sc_irq_rman.rm_descr = "ar724x PCI IRQs"; 372221254Sadrian if (rman_init(&sc->sc_irq_rman) != 0 || 373221254Sadrian rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, 374221254Sadrian AR71XX_PCI_IRQ_END) != 0) 375221254Sadrian panic("ar724x_pci_attach: failed to set up IRQ rman"); 376221254Sadrian 377221254Sadrian /* Disable interrupts */ 378221254Sadrian ATH_WRITE_REG(AR724X_PCI_INTR_STATUS, 0); 379221254Sadrian ATH_WRITE_REG(AR724X_PCI_INTR_MASK, 0); 380221254Sadrian 381221254Sadrian /* Hook up our interrupt handler. */ 382221254Sadrian if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 383221254Sadrian RF_SHAREABLE | RF_ACTIVE)) == NULL) { 384221254Sadrian device_printf(dev, "unable to allocate IRQ resource\n"); 385221254Sadrian return (ENXIO); 386221254Sadrian } 387221254Sadrian 388221254Sadrian if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, 389221254Sadrian ar724x_pci_intr, NULL, sc, &sc->sc_ih))) { 390221254Sadrian device_printf(dev, 391221254Sadrian "WARNING: unable to register interrupt handler\n"); 392221254Sadrian return (ENXIO); 393221254Sadrian } 394221254Sadrian 395221254Sadrian /* Reset PCIe core and PCIe PHY */ 396221254Sadrian ar71xx_device_stop(AR724X_RESET_PCIE); 397221254Sadrian ar71xx_device_stop(AR724X_RESET_PCIE_PHY); 398221254Sadrian ar71xx_device_stop(AR724X_RESET_PCIE_PHY_SERIAL); 399221254Sadrian DELAY(100); 400221254Sadrian 401221254Sadrian ar71xx_device_start(AR724X_RESET_PCIE_PHY_SERIAL); 402221254Sadrian DELAY(100); 403221254Sadrian ar71xx_device_start(AR724X_RESET_PCIE_PHY); 404221254Sadrian ar71xx_device_start(AR724X_RESET_PCIE); 405221254Sadrian 406221254Sadrian if (ar724x_pci_setup(dev)) 407221254Sadrian return (ENXIO); 408221254Sadrian 409234485Sadrian#ifdef AR71XX_ATH_EEPROM 410234485Sadrian ar724x_pci_slot_fixup(dev); 411234485Sadrian#endif /* AR71XX_ATH_EEPROM */ 412221254Sadrian 413221254Sadrian /* Fixup internal PCI bridge */ 414221254Sadrian ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, 415221254Sadrian PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN 416221254Sadrian | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK 417221254Sadrian | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 2); 418221254Sadrian 419221254Sadrian device_add_child(dev, "pci", busno); 420221254Sadrian return (bus_generic_attach(dev)); 421221254Sadrian} 422221254Sadrian 423221254Sadrianstatic int 424221254Sadrianar724x_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 425221254Sadrian{ 426221254Sadrian struct ar71xx_pci_softc *sc = device_get_softc(dev); 427221254Sadrian 428221254Sadrian switch (which) { 429221254Sadrian case PCIB_IVAR_DOMAIN: 430221254Sadrian *result = 0; 431221254Sadrian return (0); 432221254Sadrian case PCIB_IVAR_BUS: 433221254Sadrian *result = sc->sc_busno; 434221254Sadrian return (0); 435221254Sadrian } 436221254Sadrian 437221254Sadrian return (ENOENT); 438221254Sadrian} 439221254Sadrian 440221254Sadrianstatic int 441221254Sadrianar724x_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 442221254Sadrian{ 443221254Sadrian struct ar71xx_pci_softc * sc = device_get_softc(dev); 444221254Sadrian 445221254Sadrian switch (which) { 446221254Sadrian case PCIB_IVAR_BUS: 447221254Sadrian sc->sc_busno = result; 448221254Sadrian return (0); 449221254Sadrian } 450221254Sadrian 451221254Sadrian return (ENOENT); 452221254Sadrian} 453221254Sadrian 454221254Sadrianstatic struct resource * 455221254Sadrianar724x_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 456221254Sadrian u_long start, u_long end, u_long count, u_int flags) 457221254Sadrian{ 458221254Sadrian struct ar71xx_pci_softc *sc = device_get_softc(bus); 459221254Sadrian struct resource *rv; 460221254Sadrian struct rman *rm; 461221254Sadrian 462221254Sadrian switch (type) { 463221254Sadrian case SYS_RES_IRQ: 464221254Sadrian rm = &sc->sc_irq_rman; 465221254Sadrian break; 466221254Sadrian case SYS_RES_MEMORY: 467221254Sadrian rm = &sc->sc_mem_rman; 468221254Sadrian break; 469221254Sadrian default: 470221254Sadrian return (NULL); 471221254Sadrian } 472221254Sadrian 473221254Sadrian rv = rman_reserve_resource(rm, start, end, count, flags, child); 474221254Sadrian 475221254Sadrian if (rv == NULL) 476221254Sadrian return (NULL); 477221254Sadrian 478221254Sadrian rman_set_rid(rv, *rid); 479221254Sadrian 480221254Sadrian if (flags & RF_ACTIVE) { 481221254Sadrian if (bus_activate_resource(child, type, *rid, rv)) { 482221254Sadrian rman_release_resource(rv); 483221254Sadrian return (NULL); 484221254Sadrian } 485221254Sadrian } 486221254Sadrian 487221254Sadrian 488221254Sadrian return (rv); 489221254Sadrian} 490221254Sadrian 491221254Sadrianstatic int 492221254Sadrianar724x_pci_activate_resource(device_t bus, device_t child, int type, int rid, 493221254Sadrian struct resource *r) 494221254Sadrian{ 495221254Sadrian int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 496221254Sadrian child, type, rid, r)); 497221254Sadrian 498221254Sadrian if (!res) { 499221254Sadrian switch(type) { 500221254Sadrian case SYS_RES_MEMORY: 501221254Sadrian case SYS_RES_IOPORT: 502221254Sadrian 503221307Sadrian rman_set_bustag(r, ar71xx_bus_space_pcimem); 504221254Sadrian break; 505221254Sadrian } 506221254Sadrian } 507221254Sadrian 508221254Sadrian return (res); 509221254Sadrian} 510221254Sadrian 511221254Sadrianstatic int 512221254Sadrianar724x_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 513221254Sadrian int flags, driver_filter_t *filt, driver_intr_t *handler, 514221254Sadrian void *arg, void **cookiep) 515221254Sadrian{ 516221254Sadrian struct ar71xx_pci_softc *sc = device_get_softc(bus); 517221254Sadrian struct intr_event *event; 518221254Sadrian int irq, error; 519221254Sadrian 520221254Sadrian irq = rman_get_start(ires); 521221254Sadrian if (irq > AR71XX_PCI_IRQ_END) 522221254Sadrian panic("%s: bad irq %d", __func__, irq); 523221254Sadrian 524221254Sadrian event = sc->sc_eventstab[irq]; 525221254Sadrian if (event == NULL) { 526221254Sadrian error = intr_event_create(&event, (void *)irq, 0, irq, 527221254Sadrian ar724x_pci_mask_irq, ar724x_pci_unmask_irq, NULL, NULL, 528221254Sadrian "pci intr%d:", irq); 529221254Sadrian 530221254Sadrian if (error == 0) { 531221254Sadrian sc->sc_eventstab[irq] = event; 532221254Sadrian sc->sc_intr_counter[irq] = 533221254Sadrian mips_intrcnt_create(event->ie_name); 534221254Sadrian } 535221254Sadrian else 536221254Sadrian return error; 537221254Sadrian } 538221254Sadrian 539221254Sadrian intr_event_add_handler(event, device_get_nameunit(child), filt, 540221254Sadrian handler, arg, intr_priority(flags), flags, cookiep); 541221254Sadrian mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); 542221254Sadrian 543221254Sadrian ar724x_pci_unmask_irq((void*)irq); 544221254Sadrian 545221254Sadrian return (0); 546221254Sadrian} 547221254Sadrian 548221254Sadrianstatic int 549221254Sadrianar724x_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 550221254Sadrian void *cookie) 551221254Sadrian{ 552221254Sadrian struct ar71xx_pci_softc *sc = device_get_softc(dev); 553221254Sadrian int irq, result; 554221254Sadrian 555221254Sadrian irq = rman_get_start(ires); 556221254Sadrian if (irq > AR71XX_PCI_IRQ_END) 557221254Sadrian panic("%s: bad irq %d", __func__, irq); 558221254Sadrian 559221254Sadrian if (sc->sc_eventstab[irq] == NULL) 560221254Sadrian panic("Trying to teardown unoccupied IRQ"); 561221254Sadrian 562221254Sadrian ar724x_pci_mask_irq((void*)irq); 563221254Sadrian 564221254Sadrian result = intr_event_remove_handler(cookie); 565221254Sadrian if (!result) 566221254Sadrian sc->sc_eventstab[irq] = NULL; 567221254Sadrian 568221254Sadrian return (result); 569221254Sadrian} 570221254Sadrian 571221254Sadrianstatic int 572221254Sadrianar724x_pci_intr(void *arg) 573221254Sadrian{ 574221254Sadrian struct ar71xx_pci_softc *sc = arg; 575221254Sadrian struct intr_event *event; 576221254Sadrian uint32_t reg, irq, mask; 577221254Sadrian 578221254Sadrian ar71xx_device_ddr_flush_ip2(); 579221254Sadrian 580221254Sadrian reg = ATH_READ_REG(AR724X_PCI_INTR_STATUS); 581221254Sadrian mask = ATH_READ_REG(AR724X_PCI_INTR_MASK); 582221254Sadrian /* 583221254Sadrian * Handle only unmasked interrupts 584221254Sadrian */ 585221254Sadrian reg &= mask; 586221254Sadrian if (reg & AR724X_PCI_INTR_DEV0) { 587221254Sadrian 588221254Sadrian irq = AR71XX_PCI_IRQ_START; 589221254Sadrian event = sc->sc_eventstab[irq]; 590221254Sadrian if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 591221254Sadrian printf("Stray IRQ %d\n", irq); 592221254Sadrian return (FILTER_STRAY); 593221254Sadrian } 594221254Sadrian 595221254Sadrian /* TODO: frame instead of NULL? */ 596221254Sadrian intr_event_handle(event, NULL); 597221254Sadrian mips_intrcnt_inc(sc->sc_intr_counter[irq]); 598221254Sadrian } 599221254Sadrian 600221254Sadrian return (FILTER_HANDLED); 601221254Sadrian} 602221254Sadrian 603221254Sadrianstatic int 604221254Sadrianar724x_pci_maxslots(device_t dev) 605221254Sadrian{ 606221254Sadrian 607221254Sadrian return (PCI_SLOTMAX); 608221254Sadrian} 609221254Sadrian 610221254Sadrianstatic int 611221254Sadrianar724x_pci_route_interrupt(device_t pcib, device_t device, int pin) 612221254Sadrian{ 613221254Sadrian 614221254Sadrian return (pci_get_slot(device)); 615221254Sadrian} 616221254Sadrian 617221254Sadrianstatic device_method_t ar724x_pci_methods[] = { 618221254Sadrian /* Device interface */ 619221254Sadrian DEVMETHOD(device_probe, ar724x_pci_probe), 620221254Sadrian DEVMETHOD(device_attach, ar724x_pci_attach), 621221254Sadrian DEVMETHOD(device_shutdown, bus_generic_shutdown), 622221254Sadrian DEVMETHOD(device_suspend, bus_generic_suspend), 623221254Sadrian DEVMETHOD(device_resume, bus_generic_resume), 624221254Sadrian 625221254Sadrian /* Bus interface */ 626221254Sadrian DEVMETHOD(bus_read_ivar, ar724x_pci_read_ivar), 627221254Sadrian DEVMETHOD(bus_write_ivar, ar724x_pci_write_ivar), 628221254Sadrian DEVMETHOD(bus_alloc_resource, ar724x_pci_alloc_resource), 629221254Sadrian DEVMETHOD(bus_release_resource, bus_generic_release_resource), 630221254Sadrian DEVMETHOD(bus_activate_resource, ar724x_pci_activate_resource), 631221254Sadrian DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 632221254Sadrian DEVMETHOD(bus_setup_intr, ar724x_pci_setup_intr), 633221254Sadrian DEVMETHOD(bus_teardown_intr, ar724x_pci_teardown_intr), 634221254Sadrian 635221254Sadrian /* pcib interface */ 636221254Sadrian DEVMETHOD(pcib_maxslots, ar724x_pci_maxslots), 637221254Sadrian DEVMETHOD(pcib_read_config, ar724x_pci_read_config), 638221254Sadrian DEVMETHOD(pcib_write_config, ar724x_pci_write_config), 639221254Sadrian DEVMETHOD(pcib_route_interrupt, ar724x_pci_route_interrupt), 640221254Sadrian 641227843Smarius DEVMETHOD_END 642221254Sadrian}; 643221254Sadrian 644221254Sadrianstatic driver_t ar724x_pci_driver = { 645221254Sadrian "pcib", 646221254Sadrian ar724x_pci_methods, 647221254Sadrian sizeof(struct ar71xx_pci_softc), 648221254Sadrian}; 649221254Sadrian 650221254Sadrianstatic devclass_t ar724x_pci_devclass; 651221254Sadrian 652221254SadrianDRIVER_MODULE(ar724x_pci, nexus, ar724x_pci_driver, ar724x_pci_devclass, 0, 0); 653