io_init.c 18.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
J
John Keller 已提交
6
 * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14
 */

#include <linux/bootmem.h>
#include <linux/nodemask.h>
#include <asm/sn/types.h>
#include <asm/sn/addrs.h>
#include <asm/sn/geo.h>
#include <asm/sn/io.h>
15 16 17
#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
L
Linus Torvalds 已提交
18
#include <asm/sn/simulator.h>
19
#include <asm/sn/sn_sal.h>
20
#include <asm/sn/tioca_provider.h>
21
#include <asm/sn/tioce_provider.h>
22 23
#include "xtalk/hubdev.h"
#include "xtalk/xwidgetdev.h"
L
Linus Torvalds 已提交
24

25 26 27 28 29 30 31 32
static struct list_head sn_sysdata_list;

/* sysdata list struct */
struct sysdata_el {
	struct list_head entry;
	void *sysdata;
};

L
Linus Torvalds 已提交
33 34 35 36 37 38 39 40 41 42 43
struct slab_info {
	struct hubdev_info hubdev;
};

struct brick {
	moduleid_t id;		/* Module ID of this module        */
	struct slab_info slab_info[MAX_SLABS + 1];
};

int sn_ioif_inited = 0;		/* SN I/O infrastructure initialized? */

44 45
struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];	/* indexed by asic type */

46 47 48
static int max_segment_number = 0; /* Default highest segment number */
static int max_pcibus_number = 255; /* Default highest pci bus number */

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
/*
 * Hooks and struct for unsupported pci providers
 */

static dma_addr_t
sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
{
	return 0;
}

static void
sn_default_pci_unmap(struct pci_dev *pdev, dma_addr_t addr, int direction)
{
	return;
}

static void *
66
sn_default_pci_bus_fixup(struct pcibus_bussoft *soft, struct pci_controller *controller)
67 68 69 70 71 72 73 74 75 76 77
{
	return NULL;
}

static struct sn_pcibus_provider sn_pci_default_provider = {
	.dma_map = sn_default_pci_map,
	.dma_map_consistent = sn_default_pci_map,
	.dma_unmap = sn_default_pci_unmap,
	.bus_fixup = sn_default_pci_bus_fixup,
};

L
Linus Torvalds 已提交
78
/*
79 80
 * Retrieve the DMA Flush List given nasid, widget, and device.
 * This list is needed to implement the WAR - Flush DMA data on PIO Reads.
L
Linus Torvalds 已提交
81
 */
82 83 84
static inline u64
sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
			     u64 address)
