pci.c 19.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 * Copyright (C) 2001 Allan Trautman, IBM Corporation
 *
 * iSeries specific routines for PCI.
5
 *
L
Linus Torvalds 已提交
6 7 8 9 10 11
 * Based on code from pci.c and iSeries_pci.c 32bit
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
12
 *
L
Linus Torvalds 已提交
13 14 15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
17
 *
L
Linus Torvalds 已提交
18 19 20 21 22
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
#include <linux/kernel.h>
23
#include <linux/list.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30 31 32 33 34
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
35
#include <asm/abs_addr.h>
36
#include <asm/firmware.h>
L
Linus Torvalds 已提交
37

38
#include <asm/iseries/hv_call_xm.h>
39
#include <asm/iseries/mf.h>
40
#include <asm/iseries/iommu.h>
L
Linus Torvalds 已提交
41

42
#include <asm/ppc-pci.h>
L
Linus Torvalds 已提交
43

44
#include "irq.h"
45
#include "pci.h"
46
#include "call_pci.h"
47

L
Linus Torvalds 已提交
48
/*
49
 * Forward declares of prototypes.
L
Linus Torvalds 已提交
50
 */
51
static struct device_node *find_Device_Node(int bus, int devfn);
L
Linus Torvalds 已提交
52

53
static int Pci_Retry_Max = 3;	/* Only retry 3 times  */
L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61 62 63 64 65
static int Pci_Error_Flag = 1;	/* Set Retry Error on. */

static struct pci_ops iSeries_pci_ops;

/*
 * Table defines
 * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.
 */
#define IOMM_TABLE_MAX_ENTRIES	1024
#define IOMM_TABLE_ENTRY_SIZE	0x0000000000400000UL
#define BASE_IO_MEMORY		0xE000000000000000UL

66
static unsigned long max_io_memory = BASE_IO_MEMORY;
L
Linus Torvalds 已提交
67 68 69 70 71
static long current_iomm_table_entry;

/*
 * Lookup Tables.
 */
72 73
static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES];
L
Linus Torvalds 已提交
74

75
static const char pci_io_text[] = "iSeries PCI I/O";
L
Linus Torvalds 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
static DEFINE_SPINLOCK(iomm_table_lock);

/*
 * iomm_table_allocate_entry
 *
 * Adds pci_dev entry in address translation table
 *
 * - Allocates the number of entries required in table base on BAR
 *   size.
 * - Allocates starting at BASE_IO_MEMORY and increases.
 * - The size is round up to be a multiple of entry size.
 * - CurrentIndex is incremented to keep track of the last entry.
 * - Builds the resource entry for allocated BARs.
 */
static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
{
	struct resource *bar_res = &dev->resource[bar_num];
	long bar_size = pci_resource_len(dev, bar_num);

	/*
	 * No space to allocate, quick exit, skip Allocation.
	 */
	if (bar_size == 0)
		return;
	/*
	 * Set Resource values.
	 */
	spin_lock(&iomm_table_lock);
	bar_res->name = pci_io_text;
105
	bar_res->start = BASE_IO_MEMORY +
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117
		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
	bar_res->end = bar_res->start + bar_size - 1;
	/*
	 * Allocate the number of table entries needed for BAR.
	 */
	while (bar_size > 0 ) {
		iomm_table[current_iomm_table_entry] = dev->sysdata;
		iobar_table[current_iomm_table_entry] = bar_num;
		bar_size -= IOMM_TABLE_ENTRY_SIZE;
		++current_iomm_table_entry;
	}
	max_io_memory = BASE_IO_MEMORY +
118
		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
L
Linus Torvalds 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
	spin_unlock(&iomm_table_lock);
}

/*
 * allocate_device_bars
 *
 * - Allocates ALL pci_dev BAR's and updates the resources with the
 *   BAR value.  BARS with zero length will have the resources
 *   The HvCallPci_getBarParms is used to get the size of the BAR
 *   space.  It calls iomm_table_allocate_entry to allocate
 *   each entry.
 * - Loops through The Bar resources(0 - 5) including the ROM
 *   is resource(6).
 */
static void allocate_device_bars(struct pci_dev *dev)
{
	int bar_num;

137
	for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
		iomm_table_allocate_entry(dev, bar_num);
}

/*
 * Log error information to system console.
 * Filter out the device not there errors.
 * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx
 * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
 * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
 */
