patch-2.4.0-test2 linux/arch/arm/kernel/dec21285.c
Next file: linux/arch/arm/kernel/dma-a5k.c
Previous file: linux/arch/arm/kernel/debug-armv.S
Back to the patch index
Back to the overall index
- Lines: 344
- Date:
Mon Jun 19 17:59:34 2000
- Orig file:
v2.4.0-test1/linux/arch/arm/kernel/dec21285.c
- Orig date:
Wed Apr 26 16:34:06 2000
diff -u --recursive --new-file v2.4.0-test1/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c
@@ -1,9 +1,8 @@
/*
* arch/arm/kernel/dec21285.c: PCI functions for DC21285
*
- * Copyright (C) 1998-1999 Russell King, Phil Blundell
+ * Copyright (C) 1998-2000 Russell King, Phil Blundell
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -23,7 +22,8 @@
#define MAX_SLOTS 21
extern int setup_arm_irq(int, struct irqaction *);
-extern void pcibios_report_device_errors(int warn);
+extern void pcibios_report_status(u_int status_mask, int warn);
+extern void register_isa_ports(unsigned int, unsigned int, unsigned int);
static unsigned long
dc21285_base_address(struct pci_dev *dev)
@@ -145,86 +145,125 @@
dc21285_write_config_dword,
};
+static struct timer_list serr_timer;
+static struct timer_list perr_timer;
+
+static void dc21285_enable_error(unsigned long __data)
+{
+ switch (__data) {
+ case IRQ_PCI_SERR:
+ del_timer(&serr_timer);
+ break;
+
+ case IRQ_PCI_PERR:
+ del_timer(&perr_timer);
+ break;
+ }
+
+ enable_irq(__data);
+}
+
/*
* Warn on PCI errors.
*/
-static void
-dc21285_error(int irq, void *dev_id, struct pt_regs *regs)
+static void dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs)
{
- static unsigned long next_warn;
- unsigned long cmd = *CSR_PCICMD & 0x0000ffff;
- unsigned long ctrl = (*CSR_SA110_CNTL) & 0xffffde07;
- unsigned long irqstatus = *CSR_IRQ_RAWSTATUS;
- int warn = time_after_eq(jiffies, next_warn);
-
- if (machine_is_netwinder())
- warn = 0;
-
- ctrl |= SA110_CNTL_DISCARDTIMER;
-
- if (warn) {
- next_warn = jiffies + HZ;
- printk(KERN_DEBUG "PCI: ");
- }
+ unsigned int cmd;
+ unsigned int status;
- if (irqstatus & (1 << 31)) {
- if (warn)
- printk("parity error ");
- cmd |= 1 << 31;
- }
+ cmd = *CSR_PCICMD;
+ status = cmd >> 16;
+ cmd = cmd & 0xffff;
+
+ if (status & PCI_STATUS_REC_MASTER_ABORT) {
+ printk(KERN_DEBUG "PCI: master abort: ");
+ pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1);
+ printk("\n");
- if (irqstatus & (1 << 30)) {
- if (warn)
- printk("target abort ");
- cmd |= 1 << 28;
+ cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
}
- if (irqstatus & (1 << 29)) {
- if (warn)
- printk("master abort ");
- cmd |= 1 << 29;
- }
+ if (status & PCI_STATUS_REC_TARGET_ABORT) {
+ printk(KERN_DEBUG "PCI: target abort: ");
+ pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1);
+ printk("\n");
- if (irqstatus & (1 << 28)) {
- if (warn)
- printk("data parity error ");
- cmd |= 1 << 24;
+ cmd |= PCI_STATUS_REC_TARGET_ABORT << 16;
}
- if (irqstatus & (1 << 27)) {
- if (warn)
- printk("discard timer expired ");
- ctrl &= ~SA110_CNTL_DISCARDTIMER;
- }
+ *CSR_PCICMD = cmd;
+}
- if (irqstatus & (1 << 23)) {
- if (warn)
- printk("system error ");
- ctrl |= SA110_CNTL_RXSERR;
- }
+static void dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct timer_list *timer = dev_id;
+ unsigned int cntl;
- if (warn)
- printk("pc=[<%08lX>]\n", instruction_pointer(regs));
+ printk(KERN_DEBUG "PCI: system error received: ");
+ pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1);
+ printk("\n");
- pcibios_report_device_errors(warn);
+ cntl = *CSR_SA110_CNTL & 0xffffdf07;
+ *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
- *CSR_PCICMD = cmd;
- *CSR_SA110_CNTL = ctrl;
+ /*
+ * back off this interrupt
+ */
+ disable_irq(irq);
+ timer->expires = jiffies + HZ;
+ add_timer(timer);
}
-static struct irqaction dc21285_error_action = {
- dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL
-};
+static void dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ printk(KERN_DEBUG "PCI: discard timer expired\n");
+ *CSR_SA110_CNTL &= 0xffffde07;
+}
+
+static void dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int cmd;
+
+ printk(KERN_DEBUG "PCI: data parity error detected: ");
+ pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
+ printk("\n");
+
+ cmd = *CSR_PCICMD & 0xffff;
+ *CSR_PCICMD = cmd | 1 << 24;
+}
+
+static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct timer_list *timer = dev_id;
+ unsigned int cmd;
+
+ printk(KERN_DEBUG "PCI: parity error detected: ");
+ pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
+ printk("\n");
+
+ cmd = *CSR_PCICMD & 0xffff;
+ *CSR_PCICMD = cmd | 1 << 31;
+
+ /*
+ * back off this interrupt
+ */
+ disable_irq(irq);
+ timer->expires = jiffies + HZ;
+ add_timer(timer);
+}
void __init dc21285_init(void)
{
- static struct resource csrmem, csrio;
- struct arm_pci_sysdata sysdata;
unsigned long cntl;
- unsigned int mem_size, pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ unsigned int mem_size;
+ unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
- int i;
+ int cfn_mode;
+ /*
+ * These registers need to be set up whether we're the
+ * central function or not.
+ */
mem_size = (unsigned int)high_memory - PAGE_OFFSET;
*CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000;
*CSR_SDRAMBASEOFFSET = 0;
@@ -233,60 +272,93 @@
*CSR_CSRBASEOFFSET = 0;
*CSR_PCIADDR_EXTN = 0;
-#ifdef CONFIG_HOST_FOOTBRIDGE
+ cfn_mode = __footbridge_cfn_mode();
- csrio.flags = IORESOURCE_IO;
- csrio.name = "DC21285";
- csrmem.flags = IORESOURCE_MEM;
- csrmem.name = "DC21285";
-
- allocate_resource(&ioport_resource, &csrio, 128,
- 0xff00, 0xffff, 128, NULL, NULL);
- allocate_resource(&iomem_resource, &csrmem, 128,
- 0xf4000000, 0xf8000000, 128, NULL, NULL);
-
- /*
- * Map our SDRAM at a known address in PCI space, just in case
- * the firmware had other ideas. Using a nonzero base is
- * necessary, since some VGA cards forcefully use PCI addresses
- * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
- */
- *CSR_PCICACHELINESIZE = 0x00002008;
- *CSR_PCICSRBASE = csrmem.start;
- *CSR_PCICSRIOBASE = csrio.start;
- *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET);
- *CSR_PCIROMBASE = 0;
- *CSR_PCICMD = pci_cmd |
+ printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX in "
+ "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ?
+ "central function" : "addin");
+
+ if (cfn_mode) {
+ static struct resource csrmem, csrio;
+ struct arm_pci_sysdata sysdata;
+ int i;
+
+ csrio.flags = IORESOURCE_IO;
+ csrio.name = "DC21285";
+ csrmem.flags = IORESOURCE_MEM;
+ csrmem.name = "DC21285";
+
+ allocate_resource(&ioport_resource, &csrio, 128,
+ 0xff00, 0xffff, 128, NULL, NULL);
+ allocate_resource(&iomem_resource, &csrmem, 128,
+ 0xf4000000, 0xf8000000, 128, NULL, NULL);
+
+ /*
+ * Map our SDRAM at a known address in PCI space, just in case
+ * the firmware had other ideas. Using a nonzero base is
+ * necessary, since some VGA cards forcefully use PCI addresses
+ * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
+ */
+ *CSR_PCICACHELINESIZE = 0x00002008;
+ *CSR_PCICSRBASE = csrmem.start;
+ *CSR_PCICSRIOBASE = csrio.start;
+ *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET);
+ *CSR_PCIROMBASE = 0;
+ *CSR_PCICMD = pci_cmd |
(1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
-#endif
-
- printk(KERN_DEBUG "PCI: DC21285 footbridge, revision %02lX\n",
- *CSR_CLASSREV & 0xff);
-
- for (i = 0; i < MAX_NR_BUS; i++) {
- sysdata.bus[i].features = PCI_COMMAND_FAST_BACK |
- PCI_COMMAND_SERR |
- PCI_COMMAND_PARITY;
- sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST;
- }
- pci_scan_bus(0, &dc21285_ops, &sysdata);
+ for (i = 0; i < MAX_NR_BUS; i++) {
+ sysdata.bus[i].features = PCI_COMMAND_FAST_BACK |
+ PCI_COMMAND_SERR |
+ PCI_COMMAND_PARITY;
+ sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST;
+ }
- pci_cmd |= sysdata.bus[0].features;
+ pci_scan_bus(0, &dc21285_ops, &sysdata);
- printk("Fast back to back PCI transfers %sabled\n",
- (sysdata.bus[0].features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
+ pci_cmd |= sysdata.bus[0].features;
- /*
- * Clear any existing errors - we aren't
- * interested in historical data...
- */
- cntl = *CSR_SA110_CNTL & 0xffffde07;
- *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
- *CSR_PCICMD = pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24;
+ printk("PCI: Fast back to back transfers %sabled\n",
+ (sysdata.bus[0].features & PCI_COMMAND_FAST_BACK) ?
+ "en" : "dis");
+
+ /*
+ * Clear any existing errors - we aren't
+ * interested in historical data...
+ */
+ cntl = *CSR_SA110_CNTL & 0xffffde07;
+ *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
+ *CSR_PCICMD = pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24;
+ } else {
+ /*
+ * If we are not compiled to accept "add-in" mode, then
+ * we are using a constant virt_to_bus translation which
+ * can not hope to cater for the way the host BIOS has
+ * set up the machine.
+ */
+ panic("PCI: this kernel is compiled for central "
+ "function mode only");
+ }
/*
* Initialise PCI error IRQ after we've finished probing
*/
- setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action);
+ request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, "PCI abort", NULL);
+ request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer", NULL);
+ request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL);
+
+ init_timer(&serr_timer);
+ init_timer(&perr_timer);
+
+ serr_timer.data = IRQ_PCI_SERR;
+ serr_timer.function = dc21285_enable_error;
+ perr_timer.data = IRQ_PCI_PERR;
+ perr_timer.function = dc21285_enable_error;
+
+ request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT,
+ "PCI system error", &serr_timer);
+ request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT,
+ "PCI parity error", &perr_timer);
+
+ register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)