L
Linus Torvalds 已提交
85 86 87 88 89 90 91
{

	struct ia64_sal_retval ret_stuff;
	ret_stuff.status = 0;
	ret_stuff.v0 = 0;

	SAL_CALL_NOLOCK(ret_stuff,
92 93 94 95
			(u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST,
			(u64) nasid, (u64) widget_num,
			(u64) device_num, (u64) address, 0, 0, 0);
	return ret_stuff.status;
L
Linus Torvalds 已提交
96 97 98 99 100 101

}

/*
 * Retrieve the hub device info structure for the given nasid.
 */
102
static inline u64 sal_get_hubdev_info(u64 handle, u64 address)
L
Linus Torvalds 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
{

	struct ia64_sal_retval ret_stuff;
	ret_stuff.status = 0;
	ret_stuff.v0 = 0;

	SAL_CALL_NOLOCK(ret_stuff,
			(u64) SN_SAL_IOIF_GET_HUBDEV_INFO,
			(u64) handle, (u64) address, 0, 0, 0, 0, 0);
	return ret_stuff.v0;
}

/*
 * Retrieve the pci bus information given the bus number.
 */
118
static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
L
Linus Torvalds 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
{

	struct ia64_sal_retval ret_stuff;
	ret_stuff.status = 0;
	ret_stuff.v0 = 0;

	SAL_CALL_NOLOCK(ret_stuff,
			(u64) SN_SAL_IOIF_GET_PCIBUS_INFO,
			(u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0);
	return ret_stuff.v0;
}

/*
 * Retrieve the pci device information given the bus and device|function number.
 */
134
static inline u64
135 136
sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
		    u64 sn_irq_info)
L
Linus Torvalds 已提交
137 138 139 140 141 142 143
{
	struct ia64_sal_retval ret_stuff;
	ret_stuff.status = 0;
	ret_stuff.v0 = 0;

	SAL_CALL_NOLOCK(ret_stuff,
			(u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
144
			(u64) segment, (u64) bus_number, (u64) devfn,
L
Linus Torvalds 已提交
145 146 147 148 149
			(u64) pci_dev,
			sn_irq_info, 0, 0);
	return ret_stuff.v0;
}

J
John Keller 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
/*
 * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
 *			  device.
 */
inline struct pcidev_info *
sn_pcidev_info_get(struct pci_dev *dev)
{
	struct pcidev_info *pcidev;

	list_for_each_entry(pcidev,
			    &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) {
		if (pcidev->pdi_linux_pcidev == dev) {
			return pcidev;
		}
	}
	return NULL;
}

L
Linus Torvalds 已提交
168 169 170 171 172 173
/*
 * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
 *	each node in the system.
 */
static void sn_fixup_ionodes(void)
{
174 175
	struct sn_flush_device_kernel *sn_flush_device_kernel;
	struct sn_flush_device_kernel *dev_entry;
L
Linus Torvalds 已提交
176
	struct hubdev_info *hubdev;
177 178 179
	u64 status;
	u64 nasid;
	int i, widget, device;
L
Linus Torvalds 已提交
180

181 182 183 184
	/*
	 * Get SGI Specific HUB chipset information.
	 * Inform Prom that this kernel can support domain bus numbering.
	 */
185
	for (i = 0; i < num_cnodes; i++) {
L
Linus Torvalds 已提交
186 187
		hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
		nasid = cnodeid_to_nasid(i);
188 189
		hubdev->max_segment_number = 0xffffffff;
		hubdev->max_pcibus_number = 0xff;
190
		status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev));
L
Linus Torvalds 已提交
191 192 193
		if (status)
			continue;

194 195 196 197 198 199 200 201 202
		/* Save the largest Domain and pcibus numbers found. */
		if (hubdev->max_segment_number) {
			/*
			 * Dealing with a Prom that supports segments.
			 */
			max_segment_number = hubdev->max_segment_number;
			max_pcibus_number = hubdev->max_pcibus_number;
		}

203 204 205 206 207 208
		/* Attach the error interrupt handlers */
		if (nasid & 1)
			ice_error_init(hubdev);
		else
			hub_error_init(hubdev);

L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216
		for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++)
			hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev;

		if (!hubdev->hdi_flush_nasid_list.widget_p)
			continue;

		hubdev->hdi_flush_nasid_list.widget_p =
		    kmalloc((HUB_WIDGET_ID_MAX + 1) *
217 218
			    sizeof(struct sn_flush_device_kernel *),
			    GFP_KERNEL);
L
Linus Torvalds 已提交
219 220
		memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0,
		       (HUB_WIDGET_ID_MAX + 1) *
221
		       sizeof(struct sn_flush_device_kernel *));
L
Linus Torvalds 已提交
222 223

		for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
224 225 226 227 228 229 230
			sn_flush_device_kernel = kmalloc(DEV_PER_WIDGET *
						         sizeof(struct
						        sn_flush_device_kernel),
						        GFP_KERNEL);
			if (!sn_flush_device_kernel)
				BUG();
			memset(sn_flush_device_kernel, 0x0,
L
Linus Torvalds 已提交
231
			       DEV_PER_WIDGET *
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
			       sizeof(struct sn_flush_device_kernel));

			dev_entry = sn_flush_device_kernel;
			for (device = 0; device < DEV_PER_WIDGET;
			     device++,dev_entry++) {
				dev_entry->common = kmalloc(sizeof(struct
					      	        sn_flush_device_common),
					                    GFP_KERNEL);
				if (!dev_entry->common)
					BUG();
				memset(dev_entry->common, 0x0, sizeof(struct
					     	       sn_flush_device_common));

				status = sal_get_device_dmaflush_list(nasid,
									widget,
								       	device,
						      (u64)(dev_entry->common));
				if (status)
					BUG();

				spin_lock_init(&dev_entry->sfdl_flush_lock);
L
Linus Torvalds 已提交
253 254
			}