static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
		int AgentId, int HvRc)
{
	if (HvRc == 0x0302)
		return;
	printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
	       Error_Text, Bus, SubBus, AgentId, HvRc);
}

/*
158
 * iSeries_pci_final_fixup(void)
L
Linus Torvalds 已提交
159 160 161 162
 */
void __init iSeries_pci_final_fixup(void)
{
	struct pci_dev *pdev = NULL;
163
	struct device_node *node;
164
	int DeviceCount = 0;
L
Linus Torvalds 已提交
165 166 167 168 169 170 171 172 173 174 175

	/* Fix up at the device node and pci_dev relationship */
	mf_display_src(0xC9000100);

	printk("pcibios_final_fixup\n");
	for_each_pci_dev(pdev) {
		node = find_Device_Node(pdev->bus->number, pdev->devfn);
		printk("pci dev %p (%x.%x), node %p\n", pdev,
		       pdev->bus->number, pdev->devfn, node);

		if (node != NULL) {
176
			struct pci_dn *pdn = PCI_DN(node);
177
			const u32 *agent;
178

179
			agent = of_get_property(node, "linux,agent-id", NULL);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
			if ((pdn != NULL) && (agent != NULL)) {
				u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
						pdn->bussubno);
				int err;

				err = HvCallXm_connectBusUnit(pdn->busno, pdn->bussubno,
						*agent, irq);
				if (err)
					pci_Log_Error("Connect Bus Unit",
						pdn->busno, pdn->bussubno, *agent, err);
				else {
					err = HvCallPci_configStore8(pdn->busno, pdn->bussubno,
							*agent,
							PCI_INTERRUPT_LINE,
							irq);
					if (err)
						pci_Log_Error("PciCfgStore Irq Failed!",
							pdn->busno, pdn->bussubno, *agent, err);
				}
				if (!err)
					pdev->irq = irq;
			}

L
Linus Torvalds 已提交
203 204
			++DeviceCount;
			pdev->sysdata = (void *)node;
205
			PCI_DN(node)->pcidev = pdev;
L
Linus Torvalds 已提交
206
			allocate_device_bars(pdev);
207
			iSeries_Device_Information(pdev, DeviceCount);
208
			iommu_devnode_init_iSeries(pdev, node);
L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216 217 218 219
		} else
			printk("PCI: Device Tree not found for 0x%016lX\n",
					(unsigned long)pdev);
	}
	iSeries_activate_IRQs();
	mf_display_src(0xC9000200);
}

/*
 * Look down the chain to find the matching Device Device
 */
220
static struct device_node *find_Device_Node(int bus, int devfn)
L
Linus Torvalds 已提交
221
{
222 223 224 225
	struct device_node *node;

	for (node = NULL; (node = of_find_all_nodes(node)); ) {
		struct pci_dn *pdn = PCI_DN(node);
L
Linus Torvalds 已提交
226

227 228
		if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
			return node;
L
Linus Torvalds 已提交
229 230 231 232 233 234 235 236 237 238
	}
	return NULL;
}

#if 0
/*
 * Returns the device node for the passed pci_dev
 * Sanity Check Node PciDev to passed pci_dev
 * If none is found, returns a NULL which the client must handle.
 */
239
static struct device_node *get_Device_Node(struct pci_dev *pdev)
L
Linus Torvalds 已提交
240
{
241
	struct device_node *node;
L
Linus Torvalds 已提交
242 243

	node = pdev->sysdata;
244
	if (node == NULL || PCI_DN(node)->pcidev != pdev)
L
Linus Torvalds 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
		node = find_Device_Node(pdev->bus->number, pdev->devfn);
	return node;
}
#endif

/*
 * Config space read and write functions.
 * For now at least, we look for the device node for the bus and devfn
 * that we are asked to access.  It may be possible to translate the devfn
 * to a subbus and deviceid more directly.
 */
static u64 hv_cfg_read_func[4]  = {
	HvCallPciConfigLoad8, HvCallPciConfigLoad16,
	HvCallPciConfigLoad32, HvCallPciConfigLoad32
};

static u64 hv_cfg_write_func[4] = {
	HvCallPciConfigStore8, HvCallPciConfigStore16,
	HvCallPciConfigStore32, HvCallPciConfigStore32
};

/*
 * Read PCI config space
 */
