Skip to content

Commit

Permalink
Merge branch 'irq-irqdomain-for-linus' of git://git.kernel.org/pub/sc…
Browse files Browse the repository at this point in the history
…m/linux/kernel/git/tip/tip

Pull irq domain updates from Thomas Gleixner:
 "The real interesting irq updates:

   - Support for hierarchical irq domains:

     For complex interrupt routing scenarios where more than one
     interrupt related chip is involved we had no proper representation
     in the generic interrupt infrastructure so far.  That made people
     implement rather ugly constructs in their nested irq chip
     implementations.  The main offenders are x86 and arm/gic.

     To distangle that mess we have now hierarchical irqdomains which
     seperate the various interrupt chips and connect them via the
     hierarchical domains.  That keeps the domain specific details
     internal to the particular hierarchy level and removes the
     criss/cross referencing of chip internals.  The resulting hierarchy
     for a complex x86 system will look like this:

        vector          mapped: 74
          msi-0         mapped: 2
          dmar-ir-1     mapped: 69
            ioapic-1    mapped: 4
            ioapic-0    mapped: 20
            pci-msi-2   mapped: 45
          dmar-ir-0     mapped: 3
            ioapic-2    mapped: 1
            pci-msi-1   mapped: 2
          htirq         mapped: 0

     Neither ioapic nor pci-msi know about the dmar interrupt remapping
     between themself and the vector domain.  If interrupt remapping is
     disabled ioapic and pci-msi become direct childs of the vector
     domain.

     In hindsight we should have done that years ago, but in hindsight
     we always know better :)

   - Support for generic MSI interrupt domain handling

     We have more and more non PCI related MSI interrupts, so providing
     a generic infrastructure for this is better than having all
     affected architectures implementing their own private hacks.

   - Support for PCI-MSI interrupt domain handling, based on the generic
     MSI support.

     This part carries the pci/msi branch from Bjorn Helgaas pci tree to
     avoid a massive conflict.  The PCI/MSI parts are acked by Bjorn.

  I have two more branches on top of this.  The full conversion of x86
  to hierarchical domains and a partial conversion of arm/gic"

* 'irq-irqdomain-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (41 commits)
  genirq: Move irq_chip_write_msi_msg() helper to core
  PCI/MSI: Allow an msi_controller to be associated to an irq domain
  PCI/MSI: Provide mechanism to alloc/free MSI/MSIX interrupt from irqdomain
  PCI/MSI: Enhance core to support hierarchy irqdomain
  PCI/MSI: Move cached entry functions to irq core
  genirq: Provide default callbacks for msi_domain_ops
  genirq: Introduce msi_domain_alloc/free_irqs()
  asm-generic: Add msi.h
  genirq: Add generic msi irq domain support
  genirq: Introduce callback irq_chip.irq_write_msi_msg
  genirq: Work around __irq_set_handler vs stacked domains ordering issues
  irqdomain: Introduce helper function irq_domain_add_hierarchy()
  irqdomain: Implement a method to automatically call parent domains alloc/free
  genirq: Introduce helper irq_domain_set_info() to reduce duplicated code
  genirq: Split out flow handler typedefs into seperate header file
  genirq: Add IRQ_SET_MASK_OK_DONE to support stacked irqchip
  genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip
  genirq: Add more helper functions to support stacked irq_chip
  genirq: Introduce helper functions to support stacked irq_chip
  irqdomain: Do irq_find_mapping and set_type for hierarchy irqdomain in case OF
  ...
  • Loading branch information
torvalds committed Dec 10, 2014
2 parents ecb50f0 + 74faaf7 commit 9e66645
Show file tree
Hide file tree
Showing 53 changed files with 1,924 additions and 351 deletions.
71 changes: 71 additions & 0 deletions Documentation/IRQ-domain.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,74 @@ used and no descriptor gets allocated it is very important to make sure
that the driver using the simple domain call irq_create_mapping()
before any irq_find_mapping() since the latter will actually work
for the static IRQ assignment case.

