[BACK]Return to xen_intr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / xen / x86

Annotation of src/sys/arch/xen/x86/xen_intr.c, Revision 1.11

1.11    ! cherry      1: /*     $NetBSD: xen_intr.c,v 1.10 2018/12/24 14:55:42 cherry Exp $     */
1.2       bouyer      2:
                      3: /*-
                      4:  * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Charles M. Hannum, and by Jason R. Thorpe.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/cdefs.h>
1.11    ! cherry     33: __KERNEL_RCSID(0, "$NetBSD: xen_intr.c,v 1.10 2018/12/24 14:55:42 cherry Exp $");
1.2       bouyer     34:
                     35: #include <sys/param.h>
1.10      cherry     36: #include <sys/kernel.h>
                     37: #include <sys/kmem.h>
                     38:
1.11    ! cherry     39: #include <sys/cpu.h>
        !            40:
1.10      cherry     41: #include <xen/evtchn.h>
1.2       bouyer     42:
                     43: #include <machine/cpu.h>
                     44: #include <machine/intr.h>
                     45:
1.11    ! cherry     46: #include "acpica.h"
        !            47: #include "ioapic.h"
        !            48: #include "lapic.h"
        !            49: #include "pci.h"
        !            50:
        !            51: #if NACPICA > 0
        !            52: #include <dev/acpi/acpivar.h>
        !            53: #endif
        !            54:
        !            55: #if NIOAPIC > 0 || NACPICA > 0
        !            56: #include <machine/i82093var.h>
        !            57: #endif
        !            58:
        !            59: #if NLAPIC > 0
        !            60: #include <machine/i82489var.h>
        !            61: #endif
        !            62:
        !            63: #if NPCI > 0
        !            64: #include <dev/pci/ppbreg.h>
        !            65: #endif
        !            66:
        !            67: void xen_disable_intr(void);
        !            68: void xen_enable_intr(void);
        !            69: u_long xen_read_psl(void);
        !            70: void xen_write_psl(u_long);
        !            71:
1.2       bouyer     72: /*
                     73:  * Add a mask to cpl, and return the old value of cpl.
                     74:  */
                     75: int
                     76: splraise(int nlevel)
                     77: {
                     78:        int olevel;
                     79:        struct cpu_info *ci = curcpu();
                     80:
                     81:        olevel = ci->ci_ilevel;
                     82:        if (nlevel > olevel)
                     83:                ci->ci_ilevel = nlevel;
                     84:        __insn_barrier();
                     85:        return (olevel);
                     86: }
                     87:
                     88: /*
                     89:  * Restore a value to cpl (unmasking interrupts).  If any unmasked
                     90:  * interrupts are pending, call Xspllower() to process them.
                     91:  */
                     92: void
                     93: spllower(int nlevel)
                     94: {
                     95:        struct cpu_info *ci = curcpu();
1.11    ! cherry     96:        uint32_t xmask;
1.2       bouyer     97:        u_long psl;
                     98:
1.8       bouyer     99:        if (ci->ci_ilevel <= nlevel)
                    100:                return;
                    101:
1.2       bouyer    102:        __insn_barrier();
                    103:
1.11    ! cherry    104:        xmask = XUNMASK(ci, nlevel);
        !           105:        psl = xen_read_psl();
        !           106:        xen_disable_intr();
        !           107:        if (ci->ci_xpending & xmask) {
1.7       bouyer    108:                KASSERT(psl == 0);
1.2       bouyer    109:                Xspllower(nlevel);
                    110:                /* Xspllower does enable_intr() */
                    111:        } else {
                    112:                ci->ci_ilevel = nlevel;
1.11    ! cherry    113:                xen_write_psl(psl);
1.2       bouyer    114:        }
                    115: }
                    116:
                    117: void
1.11    ! cherry    118: xen_disable_intr(void)
1.2       bouyer    119: {
                    120:        __cli();
                    121: }
                    122:
                    123: void
1.11    ! cherry    124: xen_enable_intr(void)
1.2       bouyer    125: {
                    126:        __sti();
                    127: }
                    128:
                    129: u_long