static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
		int offset, int size, u32 *val)
{
272
	struct device_node *node = find_Device_Node(bus->number, devfn);
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281 282 283
	u64 fn;
	struct HvCallPci_LoadReturn ret;

	if (node == NULL)
		return PCIBIOS_DEVICE_NOT_FOUND;
	if (offset > 255) {
		*val = ~0;
		return PCIBIOS_BAD_REGISTER_NUMBER;
	}

	fn = hv_cfg_read_func[(size - 1) & 3];
284
	HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0);
L
Linus Torvalds 已提交
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

	if (ret.rc != 0) {
		*val = ~0;
		return PCIBIOS_DEVICE_NOT_FOUND;	/* or something */
	}

	*val = ret.value;
	return 0;
}

/*
 * Write PCI config space
 */

static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
		int offset, int size, u32 val)
{
302
	struct device_node *node = find_Device_Node(bus->number, devfn);
L
Linus Torvalds 已提交
303 304 305 306 307 308 309 310 311
	u64 fn;
	u64 ret;

	if (node == NULL)
		return PCIBIOS_DEVICE_NOT_FOUND;
	if (offset > 255)
		return PCIBIOS_BAD_REGISTER_NUMBER;

	fn = hv_cfg_write_func[(size - 1) & 3];
312
	ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0);
L
Linus Torvalds 已提交
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333

	if (ret != 0)
		return PCIBIOS_DEVICE_NOT_FOUND;

	return 0;
}

static struct pci_ops iSeries_pci_ops = {
	.read = iSeries_pci_read_config,
	.write = iSeries_pci_write_config
};

/*
 * Check Return Code
 * -> On Failure, print and log information.
 *    Increment Retry Count, if exceeds max, panic partition.
 *
 * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
 * PCI: Device 23.90 ReadL Retry( 1)
 * PCI: Device 23.90 ReadL Retry Successful(1)
 */
334
static int CheckReturnCode(char *TextHdr, struct device_node *DevNode,
335
		int *retry, u64 ret)
L
Linus Torvalds 已提交
336 337
{
	if (ret != 0)  {
338 339
		struct pci_dn *pdn = PCI_DN(DevNode);

340
		(*retry)++;
L
Linus Torvalds 已提交
341
		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
342
				TextHdr, pdn->busno, pdn->devfn,
343
				*retry, (int)ret);
L
Linus Torvalds 已提交
344 345 346 347
		/*
		 * Bump the retry and check for retry count exceeded.
		 * If, Exceeded, panic the system.
		 */
348
		if (((*retry) > Pci_Retry_Max) &&
L
Linus Torvalds 已提交
349 350
				(Pci_Error_Flag > 0)) {
			mf_display_src(0xB6000103);
351
			panic_timeout = 0;
L
Linus Torvalds 已提交
352 353 354 355 356
			panic("PCI: Hardware I/O Error, SRC B6000103, "
					"Automatic Reboot Disabled.\n");
		}
		return -1;	/* Retry Try */
	}
357
	return 0;
L
Linus Torvalds 已提交
358 359 360 361 362 363 364
}

/*
 * Translate the I/O Address into a device node, bar, and bar offset.
 * Note: Make sure the passed variable end up on the stack to avoid
 * the exposure of being device global.
 */
365
static inline struct device_node *xlate_iomm_address(
L
Linus Torvalds 已提交
366 367 368 369 370 371
		const volatile void __iomem *IoAddress,
		u64 *dsaptr, u64 *BarOffsetPtr)
{
	unsigned long OrigIoAddr;
	unsigned long BaseIoAddr;
	unsigned long TableIndex;
372
	struct device_node *DevNode;
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380 381 382

	OrigIoAddr = (unsigned long __force)IoAddress;
	if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory))
		return NULL;
	BaseIoAddr = OrigIoAddr - BASE_IO_MEMORY;
	TableIndex = BaseIoAddr / IOMM_TABLE_ENTRY_SIZE;
	DevNode = iomm_table[TableIndex];

	if (DevNode != NULL) {
		int barnum = iobar_table[TableIndex];
383
		*dsaptr = iseries_ds_addr(DevNode) | (barnum << 24);
L
Linus Torvalds 已提交
384 385 386 387 388 389 390 391 392
		*BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE;
	} else
		panic("PCI: Invalid PCI IoAddress detected!\n");
	return DevNode;
}