255 256 257 258
			if (sn_flush_device_kernel)
				hubdev->hdi_flush_nasid_list.widget_p[widget] =
						       sn_flush_device_kernel;
	        }
L
Linus Torvalds 已提交
259 260 261
	}
}

J
John Keller 已提交
262 263 264 265 266 267 268 269 270
/*
 * sn_pci_window_fixup() - Create a pci_window for each device resource.
 *			   Until ACPI support is added, we need this code
 *			   to setup pci_windows for use by
 *			   pcibios_bus_to_resource(),
 *			   pcibios_resource_to_bus(), etc.
 */
static void
sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
271
		    s64 * pci_addrs)
J
John Keller 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
{
	struct pci_controller *controller = PCI_CONTROLLER(dev->bus);
	unsigned int i;
	unsigned int idx;
	unsigned int new_count;
	struct pci_window *new_window;

	if (count == 0)
		return;
	idx = controller->windows;
	new_count = controller->windows + count;
	new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
	if (new_window == NULL)
		BUG();
	if (controller->window) {
		memcpy(new_window, controller->window,
		       sizeof(struct pci_window) * controller->windows);
		kfree(controller->window);
	}

	/* Setup a pci_window for each device resource. */
	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
		if (pci_addrs[i] == -1)
			continue;

		new_window[idx].offset = dev->resource[i].start - pci_addrs[i];
		new_window[idx].resource = dev->resource[i];
		idx++;
	}

	controller->windows = new_count;
	controller->window = new_window;
}

306 307 308 309 310 311 312 313 314
void sn_pci_unfixup_slot(struct pci_dev *dev)
{
	struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;

	sn_irq_unfixup(dev);
	pci_dev_put(host_pci_dev);
	pci_dev_put(dev);
}

L
Linus Torvalds 已提交
315 316 317 318 319 320
/*
 * sn_pci_fixup_slot() - This routine sets up a slot's resources
 * consistent with the Linux PCI abstraction layer.  Resources acquired
 * from our PCI provider include PIO maps to BAR space and interrupt
 * objects.
 */
321
void sn_pci_fixup_slot(struct pci_dev *dev)
L
Linus Torvalds 已提交
322
{
J
John Keller 已提交
323
	unsigned int count = 0;
L
Linus Torvalds 已提交
324
	int idx;
325
	int segment = pci_domain_nr(dev->bus);
L
Linus Torvalds 已提交
326
	int status = 0;
327
	struct pcibus_bussoft *bs;
328 329
 	struct pci_bus *host_pci_bus;
 	struct pci_dev *host_pci_dev;
J
John Keller 已提交
330
	struct pcidev_info *pcidev_info;
331
	s64 pci_addrs[PCI_ROM_RESOURCE + 1];
332 333 334
 	struct sn_irq_info *sn_irq_info;
 	unsigned long size;
 	unsigned int bus_no, devfn;
L
Linus Torvalds 已提交
335

336
	pci_dev_get(dev); /* for the sysdata pointer */
J
John Keller 已提交
337 338
	pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
	if (pcidev_info <= 0)
L
Linus Torvalds 已提交
339 340 341 342 343 344 345 346 347 348
		BUG();		/* Cannot afford to run out of memory */

	sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
	if (sn_irq_info <= 0)
		BUG();		/* Cannot afford to run out of memory */
	memset(sn_irq_info, 0, sizeof(struct sn_irq_info));

	/* Call to retrieve pci device information needed by kernel. */
	status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, 
				     dev->devfn,
J
John Keller 已提交
349
				     (u64) __pa(pcidev_info),
L
Linus Torvalds 已提交
350 351
				     (u64) __pa(sn_irq_info));
	if (status)
352
		BUG(); /* Cannot get platform pci device information */
L
Linus Torvalds 已提交
353

