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 @@
#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)
#else /* DEBUG_IOSAPIC */
#define DBG(x...)
#undef ASSERT
#define ASSERT(EX)
#endif /* DEBUG_IOSAPIC */
#ifdef DEBUG_IOSAPIC_IRT
......@@ -191,6 +169,12 @@ assert_failed (char *a, char *f, int l)
#define DBG_IRT(x...)
#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_WINDOW 0x10
......@@ -201,33 +185,18 @@ assert_failed (char *a, char *f, int l)
#define IOSAPIC_IRDT_ENTRY(idx) (0x10+(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);
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(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(ver) ((int) (ver & IOSAPIC_VERSION_MASK))
......@@ -265,52 +234,64 @@ static inline void iosapic_eoi(void __iomem *addr, unsigned int data)
static struct irt_entry *irt_cell;
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
**
** The "Get PCI INT Routing Table Size" option returns the number of
** entries in the PCI interrupt routing table for the cell specified
** 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" option returns, for the cell
** specified in the cell_number argument, the PCI interrupt routing
** table in the caller allocated memory pointed to by mem_addr.
** We assume the IRT only contains entries for I/O SAPIC and
** calculate the size based on the size of I/O sapic entries.
**
** The PCI interrupt routing table entry format is derived from the
** IA64 SAL Specification 2.4. The PCI interrupt routing table defines
** the routing of PCI interrupt signals between the PCI device output
** "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.
*/
/**
* iosapic_load_irt - Fill in the interrupt routing table
* @cell_num: The cell number of the CPU we're currently executing on
* @irt: The address to place the new IRT at
* @return The number of entries found
*
* The "Get PCI INT Routing Table Size" option returns the number of
* entries in the PCI interrupt routing table for the cell specified
* 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" option returns, for the cell
* specified in the cell_number argument, the PCI interrupt routing
* table in the caller allocated memory pointed to by mem_addr.
* We assume the IRT only contains entries for I/O SAPIC and
* calculate the size based on the size of I/O sapic entries.
*
* The PCI interrupt routing table entry format is derived from the
* IA64 SAL Specification 2.4. The PCI interrupt routing table defines
* the routing of PCI interrupt signals between the PCI device output
* "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)
{
long status; /* PDC return value status */
struct irt_entry *table; /* start of interrupt routing tbl */
unsigned long num_entries = 0UL;
ASSERT(NULL != irt);
BUG_ON(!irt);
if (is_pdc_pat()) {
/* Use pat pdc routine to get interrupt routing table size */
DBG("calling get_irt_size (cell %ld)\n", cell_num);
status = pdc_pat_get_irt_size(&num_entries, cell_num);
DBG("get_irt_size: %ld\n", status);
ASSERT(status == PDC_OK);
/* save the number of entries in the table */
ASSERT(0UL != num_entries);
BUG_ON(status != PDC_OK);
BUG_ON(num_entries == 0);
/*
** allocate memory for interrupt routing table
......@@ -318,45 +299,47 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
** the contents of the table are exclusively
** for I/O sapic devices.
*/
table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
table = iosapic_alloc_irt(num_entries);
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;
}
/* get PCI INT routing table */
status = pdc_pat_get_irt(table, cell_num);
DBG("pdc_pat_get_irt: %ld\n", status);
ASSERT(status == PDC_OK);
WARN_ON(status != PDC_OK);
} else {
/*
** C3000/J5000 (and similar) platforms with Sprockets PDC
** will return exactly one IRT for all iosapics.
** So if we have one, don't need to get it again.
*/
if (NULL != irt_cell)
if (irt_cell)
return 0;
/* Should be using the Elroy's HPA, but it's ignored anyway */
status = pdc_pci_irt_size(&num_entries, 0);
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 */
return 0;
}
ASSERT(0UL != num_entries);
BUG_ON(num_entries == 0);
table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
if (table == NULL) {
printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n");
table = iosapic_alloc_irt(num_entries);
if (!table) {
printk(KERN_WARNING MODULE_NAME ": read_irt : can "
"not alloc mem for IRT\n");
return 0;
}
/* HPA ignored by this call too. */
status = pdc_pci_irt(num_entries, 0, table);
ASSERT(PDC_OK == status);
BUG_ON(status != PDC_OK);
}
/* return interrupt table address */
......@@ -390,16 +373,10 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
void __init
iosapic_init(void)
void __init iosapic_init(void)
{
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");
#ifdef __LP64__
......@@ -414,11 +391,9 @@ iosapic_init(void)
}
#endif
/*
** get IRT for this cell.
*/
irt_num_entry = iosapic_load_irt(cell, &irt_cell);
if (0 == irt_num_entry)
/* get interrupt routing table for this cell */
irt_num_entry = iosapic_load_irt(cell, &irt_cell);
if (irt_num_entry == 0)
irt_cell = NULL; /* old PDC w/o iosapic */
}
......@@ -459,10 +434,7 @@ irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin)
continue;
}
/*
** Compare: dest_iosapic_addr, src_bus_irq_devno
*/
if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa))
if (!COMPARE_IRTE_ADDR(i, isi->isi_hpa))
continue;
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)
pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n",
PCI_SLOT(pcidev->devfn), intr_pin);
DBG_IRT("iosapic_xlate_pin(%s) SLOT %d pin %d\n",
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. */
return NULL;
}
......@@ -606,7 +578,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
{
u32 mode = 0;
struct irt_entry *p = vi->irte;
ASSERT(NULL != vi->irte);
if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
mode |= IOSAPIC_IRDT_PO_LOW;
......@@ -619,7 +590,6 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
** PA doesn't support EXTINT or LPRIO bits.
*/
ASSERT(vi->txn_data);
*dp0 = mode | (u32) vi->txn_data;
/*
......@@ -802,22 +772,23 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
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
* moved to enable_irq(). That way we only allocate processor IRQ
* bits for devices that actually have drivers claiming them.
* Right now we assign an IRQ to every PCI device present,
* regardless of whether it's used or not.
*/
vi->txn_irq = txn_alloc_irq(8);
if (vi->txn_irq < 0)
panic("I/O sapic: couldn't get TXN IRQ\n");
/* enable_irq() will use txn_* to program IRdT */
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_data = cpu_to_le32(vi->txn_data);
......@@ -841,10 +812,7 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
static unsigned int
iosapic_rd_version(struct iosapic_info *isi)
{
ASSERT(isi);
ASSERT(isi->isi_hpa);
return iosapic_read(isi->isi_hpa, IOSAPIC_REG_VERSION);
return iosapic_read(isi->addr, IOSAPIC_REG_VERSION);
}
......@@ -866,44 +834,38 @@ void *iosapic_register(unsigned long hpa)
int cnt; /* track how many entries we've looked at */
/*
** Astro based platforms can't support PCI OLARD if they
** implement the legacy PDC (not PAT). Though Legacy PDC
** supports an IRT, LBA's with no device under them
** 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 */
* Astro based platforms can only support PCI OLARD if they implement
* PAT PDC. Legacy PDC omits LBAs with no PCI devices from the IRT.
* Search the IRT and ignore iosapic's which aren't in the IRT.
*/
for (cnt=0; cnt < irt_num_entry; cnt++, irte++) {
ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type);
/*
** 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))
WARN_ON(IRT_IOSAPIC_TYPE != irte->entry_type);
if (COMPARE_IRTE_ADDR(irte, hpa))
break;
}
if (cnt >= irt_num_entry)
return (NULL);
if (cnt >= irt_num_entry) {
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();
return (NULL);
return NULL;
}
memset(isi, 0, sizeof(struct iosapic_info));
isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi);
isi->addr = ioremap(hpa, 4096);
isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
vip = isi->isi_vector =
IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors);
vip = isi->isi_vector = (struct vector_info *)
kmalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
if (vip == NULL) {
IOSAPIC_FREE(isi, struct iosapic_info, 1);
kfree(isi);
return NULL;
}
......@@ -924,7 +886,6 @@ iosapic_prt_irt(void *irt, long num_entry)
{
unsigned int i, *irp = (unsigned int *) irt;
ASSERT(NULL != irt);
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)
static void
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 "\t\tstatus: %.4x\n", vi->status);
printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq);
......@@ -953,10 +912,9 @@ iosapic_prt_vi(struct vector_info *vi)
static void
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 "\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);
printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version);
printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector);
}
......
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