/*
 * Read MM I/O Instructions for the iSeries
 * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
393
 * else, data is returned in Big Endian format.
L
Linus Torvalds 已提交
394
 */
395
static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
L
Linus Torvalds 已提交
396 397 398
{
	u64 BarOffset;
	u64 dsa;
399
	int retry = 0;
L
Linus Torvalds 已提交
400
	struct HvCallPci_LoadReturn ret;
401
	struct device_node *DevNode =
L
Linus Torvalds 已提交
402 403 404 405 406 407 408 409 410 411 412
		xlate_iomm_address(IoAddress, &dsa, &BarOffset);

	if (DevNode == NULL) {
		static unsigned long last_jiffies;
		static int num_printed;

		if ((jiffies - last_jiffies) > 60 * HZ) {
			last_jiffies = jiffies;
			num_printed = 0;
		}
		if (num_printed++ < 10)
413 414
			printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
			       IoAddress);
L
Linus Torvalds 已提交
415 416 417 418
		return 0xff;
	}
	do {
		HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
419
	} while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0);
L
Linus Torvalds 已提交
420

421
	return ret.value;
L
Linus Torvalds 已提交
422 423
}

424
static u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
L
Linus Torvalds 已提交
425 426 427
{
	u64 BarOffset;
	u64 dsa;
428
	int retry = 0;
L
Linus Torvalds 已提交
429
	struct HvCallPci_LoadReturn ret;
430
	struct device_node *DevNode =
L
Linus Torvalds 已提交
431 432 433 434 435 436 437 438 439 440 441
		xlate_iomm_address(IoAddress, &dsa, &BarOffset);

	if (DevNode == NULL) {
		static unsigned long last_jiffies;
		static int num_printed;

		if ((jiffies - last_jiffies) > 60 * HZ) {
			last_jiffies = jiffies;
			num_printed = 0;
		}
		if (num_printed++ < 10)
442 443
			printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n",
			       IoAddress);
L
Linus Torvalds 已提交
444 445 446 447 448
		return 0xffff;
	}
	do {
		HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
				BarOffset, 0);
449
	} while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
L
Linus Torvalds 已提交
450

451
	return ret.value;
L
Linus Torvalds 已提交
452 453
}

454
static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
L
Linus Torvalds 已提交
455 456 457
{
	u64 BarOffset;
	u64 dsa;
458
	int retry = 0;
L
Linus Torvalds 已提交
459
	struct HvCallPci_LoadReturn ret;
460
	struct device_node *DevNode =
L
Linus Torvalds 已提交
461 462 463 464 465 466 467 468 469 470 471
		xlate_iomm_address(IoAddress, &dsa, &BarOffset);

	if (DevNode == NULL) {
		static unsigned long last_jiffies;
		static int num_printed;

		if ((jiffies - last_jiffies) > 60 * HZ) {
			last_jiffies = jiffies;
			num_printed = 0;
		}
		if (num_printed++ < 10)
472 473
			printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n",
			       IoAddress);
L
Linus Torvalds 已提交
474 475 476 477 478
		return 0xffffffff;
	}
	do {
		HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
				BarOffset, 0);
479
	} while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
L
Linus Torvalds 已提交
480

481
	return ret.value;
L
Linus Torvalds 已提交
482 483 484 485 486 487
}

/*
 * Write MM I/O Instructions for the iSeries
 *
 */
488
static void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
L
Linus Torvalds 已提交
489 490 491
{
	u64 BarOffset;
	u64 dsa;
492
	int retry = 0;
L
Linus Torvalds 已提交
493
	u64 rc;
494
	struct device_node *DevNode =
L
Linus Torvalds 已提交
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
		xlate_iomm_address(IoAddress, &dsa, &BarOffset);

	if (DevNode == NULL) {
		static unsigned long last_jiffies;
		static int num_printed;

		if ((jiffies - last_jiffies) > 60 * HZ) {
			last_jiffies = jiffies;
			num_printed = 0;
		}
		if (num_printed++ < 10)
			printk(KERN_ERR "iSeries_Write_Byte: invalid access at IO address %p\n", IoAddress);
		return;
	}
	do {
		rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
511
	} while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
L
Linus Torvalds 已提交
512 513
}