J
John Keller 已提交
354 355 356 357
	/* Add pcidev_info to list in sn_pci_controller struct */
	list_add_tail(&pcidev_info->pdi_list,
		      &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info));

L
Linus Torvalds 已提交
358 359 360 361
	/* Copy over PIO Mapped Addresses */
	for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
		unsigned long start, end, addr;

J
John Keller 已提交
362 363
		if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
			pci_addrs[idx] = -1;
L
Linus Torvalds 已提交
364
			continue;
J
John Keller 已提交
365
		}
L
Linus Torvalds 已提交
366 367 368 369

		start = dev->resource[idx].start;
		end = dev->resource[idx].end;
		size = end - start;
J
John Keller 已提交
370 371 372 373 374 375 376
		if (size == 0) {
			pci_addrs[idx] = -1;
			continue;
		}
		pci_addrs[idx] = start;
		count++;
		addr = pcidev_info->pdi_pio_mapped_addr[idx];
L
Linus Torvalds 已提交
377 378 379 380 381 382 383 384
		addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
		dev->resource[idx].start = addr;
		dev->resource[idx].end = addr + size;
		if (dev->resource[idx].flags & IORESOURCE_IO)
			dev->resource[idx].parent = &ioport_resource;
		else
			dev->resource[idx].parent = &iomem_resource;
	}
J
John Keller 已提交
385 386 387 388 389
	/* Create a pci_window in the pci_controller struct for
	 * each device resource.
	 */
	if (count > 0)
		sn_pci_window_fixup(dev, count, pci_addrs);
L
Linus Torvalds 已提交
390

391 392
	/*
	 * Using the PROMs values for the PCI host bus, get the Linux
393 394 395
 	 * PCI host_pci_dev struct and set up host bus linkages
 	 */

J
John Keller 已提交
396 397
	bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
	devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
398
 	host_pci_bus = pci_find_bus(segment, bus_no);
399 400
 	host_pci_dev = pci_get_slot(host_pci_bus, devfn);

J
John Keller 已提交
401 402 403
	pcidev_info->host_pci_dev = host_pci_dev;
	pcidev_info->pdi_linux_pcidev = dev;
	pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev);
404
	bs = SN_PCIBUS_BUSSOFT(dev->bus);
J
John Keller 已提交
405
	pcidev_info->pdi_pcibus_info = bs;
406 407 408 409 410 411

	if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
		SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
	} else {
		SN_PCIDEV_BUSPROVIDER(dev) = &sn_pci_default_provider;
	}
L
Linus Torvalds 已提交
412 413

	/* Only set up IRQ stuff if this device has a host bus context */
414
	if (bs && sn_irq_info->irq_irq) {
J
John Keller 已提交
415 416
		pcidev_info->pdi_sn_irq_info = sn_irq_info;
		dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq;
L
Linus Torvalds 已提交
417
		sn_irq_fixup(dev, sn_irq_info);
418
	} else {
J
John Keller 已提交
419
		pcidev_info->pdi_sn_irq_info = NULL;
420
		kfree(sn_irq_info);
L
Linus Torvalds 已提交
421 422 423 424 425 426 427
	}
}

/*
 * sn_pci_controller_fixup() - This routine sets up a bus's resources
 * consistent with the Linux PCI abstraction layer.
 */
428
void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
L
Linus Torvalds 已提交
429 430 431 432
{
	int status = 0;
	int nasid, cnode;
	struct pci_controller *controller;
J
John Keller 已提交
433
	struct sn_pci_controller *sn_controller;
L
Linus Torvalds 已提交
434 435
	struct pcibus_bussoft *prom_bussoft_ptr;
	struct hubdev_info *hubdev_info;
436
	void *provider_soft = NULL;
437
	struct sn_pcibus_provider *provider;
L
Linus Torvalds 已提交
438

439 440 441 442
 	status = sal_get_pcibus_info((u64) segment, (u64) busnum,
 				     (u64) ia64_tpa(&prom_bussoft_ptr));
 	if (status > 0)
		return;		/*bus # does not exist */
L
Linus Torvalds 已提交
443 444
	prom_bussoft_ptr = __va(prom_bussoft_ptr);

J
John Keller 已提交
445 446 447 448 449 450 451 452
	/* Allocate a sn_pci_controller, which has a pci_controller struct
	 * as the first member.
	 */
	sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL);
	if (!sn_controller)
		BUG();
	INIT_LIST_HEAD(&sn_controller->pcidev_info);
	controller = &sn_controller->pci_controller;
