[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>

authored by Prarit Bhargava and committed by Tony Luck 6d6e4200 cfbb1426

+94 -71
+12 -4
arch/ia64/sn/include/xtalk/hubdev.h
··· 26 26 #define IIO_NUM_ITTES 7 27 27 #define HUB_NUM_BIG_WINDOW (IIO_NUM_ITTES - 1) 28 28 29 - struct sn_flush_device_list { 29 + /* This struct is shared between the PROM and the kernel. 30 + * Changes to this struct will require corresponding changes to the kernel. 31 + */ 32 + struct sn_flush_device_common { 30 33 int sfdl_bus; 31 34 int sfdl_slot; 32 35 int sfdl_pin; 33 - struct bar_list { 36 + struct common_bar_list { 34 37 unsigned long start; 35 38 unsigned long end; 36 39 } sfdl_bar_list[6]; ··· 43 40 uint32_t sfdl_persistent_busnum; 44 41 uint32_t sfdl_persistent_segment; 45 42 struct pcibus_info *sfdl_pcibus_info; 43 + }; 44 + 45 + /* This struct is kernel only and is not used by the PROM */ 46 + struct sn_flush_device_kernel { 46 47 spinlock_t sfdl_flush_lock; 48 + struct sn_flush_device_common *common; 47 49 }; 48 50 49 51 /* 50 - * **widget_p - Used as an array[wid_num][device] of sn_flush_device_list. 52 + * **widget_p - Used as an array[wid_num][device] of sn_flush_device_kernel. 51 53 */ 52 54 struct sn_flush_nasid_entry { 53 - struct sn_flush_device_list **widget_p; /* Used as a array of wid_num */ 55 + struct sn_flush_device_kernel **widget_p; // Used as an array of wid_num 54 56 uint64_t iio_itte[8]; 55 57 }; 56 58
+52 -40
arch/ia64/sn/kernel/io_init.c
··· 76 76 }; 77 77 78 78 /* 79 - * Retrieve the DMA Flush List given nasid. This list is needed 80 - * to implement the WAR - Flush DMA data on PIO Reads. 79 + * Retrieve the DMA Flush List given nasid, widget, and device. 80 + * This list is needed to implement the WAR - Flush DMA data on PIO Reads. 81 81 */ 82 - static inline uint64_t 83 - sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address) 82 + static inline u64 83 + sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num, 84 + u64 address) 84 85 { 85 86 86 87 struct ia64_sal_retval ret_stuff; ··· 89 88 ret_stuff.v0 = 0; 90 89 91 90 SAL_CALL_NOLOCK(ret_stuff, 92 - (u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST, 93 - (u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0, 94 - 0); 95 - return ret_stuff.v0; 91 + (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST, 92 + (u64) nasid, (u64) widget_num, 93 + (u64) device_num, (u64) address, 0, 0, 0); 94 + return ret_stuff.status; 96 95 97 96 } 98 97 99 98 /* 100 99 * Retrieve the hub device info structure for the given nasid. 101 100 */ 102 - static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address) 101 + static inline u64 sal_get_hubdev_info(u64 handle, u64 address) 103 102 { 104 103 105 104 struct ia64_sal_retval ret_stuff; ··· 115 114 /* 116 115 * Retrieve the pci bus information given the bus number. 117 116 */ 118 - static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) 117 + static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) 119 118 { 120 119 121 120 struct ia64_sal_retval ret_stuff; ··· 131 130 /* 132 131 * Retrieve the pci device information given the bus and device|function number. 133 132 */ 134 - static inline uint64_t 133 + static inline u64 135 134 sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, 136 135 u64 sn_irq_info) 137 136 { ··· 171 170 */ 172 171 static void sn_fixup_ionodes(void) 173 172 { 174 - 175 - struct sn_flush_device_list *sn_flush_device_list; 173 + struct sn_flush_device_kernel *sn_flush_device_kernel; 174 + struct sn_flush_device_kernel *dev_entry; 176 175 struct hubdev_info *hubdev; 177 - uint64_t status; 178 - uint64_t nasid; 179 - int i, widget; 176 + u64 status; 177 + u64 nasid; 178 + int i, widget, device; 180 179 181 180 /* 182 181 * Get SGI Specific HUB chipset information. ··· 187 186 nasid = cnodeid_to_nasid(i); 188 187 hubdev->max_segment_number = 0xffffffff; 189 188 hubdev->max_pcibus_number = 0xff; 190 - status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev)); 189 + status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev)); 191 190 if (status) 192 191 continue; 193 192 ··· 214 213 215 214 hubdev->hdi_flush_nasid_list.widget_p = 216 215 kmalloc((HUB_WIDGET_ID_MAX + 1) * 217 - sizeof(struct sn_flush_device_list *), GFP_KERNEL); 218 - 216 + sizeof(struct sn_flush_device_kernel *), 217 + GFP_KERNEL); 219 218 memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0, 220 219 (HUB_WIDGET_ID_MAX + 1) * 221 - sizeof(struct sn_flush_device_list *)); 220 + sizeof(struct sn_flush_device_kernel *)); 222 221 223 222 for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) { 224 - sn_flush_device_list = kmalloc(DEV_PER_WIDGET * 225 - sizeof(struct 226 - sn_flush_device_list), 227 - GFP_KERNEL); 228 - memset(sn_flush_device_list, 0x0, 223 + sn_flush_device_kernel = kmalloc(DEV_PER_WIDGET * 224 + sizeof(struct 225 + sn_flush_device_kernel), 226 + GFP_KERNEL); 227 + if (!sn_flush_device_kernel) 228 + BUG(); 229 + memset(sn_flush_device_kernel, 0x0, 229 230 DEV_PER_WIDGET * 230 - sizeof(struct sn_flush_device_list)); 231 + sizeof(struct sn_flush_device_kernel)); 231 232 232 - status = 233 - sal_get_widget_dmaflush_list(nasid, widget, 234 - (uint64_t) 235 - __pa 236 - (sn_flush_device_list)); 237 - if (status) { 238 - kfree(sn_flush_device_list); 239 - continue; 233 + dev_entry = sn_flush_device_kernel; 234 + for (device = 0; device < DEV_PER_WIDGET; 235 + device++,dev_entry++) { 236 + dev_entry->common = kmalloc(sizeof(struct 237 + sn_flush_device_common), 238 + GFP_KERNEL); 239 + if (!dev_entry->common) 240 + BUG(); 241 + memset(dev_entry->common, 0x0, sizeof(struct 242 + sn_flush_device_common)); 243 + 244 + status = sal_get_device_dmaflush_list(nasid, 245 + widget, 246 + device, 247 + (u64)(dev_entry->common)); 248 + if (status) 249 + BUG(); 250 + 251 + spin_lock_init(&dev_entry->sfdl_flush_lock); 240 252 } 241 253 242 - spin_lock_init(&sn_flush_device_list->sfdl_flush_lock); 243 - hubdev->hdi_flush_nasid_list.widget_p[widget] = 244 - sn_flush_device_list; 245 - } 246 - 254 + if (sn_flush_device_kernel) 255 + hubdev->hdi_flush_nasid_list.widget_p[widget] = 256 + sn_flush_device_kernel; 257 + } 247 258 } 248 - 249 259 } 250 260 251 261 /*
+18 -16
arch/ia64/sn/pci/pcibr/pcibr_dma.c
··· 218 218 uint64_t flags; 219 219 uint64_t itte; 220 220 struct hubdev_info *hubinfo; 221 - volatile struct sn_flush_device_list *p; 221 + volatile struct sn_flush_device_kernel *p; 222 + volatile struct sn_flush_device_common *common; 223 + 222 224 struct sn_flush_nasid_entry *flush_nasid_list; 223 225 224 226 if (!sn_ioif_inited) ··· 270 268 p = &flush_nasid_list->widget_p[wid_num][0]; 271 269 272 270 /* find a matching BAR */ 273 - for (i = 0; i < DEV_PER_WIDGET; i++) { 271 + for (i = 0; i < DEV_PER_WIDGET; i++,p++) { 272 + common = p->common; 274 273 for (j = 0; j < PCI_ROM_RESOURCE; j++) { 275 - if (p->sfdl_bar_list[j].start == 0) 274 + if (common->sfdl_bar_list[j].start == 0) 276 275 break; 277 - if (addr >= p->sfdl_bar_list[j].start 278 - && addr <= p->sfdl_bar_list[j].end) 276 + if (addr >= common->sfdl_bar_list[j].start 277 + && addr <= common->sfdl_bar_list[j].end) 279 278 break; 280 279 } 281 - if (j < PCI_ROM_RESOURCE && p->sfdl_bar_list[j].start != 0) 280 + if (j < PCI_ROM_RESOURCE && common->sfdl_bar_list[j].start != 0) 282 281 break; 283 - p++; 284 282 } 285 283 286 284 /* if no matching BAR, return without doing anything. */ ··· 306 304 if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) { 307 305 return; 308 306 } else { 309 - pcireg_wrb_flush_get(p->sfdl_pcibus_info, 310 - (p->sfdl_slot - 1)); 307 + pcireg_wrb_flush_get(common->sfdl_pcibus_info, 308 + (common->sfdl_slot - 1)); 311 309 } 312 310 } else { 313 - spin_lock_irqsave(&((struct sn_flush_device_list *)p)-> 314 - sfdl_flush_lock, flags); 315 - 316 - *p->sfdl_flush_addr = 0; 311 + spin_lock_irqsave((spinlock_t *)&p->sfdl_flush_lock, 312 + flags); 313 + *common->sfdl_flush_addr = 0; 317 314 318 315 /* force an interrupt. */ 319 - *(volatile uint32_t *)(p->sfdl_force_int_addr) = 1; 316 + *(volatile uint32_t *)(common->sfdl_force_int_addr) = 1; 320 317 321 318 /* wait for the interrupt to come back. */ 322 - while (*(p->sfdl_flush_addr) != 0x10f) 319 + while (*(common->sfdl_flush_addr) != 0x10f) 323 320 cpu_relax(); 324 321 325 322 /* okay, everything is synched up. */ 326 - spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags); 323 + spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, 324 + flags); 327 325 } 328 326 return; 329 327 }
+10 -10
arch/ia64/sn/pci/pcibr/pcibr_provider.c
··· 92 92 cnodeid_t near_cnode; 93 93 struct hubdev_info *hubdev_info; 94 94 struct pcibus_info *soft; 95 - struct sn_flush_device_list *sn_flush_device_list; 95 + struct sn_flush_device_kernel *sn_flush_device_kernel; 96 + struct sn_flush_device_common *common; 96 97 97 98 if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) { 98 99 return NULL; ··· 138 137 hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); 139 138 140 139 if (hubdev_info->hdi_flush_nasid_list.widget_p) { 141 - sn_flush_device_list = hubdev_info->hdi_flush_nasid_list. 140 + sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list. 142 141 widget_p[(int)soft->pbi_buscommon.bs_xid]; 143 - if (sn_flush_device_list) { 142 + if (sn_flush_device_kernel) { 144 143 for (j = 0; j < DEV_PER_WIDGET; 145 - j++, sn_flush_device_list++) { 146 - if (sn_flush_device_list->sfdl_slot == -1) 144 + j++, sn_flush_device_kernel++) { 145 + common = sn_flush_device_kernel->common; 146 + if (common->sfdl_slot == -1) 147 147 continue; 148 - if ((sn_flush_device_list-> 149 - sfdl_persistent_segment == 148 + if ((common->sfdl_persistent_segment == 150 149 soft->pbi_buscommon.bs_persist_segment) && 151 - (sn_flush_device_list-> 152 - sfdl_persistent_busnum == 150 + (common->sfdl_persistent_busnum == 153 151 soft->pbi_buscommon.bs_persist_busnum)) 154 - sn_flush_device_list->sfdl_pcibus_info = 152 + common->sfdl_pcibus_info = 155 153 soft; 156 154 } 157 155 }
+2 -1
include/asm-ia64/sn/sn_sal.h
··· 75 75 #define SN_SAL_IOIF_GET_HUBDEV_INFO 0x02000055 76 76 #define SN_SAL_IOIF_GET_PCIBUS_INFO 0x02000056 77 77 #define SN_SAL_IOIF_GET_PCIDEV_INFO 0x02000057 78 - #define SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST 0x02000058 78 + #define SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST 0x02000058 // deprecated 79 + #define SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST 0x0200005a 79 80 80 81 #define SN_SAL_HUB_ERROR_INTERRUPT 0x02000060 81 82 #define SN_SAL_BTE_RECOVER 0x02000061