1*51f66ac7Skettenis /* $OpenBSD: apic.c,v 1.19 2018/05/14 13:54:39 kettenis Exp $ */
2b95ee612Skettenis
3b95ee612Skettenis /*
4b95ee612Skettenis * Copyright (c) 2005 Michael Shalayeff
5b95ee612Skettenis * Copyright (c) 2007 Mark Kettenis
6b95ee612Skettenis * All rights reserved.
7b95ee612Skettenis *
8b95ee612Skettenis * Permission to use, copy, modify, and distribute this software for any
9b95ee612Skettenis * purpose with or without fee is hereby granted, provided that the above
10b95ee612Skettenis * copyright notice and this permission notice appear in all copies.
11b95ee612Skettenis *
12b95ee612Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13b95ee612Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14b95ee612Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15b95ee612Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16b95ee612Skettenis * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
17b95ee612Skettenis * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18b95ee612Skettenis * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
19b95ee612Skettenis
20b95ee612Skettenis #include <sys/param.h>
21b95ee612Skettenis #include <sys/systm.h>
22b95ee612Skettenis #include <sys/device.h>
23804c1233Skettenis #include <sys/evcount.h>
24b95ee612Skettenis #include <sys/malloc.h>
25b95ee612Skettenis
26b95ee612Skettenis #include <machine/autoconf.h>
27b95ee612Skettenis #include <machine/pdc.h>
28b95ee612Skettenis
29b95ee612Skettenis #include <dev/pci/pcireg.h>
30b95ee612Skettenis #include <dev/pci/pcivar.h>
31b95ee612Skettenis #include <dev/pci/pcidevs.h>
32b95ee612Skettenis
33b95ee612Skettenis #include <hppa/dev/elroyreg.h>
34b95ee612Skettenis #include <hppa/dev/elroyvar.h>
35b95ee612Skettenis
3615fe2033Skettenis #define APIC_INT_LINE_MASK 0x0000ff00
3715fe2033Skettenis #define APIC_INT_LINE_SHIFT 8
3815fe2033Skettenis #define APIC_INT_IRQ_MASK 0x0000001f
3915fe2033Skettenis
4015fe2033Skettenis #define APIC_INT_LINE(x) (((x) & APIC_INT_LINE_MASK) >> APIC_INT_LINE_SHIFT)
4115fe2033Skettenis #define APIC_INT_IRQ(x) ((x) & APIC_INT_IRQ_MASK)
4215fe2033Skettenis
4389a56fa7Skettenis /*
4489a56fa7Skettenis * Interrupt types match the Intel MP Specification.
4589a56fa7Skettenis */
4689a56fa7Skettenis
4789a56fa7Skettenis #define MPS_INTPO_DEF 0
4889a56fa7Skettenis #define MPS_INTPO_ACTHI 1
4989a56fa7Skettenis #define MPS_INTPO_ACTLO 3
5089a56fa7Skettenis #define MPS_INTPO_SHIFT 0
5189a56fa7Skettenis #define MPS_INTPO_MASK 3
5289a56fa7Skettenis
5389a56fa7Skettenis #define MPS_INTTR_DEF 0
5489a56fa7Skettenis #define MPS_INTTR_EDGE 1
5589a56fa7Skettenis #define MPS_INTTR_LEVEL 3
5689a56fa7Skettenis #define MPS_INTTR_SHIFT 2
5789a56fa7Skettenis #define MPS_INTTR_MASK 3
5889a56fa7Skettenis
5989a56fa7Skettenis #define MPS_INT(p,t) \
6089a56fa7Skettenis ((((p) & MPS_INTPO_MASK) << MPS_INTPO_SHIFT) | \
6189a56fa7Skettenis (((t) & MPS_INTTR_MASK) << MPS_INTTR_SHIFT))
6289a56fa7Skettenis
63b95ee612Skettenis struct apic_iv {
64b95ee612Skettenis struct elroy_softc *sc;
65b95ee612Skettenis pci_intr_handle_t ih;
66b95ee612Skettenis int (*handler)(void *);
67b95ee612Skettenis void *arg;
68b95ee612Skettenis struct apic_iv *next;
69804c1233Skettenis struct evcount *cnt;
70b95ee612Skettenis };
71b95ee612Skettenis
72b95ee612Skettenis struct apic_iv *apic_intr_list[CPU_NINTS];
73b95ee612Skettenis
7489a56fa7Skettenis void apic_get_int_tbl(struct elroy_softc *);
7589a56fa7Skettenis u_int32_t apic_get_int_ent0(struct elroy_softc *, int);
76b95ee612Skettenis #ifdef DEBUG
77b95ee612Skettenis void apic_dump(struct elroy_softc *);
78b95ee612Skettenis #endif
79b95ee612Skettenis
80dd6e4488Sderaadt void apic_write(volatile struct elroy_regs *r, u_int32_t reg,
81dd6e4488Sderaadt u_int32_t val);
82dd6e4488Sderaadt u_int32_t apic_read(volatile struct elroy_regs *r, u_int32_t reg);
83dd6e4488Sderaadt
84b95ee612Skettenis void
apic_write(volatile struct elroy_regs * r,u_int32_t reg,u_int32_t val)85b95ee612Skettenis apic_write(volatile struct elroy_regs *r, u_int32_t reg, u_int32_t val)
86b95ee612Skettenis {
87b95ee612Skettenis elroy_write32(&r->apic_addr, htole32(reg));
88b95ee612Skettenis elroy_write32(&r->apic_data, htole32(val));
89b95ee612Skettenis elroy_read32(&r->apic_data);
90b95ee612Skettenis }
91b95ee612Skettenis
92b95ee612Skettenis u_int32_t
apic_read(volatile struct elroy_regs * r,u_int32_t reg)93b95ee612Skettenis apic_read(volatile struct elroy_regs *r, u_int32_t reg)
94b95ee612Skettenis {
95b95ee612Skettenis elroy_write32(&r->apic_addr, htole32(reg));
96b95ee612Skettenis return letoh32(elroy_read32(&r->apic_data));
97b95ee612Skettenis }
98b95ee612Skettenis
99b95ee612Skettenis void
apic_attach(struct elroy_softc * sc)100b95ee612Skettenis apic_attach(struct elroy_softc *sc)
101b95ee612Skettenis {
102b95ee612Skettenis volatile struct elroy_regs *r = sc->sc_regs;
103b95ee612Skettenis u_int32_t data;
104b95ee612Skettenis
105b95ee612Skettenis data = apic_read(r, APIC_VERSION);
106b95ee612Skettenis sc->sc_nints = (data & APIC_VERSION_NENT) >> APIC_VERSION_NENT_SHIFT;
107b95ee612Skettenis printf(" APIC ver %x, %d pins",
108b95ee612Skettenis data & APIC_VERSION_MASK, sc->sc_nints);
109b95ee612Skettenis
1105714159aSdoug sc->sc_irq = mallocarray(sc->sc_nints, sizeof(int), M_DEVBUF,
111184c5478Skrw M_NOWAIT | M_ZERO);
11215fe2033Skettenis if (sc->sc_irq == NULL)
113859d5ed4Skrw panic("apic_attach: cannot allocate irq table");
11415fe2033Skettenis
11589a56fa7Skettenis apic_get_int_tbl(sc);
11689a56fa7Skettenis
117b95ee612Skettenis #ifdef DEBUG
118b95ee612Skettenis apic_dump(sc);
119b95ee612Skettenis #endif
120b95ee612Skettenis }
121b95ee612Skettenis
122b95ee612Skettenis int
apic_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)123b95ee612Skettenis apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
124b95ee612Skettenis {
12515fe2033Skettenis struct elroy_softc *sc = pa->pa_pc->_cookie;
126b95ee612Skettenis pci_chipset_tag_t pc = pa->pa_pc;
127b95ee612Skettenis pcitag_t tag = pa->pa_tag;
128b95ee612Skettenis pcireg_t reg;
12915fe2033Skettenis int line;
130b95ee612Skettenis
131b95ee612Skettenis reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
132b95ee612Skettenis #ifdef DEBUG
133b95ee612Skettenis printf(" pin=%d line=%d ", PCI_INTERRUPT_PIN(reg),
134b95ee612Skettenis PCI_INTERRUPT_LINE(reg));
135b95ee612Skettenis #endif
13615fe2033Skettenis line = PCI_INTERRUPT_LINE(reg);
137*51f66ac7Skettenis if (sc->sc_irq[line] <= 0) {
138*51f66ac7Skettenis if ((sc->sc_irq[line] = cpu_intr_findirq()) == -1)
139*51f66ac7Skettenis return 1;
140*51f66ac7Skettenis }
14115fe2033Skettenis *ihp = (line << APIC_INT_LINE_SHIFT) | sc->sc_irq[line];
14215fe2033Skettenis return (APIC_INT_IRQ(*ihp) == 0);
143b95ee612Skettenis }
144b95ee612Skettenis
145b95ee612Skettenis const char *
apic_intr_string(void * v,pci_intr_handle_t ih)146b95ee612Skettenis apic_intr_string(void *v, pci_intr_handle_t ih)
147b95ee612Skettenis {
148b95ee612Skettenis static char buf[32];
149b95ee612Skettenis
15015fe2033Skettenis snprintf(buf, 32, "line %ld irq %ld",
15115fe2033Skettenis APIC_INT_LINE(ih), APIC_INT_IRQ(ih));
152b95ee612Skettenis
153b95ee612Skettenis return (buf);
154b95ee612Skettenis }
155b95ee612Skettenis
156b95ee612Skettenis void *
apic_intr_establish(void * v,pci_intr_handle_t ih,int pri,int (* handler)(void *),void * arg,const char * name)157b95ee612Skettenis apic_intr_establish(void *v, pci_intr_handle_t ih,
158c03b1b92Smk int pri, int (*handler)(void *), void *arg, const char *name)
159b95ee612Skettenis {
160b95ee612Skettenis struct elroy_softc *sc = v;
161b95ee612Skettenis volatile struct elroy_regs *r = sc->sc_regs;
162b95ee612Skettenis hppa_hpa_t hpa = cpu_gethpa(0);
163804c1233Skettenis struct evcount *cnt;
164b95ee612Skettenis struct apic_iv *aiv, *biv;
165b95ee612Skettenis void *iv;
16615fe2033Skettenis int irq = APIC_INT_IRQ(ih);
16715fe2033Skettenis int line = APIC_INT_LINE(ih);
16815fe2033Skettenis u_int32_t ent0;
169b95ee612Skettenis
170b95ee612Skettenis /* no mapping or bogus */
17115fe2033Skettenis if (irq <= 0 || irq > 31)
172b95ee612Skettenis return (NULL);
173b95ee612Skettenis
174b95ee612Skettenis aiv = malloc(sizeof(struct apic_iv), M_DEVBUF, M_NOWAIT);
17554b0a103Smlarkin if (aiv == NULL)
17654b0a103Smlarkin return (NULL);
177b95ee612Skettenis
178804c1233Skettenis cnt = malloc(sizeof(struct evcount), M_DEVBUF, M_NOWAIT);
179804c1233Skettenis if (!cnt) {
180367b04a3Sderaadt free(aiv, M_DEVBUF, sizeof *aiv);
181804c1233Skettenis return (NULL);
182804c1233Skettenis }
183804c1233Skettenis
184b83c2504Skettenis aiv->sc = sc;
185b83c2504Skettenis aiv->ih = ih;
186b83c2504Skettenis aiv->handler = handler;
187b83c2504Skettenis aiv->arg = arg;
188b83c2504Skettenis aiv->next = NULL;
189b83c2504Skettenis aiv->cnt = cnt;
190b83c2504Skettenis
1914667bebbSmatthew evcount_attach(cnt, name, NULL);
192b83c2504Skettenis
193b83c2504Skettenis if (apic_intr_list[irq]) {
19415fe2033Skettenis biv = apic_intr_list[irq];
195b95ee612Skettenis while (biv->next)
196b95ee612Skettenis biv = biv->next;
197b95ee612Skettenis biv->next = aiv;
198b95ee612Skettenis return (arg);
199b95ee612Skettenis }
200b95ee612Skettenis
201b83c2504Skettenis if ((iv = cpu_intr_establish(pri, irq, apic_intr, aiv, NULL))) {
20215fe2033Skettenis ent0 = (31 - irq) & APIC_ENT0_VEC;
20389a56fa7Skettenis ent0 |= apic_get_int_ent0(sc, line);
204b95ee612Skettenis #if 0
205b95ee612Skettenis if (cold) {
20615fe2033Skettenis sc->sc_imr |= (1 << irq);
207b95ee612Skettenis ent0 |= APIC_ENT0_MASK;
208b95ee612Skettenis }
209b95ee612Skettenis #endif
21015fe2033Skettenis apic_write(sc->sc_regs, APIC_ENT0(line), APIC_ENT0_MASK);
21115fe2033Skettenis apic_write(sc->sc_regs, APIC_ENT1(line),
212b95ee612Skettenis ((hpa & 0x0ff00000) >> 4) | ((hpa & 0x000ff000) << 12));
21315fe2033Skettenis apic_write(sc->sc_regs, APIC_ENT0(line), ent0);
214b95ee612Skettenis
21515fe2033Skettenis /* Signal EOI. */
21615fe2033Skettenis elroy_write32(&r->apic_eoi,
21715fe2033Skettenis htole32((31 - irq) & APIC_ENT0_VEC));
218b95ee612Skettenis
21915fe2033Skettenis apic_intr_list[irq] = aiv;
220b95ee612Skettenis }
221b95ee612Skettenis
222b95ee612Skettenis return (arg);
223b95ee612Skettenis }
224b95ee612Skettenis
225b95ee612Skettenis void
apic_intr_disestablish(void * v,void * cookie)226b95ee612Skettenis apic_intr_disestablish(void *v, void *cookie)
227b95ee612Skettenis {
228b95ee612Skettenis }
229b95ee612Skettenis
230b95ee612Skettenis int
apic_intr(void * v)231b95ee612Skettenis apic_intr(void *v)
232b95ee612Skettenis {
233b95ee612Skettenis struct apic_iv *iv = v;
234b95ee612Skettenis struct elroy_softc *sc = iv->sc;
235b95ee612Skettenis volatile struct elroy_regs *r = sc->sc_regs;
2360b8b2ce6Skettenis pci_intr_handle_t ih = iv->ih;
237b95ee612Skettenis int claimed = 0;
238b95ee612Skettenis
239b95ee612Skettenis while (iv) {
240f84a0763Skettenis claimed = iv->handler(iv->arg);
241f84a0763Skettenis if (claimed != 0 && iv->cnt)
242804c1233Skettenis iv->cnt->ec_count++;
243f84a0763Skettenis if (claimed == 1)
244f84a0763Skettenis break;
245b95ee612Skettenis iv = iv->next;
246b95ee612Skettenis }
247b95ee612Skettenis
24815fe2033Skettenis /* Signal EOI. */
24915fe2033Skettenis elroy_write32(&r->apic_eoi,
2500b8b2ce6Skettenis htole32((31 - APIC_INT_IRQ(ih)) & APIC_ENT0_VEC));
251b95ee612Skettenis
252b95ee612Skettenis return (claimed);
253b95ee612Skettenis }
254b95ee612Skettenis
25589a56fa7Skettenis /* Maximum number of supported interrupt routing entries. */
256a97e6b04Skettenis #define MAX_INT_TBL_SZ 16
25789a56fa7Skettenis
25889a56fa7Skettenis void
apic_get_int_tbl(struct elroy_softc * sc)25989a56fa7Skettenis apic_get_int_tbl(struct elroy_softc *sc)
26089a56fa7Skettenis {
26189a56fa7Skettenis struct pdc_pat_io_num int_tbl_sz PDC_ALIGNMENT;
26289a56fa7Skettenis struct pdc_pat_pci_rt int_tbl[MAX_INT_TBL_SZ] PDC_ALIGNMENT;
26389a56fa7Skettenis size_t size;
26489a56fa7Skettenis
26589a56fa7Skettenis /*
26689a56fa7Skettenis * XXX int_tbl should not be allocated on the stack, but we need a
26789a56fa7Skettenis * 1:1 mapping, and malloc doesn't provide that.
26889a56fa7Skettenis */
26989a56fa7Skettenis
27089a56fa7Skettenis if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SZ,
27189a56fa7Skettenis &int_tbl_sz, 0, 0, 0, 0, 0))
27289a56fa7Skettenis return;
27389a56fa7Skettenis
27489a56fa7Skettenis if (int_tbl_sz.num > MAX_INT_TBL_SZ)
27589a56fa7Skettenis panic("interrupt routing table too big (%d entries)",
27689a56fa7Skettenis int_tbl_sz.num);
27789a56fa7Skettenis
27889a56fa7Skettenis size = int_tbl_sz.num * sizeof(struct pdc_pat_pci_rt);
27989a56fa7Skettenis sc->sc_int_tbl_sz = int_tbl_sz.num;
28089a56fa7Skettenis sc->sc_int_tbl = malloc(size, M_DEVBUF, M_NOWAIT);
28189a56fa7Skettenis if (sc->sc_int_tbl == NULL)
28289a56fa7Skettenis return;
28389a56fa7Skettenis
28489a56fa7Skettenis if (pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
28589a56fa7Skettenis &int_tbl_sz, 0, &int_tbl, 0, 0, 0))
28689a56fa7Skettenis return;
28789a56fa7Skettenis
28889a56fa7Skettenis memcpy(sc->sc_int_tbl, int_tbl, size);
28989a56fa7Skettenis }
29089a56fa7Skettenis
29189a56fa7Skettenis u_int32_t
apic_get_int_ent0(struct elroy_softc * sc,int line)29289a56fa7Skettenis apic_get_int_ent0(struct elroy_softc *sc, int line)
29389a56fa7Skettenis {
2941a79cf7eSkettenis volatile struct elroy_regs *r = sc->sc_regs;
29589a56fa7Skettenis int trigger = MPS_INT(MPS_INTPO_DEF, MPS_INTTR_DEF);
29689a56fa7Skettenis u_int32_t ent0 = APIC_ENT0_LOW | APIC_ENT0_LEV;
2971a79cf7eSkettenis int bus, mpspo, mpstr;
29889a56fa7Skettenis int i;
29989a56fa7Skettenis
3001a79cf7eSkettenis bus = letoh32(elroy_read32(&r->busnum)) & 0xff;
30189a56fa7Skettenis for (i = 0; i < sc->sc_int_tbl_sz; i++) {
3021a79cf7eSkettenis if (bus == sc->sc_int_tbl[i].bus &&
3031a79cf7eSkettenis line == sc->sc_int_tbl[i].line)
30489a56fa7Skettenis trigger = sc->sc_int_tbl[i].trigger;
30589a56fa7Skettenis }
30689a56fa7Skettenis
30789a56fa7Skettenis mpspo = (trigger >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
30889a56fa7Skettenis mpstr = (trigger >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
30989a56fa7Skettenis
31089a56fa7Skettenis switch (mpspo) {
31189a56fa7Skettenis case MPS_INTPO_DEF:
31289a56fa7Skettenis break;
31389a56fa7Skettenis case MPS_INTPO_ACTHI:
31489a56fa7Skettenis ent0 &= ~APIC_ENT0_LOW;
31589a56fa7Skettenis break;
31689a56fa7Skettenis case MPS_INTPO_ACTLO:
31789a56fa7Skettenis ent0 |= APIC_ENT0_LOW;
31889a56fa7Skettenis break;
31989a56fa7Skettenis default:
32089a56fa7Skettenis panic("unknown MPS interrupt polarity %d", mpspo);
32189a56fa7Skettenis }
32289a56fa7Skettenis
32389a56fa7Skettenis switch(mpstr) {
32489a56fa7Skettenis case MPS_INTTR_DEF:
32589a56fa7Skettenis break;
32689a56fa7Skettenis case MPS_INTTR_LEVEL:
32789a56fa7Skettenis ent0 |= APIC_ENT0_LEV;
32889a56fa7Skettenis break;
32989a56fa7Skettenis case MPS_INTTR_EDGE:
33089a56fa7Skettenis ent0 &= ~APIC_ENT0_LEV;
33189a56fa7Skettenis break;
33289a56fa7Skettenis default:
33389a56fa7Skettenis panic("unknown MPS interrupt trigger %d", mpstr);
33489a56fa7Skettenis }
33589a56fa7Skettenis
33689a56fa7Skettenis return ent0;
33789a56fa7Skettenis }
33889a56fa7Skettenis
339b95ee612Skettenis #ifdef DEBUG
340b95ee612Skettenis void
apic_dump(struct elroy_softc * sc)341b95ee612Skettenis apic_dump(struct elroy_softc *sc)
342b95ee612Skettenis {
343b95ee612Skettenis int i;
344b95ee612Skettenis
345b95ee612Skettenis for (i = 0; i < sc->sc_nints; i++)
346b95ee612Skettenis printf("0x%04x 0x%04x\n", apic_read(sc->sc_regs, APIC_ENT0(i)),
347b95ee612Skettenis apic_read(sc->sc_regs, APIC_ENT1(i)));
348b95ee612Skettenis
3491a79cf7eSkettenis for (i = 0; i < sc->sc_int_tbl_sz; i++) {
3501a79cf7eSkettenis printf("type=%x ", sc->sc_int_tbl[i].type);
3511a79cf7eSkettenis printf("len=%d ", sc->sc_int_tbl[i].len);
3521a79cf7eSkettenis printf("itype=%d ", sc->sc_int_tbl[i].itype);
3531a79cf7eSkettenis printf("trigger=%x ", sc->sc_int_tbl[i].trigger);
3541a79cf7eSkettenis printf("pin=%x ", sc->sc_int_tbl[i].pin);
3551a79cf7eSkettenis printf("bus=%d ", sc->sc_int_tbl[i].bus);
3561a79cf7eSkettenis printf("line=%d ", sc->sc_int_tbl[i].line);
3571a79cf7eSkettenis printf("addr=%x\n", sc->sc_int_tbl[i].addr);
358b95ee612Skettenis }
359b95ee612Skettenis }
360b95ee612Skettenis #endif
361