453
	controller->segment = segment;
454

L
Linus Torvalds 已提交
455
	if (bus == NULL) {
456 457
 		bus = pci_scan_bus(busnum, &pci_root_ops, controller);
 		if (bus == NULL)
458
 			goto error_return; /* error, or bus already scanned */
459
 		bus->sysdata = NULL;
L
Linus Torvalds 已提交
460 461
	}

462 463 464
	if (bus->sysdata)
		goto error_return; /* sysdata already alloc'd */

L
Linus Torvalds 已提交
465 466 467 468 469
	/*
	 * Per-provider fixup.  Copies the contents from prom to local
	 * area and links SN_PCIBUS_BUSSOFT().
	 */

470
	if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES)
471
		goto error_return; /* unsupported asic type */
472 473 474

	if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
		goto error_return; /* no further fixup necessary */
475 476

	provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
477
	if (provider == NULL)
478
		goto error_return; /* no provider registerd for this asic */
479

480
	bus->sysdata = controller;
481
	if (provider->bus_fixup)
482
		provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, controller);
L
Linus Torvalds 已提交
483

484 485 486 487 488
	if (provider_soft == NULL) {
		/* fixup failed or not applicable */
		bus->sysdata = NULL;
		goto error_return;
	}
L
Linus Torvalds 已提交
489

J
John Keller 已提交
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	/*
	 * Setup pci_windows for legacy IO and MEM space.
	 * (Temporary until ACPI support is in place.)
	 */
	controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL);
	if (controller->window == NULL)
		BUG();
	controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io;
	controller->window[0].resource.name = "legacy_io";
	controller->window[0].resource.flags = IORESOURCE_IO;
	controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io;
	controller->window[0].resource.end =
	    controller->window[0].resource.start + 0xffff;
	controller->window[0].resource.parent = &ioport_resource;
	controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem;
	controller->window[1].resource.name = "legacy_mem";
	controller->window[1].resource.flags = IORESOURCE_MEM;
	controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem;
	controller->window[1].resource.end =
	    controller->window[1].resource.start + (1024 * 1024) - 1;
	controller->window[1].resource.parent = &iomem_resource;
	controller->windows = 2;

L
Linus Torvalds 已提交
513 514 515 516 517 518 519 520 521 522 523
	/*
	 * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
	 * after this point.
	 */

	PCI_CONTROLLER(bus)->platform_data = provider_soft;
	nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
	cnode = nasid_to_cnodeid(nasid);
	hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
	SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
	    &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
524

525 526 527 528 529 530 531
	/*
	 * If the node information we obtained during the fixup phase is invalid
	 * then set controller->node to -1 (undetermined)
	 */
	if (controller->node >= num_online_nodes()) {
		struct pcibus_bussoft *b = SN_PCIBUS_BUSSOFT(bus);

532
		printk(KERN_WARNING "Device ASIC=%u XID=%u PBUSNUM=%u"
533 534 535 536 537 538 539 540
				    "L_IO=%lx L_MEM=%lx BASE=%lx\n",
			b->bs_asic_type, b->bs_xid, b->bs_persist_busnum,
			b->bs_legacy_io, b->bs_legacy_mem, b->bs_base);
		printk(KERN_WARNING "on node %d but only %d nodes online."
			"Association set to undetermined.\n",
			controller->node, num_online_nodes());
		controller->node = -1;
	}
541 542 543 544
	return;

error_return:

J
John Keller 已提交
545
	kfree(sn_controller);
546 547 548 549 550 551 552
	return;
}

void sn_bus_store_sysdata(struct pci_dev *dev)
{
	struct sysdata_el *element;

553
	element = kzalloc(sizeof(struct sysdata_el), GFP_KERNEL);
554 555 556 557
	if (!element) {
		dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
		return;
	}
J
John Keller 已提交
558
	element->sysdata = SN_PCIDEV_INFO(dev);
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
	list_add(&element->entry, &sn_sysdata_list);
}