==== Hierarchy IRQ domain ====
On some architectures, there may be multiple interrupt controllers
involved in delivering an interrupt from the device to the target CPU.
Let's look at a typical interrupt delivering path on x86 platforms:

Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU

There are three interrupt controllers involved:
1) IOAPIC controller
2) Interrupt remapping controller
3) Local APIC controller

To support such a hardware topology and make software architecture match
hardware architecture, an irq_domain data structure is built for each
interrupt controller and those irq_domains are organized into hierarchy.
When building irq_domain hierarchy, the irq_domain near to the device is
child and the irq_domain near to CPU is parent. So a hierarchy structure
as below will be built for the example above.
CPU Vector irq_domain (root irq_domain to manage CPU vectors)
^
|
Interrupt Remapping irq_domain (manage irq_remapping entries)
^
|
IOAPIC irq_domain (manage IOAPIC delivery entries/pins)

There are four major interfaces to use hierarchy irq_domain:
1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt
controller related resources to deliver these interrupts.
2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller
related resources associated with these interrupts.
3) irq_domain_activate_irq(): activate interrupt controller hardware to
deliver the interrupt.
3) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
to stop delivering the interrupt.

Following changes are needed to support hierarchy irq_domain.
1) a new field 'parent' is added to struct irq_domain; it's used to
maintain irq_domain hierarchy information.
2) a new field 'parent_data' is added to struct irq_data; it's used to
build hierarchy irq_data to match hierarchy irq_domains. The irq_data
is used to store irq_domain pointer and hardware irq number.
3) new callbacks are added to struct irq_domain_ops to support hierarchy
irq_domain operations.

With support of hierarchy irq_domain and hierarchy irq_data ready, an
irq_domain structure is built for each interrupt controller, and an
irq_data structure is allocated for each irq_domain associated with an
IRQ. Now we could go one step further to support stacked(hierarchy)
irq_chip. That is, an irq_chip is associated with each irq_data along
the hierarchy. A child irq_chip may implement a required action by
itself or by cooperating with its parent irq_chip.

With stacked irq_chip, interrupt controller driver only needs to deal
with the hardware managed by itself and may ask for services from its
parent irq_chip when needed. So we could achieve a much cleaner
software architecture.

For an interrupt controller driver to support hierarchy irq_domain, it
needs to:
1) Implement irq_domain_ops.alloc and irq_domain_ops.free
2) Optionally implement irq_domain_ops.activate and
irq_domain_ops.deactivate.
3) Optionally implement an irq_chip to manage the interrupt controller
hardware.
4) No need to implement irq_domain_ops.map and irq_domain_ops.unmap,
they are unused with hierarchy irq_domain.

Hierarchy irq_domain may also be used to support other architectures,
such as ARM, ARM64 etc.
10 changes: 6 additions & 4 deletions arch/arm/include/asm/mach/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ struct device;
struct hw_pci {
#ifdef CONFIG_PCI_DOMAINS
int domain;
#endif
#ifdef CONFIG_PCI_MSI
struct msi_controller *msi_ctrl;
#endif
struct pci_ops *ops;
int nr_controllers;
Expand All @@ -36,8 +39,6 @@ struct hw_pci {
resource_size_t start,
resource_size_t size,
resource_size_t align);
void (*add_bus)(struct pci_bus *bus);
void (*remove_bus)(struct pci_bus *bus);
};

/*
Expand All @@ -46,6 +47,9 @@ struct hw_pci {
struct pci_sys_data {
#ifdef CONFIG_PCI_DOMAINS
int domain;
#endif
#ifdef CONFIG_PCI_MSI
struct msi_controller *msi_ctrl;
#endif
struct list_head node;
int busnr; /* primary bus number */
Expand All @@ -65,8 +69,6 @@ struct pci_sys_data {
resource_size_t start,
resource_size_t size,
resource_size_t align);
void (*add_bus)(struct pci_bus *bus);
void (*remove_bus)(struct pci_bus *bus);
void *private_data; /* platform controller private data */
};

Expand Down
28 changes: 12 additions & 16 deletions arch/arm/kernel/bios32.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@

static int debug_pci;