1.11    ! cherry    130: xen_read_psl(void)
1.2       bouyer    131: {
                    132:
1.4       cegger    133:        return (curcpu()->ci_vcpu->evtchn_upcall_mask);
1.2       bouyer    134: }
                    135:
                    136: void
1.11    ! cherry    137: xen_write_psl(u_long psl)
1.2       bouyer    138: {
1.4       cegger    139:        struct cpu_info *ci = curcpu();
1.2       bouyer    140:
1.4       cegger    141:        ci->ci_vcpu->evtchn_upcall_mask = psl;
1.9       jym       142:        xen_rmb();
1.4       cegger    143:        if (ci->ci_vcpu->evtchn_upcall_pending && psl == 0) {
1.2       bouyer    144:                hypervisor_force_callback();
                    145:        }
                    146: }
1.10      cherry    147:
                    148: void *
                    149: xen_intr_establish(int legacy_irq, struct pic *pic, int pin,
                    150:     int type, int level, int (*handler)(void *), void *arg,
                    151:     bool known_mpsafe)
                    152: {
                    153:
                    154:        return xen_intr_establish_xname(legacy_irq, pic, pin, type, level,
                    155:            handler, arg, known_mpsafe, "XEN");
                    156: }
                    157:
                    158: void *
                    159: xen_intr_establish_xname(int legacy_irq, struct pic *pic, int pin,
                    160:     int type, int level, int (*handler)(void *), void *arg,
                    161:     bool known_mpsafe, const char *xname)
                    162: {
                    163:        const char *intrstr;
                    164:        char intrstr_buf[INTRIDBUF];
                    165:
                    166:        if (pic->pic_type == PIC_XEN) {
                    167:                struct intrhand *rih;
                    168:
                    169:                /*
                    170:                 * event_set_handler interprets `level != IPL_VM' to
                    171:                 * mean MP-safe, so we require the caller to match that
                    172:                 * for the moment.
                    173:                 */
                    174:                KASSERT(known_mpsafe == (level != IPL_VM));
                    175:
                    176:                intrstr = intr_create_intrid(legacy_irq, pic, pin, intrstr_buf,
                    177:                    sizeof(intrstr_buf));
                    178:
                    179:                event_set_handler(pin, handler, arg, level, intrstr, xname);
                    180:
                    181:                rih = kmem_zalloc(sizeof(*rih), cold ? KM_NOSLEEP : KM_SLEEP);
                    182:                if (rih == NULL) {
                    183:                        printf("%s: can't allocate handler info\n", __func__);
                    184:                        return NULL;
                    185:                }
                    186:
                    187:                /*
                    188:                 * XXX:
                    189:                 * This is just a copy for API conformance.
                    190:                 * The real ih is lost in the innards of
                    191:                 * event_set_handler(); where the details of
                    192:                 * biglock_wrapper etc are taken care of.
                    193:                 * All that goes away when we nuke event_set_handler()
                    194:                 * et. al. and unify with x86/intr.c
                    195:                 */
                    196:                rih->ih_pin = pin; /* port */
                    197:                rih->ih_fun = rih->ih_realfun = handler;
                    198:                rih->ih_arg = rih->ih_realarg = arg;
                    199:                rih->pic_type = pic->pic_type;
                    200:                return rih;
                    201:        }       /* Else we assume pintr */
                    202:
                    203: #if NPCI > 0 || NISA > 0
                    204:        struct pintrhand *pih;
                    205:        int gsi;
                    206:        int vector, evtchn;
                    207:
                    208:        KASSERTMSG(legacy_irq == -1 || (0 <= legacy_irq && legacy_irq < NUM_XEN_IRQS),
                    209:            "bad legacy IRQ value: %d", legacy_irq);
                    210:        KASSERTMSG(!(legacy_irq == -1 && pic == &i8259_pic),
                    211:            "non-legacy IRQon i8259 ");
                    212:
                    213:        gsi = xen_pic_to_gsi(pic, pin);
                    214:
                    215:        intrstr = intr_create_intrid(gsi, pic, pin, intrstr_buf,
                    216:            sizeof(intrstr_buf));
                    217:
                    218:        vector = xen_vec_alloc(gsi);
                    219:
                    220:        if (irq2port[gsi] == 0) {
                    221:                extern struct cpu_info phycpu_info_primary; /* XXX */
                    222:                struct cpu_info *ci = &phycpu_info_primary;
                    223:
                    224:                pic->pic_addroute(pic, ci, pin, vector, type);
                    225:
                    226:                evtchn = bind_pirq_to_evtch(gsi);
                    227:                KASSERT(evtchn > 0);
                    228:                KASSERT(evtchn < NR_EVENT_CHANNELS);
                    229:                irq2port[gsi] = evtchn + 1;
                    230:                xen_atomic_set_bit(&ci->ci_evtmask[0], evtchn);
                    231:        } else {
                    232:                /*
                    233:                 * Shared interrupt - we can't rebind.
                    234:                 * The port is shared instead.
                    235:                 */
                    236:                evtchn = irq2port[gsi] - 1;
                    237:        }
                    238:
                    239:        pih = pirq_establish(gsi, evtchn, handler, arg, level,
                    240:                             intrstr, xname);
                    241:        pih->pic_type = pic->pic_type;
                    242:        return pih;
                    243: #endif /* NPCI > 0 || NISA > 0 */
                    244:
                    245:        /* FALLTHROUGH */
                    246:        return NULL;
                    247: }
                    248:
                    249: /*
                    250:  * Deregister an interrupt handler.
                    251:  */
                    252: void
                    253: xen_intr_disestablish(struct intrhand *ih)
                    254: {
                    255:
                    256:        if (ih->pic_type == PIC_XEN) {
                    257:                event_remove_handler(ih->ih_pin, ih->ih_realfun,
                    258:                    ih->ih_realarg);
                    259:                kmem_free(ih, sizeof(*ih));
                    260:                return;
                    261:        }
                    262: #if defined(DOM0OPS)
                    263:        /*
                    264:         * Cache state, to prevent a use after free situation with
                    265:         * ih.
                    266:         */
                    267:
                    268:        struct pintrhand *pih = (struct pintrhand *)ih;
                    269:
                    270:        int pirq = pih->pirq;
                    271:        int port = pih->evtch;
                    272:        KASSERT(irq2port[pirq] != 0);
                    273:
                    274:        pirq_disestablish(pih);
                    275:
                    276:        if (evtsource[port] == NULL) {
                    277:                        /*
                    278:                         * Last handler was removed by
                    279:                         * event_remove_handler().
                    280:                         *
                    281:                         * We can safely unbind the pirq now.
                    282:                         */
                    283:
                    284:                        port = unbind_pirq_from_evtch(pirq);
                    285:                        KASSERT(port == pih->evtch);
                    286:                        irq2port[pirq] = 0;
                    287:        }
                    288: #endif
                    289:        return;
                    290: }
                    291:
