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