]>
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 | * | |
6 | * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. | |
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> |
c13cf371 PB |
21 | #include "xtalk/hubdev.h" |
22 | #include "xtalk/xwidgetdev.h" | |
1da177e4 | 23 | |
1da177e4 LT |
24 | nasid_t master_nasid = INVALID_NASID; /* Partition Master */ |
25 | ||
6f354b01 PB |
26 | static struct list_head sn_sysdata_list; |
27 | ||
28 | /* sysdata list struct */ | |
29 | struct sysdata_el { | |
30 | struct list_head entry; | |
31 | void *sysdata; | |
32 | }; | |
33 | ||
1da177e4 LT |
34 | struct slab_info { |
35 | struct hubdev_info hubdev; | |
36 | }; | |
37 | ||
38 | struct brick { | |
39 | moduleid_t id; /* Module ID of this module */ | |
40 | struct slab_info slab_info[MAX_SLABS + 1]; | |
41 | }; | |
42 | ||
43 | int sn_ioif_inited = 0; /* SN I/O infrastructure initialized? */ | |
44 | ||
e955d825 MM |
45 | struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ |
46 | ||
47 | /* | |
48 | * Hooks and struct for unsupported pci providers | |
49 | */ | |
50 | ||
51 | static dma_addr_t | |
52 | sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) | |
53 | { | |
54 | return 0; | |
55 | } | |
56 | ||
57 | static void | |
58 | sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) | |
59 | { | |
60 | return; | |
61 | } | |
62 | ||
63 | static void * | |
64 | sn_default_pci_bus_fixup(struct pcibus_bussoft *soft) | |
65 | { | |
66 | return NULL; | |
67 | } | |
68 | ||
69 | static struct sn_pcibus_provider sn_pci_default_provider = { | |
70 | .dma_map = sn_default_pci_map, | |
71 | .dma_map_consistent = sn_default_pci_map, | |
72 | .dma_unmap = sn_default_pci_unmap, | |
73 | .bus_fixup = sn_default_pci_bus_fixup, | |
74 | }; | |
75 | ||
1da177e4 LT |
76 | /* |
77 | * Retrieve the DMA Flush List given nasid. This list is needed | |
78 | * to implement the WAR - Flush DMA data on PIO Reads. | |
79 | */ | |
80 | static inline uint64_t | |
81 | sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address) | |
82 | { | |
83 | ||
84 | struct ia64_sal_retval ret_stuff; | |
85 | ret_stuff.status = 0; | |
86 | ret_stuff.v0 = 0; | |
87 | ||
88 | SAL_CALL_NOLOCK(ret_stuff, | |
89 | (u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST, | |
90 | (u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0, | |
91 | 0); | |
92 | return ret_stuff.v0; | |
93 | ||
94 | } | |
95 | ||
96 | /* | |
97 | * Retrieve the hub device info structure for the given nasid. | |
98 | */ | |
99 | static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address) | |
100 | { | |
101 | ||
102 | struct ia64_sal_retval ret_stuff; | |
103 | ret_stuff.status = 0; | |
104 | ret_stuff.v0 = 0; | |
105 | ||
106 | SAL_CALL_NOLOCK(ret_stuff, | |
107 | (u64) SN_SAL_IOIF_GET_HUBDEV_INFO, | |
108 | (u64) handle, (u64) address, 0, 0, 0, 0, 0); | |
109 | return ret_stuff.v0; | |
110 | } | |
111 | ||
112 | /* | |
113 | * Retrieve the pci bus information given the bus number. | |
114 | */ | |
115 | static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) | |
116 | { | |
117 | ||
118 | struct ia64_sal_retval ret_stuff; | |
119 | ret_stuff.status = 0; | |
120 | ret_stuff.v0 = 0; | |
121 | ||
122 | SAL_CALL_NOLOCK(ret_stuff, | |
123 | (u64) SN_SAL_IOIF_GET_PCIBUS_INFO, | |
124 | (u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0); | |
125 | return ret_stuff.v0; | |
126 | } | |
127 | ||
128 | /* | |
129 | * Retrieve the pci device information given the bus and device|function number. | |
130 | */ | |
131 | static inline uint64_t | |
132 | sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, | |
133 | u64 sn_irq_info) | |
134 | { | |
135 | struct ia64_sal_retval ret_stuff; | |
136 | ret_stuff.status = 0; | |
137 | ret_stuff.v0 = 0; | |
138 | ||
139 | SAL_CALL_NOLOCK(ret_stuff, | |
140 | (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, | |
141 | (u64) segment, (u64) bus_number, (u64) devfn, | |
142 | (u64) pci_dev, | |
143 | sn_irq_info, 0, 0); | |
144 | return ret_stuff.v0; | |
145 | } | |
146 | ||
1da177e4 LT |
147 | /* |
148 | * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for | |
149 | * each node in the system. | |
150 | */ | |
151 | static void sn_fixup_ionodes(void) | |
152 | { | |
153 | ||
154 | struct sn_flush_device_list *sn_flush_device_list; | |
155 | struct hubdev_info *hubdev; | |
156 | uint64_t status; | |
157 | uint64_t nasid; | |
158 | int i, widget; | |
159 | ||
160 | for (i = 0; i < numionodes; i++) { | |
161 | hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo); | |
162 | nasid = cnodeid_to_nasid(i); | |
163 | status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev)); | |
164 | if (status) | |
165 | continue; | |
166 | ||
c0b12422 CN |
167 | /* Attach the error interrupt handlers */ |
168 | if (nasid & 1) | |
169 | ice_error_init(hubdev); | |
170 | else | |
171 | hub_error_init(hubdev); | |
172 | ||
1da177e4 LT |
173 | for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) |
174 | hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev; | |
175 | ||
176 | if (!hubdev->hdi_flush_nasid_list.widget_p) | |
177 | continue; | |
178 | ||
179 | hubdev->hdi_flush_nasid_list.widget_p = | |
180 | kmalloc((HUB_WIDGET_ID_MAX + 1) * | |
181 | sizeof(struct sn_flush_device_list *), GFP_KERNEL); | |
182 | ||
183 | memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0, | |
184 | (HUB_WIDGET_ID_MAX + 1) * | |
185 | sizeof(struct sn_flush_device_list *)); | |
186 | ||
187 | for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) { | |
188 | sn_flush_device_list = kmalloc(DEV_PER_WIDGET * | |
189 | sizeof(struct | |
190 | sn_flush_device_list), | |
191 | GFP_KERNEL); | |
192 | memset(sn_flush_device_list, 0x0, | |
193 | DEV_PER_WIDGET * | |
194 | sizeof(struct sn_flush_device_list)); | |
195 | ||
196 | status = | |
197 | sal_get_widget_dmaflush_list(nasid, widget, | |
198 | (uint64_t) | |
199 | __pa | |
200 | (sn_flush_device_list)); | |
201 | if (status) { | |
202 | kfree(sn_flush_device_list); | |
203 | continue; | |
204 | } | |
205 | ||
206 | hubdev->hdi_flush_nasid_list.widget_p[widget] = | |
207 | sn_flush_device_list; | |
208 | } | |
209 | ||
1da177e4 LT |
210 | } |
211 | ||
212 | } | |
213 | ||
6f354b01 PB |
214 | void sn_pci_unfixup_slot(struct pci_dev *dev) |
215 | { | |
216 | struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; | |
217 | ||
218 | sn_irq_unfixup(dev); | |
219 | pci_dev_put(host_pci_dev); | |
220 | pci_dev_put(dev); | |
221 | } | |
222 | ||
1da177e4 LT |
223 | /* |
224 | * sn_pci_fixup_slot() - This routine sets up a slot's resources | |
225 | * consistent with the Linux PCI abstraction layer. Resources acquired | |
226 | * from our PCI provider include PIO maps to BAR space and interrupt | |
227 | * objects. | |
228 | */ | |
c13cf371 | 229 | void sn_pci_fixup_slot(struct pci_dev *dev) |
1da177e4 LT |
230 | { |
231 | int idx; | |
232 | int segment = 0; | |
1da177e4 | 233 | int status = 0; |
e955d825 | 234 | struct pcibus_bussoft *bs; |
cb4cb2cb PB |
235 | struct pci_bus *host_pci_bus; |
236 | struct pci_dev *host_pci_dev; | |
237 | struct sn_irq_info *sn_irq_info; | |
238 | unsigned long size; | |
239 | unsigned int bus_no, devfn; | |
1da177e4 | 240 | |
6f354b01 | 241 | pci_dev_get(dev); /* for the sysdata pointer */ |
1da177e4 LT |
242 | dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); |
243 | if (SN_PCIDEV_INFO(dev) <= 0) | |
244 | BUG(); /* Cannot afford to run out of memory */ | |
245 | memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info)); | |
246 | ||
247 | sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | |
248 | if (sn_irq_info <= 0) | |
249 | BUG(); /* Cannot afford to run out of memory */ | |
250 | memset(sn_irq_info, 0, sizeof(struct sn_irq_info)); | |
251 | ||
252 | /* Call to retrieve pci device information needed by kernel. */ | |
253 | status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, | |
254 | dev->devfn, | |
255 | (u64) __pa(SN_PCIDEV_INFO(dev)), | |
256 | (u64) __pa(sn_irq_info)); | |
257 | if (status) | |
cb4cb2cb | 258 | BUG(); /* Cannot get platform pci device information */ |
1da177e4 LT |
259 | |
260 | /* Copy over PIO Mapped Addresses */ | |
261 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { | |
262 | unsigned long start, end, addr; | |
263 | ||
264 | if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx]) | |
265 | continue; | |
266 | ||
267 | start = dev->resource[idx].start; | |
268 | end = dev->resource[idx].end; | |
269 | size = end - start; | |
270 | addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx]; | |
271 | addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET; | |
272 | dev->resource[idx].start = addr; | |
273 | dev->resource[idx].end = addr + size; | |
274 | if (dev->resource[idx].flags & IORESOURCE_IO) | |
275 | dev->resource[idx].parent = &ioport_resource; | |
276 | else | |
277 | dev->resource[idx].parent = &iomem_resource; | |
278 | } | |
279 | ||
6f354b01 PB |
280 | /* |
281 | * Using the PROMs values for the PCI host bus, get the Linux | |
cb4cb2cb PB |
282 | * PCI host_pci_dev struct and set up host bus linkages |
283 | */ | |
284 | ||
285 | bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32; | |
286 | devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff; | |
287 | host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no); | |
288 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); | |
289 | ||
290 | SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev; | |
1da177e4 | 291 | SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = |
cb4cb2cb | 292 | SN_PCIDEV_INFO(host_pci_dev); |
1da177e4 | 293 | SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; |
cb4cb2cb | 294 | bs = SN_PCIBUS_BUSSOFT(dev->bus); |
e955d825 MM |
295 | SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; |
296 | ||
297 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { | |
298 | SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; | |
299 | } else { | |
300 | SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; | |
301 | } | |
1da177e4 LT |
302 | |
303 | /* Only set up IRQ stuff if this device has a host bus context */ | |
e955d825 | 304 | if (bs && sn_irq_info->irq_irq) { |
1da177e4 LT |
305 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; |
306 | dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; | |
307 | sn_irq_fixup(dev, sn_irq_info); | |
cb4cb2cb PB |
308 | } else { |
309 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL; | |
310 | kfree(sn_irq_info); | |
1da177e4 LT |
311 | } |
312 | } | |
313 | ||
314 | /* | |
315 | * sn_pci_controller_fixup() - This routine sets up a bus's resources | |
316 | * consistent with the Linux PCI abstraction layer. | |
317 | */ | |
6f354b01 | 318 | void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) |
1da177e4 LT |
319 | { |
320 | int status = 0; | |
321 | int nasid, cnode; | |
1da177e4 LT |
322 | struct pci_controller *controller; |
323 | struct pcibus_bussoft *prom_bussoft_ptr; | |
324 | struct hubdev_info *hubdev_info; | |
325 | void *provider_soft; | |
e955d825 | 326 | struct sn_pcibus_provider *provider; |
1da177e4 | 327 | |
6f354b01 PB |
328 | status = sal_get_pcibus_info((u64) segment, (u64) busnum, |
329 | (u64) ia64_tpa(&prom_bussoft_ptr)); | |
330 | if (status > 0) | |
331 | return; /*bus # does not exist */ | |
1da177e4 | 332 | prom_bussoft_ptr = __va(prom_bussoft_ptr); |
1da177e4 | 333 | |
6f354b01 PB |
334 | controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL); |
335 | if (!controller) | |
336 | BUG(); | |
337 | ||
1da177e4 | 338 | if (bus == NULL) { |
6f354b01 PB |
339 | bus = pci_scan_bus(busnum, &pci_root_ops, controller); |
340 | if (bus == NULL) | |
341 | return; /* error, or bus already scanned */ | |
342 | bus->sysdata = NULL; | |
1da177e4 LT |
343 | } |
344 | ||
6f354b01 PB |
345 | if (bus->sysdata) |
346 | goto error_return; /* sysdata already alloc'd */ | |
347 | ||
1da177e4 LT |
348 | /* |
349 | * Per-provider fixup. Copies the contents from prom to local | |
350 | * area and links SN_PCIBUS_BUSSOFT(). | |
1da177e4 LT |
351 | */ |
352 | ||
6f354b01 | 353 | if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) |
e955d825 | 354 | return; /* unsupported asic type */ |
6f354b01 PB |
355 | |
356 | if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) | |
357 | goto error_return; /* no further fixup necessary */ | |
e955d825 MM |
358 | |
359 | provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; | |
6f354b01 | 360 | if (provider == NULL) |
e955d825 | 361 | return; /* no provider registerd for this asic */ |
e955d825 MM |
362 | |
363 | provider_soft = NULL; | |
6f354b01 | 364 | if (provider->bus_fixup) |
e955d825 | 365 | provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); |
1da177e4 | 366 | |
6f354b01 | 367 | if (provider_soft == NULL) |
1da177e4 | 368 | return; /* fixup failed or not applicable */ |
1da177e4 LT |
369 | |
370 | /* | |
371 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr | |
372 | * after this point. | |
373 | */ | |
374 | ||
375 | bus->sysdata = controller; | |
376 | PCI_CONTROLLER(bus)->platform_data = provider_soft; | |
1da177e4 LT |
377 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); |
378 | cnode = nasid_to_cnodeid(nasid); | |
379 | hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); | |
380 | SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = | |
381 | &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); | |
6f354b01 PB |
382 | |
383 | return; | |
384 | ||
385 | error_return: | |
386 | ||
387 | kfree(controller); | |
388 | return; | |
389 | } | |
390 | ||
391 | void sn_bus_store_sysdata(struct pci_dev *dev) | |
392 | { | |
393 | struct sysdata_el *element; | |
394 | ||
395 | element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL); | |
396 | if (!element) { | |
397 | dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); | |
398 | return; | |
399 | } | |
400 | element->sysdata = dev->sysdata; | |
401 | list_add(&element->entry, &sn_sysdata_list); | |
402 | } | |
403 | ||
404 | void sn_bus_free_sysdata(void) | |
405 | { | |
406 | struct sysdata_el *element; | |
407 | struct list_head *list; | |
408 | ||
409 | sn_sysdata_free_start: | |
410 | list_for_each(list, &sn_sysdata_list) { | |
411 | element = list_entry(list, struct sysdata_el, entry); | |
412 | list_del(&element->entry); | |
413 | kfree(element->sysdata); | |
414 | kfree(element); | |
415 | goto sn_sysdata_free_start; | |
416 | } | |
417 | return; | |
1da177e4 LT |
418 | } |
419 | ||
420 | /* | |
421 | * Ugly hack to get PCI setup until we have a proper ACPI namespace. | |
422 | */ | |
423 | ||
424 | #define PCI_BUSES_TO_SCAN 256 | |
425 | ||
426 | static int __init sn_pci_init(void) | |
427 | { | |
428 | int i = 0; | |
429 | struct pci_dev *pci_dev = NULL; | |
430 | extern void sn_init_cpei_timer(void); | |
431 | #ifdef CONFIG_PROC_FS | |
432 | extern void register_sn_procfs(void); | |
433 | #endif | |
434 | ||
71a5d027 | 435 | if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) |
1da177e4 LT |
436 | return 0; |
437 | ||
e955d825 MM |
438 | /* |
439 | * prime sn_pci_provider[]. Individial provider init routines will | |
440 | * override their respective default entries. | |
441 | */ | |
442 | ||
443 | for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) | |
444 | sn_pci_provider[i] = &sn_pci_default_provider; | |
445 | ||
446 | pcibr_init_provider(); | |
9c90bdde | 447 | tioca_init_provider(); |
e955d825 | 448 | |
1da177e4 LT |
449 | /* |
450 | * This is needed to avoid bounce limit checks in the blk layer | |
451 | */ | |
452 | ia64_max_iommu_merge_mask = ~PAGE_MASK; | |
453 | sn_fixup_ionodes(); | |
cb4cb2cb | 454 | sn_irq_lh_init(); |
6f354b01 | 455 | INIT_LIST_HEAD(&sn_sysdata_list); |
1da177e4 LT |
456 | sn_init_cpei_timer(); |
457 | ||
458 | #ifdef CONFIG_PROC_FS | |
459 | register_sn_procfs(); | |
460 | #endif | |
461 | ||
6f354b01 PB |
462 | /* busses are not known yet ... */ |
463 | for (i = 0; i < PCI_BUSES_TO_SCAN; i++) | |
464 | sn_pci_controller_fixup(0, i, NULL); | |
1da177e4 LT |
465 | |
466 | /* | |
467 | * Generic Linux PCI Layer has created the pci_bus and pci_dev | |
468 | * structures - time for us to add our SN PLatform specific | |
469 | * information. | |
470 | */ | |
471 | ||
472 | while ((pci_dev = | |
6f354b01 | 473 | pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) |
1da177e4 | 474 | sn_pci_fixup_slot(pci_dev); |
1da177e4 LT |
475 | |
476 | sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ | |
477 | ||
478 | return 0; | |
479 | } | |
480 | ||
481 | /* | |
482 | * hubdev_init_node() - Creates the HUB data structure and link them to it's | |
483 | * own NODE specific data area. | |
484 | */ | |
485 | void hubdev_init_node(nodepda_t * npda, cnodeid_t node) | |
486 | { | |
487 | ||
488 | struct hubdev_info *hubdev_info; | |
489 | ||
490 | if (node >= num_online_nodes()) /* Headless/memless IO nodes */ | |
491 | hubdev_info = | |
492 | (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(0), | |
493 | sizeof(struct | |
494 | hubdev_info)); | |
495 | else | |
496 | hubdev_info = | |
497 | (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(node), | |
498 | sizeof(struct | |
499 | hubdev_info)); | |
500 | npda->pdinfo = (void *)hubdev_info; | |
501 | ||
502 | } | |
503 | ||
504 | geoid_t | |
505 | cnodeid_get_geoid(cnodeid_t cnode) | |
506 | { | |
507 | ||
508 | struct hubdev_info *hubdev; | |
509 | ||
510 | hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); | |
511 | return hubdev->hdi_geoid; | |
512 | ||
513 | } | |
514 | ||
515 | subsys_initcall(sn_pci_init); | |
6f354b01 PB |
516 | EXPORT_SYMBOL(sn_pci_fixup_slot); |
517 | EXPORT_SYMBOL(sn_pci_unfixup_slot); | |
518 | EXPORT_SYMBOL(sn_pci_controller_fixup); | |
519 | EXPORT_SYMBOL(sn_bus_store_sysdata); | |
520 | EXPORT_SYMBOL(sn_bus_free_sysdata); |