ar71xx_pci.c revision 234205
1187706Sgonzo/*- 2187706Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3187706Sgonzo * All rights reserved. 4187706Sgonzo * 5187706Sgonzo * Redistribution and use in source and binary forms, with or without 6187706Sgonzo * modification, are permitted provided that the following conditions 7187706Sgonzo * are met: 8187706Sgonzo * 1. Redistributions of source code must retain the above copyright 9187706Sgonzo * notice unmodified, this list of conditions, and the following 10187706Sgonzo * disclaimer. 11187706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12187706Sgonzo * notice, this list of conditions and the following disclaimer in the 13187706Sgonzo * documentation and/or other materials provided with the distribution. 14187706Sgonzo * 15187706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16187706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17187706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18187706Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19187706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20187706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21187706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22187706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23187706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24187706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25187706Sgonzo * SUCH DAMAGE. 26187706Sgonzo */ 27187706Sgonzo 28187706Sgonzo#include <sys/cdefs.h> 29187706Sgonzo__FBSDID("$FreeBSD: head/sys/mips/atheros/ar71xx_pci.c 234205 2012-04-13 06:13:37Z adrian $"); 30187706Sgonzo 31230195Sadrian#include "opt_ar71xx.h" 32230195Sadrian 33187706Sgonzo#include <sys/param.h> 34187706Sgonzo#include <sys/systm.h> 35187706Sgonzo 36187706Sgonzo#include <sys/bus.h> 37187706Sgonzo#include <sys/interrupt.h> 38187706Sgonzo#include <sys/malloc.h> 39187706Sgonzo#include <sys/kernel.h> 40187706Sgonzo#include <sys/module.h> 41187706Sgonzo#include <sys/rman.h> 42187706Sgonzo 43187706Sgonzo#include <vm/vm.h> 44187706Sgonzo#include <vm/pmap.h> 45187706Sgonzo#include <vm/vm_extern.h> 46187706Sgonzo 47187706Sgonzo#include <machine/bus.h> 48187706Sgonzo#include <machine/cpu.h> 49210900Sgonzo#include <machine/intr_machdep.h> 50187706Sgonzo#include <machine/pmap.h> 51187706Sgonzo 52187706Sgonzo#include <dev/pci/pcivar.h> 53187706Sgonzo#include <dev/pci/pcireg.h> 54187706Sgonzo 55187706Sgonzo#include <dev/pci/pcib_private.h> 56187706Sgonzo#include "pcib_if.h" 57187706Sgonzo 58192161Sgonzo#include <mips/atheros/ar71xxreg.h> 59192161Sgonzo#include <mips/atheros/ar71xx_pci_bus_space.h> 60187706Sgonzo 61211478Sadrian#include <mips/atheros/ar71xx_cpudef.h> 62211478Sadrian 63187706Sgonzo#undef AR71XX_PCI_DEBUG 64187706Sgonzo#ifdef AR71XX_PCI_DEBUG 65187706Sgonzo#define dprintf printf 66187706Sgonzo#else 67187706Sgonzo#define dprintf(x, arg...) 68187706Sgonzo#endif 69187706Sgonzo 70187706Sgonzostruct ar71xx_pci_softc { 71187706Sgonzo device_t sc_dev; 72187706Sgonzo 73187706Sgonzo int sc_busno; 74187706Sgonzo struct rman sc_mem_rman; 75187706Sgonzo struct rman sc_irq_rman; 76187706Sgonzo 77191872Sgonzo struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; 78210900Sgonzo mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; 79187706Sgonzo struct resource *sc_irq; 80187706Sgonzo void *sc_ih; 81187706Sgonzo}; 82187706Sgonzo 83191872Sgonzostatic int ar71xx_pci_setup_intr(device_t, device_t, struct resource *, int, 84191872Sgonzo driver_filter_t *, driver_intr_t *, void *, void **); 85191872Sgonzostatic int ar71xx_pci_teardown_intr(device_t, device_t, struct resource *, 86191872Sgonzo void *); 87191872Sgonzostatic int ar71xx_pci_intr(void *); 88191872Sgonzo 89192822Sgonzostatic void 90192822Sgonzoar71xx_pci_mask_irq(void *source) 91191872Sgonzo{ 92191872Sgonzo uint32_t reg; 93192822Sgonzo unsigned int irq = (unsigned int)source; 94191872Sgonzo 95191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 96194273Sgonzo /* flush */ 97194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 98191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg & ~(1 << irq)); 99191872Sgonzo} 100191872Sgonzo 101192822Sgonzostatic void 102192822Sgonzoar71xx_pci_unmask_irq(void *source) 103191872Sgonzo{ 104191872Sgonzo uint32_t reg; 105192822Sgonzo unsigned int irq = (unsigned int)source; 106191872Sgonzo 107191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 108191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg | (1 << irq)); 109194273Sgonzo /* flush */ 110194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 111191872Sgonzo} 112191872Sgonzo 113187706Sgonzo/* 114187706Sgonzo * get bitmask for bytes of interest: 115187706Sgonzo * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte 116187706Sgonzo * from register 7. Bitmask would be: 0111 117187706Sgonzo */ 118187706Sgonzostatic uint32_t 119187706Sgonzoar71xx_get_bytes_to_read(int reg, int bytes) 120187706Sgonzo{ 121187706Sgonzo uint32_t bytes_to_read = 0; 122187706Sgonzo if ((bytes % 4) == 0) 123187706Sgonzo bytes_to_read = 0; 124187706Sgonzo else if ((bytes % 4) == 1) 125187706Sgonzo bytes_to_read = (~(1 << (reg % 4))) & 0xf; 126187706Sgonzo else if ((bytes % 4) == 2) 127187706Sgonzo bytes_to_read = (~(3 << (reg % 4))) & 0xf; 128187706Sgonzo else 129187706Sgonzo panic("%s: wrong combination", __func__); 130187706Sgonzo 131187706Sgonzo return (bytes_to_read); 132187706Sgonzo} 133187706Sgonzo 134187706Sgonzostatic int 135187706Sgonzoar71xx_pci_check_bus_error(void) 136187706Sgonzo{ 137187706Sgonzo uint32_t error, addr, has_errors = 0; 138187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3; 139187706Sgonzo dprintf("%s: PCI error = %02x\n", __func__, error); 140187706Sgonzo if (error) { 141187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR); 142187706Sgonzo 143187706Sgonzo /* Do not report it yet */ 144187706Sgonzo#if 0 145187706Sgonzo printf("PCI bus error %d at addr 0x%08x\n", error, addr); 146187706Sgonzo#endif 147187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_ERROR, error); 148187706Sgonzo has_errors = 1; 149187706Sgonzo } 150187706Sgonzo 151187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1; 152187706Sgonzo dprintf("%s: AHB error = %02x\n", __func__, error); 153187706Sgonzo if (error) { 154187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR); 155187706Sgonzo /* Do not report it yet */ 156187706Sgonzo#if 0 157187706Sgonzo printf("AHB bus error %d at addr 0x%08x\n", error, addr); 158187706Sgonzo#endif 159187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error); 160187706Sgonzo has_errors = 1; 161187706Sgonzo } 162187706Sgonzo 163187706Sgonzo return (has_errors); 164187706Sgonzo} 165187706Sgonzo 166187706Sgonzostatic uint32_t 167187706Sgonzoar71xx_pci_make_addr(int bus, int slot, int func, int reg) 168187706Sgonzo{ 169187706Sgonzo if (bus == 0) { 170187706Sgonzo return ((1 << slot) | (func << 8) | (reg & ~3)); 171187706Sgonzo } else { 172187706Sgonzo return ((bus << 16) | (slot << 11) | (func << 8) 173187706Sgonzo | (reg & ~3) | 1); 174187706Sgonzo } 175187706Sgonzo} 176187706Sgonzo 177187706Sgonzostatic int 178187706Sgonzoar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes, 179187706Sgonzo uint32_t cmd) 180187706Sgonzo{ 181187706Sgonzo uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3)); 182187706Sgonzo cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4); 183187706Sgonzo 184187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr); 185187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd); 186187706Sgonzo 187187706Sgonzo dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__, 188187706Sgonzo bus, slot, func, reg, bytes, addr, cmd); 189187706Sgonzo 190187706Sgonzo return ar71xx_pci_check_bus_error(); 191187706Sgonzo} 192187706Sgonzo 193187706Sgonzostatic uint32_t 194194059Sgonzoar71xx_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 195194059Sgonzo u_int reg, int bytes) 196187706Sgonzo{ 197187706Sgonzo uint32_t data; 198234205Sadrian uint32_t shift, mask; 199187706Sgonzo 200187706Sgonzo /* register access is 32-bit aligned */ 201187706Sgonzo shift = (reg & 3) * 8; 202187706Sgonzo if (shift) 203187706Sgonzo mask = (1 << shift) - 1; 204187706Sgonzo else 205187706Sgonzo mask = 0xffffffff; 206187706Sgonzo 207187706Sgonzo dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 208187706Sgonzo func, reg, bytes); 209187706Sgonzo 210234204Sadrian if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 211234204Sadrian PCI_CONF_CMD_READ) == 0) 212234204Sadrian data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA); 213234204Sadrian else 214234204Sadrian data = -1; 215187706Sgonzo 216187706Sgonzo /* get request bytes from 32-bit word */ 217187706Sgonzo data = (data >> shift) & mask; 218187706Sgonzo 219187706Sgonzo dprintf("%s: read 0x%x\n", __func__, data); 220187706Sgonzo 221187706Sgonzo return (data); 222187706Sgonzo} 223187706Sgonzo 224187706Sgonzostatic void 225234204Sadrianar71xx_pci_local_write(device_t dev, uint32_t reg, uint32_t data, int bytes) 226187706Sgonzo{ 227187706Sgonzo uint32_t cmd; 228187706Sgonzo 229234204Sadrian dprintf("%s: local write reg %d(%d)\n", __func__, reg, bytes); 230234204Sadrian 231234204Sadrian data = data << (8*(reg % 4)); 232234204Sadrian 233234204Sadrian cmd = PCI_LCONF_CMD_WRITE | (reg & ~3); 234234204Sadrian cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 20); 235234204Sadrian ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); 236234204Sadrian ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data); 237234204Sadrian} 238234204Sadrian 239234204Sadrianstatic void 240234204Sadrianar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 241234204Sadrian u_int reg, uint32_t data, int bytes) 242234204Sadrian{ 243234204Sadrian 244234204Sadrian dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 245187706Sgonzo func, reg, bytes); 246187706Sgonzo 247187706Sgonzo data = data << (8*(reg % 4)); 248187706Sgonzo 249234204Sadrian if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 250234204Sadrian PCI_CONF_CMD_WRITE) == 0) 251234204Sadrian ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data); 252187706Sgonzo} 253187706Sgonzo 254230148Sadrian#ifdef AR71XX_ATH_EEPROM 255230148Sadrian/* 256230148Sadrian * Some embedded boards (eg AP94) have the MAC attached via PCI but they 257230148Sadrian * don't have the MAC-attached EEPROM. The register initialisation 258230148Sadrian * values and calibration data are stored in the on-board flash. 259230148Sadrian * This routine initialises the NIC via the EEPROM register contents 260230148Sadrian * before the probe/attach routines get a go at things. 261230148Sadrian */ 262230148Sadrianstatic void 263230148Sadrianar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func, 264230148Sadrian long flash_addr) 265230148Sadrian{ 266230148Sadrian uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); 267230148Sadrian uint32_t reg, val, bar0; 268230148Sadrian 269230148Sadrian printf("%s: flash_addr=%lx, cal_data=%p\n", 270230148Sadrian __func__, flash_addr, cal_data); 271230148Sadrian 272230148Sadrian /* XXX check 0xa55a */ 273230148Sadrian /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ 274230148Sadrian bar0 = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_BAR(0), 4); 275230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), 276230148Sadrian AR71XX_PCI_MEM_BASE, 4); 277230148Sadrian 278230148Sadrian val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 279230148Sadrian val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 280230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 281230148Sadrian 282230148Sadrian cal_data += 3; 283230148Sadrian while (*cal_data != 0xffff) { 284230148Sadrian reg = *cal_data++; 285230148Sadrian val = *cal_data++; 286230148Sadrian val |= (*cal_data++) << 16; 287230148Sadrian printf(" reg: %x, val=%x\n", reg, val); 288230148Sadrian 289230148Sadrian /* Write eeprom fixup data to device memory */ 290230148Sadrian ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); 291230148Sadrian DELAY(100); 292230148Sadrian } 293230148Sadrian 294230148Sadrian val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 295230148Sadrian val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 296230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 297230148Sadrian 298230148Sadrian /* Write the saved bar(0) address */ 299230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), bar0, 4); 300230148Sadrian} 301230148Sadrian 302230148Sadrianstatic void 303230148Sadrianar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func) 304230148Sadrian{ 305230148Sadrian long int flash_addr; 306230148Sadrian char buf[32]; 307230148Sadrian 308230148Sadrian /* 309230148Sadrian * Check whether the given slot has a hint to poke. 310230148Sadrian */ 311230148Sadrian printf("%s: checking dev %s, %d/%d/%d\n", 312230148Sadrian __func__, device_get_nameunit(dev), bus, slot, func); 313230148Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", 314230148Sadrian bus, slot, func); 315230148Sadrian 316230148Sadrian if (resource_long_value(device_get_name(dev), device_get_unit(dev), 317230148Sadrian buf, &flash_addr) == 0) { 318230148Sadrian printf("%s: found fixupaddr at %lx: updating\n", 319230148Sadrian __func__, flash_addr); 320230148Sadrian ar71xx_pci_fixup(dev, bus, slot, func, flash_addr); 321230148Sadrian } 322230148Sadrian} 323230148Sadrian#endif /* AR71XX_ATH_EEPROM */ 324230148Sadrian 325187706Sgonzostatic int 326187706Sgonzoar71xx_pci_probe(device_t dev) 327187706Sgonzo{ 328187706Sgonzo 329187706Sgonzo return (0); 330187706Sgonzo} 331187706Sgonzo 332187706Sgonzostatic int 333187706Sgonzoar71xx_pci_attach(device_t dev) 334187706Sgonzo{ 335187706Sgonzo int busno = 0; 336187706Sgonzo int rid = 0; 337187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 338187706Sgonzo 339187706Sgonzo sc->sc_mem_rman.rm_type = RMAN_ARRAY; 340187706Sgonzo sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window"; 341187706Sgonzo if (rman_init(&sc->sc_mem_rman) != 0 || 342187706Sgonzo rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, 343187706Sgonzo AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { 344187706Sgonzo panic("ar71xx_pci_attach: failed to set up I/O rman"); 345187706Sgonzo } 346187706Sgonzo 347187706Sgonzo sc->sc_irq_rman.rm_type = RMAN_ARRAY; 348187706Sgonzo sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs"; 349187706Sgonzo if (rman_init(&sc->sc_irq_rman) != 0 || 350187706Sgonzo rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, 351187706Sgonzo AR71XX_PCI_IRQ_END) != 0) 352187706Sgonzo panic("ar71xx_pci_attach: failed to set up IRQ rman"); 353187706Sgonzo 354187706Sgonzo 355187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); 356187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); 357187706Sgonzo 358187706Sgonzo /* Hook up our interrupt handler. */ 359187706Sgonzo if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 360187706Sgonzo RF_SHAREABLE | RF_ACTIVE)) == NULL) { 361187706Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 362187706Sgonzo return ENXIO; 363187706Sgonzo } 364187706Sgonzo 365187706Sgonzo if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, 366191872Sgonzo ar71xx_pci_intr, NULL, sc, &sc->sc_ih))) { 367187706Sgonzo device_printf(dev, 368187706Sgonzo "WARNING: unable to register interrupt handler\n"); 369187706Sgonzo return ENXIO; 370187706Sgonzo } 371187706Sgonzo 372187706Sgonzo /* reset PCI core and PCI bus */ 373211478Sadrian ar71xx_device_stop(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 374203132Sgonzo DELAY(100000); 375187706Sgonzo 376211478Sadrian ar71xx_device_start(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 377203132Sgonzo DELAY(100000); 378187706Sgonzo 379187706Sgonzo /* Init PCI windows */ 380187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR); 381187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR); 382187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR); 383187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR); 384187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR); 385187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR); 386187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR); 387187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR); 388203132Sgonzo DELAY(100000); 389187706Sgonzo 390187706Sgonzo ar71xx_pci_check_bus_error(); 391187706Sgonzo 392187706Sgonzo /* Fixup internal PCI bridge */ 393234204Sadrian ar71xx_pci_local_write(dev, PCIR_COMMAND, 394234204Sadrian PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN 395187706Sgonzo | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK 396234204Sadrian | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 4); 397187706Sgonzo 398230148Sadrian#ifdef AR71XX_ATH_EEPROM 399230148Sadrian /* 400230148Sadrian * Hard-code a check for slot 17 and 18 - these are 401230148Sadrian * the two PCI slots which may have a PCI device that 402230148Sadrian * requires "fixing". 403230148Sadrian */ 404230148Sadrian ar71xx_pci_slot_fixup(dev, 0, 17, 0); 405230148Sadrian ar71xx_pci_slot_fixup(dev, 0, 18, 0); 406230148Sadrian#endif /* AR71XX_ATH_EEPROM */ 407230148Sadrian 408187706Sgonzo device_add_child(dev, "pci", busno); 409187706Sgonzo return (bus_generic_attach(dev)); 410187706Sgonzo} 411187706Sgonzo 412187706Sgonzostatic int 413187706Sgonzoar71xx_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 414187706Sgonzo{ 415187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 416187706Sgonzo 417187706Sgonzo switch (which) { 418187706Sgonzo case PCIB_IVAR_DOMAIN: 419187706Sgonzo *result = 0; 420187706Sgonzo return (0); 421187706Sgonzo case PCIB_IVAR_BUS: 422187706Sgonzo *result = sc->sc_busno; 423187706Sgonzo return (0); 424187706Sgonzo } 425187706Sgonzo 426187706Sgonzo return (ENOENT); 427187706Sgonzo} 428187706Sgonzo 429187706Sgonzostatic int 430187706Sgonzoar71xx_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 431187706Sgonzo{ 432187706Sgonzo struct ar71xx_pci_softc * sc = device_get_softc(dev); 433187706Sgonzo 434187706Sgonzo switch (which) { 435187706Sgonzo case PCIB_IVAR_BUS: 436187706Sgonzo sc->sc_busno = result; 437187706Sgonzo return (0); 438187706Sgonzo } 439187706Sgonzo 440187706Sgonzo return (ENOENT); 441187706Sgonzo} 442187706Sgonzo 443187706Sgonzostatic struct resource * 444187706Sgonzoar71xx_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 445187706Sgonzo u_long start, u_long end, u_long count, u_int flags) 446187706Sgonzo{ 447187706Sgonzo 448187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 449192161Sgonzo struct resource *rv; 450187706Sgonzo struct rman *rm; 451187706Sgonzo 452187706Sgonzo switch (type) { 453187706Sgonzo case SYS_RES_IRQ: 454187706Sgonzo rm = &sc->sc_irq_rman; 455187706Sgonzo break; 456187706Sgonzo case SYS_RES_MEMORY: 457187706Sgonzo rm = &sc->sc_mem_rman; 458187706Sgonzo break; 459187706Sgonzo default: 460187706Sgonzo return (NULL); 461187706Sgonzo } 462187706Sgonzo 463187706Sgonzo rv = rman_reserve_resource(rm, start, end, count, flags, child); 464187706Sgonzo 465187706Sgonzo if (rv == NULL) 466187706Sgonzo return (NULL); 467187706Sgonzo 468187706Sgonzo rman_set_rid(rv, *rid); 469187706Sgonzo 470187706Sgonzo if (flags & RF_ACTIVE) { 471187706Sgonzo if (bus_activate_resource(child, type, *rid, rv)) { 472187706Sgonzo rman_release_resource(rv); 473187706Sgonzo return (NULL); 474187706Sgonzo } 475187706Sgonzo } 476187706Sgonzo 477192161Sgonzo 478187706Sgonzo return (rv); 479187706Sgonzo} 480187706Sgonzo 481192161Sgonzo 482187706Sgonzostatic int 483192161Sgonzoar71xx_pci_activate_resource(device_t bus, device_t child, int type, int rid, 484192161Sgonzo struct resource *r) 485192161Sgonzo{ 486192161Sgonzo int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 487192161Sgonzo child, type, rid, r)); 488192161Sgonzo 489192161Sgonzo if (!res) { 490192161Sgonzo switch(type) { 491192161Sgonzo case SYS_RES_MEMORY: 492192161Sgonzo case SYS_RES_IOPORT: 493192161Sgonzo rman_set_bustag(r, ar71xx_bus_space_pcimem); 494192161Sgonzo break; 495192161Sgonzo } 496192161Sgonzo } 497192161Sgonzo 498192161Sgonzo return (res); 499192161Sgonzo} 500192161Sgonzo 501192161Sgonzo 502192161Sgonzo 503192161Sgonzostatic int 504191872Sgonzoar71xx_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 505191872Sgonzo int flags, driver_filter_t *filt, driver_intr_t *handler, 506191872Sgonzo void *arg, void **cookiep) 507191872Sgonzo{ 508191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 509191872Sgonzo struct intr_event *event; 510191872Sgonzo int irq, error; 511191872Sgonzo 512191872Sgonzo irq = rman_get_start(ires); 513191872Sgonzo 514191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 515191872Sgonzo panic("%s: bad irq %d", __func__, irq); 516191872Sgonzo 517191872Sgonzo event = sc->sc_eventstab[irq]; 518191872Sgonzo if (event == NULL) { 519191872Sgonzo error = intr_event_create(&event, (void *)irq, 0, irq, 520192822Sgonzo ar71xx_pci_mask_irq, ar71xx_pci_unmask_irq, NULL, NULL, 521210900Sgonzo "pci intr%d:", irq); 522191872Sgonzo 523210900Sgonzo if (error == 0) { 524210900Sgonzo sc->sc_eventstab[irq] = event; 525210900Sgonzo sc->sc_intr_counter[irq] = 526210900Sgonzo mips_intrcnt_create(event->ie_name); 527210900Sgonzo } 528210900Sgonzo else 529210900Sgonzo return error; 530191872Sgonzo } 531191872Sgonzo 532191872Sgonzo intr_event_add_handler(event, device_get_nameunit(child), filt, 533191872Sgonzo handler, arg, intr_priority(flags), flags, cookiep); 534210900Sgonzo mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); 535191872Sgonzo 536192822Sgonzo ar71xx_pci_unmask_irq((void*)irq); 537191872Sgonzo 538191872Sgonzo return (0); 539191872Sgonzo} 540191872Sgonzo 541191872Sgonzostatic int 542191872Sgonzoar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 543187706Sgonzo void *cookie) 544187706Sgonzo{ 545191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 546191872Sgonzo int irq, result; 547187706Sgonzo 548191872Sgonzo irq = rman_get_start(ires); 549191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 550191872Sgonzo panic("%s: bad irq %d", __func__, irq); 551191872Sgonzo 552191872Sgonzo if (sc->sc_eventstab[irq] == NULL) 553191872Sgonzo panic("Trying to teardown unoccupied IRQ"); 554191872Sgonzo 555192822Sgonzo ar71xx_pci_mask_irq((void*)irq); 556191872Sgonzo 557191872Sgonzo result = intr_event_remove_handler(cookie); 558191872Sgonzo if (!result) 559191872Sgonzo sc->sc_eventstab[irq] = NULL; 560191872Sgonzo 561191872Sgonzo return (result); 562187706Sgonzo} 563187706Sgonzo 564187706Sgonzostatic int 565191872Sgonzoar71xx_pci_intr(void *arg) 566191872Sgonzo{ 567191872Sgonzo struct ar71xx_pci_softc *sc = arg; 568191872Sgonzo struct intr_event *event; 569194273Sgonzo uint32_t reg, irq, mask; 570191872Sgonzo 571191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_STATUS); 572194273Sgonzo mask = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 573194273Sgonzo /* 574194273Sgonzo * Handle only unmasked interrupts 575194273Sgonzo */ 576194273Sgonzo reg &= mask; 577191872Sgonzo for (irq = AR71XX_PCI_IRQ_START; irq <= AR71XX_PCI_IRQ_END; irq++) { 578191872Sgonzo if (reg & (1 << irq)) { 579191872Sgonzo event = sc->sc_eventstab[irq]; 580191872Sgonzo if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 581191872Sgonzo /* Ignore timer interrupts */ 582191872Sgonzo if (irq != 0) 583191872Sgonzo printf("Stray IRQ %d\n", irq); 584191872Sgonzo continue; 585191872Sgonzo } 586191872Sgonzo 587221256Sadrian /* Flush DDR FIFO for IP2 */ 588221256Sadrian ar71xx_device_ddr_flush_ip2(); 589221256Sadrian 590191872Sgonzo /* TODO: frame instead of NULL? */ 591191872Sgonzo intr_event_handle(event, NULL); 592210900Sgonzo mips_intrcnt_inc(sc->sc_intr_counter[irq]); 593191872Sgonzo } 594191872Sgonzo } 595191872Sgonzo 596191872Sgonzo return (FILTER_HANDLED); 597191872Sgonzo} 598191872Sgonzo 599191872Sgonzostatic int 600187706Sgonzoar71xx_pci_maxslots(device_t dev) 601187706Sgonzo{ 602187706Sgonzo 603187706Sgonzo return (PCI_SLOTMAX); 604187706Sgonzo} 605187706Sgonzo 606187706Sgonzostatic int 607187706Sgonzoar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) 608187706Sgonzo{ 609195474Sgonzo if (pci_get_slot(device) < AR71XX_PCI_BASE_SLOT) 610195474Sgonzo panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", 611195474Sgonzo __func__, pci_get_slot(device)); 612187706Sgonzo 613195474Sgonzo return (pci_get_slot(device) - AR71XX_PCI_BASE_SLOT); 614187706Sgonzo} 615187706Sgonzo 616187706Sgonzostatic device_method_t ar71xx_pci_methods[] = { 617187706Sgonzo /* Device interface */ 618187706Sgonzo DEVMETHOD(device_probe, ar71xx_pci_probe), 619187706Sgonzo DEVMETHOD(device_attach, ar71xx_pci_attach), 620187706Sgonzo DEVMETHOD(device_shutdown, bus_generic_shutdown), 621187706Sgonzo DEVMETHOD(device_suspend, bus_generic_suspend), 622187706Sgonzo DEVMETHOD(device_resume, bus_generic_resume), 623187706Sgonzo 624187706Sgonzo /* Bus interface */ 625187706Sgonzo DEVMETHOD(bus_read_ivar, ar71xx_pci_read_ivar), 626187706Sgonzo DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar), 627187706Sgonzo DEVMETHOD(bus_alloc_resource, ar71xx_pci_alloc_resource), 628187706Sgonzo DEVMETHOD(bus_release_resource, bus_generic_release_resource), 629192161Sgonzo DEVMETHOD(bus_activate_resource, ar71xx_pci_activate_resource), 630187706Sgonzo DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 631191872Sgonzo DEVMETHOD(bus_setup_intr, ar71xx_pci_setup_intr), 632187706Sgonzo DEVMETHOD(bus_teardown_intr, ar71xx_pci_teardown_intr), 633187706Sgonzo 634187706Sgonzo /* pcib interface */ 635187706Sgonzo DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots), 636187706Sgonzo DEVMETHOD(pcib_read_config, ar71xx_pci_read_config), 637187706Sgonzo DEVMETHOD(pcib_write_config, ar71xx_pci_write_config), 638187706Sgonzo DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt), 639187706Sgonzo 640227843Smarius DEVMETHOD_END 641187706Sgonzo}; 642187706Sgonzo 643187706Sgonzostatic driver_t ar71xx_pci_driver = { 644187706Sgonzo "pcib", 645187706Sgonzo ar71xx_pci_methods, 646187706Sgonzo sizeof(struct ar71xx_pci_softc), 647187706Sgonzo}; 648187706Sgonzo 649187706Sgonzostatic devclass_t ar71xx_pci_devclass; 650187706Sgonzo 651187706SgonzoDRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0); 652