Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
3ec829b6 | 6 | * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. |
1da177e4 LT |
7 | */ |
8 | ||
9 | #include <linux/bootmem.h> | |
10 | #include <linux/nodemask.h> | |
11 | #include <asm/sn/types.h> | |
1da177e4 | 12 | #include <asm/sn/addrs.h> |
1da177e4 | 13 | #include <asm/sn/geo.h> |
1da177e4 | 14 | #include <asm/sn/io.h> |
c13cf371 PB |
15 | #include <asm/sn/pcibr_provider.h> |
16 | #include <asm/sn/pcibus_provider_defs.h> | |
17 | #include <asm/sn/pcidev.h> | |
1da177e4 | 18 | #include <asm/sn/simulator.h> |
c13cf371 | 19 | #include <asm/sn/sn_sal.h> |
9c90bdde | 20 | #include <asm/sn/tioca_provider.h> |
c9221da9 | 21 | #include <asm/sn/tioce_provider.h> |
c13cf371 PB |
22 | #include "xtalk/hubdev.h" |
23 | #include "xtalk/xwidgetdev.h" | |
1da177e4 | 24 | |
6f354b01 PB |
25 | static struct list_head sn_sysdata_list; |
26 | ||
27 | /* sysdata list struct */ | |
28 | struct sysdata_el { | |
29 | struct list_head entry; | |
30 | void *sysdata; | |
31 | }; | |
32 | ||
1da177e4 LT |
33 | struct slab_info { |
34 | struct hubdev_info hubdev; | |
35 | }; | |
36 | ||
37 | struct brick { | |
38 | moduleid_t id; /* Module ID of this module */ | |
39 | struct slab_info slab_info[MAX_SLABS + 1]; | |
40 | }; | |
41 | ||
42 | int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */ | |
43 | ||
e955d825 MM |
44 | struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ |
45 | ||
674c6479 CN |
46 | static int max_segment_number = 0; /* Default highest segment number */ |
47 | static int max_pcibus_number = 255; /* Default highest pci bus number */ | |
48 | ||
e955d825 MM |
49 | /* |
50 | * Hooks and struct for unsupported pci providers | |
51 | */ | |
52 | ||
53 | static dma_addr_t | |
54 | sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) | |
55 | { | |
56 | return 0; | |
57 | } | |
58 | ||
59 | static void | |
60 | sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) | |
61 | { | |
62 | return; | |
63 | } | |
64 | ||
65 | static void * | |
7c2a6c62 | 66 | sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller) |
e955d825 MM |
67 | { |
68 | return NULL; | |
69 | } | |
70 | ||
71 | static struct sn_pcibus_provider sn_pci_default_provider = { | |
72 | .dma_map = sn_default_pci_map, | |
73 | .dma_map_consistent = sn_default_pci_map, | |
74 | .dma_unmap = sn_default_pci_unmap, | |
75 | .bus_fixup = sn_default_pci_bus_fixup, | |
76 | }; | |
77 | ||
1da177e4 | 78 | /* |
6d6e4200 PB |
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. | |
1da177e4 | 81 | */ |
6d6e4200 PB |
82 | static inline u64 |
83 | sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num, | |
84 | u64 address) | |
1da177e4 LT |
85 | { |
86 | ||
87 | struct ia64_sal_retval ret_stuff; | |
88 | ret_stuff.status = 0; | |
89 | ret_stuff.v0 = 0; | |
90 | ||
91 | SAL_CALL_NOLOCK(ret_stuff, | |
6d6e4200 PB |
92 | (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST, |
93 | (u64) nasid, (u64) widget_num, | |
94 | (u64) device_num, (u64) address, 0, 0, 0); | |
95 | return ret_stuff.status; | |
1da177e4 LT |
96 | |
97 | } | |
98 | ||
99 | /* | |
100 | * Retrieve the hub device info structure for the given nasid. | |
101 | */ | |
6d6e4200 | 102 | static inline u64 sal_get_hubdev_info(u64 handle, u64 address) |
1da177e4 LT |
103 | { |
104 | ||
105 | struct ia64_sal_retval ret_stuff; | |
106 | ret_stuff.status = 0; | |
107 | ret_stuff.v0 = 0; | |
108 | ||
109 | SAL_CALL_NOLOCK(ret_stuff, | |
110 | (u64) SN_SAL_IOIF_GET_HUBDEV_INFO, | |
111 | (u64) handle, (u64) address, 0, 0, 0, 0, 0); | |
112 | return ret_stuff.v0; | |
113 | } | |
114 | ||
115 | /* | |
116 | * Retrieve the pci bus information given the bus number. | |
117 | */ | |
6d6e4200 | 118 | static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) |
1da177e4 LT |
119 | { |
120 | ||
121 | struct ia64_sal_retval ret_stuff; | |
122 | ret_stuff.status = 0; | |
123 | ret_stuff.v0 = 0; | |
124 | ||
125 | SAL_CALL_NOLOCK(ret_stuff, | |
126 | (u64) SN_SAL_IOIF_GET_PCIBUS_INFO, | |
127 | (u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0); | |
128 | return ret_stuff.v0; | |
129 | } | |
130 | ||
131 | /* | |
132 | * Retrieve the pci device information given the bus and device|function number. | |
133 | */ | |
6d6e4200 | 134 | static inline u64 |
53493dcf PB |
135 | sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, |
136 | u64 sn_irq_info) | |
1da177e4 LT |
137 | { |
138 | struct ia64_sal_retval ret_stuff; | |
139 | ret_stuff.status = 0; | |
140 | ret_stuff.v0 = 0; | |
141 | ||
142 | SAL_CALL_NOLOCK(ret_stuff, | |
143 | (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, | |
53493dcf | 144 | (u64) segment, (u64) bus_number, (u64) devfn, |
1da177e4 LT |
145 | (u64) pci_dev, |
146 | sn_irq_info, 0, 0); | |
147 | return ret_stuff.v0; | |
148 | } | |
149 | ||
3ec829b6 JK |
150 | /* |
151 | * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified | |
152 | * device. | |
153 | */ | |
154 | inline struct pcidev_info * | |
155 | sn_pcidev_info_get(struct pci_dev *dev) | |
156 | { | |
157 | struct pcidev_info *pcidev; | |
158 | ||
159 | list_for_each_entry(pcidev, | |
160 | &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) { | |
161 | if (pcidev->pdi_linux_pcidev == dev) { | |
162 | return pcidev; | |
163 | } | |
164 | } | |
165 | return NULL; | |
166 | } | |
167 | ||
1da177e4 LT |
168 | /* |
169 | * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for | |
170 | * each node in the system. | |
171 | */ | |
172 | static void sn_fixup_ionodes(void) | |
173 | { | |
6d6e4200 PB |
174 | struct sn_flush_device_kernel *sn_flush_device_kernel; |
175 | struct sn_flush_device_kernel *dev_entry; | |
1da177e4 | 176 | struct hubdev_info *hubdev; |
6d6e4200 PB |
177 | u64 status; |
178 | u64 nasid; | |
179 | int i, widget, device; | |
1da177e4 | 180 | |
674c6479 CN |
181 | /* |
182 | * Get SGI Specific HUB chipset information. | |
183 | * Inform Prom that this kernel can support domain bus numbering. | |
184 | */ | |
24ee0a6d | 185 | for (i = 0; i < num_cnodes; i++) { |
1da177e4 LT |
186 | hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); |
187 | nasid = cnodeid_to_nasid(i); | |
674c6479 CN |
188 | hubdev->max_segment_number = 0xffffffff; |
189 | hubdev->max_pcibus_number = 0xff; | |
6d6e4200 | 190 | status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev)); |
1da177e4 LT |
191 | if (status) |
192 | continue; | |
193 | ||
674c6479 CN |
194 | /* Save the largest Domain and pcibus numbers found. */ |
195 | if (hubdev->max_segment_number) { | |
196 | /* | |
197 | * Dealing with a Prom that supports segments. | |
198 | */ | |
199 | max_segment_number = hubdev->max_segment_number; | |
200 | max_pcibus_number = hubdev->max_pcibus_number; | |
201 | } | |
202 | ||
c0b12422 CN |
203 | /* Attach the error interrupt handlers */ |
204 | if (nasid & 1) | |
205 | ice_error_init(hubdev); | |
206 | else | |
207 | hub_error_init(hubdev); | |
208 | ||
1da177e4 LT |
209 | for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) |
210 | hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev; | |
211 | ||
212 | if (!hubdev->hdi_flush_nasid_list.widget_p) | |
213 | continue; | |
214 | ||
215 | hubdev->hdi_flush_nasid_list.widget_p = | |
216 | kmalloc((HUB_WIDGET_ID_MAX + 1) * | |
6d6e4200 PB |
217 | sizeof(struct sn_flush_device_kernel *), |
218 | GFP_KERNEL); | |
1da177e4 LT |
219 | memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0, |
220 | (HUB_WIDGET_ID_MAX + 1) * | |
6d6e4200 | 221 | sizeof(struct sn_flush_device_kernel *)); |
1da177e4 LT |
222 | |
223 | for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) { | |
6d6e4200 PB |
224 | sn_flush_device_kernel = kmalloc(DEV_PER_WIDGET * |
225 | sizeof(struct | |
226 | sn_flush_device_kernel), | |
227 | GFP_KERNEL); | |
228 | if (!sn_flush_device_kernel) | |
229 | BUG(); | |
230 | memset(sn_flush_device_kernel, 0x0, | |
1da177e4 | 231 | DEV_PER_WIDGET * |
6d6e4200 PB |
232 | sizeof(struct sn_flush_device_kernel)); |
233 | ||
234 | dev_entry = sn_flush_device_kernel; | |
235 | for (device = 0; device < DEV_PER_WIDGET; | |
236 | device++,dev_entry++) { | |
237 | dev_entry->common = kmalloc(sizeof(struct | |
238 | sn_flush_device_common), | |
239 | GFP_KERNEL); | |
240 | if (!dev_entry->common) | |
241 | BUG(); | |
242 | memset(dev_entry->common, 0x0, sizeof(struct | |
243 | sn_flush_device_common)); | |
244 | ||
245 | status = sal_get_device_dmaflush_list(nasid, | |
246 | widget, | |
247 | device, | |
248 | (u64)(dev_entry->common)); | |
249 | if (status) | |
250 | BUG(); | |
251 | ||
252 | spin_lock_init(&dev_entry->sfdl_flush_lock); | |
1da177e4 LT |
253 | } |
254 | ||
6d6e4200 PB |
255 | if (sn_flush_device_kernel) |
256 | hubdev->hdi_flush_nasid_list.widget_p[widget] = | |
257 | sn_flush_device_kernel; | |
258 | } | |
1da177e4 | 259 | } |
1da177e4 LT |
260 | } |
261 | ||
3ec829b6 JK |
262 | /* |
263 | * sn_pci_window_fixup() - Create a pci_window for each device resource. | |
264 | * Until ACPI support is added, we need this code | |
265 | * to setup pci_windows for use by | |
266 | * pcibios_bus_to_resource(), | |
267 | * pcibios_resource_to_bus(), etc. | |
268 | */ | |
269 | static void | |
270 | sn_pci_window_fixup(struct pci_dev *dev, unsigned int count, | |
53493dcf | 271 | s64 * pci_addrs) |
3ec829b6 JK |
272 | { |
273 | struct pci_controller *controller = PCI_CONTROLLER(dev->bus); | |
274 | unsigned int i; | |
275 | unsigned int idx; | |
276 | unsigned int new_count; | |
277 | struct pci_window *new_window; | |
278 | ||
279 | if (count == 0) | |
280 | return; | |
281 | idx = controller->windows; | |
282 | new_count = controller->windows + count; | |
283 | new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL); | |
284 | if (new_window == NULL) | |
285 | BUG(); | |
286 | if (controller->window) { | |
287 | memcpy(new_window, controller->window, | |
288 | sizeof(struct pci_window) * controller->windows); | |
289 | kfree(controller->window); | |
290 | } | |
291 | ||
292 | /* Setup a pci_window for each device resource. */ | |
293 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | |
294 | if (pci_addrs[i] == -1) | |
295 | continue; | |
296 | ||
297 | new_window[idx].offset = dev->resource[i].start - pci_addrs[i]; | |
298 | new_window[idx].resource = dev->resource[i]; | |
299 | idx++; | |
300 | } | |
301 | ||
302 | controller->windows = new_count; | |
303 | controller->window = new_window; | |
304 | } | |
305 | ||
6f354b01 PB |
306 | void sn_pci_unfixup_slot(struct pci_dev *dev) |
307 | { | |
308 | struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; | |
309 | ||
310 | sn_irq_unfixup(dev); | |
311 | pci_dev_put(host_pci_dev); | |
312 | pci_dev_put(dev); | |
313 | } | |
314 | ||
1da177e4 LT |
315 | /* |
316 | * sn_pci_fixup_slot() - This routine sets up a slot's resources | |
317 | * consistent with the Linux PCI abstraction layer. Resources acquired | |
318 | * from our PCI provider include PIO maps to BAR space and interrupt | |
319 | * objects. | |
320 | */ | |
c13cf371 | 321 | void sn_pci_fixup_slot(struct pci_dev *dev) |
1da177e4 | 322 | { |
3ec829b6 | 323 | unsigned int count = 0; |
1da177e4 | 324 | int idx; |
674c6479 | 325 | int segment = pci_domain_nr(dev->bus); |
1da177e4 | 326 | int status = 0; |
e955d825 | 327 | struct pcibus_bussoft *bs; |
cb4cb2cb PB |
328 | struct pci_bus *host_pci_bus; |
329 | struct pci_dev *host_pci_dev; | |
3ec829b6 | 330 | struct pcidev_info *pcidev_info; |
53493dcf | 331 | s64 pci_addrs[PCI_ROM_RESOURCE + 1]; |
cb4cb2cb PB |
332 | struct sn_irq_info *sn_irq_info; |
333 | unsigned long size; | |
334 | unsigned int bus_no, devfn; | |
1da177e4 | 335 | |
6f354b01 | 336 | pci_dev_get(dev); /* for the sysdata pointer */ |
3ec829b6 JK |
337 | pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); |
338 | if (pcidev_info <= 0) | |
1da177e4 | 339 | BUG(); /* Cannot afford to run out of memory */ |
1da177e4 LT |
340 | |
341 | sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | |
342 | if (sn_irq_info <= 0) | |
343 | BUG(); /* Cannot afford to run out of memory */ | |
344 | memset(sn_irq_info, 0, sizeof(struct sn_irq_info)); | |
345 | ||
346 | /* Call to retrieve pci device information needed by kernel. */ | |
347 | status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, | |
348 | dev->devfn, | |
3ec829b6 | 349 | (u64) __pa(pcidev_info), |
1da177e4 LT |
350 | (u64) __pa(sn_irq_info)); |
351 | if (status) | |
cb4cb2cb | 352 | BUG(); /* Cannot get platform pci device information */ |
1da177e4 | 353 | |
3ec829b6 JK |
354 | /* Add pcidev_info to list in sn_pci_controller struct */ |
355 | list_add_tail(&pcidev_info->pdi_list, | |
356 | &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info)); | |
357 | ||
1da177e4 LT |
358 | /* Copy over PIO Mapped Addresses */ |
359 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { | |
360 | unsigned long start, end, addr; | |
361 | ||
3ec829b6 JK |
362 | if (!pcidev_info->pdi_pio_mapped_addr[idx]) { |
363 | pci_addrs[idx] = -1; | |
1da177e4 | 364 | continue; |
3ec829b6 | 365 | } |
1da177e4 LT |
366 | |
367 | start = dev->resource[idx].start; | |
368 | end = dev->resource[idx].end; | |
369 | size = end - start; | |
3ec829b6 JK |
370 | if (size == 0) { |
371 | pci_addrs[idx] = -1; | |
372 | continue; | |
373 | } | |
374 | pci_addrs[idx] = start; | |
375 | count++; | |
376 | addr = pcidev_info->pdi_pio_mapped_addr[idx]; | |
1da177e4 LT |
377 | addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET; |
378 | dev->resource[idx].start = addr; | |
379 | dev->resource[idx].end = addr + size; | |
380 | if (dev->resource[idx].flags & IORESOURCE_IO) | |
381 | dev->resource[idx].parent = &ioport_resource; | |
382 | else | |
383 | dev->resource[idx].parent = &iomem_resource; | |
384 | } | |
3ec829b6 JK |
385 | /* Create a pci_window in the pci_controller struct for |
386 | * each device resource. | |
387 | */ | |
388 | if (count > 0) | |
389 | sn_pci_window_fixup(dev, count, pci_addrs); | |
1da177e4 | 390 | |
6f354b01 PB |
391 | /* |
392 | * Using the PROMs values for the PCI host bus, get the Linux | |
cb4cb2cb PB |
393 | * PCI host_pci_dev struct and set up host bus linkages |
394 | */ | |
395 | ||
3ec829b6 JK |
396 | bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; |
397 | devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff; | |
674c6479 | 398 | host_pci_bus = pci_find_bus(segment, bus_no); |
cb4cb2cb PB |
399 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); |
400 | ||
3ec829b6 JK |
401 | pcidev_info->host_pci_dev = host_pci_dev; |
402 | pcidev_info->pdi_linux_pcidev = dev; | |
403 | pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev); | |
cb4cb2cb | 404 | bs = SN_PCIBUS_BUSSOFT(dev->bus); |
3ec829b6 | 405 | pcidev_info->pdi_pcibus_info = bs; |
e955d825 MM |
406 | |
407 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { | |
408 | SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; | |
409 | } else { | |
410 | SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; | |
411 | } | |
1da177e4 LT |
412 | |
413 | /* Only set up IRQ stuff if this device has a host bus context */ | |
e955d825 | 414 | if (bs && sn_irq_info->irq_irq) { |
3ec829b6 JK |
415 | pcidev_info->pdi_sn_irq_info = sn_irq_info; |
416 | dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq; | |
1da177e4 | 417 | sn_irq_fixup(dev, sn_irq_info); |
cb4cb2cb | 418 | } else { |
3ec829b6 | 419 | pcidev_info->pdi_sn_irq_info = NULL; |
cb4cb2cb | 420 | kfree(sn_irq_info); |
1da177e4 LT |
421 | } |
422 | } | |
423 | ||
424 | /* | |
425 | * sn_pci_controller_fixup() - This routine sets up a bus's resources | |
426 | * consistent with the Linux PCI abstraction layer. | |
427 | */ | |
6f354b01 | 428 | void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) |
1da177e4 LT |
429 | { |
430 | int status = 0; | |
431 | int nasid, cnode; | |
1da177e4 | 432 | struct pci_controller *controller; |
3ec829b6 | 433 | struct sn_pci_controller *sn_controller; |
1da177e4 LT |
434 | struct pcibus_bussoft *prom_bussoft_ptr; |
435 | struct hubdev_info *hubdev_info; | |
c1ffb910 | 436 | void *provider_soft = NULL; |
e955d825 | 437 | struct sn_pcibus_provider *provider; |
1da177e4 | 438 | |
6f354b01 PB |
439 | status = sal_get_pcibus_info((u64) segment, (u64) busnum, |
440 | (u64) ia64_tpa(&prom_bussoft_ptr)); | |
441 | if (status > 0) | |
442 | return; /*bus # does not exist */ | |
1da177e4 | 443 | prom_bussoft_ptr = __va(prom_bussoft_ptr); |
1da177e4 | 444 | |
3ec829b6 JK |
445 | /* Allocate a sn_pci_controller, which has a pci_controller struct |
446 | * as the first member. | |
447 | */ | |
448 | sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL); | |
449 | if (!sn_controller) | |
450 | BUG(); | |
451 | INIT_LIST_HEAD(&sn_controller->pcidev_info); | |
452 | controller = &sn_controller->pci_controller; | |
674c6479 | 453 | controller->segment = segment; |
6f354b01 | 454 | |
1da177e4 | 455 | if (bus == NULL) { |
6f354b01 PB |
456 | bus = pci_scan_bus(busnum, &pci_root_ops, controller); |
457 | if (bus == NULL) | |
c1ffb910 | 458 | goto error_return; /* error, or bus already scanned */ |
6f354b01 | 459 | bus->sysdata = NULL; |
1da177e4 LT |
460 | } |
461 | ||
6f354b01 PB |
462 | if (bus->sysdata) |
463 | goto error_return; /* sysdata already alloc'd */ | |
464 | ||
1da177e4 LT |
465 | /* |
466 | * Per-provider fixup. Copies the contents from prom to local | |
467 | * area and links SN_PCIBUS_BUSSOFT(). | |
1da177e4 LT |
468 | */ |
469 | ||
6f354b01 | 470 | if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) |
c1ffb910 | 471 | goto error_return; /* unsupported asic type */ |
6f354b01 PB |
472 | |
473 | if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) | |
474 | goto error_return; /* no further fixup necessary */ | |
e955d825 MM |
475 | |
476 | provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; | |
6f354b01 | 477 | if (provider == NULL) |
c1ffb910 | 478 | goto error_return; /* no provider registerd for this asic */ |
e955d825 | 479 | |
c1ffb910 | 480 | bus->sysdata = controller; |
6f354b01 | 481 | if (provider->bus_fixup) |
7c2a6c62 | 482 | provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, controller); |
1da177e4 | 483 | |
c1ffb910 PB |
484 | if (provider_soft == NULL) { |
485 | /* fixup failed or not applicable */ | |
486 | bus->sysdata = NULL; | |
487 | goto error_return; | |
488 | } | |
1da177e4 | 489 | |
3ec829b6 JK |
490 | /* |
491 | * Setup pci_windows for legacy IO and MEM space. | |
492 | * (Temporary until ACPI support is in place.) | |
493 | */ | |
494 | controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL); | |
495 | if (controller->window == NULL) | |
496 | BUG(); | |
497 | controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io; | |
498 | controller->window[0].resource.name = "legacy_io"; | |
499 | controller->window[0].resource.flags = IORESOURCE_IO; | |
500 | controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io; | |
501 | controller->window[0].resource.end = | |
502 | controller->window[0].resource.start + 0xffff; | |
503 | controller->window[0].resource.parent = &ioport_resource; | |
504 | controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem; | |
505 | controller->window[1].resource.name = "legacy_mem"; | |
506 | controller->window[1].resource.flags = IORESOURCE_MEM; | |
507 | controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem; | |
508 | controller->window[1].resource.end = | |
509 | controller->window[1].resource.start + (1024 * 1024) - 1; | |
510 | controller->window[1].resource.parent = &iomem_resource; | |
511 | controller->windows = 2; | |
512 | ||
1da177e4 LT |
513 | /* |
514 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr | |
515 | * after this point. | |
516 | */ | |
517 | ||
1da177e4 | 518 | PCI_CONTROLLER(bus)->platform_data = provider_soft; |
1da177e4 LT |
519 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); |
520 | cnode = nasid_to_cnodeid(nasid); | |
521 | hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); | |
522 | SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = | |
523 | &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); | |
6f354b01 | 524 | |
7c2a6c62 CL |
525 | /* |
526 | * If the node information we obtained during the fixup phase is invalid | |
527 | * then set controller->node to -1 (undetermined) | |
528 | */ | |
529 | if (controller->node >= num_online_nodes()) { | |
530 | struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus); | |
531 | ||
674c6479 | 532 | printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u" |
7c2a6c62 CL |
533 | "L_IO=%lx L_MEM=%lx BASE=%lx\n", |
534 | b->bs_asic_type, b->bs_xid, b->bs_persist_busnum, | |
535 | b->bs_legacy_io, b->bs_legacy_mem, b->bs_base); | |
536 | printk(KERN_WARNING "on node %d but only %d nodes online." | |
537 | "Association set to undetermined.\n", | |
538 | controller->node, num_online_nodes()); | |
539 | controller->node = -1; | |
540 | } | |
6f354b01 PB |
541 | return; |
542 | ||
543 | error_return: | |
544 | ||
3ec829b6 | 545 | kfree(sn_controller); |
6f354b01 PB |
546 | return; |
547 | } | |
548 | ||
549 | void sn_bus_store_sysdata(struct pci_dev *dev) | |
550 | { | |
551 | struct sysdata_el *element; | |
552 | ||
f96cb1f0 | 553 | element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL); |
6f354b01 PB |
554 | if (!element) { |
555 | dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); | |
556 | return; | |
557 | } | |
3ec829b6 | 558 | element->sysdata = SN_PCIDEV_INFO(dev); |
6f354b01 PB |
559 | list_add(&element->entry, &sn_sysdata_list); |
560 | } | |
561 | ||
562 | void sn_bus_free_sysdata(void) | |
563 | { | |
564 | struct sysdata_el *element; | |
565 | struct list_head *list; | |
566 | ||
567 | sn_sysdata_free_start: | |
568 | list_for_each(list, &sn_sysdata_list) { | |
569 | element = list_entry(list, struct sysdata_el, entry); | |
570 | list_del(&element->entry); | |
571 | kfree(element->sysdata); | |
572 | kfree(element); | |
573 | goto sn_sysdata_free_start; | |
574 | } | |
575 | return; | |
1da177e4 LT |
576 | } |
577 | ||
578 | /* | |
579 | * Ugly hack to get PCI setup until we have a proper ACPI namespace. | |
580 | */ | |
581 | ||
582 | #define PCI_BUSES_TO_SCAN 256 | |
583 | ||
584 | static int __init sn_pci_init(void) | |
585 | { | |
586 | int i = 0; | |
674c6479 | 587 | int j = 0; |
1da177e4 LT |
588 | struct pci_dev *pci_dev = NULL; |
589 | extern void sn_init_cpei_timer(void); | |
590 | #ifdef CONFIG_PROC_FS | |
591 | extern void register_sn_procfs(void); | |
592 | #endif | |
593 | ||
71a5d027 | 594 | if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) |
1da177e4 LT |
595 | return 0; |
596 | ||
e955d825 MM |
597 | /* |
598 | * prime sn_pci_provider[]. Individial provider init routines will | |
599 | * override their respective default entries. | |
600 | */ | |
601 | ||
602 | for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) | |
603 | sn_pci_provider[i] = &sn_pci_default_provider; | |
604 | ||
605 | pcibr_init_provider(); | |
9c90bdde | 606 | tioca_init_provider(); |
c9221da9 | 607 | tioce_init_provider(); |
e955d825 | 608 | |
1da177e4 LT |
609 | /* |
610 | * This is needed to avoid bounce limit checks in the blk layer | |
611 | */ | |
612 | ia64_max_iommu_merge_mask = ~PAGE_MASK; | |
613 | sn_fixup_ionodes(); | |
cb4cb2cb | 614 | sn_irq_lh_init(); |
6f354b01 | 615 | INIT_LIST_HEAD(&sn_sysdata_list); |
1da177e4 LT |
616 | sn_init_cpei_timer(); |
617 | ||
618 | #ifdef CONFIG_PROC_FS | |
619 | register_sn_procfs(); | |
620 | #endif | |
621 | ||
6f354b01 | 622 | /* busses are not known yet ... */ |
674c6479 CN |
623 | for (i = 0; i <= max_segment_number; i++) |
624 | for (j = 0; j <= max_pcibus_number; j++) | |
625 | sn_pci_controller_fixup(i, j, NULL); | |
1da177e4 LT |
626 | |
627 | /* | |
628 | * Generic Linux PCI Layer has created the pci_bus and pci_dev | |
629 | * structures - time for us to add our SN PLatform specific | |
630 | * information. | |
631 | */ | |
632 | ||
633 | while ((pci_dev = | |
6f354b01 | 634 | pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) |
1da177e4 | 635 | sn_pci_fixup_slot(pci_dev); |
1da177e4 LT |
636 | |
637 | sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ | |
638 | ||
639 | return 0; | |
640 | } | |
641 | ||
642 | /* | |
643 | * hubdev_init_node() - Creates the HUB data structure and link them to it's | |
644 | * own NODE specific data area. | |
645 | */ | |
646 | void hubdev_init_node(nodepda_t * npda, cnodeid_t node) | |
647 | { | |
648 | ||
649 | struct hubdev_info *hubdev_info; | |
650 | ||
651 | if (node >= num_online_nodes()) /* Headless/memless IO nodes */ | |
652 | hubdev_info = | |
653 | (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(0), | |
654 | sizeof(struct | |
655 | hubdev_info)); | |
656 | else | |
657 | hubdev_info = | |
658 | (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(node), | |
659 | sizeof(struct | |
660 | hubdev_info)); | |
661 | npda->pdinfo = (void *)hubdev_info; | |
662 | ||
663 | } | |
664 | ||
665 | geoid_t | |
666 | cnodeid_get_geoid(cnodeid_t cnode) | |
667 | { | |
668 | ||
669 | struct hubdev_info *hubdev; | |
670 | ||
671 | hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); | |
672 | return hubdev->hdi_geoid; | |
673 | ||
674 | } | |
675 | ||
676 | subsys_initcall(sn_pci_init); | |
6f354b01 PB |
677 | EXPORT_SYMBOL(sn_pci_fixup_slot); |
678 | EXPORT_SYMBOL(sn_pci_unfixup_slot); | |
679 | EXPORT_SYMBOL(sn_pci_controller_fixup); | |
680 | EXPORT_SYMBOL(sn_bus_store_sysdata); | |
681 | EXPORT_SYMBOL(sn_bus_free_sysdata); |