1.11    ! cherry    292: /* MI interface for kern_cpu.c */
        !           293: void xen_cpu_intr_redistribute(void);
        !           294:
        !           295: void
        !           296: xen_cpu_intr_redistribute(void)
        !           297: {
        !           298:        KASSERT(mutex_owned(&cpu_lock));
        !           299:        KASSERT(mp_online);
        !           300:
        !           301:        return;
        !           302: }
        !           303:
        !           304: /* MD - called by x86/cpu.c */
        !           305: void
        !           306: cpu_intr_init(struct cpu_info *ci)
        !           307: {
        !           308:        int i; /* XXX: duplicate */
        !           309:
        !           310:        ci->ci_xunmask[0] = 0xfffffffe;
        !           311:        for (i = 1; i < NIPL; i++)
        !           312:                ci->ci_xunmask[i] = ci->ci_xunmask[i - 1] & ~(1 << i);
        !           313:
        !           314: #if defined(INTRSTACKSIZE)
        !           315:        vaddr_t istack;
        !           316:
        !           317:        /*
        !           318:         * If the red zone is activated, protect both the top and
        !           319:         * the bottom of the stack with an unmapped page.
        !           320:         */
        !           321:        istack = uvm_km_alloc(kernel_map,
        !           322:            INTRSTACKSIZE + redzone_const_or_zero(2 * PAGE_SIZE), 0,
        !           323:            UVM_KMF_WIRED|UVM_KMF_ZERO);
        !           324:        if (redzone_const_or_false(true)) {
        !           325:                pmap_kremove(istack, PAGE_SIZE);
        !           326:                pmap_kremove(istack + INTRSTACKSIZE + PAGE_SIZE, PAGE_SIZE);
        !           327:                pmap_update(pmap_kernel());
        !           328:        }
        !           329:
        !           330:        /*
        !           331:         * 33 used to be 1.  Arbitrarily reserve 32 more register_t's
        !           332:         * of space for ddb(4) to examine some subroutine arguments
        !           333:         * and to hunt for the next stack frame.
        !           334:         */
        !           335:        ci->ci_intrstack = (char *)istack + redzone_const_or_zero(PAGE_SIZE) +
        !           336:            INTRSTACKSIZE - 33 * sizeof(register_t);
        !           337: #endif
        !           338:
        !           339:        ci->ci_idepth = -1;
        !           340: }
        !           341:
        !           342: /*
        !           343:  * Everything below from here is duplicated from x86/intr.c
        !           344:  * When intr.c and xen_intr.c are unified, these will need to be
        !           345:  * merged.
        !           346:  */
        !           347:
        !           348: u_int xen_cpu_intr_count(struct cpu_info *ci);
        !           349:
        !           350: u_int
        !           351: xen_cpu_intr_count(struct cpu_info *ci)
        !           352: {
        !           353:
        !           354:        KASSERT(ci->ci_nintrhand >= 0);
        !           355:
        !           356:        return ci->ci_nintrhand;
        !           357: }
        !           358:
        !           359: static const char *
        !           360: xen_intr_string(int port, char *buf, size_t len, struct pic *pic)
        !           361: {
        !           362:        KASSERT(pic->pic_type == PIC_XEN);
        !           363:
        !           364:        KASSERT(port >= 0);
        !           365:        KASSERT(port < NR_EVENT_CHANNELS);
        !           366:
        !           367:        snprintf(buf, len, "%s channel %d", pic->pic_name, port);
        !           368:
        !           369:        return buf;
        !           370: }
        !           371:
        !           372: static const char *
        !           373: legacy_intr_string(int ih, char *buf, size_t len, struct pic *pic)
        !           374: {
        !           375:        int legacy_irq;
        !           376:
        !           377:        KASSERT(pic->pic_type == PIC_I8259);
        !           378: #if NLAPIC > 0
        !           379:        KASSERT(APIC_IRQ_ISLEGACY(ih));
        !           380:
        !           381:        legacy_irq = APIC_IRQ_LEGACY_IRQ(ih);
        !           382: #else
        !           383:        legacy_irq = ih;
        !           384: #endif
        !           385:        KASSERT(legacy_irq >= 0 && legacy_irq < 16);
        !           386:
        !           387:        snprintf(buf, len, "%s pin %d", pic->pic_name, legacy_irq);
        !           388:
        !           389:        return buf;
        !           390: }
        !           391:
        !           392: const char *
        !           393: intr_string(intr_handle_t ih, char *buf, size_t len)
        !           394: {
        !           395: #if NIOAPIC > 0
        !           396:        struct ioapic_softc *pic;
        !           397: #endif
        !           398:
        !           399:        if (ih == 0)
        !           400:                panic("%s: bogus handle 0x%" PRIx64, __func__, ih);
        !           401:
        !           402: #if NIOAPIC > 0
        !           403:        if (ih & APIC_INT_VIA_APIC) {
        !           404:                pic = ioapic_find(APIC_IRQ_APIC(ih));
        !           405:                if (pic != NULL) {
        !           406:                        snprintf(buf, len, "%s pin %d",
        !           407:                            device_xname(pic->sc_dev), APIC_IRQ_PIN(ih));
        !           408:                } else {
        !           409:                        snprintf(buf, len,
        !           410:                            "apic %d int %d (irq %d)",
        !           411:                            APIC_IRQ_APIC(ih),
        !           412:                            APIC_IRQ_PIN(ih),
        !           413:                            APIC_IRQ_LEGACY_IRQ(ih));
        !           414:                }
        !           415:        } else
        !           416:                snprintf(buf, len, "irq %d", APIC_IRQ_LEGACY_IRQ(ih));
        !           417:
        !           418: #elif NLAPIC > 0
        !           419:        snprintf(buf, len, "irq %d" APIC_IRQ_LEGACY_IRQ(ih));
        !           420: #else
        !           421:        snprintf(buf, len, "irq %d", (int) ih);
        !           422: #endif
        !           423:        return buf;
        !           424:
        !           425: }
        !           426:
        !           427: /*
        !           428:  * Create an interrupt id such as "ioapic0 pin 9". This interrupt id is used
        !           429:  * by MI code and intrctl(8).
        !           430:  */
        !           431: const char *
        !           432: intr_create_intrid(int legacy_irq, struct pic *pic, int pin, char *buf, size_t len)
        !           433: {
        !           434:        int ih = 0;
        !           435:
        !           436: #if NPCI > 0
        !           437: #if defined(__HAVE_PCI_MSI_MSIX)
        !           438:        if ((pic->pic_type == PIC_MSI) || (pic->pic_type == PIC_MSIX)) {
        !           439:                uint64_t pih;
        !           440:                int dev, vec;
        !           441:
        !           442:                dev = msipic_get_devid(pic);
        !           443:                vec = pin;
        !           444:                pih = __SHIFTIN((uint64_t)dev, MSI_INT_DEV_MASK)
        !           445:                        | __SHIFTIN((uint64_t)vec, MSI_INT_VEC_MASK)
        !           446:                        | APIC_INT_VIA_MSI;
        !           447:                if (pic->pic_type == PIC_MSI)
        !           448:                        MSI_INT_MAKE_MSI(pih);
        !           449:                else if (pic->pic_type == PIC_MSIX)
        !           450:                        MSI_INT_MAKE_MSIX(pih);
        !           451:
        !           452:                return x86_pci_msi_string(NULL, pih, buf, len);
        !           453:        }
        !           454: #endif /* __HAVE_PCI_MSI_MSIX */
        !           455: #endif
        !           456:
        !           457:        if (pic->pic_type == PIC_XEN) {
        !           458:                ih = pin;       /* Port == pin */
        !           459:                return xen_intr_string(pin, buf, len, pic);
        !           460:        }
        !           461:
        !           462:        /*
        !           463:         * If the device is pci, "legacy_irq" is alway -1. Least 8 bit of "ih"
        !           464:         * is only used in intr_string() to show the irq number.
        !           465:         * If the device is "legacy"(such as floppy), it should not use
        !           466:         * intr_string().
        !           467:         */
        !           468:        if (pic->pic_type == PIC_I8259) {
        !           469:                ih = legacy_irq;
        !           470:                return legacy_intr_string(ih, buf, len, pic);
        !           471:        }
        !           472:
        !           473: #if NIOAPIC > 0 || NACPICA > 0
        !           474:        ih = ((pic->pic_apicid << APIC_INT_APIC_SHIFT) & APIC_INT_APIC_MASK)
        !           475:            | ((pin << APIC_INT_PIN_SHIFT) & APIC_INT_PIN_MASK);
        !           476:        if (pic->pic_type == PIC_IOAPIC) {
        !           477:                ih |= APIC_INT_VIA_APIC;
        !           478:        }
        !           479:        ih |= pin;
        !           480:        return intr_string(ih, buf, len);
        !           481: #endif
        !           482:
        !           483:        return NULL; /* No pic found! */
        !           484: }
        !           485:
        !           486: __weak_alias(x86_disable_intr, xen_disable_intr);
        !           487: __weak_alias(x86_enable_intr, xen_enable_intr);
        !           488: __weak_alias(x86_read_psl, xen_read_psl);
        !           489: __weak_alias(x86_write_psl, xen_write_psl);
        !           490:
1.10      cherry    491: __weak_alias(intr_establish, xen_intr_establish);
                    492: __weak_alias(intr_establish_xname, xen_intr_establish_xname);
                    493: __weak_alias(intr_disestablish, xen_intr_disestablish);
1.11    ! cherry    494: __weak_alias(cpu_intr_redistribute, xen_cpu_intr_redistribute);
        !           495: __weak_alias(cpu_intr_count, xen_cpu_intr_count);
        !           496:

CVSweb <webmaster@jp.NetBSD.org>