patch-2.4.20 linux-2.4.20/arch/parisc/kernel/iosapic.c
Next file: linux-2.4.20/arch/parisc/kernel/iosapic_private.h
Previous file: linux-2.4.20/arch/parisc/kernel/ioctl32.c
Back to the patch index
Back to the overall index
- Lines: 506
- Date:
Thu Nov 28 15:53:10 2002
- Orig file:
linux-2.4.19/arch/parisc/kernel/iosapic.c
- Orig date:
Fri Feb 9 11:29:44 2001
diff -urN linux-2.4.19/arch/parisc/kernel/iosapic.c linux-2.4.20/arch/parisc/kernel/iosapic.c
@@ -169,11 +169,13 @@
#include <asm/byteorder.h> /* get in-line asm for swab */
#include <asm/pdc.h>
-#include <asm/pdcpat.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/gsc.h> /* gsc_read/write functions */
+#ifdef CONFIG_SUPERIO
+#include <asm/superio.h>
+#endif
#include <asm/iosapic.h>
#include "./iosapic_private.h"
@@ -181,7 +183,6 @@
#define MODULE_NAME "iosapic"
/* "local" compile flags */
-#undef IOSAPIC_CALLBACK
#undef PCI_BRIDGE_FUNCS
#undef DEBUG_IOSAPIC
#undef DEBUG_IOSAPIC_IRT
@@ -282,28 +283,6 @@
#define IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr)
-#if IOSAPIC_CALLBACK
-/*
-** Shouldn't use callback since SAPIC doesn't have an officially assigned
-** H or S version numbers. Slight long term risk the number chosen would
-** collide with something else.
-** But benefit is cleaner lba/sapic interface.
-** Might be worth it but for just use direct calls for now.
-**
-** Entry below is copied from lba driver.
-** Only thing different is hw_type.
-*/
-static struct pa_iodc_driver iosapic_driver_for[] = {
- {HPHW_OTHER, 0x782, 0, 0x0000A, 0, 0x00,
- DRIVER_CHECK_HWTYPE + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION,
- "I/O Sapic", "",(void *) iosapic_callback},
- {0,0,0,0,0,0,
- 0,
- (char *) NULL,(char *) NULL,(void *) NULL}
-};
-#endif /* IOSAPIO_CALLBACK */
-
-
static struct iosapic_info *iosapic_list;
static spinlock_t iosapic_lock;
static int iosapic_count;
@@ -350,25 +329,22 @@
static int __init /* return number of entries as success/fail flag */
iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
{
- struct pdc_pat_io_num pdc_io_num; /* PAT PDC return block */
long status; /* PDC return value status */
- struct irt_entry *table = NULL; /* start of interrupt routing tbl */
+ struct irt_entry *table; /* start of interrupt routing tbl */
unsigned long num_entries = 0UL;
ASSERT(NULL != irt);
- /* FIXME ASSERT(((&pdc_io_num) & (0x3f)) == 0); enforce 32-byte alignment */
- /* Try PAT_PDC to get interrupt routing table size */
- DBG(KERN_DEBUG "calling get_irt_size\n");
- status = pdc_pat_get_irt_size( &pdc_io_num, cell_num);
- DBG(KERN_DEBUG "get_irt_size: %ld\n", status);
+ if (is_pdc_pat()) {
- switch(status) {
+ /* 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);
- case PDC_RET_OK: /* PAT box. Proceed to get the IRT */
+ ASSERT(status == PDC_OK);
/* save the number of entries in the table */
- num_entries = pdc_io_num.num;
ASSERT(0UL != num_entries);
/*
@@ -384,30 +360,27 @@
}
/* get PCI INT routing table */
- status = pdc_pat_get_irt( (void *) table, cell_num);
- DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status);
- ASSERT(status == PDC_RET_OK);
- break;
-
- case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */
+ status = pdc_pat_get_irt(table, cell_num);
+ DBG("pdc_pat_get_irt: %ld\n", status);
+ ASSERT(status == PDC_OK);
+ } else {
/*
- ** C3000/J5000 (and similar) platforms with "legacy" PDC
- ** will return exactly one IRT.
+ ** 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)
- break;
+ return 0;
- status = pdc_pci_irt_size( (void *)&pdc_io_num,
- /* elroy HPA (really a NOP) */ 0);
- DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status);
+ /* 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_RET_OK != status) {
+ if (PDC_OK != status) {
/* Not a "legacy" system with I/O SAPIC either */
return 0;
}
- num_entries = pdc_io_num.num;
ASSERT(0UL != num_entries);
table = IOSAPIC_KALLOC(struct irt_entry, num_entries);
@@ -416,36 +389,27 @@
return 0;
}
- status = pdc_pci_irt( (void *) &pdc_io_num,
- (void *) NULL, /* Elroy HPA - not used */
- (void *) table);
-
- ASSERT(PDC_RET_OK == status);
- break;
-
- default:
- printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status);
- break;
+ /* HPA ignored by this call too. */
+ status = pdc_pci_irt(num_entries, 0, table);
+ ASSERT(PDC_OK == status);
}
/* return interrupt table address */
*irt = table;
-
#ifdef DEBUG_IOSAPIC_IRT
- {
+{
struct irt_entry *p = table;
int i;
- printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
- printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
+ printk(KERN_DEBUG MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
+ printk(KERN_DEBUG MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n",
table,
num_entries,
(int) sizeof(struct irt_entry));
- for (i = 0 ; i < num_entries ; i++, p++)
- {
- printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
+ for (i = 0 ; i < num_entries ; i++, p++) {
+ printk(KERN_DEBUG MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
p->entry_type, p->entry_length, p->interrupt_type,
p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id,
p->src_seg_id, p->dest_iosapic_intin,
@@ -453,7 +417,7 @@
((u32 *) p)[3]
);
}
- }
+}
#endif /* DEBUG_IOSAPIC_IRT */
return num_entries;
@@ -464,6 +428,8 @@
void __init
iosapic_init(void)
{
+ unsigned long cell = 0;
+
/* init global data */
iosapic_lock = SPIN_LOCK_UNLOCKED;
iosapic_list = (struct iosapic_info *) NULL;
@@ -471,22 +437,24 @@
DBG("iosapic_init()\n");
+#ifdef __LP64__
+ if (is_pdc_pat()) {
+ int status;
+ struct pdc_pat_cell_num cell_info;
+
+ status = pdc_pat_cell_get_number(&cell_info);
+ if (status == PDC_OK) {
+ cell = cell_info.cell_num;
+ }
+ }
+#endif
+
/*
** get IRT for this cell.
*/
- irt_num_entry = iosapic_load_irt(0L, &irt_cell);
+ irt_num_entry = iosapic_load_irt(cell, &irt_cell);
if (0 == irt_num_entry)
irt_cell = NULL; /* old PDC w/o iosapic */
-
-#ifdef IOSAPIC_CALLBACK
- /*
- ** When new I/O SAPICs are discovered, this callback
- ** will get invoked. Implies lba driver will register
- ** I/O Sapic as a device it "discovered" with faked
- ** IODC data.
- */
- register_driver(iosapic_driver_for);
-#endif /* IOSAPIC_CALLBACK */
}
@@ -546,7 +514,7 @@
return i;
}
- printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n",
+ printk(KERN_WARNING MODULE_NAME ": 0x%lx : no IRT entry for slot %d, pin %d\n",
isi->isi_hpa, slot, intr_pin);
return NULL;
}
@@ -571,21 +539,18 @@
{
u8 intr_pin, intr_slot;
- (void) 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", PCI_SLOT(pcidev->devfn), intr_pin);
+ DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n",
+ PCI_SLOT(pcidev->devfn), intr_pin);
- if (0 == intr_pin)
- {
- /*
- ** The device does NOT support/use IRQ lines.
- */
+ if (0 == intr_pin) {
+ /* The device does NOT support/use IRQ lines. */
return NULL;
}
/* Check if pcidev behind a PPB */
- if (NULL != pcidev->bus->self)
- {
+ if (NULL != pcidev->bus->self) {
/* Convert pcidev INTR_PIN into something we
** can lookup in the IRT.
*/
@@ -600,7 +565,7 @@
** or by some ambitous soul who wants to watch TV.
*/
if (pci_bridge_funcs->xlate_intr_line) {
- intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev);
+ intr_pin = pci_bridge_funcs->xlate_intr_line(pcidev);
}
#else /* PCI_BRIDGE_FUNCS */
struct pci_bus *p = pcidev->bus;
@@ -646,8 +611,8 @@
extern void do_irq(struct irqaction *a, int i, struct pt_regs *p);
int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline;
- DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline,
- vi->vi_eoi_addr);
+ DBG("iosapic_interrupt(): irq %d line %d eoi %p\n",
+ irq, vi->vi_irqline, vi->vi_eoi_addr);
/* FIXME: Need to mask/unmask? processor IRQ is already masked... */
do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs);
@@ -668,12 +633,39 @@
struct vector_info *vi;
int isi_line; /* line used by device */
int tmp;
+ int return_irq;
+#ifdef CONFIG_SUPERIO
+ int superio_irq = -1;
+#endif
if (NULL == isi) {
- printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa);
+ printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
+ pcidev->name);
return(-1);
}
+#ifdef CONFIG_SUPERIO
+ if (is_superio_device(pcidev)) {
+ superio_irq = superio_fixup_irq(pcidev);
+ if (superio_irq == -1)
+ return(-1);
+
+ if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) {
+
+ /*
+ * SuperIO USB controller has an irt entry.
+ * Only let the USB controller hookup the rest
+ * of the interrupt routing when it comes through.
+ * Note that interrupts for all three functions
+ * actually come through the PIC's on function 1!
+ */
+
+ pcidev->irq = superio_irq;
+ return superio_irq;
+ }
+ }
+#endif /* CONFIG_SUPERIO */
+
/* lookup IRT entry for isi/slot/pin set */
irte = iosapic_xlate_pin(isi, pcidev);
if (NULL == irte) {
@@ -714,22 +706,31 @@
vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8);
ASSERT(vi->vi_txn_data < 256); /* matches 8 above */
- tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi);
+ tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0,
+ vi->vi_name, vi);
ASSERT(tmp == 0);
- vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI;
+ vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI);
vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline);
ASSERT(NULL != isi->isi_region);
- /*
- ** pcidev->irq still needs to be virtualized.
- */
- pcidev->irq = isi->isi_region->data.irqbase + isi_line;
+ /* pcidev->irq still needs to be virtualized. */
+
+ return_irq = isi->isi_region->data.irqbase + isi_line;
- DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn),
- PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
+#ifdef CONFIG_SUPERIO
+ if (superio_irq != -1) {
+ superio_inform_irq(return_irq);
+ return_irq = superio_irq;
+ }
+#endif
+ pcidev->irq = return_irq;
+
+ DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
+ PCI_SLOT(pcidev->devfn),
+ PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq);
- return(pcidev->irq);
+ return return_irq;
}
@@ -755,7 +756,7 @@
struct iosapic_info *isp = vi->vi_ios;
ASSERT(NULL != isp);
- ASSERT(NULL != isp->isi_hpa);
+ ASSERT(0 != isp->isi_hpa);
DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n",
vi->vi_irqline,
isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW,
@@ -807,16 +808,13 @@
** Extracting id_eid isn't a real clean way of getting it.
** But the encoding is the same for both PA and IA64 platforms.
*/
-#ifdef __LP64__
- if (pdc_pat) {
+ if (is_pdc_pat()) {
/*
** PAT PDC just hands it to us "right".
** vi_txn_addr comes from cpu_data[x].txn_addr.
*/
*dp1 = (u32) (vi->vi_txn_addr);
- } else
-#endif
- {
+ } else {
/*
** eg if base_addr == 0xfffa0000),
** we want to get 0xa0ff0000.
@@ -886,7 +884,6 @@
/* data is initialized by fixup_irq */
ASSERT(0 < vi->vi_txn_irq);
- ASSERT(0UL != vi->vi_txn_addr);
ASSERT(0UL != vi->vi_txn_data);
iosapic_set_irt_data(vi, &d0, &d1);
@@ -895,10 +892,10 @@
#ifdef DEBUG_IOSAPIC_IRT
{
-u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
-printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
-while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
-printk("\n");
+ u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL);
+ printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr);
+ while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++));
+ printk("\n");
}
printk("iosapic_enable_irq(): sel ");
@@ -943,10 +940,10 @@
static struct irq_region_ops iosapic_irq_ops = {
- iosapic_disable_irq,
- iosapic_enable_irq,
- iosapic_mask_irq,
- iosapic_unmask_irq
+ disable_irq: iosapic_disable_irq,
+ enable_irq: iosapic_enable_irq,
+ mask_irq: iosapic_mask_irq,
+ unmask_irq: iosapic_unmask_irq
};
@@ -967,15 +964,9 @@
}
-#ifndef IOSAPIC_CALLBACK
-/*
-** iosapic_register() is the alternative to iosapic_driver_for().
-** (Only one or the other should be implemented.)
-*/
-
/*
** iosapic_register() is called by "drivers" with an integrated I/O SAPIC.
-** Caller must be certain they have an I/O SAPIC and know it's MMIO address.
+** Caller must be certain they have an I/O SAPIC and know its MMIO address.
**
** o allocate iosapic_info and add it to the list
** o read iosapic version and squirrel that away
@@ -984,7 +975,7 @@
** o allocate isi_region (registers region handlers)
*/
void *
-iosapic_register(void *hpa)
+iosapic_register(unsigned long hpa)
{
struct iosapic_info *isi = NULL;
struct irt_entry *irte = irt_cell;
@@ -1021,7 +1012,7 @@
memset(isi, 0, sizeof(struct iosapic_info));
- isi->isi_hpa = (unsigned char *) hpa;
+ isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
@@ -1034,6 +1025,7 @@
}
memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors);
+ sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++);
/*
** Initialize vector array
@@ -1041,17 +1033,16 @@
for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
vip->vi_irqline = (unsigned char) cnt;
vip->vi_ios = isi;
+ sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt);
}
isi->isi_region = alloc_irq_region(isi->isi_num_vectors,
- &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK,
- "I/O Sapic", (void *) isi->isi_vector);
+ &iosapic_irq_ops, isi->isi_name,
+ (void *) isi->isi_vector);
ASSERT(NULL != isi->isi_region);
return ((void *) isi);
}
-#endif /* !IOSAPIC_CALLBACK */
-
#ifdef DEBUG_IOSAPIC
@@ -1092,8 +1083,8 @@
{
ASSERT(NULL != isi);
printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
- printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa);
- printk(KERN_DEBUG "\t\tisi_satus: %x\n", isi->isi_status);
+ 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_version: %x\n", isi->isi_version);
printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)