Annotation of sys/arch/hppa/dev/apic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: apic.c,v 1.6 2007/07/01 14:20:50 kettenis Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 Michael Shalayeff
! 5: * Copyright (c) 2007 Mark Kettenis
! 6: * All rights reserved.
! 7: *
! 8: * Permission to use, copy, modify, and distribute this software for any
! 9: * purpose with or without fee is hereby granted, provided that the above
! 10: * copyright notice and this permission notice appear in all copies.
! 11: *
! 12: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 13: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 14: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 15: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 16: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
! 17: * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 18: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
! 19:
! 20: #include <sys/param.h>
! 21: #include <sys/systm.h>
! 22: #include <sys/device.h>
! 23: #include <sys/evcount.h>
! 24: #include <sys/malloc.h>
! 25:
! 26: #include <machine/autoconf.h>
! 27: #include <machine/pdc.h>
! 28:
! 29: #include <dev/pci/pcireg.h>
! 30: #include <dev/pci/pcivar.h>
! 31: #include <dev/pci/pcidevs.h>
! 32:
! 33: #include <hppa/dev/elroyreg.h>
! 34: #include <hppa/dev/elroyvar.h>
! 35:
! 36: #define APIC_INT_LINE_MASK 0x0000ff00
! 37: #define APIC_INT_LINE_SHIFT 8
! 38: #define APIC_INT_IRQ_MASK 0x0000001f
! 39:
! 40: #define APIC_INT_LINE(x) (((x) & APIC_INT_LINE_MASK) >> APIC_INT_LINE_SHIFT)
! 41: #define APIC_INT_IRQ(x) ((x) & APIC_INT_IRQ_MASK)
! 42:
! 43: /*
! 44: * Interrupt types match the Intel MP Specification.
! 45: */
! 46:
! 47: #define MPS_INTPO_DEF 0
! 48: #define MPS_INTPO_ACTHI 1
! 49: #define MPS_INTPO_ACTLO 3
! 50: #define MPS_INTPO_SHIFT 0
! 51: #define MPS_INTPO_MASK 3
! 52:
! 53: #define MPS_INTTR_DEF 0
! 54: #define MPS_INTTR_EDGE 1
! 55: #define MPS_INTTR_LEVEL 3
! 56: #define MPS_INTTR_SHIFT 2
! 57: #define MPS_INTTR_MASK 3
! 58:
! 59: #define MPS_INT(p,t) \
! 60: ((((p) & MPS_INTPO_MASK) << MPS_INTPO_SHIFT) | \
! 61: (((t) & MPS_INTTR_MASK) << MPS_INTTR_SHIFT))
! 62:
! 63: struct apic_iv {
! 64: struct elroy_softc *sc;
! 65: pci_intr_handle_t ih;
! 66: int (*handler)(void *);
! 67: void *arg;
! 68: struct apic_iv *next;
! 69: struct evcount *cnt;
! 70: };
! 71:
! 72: struct apic_iv *apic_intr_list[CPU_NINTS];
! 73:
! 74: void apic_get_int_tbl(struct elroy_softc *);
! 75: u_int32_t apic_get_int_ent0(struct elroy_softc *, int);
! 76: #ifdef DEBUG
! 77: void apic_dump(struct elroy_softc *);
! 78: #endif
! 79:
! 80: void
! 81: apic_write(volatile struct elroy_regs *r, u_int32_t reg, u_int32_t val)
! 82: {
! 83: elroy_write32(&r->apic_addr, htole32(reg));
! 84: elroy_write32(&r->apic_data, htole32(val));
! 85: elroy_read32(&r->apic_data);
! 86: }
! 87:
! 88: u_int32_t
! 89: apic_read(volatile struct elroy_regs *r, u_int32_t reg)
! 90: {
! 91: elroy_write32(&r->apic_addr, htole32(reg));
! 92: return letoh32(elroy_read32(&r->apic_data));
! 93: }
! 94:
! 95: void
! 96: apic_attach(struct elroy_softc *sc)
! 97: {
! 98: volatile struct elroy_regs *r = sc->sc_regs;
! 99: u_int32_t data;
! 100:
! 101: data = apic_read(r, APIC_VERSION);
! 102: sc->sc_nints = (data & APIC_VERSION_NENT) >> APIC_VERSION_NENT_SHIFT;
! 103: printf(" APIC ver %x, %d pins",
! 104: data & APIC_VERSION_MASK, sc->sc_nints);
! 105:
! 106: sc->sc_irq = malloc(sc->sc_nints * sizeof(int), M_DEVBUF, M_NOWAIT);
! 107: if (sc->sc_irq == NULL)
! 108: panic("apic_attach: cannot allocate irq table\n");
! 109: memset(sc->sc_irq, 0, sc->sc_nints * sizeof(int));
! 110:
! 111: apic_get_int_tbl(sc);
! 112:
! 113: #ifdef DEBUG
! 114: apic_dump(sc);
! 115: #endif
! 116: }
! 117:
! 118: int
! 119: apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
! 120: {
! 121: struct elroy_softc *sc = pa->pa_pc->_cookie;
! 122: pci_chipset_tag_t pc = pa->pa_pc;
! 123: pcitag_t tag = pa->pa_tag;
! 124: pcireg_t reg;
! 125: int line;
! 126:
! 127: reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
! 128: #ifdef DEBUG
! 129: printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg),
! 130: PCI_INTERRUPT_LINE(reg));
! 131: #endif
! 132: line = PCI_INTERRUPT_LINE(reg);
! 133: if (sc->sc_irq[line] == 0)
! 134: sc->sc_irq[line] = cpu_intr_findirq();
! 135: *ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line];
! 136: return (APIC_INT_IRQ(*ihp) == 0);
! 137: }
! 138:
! 139: const char *
! 140: apic_intr_string(void *v, pci_intr_handle_t ih)
! 141: {
! 142: static char buf[32];
! 143:
! 144: snprintf(buf, 32, "line %ld irq %ld",
! 145: APIC_INT_LINE(ih), APIC_INT_IRQ(ih));
! 146:
! 147: return (buf);
! 148: }
! 149:
! 150: void *
! 151: apic_intr_establish(void *v, pci_intr_handle_t ih,
! 152: int pri, int (*handler)(void *), void *arg, char *name)
! 153: {
! 154: struct elroy_softc *sc = v;
! 155: volatile struct elroy_regs *r = sc->sc_regs;
! 156: hppa_hpa_t hpa = cpu_gethpa(0);
! 157: struct evcount *cnt;
! 158: struct apic_iv *aiv, *biv;
! 159: void *iv;
! 160: int irq = APIC_INT_IRQ(ih);
! 161: int line = APIC_INT_LINE(ih);
! 162: u_int32_t ent0;
! 163:
! 164: /* no mapping or bogus */
! 165: if (irq <= 0 || irq > 31)
! 166: return (NULL);
! 167:
! 168: aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT);
! 169: if (aiv == NULL) {
! 170: free(cnt, M_DEVBUF);
! 171: return NULL;
! 172: }
! 173:
! 174: aiv->sc = sc;
! 175: aiv->ih = ih;
! 176: aiv->handler = handler;
! 177: aiv->arg = arg;
! 178: aiv->next = NULL;
! 179: aiv->cnt = NULL;
! 180: if (apic_intr_list[irq]) {
! 181: cnt = malloc(sizeof(struct evcount), M_DEVBUF, M_NOWAIT);
! 182: if (!cnt) {
! 183: free(aiv, M_DEVBUF);
! 184: return (NULL);
! 185: }
! 186:
! 187: evcount_attach(cnt, name, NULL, &evcount_intr);
! 188: biv = apic_intr_list[irq];
! 189: while (biv->next)
! 190: biv = biv->next;
! 191: biv->next = aiv;
! 192: aiv->cnt = cnt;
! 193: return (arg);
! 194: }
! 195:
! 196: if ((iv = cpu_intr_establish(pri, irq, apic_intr, aiv, name))) {
! 197: ent0 = (31 - irq) & APIC_ENT0_VEC;
! 198: ent0 |= apic_get_int_ent0(sc, line);
! 199: #if 0
! 200: if (cold) {
! 201: sc->sc_imr |= (1 << irq);
! 202: ent0 |= APIC_ENT0_MASK;
! 203: }
! 204: #endif
! 205: apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK);
! 206: apic_write(sc->sc_regs, APIC_ENT1(line),
! 207: ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
! 208: apic_write(sc->sc_regs, APIC_ENT0(line), ent0);
! 209:
! 210: /* Signal EOI. */
! 211: elroy_write32(&r->apic_eoi,
! 212: htole32((31 - irq) & APIC_ENT0_VEC));
! 213:
! 214: apic_intr_list[irq] = aiv;
! 215: }
! 216:
! 217: return (arg);
! 218: }
! 219:
! 220: void
! 221: apic_intr_disestablish(void *v, void *cookie)
! 222: {
! 223: }
! 224:
! 225: int
! 226: apic_intr(void *v)
! 227: {
! 228: struct apic_iv *iv = v;
! 229: struct elroy_softc *sc = iv->sc;
! 230: volatile struct elroy_regs *r = sc->sc_regs;
! 231: int claimed = 0;
! 232:
! 233: while (iv) {
! 234: if (iv->handler(iv->arg)) {
! 235: if (iv->cnt)
! 236: iv->cnt->ec_count++;
! 237: else
! 238: claimed = 1;
! 239: }
! 240: iv = iv->next;
! 241: }
! 242:
! 243: /* Signal EOI. */
! 244: elroy_write32(&r->apic_eoi,
! 245: htole32((31 - APIC_INT_IRQ(iv->ih)) & APIC_ENT0_VEC));
! 246:
! 247: return (claimed);
! 248: }
! 249:
! 250: /* Maximum number of supported interrupt routing entries. */
! 251: #define MAX_INT_TBL_SZ 16
! 252:
! 253: void
! 254: apic_get_int_tbl(struct elroy_softc *sc)
! 255: {
! 256: struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT;
! 257: struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT;
! 258: size_t size;
! 259:
! 260: /*
! 261: * XXX int_tbl should not be allocated on the stack, but we need a
! 262: * 1:1 mapping, and malloc doesn't provide that.
! 263: */
! 264:
! 265: if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SZ,
! 266: &int_tbl_sz, 0, 0, 0, 0, 0))
! 267: return;
! 268:
! 269: if (int_tbl_sz.num > MAX_INT_TBL_SZ)
! 270: panic("interrupt routing table too big (%d entries)",
! 271: int_tbl_sz.num);
! 272:
! 273: size = int_tbl_sz.num * sizeof(struct pdc_pat_pci_rt);
! 274: sc->sc_int_tbl_sz = int_tbl_sz.num;
! 275: sc->sc_int_tbl = malloc(size, M_DEVBUF, M_NOWAIT);
! 276: if (sc->sc_int_tbl == NULL)
! 277: return;
! 278:
! 279: if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
! 280: &int_tbl_sz, 0, &int_tbl, 0, 0, 0))
! 281: return;
! 282:
! 283: memcpy(sc->sc_int_tbl, int_tbl, size);
! 284: }
! 285:
! 286: u_int32_t
! 287: apic_get_int_ent0(struct elroy_softc *sc, int line)
! 288: {
! 289: volatile struct elroy_regs *r = sc->sc_regs;
! 290: int trigger = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF);
! 291: u_int32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV;
! 292: int bus, mpspo, mpstr;
! 293: int i;
! 294:
! 295: bus = letoh32(elroy_read32(&r->busnum)) & 0xff;
! 296: for (i = 0; i < sc->sc_int_tbl_sz; i++) {
! 297: if (bus == sc->sc_int_tbl[i].bus &&
! 298: line == sc->sc_int_tbl[i].line)
! 299: trigger = sc->sc_int_tbl[i].trigger;
! 300: }
! 301:
! 302: mpspo = (trigger >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
! 303: mpstr = (trigger >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
! 304:
! 305: switch (mpspo) {
! 306: case MPS_INTPO_DEF:
! 307: break;
! 308: case MPS_INTPO_ACTHI:
! 309: ent0 &= ~APIC_ENT0_LOW;
! 310: break;
! 311: case MPS_INTPO_ACTLO:
! 312: ent0 |= APIC_ENT0_LOW;
! 313: break;
! 314: default:
! 315: panic("unknown MPS interrupt polarity %d", mpspo);
! 316: }
! 317:
! 318: switch(mpstr) {
! 319: case MPS_INTTR_DEF:
! 320: break;
! 321: case MPS_INTTR_LEVEL:
! 322: ent0 |= APIC_ENT0_LEV;
! 323: break;
! 324: case MPS_INTTR_EDGE:
! 325: ent0 &= ~APIC_ENT0_LEV;
! 326: break;
! 327: default:
! 328: panic("unknown MPS interrupt trigger %d", mpstr);
! 329: }
! 330:
! 331: return ent0;
! 332: }
! 333:
! 334: #ifdef DEBUG
! 335: void
! 336: apic_dump(struct elroy_softc *sc)
! 337: {
! 338: int i;
! 339:
! 340: for (i = 0; i < sc->sc_nints; i++)
! 341: printf("0x%04x 0x%04x\n", apic_read(sc->sc_regs, APIC_ENT0(i)),
! 342: apic_read(sc->sc_regs, APIC_ENT1(i)));
! 343:
! 344: for (i = 0; i < sc->sc_int_tbl_sz; i++) {
! 345: printf("type=%x ", sc->sc_int_tbl[i].type);
! 346: printf("len=%d ", sc->sc_int_tbl[i].len);
! 347: printf("itype=%d ", sc->sc_int_tbl[i].itype);
! 348: printf("trigger=%x ", sc->sc_int_tbl[i].trigger);
! 349: printf("pin=%x ", sc->sc_int_tbl[i].pin);
! 350: printf("bus=%d ", sc->sc_int_tbl[i].bus);
! 351: printf("line=%d ", sc->sc_int_tbl[i].line);
! 352: printf("addr=%x\n", sc->sc_int_tbl[i].addr);
! 353: }
! 354: }
! 355: #endif
CVSweb