void sn_bus_free_sysdata(void)
{
	struct sysdata_el *element;
	struct list_head *list;

sn_sysdata_free_start:
	list_for_each(list, &sn_sysdata_list) {
		element = list_entry(list, struct sysdata_el, entry);
		list_del(&element->entry);
		kfree(element->sysdata);
		kfree(element);
		goto sn_sysdata_free_start;
	}
	return;
L
Linus Torvalds 已提交
576 577 578 579 580 581 582 583 584 585 586
}

/*
 * Ugly hack to get PCI setup until we have a proper ACPI namespace.
 */

#define PCI_BUSES_TO_SCAN 256

static int __init sn_pci_init(void)
{
	int i = 0;
587
	int j = 0;
L
Linus Torvalds 已提交
588 589 590 591 592 593
	struct pci_dev *pci_dev = NULL;
	extern void sn_init_cpei_timer(void);
#ifdef CONFIG_PROC_FS
	extern void register_sn_procfs(void);
#endif

594
	if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
L
Linus Torvalds 已提交
595 596
		return 0;

597 598 599 600 601 602 603 604 605
	/*
	 * prime sn_pci_provider[].  Individial provider init routines will
	 * override their respective default entries.
	 */

	for (i = 0; i < PCIIO_ASIC_MAX_TYPES; i++)
		sn_pci_provider[i] = &sn_pci_default_provider;

	pcibr_init_provider();
606
	tioca_init_provider();
607
	tioce_init_provider();
608

L
Linus Torvalds 已提交
609 610 611 612 613
	/*
	 * This is needed to avoid bounce limit checks in the blk layer
	 */
	ia64_max_iommu_merge_mask = ~PAGE_MASK;
	sn_fixup_ionodes();
614
	sn_irq_lh_init();
615
	INIT_LIST_HEAD(&sn_sysdata_list);
L
Linus Torvalds 已提交
616 617 618 619 620 621
	sn_init_cpei_timer();

#ifdef CONFIG_PROC_FS
	register_sn_procfs();
#endif

622
	/* busses are not known yet ... */
623 624 625
	for (i = 0; i <= max_segment_number; i++)
		for (j = 0; j <= max_pcibus_number; j++)
			sn_pci_controller_fixup(i, j, NULL);
L
Linus Torvalds 已提交
626 627 628 629 630 631 632 633

	/*
	 * Generic Linux PCI Layer has created the pci_bus and pci_dev 
	 * structures - time for us to add our SN PLatform specific 
	 * information.
	 */

	while ((pci_dev =
634
		pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL)
L
Linus Torvalds 已提交
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
		sn_pci_fixup_slot(pci_dev);

	sn_ioif_inited = 1;	/* sn I/O infrastructure now initialized */

	return 0;
}

/*
 * hubdev_init_node() - Creates the HUB data structure and link them to it's 
 *	own NODE specific data area.
 */
void hubdev_init_node(nodepda_t * npda, cnodeid_t node)
{

	struct hubdev_info *hubdev_info;

	if (node >= num_online_nodes())	/* Headless/memless IO nodes */
		hubdev_info =
		    (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(0),
							     sizeof(struct
								    hubdev_info));
	else
		hubdev_info =
		    (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(node),
							     sizeof(struct
								    hubdev_info));
	npda->pdinfo = (void *)hubdev_info;

}

geoid_t
cnodeid_get_geoid(cnodeid_t cnode)
{

	struct hubdev_info *hubdev;

	hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
	return hubdev->hdi_geoid;

}

subsys_initcall(sn_pci_init);
677 678 679 680 681
EXPORT_SYMBOL(sn_pci_fixup_slot);
EXPORT_SYMBOL(sn_pci_unfixup_slot);
EXPORT_SYMBOL(sn_pci_controller_fixup);
EXPORT_SYMBOL(sn_bus_store_sysdata);
EXPORT_SYMBOL(sn_bus_free_sysdata);