Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 291906
b: refs/heads/master
c: 1bc04f2
h: refs/heads/master
v: v3
  • Loading branch information
Grant Likely committed Feb 16, 2012
1 parent cf7bc0f commit bb07e0d
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 39 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: a8db8cf0d894df5f1dcfd4bce9894e0dbcc01c96
refs/heads/master: 1bc04f2cf8c2a1feadbd994f50c40bb145bf2989
3 changes: 0 additions & 3 deletions trunk/arch/powerpc/include/asm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ extern atomic_t ppc_n_lost_interrupts;
/* Total number of virq in the platform */
#define NR_IRQS CONFIG_NR_IRQS

/* Number of irqs reserved for the legacy controller */
#define NUM_ISA_INTERRUPTS 16

/* Same thing, used by the generic IRQ code */
#define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS

Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/sysdev/i8259.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr)
raw_spin_unlock_irqrestore(&i8259_lock, flags);

/* create a legacy host */
i8259_host = irq_domain_add_legacy(node, &i8259_host_ops, NULL);
i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL);
if (i8259_host == NULL) {
printk(KERN_ERR "i8259: failed to allocate irq host !\n");
return;
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/sysdev/tsi108_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ void __init tsi108_pci_int_init(struct device_node *node)
{
DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");

pci_irq_host = irq_domain_add_legacy(node, &pci_irq_domain_ops, NULL);
pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL);
if (pci_irq_host == NULL) {
printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
return;
Expand Down
20 changes: 19 additions & 1 deletion trunk/include/linux/irqdomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ struct device_node;
struct irq_domain;
struct of_device_id;

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

/* This type is the placeholder for a hardware interrupt number. It has to
* be big enough to enclose whatever representation is used by a given
* platform.
Expand Down Expand Up @@ -96,6 +99,11 @@ struct irq_domain {
/* type of reverse mapping_technique */
unsigned int revmap_type;
union {
struct {
unsigned int size;
unsigned int first_irq;
irq_hw_number_t first_hwirq;
} legacy;
struct {
unsigned int size;
unsigned int *revmap;
Expand All @@ -117,6 +125,9 @@ struct irq_domain {
#ifdef CONFIG_IRQ_DOMAIN
#ifdef CONFIG_PPC
struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
unsigned int size,
unsigned int first_irq,
irq_hw_number_t first_hwirq,
struct irq_domain_ops *ops,
void *host_data);
struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
Expand All @@ -130,11 +141,18 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
struct irq_domain_ops *ops,
void *host_data);


extern struct irq_domain *irq_find_host(struct device_node *node);
extern void irq_set_default_host(struct irq_domain *host);
extern void irq_set_virq_count(unsigned int count);

static inline struct irq_domain *irq_domain_add_legacy_isa(
struct device_node *of_node,
struct irq_domain_ops *ops,
void *host_data)
{
return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
host_data);
}

extern unsigned int irq_create_mapping(struct irq_domain *host,
irq_hw_number_t hwirq);
Expand Down
96 changes: 64 additions & 32 deletions trunk/kernel/irq/irqdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
#include <linux/smp.h>
#include <linux/fs.h>

#define IRQ_DOMAIN_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */
#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
* ie. legacy 8259, gets irqs 1..15 */
#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
Expand Down Expand Up @@ -74,9 +75,25 @@ static void irq_domain_add(struct irq_domain *domain)
domain->revmap_type, domain);
}

static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
irq_hw_number_t hwirq)
{
irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq;
int size = domain->revmap_data.legacy.size;

if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size))
return 0;
return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
}

/**
* irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
* @size: total number of irqs in legacy mapping
* @first_irq: first number of irq block assigned to the domain
* @first_hwirq: first hwirq number to use for the translation. Should normally
* be '0', but a positive integer can be used if the effective
* hwirqs numbering does not begin at zero.
* @ops: map/unmap domain callbacks
* @host_data: Controller private data pointer
*
Expand All @@ -85,44 +102,64 @@ static void irq_domain_add(struct irq_domain *domain)
* a legacy controller).
*/
struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
unsigned int size,
unsigned int first_irq,
irq_hw_number_t first_hwirq,
struct irq_domain_ops *ops,
void *host_data)
{
struct irq_domain *domain, *h;
struct irq_domain *domain;
unsigned int i;

domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
if (!domain)
return NULL;

domain->revmap_data.legacy.first_irq = first_irq;
domain->revmap_data.legacy.first_hwirq = first_hwirq;
domain->revmap_data.legacy.size = size;

mutex_lock(&irq_domain_mutex);
/* Make sure only one legacy controller can be created */
list_for_each_entry(h, &irq_domain_list, link) {
if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) {
/* Verify that all the irqs are available */
for (i = 0; i < size; i++) {
int irq = first_irq + i;
struct irq_data *irq_data = irq_get_irq_data(irq);

if (WARN_ON(!irq_data || irq_data->domain)) {
mutex_unlock(&irq_domain_mutex);
of_node_put(domain->of_node);
kfree(domain);
return NULL;
}
}
list_add(&domain->link, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);

/* setup us as the domain for all legacy interrupts */
for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
struct irq_data *irq_data = irq_get_irq_data(i);
irq_data->hwirq = i;
/* Claim all of the irqs before registering a legacy domain */
for (i = 0; i < size; i++) {
struct irq_data *irq_data = irq_get_irq_data(first_irq + i);
irq_data->hwirq = first_hwirq + i;
irq_data->domain = domain;
}
mutex_unlock(&irq_domain_mutex);

for (i = 0; i < size; i++) {
int irq = first_irq + i;
int hwirq = first_hwirq + i;

/* IRQ0 gets ignored */
if (!irq)
continue;

/* Legacy flags are left to default at this point,
* one can then use irq_create_mapping() to
* explicitly change them
*/
ops->map(domain, i, i);
ops->map(domain, irq, hwirq);

/* Clear norequest flags */
irq_clear_status_flags(i, IRQ_NOREQUEST);
irq_clear_status_flags(irq, IRQ_NOREQUEST);
}

irq_domain_add(domain);
return domain;
}

Expand Down Expand Up @@ -338,24 +375,19 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
}

/* Get a virtual interrupt number */
if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) {
/* Handle legacy */
virq = (unsigned int)hwirq;
if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)
return 0;
return virq;
} else {
/* Allocate a virtual interrupt number */
hint = hwirq % irq_virq_count;
if (hint == 0)
hint++;
virq = irq_alloc_desc_from(hint, 0);
if (!virq)
virq = irq_alloc_desc_from(1, 0);
if (!virq) {
pr_debug("irq: -> virq allocation failed\n");
return 0;
}
if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
return irq_domain_legacy_revmap(domain, hwirq);

/* Allocate a virtual interrupt number */
hint = hwirq % irq_virq_count;
if (hint == 0)
hint++;
virq = irq_alloc_desc_from(hint, 0);
if (!virq)
virq = irq_alloc_desc_from(1, 0);
if (!virq) {
pr_debug("irq: -> virq allocation failed\n");
return 0;
}

if (irq_setup_virq(domain, virq, hwirq)) {
Expand Down Expand Up @@ -483,7 +515,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain,

/* legacy -> bail early */
if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
return hwirq;
return irq_domain_legacy_revmap(domain, hwirq);

/* Slow path does a linear search of the map */
if (hint == 0)
Expand Down

0 comments on commit bb07e0d

Please sign in to comment.