Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 173469
b: refs/heads/master
c: 1ce7b03
h: refs/heads/master
i:
  173467: 1c35c13
v: v3
  • Loading branch information
Paul Mundt committed Nov 2, 2009
1 parent 57fc5ce commit ce4e775
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 2 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: 58ee987e2fd8acff6263d194d8fa43267cc8b1c9
refs/heads/master: 1ce7b039b5029ab698f9d64c0ad603794bc31ae7
84 changes: 83 additions & 1 deletion trunk/drivers/sh/intc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Shared interrupt handling code for IPR and INTC2 types of IRQs.
*
* Copyright (C) 2007, 2008 Magnus Damm
* Copyright (C) 2009 Paul Mundt
*
* Based on intc2.c and ipr.c
*
Expand All @@ -24,6 +25,7 @@
#include <linux/sysdev.h>
#include <linux/list.h>
#include <linux/topology.h>
#include <linux/bitmap.h>

#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
Expand Down Expand Up @@ -59,6 +61,20 @@ struct intc_desc_int {

static LIST_HEAD(intc_list);

/*
* The intc_irq_map provides a global map of bound IRQ vectors for a
* given platform. Allocation of IRQs are either static through the CPU
* vector map, or dynamic in the case of board mux vectors or MSI.
*
* As this is a central point for all IRQ controllers on the system,
* each of the available sources are mapped out here. This combined with
* sparseirq makes it quite trivial to keep the vector map tightly packed
* when dynamically creating IRQs, as well as tying in to otherwise
* unused irq_desc positions in the sparse array.
*/
static DECLARE_BITMAP(intc_irq_map, NR_IRQS);
static DEFINE_SPINLOCK(vector_lock);

#ifdef CONFIG_SMP
#define IS_SMP(x) x.smp
#define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
Expand Down Expand Up @@ -566,6 +582,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
struct intc_handle_int *hp;
unsigned int data[2], primary;

/*
* Register the IRQ position with the global IRQ map
*/
set_bit(irq, intc_irq_map);

/* Prefer single interrupt source bitmap over other combinations:
* 1. bitmap, single interrupt source
* 2. priority, single interrupt source
Expand Down Expand Up @@ -844,5 +865,66 @@ static int __init register_intc_sysdevs(void)

return error;
}

device_initcall(register_intc_sysdevs);

/*
* Dynamic IRQ allocation and deallocation
*/
static unsigned int create_irq_on_node(unsigned int irq_want, int node)
{
unsigned int irq = 0, new;
unsigned long flags;
struct irq_desc *desc;

spin_lock_irqsave(&vector_lock, flags);

/*
* First try the wanted IRQ, then scan.
*/
if (test_and_set_bit(irq_want, intc_irq_map)) {
new = find_first_zero_bit(intc_irq_map, nr_irqs);
if (unlikely(new == nr_irqs))
goto out_unlock;

desc = irq_to_desc_alloc_node(new, node);
if (unlikely(!desc)) {
pr_info("can't get irq_desc for %d\n", new);
goto out_unlock;
}

desc = move_irq_desc(desc, node);
__set_bit(new, intc_irq_map);
irq = new;
}

out_unlock:
spin_unlock_irqrestore(&vector_lock, flags);

if (irq > 0)
dynamic_irq_init(irq);

return irq;
}

int create_irq(void)
{
int nid = cpu_to_node(smp_processor_id());
int irq;

irq = create_irq_on_node(NR_IRQS_LEGACY, nid);
if (irq == 0)
irq = -1;

return irq;
}

void destroy_irq(unsigned int irq)
{
unsigned long flags;

dynamic_irq_cleanup(irq);

spin_lock_irqsave(&vector_lock, flags);
__clear_bit(irq, intc_irq_map);
spin_unlock_irqrestore(&vector_lock, flags);
}

0 comments on commit ce4e775

Please sign in to comment.