514
static void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress)
L
Linus Torvalds 已提交
515 516 517
{
	u64 BarOffset;
	u64 dsa;
518
	int retry = 0;
L
Linus Torvalds 已提交
519
	u64 rc;
520
	struct device_node *DevNode =
L
Linus Torvalds 已提交
521 522 523 524 525 526 527 528 529 530 531
		xlate_iomm_address(IoAddress, &dsa, &BarOffset);

	if (DevNode == NULL) {
		static unsigned long last_jiffies;
		static int num_printed;

		if ((jiffies - last_jiffies) > 60 * HZ) {
			last_jiffies = jiffies;
			num_printed = 0;
		}
		if (num_printed++ < 10)
532 533
			printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n",
			       IoAddress);
L
Linus Torvalds 已提交
534 535 536
		return;
	}
	do {
537
		rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, data, 0);
538
	} while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
L
Linus Torvalds 已提交
539 540
}

541
static void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress)
L
Linus Torvalds 已提交
542 543 544
{
	u64 BarOffset;
	u64 dsa;
545
	int retry = 0;
L
Linus Torvalds 已提交
546
	u64 rc;
547
	struct device_node *DevNode =
L
Linus Torvalds 已提交
548 549 550 551 552 553 554 555 556 557 558
		xlate_iomm_address(IoAddress, &dsa, &BarOffset);

	if (DevNode == NULL) {
		static unsigned long last_jiffies;
		static int num_printed;

		if ((jiffies - last_jiffies) > 60 * HZ) {
			last_jiffies = jiffies;
			num_printed = 0;
		}
		if (num_printed++ < 10)
559 560
			printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n",
			       IoAddress);
L
Linus Torvalds 已提交
561 562 563
		return;
	}
	do {
564
		rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, data, 0);
565
	} while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
L
Linus Torvalds 已提交
566
}
567

568
static u8 iseries_readb(const volatile void __iomem *addr)
569
{
570
	return iSeries_Read_Byte(addr);
571 572
}

573
static u16 iseries_readw(const volatile void __iomem *addr)
574
{
575
	return le16_to_cpu(iSeries_Read_Word(addr));
576 577
}

578
static u32 iseries_readl(const volatile void __iomem *addr)
579
{
580
	return le32_to_cpu(iSeries_Read_Long(addr));
581 582
}

583
static u16 iseries_readw_be(const volatile void __iomem *addr)
584
{
585
	return iSeries_Read_Word(addr);
586 587
}

588
static u32 iseries_readl_be(const volatile void __iomem *addr)
589
{
590
	return iSeries_Read_Long(addr);
591 592
}

593
static void iseries_writeb(u8 data, volatile void __iomem *addr)
594
{
595
	iSeries_Write_Byte(data, addr);
596 597
}

598
static void iseries_writew(u16 data, volatile void __iomem *addr)
599
{
600
	iSeries_Write_Word(cpu_to_le16(data), addr);
601 602
}

603
static void iseries_writel(u32 data, volatile void __iomem *addr)
604
{
605
	iSeries_Write_Long(cpu_to_le32(data), addr);
606 607
}

608
static void iseries_writew_be(u16 data, volatile void __iomem *addr)
609
{
610
	iSeries_Write_Word(data, addr);
611 612
}

613
static void iseries_writel_be(u32 data, volatile void __iomem *addr)
614
{
615
	iSeries_Write_Long(data, addr);
616 617
}

618 619
static void iseries_readsb(const volatile void __iomem *addr, void *buf,
			   unsigned long count)
620
{
621 622 623
	u8 *dst = buf;
	while(count-- > 0)
		*(dst++) = iSeries_Read_Byte(addr);
624 625
}

626 627
static void iseries_readsw(const volatile void __iomem *addr, void *buf,
			   unsigned long count)
628
{
629 630 631
	u16 *dst = buf;
	while(count-- > 0)
		*(dst++) = iSeries_Read_Word(addr);
632 633
}

634 635
static void iseries_readsl(const volatile void __iomem *addr, void *buf,
			   unsigned long count)
636
{
637 638 639
	u32 *dst = buf;
	while(count-- > 0)
		*(dst++) = iSeries_Read_Long(addr);
640 641
}

642 643
static void iseries_writesb(volatile void __iomem *addr, const void *buf,
			    unsigned long count)