#ifdef CONFIG_PCI_MSI
struct msi_controller *pcibios_msi_controller(struct pci_dev *dev)
{
struct pci_sys_data *sysdata = dev->bus->sysdata;

return sysdata->msi_ctrl;
}
#endif

/*
* We can't use pci_get_device() here since we are
* called from interrupt context.
Expand Down Expand Up @@ -360,20 +369,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL(pcibios_fixup_bus);

void pcibios_add_bus(struct pci_bus *bus)
{
struct pci_sys_data *sys = bus->sysdata;
if (sys->add_bus)
sys->add_bus(bus);
}

void pcibios_remove_bus(struct pci_bus *bus)
{
struct pci_sys_data *sys = bus->sysdata;
if (sys->remove_bus)
sys->remove_bus(bus);
}

/*
* Swizzle the device pin each time we cross a bridge. If a platform does
* not provide a swizzle function, we perform the standard PCI swizzling.
Expand Down Expand Up @@ -470,13 +465,14 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,

#ifdef CONFIG_PCI_DOMAINS
sys->domain = hw->domain;
#endif
#ifdef CONFIG_PCI_MSI
sys->msi_ctrl = hw->msi_ctrl;
#endif
sys->busnr = busnr;
sys->swizzle = hw->swizzle;
sys->map_irq = hw->map_irq;
sys->align_resource = hw->align_resource;
sys->add_bus = hw->add_bus;
sys->remove_bus = hw->remove_bus;
INIT_LIST_HEAD(&sys->resources);

if (hw->private_data)
Expand Down
10 changes: 5 additions & 5 deletions arch/arm/mach-iop13xx/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ static void iop13xx_msi_nop(struct irq_data *d)
static struct irq_chip iop13xx_msi_chip = {
.name = "PCI-MSI",
.irq_ack = iop13xx_msi_nop,
.irq_enable = unmask_msi_irq,
.irq_disable = mask_msi_irq,
.irq_mask = mask_msi_irq,
.irq_unmask = unmask_msi_irq,
.irq_enable = pci_msi_unmask_irq,
.irq_disable = pci_msi_mask_irq,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
};

int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
Expand All @@ -153,7 +153,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
id = iop13xx_cpu_id();
msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f);

write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq);

return 0;
Expand Down
8 changes: 4 additions & 4 deletions arch/ia64/kernel/msi_ia64.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
data |= MSI_DATA_VECTOR(irq_to_vector(irq));
msg.data = data;

write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
cpumask_copy(idata->affinity, cpumask_of(cpu));

return 0;
Expand Down Expand Up @@ -71,7 +71,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR(vector);

write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);

return 0;
Expand Down Expand Up @@ -102,8 +102,8 @@ static int ia64_msi_retrigger_irq(struct irq_data *data)
*/
static struct irq_chip ia64_msi_chip = {
.name = "PCI-MSI",
.irq_mask = mask_msi_irq,
.irq_unmask = unmask_msi_irq,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
.irq_ack = ia64_ack_msi_irq,
#ifdef CONFIG_SMP
.irq_set_affinity = ia64_set_msi_irq_affinity,
Expand Down
8 changes: 4 additions & 4 deletions arch/ia64/sn/kernel/msi_sn.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
msg.data = 0x100 + irq;

irq_set_msi_desc(irq, entry);
write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);

return 0;
Expand Down Expand Up @@ -205,7 +205,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
msg.address_hi = (u32)(bus_addr >> 32);
msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);

write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
cpumask_copy(data->affinity, cpu_mask);

return 0;
Expand All @@ -228,8 +228,8 @@ static int sn_msi_retrigger_irq(struct irq_data *data)

static struct irq_chip sn_msi_chip = {
.name = "PCI-MSI",
.irq_mask = mask_msi_irq,
.irq_unmask = unmask_msi_irq,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
.irq_ack = sn_ack_msi_irq,
#ifdef CONFIG_SMP
.irq_set_affinity = sn_set_msi_irq_affinity,
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/pci/msi-octeon.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);

irq_set_msi_desc(irq, desc);
write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
return 0;
}

Expand Down
12 changes: 6 additions & 6 deletions arch/mips/pci/msi-xlp.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ static void xlp_msix_mask_ack(struct irq_data *d)

