ar71xx_pci.c revision 210900
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 210900 2010-08-05 21:31:29Z gonzo $"); 30187706Sgonzo 31187706Sgonzo#include <sys/param.h> 32187706Sgonzo#include <sys/systm.h> 33187706Sgonzo 34187706Sgonzo#include <sys/bus.h> 35187706Sgonzo#include <sys/interrupt.h> 36187706Sgonzo#include <sys/malloc.h> 37187706Sgonzo#include <sys/kernel.h> 38187706Sgonzo#include <sys/module.h> 39187706Sgonzo#include <sys/rman.h> 40187706Sgonzo 41187706Sgonzo#include <vm/vm.h> 42187706Sgonzo#include <vm/pmap.h> 43187706Sgonzo#include <vm/vm_extern.h> 44187706Sgonzo 45187706Sgonzo#include <machine/bus.h> 46187706Sgonzo#include <machine/cpu.h> 47210900Sgonzo#include <machine/intr_machdep.h> 48187706Sgonzo#include <machine/pmap.h> 49187706Sgonzo 50187706Sgonzo#include <dev/pci/pcivar.h> 51187706Sgonzo#include <dev/pci/pcireg.h> 52187706Sgonzo 53187706Sgonzo#include <dev/pci/pcib_private.h> 54187706Sgonzo#include "pcib_if.h" 55187706Sgonzo 56192161Sgonzo#include <mips/atheros/ar71xxreg.h> 57192161Sgonzo#include <mips/atheros/ar71xx_pci_bus_space.h> 58187706Sgonzo 59187706Sgonzo#undef AR71XX_PCI_DEBUG 60187706Sgonzo#ifdef AR71XX_PCI_DEBUG 61187706Sgonzo#define dprintf printf 62187706Sgonzo#else 63187706Sgonzo#define dprintf(x, arg...) 64187706Sgonzo#endif 65187706Sgonzo 66187706Sgonzostruct ar71xx_pci_softc { 67187706Sgonzo device_t sc_dev; 68187706Sgonzo 69187706Sgonzo int sc_busno; 70187706Sgonzo struct rman sc_mem_rman; 71187706Sgonzo struct rman sc_irq_rman; 72187706Sgonzo 73191872Sgonzo struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; 74210900Sgonzo mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; 75187706Sgonzo struct resource *sc_irq; 76187706Sgonzo void *sc_ih; 77187706Sgonzo}; 78187706Sgonzo 79191872Sgonzostatic int ar71xx_pci_setup_intr(device_t, device_t, struct resource *, int, 80191872Sgonzo driver_filter_t *, driver_intr_t *, void *, void **); 81191872Sgonzostatic int ar71xx_pci_teardown_intr(device_t, device_t, struct resource *, 82191872Sgonzo void *); 83191872Sgonzostatic int ar71xx_pci_intr(void *); 84191872Sgonzo 85192822Sgonzostatic void 86192822Sgonzoar71xx_pci_mask_irq(void *source) 87191872Sgonzo{ 88191872Sgonzo uint32_t reg; 89192822Sgonzo unsigned int irq = (unsigned int)source; 90191872Sgonzo 91191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 92194273Sgonzo /* flush */ 93194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 94191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg & ~(1 << irq)); 95191872Sgonzo} 96191872Sgonzo 97192822Sgonzostatic void 98192822Sgonzoar71xx_pci_unmask_irq(void *source) 99191872Sgonzo{ 100191872Sgonzo uint32_t reg; 101192822Sgonzo unsigned int irq = (unsigned int)source; 102191872Sgonzo 103191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 104191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg | (1 << irq)); 105194273Sgonzo /* flush */ 106194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 107191872Sgonzo} 108191872Sgonzo 109187706Sgonzo/* 110187706Sgonzo * get bitmask for bytes of interest: 111187706Sgonzo * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte 112187706Sgonzo * from register 7. Bitmask would be: 0111 113187706Sgonzo */ 114187706Sgonzostatic uint32_t 115187706Sgonzoar71xx_get_bytes_to_read(int reg, int bytes) 116187706Sgonzo{ 117187706Sgonzo uint32_t bytes_to_read = 0; 118187706Sgonzo if ((bytes % 4) == 0) 119187706Sgonzo bytes_to_read = 0; 120187706Sgonzo else if ((bytes % 4) == 1) 121187706Sgonzo bytes_to_read = (~(1 << (reg % 4))) & 0xf; 122187706Sgonzo else if ((bytes % 4) == 2) 123187706Sgonzo bytes_to_read = (~(3 << (reg % 4))) & 0xf; 124187706Sgonzo else 125187706Sgonzo panic("%s: wrong combination", __func__); 126187706Sgonzo 127187706Sgonzo return (bytes_to_read); 128187706Sgonzo} 129187706Sgonzo 130187706Sgonzostatic int 131187706Sgonzoar71xx_pci_check_bus_error(void) 132187706Sgonzo{ 133187706Sgonzo uint32_t error, addr, has_errors = 0; 134187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3; 135187706Sgonzo dprintf("%s: PCI error = %02x\n", __func__, error); 136187706Sgonzo if (error) { 137187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR); 138187706Sgonzo 139187706Sgonzo /* Do not report it yet */ 140187706Sgonzo#if 0 141187706Sgonzo printf("PCI bus error %d at addr 0x%08x\n", error, addr); 142187706Sgonzo#endif 143187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_ERROR, error); 144187706Sgonzo has_errors = 1; 145187706Sgonzo } 146187706Sgonzo 147187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1; 148187706Sgonzo dprintf("%s: AHB error = %02x\n", __func__, error); 149187706Sgonzo if (error) { 150187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR); 151187706Sgonzo /* Do not report it yet */ 152187706Sgonzo#if 0 153187706Sgonzo printf("AHB bus error %d at addr 0x%08x\n", error, addr); 154187706Sgonzo#endif 155187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error); 156187706Sgonzo has_errors = 1; 157187706Sgonzo } 158187706Sgonzo 159187706Sgonzo return (has_errors); 160187706Sgonzo} 161187706Sgonzo 162187706Sgonzostatic uint32_t 163187706Sgonzoar71xx_pci_make_addr(int bus, int slot, int func, int reg) 164187706Sgonzo{ 165187706Sgonzo if (bus == 0) { 166187706Sgonzo return ((1 << slot) | (func << 8) | (reg & ~3)); 167187706Sgonzo } else { 168187706Sgonzo return ((bus << 16) | (slot << 11) | (func << 8) 169187706Sgonzo | (reg & ~3) | 1); 170187706Sgonzo } 171187706Sgonzo} 172187706Sgonzo 173187706Sgonzostatic int 174187706Sgonzoar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes, 175187706Sgonzo uint32_t cmd) 176187706Sgonzo{ 177187706Sgonzo uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3)); 178187706Sgonzo cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4); 179187706Sgonzo 180187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr); 181187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd); 182187706Sgonzo 183187706Sgonzo dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__, 184187706Sgonzo bus, slot, func, reg, bytes, addr, cmd); 185187706Sgonzo 186187706Sgonzo return ar71xx_pci_check_bus_error(); 187187706Sgonzo} 188187706Sgonzo 189187706Sgonzostatic uint32_t 190194059Sgonzoar71xx_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 191194059Sgonzo u_int reg, int bytes) 192187706Sgonzo{ 193187706Sgonzo uint32_t data; 194187706Sgonzo uint32_t cmd, shift, mask; 195187706Sgonzo 196187706Sgonzo /* register access is 32-bit aligned */ 197187706Sgonzo shift = (reg & 3) * 8; 198187706Sgonzo if (shift) 199187706Sgonzo mask = (1 << shift) - 1; 200187706Sgonzo else 201187706Sgonzo mask = 0xffffffff; 202187706Sgonzo 203187706Sgonzo dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 204187706Sgonzo func, reg, bytes); 205187706Sgonzo 206187706Sgonzo if ((bus == 0) && (slot == 0) && (func == 0)) { 207187706Sgonzo cmd = PCI_LCONF_CMD_READ | (reg & ~3); 208187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); 209187706Sgonzo data = ATH_READ_REG(AR71XX_PCI_LCONF_READ_DATA); 210187706Sgonzo } else { 211187706Sgonzo if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 212187706Sgonzo PCI_CONF_CMD_READ) == 0) 213187706Sgonzo data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA); 214187706Sgonzo else 215187706Sgonzo data = -1; 216187706Sgonzo } 217187706Sgonzo 218187706Sgonzo /* get request bytes from 32-bit word */ 219187706Sgonzo data = (data >> shift) & mask; 220187706Sgonzo 221187706Sgonzo dprintf("%s: read 0x%x\n", __func__, data); 222187706Sgonzo 223187706Sgonzo return (data); 224187706Sgonzo} 225187706Sgonzo 226187706Sgonzostatic void 227194059Sgonzoar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 228194059Sgonzo u_int reg, uint32_t data, int bytes) 229187706Sgonzo{ 230187706Sgonzo uint32_t cmd; 231187706Sgonzo 232187706Sgonzo dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 233187706Sgonzo func, reg, bytes); 234187706Sgonzo 235187706Sgonzo data = data << (8*(reg % 4)); 236187706Sgonzo 237187706Sgonzo if ((bus == 0) && (slot == 0) && (func == 0)) { 238187706Sgonzo cmd = PCI_LCONF_CMD_WRITE | (reg & ~3); 239187706Sgonzo cmd |= ar71xx_get_bytes_to_read(reg, bytes) << 20; 240187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); 241187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data); 242187706Sgonzo } else { 243187706Sgonzo if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 244187706Sgonzo PCI_CONF_CMD_WRITE) == 0) 245187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data); 246187706Sgonzo } 247187706Sgonzo} 248187706Sgonzo 249187706Sgonzostatic int 250187706Sgonzoar71xx_pci_probe(device_t dev) 251187706Sgonzo{ 252187706Sgonzo 253187706Sgonzo return (0); 254187706Sgonzo} 255187706Sgonzo 256187706Sgonzostatic int 257187706Sgonzoar71xx_pci_attach(device_t dev) 258187706Sgonzo{ 259187706Sgonzo int busno = 0; 260187706Sgonzo int rid = 0; 261187706Sgonzo uint32_t reset; 262187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 263187706Sgonzo 264187706Sgonzo sc->sc_mem_rman.rm_type = RMAN_ARRAY; 265187706Sgonzo sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window"; 266187706Sgonzo if (rman_init(&sc->sc_mem_rman) != 0 || 267187706Sgonzo rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, 268187706Sgonzo AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { 269187706Sgonzo panic("ar71xx_pci_attach: failed to set up I/O rman"); 270187706Sgonzo } 271187706Sgonzo 272187706Sgonzo sc->sc_irq_rman.rm_type = RMAN_ARRAY; 273187706Sgonzo sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs"; 274187706Sgonzo if (rman_init(&sc->sc_irq_rman) != 0 || 275187706Sgonzo rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, 276187706Sgonzo AR71XX_PCI_IRQ_END) != 0) 277187706Sgonzo panic("ar71xx_pci_attach: failed to set up IRQ rman"); 278187706Sgonzo 279187706Sgonzo 280187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); 281187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); 282187706Sgonzo 283187706Sgonzo /* Hook up our interrupt handler. */ 284187706Sgonzo if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 285187706Sgonzo RF_SHAREABLE | RF_ACTIVE)) == NULL) { 286187706Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 287187706Sgonzo return ENXIO; 288187706Sgonzo } 289187706Sgonzo 290187706Sgonzo if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, 291191872Sgonzo ar71xx_pci_intr, NULL, sc, &sc->sc_ih))) { 292187706Sgonzo device_printf(dev, 293187706Sgonzo "WARNING: unable to register interrupt handler\n"); 294187706Sgonzo return ENXIO; 295187706Sgonzo } 296187706Sgonzo 297187706Sgonzo /* reset PCI core and PCI bus */ 298187706Sgonzo reset = ATH_READ_REG(AR71XX_RST_RESET); 299187706Sgonzo reset |= (RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 300187706Sgonzo ATH_WRITE_REG(AR71XX_RST_RESET, reset); 301194470Sgonzo ATH_READ_REG(AR71XX_RST_RESET); 302203132Sgonzo DELAY(100000); 303187706Sgonzo 304187706Sgonzo reset &= ~(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 305187706Sgonzo ATH_WRITE_REG(AR71XX_RST_RESET, reset); 306194470Sgonzo ATH_READ_REG(AR71XX_RST_RESET); 307203132Sgonzo DELAY(100000); 308187706Sgonzo 309187706Sgonzo /* Init PCI windows */ 310187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR); 311187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR); 312187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR); 313187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR); 314187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR); 315187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR); 316187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR); 317187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR); 318203132Sgonzo DELAY(100000); 319187706Sgonzo 320187706Sgonzo ar71xx_pci_check_bus_error(); 321187706Sgonzo 322187706Sgonzo /* Fixup internal PCI bridge */ 323187706Sgonzo ar71xx_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, 324187706Sgonzo PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN 325187706Sgonzo | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK 326187706Sgonzo | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 2); 327187706Sgonzo 328187706Sgonzo device_add_child(dev, "pci", busno); 329187706Sgonzo return (bus_generic_attach(dev)); 330187706Sgonzo} 331187706Sgonzo 332187706Sgonzostatic int 333187706Sgonzoar71xx_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 334187706Sgonzo{ 335187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 336187706Sgonzo 337187706Sgonzo switch (which) { 338187706Sgonzo case PCIB_IVAR_DOMAIN: 339187706Sgonzo *result = 0; 340187706Sgonzo return (0); 341187706Sgonzo case PCIB_IVAR_BUS: 342187706Sgonzo *result = sc->sc_busno; 343187706Sgonzo return (0); 344187706Sgonzo } 345187706Sgonzo 346187706Sgonzo return (ENOENT); 347187706Sgonzo} 348187706Sgonzo 349187706Sgonzostatic int 350187706Sgonzoar71xx_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 351187706Sgonzo{ 352187706Sgonzo struct ar71xx_pci_softc * sc = device_get_softc(dev); 353187706Sgonzo 354187706Sgonzo switch (which) { 355187706Sgonzo case PCIB_IVAR_BUS: 356187706Sgonzo sc->sc_busno = result; 357187706Sgonzo return (0); 358187706Sgonzo } 359187706Sgonzo 360187706Sgonzo return (ENOENT); 361187706Sgonzo} 362187706Sgonzo 363187706Sgonzostatic struct resource * 364187706Sgonzoar71xx_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 365187706Sgonzo u_long start, u_long end, u_long count, u_int flags) 366187706Sgonzo{ 367187706Sgonzo 368187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 369192161Sgonzo struct resource *rv; 370187706Sgonzo struct rman *rm; 371187706Sgonzo 372187706Sgonzo switch (type) { 373187706Sgonzo case SYS_RES_IRQ: 374187706Sgonzo rm = &sc->sc_irq_rman; 375187706Sgonzo break; 376187706Sgonzo case SYS_RES_MEMORY: 377187706Sgonzo rm = &sc->sc_mem_rman; 378187706Sgonzo break; 379187706Sgonzo default: 380187706Sgonzo return (NULL); 381187706Sgonzo } 382187706Sgonzo 383187706Sgonzo rv = rman_reserve_resource(rm, start, end, count, flags, child); 384187706Sgonzo 385187706Sgonzo if (rv == NULL) 386187706Sgonzo return (NULL); 387187706Sgonzo 388187706Sgonzo rman_set_rid(rv, *rid); 389187706Sgonzo 390187706Sgonzo if (flags & RF_ACTIVE) { 391187706Sgonzo if (bus_activate_resource(child, type, *rid, rv)) { 392187706Sgonzo rman_release_resource(rv); 393187706Sgonzo return (NULL); 394187706Sgonzo } 395187706Sgonzo } 396187706Sgonzo 397192161Sgonzo 398187706Sgonzo return (rv); 399187706Sgonzo} 400187706Sgonzo 401192161Sgonzo 402187706Sgonzostatic int 403192161Sgonzoar71xx_pci_activate_resource(device_t bus, device_t child, int type, int rid, 404192161Sgonzo struct resource *r) 405192161Sgonzo{ 406192161Sgonzo int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 407192161Sgonzo child, type, rid, r)); 408192161Sgonzo 409192161Sgonzo if (!res) { 410192161Sgonzo switch(type) { 411192161Sgonzo case SYS_RES_MEMORY: 412192161Sgonzo case SYS_RES_IOPORT: 413192161Sgonzo rman_set_bustag(r, ar71xx_bus_space_pcimem); 414192161Sgonzo break; 415192161Sgonzo } 416192161Sgonzo } 417192161Sgonzo 418192161Sgonzo return (res); 419192161Sgonzo} 420192161Sgonzo 421192161Sgonzo 422192161Sgonzo 423192161Sgonzostatic int 424191872Sgonzoar71xx_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 425191872Sgonzo int flags, driver_filter_t *filt, driver_intr_t *handler, 426191872Sgonzo void *arg, void **cookiep) 427191872Sgonzo{ 428191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 429191872Sgonzo struct intr_event *event; 430191872Sgonzo int irq, error; 431191872Sgonzo 432191872Sgonzo irq = rman_get_start(ires); 433191872Sgonzo 434191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 435191872Sgonzo panic("%s: bad irq %d", __func__, irq); 436191872Sgonzo 437191872Sgonzo event = sc->sc_eventstab[irq]; 438191872Sgonzo if (event == NULL) { 439191872Sgonzo error = intr_event_create(&event, (void *)irq, 0, irq, 440192822Sgonzo ar71xx_pci_mask_irq, ar71xx_pci_unmask_irq, NULL, NULL, 441210900Sgonzo "pci intr%d:", irq); 442191872Sgonzo 443210900Sgonzo if (error == 0) { 444210900Sgonzo sc->sc_eventstab[irq] = event; 445210900Sgonzo sc->sc_intr_counter[irq] = 446210900Sgonzo mips_intrcnt_create(event->ie_name); 447210900Sgonzo } 448210900Sgonzo else 449210900Sgonzo return error; 450191872Sgonzo } 451191872Sgonzo 452191872Sgonzo intr_event_add_handler(event, device_get_nameunit(child), filt, 453191872Sgonzo handler, arg, intr_priority(flags), flags, cookiep); 454210900Sgonzo mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); 455191872Sgonzo 456192822Sgonzo ar71xx_pci_unmask_irq((void*)irq); 457191872Sgonzo 458191872Sgonzo return (0); 459191872Sgonzo} 460191872Sgonzo 461191872Sgonzostatic int 462191872Sgonzoar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 463187706Sgonzo void *cookie) 464187706Sgonzo{ 465191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 466191872Sgonzo int irq, result; 467187706Sgonzo 468191872Sgonzo irq = rman_get_start(ires); 469191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 470191872Sgonzo panic("%s: bad irq %d", __func__, irq); 471191872Sgonzo 472191872Sgonzo if (sc->sc_eventstab[irq] == NULL) 473191872Sgonzo panic("Trying to teardown unoccupied IRQ"); 474191872Sgonzo 475192822Sgonzo ar71xx_pci_mask_irq((void*)irq); 476191872Sgonzo 477191872Sgonzo result = intr_event_remove_handler(cookie); 478191872Sgonzo if (!result) 479191872Sgonzo sc->sc_eventstab[irq] = NULL; 480191872Sgonzo 481191872Sgonzo return (result); 482187706Sgonzo} 483187706Sgonzo 484187706Sgonzostatic int 485191872Sgonzoar71xx_pci_intr(void *arg) 486191872Sgonzo{ 487191872Sgonzo struct ar71xx_pci_softc *sc = arg; 488191872Sgonzo struct intr_event *event; 489194273Sgonzo uint32_t reg, irq, mask; 490191872Sgonzo 491191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_STATUS); 492194273Sgonzo mask = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 493194273Sgonzo /* 494194273Sgonzo * Handle only unmasked interrupts 495194273Sgonzo */ 496194273Sgonzo reg &= mask; 497191872Sgonzo for (irq = AR71XX_PCI_IRQ_START; irq <= AR71XX_PCI_IRQ_END; irq++) { 498191872Sgonzo if (reg & (1 << irq)) { 499191872Sgonzo event = sc->sc_eventstab[irq]; 500191872Sgonzo if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 501191872Sgonzo /* Ignore timer interrupts */ 502191872Sgonzo if (irq != 0) 503191872Sgonzo printf("Stray IRQ %d\n", irq); 504191872Sgonzo continue; 505191872Sgonzo } 506191872Sgonzo 507191872Sgonzo /* TODO: frame instead of NULL? */ 508191872Sgonzo intr_event_handle(event, NULL); 509210900Sgonzo mips_intrcnt_inc(sc->sc_intr_counter[irq]); 510191872Sgonzo } 511191872Sgonzo } 512191872Sgonzo 513191872Sgonzo return (FILTER_HANDLED); 514191872Sgonzo} 515191872Sgonzo 516191872Sgonzostatic int 517187706Sgonzoar71xx_pci_maxslots(device_t dev) 518187706Sgonzo{ 519187706Sgonzo 520187706Sgonzo return (PCI_SLOTMAX); 521187706Sgonzo} 522187706Sgonzo 523187706Sgonzostatic int 524187706Sgonzoar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) 525187706Sgonzo{ 526195474Sgonzo if (pci_get_slot(device) < AR71XX_PCI_BASE_SLOT) 527195474Sgonzo panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", 528195474Sgonzo __func__, pci_get_slot(device)); 529187706Sgonzo 530195474Sgonzo return (pci_get_slot(device) - AR71XX_PCI_BASE_SLOT); 531187706Sgonzo} 532187706Sgonzo 533187706Sgonzostatic device_method_t ar71xx_pci_methods[] = { 534187706Sgonzo /* Device interface */ 535187706Sgonzo DEVMETHOD(device_probe, ar71xx_pci_probe), 536187706Sgonzo DEVMETHOD(device_attach, ar71xx_pci_attach), 537187706Sgonzo DEVMETHOD(device_shutdown, bus_generic_shutdown), 538187706Sgonzo DEVMETHOD(device_suspend, bus_generic_suspend), 539187706Sgonzo DEVMETHOD(device_resume, bus_generic_resume), 540187706Sgonzo 541187706Sgonzo /* Bus interface */ 542187706Sgonzo DEVMETHOD(bus_print_child, bus_generic_print_child), 543187706Sgonzo DEVMETHOD(bus_read_ivar, ar71xx_pci_read_ivar), 544187706Sgonzo DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar), 545187706Sgonzo DEVMETHOD(bus_alloc_resource, ar71xx_pci_alloc_resource), 546187706Sgonzo DEVMETHOD(bus_release_resource, bus_generic_release_resource), 547192161Sgonzo DEVMETHOD(bus_activate_resource, ar71xx_pci_activate_resource), 548187706Sgonzo DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 549191872Sgonzo DEVMETHOD(bus_setup_intr, ar71xx_pci_setup_intr), 550187706Sgonzo DEVMETHOD(bus_teardown_intr, ar71xx_pci_teardown_intr), 551187706Sgonzo 552187706Sgonzo /* pcib interface */ 553187706Sgonzo DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots), 554187706Sgonzo DEVMETHOD(pcib_read_config, ar71xx_pci_read_config), 555187706Sgonzo DEVMETHOD(pcib_write_config, ar71xx_pci_write_config), 556187706Sgonzo DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt), 557187706Sgonzo 558187706Sgonzo {0, 0} 559187706Sgonzo}; 560187706Sgonzo 561187706Sgonzostatic driver_t ar71xx_pci_driver = { 562187706Sgonzo "pcib", 563187706Sgonzo ar71xx_pci_methods, 564187706Sgonzo sizeof(struct ar71xx_pci_softc), 565187706Sgonzo}; 566187706Sgonzo 567187706Sgonzostatic devclass_t ar71xx_pci_devclass; 568187706Sgonzo 569187706SgonzoDRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0); 570