644
{
645 646 647
	const u8 *src = buf;
	while(count-- > 0)
		iSeries_Write_Byte(*(src++), addr);
648 649
}

650 651
static void iseries_writesw(volatile void __iomem *addr, const void *buf,
			    unsigned long count)
652
{
653 654 655
	const u16 *src = buf;
	while(count-- > 0)
		iSeries_Write_Word(*(src++), addr);
656 657
}

658 659
static void iseries_writesl(volatile void __iomem *addr, const void *buf,
			    unsigned long count)
660
{
661 662 663
	const u32 *src = buf;
	while(count-- > 0)
		iSeries_Write_Long(*(src++), addr);
664 665
}

666 667
static void iseries_memset_io(volatile void __iomem *addr, int c,
			      unsigned long n)
668
{
669
	volatile char __iomem *d = addr;
670

671 672
	while (n-- > 0)
		iSeries_Write_Byte(c, d++);
673 674
}

675 676
static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
				  unsigned long n)
677
{
678 679
	char *d = dest;
	const volatile char __iomem *s = src;
680

681 682
	while (n-- > 0)
		*d++ = iSeries_Read_Byte(s++);
683 684
}

685 686
static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
				unsigned long n)
687
{
688 689
	const char *s = src;
	volatile char __iomem *d = dest;
690

691 692
	while (n-- > 0)
		iSeries_Write_Byte(*s++, d++);
693 694
}

695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
/* We only set MMIO ops. The default PIO ops will be default
 * to the MMIO ops + pci_io_base which is 0 on iSeries as
 * expected so both should work.
 *
 * Note that we don't implement the readq/writeq versions as
 * I don't know of an HV call for doing so. Thus, the default
 * operation will be used instead, which will fault a the value
 * return by iSeries for MMIO addresses always hits a non mapped
 * area. This is as good as the BUG() we used to have there.
 */
static struct ppc_pci_io __initdata iseries_pci_io = {
	.readb = iseries_readb,
	.readw = iseries_readw,
	.readl = iseries_readl,
	.readw_be = iseries_readw_be,
	.readl_be = iseries_readl_be,
	.writeb = iseries_writeb,
	.writew = iseries_writew,
	.writel = iseries_writel,
	.writew_be = iseries_writew_be,
	.writel_be = iseries_writel_be,
	.readsb = iseries_readsb,
	.readsw = iseries_readsw,
	.readsl = iseries_readsl,
	.writesb = iseries_writesb,
	.writesw = iseries_writesw,
	.writesl = iseries_writesl,
	.memset_io = iseries_memset_io,
	.memcpy_fromio = iseries_memcpy_fromio,
	.memcpy_toio = iseries_memcpy_toio,
};
726

727 728 729 730 731 732 733 734 735 736
/*
 * iSeries_pcibios_init
 *
 * Description:
 *   This function checks for all possible system PCI host bridges that connect
 *   PCI buses.  The system hypervisor is queried as to the guest partition
 *   ownership status.  A pci_controller is built for any bus which is partially
 *   owned or fully owned by this guest partition.
 */
void __init iSeries_pcibios_init(void)
737
{
738 739 740
	struct pci_controller *phb;
	struct device_node *root = of_find_node_by_path("/");
	struct device_node *node = NULL;
741

742 743
	/* Install IO hooks */
	ppc_pci_io = iseries_pci_io;
744

745 746 747 748 749
	/* iSeries has no IO space in the common sense, it needs to set
	 * the IO base to 0
	 */
	pci_io_base = 0;

750 751 752 753 754 755 756 757
	if (root == NULL) {
		printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
				"of device tree\n");
		return;
	}
	while ((node = of_get_next_child(root, node)) != NULL) {
		HvBusNumber bus;
		const u32 *busp;
758

759 760
		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
			continue;
761

762
		busp = of_get_property(node, "bus-range", NULL);
763 764 765 766 767 768 769
		if (busp == NULL)
			continue;
		bus = *busp;
		printk("bus %d appears to exist\n", bus);
		phb = pcibios_alloc_controller(node);
		if (phb == NULL)
			continue;
770

771 772 773 774 775
		phb->pci_mem_offset = phb->local_number = bus;
		phb->first_busno = bus;
		phb->last_busno = bus;
		phb->ops = &iSeries_pci_ops;
	}
776

777
	of_node_put(root);
778

779
	pci_devs_phb_init();
780
}
781