patch-2.4.21 linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c
Next file: linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c
Previous file: linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c
Back to the patch index
Back to the overall index
- Lines: 723
- Date:
2003-06-13 07:51:31.000000000 -0700
- Orig file:
linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c
- Orig date:
2002-08-02 17:39:43.000000000 -0700
diff -urN linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c
@@ -4,11 +4,10 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
*/
#include <linux/types.h>
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <asm/sn/sgi.h>
@@ -39,11 +38,11 @@
#define rmalloc atealloc
#endif
-unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines);
+unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots);
pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
void pcibr_intr_free(pcibr_intr_t);
void pcibr_setpciint(xtalk_intr_t);
-int pcibr_intr_connect(pcibr_intr_t);
+int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);
void pcibr_intr_disconnect(pcibr_intr_t);
devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t);
@@ -58,9 +57,9 @@
unsigned
pcibr_intr_bits(pciio_info_t info,
- pciio_intr_line_t lines)
+ pciio_intr_line_t lines, int nslots)
{
- pciio_slot_t slot = pciio_info_slot_get(info);
+ pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(info);
unsigned bbits = 0;
/*
@@ -79,7 +78,7 @@
* 7 7 3 7 3
*/
- if (slot < 8) {
+ if (slot < nslots) {
if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C))
bbits |= 1 << slot;
if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D))
@@ -165,20 +164,26 @@
* to check if a specific Bridge b_int_status bit is set, and if so,
* cause the setting of the corresponding interrupt bit.
*
- * On a XBridge (IP35), we do this by writing the appropriate Bridge Force
- * Interrupt register.
+ * On a XBridge (SN1), we do this by writing the appropriate Bridge Force
+ * Interrupt register. On SN0, or SN1 with an older Bridge, the Bridge
+ * Force Interrupt register does not exist, so we write the Hub
+ * INT_PEND_MOD register directly. Likewise for Octane, where we write the
+ * Heart Set Interrupt Status register directly.
*/
void
pcibr_force_interrupt(pcibr_intr_wrap_t wrap)
{
+#ifdef PIC_LATER
unsigned bit;
pcibr_soft_t pcibr_soft = wrap->iw_soft;
bridge_t *bridge = pcibr_soft->bs_base;
- cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl);
- bit = wrap->iw_intr;
+ bit = wrap->iw_ibit;
- if (pcibr_soft->bs_xbridge) {
+ PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl,
+ "pcibr_force_interrupt: bit=0x%x\n", bit));
+
+ if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
bridge->b_force_pin[bit].intr = 1;
} else if ((1 << bit) & *wrap->iw_stat) {
cpuid_t cpu;
@@ -187,11 +192,10 @@
pcibr_soft->bs_intr[bit].bsi_xtalk_intr;
intr_bit = (short) xtalk_intr_vector_get(xtalk_intr);
- cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
-#if defined(CONFIG_IA64_SGI_SN1)
+ cpu = xtalk_intr_cpuid_get(xtalk_intr);
REMOTE_CPU_SEND_INTR(cpu, intr_bit);
-#endif
}
+#endif /* PIC_LATER */
}
/*ARGSUSED */
@@ -202,12 +206,11 @@
devfs_handle_t owner_dev)
{
pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl);
- pciio_slot_t pciio_slot = pcibr_info->f_slot;
+ pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn;
bridge_t *bridge = pcibr_soft->bs_base;
int is_threaded = 0;
- int thread_swlevel;
xtalk_intr_t *xtalk_intr_p;
pcibr_intr_t *pcibr_intr_p;
@@ -222,41 +225,32 @@
pcibr_intr_list_t intr_list;
bridgereg_t int_dev;
-#if DEBUG && INTR_DEBUG
- printk("%v: pcibr_intr_alloc\n"
- "%v:%s%s%s%s%s\n",
- owner_dev, pconn_vhdl,
- !(lines & 15) ? " No INTs?" : "",
- lines & 1 ? " INTA" : "",
- lines & 2 ? " INTB" : "",
- lines & 4 ? " INTC" : "",
- lines & 8 ? " INTD" : "");
-#endif
+
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "pcibr_intr_alloc: %s%s%s%s%s\n",
+ !(lines & 15) ? " No INTs?" : "",
+ lines & 1 ? " INTA" : "",
+ lines & 2 ? " INTB" : "",
+ lines & 4 ? " INTC" : "",
+ lines & 8 ? " INTD" : ""));
NEW(pcibr_intr);
if (!pcibr_intr)
return NULL;
- if (dev_desc) {
- cpuid_t intr_target_from_desc(device_desc_t, int);
- } else {
- extern int default_intr_pri;
-
- is_threaded = 1; /* PCI interrupts are threaded, by default */
- thread_swlevel = default_intr_pri;
- }
-
pcibr_intr->bi_dev = pconn_vhdl;
pcibr_intr->bi_lines = lines;
pcibr_intr->bi_soft = pcibr_soft;
pcibr_intr->bi_ibits = 0; /* bits will be added below */
+ pcibr_intr->bi_func = 0; /* unset until connect */
+ pcibr_intr->bi_arg = 0; /* unset until connect */
pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD;
pcibr_intr->bi_mustruncpu = CPU_NONE;
pcibr_intr->bi_ibuf.ib_in = 0;
pcibr_intr->bi_ibuf.ib_out = 0;
mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock);
-
- pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines);
+ pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines,
+ PCIBR_NUM_SLOTS(pcibr_soft));
/*
@@ -265,9 +259,8 @@
* to, and make sure there are xtalk resources
* allocated for it.
*/
-#if DEBUG && INTR_DEBUG
- printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "pcibr_intr_alloc: pcibr_int_bits: 0x%x\n", pcibr_int_bits));
for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) {
if (pcibr_int_bits & (1 << pcibr_int_bit)) {
xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
@@ -282,10 +275,9 @@
* ordering problems with DMA, completion interrupts, and error
* interrupts. (Use of xconn_vhdl forces this.)
*
- * 2) On IP35, addressing constraints on IP35 and Bridge force
+ * 2) On SN1, addressing constraints on SN1 and Bridge force
* us to use a single PI number for all interrupts from a
- * single Bridge. (IP35-specific code forces this, and we
- * verify in pcibr_setwidint.)
+ * single Bridge. (SN1-specific code forces this).
*/
/*
@@ -298,9 +290,9 @@
*/
xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc,
owner_dev);
-#if DEBUG && INTR_DEBUG
- printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr);
-#endif
+
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "pcibr_intr_alloc: xtalk_intr=0x%x\n", xtalk_intr));
/* both an assert and a runtime check on this:
* we need to check in non-DEBUG kernels, and
@@ -338,10 +330,9 @@
int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit);
bridge->b_int_device = int_dev; /* XXXMP */
-#if DEBUG && INTR_DEBUG
- printk("%v: bridge intr bit %d clears my wrb\n",
- pconn_vhdl, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "bridge intr bit %d clears my wrb\n",
+ pcibr_int_bit));
} else {
/* someone else got one allocated first;
* free the one we just created, and
@@ -373,25 +364,17 @@
intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg);
intr_list_p =
&pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
-#if DEBUG && INTR_DEBUG
-#if defined(SUPPORT_PRINTING_V_FORMAT)
- printk("0x%x: Bridge bit %d wrap=0x%x\n",
- pconn_vhdl, pcibr_int_bit,
- pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
-#else
- printk("%v: Bridge bit %d wrap=0x%x\n",
- pconn_vhdl, pcibr_int_bit,
- pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
-#endif
-#endif
+
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "Bridge bit 0x%x wrap=0x%x\n", pcibr_int_bit,
+ pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap));
if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
/* we are the first interrupt on this bridge bit.
*/
-#if DEBUG && INTR_DEBUG
- printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n",
- pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "INT 0x%x (bridge bit %d) allocated [FIRST]\n",
+ pcibr_int_bits, pcibr_int_bit));
continue;
}
intr_list = *intr_list_p;
@@ -402,10 +385,9 @@
* don't need our intr_entry.
*/
DEL(intr_entry);
-#if DEBUG && INTR_DEBUG
- printk("%v INT 0x%x (bridge bit %d) replaces erased first\n",
- pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "INT 0x%x (bridge bit %d) replaces erased first\n",
+ pcibr_int_bits, pcibr_int_bit));
continue;
}
intr_list_p = &intr_list->il_next;
@@ -413,10 +395,9 @@
/* we are the new second interrupt on this bit.
*/
pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1;
-#if DEBUG && INTR_DEBUG
- printk("%v INT 0x%x (bridge bit %d) is new SECOND\n",
- pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "INT 0x%x (bridge bit %d) is new SECOND\n",
+ pcibr_int_bits, pcibr_int_bit));
continue;
}
while (1) {
@@ -427,20 +408,19 @@
* don't need our intr_entry.
*/
DEL(intr_entry);
-#if DEBUG && INTR_DEBUG
- printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n",
- pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "INT 0x%x (bridge bit %d) replaces erase Nth\n",
+ pcibr_int_bits, pcibr_int_bit));
break;
}
intr_list_p = &intr_list->il_next;
if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
/* entry appended to share list
*/
-#if DEBUG && INTR_DEBUG
- printk("%v INT 0x%x (bridge bit %d) is new Nth\n",
- pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+ "INT 0x%x (bridge bit %d) is new Nth\n",
+ pcibr_int_bits, pcibr_int_bit));
break;
}
/* step to next record in chain
@@ -479,10 +459,11 @@
if (compare_and_swap_ptr((void **) &intr_list->il_intr,
pcibr_intr,
NULL)) {
-#if DEBUG && INTR_DEBUG
- printk("%s: cleared a handler from bit %d\n",
- pcibr_soft->bs_name, pcibr_int_bit);
-#endif
+
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC,
+ pcibr_intr->bi_dev,
+ "pcibr_intr_free: cleared hdlr from bit 0x%x\n",
+ pcibr_int_bit));
}
/* If this interrupt line is not being shared between multiple
* devices release the xtalk interrupt resources.
@@ -515,34 +496,49 @@
void
pcibr_setpciint(xtalk_intr_t xtalk_intr)
{
- iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr);
- xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr);
- bridgereg_t *int_addr = (bridgereg_t *)
- xtalk_intr_sfarg_get(xtalk_intr);
-
- *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
- (BRIDGE_INT_ADDR_FLD & vect));
+ iopaddr_t addr;
+ xtalk_intr_vector_t vect;
+ devfs_handle_t vhdl;
+ bridge_t *bridge;
+
+ addr = xtalk_intr_addr_get(xtalk_intr);
+ vect = xtalk_intr_vector_get(xtalk_intr);
+ vhdl = xtalk_intr_dev_get(xtalk_intr);
+ bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0);
+
+ if (is_pic(bridge)) {
+ picreg_t *int_addr;
+ int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr);
+ *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) |
+ (PIC_INT_ADDR_HOST & addr));
+ } else {
+ bridgereg_t *int_addr;
+ int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr);
+ *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
+ (BRIDGE_INT_ADDR_FLD & vect));
+ }
}
/*ARGSUSED */
int
-pcibr_intr_connect(pcibr_intr_t pcibr_intr)
+pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg)
{
pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft;
bridge_t *bridge = pcibr_soft->bs_base;
unsigned pcibr_int_bits = pcibr_intr->bi_ibits;
unsigned pcibr_int_bit;
- bridgereg_t b_int_enable;
+ uint64_t int_enable;
unsigned long s;
if (pcibr_intr == NULL)
return -1;
-#if DEBUG && INTR_DEBUG
- printk("%v: pcibr_intr_connect\n",
- pcibr_intr->bi_dev);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+ "pcibr_intr_connect: intr_func=0x%x\n",
+ pcibr_intr));
+ pcibr_intr->bi_func = intr_func;
+ pcibr_intr->bi_arg = intr_arg;
*((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED;
/*
@@ -553,9 +549,12 @@
*/
for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
if (pcibr_int_bits & (1 << pcibr_int_bit)) {
+ pcibr_intr_wrap_t intr_wrap;
xtalk_intr_t xtalk_intr;
+ void *int_addr;
xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
+ intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
/*
* If this interrupt line is being shared and the connect has
@@ -569,21 +568,43 @@
* Use the pcibr wrapper function to handle all Bridge interrupts
* regardless of whether the interrupt line is shared or not.
*/
- xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint,
- (void *)&(bridge->b_int_addr[pcibr_int_bit].addr));
+ if (IS_PIC_SOFT(pcibr_soft))
+ int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]);
+ else
+ int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr);
+
+ xtalk_intr_connect(xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap,
+ (xtalk_intr_setfunc_t) pcibr_setpciint,
+ (void *)int_addr);
+
pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1;
-#if DEBUG && INTR_DEBUG
- printk("%v bridge bit %d wrapper connected\n",
- pcibr_intr->bi_dev, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+ "pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, "
+ "pcibr_int_bit=0x%x\n", int_addr,
+ (is_pic(bridge) ?
+ *(picreg_t *)int_addr : *(bridgereg_t *)int_addr),
+ pcibr_int_bit));
}
- s = pcibr_lock(pcibr_soft);
- b_int_enable = bridge->b_int_enable;
- b_int_enable |= pcibr_int_bits;
- bridge->b_int_enable = b_int_enable;
- bridge->b_wid_tflush; /* wait until Bridge PIO complete */
- pcibr_unlock(pcibr_soft, s);
+
+ /* PIC WAR. PV# 854697
+ * On PIC we must write 64-bit MMRs with 64-bit stores
+ */
+ s = pcibr_lock(pcibr_soft);
+ if (IS_PIC_SOFT(pcibr_soft) &&
+ PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+ int_enable = bridge->p_int_enable_64;
+ int_enable |= pcibr_int_bits;
+ bridge->p_int_enable_64 = int_enable;
+ } else {
+ bridgereg_t int_enable;
+
+ int_enable = bridge->b_int_enable;
+ int_enable |= pcibr_int_bits;
+ bridge->b_int_enable = int_enable;
+ }
+ bridge->b_wid_tflush; /* wait until Bridge PIO complete */
+ pcibr_unlock(pcibr_soft, s);
return 0;
}
@@ -596,13 +617,15 @@
bridge_t *bridge = pcibr_soft->bs_base;
unsigned pcibr_int_bits = pcibr_intr->bi_ibits;
unsigned pcibr_int_bit;
- bridgereg_t b_int_enable;
+ pcibr_intr_wrap_t intr_wrap;
+ uint64_t int_enable;
unsigned long s;
/* Stop calling the function. Now.
*/
*((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED;
-
+ pcibr_intr->bi_func = 0;
+ pcibr_intr->bi_arg = 0;
/*
* For each PCI interrupt line requested, figure
* out which Bridge PCI Interrupt Line it maps
@@ -619,15 +642,30 @@
if (!pcibr_int_bits)
return;
+ /* PIC WAR. PV# 854697
+ * On PIC we must write 64-bit MMRs with 64-bit stores
+ */
s = pcibr_lock(pcibr_soft);
- b_int_enable = bridge->b_int_enable;
- b_int_enable &= ~pcibr_int_bits;
- bridge->b_int_enable = b_int_enable;
+ if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+ int_enable = bridge->p_int_enable_64;
+ int_enable &= ~pcibr_int_bits;
+ bridge->p_int_enable_64 = int_enable;
+ } else {
+ int_enable = (uint64_t)bridge->b_int_enable;
+ int_enable &= ~pcibr_int_bits;
+ bridge->b_int_enable = (bridgereg_t)int_enable;
+ }
bridge->b_wid_tflush; /* wait until Bridge PIO complete */
pcibr_unlock(pcibr_soft, s);
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+ "pcibr_intr_disconnect: disabled int_bits=0x%x\n",
+ pcibr_int_bits));
+
for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
if (pcibr_int_bits & (1 << pcibr_int_bit)) {
+ void *int_addr;
+
/* if the interrupt line is now shared,
* do not disconnect it.
*/
@@ -637,10 +675,9 @@
xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr);
pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0;
-#if DEBUG && INTR_DEBUG
- printk("%s: xtalk disconnect done for Bridge bit %d\n",
- pcibr_soft->bs_name, pcibr_int_bit);
-#endif
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+ "pcibr_intr_disconnect: disconnect int_bits=0x%x\n",
+ pcibr_int_bits));
/* if we are sharing the interrupt line,
* connect us up; this closes the hole
@@ -650,9 +687,22 @@
if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
continue;
+ intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
+ if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
+ continue;
+
+ if (IS_PIC_SOFT(pcibr_soft))
+ int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]);
+ else
+ int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr);
+
xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr,
+ pcibr_intr_func, (intr_arg_t) intr_wrap,
(xtalk_intr_setfunc_t)pcibr_setpciint,
- (void *) &(bridge->b_int_addr[pcibr_int_bit].addr));
+ (void *)pcibr_int_bit);
+ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+ "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n",
+ pcibr_int_bit));
}
}
@@ -729,6 +779,10 @@
bridge->b_wid_int_upper = NEW_b_wid_int_upper;
bridge->b_wid_int_lower = NEW_b_wid_int_lower;
bridge->b_int_host_err = vect;
+
+printk("pcibr_setwidint: b_wid_int_upper 0x%x b_wid_int_lower 0x%x b_int_host_err 0x%x\n",
+ NEW_b_wid_int_upper, NEW_b_wid_int_lower, vect);
+
}
/*
@@ -752,6 +806,9 @@
XTALK_ADDR_TO_UPPER(addr));
bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
bridge->b_int_host_err = vect;
+printk("pcibr_xintr_preset: b_wid_int_upper 0x%lx b_wid_int_lower 0x%lx b_int_host_err 0x%x\n",
+ ( (0x000F0000 & (targ << 16)) | XTALK_ADDR_TO_UPPER(addr)),
+ XTALK_ADDR_TO_LOWER(addr), vect);
/* turn on all interrupts except
* the PCI interrupt requests,
@@ -794,12 +851,37 @@
{
pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg;
reg_p wrbf;
+ intr_func_t func;
pcibr_intr_t intr;
pcibr_intr_list_t list;
int clearit;
int do_nonthreaded = 1;
int is_threaded = 0;
int x = 0;
+ pcibr_soft_t pcibr_soft = wrap->iw_soft;
+ bridge_t *bridge = pcibr_soft->bs_base;
+ uint64_t p_enable = pcibr_soft->bs_int_enable;
+ int bit = wrap->iw_ibit;
+
+ /*
+ * PIC WAR. PV#855272
+ * Early attempt at a workaround for the runaway
+ * interrupt problem. Briefly disable the enable bit for
+ * this device.
+ */
+ if (IS_PIC_SOFT(pcibr_soft) &&
+ PCIBR_WAR_ENABLED(PV855272, pcibr_soft)) {
+ unsigned s;
+
+ /* disable-enable interrupts for this bridge pin */
+
+ p_enable &= ~(1 << bit);
+ s = pcibr_lock(pcibr_soft);
+ bridge->p_int_enable_64 = p_enable;
+ p_enable |= (1 << bit);
+ bridge->p_int_enable_64 = p_enable;
+ pcibr_unlock(pcibr_soft, s);
+ }
/*
* If any handler is still running from a previous interrupt
@@ -821,35 +903,31 @@
clearit = 1;
while (do_nonthreaded) {
for (list = wrap->iw_list; list != NULL; list = list->il_next) {
- if ((intr = list->il_intr) &&
- (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
+ if ((intr = list->il_intr) && (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
- /*
- * This device may have initiated write
- * requests since the bridge last saw
- * an edge on this interrupt input; flushing
- * the buffer prior to invoking the handler
- * should help but may not be sufficient if we
- * get more requests after the flush, followed
- * by the card deciding it wants service, before
- * the interrupt handler checks to see if things need
- * to be done.
- *
- * There is a similar race condition if
- * an interrupt handler loops around and
- * notices further service is required.
- * Perhaps we need to have an explicit
- * call that interrupt handlers need to
- * do between noticing that DMA to memory
- * has completed, but before observing the
- * contents of memory?
- */
-
- if ((do_nonthreaded) && (!is_threaded)) {
- /* Non-threaded.
- * Call the interrupt handler at interrupt level
- */
+ /*
+ * This device may have initiated write
+ * requests since the bridge last saw
+ * an edge on this interrupt input; flushing
+ * the buffer prior to invoking the handler
+ * should help but may not be sufficient if we
+ * get more requests after the flush, followed
+ * by the card deciding it wants service, before
+ * the interrupt handler checks to see if things need
+ * to be done.
+ *
+ * There is a similar race condition if
+ * an interrupt handler loops around and
+ * notices further service is required.
+ * Perhaps we need to have an explicit
+ * call that interrupt handlers need to
+ * do between noticing that DMA to memory
+ * has completed, but before observing the
+ * contents of memory?
+ */
+ if ((do_nonthreaded) && (!is_threaded)) {
+ /* Non-threaded - Call the interrupt handler at interrupt level */
/* Only need to flush write buffers if sharing */
if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) {
@@ -864,21 +942,23 @@
(void *)list->il_intr->bi_dev, (long) wrbf);
#endif
}
+ func = intr->bi_func;
+ if ( func )
+ func(intr->bi_arg);
}
-
clearit = 0;
}
}
+ do_nonthreaded = 0;
- do_nonthreaded = 0;
- /*
- * If the non-threaded handler was the last to complete,
- * (i.e., no threaded handlers still running) force an
- * interrupt to avoid a potential deadlock situation.
- */
- if (wrap->iw_hdlrcnt == 0) {
- pcibr_force_interrupt(wrap);
- }
+ /*
+ * If the non-threaded handler was the last to complete,
+ * (i.e., no threaded handlers still running) force an
+ * interrupt to avoid a potential deadlock situation.
+ */
+ if (wrap->iw_hdlrcnt == 0) {
+ pcibr_force_interrupt(wrap);
+ }
}
/* If there were no handlers,
@@ -892,14 +972,24 @@
if (clearit) {
pcibr_soft_t pcibr_soft = wrap->iw_soft;
bridge_t *bridge = pcibr_soft->bs_base;
- bridgereg_t b_int_enable;
- bridgereg_t mask = 1 << wrap->iw_intr;
+ bridgereg_t int_enable;
+ bridgereg_t mask = 1 << wrap->iw_ibit;
unsigned long s;
+ /* PIC BRINUGP WAR (PV# 854697):
+ * On PIC we must write 64-bit MMRs with 64-bit stores
+ */
s = pcibr_lock(pcibr_soft);
- b_int_enable = bridge->b_int_enable;
- b_int_enable &= ~mask;
- bridge->b_int_enable = b_int_enable;
+ if (IS_PIC_SOFT(pcibr_soft) &&
+ PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+ int_enable = bridge->p_int_enable_64;
+ int_enable &= ~mask;
+ bridge->p_int_enable_64 = int_enable;
+ } else {
+ int_enable = (uint64_t)bridge->b_int_enable;
+ int_enable &= ~mask;
+ bridge->b_int_enable = (bridgereg_t)int_enable;
+ }
bridge->b_wid_tflush; /* wait until Bridge PIO complete */
pcibr_unlock(pcibr_soft, s);
return;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)