John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 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) 2006 Silicon Graphics, Inc. All rights reserved. |
| 7 | */ |
| 8 | |
| 9 | #include <linux/bootmem.h> |
| 10 | #include <asm/sn/types.h> |
| 11 | #include <asm/sn/addrs.h> |
| 12 | #include <asm/sn/sn_feature_sets.h> |
| 13 | #include <asm/sn/geo.h> |
| 14 | #include <asm/sn/io.h> |
| 15 | #include <asm/sn/l1.h> |
| 16 | #include <asm/sn/module.h> |
| 17 | #include <asm/sn/pcibr_provider.h> |
| 18 | #include <asm/sn/pcibus_provider_defs.h> |
| 19 | #include <asm/sn/pcidev.h> |
| 20 | #include <asm/sn/simulator.h> |
| 21 | #include <asm/sn/sn_sal.h> |
| 22 | #include <asm/sn/tioca_provider.h> |
| 23 | #include <asm/sn/tioce_provider.h> |
| 24 | #include "xtalk/hubdev.h" |
| 25 | #include "xtalk/xwidgetdev.h" |
| 26 | #include <linux/acpi.h> |
| 27 | #include <asm/sn/sn2/sn_hwperf.h> |
Len Brown | 647fb47 | 2007-02-02 22:14:22 -0500 | [diff] [blame] | 28 | #include <asm/sn/acpi.h> |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 29 | #include "acpi/acglobal.h" |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 30 | |
| 31 | extern void sn_init_cpei_timer(void); |
| 32 | extern void register_sn_procfs(void); |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 33 | extern void sn_io_acpi_init(void); |
| 34 | extern void sn_io_init(void); |
| 35 | |
Len Brown | 647fb47 | 2007-02-02 22:14:22 -0500 | [diff] [blame] | 36 | |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 37 | static struct list_head sn_sysdata_list; |
| 38 | |
| 39 | /* sysdata list struct */ |
| 40 | struct sysdata_el { |
| 41 | struct list_head entry; |
| 42 | void *sysdata; |
| 43 | }; |
| 44 | |
| 45 | int sn_ioif_inited; /* SN I/O infrastructure initialized? */ |
| 46 | |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 47 | int sn_acpi_rev; /* SN ACPI revision */ |
| 48 | EXPORT_SYMBOL_GPL(sn_acpi_rev); |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 49 | |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 50 | struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ |
Alexey Starikovskiy | ad71860a | 2007-02-02 19:48:19 +0300 | [diff] [blame] | 51 | |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 52 | /* |
| 53 | * Hooks and struct for unsupported pci providers |
| 54 | */ |
| 55 | |
| 56 | static dma_addr_t |
| 57 | sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type) |
| 58 | { |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | static void |
| 63 | sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction) |
| 64 | { |
| 65 | return; |
| 66 | } |
| 67 | |
| 68 | static void * |
| 69 | sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller) |
| 70 | { |
| 71 | return NULL; |
| 72 | } |
| 73 | |
| 74 | static struct sn_pcibus_provider sn_pci_default_provider = { |
| 75 | .dma_map = sn_default_pci_map, |
| 76 | .dma_map_consistent = sn_default_pci_map, |
| 77 | .dma_unmap = sn_default_pci_unmap, |
| 78 | .bus_fixup = sn_default_pci_bus_fixup, |
| 79 | }; |
| 80 | |
| 81 | /* |
| 82 | * Retrieve the DMA Flush List given nasid, widget, and device. |
| 83 | * This list is needed to implement the WAR - Flush DMA data on PIO Reads. |
| 84 | */ |
| 85 | static inline u64 |
| 86 | sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num, |
| 87 | u64 address) |
| 88 | { |
| 89 | struct ia64_sal_retval ret_stuff; |
| 90 | ret_stuff.status = 0; |
| 91 | ret_stuff.v0 = 0; |
| 92 | |
| 93 | SAL_CALL_NOLOCK(ret_stuff, |
| 94 | (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST, |
| 95 | (u64) nasid, (u64) widget_num, |
| 96 | (u64) device_num, (u64) address, 0, 0, 0); |
| 97 | return ret_stuff.status; |
| 98 | } |
| 99 | |
| 100 | /* |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 101 | * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified |
| 102 | * device. |
| 103 | */ |
| 104 | inline struct pcidev_info * |
| 105 | sn_pcidev_info_get(struct pci_dev *dev) |
| 106 | { |
| 107 | struct pcidev_info *pcidev; |
| 108 | |
| 109 | list_for_each_entry(pcidev, |
| 110 | &(SN_PLATFORM_DATA(dev)->pcidev_info), pdi_list) { |
| 111 | if (pcidev->pdi_linux_pcidev == dev) |
| 112 | return pcidev; |
| 113 | } |
| 114 | return NULL; |
| 115 | } |
| 116 | |
| 117 | /* Older PROM flush WAR |
| 118 | * |
| 119 | * 01/16/06 -- This war will be in place until a new official PROM is released. |
| 120 | * Additionally note that the struct sn_flush_device_war also has to be |
| 121 | * removed from arch/ia64/sn/include/xtalk/hubdev.h |
| 122 | */ |
| 123 | static u8 war_implemented = 0; |
| 124 | |
| 125 | static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device, |
| 126 | struct sn_flush_device_common *common) |
| 127 | { |
| 128 | struct sn_flush_device_war *war_list; |
| 129 | struct sn_flush_device_war *dev_entry; |
| 130 | struct ia64_sal_retval isrv = {0,0,0,0}; |
| 131 | |
| 132 | if (!war_implemented) { |
| 133 | printk(KERN_WARNING "PROM version < 4.50 -- implementing old " |
| 134 | "PROM flush WAR\n"); |
| 135 | war_implemented = 1; |
| 136 | } |
| 137 | |
| 138 | war_list = kzalloc(DEV_PER_WIDGET * sizeof(*war_list), GFP_KERNEL); |
| 139 | if (!war_list) |
| 140 | BUG(); |
| 141 | |
| 142 | SAL_CALL_NOLOCK(isrv, SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST, |
| 143 | nasid, widget, __pa(war_list), 0, 0, 0 ,0); |
| 144 | if (isrv.status) |
| 145 | panic("sn_device_fixup_war failed: %s\n", |
| 146 | ia64_sal_strerror(isrv.status)); |
| 147 | |
| 148 | dev_entry = war_list + device; |
| 149 | memcpy(common,dev_entry, sizeof(*common)); |
| 150 | kfree(war_list); |
| 151 | |
| 152 | return isrv.status; |
| 153 | } |
| 154 | |
| 155 | /* |
| 156 | * sn_common_hubdev_init() - This routine is called to initialize the HUB data |
| 157 | * structure for each node in the system. |
| 158 | */ |
| 159 | void __init |
| 160 | sn_common_hubdev_init(struct hubdev_info *hubdev) |
| 161 | { |
| 162 | |
| 163 | struct sn_flush_device_kernel *sn_flush_device_kernel; |
| 164 | struct sn_flush_device_kernel *dev_entry; |
| 165 | s64 status; |
| 166 | int widget, device, size; |
| 167 | |
| 168 | /* Attach the error interrupt handlers */ |
| 169 | if (hubdev->hdi_nasid & 1) /* If TIO */ |
| 170 | ice_error_init(hubdev); |
| 171 | else |
| 172 | hub_error_init(hubdev); |
| 173 | |
| 174 | for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) |
| 175 | hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev; |
| 176 | |
| 177 | if (!hubdev->hdi_flush_nasid_list.widget_p) |
| 178 | return; |
| 179 | |
| 180 | size = (HUB_WIDGET_ID_MAX + 1) * |
| 181 | sizeof(struct sn_flush_device_kernel *); |
| 182 | hubdev->hdi_flush_nasid_list.widget_p = |
| 183 | kzalloc(size, GFP_KERNEL); |
| 184 | if (!hubdev->hdi_flush_nasid_list.widget_p) |
| 185 | BUG(); |
| 186 | |
| 187 | for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) { |
| 188 | size = DEV_PER_WIDGET * |
| 189 | sizeof(struct sn_flush_device_kernel); |
| 190 | sn_flush_device_kernel = kzalloc(size, GFP_KERNEL); |
| 191 | if (!sn_flush_device_kernel) |
| 192 | BUG(); |
| 193 | |
| 194 | dev_entry = sn_flush_device_kernel; |
| 195 | for (device = 0; device < DEV_PER_WIDGET; |
| 196 | device++, dev_entry++) { |
| 197 | size = sizeof(struct sn_flush_device_common); |
| 198 | dev_entry->common = kzalloc(size, GFP_KERNEL); |
| 199 | if (!dev_entry->common) |
| 200 | BUG(); |
| 201 | if (sn_prom_feature_available(PRF_DEVICE_FLUSH_LIST)) |
| 202 | status = sal_get_device_dmaflush_list( |
| 203 | hubdev->hdi_nasid, widget, device, |
| 204 | (u64)(dev_entry->common)); |
| 205 | else |
| 206 | status = sn_device_fixup_war(hubdev->hdi_nasid, |
| 207 | widget, device, |
| 208 | dev_entry->common); |
| 209 | if (status != SALRET_OK) |
| 210 | panic("SAL call failed: %s\n", |
| 211 | ia64_sal_strerror(status)); |
| 212 | |
| 213 | spin_lock_init(&dev_entry->sfdl_flush_lock); |
| 214 | } |
| 215 | |
| 216 | if (sn_flush_device_kernel) |
| 217 | hubdev->hdi_flush_nasid_list.widget_p[widget] = |
| 218 | sn_flush_device_kernel; |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | void sn_pci_unfixup_slot(struct pci_dev *dev) |
| 223 | { |
| 224 | struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; |
| 225 | |
| 226 | sn_irq_unfixup(dev); |
| 227 | pci_dev_put(host_pci_dev); |
| 228 | pci_dev_put(dev); |
| 229 | } |
| 230 | |
| 231 | /* |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 232 | * sn_pci_fixup_slot() |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 233 | */ |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 234 | void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info, |
| 235 | struct sn_irq_info *sn_irq_info) |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 236 | { |
| 237 | int segment = pci_domain_nr(dev->bus); |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 238 | struct pcibus_bussoft *bs; |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 239 | struct pci_bus *host_pci_bus; |
| 240 | struct pci_dev *host_pci_dev; |
| 241 | unsigned int bus_no, devfn; |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 242 | |
| 243 | pci_dev_get(dev); /* for the sysdata pointer */ |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 244 | |
| 245 | /* Add pcidev_info to list in pci_controller.platform_data */ |
| 246 | list_add_tail(&pcidev_info->pdi_list, |
| 247 | &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 248 | /* |
| 249 | * Using the PROMs values for the PCI host bus, get the Linux |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 250 | * PCI host_pci_dev struct and set up host bus linkages |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 251 | */ |
| 252 | |
| 253 | bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; |
| 254 | devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff; |
| 255 | host_pci_bus = pci_find_bus(segment, bus_no); |
| 256 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); |
| 257 | |
| 258 | pcidev_info->host_pci_dev = host_pci_dev; |
| 259 | pcidev_info->pdi_linux_pcidev = dev; |
| 260 | pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev); |
| 261 | bs = SN_PCIBUS_BUSSOFT(dev->bus); |
| 262 | pcidev_info->pdi_pcibus_info = bs; |
| 263 | |
| 264 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { |
| 265 | SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; |
| 266 | } else { |
| 267 | SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider; |
| 268 | } |
| 269 | |
| 270 | /* Only set up IRQ stuff if this device has a host bus context */ |
| 271 | if (bs && sn_irq_info->irq_irq) { |
| 272 | pcidev_info->pdi_sn_irq_info = sn_irq_info; |
| 273 | dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq; |
| 274 | sn_irq_fixup(dev, sn_irq_info); |
| 275 | } else { |
| 276 | pcidev_info->pdi_sn_irq_info = NULL; |
| 277 | kfree(sn_irq_info); |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | /* |
| 282 | * sn_common_bus_fixup - Perform platform specific bus fixup. |
| 283 | * Execute the ASIC specific fixup routine |
| 284 | * for this bus. |
| 285 | */ |
| 286 | void |
| 287 | sn_common_bus_fixup(struct pci_bus *bus, |
| 288 | struct pcibus_bussoft *prom_bussoft_ptr) |
| 289 | { |
| 290 | int cnode; |
| 291 | struct pci_controller *controller; |
| 292 | struct hubdev_info *hubdev_info; |
| 293 | int nasid; |
| 294 | void *provider_soft; |
| 295 | struct sn_pcibus_provider *provider; |
| 296 | struct sn_platform_data *sn_platform_data; |
| 297 | |
| 298 | controller = PCI_CONTROLLER(bus); |
| 299 | /* |
| 300 | * Per-provider fixup. Copies the bus soft structure from prom |
| 301 | * to local area and links SN_PCIBUS_BUSSOFT(). |
| 302 | */ |
| 303 | |
| 304 | if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { |
| 305 | printk(KERN_WARNING "sn_common_bus_fixup: Unsupported asic type, %d", |
| 306 | prom_bussoft_ptr->bs_asic_type); |
| 307 | return; |
| 308 | } |
| 309 | |
| 310 | if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) |
| 311 | return; /* no further fixup necessary */ |
| 312 | |
| 313 | provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; |
| 314 | if (provider == NULL) |
| 315 | panic("sn_common_bus_fixup: No provider registered for this asic type, %d", |
| 316 | prom_bussoft_ptr->bs_asic_type); |
| 317 | |
| 318 | if (provider->bus_fixup) |
| 319 | provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, |
| 320 | controller); |
| 321 | else |
| 322 | provider_soft = NULL; |
| 323 | |
| 324 | /* |
| 325 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr |
| 326 | * after this point. |
| 327 | */ |
| 328 | controller->platform_data = kzalloc(sizeof(struct sn_platform_data), |
| 329 | GFP_KERNEL); |
| 330 | if (controller->platform_data == NULL) |
| 331 | BUG(); |
| 332 | sn_platform_data = |
| 333 | (struct sn_platform_data *) controller->platform_data; |
| 334 | sn_platform_data->provider_soft = provider_soft; |
| 335 | INIT_LIST_HEAD(&((struct sn_platform_data *) |
| 336 | controller->platform_data)->pcidev_info); |
| 337 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); |
| 338 | cnode = nasid_to_cnodeid(nasid); |
| 339 | hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); |
| 340 | SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = |
| 341 | &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); |
| 342 | |
| 343 | /* |
| 344 | * If the node information we obtained during the fixup phase is |
| 345 | * invalid then set controller->node to -1 (undetermined) |
| 346 | */ |
| 347 | if (controller->node >= num_online_nodes()) { |
| 348 | struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus); |
| 349 | |
| 350 | printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u" |
| 351 | "L_IO=%lx L_MEM=%lx BASE=%lx\n", |
| 352 | b->bs_asic_type, b->bs_xid, b->bs_persist_busnum, |
| 353 | b->bs_legacy_io, b->bs_legacy_mem, b->bs_base); |
| 354 | printk(KERN_WARNING "on node %d but only %d nodes online." |
| 355 | "Association set to undetermined.\n", |
| 356 | controller->node, num_online_nodes()); |
| 357 | controller->node = -1; |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | void sn_bus_store_sysdata(struct pci_dev *dev) |
| 362 | { |
| 363 | struct sysdata_el *element; |
| 364 | |
| 365 | element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL); |
| 366 | if (!element) { |
Tony Luck | 34ef30c | 2007-05-10 09:39:41 -0700 | [diff] [blame] | 367 | dev_dbg(&dev->dev, "%s: out of memory!\n", __FUNCTION__); |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 368 | return; |
| 369 | } |
| 370 | element->sysdata = SN_PCIDEV_INFO(dev); |
| 371 | list_add(&element->entry, &sn_sysdata_list); |
| 372 | } |
| 373 | |
| 374 | void sn_bus_free_sysdata(void) |
| 375 | { |
| 376 | struct sysdata_el *element; |
| 377 | struct list_head *list, *safe; |
| 378 | |
| 379 | list_for_each_safe(list, safe, &sn_sysdata_list) { |
| 380 | element = list_entry(list, struct sysdata_el, entry); |
| 381 | list_del(&element->entry); |
| 382 | list_del(&(((struct pcidev_info *) |
| 383 | (element->sysdata))->pdi_list)); |
| 384 | kfree(element->sysdata); |
| 385 | kfree(element); |
| 386 | } |
| 387 | return; |
| 388 | } |
| 389 | |
| 390 | /* |
| 391 | * hubdev_init_node() - Creates the HUB data structure and link them to it's |
| 392 | * own NODE specific data area. |
| 393 | */ |
| 394 | void hubdev_init_node(nodepda_t * npda, cnodeid_t node) |
| 395 | { |
| 396 | struct hubdev_info *hubdev_info; |
| 397 | int size; |
| 398 | pg_data_t *pg; |
| 399 | |
| 400 | size = sizeof(struct hubdev_info); |
| 401 | |
| 402 | if (node >= num_online_nodes()) /* Headless/memless IO nodes */ |
| 403 | pg = NODE_DATA(0); |
| 404 | else |
| 405 | pg = NODE_DATA(node); |
| 406 | |
| 407 | hubdev_info = (struct hubdev_info *)alloc_bootmem_node(pg, size); |
| 408 | |
| 409 | npda->pdinfo = (void *)hubdev_info; |
| 410 | } |
| 411 | |
| 412 | geoid_t |
| 413 | cnodeid_get_geoid(cnodeid_t cnode) |
| 414 | { |
| 415 | struct hubdev_info *hubdev; |
| 416 | |
| 417 | hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); |
| 418 | return hubdev->hdi_geoid; |
| 419 | } |
| 420 | |
| 421 | void sn_generate_path(struct pci_bus *pci_bus, char *address) |
| 422 | { |
| 423 | nasid_t nasid; |
| 424 | cnodeid_t cnode; |
| 425 | geoid_t geoid; |
| 426 | moduleid_t moduleid; |
| 427 | u16 bricktype; |
| 428 | |
| 429 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base); |
| 430 | cnode = nasid_to_cnodeid(nasid); |
| 431 | geoid = cnodeid_get_geoid(cnode); |
| 432 | moduleid = geo_module(geoid); |
| 433 | |
| 434 | sprintf(address, "module_%c%c%c%c%.2d", |
| 435 | '0'+RACK_GET_CLASS(MODULE_GET_RACK(moduleid)), |
| 436 | '0'+RACK_GET_GROUP(MODULE_GET_RACK(moduleid)), |
| 437 | '0'+RACK_GET_NUM(MODULE_GET_RACK(moduleid)), |
| 438 | MODULE_GET_BTCHAR(moduleid), MODULE_GET_BPOS(moduleid)); |
| 439 | |
| 440 | /* Tollhouse requires slot id to be displayed */ |
| 441 | bricktype = MODULE_GET_BTYPE(moduleid); |
| 442 | if ((bricktype == L1_BRICKTYPE_191010) || |
| 443 | (bricktype == L1_BRICKTYPE_1932)) |
| 444 | sprintf(address, "%s^%d", address, geo_slot(geoid)); |
| 445 | } |
| 446 | |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 447 | void __devinit |
| 448 | sn_pci_fixup_bus(struct pci_bus *bus) |
| 449 | { |
| 450 | |
Len Brown | 647fb47 | 2007-02-02 22:14:22 -0500 | [diff] [blame] | 451 | if (SN_ACPI_BASE_SUPPORT()) |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 452 | sn_acpi_bus_fixup(bus); |
| 453 | else |
| 454 | sn_bus_fixup(bus); |
| 455 | } |
| 456 | |
| 457 | /* |
| 458 | * sn_io_early_init - Perform early IO (and some non-IO) initialization. |
| 459 | * In particular, setup the sn_pci_provider[] array. |
| 460 | * This needs to be done prior to any bus scanning |
| 461 | * (acpi_scan_init()) in the ACPI case, as the SN |
| 462 | * bus fixup code will reference the array. |
| 463 | */ |
| 464 | static int __init |
| 465 | sn_io_early_init(void) |
| 466 | { |
| 467 | int i; |
| 468 | |
| 469 | if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) |
| 470 | return 0; |
| 471 | |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 472 | /* we set the acpi revision to that of the DSDT table OEM rev. */ |
| 473 | { |
| 474 | struct acpi_table_header *header = NULL; |
| 475 | |
| 476 | acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); |
| 477 | BUG_ON(header == NULL); |
| 478 | sn_acpi_rev = header->oem_revision; |
| 479 | } |
| 480 | |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 481 | /* |
| 482 | * prime sn_pci_provider[]. Individial provider init routines will |
| 483 | * override their respective default entries. |
| 484 | */ |
| 485 | |
| 486 | for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++) |
| 487 | sn_pci_provider[i] = &sn_pci_default_provider; |
| 488 | |
| 489 | pcibr_init_provider(); |
| 490 | tioca_init_provider(); |
| 491 | tioce_init_provider(); |
| 492 | |
| 493 | /* |
| 494 | * This is needed to avoid bounce limit checks in the blk layer |
| 495 | */ |
| 496 | ia64_max_iommu_merge_mask = ~PAGE_MASK; |
| 497 | |
| 498 | sn_irq_lh_init(); |
| 499 | INIT_LIST_HEAD(&sn_sysdata_list); |
| 500 | sn_init_cpei_timer(); |
| 501 | |
| 502 | #ifdef CONFIG_PROC_FS |
| 503 | register_sn_procfs(); |
| 504 | #endif |
| 505 | |
Len Brown | 647fb47 | 2007-02-02 22:14:22 -0500 | [diff] [blame] | 506 | { |
| 507 | struct acpi_table_header *header; |
| 508 | (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); |
| 509 | printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", |
| 510 | header->oem_revision); |
| 511 | } |
| 512 | if (SN_ACPI_BASE_SUPPORT()) |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 513 | sn_io_acpi_init(); |
| 514 | else |
| 515 | sn_io_init(); |
| 516 | return 0; |
| 517 | } |
| 518 | |
| 519 | arch_initcall(sn_io_early_init); |
| 520 | |
| 521 | /* |
| 522 | * sn_io_late_init() - Perform any final platform specific IO initialization. |
| 523 | */ |
| 524 | |
| 525 | int __init |
| 526 | sn_io_late_init(void) |
| 527 | { |
| 528 | struct pci_bus *bus; |
| 529 | struct pcibus_bussoft *bussoft; |
| 530 | cnodeid_t cnode; |
| 531 | nasid_t nasid; |
| 532 | cnodeid_t near_cnode; |
| 533 | |
| 534 | if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) |
| 535 | return 0; |
| 536 | |
| 537 | /* |
| 538 | * Setup closest node in pci_controller->node for |
| 539 | * PIC, TIOCP, TIOCE (TIOCA does it during bus fixup using |
| 540 | * info from the PROM). |
| 541 | */ |
| 542 | bus = NULL; |
| 543 | while ((bus = pci_find_next_bus(bus)) != NULL) { |
| 544 | bussoft = SN_PCIBUS_BUSSOFT(bus); |
| 545 | nasid = NASID_GET(bussoft->bs_base); |
| 546 | cnode = nasid_to_cnodeid(nasid); |
| 547 | if ((bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCP) || |
| 548 | (bussoft->bs_asic_type == PCIIO_ASIC_TYPE_TIOCE)) { |
| 549 | /* TIO PCI Bridge: find nearest node with CPUs */ |
| 550 | int e = sn_hwperf_get_nearest_node(cnode, NULL, |
| 551 | &near_cnode); |
| 552 | if (e < 0) { |
| 553 | near_cnode = (cnodeid_t)-1; /* use any node */ |
| 554 | printk(KERN_WARNING "pcibr_bus_fixup: failed " |
| 555 | "to find near node with CPUs to TIO " |
| 556 | "node %d, err=%d\n", cnode, e); |
| 557 | } |
| 558 | PCI_CONTROLLER(bus)->node = near_cnode; |
| 559 | } else if (bussoft->bs_asic_type == PCIIO_ASIC_TYPE_PIC) { |
| 560 | PCI_CONTROLLER(bus)->node = cnode; |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | sn_ioif_inited = 1; /* SN I/O infrastructure now initialized */ |
| 565 | |
| 566 | return 0; |
| 567 | } |
| 568 | |
| 569 | fs_initcall(sn_io_late_init); |
| 570 | |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 571 | EXPORT_SYMBOL(sn_pci_unfixup_slot); |
| 572 | EXPORT_SYMBOL(sn_bus_store_sysdata); |
| 573 | EXPORT_SYMBOL(sn_bus_free_sysdata); |
| 574 | EXPORT_SYMBOL(sn_generate_path); |
| 575 | |