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$"); 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> 42234365Sadrian#include <sys/lock.h> 43234365Sadrian#include <sys/mutex.h> 44187706Sgonzo 45187706Sgonzo#include <vm/vm.h> 46187706Sgonzo#include <vm/pmap.h> 47187706Sgonzo#include <vm/vm_extern.h> 48187706Sgonzo 49187706Sgonzo#include <machine/bus.h> 50187706Sgonzo#include <machine/cpu.h> 51210900Sgonzo#include <machine/intr_machdep.h> 52187706Sgonzo 53187706Sgonzo#include <dev/pci/pcivar.h> 54187706Sgonzo#include <dev/pci/pcireg.h> 55187706Sgonzo 56187706Sgonzo#include <dev/pci/pcib_private.h> 57187706Sgonzo#include "pcib_if.h" 58187706Sgonzo 59192161Sgonzo#include <mips/atheros/ar71xxreg.h> 60192161Sgonzo#include <mips/atheros/ar71xx_pci_bus_space.h> 61187706Sgonzo 62211478Sadrian#include <mips/atheros/ar71xx_cpudef.h> 63211478Sadrian 64234217Sadrian#ifdef AR71XX_ATH_EEPROM 65234485Sadrian#include <mips/atheros/ar71xx_fixup.h> 66234217Sadrian#endif /* AR71XX_ATH_EEPROM */ 67234217Sadrian 68234366Sadrian#undef AR71XX_PCI_DEBUG 69234366Sadrian#ifdef AR71XX_PCI_DEBUG 70234366Sadrian#define dprintf printf 71187706Sgonzo#else 72234366Sadrian#define dprintf(x, arg...) 73187706Sgonzo#endif 74187706Sgonzo 75234365Sadrianstruct mtx ar71xx_pci_mtx; 76234365SadrianMTX_SYSINIT(ar71xx_pci_mtx, &ar71xx_pci_mtx, "ar71xx PCI space mutex", 77234365Sadrian MTX_SPIN); 78234365Sadrian 79187706Sgonzostruct ar71xx_pci_softc { 80187706Sgonzo device_t sc_dev; 81187706Sgonzo 82187706Sgonzo int sc_busno; 83245112Smonthadar int sc_baseslot; 84187706Sgonzo struct rman sc_mem_rman; 85187706Sgonzo struct rman sc_irq_rman; 86187706Sgonzo 87191872Sgonzo struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; 88210900Sgonzo mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; 89187706Sgonzo struct resource *sc_irq; 90187706Sgonzo void *sc_ih; 91187706Sgonzo}; 92187706Sgonzo 93191872Sgonzostatic int ar71xx_pci_setup_intr(device_t, device_t, struct resource *, int, 94191872Sgonzo driver_filter_t *, driver_intr_t *, void *, void **); 95191872Sgonzostatic int ar71xx_pci_teardown_intr(device_t, device_t, struct resource *, 96191872Sgonzo void *); 97191872Sgonzostatic int ar71xx_pci_intr(void *); 98191872Sgonzo 99234366Sadrianstatic void 100192822Sgonzoar71xx_pci_mask_irq(void *source) 101191872Sgonzo{ 102191872Sgonzo uint32_t reg; 103192822Sgonzo unsigned int irq = (unsigned int)source; 104191872Sgonzo 105234365Sadrian /* XXX is the PCI lock required here? */ 106191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 107194273Sgonzo /* flush */ 108194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 109191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg & ~(1 << irq)); 110191872Sgonzo} 111191872Sgonzo 112234366Sadrianstatic void 113192822Sgonzoar71xx_pci_unmask_irq(void *source) 114191872Sgonzo{ 115191872Sgonzo uint32_t reg; 116192822Sgonzo unsigned int irq = (unsigned int)source; 117191872Sgonzo 118234365Sadrian /* XXX is the PCI lock required here? */ 119191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 120191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg | (1 << irq)); 121194273Sgonzo /* flush */ 122194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 123191872Sgonzo} 124191872Sgonzo 125234366Sadrian/* 126234366Sadrian * get bitmask for bytes of interest: 127234366Sadrian * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte 128187706Sgonzo * from register 7. Bitmask would be: 0111 129187706Sgonzo */ 130187706Sgonzostatic uint32_t 131187706Sgonzoar71xx_get_bytes_to_read(int reg, int bytes) 132187706Sgonzo{ 133187706Sgonzo uint32_t bytes_to_read = 0; 134234366Sadrian 135187706Sgonzo if ((bytes % 4) == 0) 136187706Sgonzo bytes_to_read = 0; 137187706Sgonzo else if ((bytes % 4) == 1) 138187706Sgonzo bytes_to_read = (~(1 << (reg % 4))) & 0xf; 139187706Sgonzo else if ((bytes % 4) == 2) 140187706Sgonzo bytes_to_read = (~(3 << (reg % 4))) & 0xf; 141187706Sgonzo else 142187706Sgonzo panic("%s: wrong combination", __func__); 143187706Sgonzo 144187706Sgonzo return (bytes_to_read); 145187706Sgonzo} 146187706Sgonzo 147234366Sadrianstatic int 148187706Sgonzoar71xx_pci_check_bus_error(void) 149187706Sgonzo{ 150187706Sgonzo uint32_t error, addr, has_errors = 0; 151234365Sadrian 152234365Sadrian mtx_assert(&ar71xx_pci_mtx, MA_OWNED); 153234365Sadrian 154187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3; 155187706Sgonzo dprintf("%s: PCI error = %02x\n", __func__, error); 156187706Sgonzo if (error) { 157187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR); 158187706Sgonzo 159187706Sgonzo /* Do not report it yet */ 160187706Sgonzo#if 0 161187706Sgonzo printf("PCI bus error %d at addr 0x%08x\n", error, addr); 162187706Sgonzo#endif 163187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_ERROR, error); 164187706Sgonzo has_errors = 1; 165187706Sgonzo } 166187706Sgonzo 167187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1; 168187706Sgonzo dprintf("%s: AHB error = %02x\n", __func__, error); 169187706Sgonzo if (error) { 170187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR); 171187706Sgonzo /* Do not report it yet */ 172187706Sgonzo#if 0 173187706Sgonzo printf("AHB bus error %d at addr 0x%08x\n", error, addr); 174187706Sgonzo#endif 175187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error); 176187706Sgonzo has_errors = 1; 177187706Sgonzo } 178187706Sgonzo 179187706Sgonzo return (has_errors); 180187706Sgonzo} 181187706Sgonzo 182187706Sgonzostatic uint32_t 183187706Sgonzoar71xx_pci_make_addr(int bus, int slot, int func, int reg) 184187706Sgonzo{ 185187706Sgonzo if (bus == 0) { 186187706Sgonzo return ((1 << slot) | (func << 8) | (reg & ~3)); 187187706Sgonzo } else { 188234366Sadrian return ((bus << 16) | (slot << 11) | (func << 8) 189187706Sgonzo | (reg & ~3) | 1); 190187706Sgonzo } 191187706Sgonzo} 192187706Sgonzo 193187706Sgonzostatic int 194234366Sadrianar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes, 195187706Sgonzo uint32_t cmd) 196187706Sgonzo{ 197187706Sgonzo uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3)); 198234365Sadrian 199234365Sadrian mtx_assert(&ar71xx_pci_mtx, MA_OWNED); 200234365Sadrian 201234366Sadrian cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4); 202187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr); 203187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd); 204187706Sgonzo 205187706Sgonzo dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__, 206187706Sgonzo bus, slot, func, reg, bytes, addr, cmd); 207187706Sgonzo 208187706Sgonzo return ar71xx_pci_check_bus_error(); 209187706Sgonzo} 210187706Sgonzo 211187706Sgonzostatic uint32_t 212234366Sadrianar71xx_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 213194059Sgonzo u_int reg, int bytes) 214187706Sgonzo{ 215187706Sgonzo uint32_t data; 216234205Sadrian uint32_t shift, mask; 217187706Sgonzo 218187706Sgonzo /* register access is 32-bit aligned */ 219187706Sgonzo shift = (reg & 3) * 8; 220234306Sadrian 221234306Sadrian /* Create a mask based on the width, post-shift */ 222234306Sadrian if (bytes == 2) 223234306Sadrian mask = 0xffff; 224234306Sadrian else if (bytes == 1) 225234306Sadrian mask = 0xff; 226187706Sgonzo else 227187706Sgonzo mask = 0xffffffff; 228187706Sgonzo 229187706Sgonzo dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 230187706Sgonzo func, reg, bytes); 231187706Sgonzo 232234365Sadrian mtx_lock_spin(&ar71xx_pci_mtx); 233234204Sadrian if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 234234204Sadrian PCI_CONF_CMD_READ) == 0) 235234204Sadrian data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA); 236234204Sadrian else 237234204Sadrian data = -1; 238234365Sadrian mtx_unlock_spin(&ar71xx_pci_mtx); 239187706Sgonzo 240187706Sgonzo /* get request bytes from 32-bit word */ 241187706Sgonzo data = (data >> shift) & mask; 242187706Sgonzo 243234366Sadrian dprintf("%s: read 0x%x\n", __func__, data); 244187706Sgonzo 245187706Sgonzo return (data); 246187706Sgonzo} 247187706Sgonzo 248187706Sgonzostatic void 249234204Sadrianar71xx_pci_local_write(device_t dev, uint32_t reg, uint32_t data, int bytes) 250187706Sgonzo{ 251187706Sgonzo uint32_t cmd; 252187706Sgonzo 253234204Sadrian dprintf("%s: local write reg %d(%d)\n", __func__, reg, bytes); 254234204Sadrian 255234204Sadrian data = data << (8*(reg % 4)); 256234204Sadrian cmd = PCI_LCONF_CMD_WRITE | (reg & ~3); 257234204Sadrian cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 20); 258234365Sadrian mtx_lock_spin(&ar71xx_pci_mtx); 259234204Sadrian ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); 260234204Sadrian ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data); 261234365Sadrian mtx_unlock_spin(&ar71xx_pci_mtx); 262234204Sadrian} 263234204Sadrian 264234204Sadrianstatic void 265234204Sadrianar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 266234204Sadrian u_int reg, uint32_t data, int bytes) 267234204Sadrian{ 268234204Sadrian 269234204Sadrian dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 270187706Sgonzo func, reg, bytes); 271187706Sgonzo 272187706Sgonzo data = data << (8*(reg % 4)); 273234365Sadrian mtx_lock_spin(&ar71xx_pci_mtx); 274234204Sadrian if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 275234204Sadrian PCI_CONF_CMD_WRITE) == 0) 276234204Sadrian ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data); 277234365Sadrian mtx_unlock_spin(&ar71xx_pci_mtx); 278187706Sgonzo} 279187706Sgonzo 280230148Sadrian#ifdef AR71XX_ATH_EEPROM 281230148Sadrian/* 282230148Sadrian * Some embedded boards (eg AP94) have the MAC attached via PCI but they 283230148Sadrian * don't have the MAC-attached EEPROM. The register initialisation 284230148Sadrian * values and calibration data are stored in the on-board flash. 285230148Sadrian * This routine initialises the NIC via the EEPROM register contents 286230148Sadrian * before the probe/attach routines get a go at things. 287230148Sadrian */ 288230148Sadrianstatic void 289230148Sadrianar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func, 290234485Sadrian long flash_addr, int len) 291230148Sadrian{ 292230148Sadrian uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); 293230148Sadrian uint32_t reg, val, bar0; 294230148Sadrian 295234217Sadrian if (bootverbose) 296234217Sadrian device_printf(dev, "%s: flash_addr=%lx, cal_data=%p\n", 297234217Sadrian __func__, flash_addr, cal_data); 298230148Sadrian 299230148Sadrian /* XXX check 0xa55a */ 300230148Sadrian /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ 301230148Sadrian bar0 = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_BAR(0), 4); 302230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), 303230148Sadrian AR71XX_PCI_MEM_BASE, 4); 304230148Sadrian 305230148Sadrian val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 306230148Sadrian val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 307230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 308230148Sadrian 309230148Sadrian cal_data += 3; 310230148Sadrian while (*cal_data != 0xffff) { 311230148Sadrian reg = *cal_data++; 312230148Sadrian val = *cal_data++; 313230148Sadrian val |= (*cal_data++) << 16; 314234217Sadrian if (bootverbose) 315234217Sadrian printf(" reg: %x, val=%x\n", reg, val); 316230148Sadrian 317230148Sadrian /* Write eeprom fixup data to device memory */ 318230148Sadrian ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); 319230148Sadrian DELAY(100); 320230148Sadrian } 321230148Sadrian 322230148Sadrian val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 323230148Sadrian val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 324230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 325230148Sadrian 326230148Sadrian /* Write the saved bar(0) address */ 327230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), bar0, 4); 328230148Sadrian} 329230148Sadrian 330230148Sadrianstatic void 331230148Sadrianar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func) 332230148Sadrian{ 333230148Sadrian long int flash_addr; 334234485Sadrian char buf[64]; 335234485Sadrian int size; 336230148Sadrian 337230148Sadrian /* 338230148Sadrian * Check whether the given slot has a hint to poke. 339230148Sadrian */ 340234217Sadrian if (bootverbose) 341234217Sadrian device_printf(dev, "%s: checking dev %s, %d/%d/%d\n", 342230148Sadrian __func__, device_get_nameunit(dev), bus, slot, func); 343234485Sadrian 344230148Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", 345230148Sadrian bus, slot, func); 346230148Sadrian 347230148Sadrian if (resource_long_value(device_get_name(dev), device_get_unit(dev), 348230148Sadrian buf, &flash_addr) == 0) { 349234485Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size", 350234485Sadrian bus, slot, func); 351234485Sadrian if (resource_int_value(device_get_name(dev), 352234485Sadrian device_get_unit(dev), buf, &size) != 0) { 353234485Sadrian device_printf(dev, 354234485Sadrian "%s: missing hint '%s', aborting EEPROM\n", 355234485Sadrian __func__, buf); 356234485Sadrian return; 357234485Sadrian } 358234485Sadrian 359234485Sadrian 360234217Sadrian device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n", 361234217Sadrian flash_addr, bus, slot, func); 362234485Sadrian ar71xx_pci_fixup(dev, bus, slot, func, flash_addr, size); 363234217Sadrian ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func, 364234485Sadrian flash_addr, size); 365230148Sadrian } 366230148Sadrian} 367230148Sadrian#endif /* AR71XX_ATH_EEPROM */ 368230148Sadrian 369187706Sgonzostatic int 370187706Sgonzoar71xx_pci_probe(device_t dev) 371187706Sgonzo{ 372187706Sgonzo 373257338Snwhitehorn return (BUS_PROBE_NOWILDCARD); 374187706Sgonzo} 375187706Sgonzo 376187706Sgonzostatic int 377187706Sgonzoar71xx_pci_attach(device_t dev) 378187706Sgonzo{ 379187706Sgonzo int rid = 0; 380187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 381187706Sgonzo 382187706Sgonzo sc->sc_mem_rman.rm_type = RMAN_ARRAY; 383187706Sgonzo sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window"; 384187706Sgonzo if (rman_init(&sc->sc_mem_rman) != 0 || 385187706Sgonzo rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, 386187706Sgonzo AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { 387187706Sgonzo panic("ar71xx_pci_attach: failed to set up I/O rman"); 388187706Sgonzo } 389187706Sgonzo 390187706Sgonzo sc->sc_irq_rman.rm_type = RMAN_ARRAY; 391187706Sgonzo sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs"; 392187706Sgonzo if (rman_init(&sc->sc_irq_rman) != 0 || 393187706Sgonzo rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, 394187706Sgonzo AR71XX_PCI_IRQ_END) != 0) 395187706Sgonzo panic("ar71xx_pci_attach: failed to set up IRQ rman"); 396187706Sgonzo 397245112Smonthadar /* 398245112Smonthadar * Check if there is a base slot hint. Otherwise use default value. 399245112Smonthadar */ 400245112Smonthadar if (resource_int_value(device_get_name(dev), 401245112Smonthadar device_get_unit(dev), "baseslot", &sc->sc_baseslot) != 0) { 402245112Smonthadar device_printf(dev, 403245112Smonthadar "%s: missing hint '%s', default to AR71XX_PCI_BASE_SLOT\n", 404245112Smonthadar __func__, "baseslot"); 405245112Smonthadar sc->sc_baseslot = AR71XX_PCI_BASE_SLOT; 406245112Smonthadar } 407187706Sgonzo 408187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); 409187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); 410187706Sgonzo 411187706Sgonzo /* Hook up our interrupt handler. */ 412187706Sgonzo if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 413187706Sgonzo RF_SHAREABLE | RF_ACTIVE)) == NULL) { 414187706Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 415187706Sgonzo return ENXIO; 416187706Sgonzo } 417187706Sgonzo 418187706Sgonzo if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, 419191872Sgonzo ar71xx_pci_intr, NULL, sc, &sc->sc_ih))) { 420234366Sadrian device_printf(dev, 421187706Sgonzo "WARNING: unable to register interrupt handler\n"); 422187706Sgonzo return ENXIO; 423187706Sgonzo } 424187706Sgonzo 425187706Sgonzo /* reset PCI core and PCI bus */ 426211478Sadrian ar71xx_device_stop(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 427203132Sgonzo DELAY(100000); 428187706Sgonzo 429211478Sadrian ar71xx_device_start(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 430203132Sgonzo DELAY(100000); 431187706Sgonzo 432187706Sgonzo /* Init PCI windows */ 433187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR); 434187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR); 435187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR); 436187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR); 437187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR); 438187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR); 439187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR); 440187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR); 441203132Sgonzo DELAY(100000); 442187706Sgonzo 443234365Sadrian mtx_lock_spin(&ar71xx_pci_mtx); 444187706Sgonzo ar71xx_pci_check_bus_error(); 445234365Sadrian mtx_unlock_spin(&ar71xx_pci_mtx); 446187706Sgonzo 447187706Sgonzo /* Fixup internal PCI bridge */ 448234204Sadrian ar71xx_pci_local_write(dev, PCIR_COMMAND, 449234204Sadrian PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN 450187706Sgonzo | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK 451234204Sadrian | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 4); 452187706Sgonzo 453230148Sadrian#ifdef AR71XX_ATH_EEPROM 454230148Sadrian /* 455230148Sadrian * Hard-code a check for slot 17 and 18 - these are 456230148Sadrian * the two PCI slots which may have a PCI device that 457230148Sadrian * requires "fixing". 458230148Sadrian */ 459230148Sadrian ar71xx_pci_slot_fixup(dev, 0, 17, 0); 460230148Sadrian ar71xx_pci_slot_fixup(dev, 0, 18, 0); 461230148Sadrian#endif /* AR71XX_ATH_EEPROM */ 462230148Sadrian 463287882Szbb device_add_child(dev, "pci", -1); 464187706Sgonzo return (bus_generic_attach(dev)); 465187706Sgonzo} 466187706Sgonzo 467187706Sgonzostatic int 468234366Sadrianar71xx_pci_read_ivar(device_t dev, device_t child, int which, 469234366Sadrian uintptr_t *result) 470187706Sgonzo{ 471187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 472187706Sgonzo 473187706Sgonzo switch (which) { 474187706Sgonzo case PCIB_IVAR_DOMAIN: 475187706Sgonzo *result = 0; 476187706Sgonzo return (0); 477187706Sgonzo case PCIB_IVAR_BUS: 478187706Sgonzo *result = sc->sc_busno; 479187706Sgonzo return (0); 480187706Sgonzo } 481187706Sgonzo 482187706Sgonzo return (ENOENT); 483187706Sgonzo} 484187706Sgonzo 485187706Sgonzostatic int 486234366Sadrianar71xx_pci_write_ivar(device_t dev, device_t child, int which, 487234366Sadrian uintptr_t result) 488187706Sgonzo{ 489187706Sgonzo struct ar71xx_pci_softc * sc = device_get_softc(dev); 490187706Sgonzo 491187706Sgonzo switch (which) { 492187706Sgonzo case PCIB_IVAR_BUS: 493187706Sgonzo sc->sc_busno = result; 494187706Sgonzo return (0); 495187706Sgonzo } 496187706Sgonzo 497187706Sgonzo return (ENOENT); 498187706Sgonzo} 499187706Sgonzo 500187706Sgonzostatic struct resource * 501187706Sgonzoar71xx_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 502294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 503187706Sgonzo{ 504187706Sgonzo 505234366Sadrian struct ar71xx_pci_softc *sc = device_get_softc(bus); 506192161Sgonzo struct resource *rv; 507187706Sgonzo struct rman *rm; 508187706Sgonzo 509187706Sgonzo switch (type) { 510187706Sgonzo case SYS_RES_IRQ: 511187706Sgonzo rm = &sc->sc_irq_rman; 512187706Sgonzo break; 513187706Sgonzo case SYS_RES_MEMORY: 514187706Sgonzo rm = &sc->sc_mem_rman; 515187706Sgonzo break; 516187706Sgonzo default: 517187706Sgonzo return (NULL); 518187706Sgonzo } 519187706Sgonzo 520187706Sgonzo rv = rman_reserve_resource(rm, start, end, count, flags, child); 521187706Sgonzo 522187706Sgonzo if (rv == NULL) 523187706Sgonzo return (NULL); 524187706Sgonzo 525187706Sgonzo rman_set_rid(rv, *rid); 526187706Sgonzo 527187706Sgonzo if (flags & RF_ACTIVE) { 528187706Sgonzo if (bus_activate_resource(child, type, *rid, rv)) { 529187706Sgonzo rman_release_resource(rv); 530187706Sgonzo return (NULL); 531187706Sgonzo } 532234366Sadrian } 533187706Sgonzo return (rv); 534187706Sgonzo} 535187706Sgonzo 536187706Sgonzostatic int 537192161Sgonzoar71xx_pci_activate_resource(device_t bus, device_t child, int type, int rid, 538192161Sgonzo struct resource *r) 539192161Sgonzo{ 540192161Sgonzo int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 541192161Sgonzo child, type, rid, r)); 542192161Sgonzo 543192161Sgonzo if (!res) { 544192161Sgonzo switch(type) { 545192161Sgonzo case SYS_RES_MEMORY: 546192161Sgonzo case SYS_RES_IOPORT: 547192161Sgonzo rman_set_bustag(r, ar71xx_bus_space_pcimem); 548192161Sgonzo break; 549192161Sgonzo } 550192161Sgonzo } 551192161Sgonzo return (res); 552192161Sgonzo} 553192161Sgonzo 554192161Sgonzostatic int 555191872Sgonzoar71xx_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 556234366Sadrian int flags, driver_filter_t *filt, driver_intr_t *handler, 557234366Sadrian void *arg, void **cookiep) 558191872Sgonzo{ 559191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 560191872Sgonzo struct intr_event *event; 561191872Sgonzo int irq, error; 562191872Sgonzo 563191872Sgonzo irq = rman_get_start(ires); 564191872Sgonzo 565191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 566191872Sgonzo panic("%s: bad irq %d", __func__, irq); 567191872Sgonzo 568191872Sgonzo event = sc->sc_eventstab[irq]; 569191872Sgonzo if (event == NULL) { 570191872Sgonzo error = intr_event_create(&event, (void *)irq, 0, irq, 571192822Sgonzo ar71xx_pci_mask_irq, ar71xx_pci_unmask_irq, NULL, NULL, 572210900Sgonzo "pci intr%d:", irq); 573191872Sgonzo 574210900Sgonzo if (error == 0) { 575210900Sgonzo sc->sc_eventstab[irq] = event; 576210900Sgonzo sc->sc_intr_counter[irq] = 577210900Sgonzo mips_intrcnt_create(event->ie_name); 578210900Sgonzo } 579210900Sgonzo else 580234366Sadrian return (error); 581191872Sgonzo } 582191872Sgonzo 583191872Sgonzo intr_event_add_handler(event, device_get_nameunit(child), filt, 584191872Sgonzo handler, arg, intr_priority(flags), flags, cookiep); 585210900Sgonzo mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); 586191872Sgonzo 587192822Sgonzo ar71xx_pci_unmask_irq((void*)irq); 588191872Sgonzo 589191872Sgonzo return (0); 590191872Sgonzo} 591191872Sgonzo 592191872Sgonzostatic int 593191872Sgonzoar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 594187706Sgonzo void *cookie) 595187706Sgonzo{ 596191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 597191872Sgonzo int irq, result; 598187706Sgonzo 599191872Sgonzo irq = rman_get_start(ires); 600191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 601191872Sgonzo panic("%s: bad irq %d", __func__, irq); 602191872Sgonzo 603191872Sgonzo if (sc->sc_eventstab[irq] == NULL) 604191872Sgonzo panic("Trying to teardown unoccupied IRQ"); 605191872Sgonzo 606192822Sgonzo ar71xx_pci_mask_irq((void*)irq); 607191872Sgonzo 608191872Sgonzo result = intr_event_remove_handler(cookie); 609191872Sgonzo if (!result) 610191872Sgonzo sc->sc_eventstab[irq] = NULL; 611191872Sgonzo 612191872Sgonzo return (result); 613187706Sgonzo} 614187706Sgonzo 615187706Sgonzostatic int 616191872Sgonzoar71xx_pci_intr(void *arg) 617191872Sgonzo{ 618191872Sgonzo struct ar71xx_pci_softc *sc = arg; 619191872Sgonzo struct intr_event *event; 620194273Sgonzo uint32_t reg, irq, mask; 621191872Sgonzo 622191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_STATUS); 623194273Sgonzo mask = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 624194273Sgonzo /* 625194273Sgonzo * Handle only unmasked interrupts 626194273Sgonzo */ 627194273Sgonzo reg &= mask; 628191872Sgonzo for (irq = AR71XX_PCI_IRQ_START; irq <= AR71XX_PCI_IRQ_END; irq++) { 629191872Sgonzo if (reg & (1 << irq)) { 630191872Sgonzo event = sc->sc_eventstab[irq]; 631191872Sgonzo if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 632191872Sgonzo /* Ignore timer interrupts */ 633191872Sgonzo if (irq != 0) 634191872Sgonzo printf("Stray IRQ %d\n", irq); 635191872Sgonzo continue; 636191872Sgonzo } 637191872Sgonzo 638285121Sadrian /* Flush DDR FIFO for PCI/PCIe */ 639285121Sadrian ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_PCIE); 640221256Sadrian 641191872Sgonzo /* TODO: frame instead of NULL? */ 642191872Sgonzo intr_event_handle(event, NULL); 643210900Sgonzo mips_intrcnt_inc(sc->sc_intr_counter[irq]); 644191872Sgonzo } 645191872Sgonzo } 646191872Sgonzo 647191872Sgonzo return (FILTER_HANDLED); 648191872Sgonzo} 649191872Sgonzo 650191872Sgonzostatic int 651187706Sgonzoar71xx_pci_maxslots(device_t dev) 652187706Sgonzo{ 653187706Sgonzo 654187706Sgonzo return (PCI_SLOTMAX); 655187706Sgonzo} 656187706Sgonzo 657187706Sgonzostatic int 658187706Sgonzoar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) 659187706Sgonzo{ 660245112Smonthadar struct ar71xx_pci_softc *sc = device_get_softc(pcib); 661245112Smonthadar 662245112Smonthadar if (pci_get_slot(device) < sc->sc_baseslot) 663195474Sgonzo panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", 664195474Sgonzo __func__, pci_get_slot(device)); 665187706Sgonzo 666245112Smonthadar return (pci_get_slot(device) - sc->sc_baseslot); 667187706Sgonzo} 668187706Sgonzo 669187706Sgonzostatic device_method_t ar71xx_pci_methods[] = { 670187706Sgonzo /* Device interface */ 671187706Sgonzo DEVMETHOD(device_probe, ar71xx_pci_probe), 672187706Sgonzo DEVMETHOD(device_attach, ar71xx_pci_attach), 673187706Sgonzo DEVMETHOD(device_shutdown, bus_generic_shutdown), 674187706Sgonzo DEVMETHOD(device_suspend, bus_generic_suspend), 675187706Sgonzo DEVMETHOD(device_resume, bus_generic_resume), 676187706Sgonzo 677187706Sgonzo /* Bus interface */ 678187706Sgonzo DEVMETHOD(bus_read_ivar, ar71xx_pci_read_ivar), 679187706Sgonzo DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar), 680187706Sgonzo DEVMETHOD(bus_alloc_resource, ar71xx_pci_alloc_resource), 681187706Sgonzo DEVMETHOD(bus_release_resource, bus_generic_release_resource), 682192161Sgonzo DEVMETHOD(bus_activate_resource, ar71xx_pci_activate_resource), 683187706Sgonzo DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 684191872Sgonzo DEVMETHOD(bus_setup_intr, ar71xx_pci_setup_intr), 685187706Sgonzo DEVMETHOD(bus_teardown_intr, ar71xx_pci_teardown_intr), 686187706Sgonzo 687187706Sgonzo /* pcib interface */ 688187706Sgonzo DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots), 689187706Sgonzo DEVMETHOD(pcib_read_config, ar71xx_pci_read_config), 690187706Sgonzo DEVMETHOD(pcib_write_config, ar71xx_pci_write_config), 691187706Sgonzo DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt), 692187706Sgonzo 693227843Smarius DEVMETHOD_END 694187706Sgonzo}; 695187706Sgonzo 696187706Sgonzostatic driver_t ar71xx_pci_driver = { 697187706Sgonzo "pcib", 698187706Sgonzo ar71xx_pci_methods, 699187706Sgonzo sizeof(struct ar71xx_pci_softc), 700187706Sgonzo}; 701187706Sgonzo 702187706Sgonzostatic devclass_t ar71xx_pci_devclass; 703187706Sgonzo 704187706SgonzoDRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0); 705