msixvec = nlm_irq_msixvec(d->irq);
link = nlm_irq_msixlink(msixvec);
mask_msi_irq(d);
pci_msi_mask_irq(d);
md = irq_data_get_irq_handler_data(d);

/* Ack MSI on bridge */
Expand All @@ -239,10 +239,10 @@ static void xlp_msix_mask_ack(struct irq_data *d)

static struct irq_chip xlp_msix_chip = {
.name = "XLP-MSIX",
.irq_enable = unmask_msi_irq,
.irq_disable = mask_msi_irq,
.irq_enable = pci_msi_unmask_irq,
.irq_disable = pci_msi_mask_irq,
.irq_mask_ack = xlp_msix_mask_ack,
.irq_unmask = unmask_msi_irq,
.irq_unmask = pci_msi_unmask_irq,
};

void arch_teardown_msi_irq(unsigned int irq)
Expand Down Expand Up @@ -345,7 +345,7 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link,
if (ret < 0)
return ret;

write_msi_msg(xirq, &msg);
pci_write_msi_msg(xirq, &msg);
return 0;
}

Expand Down Expand Up @@ -446,7 +446,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link,
if (ret < 0)
return ret;

write_msi_msg(xirq, &msg);
pci_write_msi_msg(xirq, &msg);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion arch/mips/pci/pci-xlr.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
if (ret < 0)
return ret;

write_msi_msg(irq, &msg);
pci_write_msi_msg(irq, &msg);
return 0;
}
#endif
Expand Down
8 changes: 4 additions & 4 deletions arch/powerpc/platforms/cell/axon_msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)

irq_set_msi_desc(virq, entry);
msg.data = virq;
write_msi_msg(virq, &msg);
pci_write_msi_msg(virq, &msg);
}

return 0;
Expand All @@ -301,9 +301,9 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
}

static struct irq_chip msic_irq_chip = {
.irq_mask = mask_msi_irq,
.irq_unmask = unmask_msi_irq,
.irq_shutdown = mask_msi_irq,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
.irq_shutdown = pci_msi_mask_irq,
.name = "AXON-MSI",
};

Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/powernv/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return rc;
}
irq_set_msi_desc(virq, entry);
write_msi_msg(virq, &msg);
pci_write_msi_msg(virq, &msg);
}
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/pseries/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
irq_set_msi_desc(virq, entry);

/* Read config space back so we can restore after reset */
__read_msi_msg(entry, &msg);
__pci_read_msi_msg(entry, &msg);
entry->msg = msg;
}

Expand Down
6 changes: 3 additions & 3 deletions arch/powerpc/sysdev/fsl_msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p)


static struct irq_chip fsl_msi_chip = {
.irq_mask = mask_msi_irq,
.irq_unmask = unmask_msi_irq,
.irq_mask = pci_msi_mask_irq,
.irq_unmask = pci_msi_unmask_irq,
.irq_ack = fsl_msi_end_irq,
.irq_print_chip = fsl_msi_print_chip,
};
Expand Down Expand Up @@ -242,7 +242,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
irq_set_msi_desc(virq, entry);

fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
write_msi_msg(virq, &msg);
pci_write_msi_msg(virq, &msg);
}
return 0;

Expand Down
6 changes: 3 additions & 3 deletions arch/powerpc/sysdev/mpic_pasemi_msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ static struct mpic *msi_mpic;
static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
{
pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
mask_msi_irq(data);
pci_msi_mask_irq(data);
mpic_mask_irq(data);
}

static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
{
pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
mpic_unmask_irq(data);
unmask_msi_irq(data);
pci_msi_unmask_irq(data);
}

static struct irq_chip mpic_pasemi_msi_chip = {
Expand Down Expand Up @@ -136,7 +136,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
* register to generate MSI [512...1023]
*/
msg.data = hwirq-0x200;
write_msi_msg(virq, &msg);
pci_write_msi_msg(virq, &msg);
}

return 0;
Expand Down
Loading

0 comments on commit 9e66645

Please sign in to comment.