Skip to content

Commit

Permalink
KVM: PPC: Book3S HV: Convert ICS mutex lock to spin lock
Browse files Browse the repository at this point in the history
Replaces the ICS mutex lock with a spin lock since we will be porting
these routines to real mode. Note that we need to disable interrupts
before we take the lock in anticipation of the fact that on the guest
side, we are running in the context of a hard irq and interrupts are
disabled (EE bit off) when the lock is acquired. Again, because we
will be acquiring the lock in hypervisor real mode, we need to use
an arch_spinlock_t instead of a normal spinlock here as we want to
avoid running any lockdep code (which may not be safe to execute in
real mode).

Signed-off-by: Suresh Warrier <warrier@linux.vnet.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
  • Loading branch information
Suresh Warrier authored and Alexander Graf committed Apr 21, 2015
1 parent 878610f commit 34cb795
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 22 deletions.
68 changes: 47 additions & 21 deletions arch/powerpc/kvm/book3s_xics.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <asm/xics.h>
#include <asm/debug.h>
#include <asm/time.h>
#include <asm/spinlock.h>

#include <linux/debugfs.h>
#include <linux/seq_file.h>
Expand All @@ -39,7 +40,7 @@
* LOCKING
* =======
*
* Each ICS has a mutex protecting the information about the IRQ
* Each ICS has a spin lock protecting the information about the IRQ
* sources and avoiding simultaneous deliveries if the same interrupt.
*
* ICP operations are done via a single compare & swap transaction
Expand Down Expand Up @@ -109,7 +110,10 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
{
int i;

mutex_lock(&ics->lock);
unsigned long flags;

local_irq_save(flags);
arch_spin_lock(&ics->lock);

for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
struct ics_irq_state *state = &ics->irq_state[i];
Expand All @@ -120,21 +124,26 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
XICS_DBG("resend %#x prio %#x\n", state->number,
state->priority);

mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);
icp_deliver_irq(xics, icp, state->number);
mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);
}

mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);
}

static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
struct ics_irq_state *state,
u32 server, u32 priority, u32 saved_priority)
{
bool deliver;
unsigned long flags;

mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);

state->server = server;
state->priority = priority;
Expand All @@ -145,7 +154,8 @@ static bool write_xive(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
deliver = true;
}

mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);

return deliver;
}
Expand Down Expand Up @@ -186,6 +196,7 @@ int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority)
struct kvmppc_ics *ics;
struct ics_irq_state *state;
u16 src;
unsigned long flags;

if (!xics)
return -ENODEV;
Expand All @@ -195,10 +206,12 @@ int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority)
return -EINVAL;
state = &ics->irq_state[src];

mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);
*server = state->server;
*priority = state->priority;
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);

return 0;
}
Expand Down Expand Up @@ -365,6 +378,7 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
struct kvmppc_ics *ics;
u32 reject;
u16 src;
unsigned long flags;

/*
* This is used both for initial delivery of an interrupt and
Expand All @@ -391,7 +405,8 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
state = &ics->irq_state[src];

/* Get a lock on the ICS */
mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);

/* Get our server */
if (!icp || state->server != icp->server_num) {
Expand Down Expand Up @@ -434,7 +449,7 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
*
* Note that if successful, the new delivery might have itself
* rejected an interrupt that was "delivered" before we took the
* icp mutex.
* ics spin lock.
*
* In this case we do the whole sequence all over again for the
* new guy. We cannot assume that the rejected interrupt is less
Expand All @@ -448,7 +463,8 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
* Delivery was successful, did we reject somebody else ?
*/
if (reject && reject != XICS_IPI) {
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);
new_irq = reject;
goto again;
}
Expand All @@ -468,12 +484,14 @@ static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
*/
smp_mb();
if (!icp->state.need_resend) {
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);
goto again;
}
}
out:
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);
}

static void icp_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
Expand Down Expand Up @@ -880,6 +898,7 @@ static int xics_debug_show(struct seq_file *m, void *private)
struct kvm *kvm = xics->kvm;
struct kvm_vcpu *vcpu;
int icsid, i;
unsigned long flags;
unsigned long t_rm_kick_vcpu, t_rm_check_resend;
unsigned long t_rm_reject, t_rm_notify_eoi;

Expand Down Expand Up @@ -924,7 +943,8 @@ static int xics_debug_show(struct seq_file *m, void *private)
seq_printf(m, "=========\nICS state for ICS 0x%x\n=========\n",
icsid);

mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);

for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
struct ics_irq_state *irq = &ics->irq_state[i];
Expand All @@ -935,7 +955,8 @@ static int xics_debug_show(struct seq_file *m, void *private)
irq->resend, irq->masked_pending);

}
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);
}
return 0;
}
Expand Down Expand Up @@ -988,7 +1009,6 @@ static struct kvmppc_ics *kvmppc_xics_create_ics(struct kvm *kvm,
if (!ics)
goto out;

mutex_init(&ics->lock);
ics->icsid = icsid;

for (i = 0; i < KVMPPC_XICS_IRQ_PER_ICS; i++) {
Expand Down Expand Up @@ -1130,13 +1150,15 @@ static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr)
u64 __user *ubufp = (u64 __user *) addr;
u16 idx;
u64 val, prio;
unsigned long flags;

ics = kvmppc_xics_find_ics(xics, irq, &idx);
if (!ics)
return -ENOENT;

irqp = &ics->irq_state[idx];
mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);
ret = -ENOENT;
if (irqp->exists) {
val = irqp->server;
Expand All @@ -1152,7 +1174,8 @@ static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr)
val |= KVM_XICS_PENDING;
ret = 0;
}
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);

if (!ret && put_user(val, ubufp))
ret = -EFAULT;
Expand All @@ -1169,6 +1192,7 @@ static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr)
u64 val;
u8 prio;
u32 server;
unsigned long flags;

if (irq < KVMPPC_XICS_FIRST_IRQ || irq >= KVMPPC_XICS_NR_IRQS)
return -ENOENT;
Expand All @@ -1189,7 +1213,8 @@ static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr)
kvmppc_xics_find_server(xics->kvm, server) == NULL)
return -EINVAL;

mutex_lock(&ics->lock);
local_irq_save(flags);
arch_spin_lock(&ics->lock);
irqp->server = server;
irqp->saved_priority = prio;
if (val & KVM_XICS_MASKED)
Expand All @@ -1201,7 +1226,8 @@ static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr)
if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE))
irqp->asserted = 1;
irqp->exists = 1;
mutex_unlock(&ics->lock);
arch_spin_unlock(&ics->lock);
local_irq_restore(flags);

if (val & KVM_XICS_PENDING)
icp_deliver_irq(xics, NULL, irqp->number);
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/kvm/book3s_xics.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct kvmppc_icp {
};

struct kvmppc_ics {
struct mutex lock;
arch_spinlock_t lock;
u16 icsid;
struct ics_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS];
};
Expand Down

0 comments on commit 34cb795

Please sign in to comment.