Commit 8047e247 authored by David S. Miller's avatar David S. Miller

[SPARC64]: Virtualize IRQ numbers.

Inspired by PowerPC XICS interrupt support code.

All IRQs are virtualized in order to keep NR_IRQS from needing
to be too large.  Interrupts on sparc64 are arbitrary 11-bit
values, but we don't need to define NR_IRQS to 2048 if we
virtualize the IRQs.

As PCI and SBUS controller drivers build device IRQs, we divy
out virtual IRQ numbers incrementally starting at 1.  Zero is
a special virtual IRQ used for the timer interrupt.

So device drivers all see virtual IRQs, and all the normal
interfaces such as request_irq(), enable_irq(), etc. translate
that into a real IRQ number in order to configure the IRQ.

At this point knowledge of the struct ino_bucket is almost
entirely contained within arch/sparc64/kernel/irq.c  There are
a few small bits in the PCI controller drivers that need to
be swept away before we can remove ino_bucket's definition
out of asm-sparc64/irq.h and privately into kernel/irq.c
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 37cdcd9e
This diff is collapsed.
...@@ -280,7 +280,6 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, ...@@ -280,7 +280,6 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev, struct pci_dev *pdev,
unsigned int ino) unsigned int ino)
{ {
struct ino_bucket *bucket;
unsigned long imap, iclr; unsigned long imap, iclr;
unsigned long imap_off, iclr_off; unsigned long imap_off, iclr_off;
int inofixup = 0; int inofixup = 0;
...@@ -309,10 +308,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, ...@@ -309,10 +308,7 @@ static unsigned int psycho_irq_build(struct pci_pbm_info *pbm,
if ((ino & 0x20) == 0) if ((ino & 0x20) == 0)
inofixup = ino & 0x03; inofixup = ino & 0x03;
bucket = __bucket(build_irq(inofixup, iclr, imap)); return build_irq(inofixup, iclr, imap, IBF_PCI);
bucket->flags |= IBF_PCI;
return __irq(bucket);
} }
/* PSYCHO error handling support. */ /* PSYCHO error handling support. */
......
...@@ -544,10 +544,10 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, ...@@ -544,10 +544,10 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev, struct pci_dev *pdev,
unsigned int ino) unsigned int ino)
{ {
struct ino_bucket *bucket;
unsigned long imap, iclr; unsigned long imap, iclr;
unsigned long imap_off, iclr_off; unsigned long imap_off, iclr_off;
int inofixup = 0; int inofixup = 0;
int virt_irq;
ino &= PCI_IRQ_INO; ino &= PCI_IRQ_INO;
if (ino < SABRE_ONBOARD_IRQ_BASE) { if (ino < SABRE_ONBOARD_IRQ_BASE) {
...@@ -573,23 +573,23 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, ...@@ -573,23 +573,23 @@ static unsigned int sabre_irq_build(struct pci_pbm_info *pbm,
if ((ino & 0x20) == 0) if ((ino & 0x20) == 0)
inofixup = ino & 0x03; inofixup = ino & 0x03;
bucket = __bucket(build_irq(inofixup, iclr, imap)); virt_irq = build_irq(inofixup, iclr, imap, IBF_PCI);
bucket->flags |= IBF_PCI;
if (pdev) { if (pdev) {
struct pcidev_cookie *pcp = pdev->sysdata; struct pcidev_cookie *pcp = pdev->sysdata;
if (pdev->bus->number != pcp->pbm->pci_first_busno) { if (pdev->bus->number != pcp->pbm->pci_first_busno) {
struct pci_controller_info *p = pcp->pbm->parent; struct pci_controller_info *p = pcp->pbm->parent;
struct irq_desc *d = bucket->irq_info;
d->pre_handler = sabre_wsync_handler; irq_install_pre_handler(virt_irq,
d->pre_handler_arg1 = pdev; sabre_wsync_handler,
d->pre_handler_arg2 = (void *) pdev,
p->pbm_A.controller_regs + SABRE_WRSYNC; (void *)
p->pbm_A.controller_regs +
SABRE_WRSYNC);
} }
} }
return __irq(bucket); return virt_irq;
} }
/* SABRE error handling support. */ /* SABRE error handling support. */
......
...@@ -270,25 +270,33 @@ static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void ...@@ -270,25 +270,33 @@ static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void
} }
} }
static unsigned long schizo_ino_to_iclr(struct pci_pbm_info *pbm,
unsigned int ino)
{
ino &= PCI_IRQ_INO;
return pbm->pbm_regs + schizo_iclr_offset(ino) + 4;
}
static unsigned long schizo_ino_to_imap(struct pci_pbm_info *pbm,
unsigned int ino)
{
ino &= PCI_IRQ_INO;
return pbm->pbm_regs + schizo_imap_offset(ino) + 4;
}
static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev, struct pci_dev *pdev,
unsigned int ino) unsigned int ino)
{ {
struct ino_bucket *bucket;
unsigned long imap, iclr; unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
int ign_fixup; int ign_fixup;
int virt_irq;
ino &= PCI_IRQ_INO; ino &= PCI_IRQ_INO;
imap_off = schizo_imap_offset(ino);
/* Now build the IRQ bucket. */ /* Now build the IRQ bucket. */
imap = pbm->pbm_regs + imap_off; imap = schizo_ino_to_imap(pbm, ino);
imap += 4; iclr = schizo_ino_to_iclr(pbm, ino);
iclr_off = schizo_iclr_offset(ino);
iclr = pbm->pbm_regs + iclr_off;
iclr += 4;
/* On Schizo, no inofixup occurs. This is because each /* On Schizo, no inofixup occurs. This is because each
* INO has it's own IMAP register. On Psycho and Sabre * INO has it's own IMAP register. On Psycho and Sabre
...@@ -305,19 +313,17 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, ...@@ -305,19 +313,17 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
ign_fixup = (1 << 6); ign_fixup = (1 << 6);
} }
bucket = __bucket(build_irq(ign_fixup, iclr, imap)); virt_irq = build_irq(ign_fixup, iclr, imap, IBF_PCI);
bucket->flags |= IBF_PCI;
if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
struct irq_desc *p = bucket->irq_info; irq_install_pre_handler(virt_irq,
tomatillo_wsync_handler,
p->pre_handler = tomatillo_wsync_handler; ((pbm->chip_version <= 4) ?
p->pre_handler_arg1 = ((pbm->chip_version <= 4) ? (void *) 1 : (void *) 0),
(void *) 1 : (void *) 0); (void *) pbm->sync_reg);
p->pre_handler_arg2 = (void *) pbm->sync_reg;
} }
return __irq(bucket); return virt_irq;
} }
/* SCHIZO error handling support. */ /* SCHIZO error handling support. */
...@@ -358,7 +364,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) ...@@ -358,7 +364,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq)
{ {
struct pci_pbm_info *pbm; struct pci_pbm_info *pbm;
struct ino_bucket *bucket;
unsigned long iclr; unsigned long iclr;
/* Do not clear the interrupt for the other PCI bus. /* Do not clear the interrupt for the other PCI bus.
...@@ -376,11 +381,11 @@ static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) ...@@ -376,11 +381,11 @@ static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq)
else else
pbm = &p->pbm_A; pbm = &p->pbm_A;
irq = schizo_irq_build(pbm, NULL, schizo_irq_build(pbm, NULL,
(pbm->portid << 6) | (irq & IMAP_INO)); (pbm->portid << 6) | (irq & IMAP_INO));
bucket = __bucket(irq);
iclr = bucket->iclr;
iclr = schizo_ino_to_iclr(pbm,
(pbm->portid << 6) | (irq & IMAP_INO));
upa_writel(ICLR_IDLE, iclr); upa_writel(ICLR_IDLE, iclr);
} }
...@@ -1125,7 +1130,6 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) ...@@ -1125,7 +1130,6 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
{ {
struct pci_pbm_info *pbm; struct pci_pbm_info *pbm;
unsigned int irq; unsigned int irq;
struct ino_bucket *bucket;
u64 tmp, err_mask, err_no_mask; u64 tmp, err_mask, err_no_mask;
/* Build IRQs and register handlers. */ /* Build IRQs and register handlers. */
...@@ -1137,8 +1141,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) ...@@ -1137,8 +1141,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + upa_writel(tmp, (pbm->pbm_regs +
schizo_imap_offset(SCHIZO_UE_INO) + 4)); schizo_imap_offset(SCHIZO_UE_INO) + 4));
...@@ -1150,8 +1153,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) ...@@ -1150,8 +1153,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + upa_writel(tmp, (pbm->pbm_regs +
schizo_imap_offset(SCHIZO_CE_INO) + 4)); schizo_imap_offset(SCHIZO_CE_INO) + 4));
...@@ -1164,8 +1166,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) ...@@ -1164,8 +1166,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) |
tmp = upa_readl(bucket->imap); SCHIZO_PCIERR_A_INO)));
upa_writel(tmp, (pbm->pbm_regs + upa_writel(tmp, (pbm->pbm_regs +
schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
...@@ -1178,8 +1180,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) ...@@ -1178,8 +1180,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) |
tmp = upa_readl(bucket->imap); SCHIZO_PCIERR_B_INO)));
upa_writel(tmp, (pbm->pbm_regs + upa_writel(tmp, (pbm->pbm_regs +
schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
...@@ -1191,8 +1193,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) ...@@ -1191,8 +1193,8 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) |
tmp = upa_readl(bucket->imap); SCHIZO_SERR_INO)));
upa_writel(tmp, (pbm->pbm_regs + upa_writel(tmp, (pbm->pbm_regs +
schizo_imap_offset(SCHIZO_SERR_INO) + 4)); schizo_imap_offset(SCHIZO_SERR_INO) + 4));
...@@ -1263,7 +1265,6 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) ...@@ -1263,7 +1265,6 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
{ {
struct pci_pbm_info *pbm; struct pci_pbm_info *pbm;
unsigned int irq; unsigned int irq;
struct ino_bucket *bucket;
u64 tmp, err_mask, err_no_mask; u64 tmp, err_mask, err_no_mask;
/* Build IRQs and register handlers. */ /* Build IRQs and register handlers. */
...@@ -1275,8 +1276,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) ...@@ -1275,8 +1276,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4));
pbm = pbm_for_ino(p, SCHIZO_CE_INO); pbm = pbm_for_ino(p, SCHIZO_CE_INO);
...@@ -1287,8 +1287,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) ...@@ -1287,8 +1287,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4));
pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
...@@ -1299,8 +1298,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) ...@@ -1299,8 +1298,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
...@@ -1311,8 +1309,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) ...@@ -1311,8 +1309,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
pbm = pbm_for_ino(p, SCHIZO_SERR_INO); pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
...@@ -1323,8 +1320,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p) ...@@ -1323,8 +1320,7 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
pbm->name); pbm->name);
prom_halt(); prom_halt();
} }
bucket = __bucket(irq); tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_SERR_INO));
tmp = upa_readl(bucket->imap);
upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4));
/* Enable UE and CE interrupts for controller. */ /* Enable UE and CE interrupts for controller. */
......
...@@ -821,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) ...@@ -821,7 +821,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
iclr += ((unsigned long)sbus_level - 1UL) * 8UL; iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
} }
return build_irq(sbus_level, iclr, imap); return build_irq(sbus_level, iclr, imap, 0);
} }
/* Error interrupt handling. */ /* Error interrupt handling. */
......
...@@ -98,13 +98,22 @@ extern struct ino_bucket ivector_table[NUM_IVECS]; ...@@ -98,13 +98,22 @@ extern struct ino_bucket ivector_table[NUM_IVECS];
#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) #define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
#define NR_IRQS 16 /* The largest number of unique interrupt sources we support.
* If this needs to ever be larger than 255, you need to change
* the type of ino_bucket->virt_irq as appropriate.
*
* ino_bucket->virt_irq allocation is made during {sun4v_,}build_irq().
*/
#define NR_IRQS 255
extern void irq_install_pre_handler(int virt_irq,
void (*func)(struct ino_bucket *, void *, void *),
void *arg1, void *arg2);
#define irq_canonicalize(irq) (irq) #define irq_canonicalize(irq) (irq)
extern void disable_irq(unsigned int); extern void disable_irq(unsigned int);
#define disable_irq_nosync disable_irq #define disable_irq_nosync disable_irq
extern void enable_irq(unsigned int); extern void enable_irq(unsigned int);
extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap); extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap, unsigned char flags);
extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags); extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, unsigned char flags);
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment