Commit 9da300e9 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] Update PA-RISC IOSAPIC driver

 - Fix all ioremap abuse noticed by CONFIG_DEBUG_IOREMAP on an N4000.
 - F_EXTEND doesn't do what I thought it did on a 32-bit box.
 - New calling convention for txn_alloc_irq()
 - Replace CONFIG_PARISC64 with CONFIG_64BIT
 - Ensure alignment of the irt buffer to 8 bytes even when slab debugging
   is enabled
Signed-off-by: default avatarMatthew Wilcox <willy@parisc-linux.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b4a993e7
...@@ -158,31 +158,9 @@ ...@@ -158,31 +158,9 @@
#ifdef DEBUG_IOSAPIC #ifdef DEBUG_IOSAPIC
static char assert_buf[128];
static int
assert_failed (char *a, char *f, int l)
{
sprintf(assert_buf,
"ASSERT(%s) failed!\nline %d in %s\n",
a, /* assertion text */
l, /* line number */
f); /* file name */
panic(assert_buf);
return 0;
}
#undef ASSERT
#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); }
#define DBG(x...) printk(x) #define DBG(x...) printk(x)
#else /* DEBUG_IOSAPIC */ #else /* DEBUG_IOSAPIC */
#define DBG(x...) #define DBG(x...)
#undef ASSERT
#define ASSERT(EX)
#endif /* DEBUG_IOSAPIC */ #endif /* DEBUG_IOSAPIC */
#ifdef DEBUG_IOSAPIC_IRT #ifdef DEBUG_IOSAPIC_IRT
...@@ -191,6 +169,12 @@ assert_failed (char *a, char *f, int l) ...@@ -191,6 +169,12 @@ assert_failed (char *a, char *f, int l)
#define DBG_IRT(x...) #define DBG_IRT(x...)
#endif #endif
#ifdef CONFIG_64BIT
#define COMPARE_IRTE_ADDR(irte, hpa) ((irte)->dest_iosapic_addr == (hpa))
#else
#define COMPARE_IRTE_ADDR(irte, hpa) \
((irte)->dest_iosapic_addr == ((hpa) | 0xffffffff00000000ULL))
#endif
#define IOSAPIC_REG_SELECT 0x00 #define IOSAPIC_REG_SELECT 0x00
#define IOSAPIC_REG_WINDOW 0x10 #define IOSAPIC_REG_WINDOW 0x10
...@@ -201,33 +185,18 @@ assert_failed (char *a, char *f, int l) ...@@ -201,33 +185,18 @@ assert_failed (char *a, char *f, int l)
#define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2) #define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2)
#define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2) #define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2)
static inline unsigned int iosapic_read(unsigned long iosapic, unsigned int reg) static inline unsigned int iosapic_read(void __iomem *iosapic, unsigned int reg)
{ {
writel(reg, iosapic + IOSAPIC_REG_SELECT); writel(reg, iosapic + IOSAPIC_REG_SELECT);
return readl(iosapic + IOSAPIC_REG_WINDOW); return readl(iosapic + IOSAPIC_REG_WINDOW);
} }
static inline void iosapic_write(unsigned long iosapic, unsigned int reg, u32 val) static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 val)
{ {
writel(reg, iosapic + IOSAPIC_REG_SELECT); writel(reg, iosapic + IOSAPIC_REG_SELECT);
writel(val, iosapic + IOSAPIC_REG_WINDOW); writel(val, iosapic + IOSAPIC_REG_WINDOW);
} }
/*
** GFP_KERNEL includes __GFP_WAIT flag and that may not
** be acceptable. Since this is boot time, we shouldn't have
** to wait ever and this code should (will?) never get called
** from the interrrupt context.
*/
#define IOSAPIC_KALLOC(a_type, cnt) \
(a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL)
#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr)
#define IOSAPIC_LOCK(lck) spin_lock_irqsave(lck, irqflags)
#define IOSAPIC_UNLOCK(lck) spin_unlock_irqrestore(lck, irqflags)
#define IOSAPIC_VERSION_MASK 0x000000ff #define IOSAPIC_VERSION_MASK 0x000000ff
#define IOSAPIC_VERSION(ver) ((int) (ver & IOSAPIC_VERSION_MASK)) #define IOSAPIC_VERSION(ver) ((int) (ver & IOSAPIC_VERSION_MASK))
...@@ -265,52 +234,64 @@ static inline void iosapic_eoi(void __iomem *addr, unsigned int data) ...@@ -265,52 +234,64 @@ static inline void iosapic_eoi(void __iomem *addr, unsigned int data)
static struct irt_entry *irt_cell; static struct irt_entry *irt_cell;
static size_t irt_num_entry; static size_t irt_num_entry;
static struct irt_entry *iosapic_alloc_irt(int num_entries)
{
unsigned long a;
/* The IRT needs to be 8-byte aligned for the PDC call.
* Normally kmalloc would guarantee larger alignment, but
* if CONFIG_DEBUG_SLAB is enabled, then we can get only
* 4-byte alignment on 32-bit kernels
*/
a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL);
a = (a + 7) & ~7;
return (struct irt_entry *)a;
}
/* /**
** iosapic_load_irt * iosapic_load_irt - Fill in the interrupt routing table
** * @cell_num: The cell number of the CPU we're currently executing on
** The "Get PCI INT Routing Table Size" option returns the number of * @irt: The address to place the new IRT at
** entries in the PCI interrupt routing table for the cell specified * @return The number of entries found
** in the cell_number argument. The cell number must be for a cell *
** within the caller's protection domain. * The "Get PCI INT Routing Table Size" option returns the number of
** * entries in the PCI interrupt routing table for the cell specified
** The "Get PCI INT Routing Table" option returns, for the cell * in the cell_number argument. The cell number must be for a cell
** specified in the cell_number argument, the PCI interrupt routing * within the caller's protection domain.
** table in the caller allocated memory pointed to by mem_addr. *
** We assume the IRT only contains entries for I/O SAPIC and * The "Get PCI INT Routing Table" option returns, for the cell
** calculate the size based on the size of I/O sapic entries. * specified in the cell_number argument, the PCI interrupt routing
** * table in the caller allocated memory pointed to by mem_addr.
** The PCI interrupt routing table entry format is derived from the * We assume the IRT only contains entries for I/O SAPIC and
** IA64 SAL Specification 2.4. The PCI interrupt routing table defines * calculate the size based on the size of I/O sapic entries.
** the routing of PCI interrupt signals between the PCI device output *
** "pins" and the IO SAPICs' input "lines" (including core I/O PCI * The PCI interrupt routing table entry format is derived from the
** devices). This table does NOT include information for devices/slots * IA64 SAL Specification 2.4. The PCI interrupt routing table defines
** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec. * the routing of PCI interrupt signals between the PCI device output
** for the architected method of routing of IRQ's behind PPB's. * "pins" and the IO SAPICs' input "lines" (including core I/O PCI
*/ * devices). This table does NOT include information for devices/slots
* behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
* for the architected method of routing of IRQ's behind PPB's.
*/
static int __init /* return number of entries as success/fail flag */ static int __init
iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
{ {
long status; /* PDC return value status */ long status; /* PDC return value status */
struct irt_entry *table; /* start of interrupt routing tbl */ struct irt_entry *table; /* start of interrupt routing tbl */
unsigned long num_entries = 0UL; unsigned long num_entries = 0UL;
ASSERT(NULL != irt); BUG_ON(!irt);
if (is_pdc_pat()) { if (is_pdc_pat()) {
/* Use pat pdc routine to get interrupt routing table size */ /* Use pat pdc routine to get interrupt routing table size */
DBG("calling get_irt_size (cell %ld)\n", cell_num); DBG("calling get_irt_size (cell %ld)\n", cell_num);
status = pdc_pat_get_irt_size(&num_entries, cell_num); status = pdc_pat_get_irt_size(&num_entries, cell_num);
DBG("get_irt_size: %ld\n", status); DBG("get_irt_size: %ld\n", status);
ASSERT(status == PDC_OK); BUG_ON(status != PDC_OK);
BUG_ON(num_entries == 0);
/* save the number of entries in the table */
ASSERT(0UL != num_entries);
/* /*
** allocate memory for interrupt routing table ** allocate memory for interrupt routing table
...@@ -318,45 +299,47 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) ...@@ -318,45 +299,47 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
** the contents of the table are exclusively ** the contents of the table are exclusively
** for I/O sapic devices. ** for I/O sapic devices.
*/ */
table = IOSAPIC_KALLOC(struct irt_entry, num_entries); table = iosapic_alloc_irt(num_entries);
if (table == NULL) { if (table == NULL) {
printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); printk(KERN_WARNING MODULE_NAME ": read_irt : can "
"not alloc mem for IRT\n");
return 0; return 0;
} }
/* get PCI INT routing table */ /* get PCI INT routing table */
status = pdc_pat_get_irt(table, cell_num); status = pdc_pat_get_irt(table, cell_num);
DBG("pdc_pat_get_irt: %ld\n", status); DBG("pdc_pat_get_irt: %ld\n", status);
ASSERT(status == PDC_OK); WARN_ON(status != PDC_OK);
} else { } else {
/* /*
** C3000/J5000 (and similar) platforms with Sprockets PDC ** C3000/J5000 (and similar) platforms with Sprockets PDC
** will return exactly one IRT for all iosapics. ** will return exactly one IRT for all iosapics.
** So if we have one, don't need to get it again. ** So if we have one, don't need to get it again.
*/ */
if (NULL != irt_cell) if (irt_cell)
return 0; return 0;
/* Should be using the Elroy's HPA, but it's ignored anyway */ /* Should be using the Elroy's HPA, but it's ignored anyway */
status = pdc_pci_irt_size(&num_entries, 0); status = pdc_pci_irt_size(&num_entries, 0);
DBG("pdc_pci_irt_size: %ld\n", status); DBG("pdc_pci_irt_size: %ld\n", status);
if (PDC_OK != status) { if (status != PDC_OK) {
/* Not a "legacy" system with I/O SAPIC either */ /* Not a "legacy" system with I/O SAPIC either */
return 0; return 0;
} }
ASSERT(0UL != num_entries); BUG_ON(num_entries == 0);
table = IOSAPIC_KALLOC(struct irt_entry, num_entries); table = iosapic_alloc_irt(num_entries);
if (table == NULL) { if (!table) {
printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); printk(KERN_WARNING MODULE_NAME ": read_irt : can "
"not alloc mem for IRT\n");
return 0; return 0;
} }
/* HPA ignored by this call too. */ /* HPA ignored by this call too. */
status = pdc_pci_irt(num_entries, 0, table); status = pdc_pci_irt(num_entries, 0, table);
ASSERT(PDC_OK == status); BUG_ON(status != PDC_OK);
} }
/* return interrupt table address */ /* return interrupt table address */
...@@ -390,16 +373,10 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) ...@@ -390,16 +373,10 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
void __init void __init iosapic_init(void)
iosapic_init(void)
{ {
unsigned long cell = 0; unsigned long cell = 0;
/* init global data */
spin_lock_init(&iosapic_lock);
iosapic_list = (struct iosapic_info *) NULL;
iosapic_count = 0;
DBG("iosapic_init()\n"); DBG("iosapic_init()\n");
#ifdef __LP64__ #ifdef __LP64__
...@@ -414,11 +391,9 @@ iosapic_init(void) ...@@ -414,11 +391,9 @@ iosapic_init(void)
} }
#endif #endif
/* /* get interrupt routing table for this cell */
** get IRT for this cell.
*/
irt_num_entry = iosapic_load_irt(cell, &irt_cell); irt_num_entry = iosapic_load_irt(cell, &irt_cell);
if (0 == irt_num_entry) if (irt_num_entry == 0)
irt_cell = NULL; /* old PDC w/o iosapic */ irt_cell = NULL; /* old PDC w/o iosapic */
} }
...@@ -459,10 +434,7 @@ irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin) ...@@ -459,10 +434,7 @@ irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin)
continue; continue;
} }
/* if (!COMPARE_IRTE_ADDR(i, isi->isi_hpa))
** Compare: dest_iosapic_addr, src_bus_irq_devno
*/
if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa))
continue; continue;
if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno) if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno)
...@@ -506,10 +478,10 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev) ...@@ -506,10 +478,10 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin); pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", DBG_IRT("iosapic_xlate_pin(%s) SLOT %d pin %d\n",
PCI_SLOT(pcidev->devfn), intr_pin); pcidev->slot_name, PCI_SLOT(pcidev->devfn), intr_pin);
if (0 == intr_pin) { if (intr_pin == 0) {
/* The device does NOT support/use IRQ lines. */ /* The device does NOT support/use IRQ lines. */
return NULL; return NULL;
} }
...@@ -606,7 +578,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) ...@@ -606,7 +578,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
{ {
u32 mode = 0; u32 mode = 0;
struct irt_entry *p = vi->irte; struct irt_entry *p = vi->irte;
ASSERT(NULL != vi->irte);
if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
mode |= IOSAPIC_IRDT_PO_LOW; mode |= IOSAPIC_IRDT_PO_LOW;
...@@ -619,7 +590,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) ...@@ -619,7 +590,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
** PA doesn't support EXTINT or LPRIO bits. ** PA doesn't support EXTINT or LPRIO bits.
*/ */
ASSERT(vi->txn_data);
*dp0 = mode | (u32) vi->txn_data; *dp0 = mode | (u32) vi->txn_data;
/* /*
...@@ -802,22 +772,23 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -802,22 +772,23 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
vi->irte = irte; vi->irte = irte;
/* Allocate processor IRQ */
vi->txn_irq = txn_alloc_irq();
/* /*
* Allocate processor IRQ
*
* XXX/FIXME The txn_alloc_irq() code and related code should be * XXX/FIXME The txn_alloc_irq() code and related code should be
* moved to enable_irq(). That way we only allocate processor IRQ * moved to enable_irq(). That way we only allocate processor IRQ
* bits for devices that actually have drivers claiming them. * bits for devices that actually have drivers claiming them.
* Right now we assign an IRQ to every PCI device present, * Right now we assign an IRQ to every PCI device present,
* regardless of whether it's used or not. * regardless of whether it's used or not.
*/ */
vi->txn_irq = txn_alloc_irq(8);
if (vi->txn_irq < 0) if (vi->txn_irq < 0)
panic("I/O sapic: couldn't get TXN IRQ\n"); panic("I/O sapic: couldn't get TXN IRQ\n");
/* enable_irq() will use txn_* to program IRdT */ /* enable_irq() will use txn_* to program IRdT */
vi->txn_addr = txn_alloc_addr(vi->txn_irq); vi->txn_addr = txn_alloc_addr(vi->txn_irq);
vi->txn_data = txn_alloc_data(vi->txn_irq, 8); vi->txn_data = txn_alloc_data(vi->txn_irq);
vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI; vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
vi->eoi_data = cpu_to_le32(vi->txn_data); vi->eoi_data = cpu_to_le32(vi->txn_data);
...@@ -841,10 +812,7 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) ...@@ -841,10 +812,7 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
static unsigned int static unsigned int
iosapic_rd_version(struct iosapic_info *isi) iosapic_rd_version(struct iosapic_info *isi)
{ {
ASSERT(isi); return iosapic_read(isi->addr, IOSAPIC_REG_VERSION);
ASSERT(isi->isi_hpa);
return iosapic_read(isi->isi_hpa, IOSAPIC_REG_VERSION);
} }
...@@ -866,44 +834,38 @@ void *iosapic_register(unsigned long hpa) ...@@ -866,44 +834,38 @@ void *iosapic_register(unsigned long hpa)
int cnt; /* track how many entries we've looked at */ int cnt; /* track how many entries we've looked at */
/* /*
** Astro based platforms can't support PCI OLARD if they * Astro based platforms can only support PCI OLARD if they implement
** implement the legacy PDC (not PAT). Though Legacy PDC * PAT PDC. Legacy PDC omits LBAs with no PCI devices from the IRT.
** supports an IRT, LBA's with no device under them * Search the IRT and ignore iosapic's which aren't in the IRT.
** are *not* listed in the IRT.
** Search the IRT and ignore iosapic's which aren't
** in the IRT.
*/ */
ASSERT(NULL != irte); /* always have built-in devices */
for (cnt=0; cnt < irt_num_entry; cnt++, irte++) { for (cnt=0; cnt < irt_num_entry; cnt++, irte++) {
ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type); WARN_ON(IRT_IOSAPIC_TYPE != irte->entry_type);
/* if (COMPARE_IRTE_ADDR(irte, hpa))
** We need sign extension of the hpa on 32-bit kernels.
** The address in the IRT is *always* 64 bit and really
** is an unsigned quantity (like all physical addresses).
*/
if (irte->dest_iosapic_addr == (s64) ((long) hpa))
break; break;
} }
if (cnt >= irt_num_entry) if (cnt >= irt_num_entry) {
return (NULL); DBG("iosapic_register() ignoring 0x%lx (NOT FOUND)\n", hpa);
return NULL;
}
if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) { isi = (struct iosapic_info *)kmalloc(sizeof(struct iosapic_info), GFP_KERNEL);
if (!isi) {
BUG(); BUG();
return (NULL); return NULL;
} }
memset(isi, 0, sizeof(struct iosapic_info)); memset(isi, 0, sizeof(struct iosapic_info));
isi->addr = ioremap(hpa, 4096);
isi->isi_hpa = hpa; isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi); isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
vip = isi->isi_vector = vip = isi->isi_vector = (struct vector_info *)
IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors); kmalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
if (vip == NULL) { if (vip == NULL) {
IOSAPIC_FREE(isi, struct iosapic_info, 1); kfree(isi);
return NULL; return NULL;
} }
...@@ -924,7 +886,6 @@ iosapic_prt_irt(void *irt, long num_entry) ...@@ -924,7 +886,6 @@ iosapic_prt_irt(void *irt, long num_entry)
{ {
unsigned int i, *irp = (unsigned int *) irt; unsigned int i, *irp = (unsigned int *) irt;
ASSERT(NULL != irt);
printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry); printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry);
...@@ -938,8 +899,6 @@ iosapic_prt_irt(void *irt, long num_entry) ...@@ -938,8 +899,6 @@ iosapic_prt_irt(void *irt, long num_entry)
static void static void
iosapic_prt_vi(struct vector_info *vi) iosapic_prt_vi(struct vector_info *vi)
{ {
ASSERT(NULL != vi);
printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi); printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status); printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status);
printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq); printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq);
...@@ -953,7 +912,6 @@ iosapic_prt_vi(struct vector_info *vi) ...@@ -953,7 +912,6 @@ iosapic_prt_vi(struct vector_info *vi)
static void static void
iosapic_prt_isi(struct iosapic_info *isi) iosapic_prt_isi(struct iosapic_info *isi)
{ {
ASSERT(NULL != isi);
printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi); printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
printk(KERN_DEBUG "\t\tisi_hpa: %lx\n", isi->isi_hpa); printk(KERN_DEBUG "\t\tisi_hpa: %lx\n", isi->isi_hpa);
printk(KERN_DEBUG "\t\tisi_status: %x\n", isi->isi_status); printk(KERN_DEBUG "\t\tisi_status: %x\n", isi->isi_status);
......
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