summaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/pci
diff options
context:
space:
mode:
authorPrarit Bhargava <prarit@sgi.com>2005-12-23 13:33:25 -0500
committerTony Luck <tony.luck@intel.com>2006-01-13 14:13:08 -0800
commit6d6e420005f3753392b608a614eee8475bdc16f7 (patch)
treea59860fc15ce4e92c00015d068de4aba12a9b889 /arch/ia64/sn/pci
parentcfbb1426bd76c4ba6ec4491c8df2a5dd3d984750 (diff)
[IA64-SGI] Fix sn_flush_device_kernel & spinlock initialization
This patch separates the sn_flush_device_list struct into kernel and common (both kernel and PROM accessible) structures. As it was, if the size of a spinlock_t changed (due to additional CONFIG options, etc.) the sal call which populated the sn_flush_device_list structs would erroneously write data (and cause memory corruption and/or a panic). This patch does the following: 1. Removes sn_flush_device_list and adds sn_flush_device_common and sn_flush_device_kernel. 2. Adds a new SAL call to populate a sn_flush_device_common struct per device, not per widget as previously done. 3. Correctly initializes each device's sn_flush_device_kernel spinlock_t struct (before it was only doing each widget's first device). Signed-off-by: Prarit Bhargava <prarit@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/sn/pci')
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_dma.c34
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c20
2 files changed, 28 insertions, 26 deletions
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index 34093476e96..e68332d9317 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -218,7 +218,9 @@ void sn_dma_flush(uint64_t addr)
uint64_t flags;
uint64_t itte;
struct hubdev_info *hubinfo;
- volatile struct sn_flush_device_list *p;
+ volatile struct sn_flush_device_kernel *p;
+ volatile struct sn_flush_device_common *common;
+
struct sn_flush_nasid_entry *flush_nasid_list;
if (!sn_ioif_inited)
@@ -268,17 +270,17 @@ void sn_dma_flush(uint64_t addr)
p = &flush_nasid_list->widget_p[wid_num][0];
/* find a matching BAR */
- for (i = 0; i < DEV_PER_WIDGET; i++) {
+ for (i = 0; i < DEV_PER_WIDGET; i++,p++) {
+ common = p->common;
for (j = 0; j < PCI_ROM_RESOURCE; j++) {
- if (p->sfdl_bar_list[j].start == 0)
+ if (common->sfdl_bar_list[j].start == 0)
break;
- if (addr >= p->sfdl_bar_list[j].start
- && addr <= p->sfdl_bar_list[j].end)
+ if (addr >= common->sfdl_bar_list[j].start
+ && addr <= common->sfdl_bar_list[j].end)
break;
}
- if (j < PCI_ROM_RESOURCE && p->sfdl_bar_list[j].start != 0)
+ if (j < PCI_ROM_RESOURCE && common->sfdl_bar_list[j].start != 0)
break;
- p++;
}
/* if no matching BAR, return without doing anything. */
@@ -304,24 +306,24 @@ void sn_dma_flush(uint64_t addr)
if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) {
return;
} else {
- pcireg_wrb_flush_get(p->sfdl_pcibus_info,
- (p->sfdl_slot - 1));
+ pcireg_wrb_flush_get(common->sfdl_pcibus_info,
+ (common->sfdl_slot - 1));
}
} else {
- spin_lock_irqsave(&((struct sn_flush_device_list *)p)->
- sfdl_flush_lock, flags);
-
- *p->sfdl_flush_addr = 0;
+ spin_lock_irqsave((spinlock_t *)&p->sfdl_flush_lock,
+ flags);
+ *common->sfdl_flush_addr = 0;
/* force an interrupt. */
- *(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
+ *(volatile uint32_t *)(common->sfdl_force_int_addr) = 1;
/* wait for the interrupt to come back. */
- while (*(p->sfdl_flush_addr) != 0x10f)
+ while (*(common->sfdl_flush_addr) != 0x10f)
cpu_relax();
/* okay, everything is synched up. */
- spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
+ spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock,
+ flags);
}
return;
}
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 1f500c81002..e328e948175 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -92,7 +92,8 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
cnodeid_t near_cnode;
struct hubdev_info *hubdev_info;
struct pcibus_info *soft;
- struct sn_flush_device_list *sn_flush_device_list;
+ struct sn_flush_device_kernel *sn_flush_device_kernel;
+ struct sn_flush_device_common *common;
if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) {
return NULL;
@@ -137,20 +138,19 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
if (hubdev_info->hdi_flush_nasid_list.widget_p) {
- sn_flush_device_list = hubdev_info->hdi_flush_nasid_list.
+ sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list.
widget_p[(int)soft->pbi_buscommon.bs_xid];
- if (sn_flush_device_list) {
+ if (sn_flush_device_kernel) {
for (j = 0; j < DEV_PER_WIDGET;
- j++, sn_flush_device_list++) {
- if (sn_flush_device_list->sfdl_slot == -1)
+ j++, sn_flush_device_kernel++) {
+ common = sn_flush_device_kernel->common;
+ if (common->sfdl_slot == -1)
continue;
- if ((sn_flush_device_list->
- sfdl_persistent_segment ==
+ if ((common->sfdl_persistent_segment ==
soft->pbi_buscommon.bs_persist_segment) &&
- (sn_flush_device_list->
- sfdl_persistent_busnum ==
+ (common->sfdl_persistent_busnum ==
soft->pbi_buscommon.bs_persist_busnum))
- sn_flush_device_list->sfdl_pcibus_info =
+ common->sfdl_pcibus_info =
soft;
}
}