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