diff options
Diffstat (limited to 'linux/x86/i8259.c')
-rw-r--r-- | linux/x86/i8259.c | 115 |
1 files changed, 34 insertions, 81 deletions
diff --git a/linux/x86/i8259.c b/linux/x86/i8259.c index d316fc6..76c25b5 100644 --- a/linux/x86/i8259.c +++ b/linux/x86/i8259.c @@ -43,7 +43,6 @@ * * Copyright (c) 2003-2004 Fabrice Bellard * Copyright (c) 2007 Intel Corporation - * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -74,44 +73,6 @@ #include <linux/kvm_host.h> #include "trace.h" -static void pic_irq_request(struct kvm *kvm, int level); - -static void pic_lock(struct kvm_pic *s) - __acquires(&s->lock) -{ - spin_lock(&s->lock); -} - -static void pic_unlock(struct kvm_pic *s) - __releases(&s->lock) -{ - bool wakeup = s->wakeup_needed; - struct kvm_vcpu *vcpu, *found = NULL; - int i; - - s->wakeup_needed = false; - - spin_unlock(&s->lock); - - if (wakeup) { - kvm_for_each_vcpu(i, vcpu, s->kvm) { - if (kvm_apic_accept_pic_intr(vcpu)) { - found = vcpu; - break; - } - } - - if (!found) - found = s->kvm->bsp_vcpu; - - if (!found) - return; - - kvm_make_request(KVM_REQ_EVENT, found); - kvm_vcpu_kick(found); - } -} - static void pic_clear_isr(struct kvm_kpic_state *s, int irq) { s->isr &= ~(1 << irq); @@ -124,19 +85,19 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq) * Other interrupt may be delivered to PIC while lock is dropped but * it should be safe since PIC state is already updated at this stage. */ - pic_unlock(s->pics_state); + raw_spin_unlock(&s->pics_state->lock); kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq); - pic_lock(s->pics_state); + raw_spin_lock(&s->pics_state->lock); } void kvm_pic_clear_isr_ack(struct kvm *kvm) { struct kvm_pic *s = pic_irqchip(kvm); - pic_lock(s); + raw_spin_lock(&s->lock); s->pics[0].isr_ack = 0xff; s->pics[1].isr_ack = 0xff; - pic_unlock(s); + raw_spin_unlock(&s->lock); } /* @@ -229,14 +190,17 @@ static void pic_update_irq(struct kvm_pic *s) pic_set_irq1(&s->pics[0], 2, 0); } irq = pic_get_irq(&s->pics[0]); - pic_irq_request(s->kvm, irq >= 0); + if (irq >= 0) + s->irq_request(s->irq_request_opaque, 1); + else + s->irq_request(s->irq_request_opaque, 0); } void kvm_pic_update_irq(struct kvm_pic *s) { - pic_lock(s); + raw_spin_lock(&s->lock); pic_update_irq(s); - pic_unlock(s); + raw_spin_unlock(&s->lock); } int kvm_pic_set_irq(void *opaque, int irq, int level) @@ -244,14 +208,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level) struct kvm_pic *s = opaque; int ret = -1; - pic_lock(s); + raw_spin_lock(&s->lock); if (irq >= 0 && irq < PIC_NUM_PINS) { ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); pic_update_irq(s); trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, s->pics[irq >> 3].imr, ret == 0); } - pic_unlock(s); + raw_spin_unlock(&s->lock); return ret; } @@ -281,7 +245,7 @@ int kvm_pic_read_irq(struct kvm *kvm) int irq, irq2, intno; struct kvm_pic *s = pic_irqchip(kvm); - pic_lock(s); + raw_spin_lock(&s->lock); irq = pic_get_irq(&s->pics[0]); if (irq >= 0) { pic_intack(&s->pics[0], irq); @@ -306,7 +270,7 @@ int kvm_pic_read_irq(struct kvm *kvm) intno = s->pics[0].irq_base + irq; } pic_update_irq(s); - pic_unlock(s); + raw_spin_unlock(&s->lock); return intno; } @@ -314,7 +278,8 @@ int kvm_pic_read_irq(struct kvm *kvm) void kvm_pic_reset(struct kvm_kpic_state *s) { int irq; - struct kvm_vcpu *vcpu0 = s->pics_state->kvm->bsp_vcpu; + struct kvm *kvm = s->pics_state->irq_request_opaque; + struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu; u8 irr = s->irr, isr = s->imr; s->last_irr = 0; @@ -349,17 +314,14 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) addr &= 1; if (addr == 0) { if (val & 0x10) { - s->init4 = val & 1; - s->last_irr = 0; - s->imr = 0; - s->priority_add = 0; - s->special_mask = 0; - s->read_reg_select = 0; - if (!s->init4) { - s->special_fully_nested_mode = 0; - s->auto_eoi = 0; - } + kvm_pic_reset(s); /* init */ + /* + * deassert a pending interrupt + */ + s->pics_state->irq_request(s->pics_state-> + irq_request_opaque, 0); s->init_state = 1; + s->init4 = val & 1; if (val & 0x02) printk(KERN_ERR "single mode not supported"); if (val & 0x08) @@ -411,20 +373,10 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) } } else switch (s->init_state) { - case 0: { /* normal mode */ - u8 imr_diff = s->imr ^ val, - off = (s == &s->pics_state->pics[0]) ? 0 : 8; + case 0: /* normal mode */ s->imr = val; - for (irq = 0; irq < PIC_NUM_PINS/2; irq++) - if (imr_diff & (1 << irq)) - kvm_fire_mask_notifiers( - s->pics_state->kvm, - SELECT_PIC(irq + off), - irq + off, - !!(s->imr & (1 << irq))); pic_update_irq(s->pics_state); break; - } case 1: s->irq_base = val & 0xf8; s->init_state = 2; @@ -532,7 +484,7 @@ static int picdev_write(struct kvm_io_device *this, printk(KERN_ERR "PIC: non byte write\n"); return 0; } - pic_lock(s); + raw_spin_lock(&s->lock); switch (addr) { case 0x20: case 0x21: @@ -545,7 +497,7 @@ static int picdev_write(struct kvm_io_device *this, elcr_ioport_write(&s->pics[addr & 1], addr, data); break; } - pic_unlock(s); + raw_spin_unlock(&s->lock); return 0; } @@ -562,7 +514,7 @@ static int picdev_read(struct kvm_io_device *this, printk(KERN_ERR "PIC: non byte read\n"); return 0; } - pic_lock(s); + raw_spin_lock(&s->lock); switch (addr) { case 0x20: case 0x21: @@ -576,15 +528,16 @@ static int picdev_read(struct kvm_io_device *this, break; } *(unsigned char *)val = data; - pic_unlock(s); + raw_spin_unlock(&s->lock); return 0; } /* * callback when PIC0 irq status changed */ -static void pic_irq_request(struct kvm *kvm, int level) +static void pic_irq_request(void *opaque, int level) { + struct kvm *kvm = opaque; struct kvm_vcpu *vcpu = kvm->bsp_vcpu; struct kvm_pic *s = pic_irqchip(kvm); int irq = pic_get_irq(&s->pics[0]); @@ -592,7 +545,7 @@ static void pic_irq_request(struct kvm *kvm, int level) s->output = level; if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { s->pics[0].isr_ack &= ~(1 << irq); - s->wakeup_needed = true; + kvm_vcpu_kick(vcpu); } } @@ -609,14 +562,14 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); if (!s) return NULL; - spin_lock_init(&s->lock); + raw_spin_lock_init(&s->lock); s->kvm = kvm; s->pics[0].elcr_mask = 0xf8; s->pics[1].elcr_mask = 0xde; + s->irq_request = pic_irq_request; + s->irq_request_opaque = kvm; s->pics[0].pics_state = s; s->pics[1].pics_state = s; - s->pics[0].isr_ack = 0xff; - s->pics[1].isr_ack = 0xff; /* * Initialize PIO device |