[BACK]Return to apic.c CVS log [TXT][DIR] Up to [local] / sys / arch / hppa / dev

Annotation of sys/arch/hppa/dev/apic.c, Revision 1.1.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