Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 81190
b: refs/heads/master
c: c809056
h: refs/heads/master
v: v3
  • Loading branch information
Valentine Barshak authored and Josh Boyer committed Dec 23, 2007
1 parent a848511 commit 89af7fc
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 63 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 309ae1a363181a6b290b5bdfaee81123431f8644
refs/heads/master: c80905637efb4af6e58da91fae89ffcb2cf8f1aa
81 changes: 19 additions & 62 deletions trunk/arch/powerpc/sysdev/uic.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,19 @@ struct uic {

static void uic_unmask_irq(unsigned int virq)
{
struct irq_desc *desc = get_irq_desc(virq);
struct uic *uic = get_irq_chip_data(virq);
unsigned int src = uic_irq_to_hw(virq);
unsigned long flags;
u32 er;
u32 er, sr;

sr = 1 << (31-src);
spin_lock_irqsave(&uic->lock, flags);
/* ack level-triggered interrupts here */
if (desc->status & IRQ_LEVEL)
mtdcr(uic->dcrbase + UIC_SR, sr);
er = mfdcr(uic->dcrbase + UIC_ER);
er |= 1 << (31 - src);
er |= sr;
mtdcr(uic->dcrbase + UIC_ER, er);
spin_unlock_irqrestore(&uic->lock, flags);
}
Expand Down Expand Up @@ -99,6 +104,7 @@ static void uic_ack_irq(unsigned int virq)

static void uic_mask_ack_irq(unsigned int virq)
{
struct irq_desc *desc = get_irq_desc(virq);
struct uic *uic = get_irq_chip_data(virq);
unsigned int src = uic_irq_to_hw(virq);
unsigned long flags;
Expand All @@ -109,7 +115,16 @@ static void uic_mask_ack_irq(unsigned int virq)
er = mfdcr(uic->dcrbase + UIC_ER);
er &= ~sr;
mtdcr(uic->dcrbase + UIC_ER, er);
mtdcr(uic->dcrbase + UIC_SR, sr);
/* On the UIC, acking (i.e. clearing the SR bit)
* a level irq will have no effect if the interrupt
* is still asserted by the device, even if
* the interrupt is already masked. Therefore
* we only ack the egde interrupts here, while
* level interrupts are ack'ed after the actual
* isr call in the uic_unmask_irq()
*/
if (!(desc->status & IRQ_LEVEL))
mtdcr(uic->dcrbase + UIC_SR, sr);
spin_unlock_irqrestore(&uic->lock, flags);
}

Expand Down Expand Up @@ -173,64 +188,6 @@ static struct irq_chip uic_irq_chip = {
.set_type = uic_set_irq_type,
};

/**
* handle_uic_irq - irq flow handler for UIC
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* This is modified version of the generic handle_level_irq() suitable
* for the UIC. On the UIC, acking (i.e. clearing the SR bit) a level
* irq will have no effect if the interrupt is still asserted by the
* device, even if the interrupt is already masked. Therefore, unlike
* the standard handle_level_irq(), we must ack the interrupt *after*
* invoking the ISR (which should have de-asserted the interrupt in
* the external source). For edge interrupts we ack at the beginning
* instead of the end, to keep the window in which we can miss an
* interrupt as small as possible.
*/
void fastcall handle_uic_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned int cpu = smp_processor_id();
struct irqaction *action;
irqreturn_t action_ret;

spin_lock(&desc->lock);
if (desc->status & IRQ_LEVEL)
desc->chip->mask(irq);
else
desc->chip->mask_ack(irq);

if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++;

/*
* If its disabled or no action available
* keep it masked and get out of here
*/
action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
desc->status |= IRQ_PENDING;
goto out_unlock;
}

desc->status |= IRQ_INPROGRESS;
desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);

action_ret = handle_IRQ_event(irq, action);

spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
if (desc->status & IRQ_LEVEL)
desc->chip->ack(irq);
if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc->chip->unmask(irq);
out_unlock:
spin_unlock(&desc->lock);
}

static int uic_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
Expand All @@ -239,7 +196,7 @@ static int uic_host_map(struct irq_host *h, unsigned int virq,
set_irq_chip_data(virq, uic);
/* Despite the name, handle_level_irq() works for both level
* and edge irqs on UIC. FIXME: check this is correct */
set_irq_chip_and_handler(virq, &uic_irq_chip, handle_uic_irq);
set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);

/* Set default irq type */
set_irq_type(virq, IRQ_TYPE_NONE);
Expand Down

0 comments on commit 89af7fc

Please sign in to comment.