summaryrefslogtreecommitdiff
path: root/linux/x86/i8259.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/x86/i8259.c')
-rw-r--r--linux/x86/i8259.c115
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