ar71xx_pci.c revision 294883
1171095Ssam/*- 2171095Ssam * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3171095Ssam * All rights reserved. 4171095Ssam * 5171095Ssam * Redistribution and use in source and binary forms, with or without 6171095Ssam * modification, are permitted provided that the following conditions 7171095Ssam * are met: 8171095Ssam * 1. Redistributions of source code must retain the above copyright 9171095Ssam * notice unmodified, this list of conditions, and the following 10171095Ssam * disclaimer. 11171095Ssam * 2. Redistributions in binary form must reproduce the above copyright 12171095Ssam * notice, this list of conditions and the following disclaimer in the 13171095Ssam * documentation and/or other materials provided with the distribution. 14171095Ssam * 15171095Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16171095Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17171095Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18171095Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19171095Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20171095Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21171095Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22171095Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23171095Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24171095Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25171095Ssam * SUCH DAMAGE. 26171095Ssam */ 27171095Ssam 28171095Ssam#include <sys/cdefs.h> 29171095Ssam__FBSDID("$FreeBSD: head/sys/mips/atheros/ar71xx_pci.c 294883 2016-01-27 02:23:54Z jhibbits $"); 30171095Ssam 31171095Ssam#include "opt_ar71xx.h" 32171095Ssam 33171095Ssam#include <sys/param.h> 34173139Srwatson#include <sys/systm.h> 35173139Srwatson 36173139Srwatson#include <sys/bus.h> 37173139Srwatson#include <sys/interrupt.h> 38173139Srwatson#include <sys/malloc.h> 39173139Srwatson#include <sys/kernel.h> 40173139Srwatson#include <sys/module.h> 41171095Ssam#include <sys/rman.h> 42171095Ssam#include <sys/lock.h> 43171095Ssam#include <sys/mutex.h> 44171095Ssam 45171095Ssam#include <vm/vm.h> 46171095Ssam#include <vm/pmap.h> 47171095Ssam#include <vm/vm_extern.h> 48171095Ssam 49173139Srwatson#include <machine/bus.h> 50173139Srwatson#include <machine/cpu.h> 51173139Srwatson#include <machine/intr_machdep.h> 52173139Srwatson#include <machine/pmap.h> 53171095Ssam 54171095Ssam#include <dev/pci/pcivar.h> 55171095Ssam#include <dev/pci/pcireg.h> 56171095Ssam 57171095Ssam#include <dev/pci/pcib_private.h> 58171095Ssam#include "pcib_if.h" 59171095Ssam 60171095Ssam#include <mips/atheros/ar71xxreg.h> 61171095Ssam#include <mips/atheros/ar71xx_pci_bus_space.h> 62171095Ssam 63171095Ssam#include <mips/atheros/ar71xx_cpudef.h> 64171095Ssam 65171095Ssam#ifdef AR71XX_ATH_EEPROM 66171095Ssam#include <mips/atheros/ar71xx_fixup.h> 67171095Ssam#endif /* AR71XX_ATH_EEPROM */ 68171095Ssam 69171095Ssam#undef AR71XX_PCI_DEBUG 70171095Ssam#ifdef AR71XX_PCI_DEBUG 71171095Ssam#define dprintf printf 72171095Ssam#else 73171095Ssam#define dprintf(x, arg...) 74171095Ssam#endif 75171095Ssam 76171095Ssamstruct mtx ar71xx_pci_mtx; 77171095SsamMTX_SYSINIT(ar71xx_pci_mtx, &ar71xx_pci_mtx, "ar71xx PCI space mutex", 78171095Ssam MTX_SPIN); 79171095Ssam 80173139Srwatsonstruct ar71xx_pci_softc { 81173139Srwatson device_t sc_dev; 82173139Srwatson 83173139Srwatson int sc_busno; 84173139Srwatson int sc_baseslot; 85173139Srwatson struct rman sc_mem_rman; 86173139Srwatson struct rman sc_irq_rman; 87173139Srwatson 88171095Ssam struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; 89171095Ssam mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; 90171095Ssam struct resource *sc_irq; 91171095Ssam void *sc_ih; 92171095Ssam}; 93171095Ssam 94173139Srwatsonstatic int ar71xx_pci_setup_intr(device_t, device_t, struct resource *, int, 95173139Srwatson driver_filter_t *, driver_intr_t *, void *, void **); 96171095Ssamstatic int ar71xx_pci_teardown_intr(device_t, device_t, struct resource *, 97171095Ssam void *); 98171095Ssamstatic int ar71xx_pci_intr(void *); 99171095Ssam 100171095Ssamstatic void 101171095Ssamar71xx_pci_mask_irq(void *source) 102171095Ssam{ 103171095Ssam uint32_t reg; 104173139Srwatson unsigned int irq = (unsigned int)source; 105173139Srwatson 106173139Srwatson /* XXX is the PCI lock required here? */ 107173139Srwatson reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 108173139Srwatson /* flush */ 109173139Srwatson reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 110173139Srwatson ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg & ~(1 << irq)); 111171095Ssam} 112171095Ssam 113171095Ssamstatic void 114171095Ssamar71xx_pci_unmask_irq(void *source) 115171095Ssam{ 116171095Ssam uint32_t reg; 117171095Ssam unsigned int irq = (unsigned int)source; 118171095Ssam 119171095Ssam /* XXX is the PCI lock required here? */ 120171095Ssam reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 121173139Srwatson ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg | (1 << irq)); 122173139Srwatson /* flush */ 123173139Srwatson reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 124173139Srwatson} 125171095Ssam 126171095Ssam/* 127171095Ssam * get bitmask for bytes of interest: 128171095Ssam * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte 129173139Srwatson * from register 7. Bitmask would be: 0111 130173139Srwatson */ 131173139Srwatsonstatic uint32_t 132173139Srwatsonar71xx_get_bytes_to_read(int reg, int bytes) 133173139Srwatson{ 134173139Srwatson uint32_t bytes_to_read = 0; 135171095Ssam 136173139Srwatson if ((bytes % 4) == 0) 137173139Srwatson bytes_to_read = 0; 138171095Ssam else if ((bytes % 4) == 1) 139173139Srwatson bytes_to_read = (~(1 << (reg % 4))) & 0xf; 140173139Srwatson else if ((bytes % 4) == 2) 141173139Srwatson bytes_to_read = (~(3 << (reg % 4))) & 0xf; 142173139Srwatson else 143173139Srwatson panic("%s: wrong combination", __func__); 144173139Srwatson 145171095Ssam return (bytes_to_read); 146173139Srwatson} 147173139Srwatson 148171095Ssamstatic int 149171095Ssamar71xx_pci_check_bus_error(void) 150171095Ssam{ 151171095Ssam uint32_t error, addr, has_errors = 0; 152171095Ssam 153171095Ssam mtx_assert(&ar71xx_pci_mtx, MA_OWNED); 154171095Ssam 155171095Ssam error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3; 156171095Ssam dprintf("%s: PCI error = %02x\n", __func__, error); 157171095Ssam if (error) { 158171095Ssam addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR); 159171095Ssam 160171095Ssam /* Do not report it yet */ 161171095Ssam#if 0 162171095Ssam printf("PCI bus error %d at addr 0x%08x\n", error, addr); 163171095Ssam#endif 164171095Ssam ATH_WRITE_REG(AR71XX_PCI_ERROR, error); 165171095Ssam has_errors = 1; 166171095Ssam } 167171095Ssam 168171095Ssam error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1; 169171095Ssam dprintf("%s: AHB error = %02x\n", __func__, error); 170171095Ssam if (error) { 171171095Ssam addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR); 172171095Ssam /* Do not report it yet */ 173171095Ssam#if 0 174171095Ssam printf("AHB bus error %d at addr 0x%08x\n", error, addr); 175173139Srwatson#endif 176171095Ssam ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error); 177171095Ssam has_errors = 1; 178173139Srwatson } 179171095Ssam 180171095Ssam return (has_errors); 181171095Ssam} 182173139Srwatson 183171095Ssamstatic uint32_t 184171095Ssamar71xx_pci_make_addr(int bus, int slot, int func, int reg) 185173139Srwatson{ 186173139Srwatson if (bus == 0) { 187171095Ssam return ((1 << slot) | (func << 8) | (reg & ~3)); 188171095Ssam } else { 189171095Ssam return ((bus << 16) | (slot << 11) | (func << 8) 190171095Ssam | (reg & ~3) | 1); 191173139Srwatson } 192171095Ssam} 193171095Ssam 194171095Ssamstatic int 195171095Ssamar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes, 196171095Ssam uint32_t cmd) 197171095Ssam{ 198173139Srwatson uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3)); 199171095Ssam 200171095Ssam mtx_assert(&ar71xx_pci_mtx, MA_OWNED); 201171095Ssam 202171095Ssam cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4); 203173139Srwatson ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr); 204171095Ssam ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd); 205171095Ssam 206173139Srwatson dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__, 207171095Ssam bus, slot, func, reg, bytes, addr, cmd); 208171095Ssam 209171095Ssam return ar71xx_pci_check_bus_error(); 210171095Ssam} 211171095Ssam 212173139Srwatsonstatic uint32_t 213173139Srwatsonar71xx_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 214173139Srwatson u_int reg, int bytes) 215171095Ssam{ 216171095Ssam uint32_t data; 217171095Ssam uint32_t shift, mask; 218171095Ssam 219171095Ssam /* register access is 32-bit aligned */ 220171095Ssam shift = (reg & 3) * 8; 221171095Ssam 222171095Ssam /* Create a mask based on the width, post-shift */ 223171095Ssam if (bytes == 2) 224171095Ssam mask = 0xffff; 225171095Ssam else if (bytes == 1) 226171095Ssam mask = 0xff; 227171095Ssam else 228171095Ssam mask = 0xffffffff; 229171095Ssam 230171095Ssam dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 231171095Ssam func, reg, bytes); 232171095Ssam 233171095Ssam mtx_lock_spin(&ar71xx_pci_mtx); 234173139Srwatson if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 235173139Srwatson PCI_CONF_CMD_READ) == 0) 236171095Ssam data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA); 237171095Ssam else 238171095Ssam data = -1; 239171095Ssam mtx_unlock_spin(&ar71xx_pci_mtx); 240173139Srwatson 241171095Ssam /* get request bytes from 32-bit word */ 242171095Ssam data = (data >> shift) & mask; 243171095Ssam 244173139Srwatson dprintf("%s: read 0x%x\n", __func__, data); 245173139Srwatson 246171095Ssam return (data); 247171095Ssam} 248171095Ssam 249171095Ssamstatic void 250171095Ssamar71xx_pci_local_write(device_t dev, uint32_t reg, uint32_t data, int bytes) 251171095Ssam{ 252171095Ssam uint32_t cmd; 253171095Ssam 254171095Ssam dprintf("%s: local write reg %d(%d)\n", __func__, reg, bytes); 255173139Srwatson 256171095Ssam data = data << (8*(reg % 4)); 257171095Ssam cmd = PCI_LCONF_CMD_WRITE | (reg & ~3); 258173139Srwatson cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 20); 259173139Srwatson mtx_lock_spin(&ar71xx_pci_mtx); 260173139Srwatson ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); 261173139Srwatson ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data); 262173139Srwatson mtx_unlock_spin(&ar71xx_pci_mtx); 263173139Srwatson} 264173139Srwatson 265173139Srwatsonstatic void 266171095Ssamar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 267173139Srwatson u_int reg, uint32_t data, int bytes) 268171095Ssam{ 269171095Ssam 270171095Ssam dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 271173139Srwatson func, reg, bytes); 272173139Srwatson 273173139Srwatson data = data << (8*(reg % 4)); 274171095Ssam mtx_lock_spin(&ar71xx_pci_mtx); 275173139Srwatson if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 276173139Srwatson PCI_CONF_CMD_WRITE) == 0) 277171095Ssam ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data); 278171095Ssam mtx_unlock_spin(&ar71xx_pci_mtx); 279173139Srwatson} 280173139Srwatson 281173139Srwatson#ifdef AR71XX_ATH_EEPROM 282173139Srwatson/* 283173139Srwatson * Some embedded boards (eg AP94) have the MAC attached via PCI but they 284173139Srwatson * don't have the MAC-attached EEPROM. The register initialisation 285173139Srwatson * values and calibration data are stored in the on-board flash. 286171095Ssam * This routine initialises the NIC via the EEPROM register contents 287171095Ssam * before the probe/attach routines get a go at things. 288171095Ssam */ 289173139Srwatsonstatic void 290173139Srwatsonar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func, 291171095Ssam long flash_addr, int len) 292171095Ssam{ 293171095Ssam uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); 294171095Ssam uint32_t reg, val, bar0; 295171095Ssam 296173139Srwatson if (bootverbose) 297173139Srwatson device_printf(dev, "%s: flash_addr=%lx, cal_data=%p\n", 298171095Ssam __func__, flash_addr, cal_data); 299171095Ssam 300171095Ssam /* XXX check 0xa55a */ 301173139Srwatson /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ 302173139Srwatson bar0 = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_BAR(0), 4); 303173139Srwatson ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), 304173139Srwatson AR71XX_PCI_MEM_BASE, 4); 305171095Ssam 306171095Ssam val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 307171095Ssam val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 308171095Ssam ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 309173139Srwatson 310173139Srwatson cal_data += 3; 311171095Ssam while (*cal_data != 0xffff) { 312171095Ssam reg = *cal_data++; 313171095Ssam val = *cal_data++; 314171095Ssam val |= (*cal_data++) << 16; 315171095Ssam if (bootverbose) 316171095Ssam printf(" reg: %x, val=%x\n", reg, val); 317171095Ssam 318171095Ssam /* Write eeprom fixup data to device memory */ 319171095Ssam ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); 320171095Ssam DELAY(100); 321171095Ssam } 322171095Ssam 323171095Ssam val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 324173139Srwatson val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 325171095Ssam ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 326171095Ssam 327171095Ssam /* Write the saved bar(0) address */ 328171095Ssam ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), bar0, 4); 329171095Ssam} 330171095Ssam 331171095Ssamstatic void 332171095Ssamar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func) 333171095Ssam{ 334171095Ssam long int flash_addr; 335171095Ssam char buf[64]; 336173139Srwatson int size; 337171095Ssam 338173139Srwatson /* 339173139Srwatson * Check whether the given slot has a hint to poke. 340171095Ssam */ 341171095Ssam if (bootverbose) 342171095Ssam device_printf(dev, "%s: checking dev %s, %d/%d/%d\n", 343171095Ssam __func__, device_get_nameunit(dev), bus, slot, func); 344171095Ssam 345171095Ssam snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", 346171095Ssam bus, slot, func); 347171095Ssam 348171095Ssam if (resource_long_value(device_get_name(dev), device_get_unit(dev), 349171095Ssam buf, &flash_addr) == 0) { 350171095Ssam snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size", 351171095Ssam bus, slot, func); 352171095Ssam if (resource_int_value(device_get_name(dev), 353171095Ssam device_get_unit(dev), buf, &size) != 0) { 354171095Ssam device_printf(dev, 355171095Ssam "%s: missing hint '%s', aborting EEPROM\n", 356171095Ssam __func__, buf); 357171095Ssam return; 358171095Ssam } 359171095Ssam 360171095Ssam 361171095Ssam device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n", 362171095Ssam flash_addr, bus, slot, func); 363171095Ssam ar71xx_pci_fixup(dev, bus, slot, func, flash_addr, size); 364171095Ssam ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func, 365171095Ssam flash_addr, size); 366171095Ssam } 367171095Ssam} 368171095Ssam#endif /* AR71XX_ATH_EEPROM */ 369171095Ssam 370171095Ssamstatic int 371171095Ssamar71xx_pci_probe(device_t dev) 372171095Ssam{ 373171095Ssam 374171095Ssam return (BUS_PROBE_NOWILDCARD); 375171095Ssam} 376171095Ssam 377171095Ssamstatic int 378173139Srwatsonar71xx_pci_attach(device_t dev) 379173139Srwatson{ 380173139Srwatson int rid = 0; 381173139Srwatson struct ar71xx_pci_softc *sc = device_get_softc(dev); 382173139Srwatson 383171095Ssam sc->sc_mem_rman.rm_type = RMAN_ARRAY; 384173139Srwatson sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window"; 385173139Srwatson if (rman_init(&sc->sc_mem_rman) != 0 || 386173139Srwatson rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, 387173139Srwatson AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { 388173139Srwatson panic("ar71xx_pci_attach: failed to set up I/O rman"); 389171095Ssam } 390171095Ssam 391173139Srwatson sc->sc_irq_rman.rm_type = RMAN_ARRAY; 392173139Srwatson sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs"; 393173139Srwatson if (rman_init(&sc->sc_irq_rman) != 0 || 394173139Srwatson rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, 395171095Ssam AR71XX_PCI_IRQ_END) != 0) 396171095Ssam panic("ar71xx_pci_attach: failed to set up IRQ rman"); 397171095Ssam 398171095Ssam /* 399171095Ssam * Check if there is a base slot hint. Otherwise use default value. 400173139Srwatson */ 401173139Srwatson if (resource_int_value(device_get_name(dev), 402171095Ssam device_get_unit(dev), "baseslot", &sc->sc_baseslot) != 0) { 403173139Srwatson device_printf(dev, 404173139Srwatson "%s: missing hint '%s', default to AR71XX_PCI_BASE_SLOT\n", 405173139Srwatson __func__, "baseslot"); 406173139Srwatson sc->sc_baseslot = AR71XX_PCI_BASE_SLOT; 407173139Srwatson } 408173139Srwatson 409173139Srwatson ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); 410171095Ssam ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); 411173139Srwatson 412173139Srwatson /* Hook up our interrupt handler. */ 413173139Srwatson if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 414173139Srwatson RF_SHAREABLE | RF_ACTIVE)) == NULL) { 415173139Srwatson device_printf(dev, "unable to allocate IRQ resource\n"); 416173139Srwatson return ENXIO; 417173139Srwatson } 418173139Srwatson 419173139Srwatson if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, 420173139Srwatson ar71xx_pci_intr, NULL, sc, &sc->sc_ih))) { 421173139Srwatson device_printf(dev, 422173139Srwatson "WARNING: unable to register interrupt handler\n"); 423173139Srwatson return ENXIO; 424173139Srwatson } 425173139Srwatson 426173139Srwatson /* reset PCI core and PCI bus */ 427173139Srwatson ar71xx_device_stop(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 428173139Srwatson DELAY(100000); 429173139Srwatson 430173139Srwatson ar71xx_device_start(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 431171095Ssam DELAY(100000); 432171095Ssam 433171095Ssam /* Init PCI windows */ 434171095Ssam ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR); 435171095Ssam ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR); 436171095Ssam ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR); 437171095Ssam ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR); 438171095Ssam ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR); 439171095Ssam ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR); 440173139Srwatson ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR); 441173139Srwatson ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR); 442173139Srwatson DELAY(100000); 443173139Srwatson 444171095Ssam mtx_lock_spin(&ar71xx_pci_mtx); 445171095Ssam ar71xx_pci_check_bus_error(); 446171095Ssam mtx_unlock_spin(&ar71xx_pci_mtx); 447171095Ssam 448171095Ssam /* Fixup internal PCI bridge */ 449171095Ssam ar71xx_pci_local_write(dev, PCIR_COMMAND, 450171095Ssam PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN 451171095Ssam | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK 452173139Srwatson | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 4); 453173139Srwatson 454173139Srwatson#ifdef AR71XX_ATH_EEPROM 455171095Ssam /* 456171095Ssam * Hard-code a check for slot 17 and 18 - these are 457171095Ssam * the two PCI slots which may have a PCI device that 458171095Ssam * requires "fixing". 459171095Ssam */ 460171095Ssam ar71xx_pci_slot_fixup(dev, 0, 17, 0); 461171095Ssam ar71xx_pci_slot_fixup(dev, 0, 18, 0); 462173139Srwatson#endif /* AR71XX_ATH_EEPROM */ 463173139Srwatson 464171095Ssam device_add_child(dev, "pci", -1); 465173139Srwatson return (bus_generic_attach(dev)); 466173139Srwatson} 467173139Srwatson 468173139Srwatsonstatic int 469171095Ssamar71xx_pci_read_ivar(device_t dev, device_t child, int which, 470173139Srwatson uintptr_t *result) 471173139Srwatson{ 472173139Srwatson struct ar71xx_pci_softc *sc = device_get_softc(dev); 473173139Srwatson 474173139Srwatson switch (which) { 475173139Srwatson case PCIB_IVAR_DOMAIN: 476173139Srwatson *result = 0; 477173139Srwatson return (0); 478173139Srwatson case PCIB_IVAR_BUS: 479173139Srwatson *result = sc->sc_busno; 480173139Srwatson return (0); 481171095Ssam } 482173139Srwatson 483173139Srwatson return (ENOENT); 484173139Srwatson} 485173139Srwatson 486171095Ssamstatic int 487171095Ssamar71xx_pci_write_ivar(device_t dev, device_t child, int which, 488171095Ssam uintptr_t result) 489171095Ssam{ 490171095Ssam struct ar71xx_pci_softc * sc = device_get_softc(dev); 491171095Ssam 492171095Ssam switch (which) { 493171095Ssam case PCIB_IVAR_BUS: 494171095Ssam sc->sc_busno = result; 495173139Srwatson return (0); 496171095Ssam } 497171095Ssam 498171095Ssam return (ENOENT); 499171095Ssam} 500171095Ssam 501171095Ssamstatic struct resource * 502173139Srwatsonar71xx_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 503173139Srwatson rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 504173139Srwatson{ 505173139Srwatson 506173139Srwatson struct ar71xx_pci_softc *sc = device_get_softc(bus); 507171095Ssam struct resource *rv; 508173139Srwatson struct rman *rm; 509171095Ssam 510171095Ssam switch (type) { 511173139Srwatson case SYS_RES_IRQ: 512171095Ssam rm = &sc->sc_irq_rman; 513171095Ssam break; 514171095Ssam case SYS_RES_MEMORY: 515171095Ssam rm = &sc->sc_mem_rman; 516171095Ssam break; 517171095Ssam default: 518171095Ssam return (NULL); 519171095Ssam } 520173139Srwatson 521171095Ssam rv = rman_reserve_resource(rm, start, end, count, flags, child); 522171095Ssam 523171095Ssam if (rv == NULL) 524171095Ssam return (NULL); 525171095Ssam 526173139Srwatson rman_set_rid(rv, *rid); 527171095Ssam 528171095Ssam if (flags & RF_ACTIVE) { 529171095Ssam if (bus_activate_resource(child, type, *rid, rv)) { 530171095Ssam rman_release_resource(rv); 531171095Ssam return (NULL); 532171095Ssam } 533171095Ssam } 534171095Ssam return (rv); 535173139Srwatson} 536173139Srwatson 537173139Srwatsonstatic int 538173139Srwatsonar71xx_pci_activate_resource(device_t bus, device_t child, int type, int rid, 539173139Srwatson struct resource *r) 540173139Srwatson{ 541171095Ssam int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 542173139Srwatson child, type, rid, r)); 543171095Ssam 544171095Ssam if (!res) { 545171095Ssam switch(type) { 546171095Ssam case SYS_RES_MEMORY: 547173139Srwatson case SYS_RES_IOPORT: 548173139Srwatson rman_set_bustag(r, ar71xx_bus_space_pcimem); 549173139Srwatson break; 550171095Ssam } 551171095Ssam } 552173139Srwatson return (res); 553173139Srwatson} 554171095Ssam 555171095Ssamstatic int 556171095Ssamar71xx_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 557171095Ssam int flags, driver_filter_t *filt, driver_intr_t *handler, 558171095Ssam void *arg, void **cookiep) 559171095Ssam{ 560171095Ssam struct ar71xx_pci_softc *sc = device_get_softc(bus); 561 struct intr_event *event; 562 int irq, error; 563 564 irq = rman_get_start(ires); 565 566 if (irq > AR71XX_PCI_IRQ_END) 567 panic("%s: bad irq %d", __func__, irq); 568 569 event = sc->sc_eventstab[irq]; 570 if (event == NULL) { 571 error = intr_event_create(&event, (void *)irq, 0, irq, 572 ar71xx_pci_mask_irq, ar71xx_pci_unmask_irq, NULL, NULL, 573 "pci intr%d:", irq); 574 575 if (error == 0) { 576 sc->sc_eventstab[irq] = event; 577 sc->sc_intr_counter[irq] = 578 mips_intrcnt_create(event->ie_name); 579 } 580 else 581 return (error); 582 } 583 584 intr_event_add_handler(event, device_get_nameunit(child), filt, 585 handler, arg, intr_priority(flags), flags, cookiep); 586 mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); 587 588 ar71xx_pci_unmask_irq((void*)irq); 589 590 return (0); 591} 592 593static int 594ar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 595 void *cookie) 596{ 597 struct ar71xx_pci_softc *sc = device_get_softc(dev); 598 int irq, result; 599 600 irq = rman_get_start(ires); 601 if (irq > AR71XX_PCI_IRQ_END) 602 panic("%s: bad irq %d", __func__, irq); 603 604 if (sc->sc_eventstab[irq] == NULL) 605 panic("Trying to teardown unoccupied IRQ"); 606 607 ar71xx_pci_mask_irq((void*)irq); 608 609 result = intr_event_remove_handler(cookie); 610 if (!result) 611 sc->sc_eventstab[irq] = NULL; 612 613 return (result); 614} 615 616static int 617ar71xx_pci_intr(void *arg) 618{ 619 struct ar71xx_pci_softc *sc = arg; 620 struct intr_event *event; 621 uint32_t reg, irq, mask; 622 623 reg = ATH_READ_REG(AR71XX_PCI_INTR_STATUS); 624 mask = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 625 /* 626 * Handle only unmasked interrupts 627 */ 628 reg &= mask; 629 for (irq = AR71XX_PCI_IRQ_START; irq <= AR71XX_PCI_IRQ_END; irq++) { 630 if (reg & (1 << irq)) { 631 event = sc->sc_eventstab[irq]; 632 if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 633 /* Ignore timer interrupts */ 634 if (irq != 0) 635 printf("Stray IRQ %d\n", irq); 636 continue; 637 } 638 639 /* Flush DDR FIFO for PCI/PCIe */ 640 ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_PCIE); 641 642 /* TODO: frame instead of NULL? */ 643 intr_event_handle(event, NULL); 644 mips_intrcnt_inc(sc->sc_intr_counter[irq]); 645 } 646 } 647 648 return (FILTER_HANDLED); 649} 650 651static int 652ar71xx_pci_maxslots(device_t dev) 653{ 654 655 return (PCI_SLOTMAX); 656} 657 658static int 659ar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) 660{ 661 struct ar71xx_pci_softc *sc = device_get_softc(pcib); 662 663 if (pci_get_slot(device) < sc->sc_baseslot) 664 panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", 665 __func__, pci_get_slot(device)); 666 667 return (pci_get_slot(device) - sc->sc_baseslot); 668} 669 670static device_method_t ar71xx_pci_methods[] = { 671 /* Device interface */ 672 DEVMETHOD(device_probe, ar71xx_pci_probe), 673 DEVMETHOD(device_attach, ar71xx_pci_attach), 674 DEVMETHOD(device_shutdown, bus_generic_shutdown), 675 DEVMETHOD(device_suspend, bus_generic_suspend), 676 DEVMETHOD(device_resume, bus_generic_resume), 677 678 /* Bus interface */ 679 DEVMETHOD(bus_read_ivar, ar71xx_pci_read_ivar), 680 DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar), 681 DEVMETHOD(bus_alloc_resource, ar71xx_pci_alloc_resource), 682 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 683 DEVMETHOD(bus_activate_resource, ar71xx_pci_activate_resource), 684 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 685 DEVMETHOD(bus_setup_intr, ar71xx_pci_setup_intr), 686 DEVMETHOD(bus_teardown_intr, ar71xx_pci_teardown_intr), 687 688 /* pcib interface */ 689 DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots), 690 DEVMETHOD(pcib_read_config, ar71xx_pci_read_config), 691 DEVMETHOD(pcib_write_config, ar71xx_pci_write_config), 692 DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt), 693 694 DEVMETHOD_END 695}; 696 697static driver_t ar71xx_pci_driver = { 698 "pcib", 699 ar71xx_pci_methods, 700 sizeof(struct ar71xx_pci_softc), 701}; 702 703static devclass_t ar71xx_pci_devclass; 704 705DRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0); 706