Commit c4f34fde authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: Get native PCI going on iSeries, from Paul Mackerras

From: Anton Blanchard <anton@samba.org>

Get native PCI going on iSeries, from Paul Mackerras
parent 0385d58f
......@@ -31,7 +31,6 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <asm/ppcdebug.h>
#include <asm/flight_recorder.h>
#include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/iSeries_pci.h>
......
......@@ -153,7 +153,7 @@ int device_Location(struct pci_dev *PciDev, char *BufPtr)
struct iSeries_Device_Node *DevNode =
(struct iSeries_Device_Node *)PciDev->sysdata;
return sprintf(BufPtr, "PCI: Bus%3d, AgentId%3d, Vendor %04X, Location %s",
DevNode->DsaAddr.busNumber, DevNode->AgentId,
DevNode->DsaAddr.Dsa.busNumber, DevNode->AgentId,
DevNode->Vendor, DevNode->Location);
}
......
......@@ -55,45 +55,13 @@ static hw_irq_controller iSeries_IRQ_handler = {
.end = iSeries_end_IRQ
};
struct iSeries_irqEntry {
u32 dsa;
struct iSeries_irqEntry* next;
};
struct iSeries_irqAnchor {
u8 valid : 1;
u8 reserved : 7;
u16 entryCount;
struct iSeries_irqEntry* head;
};
static struct iSeries_irqAnchor iSeries_irqMap[NR_IRQS];
#if 0
static void iSeries_init_irqMap(int irq);
#endif
void iSeries_init_irq_desc(irq_desc_t *desc)
{
desc->handler = &iSeries_IRQ_handler;
}
/* This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c */
void __init iSeries_init_IRQ(void)
{
#if 0
int i;
irq_desc_t *desc;
for (i = 0; i < NR_IRQS; i++) {
desc = get_irq_desc(i);
desc->handler = &iSeries_IRQ_handler;
desc->status = 0;
desc->status |= IRQ_DISABLED;
desc->depth = 1;
iSeries_init_irqMap(i);
}
#endif
/* Register PCI event handler and open an event path */
PPCDBG(PPCDBG_BUSWALK,
"Register PCI event handler and open an event path\n");
......@@ -101,35 +69,24 @@ void __init iSeries_init_IRQ(void)
return;
}
#if 0
/*
* Called by iSeries_init_IRQ
* Prevent IRQs 0 and 255 from being used. IRQ 0 appears in
* uninitialized devices. IRQ 255 appears in the PCI interrupt
* line register if a PCI error occurs,
*/
static void __init iSeries_init_irqMap(int irq)
{
iSeries_irqMap[irq].valid = ((irq == 0) || (irq == 255)) ? 0 : 1;
iSeries_irqMap[irq].entryCount = 0;
iSeries_irqMap[irq].head = NULL;
}
#endif
/*
* This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
* It calculates the irq value for the slot.
* Note that subBusNumber is always 0 (at the moment at least).
*/
int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
HvSubBusNumber subBusNumber, HvAgentId deviceId)
{
u8 idsel = (deviceId >> 4);
u8 function = deviceId & 0x0F;
u8 function = deviceId & 7;
return ((((busNumber - 1) * 16 + (idsel - 1) * 8
+ function) * 9 / 8) % 253) + 2;
return ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function + 1;
}
#define IRQ_TO_BUS(irq) (((((irq) - 1) >> 6) & 0xff) + 1)
#define IRQ_TO_IDSEL(irq) (((((irq) - 1) >> 3) & 7) + 1)
#define IRQ_TO_FUNC(irq) (((irq) - 1) & 7)
/*
* This is called out of iSeries_scan_slot to assign the EADS slot
* to its IRQ number
......@@ -137,66 +94,33 @@ int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
int __init iSeries_assign_IRQ(int irq, HvBusNumber busNumber,
HvSubBusNumber subBusNumber, HvAgentId deviceId)
{
int rc;
u32 dsa = (busNumber << 16) | (subBusNumber << 8) | deviceId;
struct iSeries_irqEntry *newEntry;
unsigned long flags;
irq_desc_t *desc = get_irq_desc(irq);
irq_desc_t *desc = get_real_irq_desc(irq);
if ((irq < 0) || (irq >= NR_IRQS))
if (desc == NULL)
return -1;
newEntry = kmalloc(sizeof(*newEntry), GFP_KERNEL);
if (newEntry == NULL)
return -ENOMEM;
newEntry->dsa = dsa;
newEntry->next = NULL;
/*
* Probably not necessary to lock the irq since allocation is only
* done during buswalk, but it should not hurt anything except a
* little performance to be smp safe.
*/
spin_lock_irqsave(&desc->lock, flags);
if (iSeries_irqMap[irq].valid) {
/* Push the new element onto the irq stack */
newEntry->next = iSeries_irqMap[irq].head;
iSeries_irqMap[irq].head = newEntry;
++iSeries_irqMap[irq].entryCount;
rc = 0;
PPCDBG(PPCDBG_BUSWALK, "iSeries_assign_IRQ 0x%04X.%02X.%02X = 0x%04X\n",
busNumber, subBusNumber, deviceId, irq);
} else {
printk("PCI: Something is wrong with the iSeries_irqMap.\n");
kfree(newEntry);
rc = -1;
}
spin_unlock_irqrestore(&desc->lock, flags);
return rc;
desc->handler = &iSeries_IRQ_handler;
return 0;
}
/* This is called by iSeries_activate_IRQs */
static unsigned int iSeries_startup_IRQ(unsigned int irq)
{
struct iSeries_irqEntry *entry;
u32 bus, subBus, deviceId, function, mask;
u32 bus, deviceId, function, mask;
const u32 subBus = 0;
for (entry = iSeries_irqMap[irq].head; entry != NULL;
entry = entry->next) {
bus = (entry->dsa >> 16) & 0xFFFF;
subBus = (entry->dsa >> 8) & 0xFF;
deviceId = entry->dsa & 0xFF;
function = deviceId & 0x0F;
/* Link the IRQ number to the bridge */
HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
/* Unmask bridge interrupts in the FISR */
mask = 0x01010000 << function;
HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK, "iSeries_activate_IRQ 0x%02X.%02X.%02X Irq:0x%02X\n",
bus = IRQ_TO_BUS(irq);
function = IRQ_TO_FUNC(irq);
deviceId = (IRQ_TO_IDSEL(irq) << 4) + function;
/* Link the IRQ number to the bridge */
HvCallXm_connectBusUnit(bus, subBus, deviceId, irq);
/* Unmask bridge interrupts in the FISR */
mask = 0x01010000 << function;
HvCallPci_unmaskFisr(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK, "iSeries_activate_IRQ 0x%02X.%02X.%02X Irq:0x%02X\n",
bus, subBus, deviceId, irq);
}
return 0;
}
......@@ -223,22 +147,20 @@ void __init iSeries_activate_IRQs()
/* this is not called anywhere currently */
static void iSeries_shutdown_IRQ(unsigned int irq)
{
struct iSeries_irqEntry *entry;
u32 bus, subBus, deviceId, function, mask;
u32 bus, deviceId, function, mask;
const u32 subBus = 0;
/* irq should be locked by the caller */
bus = IRQ_TO_BUS(irq);
function = IRQ_TO_FUNC(irq);
deviceId = (IRQ_TO_IDSEL(irq) << 4) + function;
/* Invalidate the IRQ number in the bridge */
HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
for (entry = iSeries_irqMap[irq].head; entry; entry = entry->next) {
bus = (entry->dsa >> 16) & 0xFFFF;
subBus = (entry->dsa >> 8) & 0xFF;
deviceId = entry->dsa & 0xFF;
function = deviceId & 0x0F;
/* Invalidate the IRQ number in the bridge */
HvCallXm_connectBusUnit(bus, subBus, deviceId, 0);
/* Mask bridge interrupts in the FISR */
mask = 0x01010000 << function;
HvCallPci_maskFisr(bus, subBus, deviceId, mask);
}
/* Mask bridge interrupts in the FISR */
mask = 0x01010000 << function;
HvCallPci_maskFisr(bus, subBus, deviceId, mask);
}
/*
......@@ -247,21 +169,19 @@ static void iSeries_shutdown_IRQ(unsigned int irq)
*/
static void iSeries_disable_IRQ(unsigned int irq)
{
struct iSeries_irqEntry *entry;
u32 bus, subBus, deviceId, mask;
u32 bus, deviceId, function, mask;
const u32 subBus = 0;
/* The IRQ has already been locked by the caller */
for (entry = iSeries_irqMap[irq].head; entry; entry = entry->next) {
bus = (entry->dsa >> 16) & 0xFFFF;
subBus = (entry->dsa >> 8) & 0xFF;
deviceId = entry->dsa & 0xFF;
/* Mask secondary INTA */
mask = 0x80000000;
HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK,
"iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
bus, subBus, deviceId, irq);
}
bus = IRQ_TO_BUS(irq);
function = IRQ_TO_FUNC(irq);
deviceId = (IRQ_TO_IDSEL(irq) << 4) + function;
/* Mask secondary INTA */
mask = 0x80000000;
HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
bus, subBus, deviceId, irq);
}
/*
......@@ -270,21 +190,19 @@ static void iSeries_disable_IRQ(unsigned int irq)
*/
static void iSeries_enable_IRQ(unsigned int irq)
{
struct iSeries_irqEntry *entry;
u32 bus, subBus, deviceId, mask;
u32 bus, deviceId, function, mask;
const u32 subBus = 0;
/* The IRQ has already been locked by the caller */
for (entry = iSeries_irqMap[irq].head; entry; entry = entry->next) {
bus = (entry->dsa >> 16) & 0xFFFF;
subBus = (entry->dsa >> 8) & 0xFF;
deviceId = entry->dsa & 0xFF;
/* Unmask secondary INTA */
mask = 0x80000000;
HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK,
"iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
bus, subBus, deviceId, irq);
}
bus = IRQ_TO_BUS(irq);
function = IRQ_TO_FUNC(irq);
deviceId = (IRQ_TO_IDSEL(irq) << 4) + function;
/* Unmask secondary INTA */
mask = 0x80000000;
HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
bus, subBus, deviceId, irq);
}
/*
......
......@@ -36,7 +36,6 @@
#include <asm/pci-bridge.h>
#include <asm/ppcdebug.h>
#include <asm/naca.h>
#include <asm/flight_recorder.h>
#include <asm/pci_dma.h>
#include <asm/iSeries/HvCallPci.h>
......@@ -50,16 +49,10 @@
#include "iSeries_IoMmTable.h"
#include "pci.h"
extern struct pci_controller *hose_head;
extern struct pci_controller **hose_tail;
extern int global_phb_number;
extern int panic_timeout;
extern struct device_node *allnodes;
extern unsigned long iSeries_Base_Io_Memory;
extern struct pci_ops iSeries_pci_ops;
extern struct flightRecorder *PciFr;
extern struct TceTable *tceTables[256];
extern void iSeries_MmIoTest(void);
......@@ -67,8 +60,7 @@ extern void iSeries_MmIoTest(void);
/*
* Forward declares of prototypes.
*/
static struct iSeries_Device_Node *find_Device_Node(struct pci_dev *PciDev);
unsigned long find_and_init_phbs(void);
static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn);
static void iSeries_Scan_PHBs_Slots(struct pci_controller *Phb);
static void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus,
int IdSel);
......@@ -90,7 +82,8 @@ static long Pci_Error_Count;
static int Pci_Retry_Max = 3; /* Only retry 3 times */
static int Pci_Error_Flag = 1; /* Set Retry Error on. */
static int Pci_Trace_Flag;
static struct pci_ops iSeries_pci_ops;
/*
* Log Error infor in Flight Recorder to system Console.
......@@ -102,14 +95,11 @@ static int Pci_Trace_Flag;
static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
int AgentId, int HvRc)
{
if (HvRc != 0x0302) {
char ErrorString[128];
if (HvRc == 0x0302)
return;
sprintf(ErrorString, "%s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
Error_Text, Bus, SubBus, AgentId, HvRc);
PCIFR(ErrorString);
printk("PCI: %s\n", ErrorString);
}
printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
Error_Text, Bus, SubBus, AgentId, HvRc);
}
#if 0
......@@ -159,95 +149,68 @@ static void list_device_nodes(void)
static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus,
HvSubBusNumber SubBus, int AgentId, int Function)
{
struct iSeries_Device_Node *DeviceNode;
struct iSeries_Device_Node *node;
PPCDBG(PPCDBG_BUSWALK,
"-build_device_node 0x%02X.%02X.%02X Function: %02X\n",
Bus, SubBus, AgentId, Function);
DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL);
if (DeviceNode == NULL)
return NULL;
memset(DeviceNode, 0, sizeof(struct iSeries_Device_Node));
list_add_tail(&DeviceNode->Device_List, &iSeries_Global_Device_List);
/* DeviceNode->DsaAddr =
((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); */
ISERIES_BUS(DeviceNode) = Bus;
ISERIES_SUBBUS(DeviceNode) = SubBus;
DeviceNode->DsaAddr.deviceId = 0x10;
DeviceNode->DsaAddr.barNumber = 0;
DeviceNode->AgentId = AgentId;
DeviceNode->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
DeviceNode->IoRetry = 0;
iSeries_Get_Location_Code(DeviceNode);
PCIFR("Device 0x%02X.%2X, Node:0x%p ", ISERIES_BUS(DeviceNode),
ISERIES_DEVFUN(DeviceNode), DeviceNode);
return DeviceNode;
}
/*
* Allocate pci_controller(phb) initialized common variables.
*/
static struct pci_controller *pci_alloc_pci_controllerX(char *model,
enum phb_types controller_type)
{
struct pci_controller *hose;
hose = (struct pci_controller *)kmalloc(sizeof(struct pci_controller),
GFP_KERNEL);
if (hose == NULL)
node = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL);
if (node == NULL)
return NULL;
memset(hose, 0, sizeof(struct pci_controller));
if (strlen(model) < 8)
strcpy(hose->what, model);
else
memcpy(hose->what, model, 7);
hose->type = controller_type;
hose->global_number = global_phb_number;
global_phb_number++;
*hose_tail = hose;
hose_tail = &hose->next;
return hose;
memset(node, 0, sizeof(struct iSeries_Device_Node));
list_add_tail(&node->Device_List, &iSeries_Global_Device_List);
#if 0
node->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32);
#endif
node->DsaAddr.DsaAddr = 0;
node->DsaAddr.Dsa.busNumber = Bus;
node->DsaAddr.Dsa.subBusNumber = SubBus;
node->DsaAddr.Dsa.deviceId = 0x10;
node->AgentId = AgentId;
node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
node->IoRetry = 0;
iSeries_Get_Location_Code(node);
PCIFR("Device 0x%02X.%2X, Node:0x%p ", ISERIES_BUS(node),
ISERIES_DEVFUN(node), node);
return node;
}
/*
* unsigned int __init find_and_init_phbs(void)
* unsigned long __init find_and_init_phbs(void)
*
* 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 build for any bus which is partially
* ownership status. A pci_controller is built for any bus which is partially
* owned or fully owned by this guest partition.
*/
unsigned long __init find_and_init_phbs(void)
{
struct pci_controller *phb;
HvBusNumber BusNumber;
HvBusNumber bus;
PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n");
/* Check all possible buses. */
for (BusNumber = 0; BusNumber < 256; BusNumber++) {
int RtnCode = HvCallXm_testBus(BusNumber);
if (RtnCode == 0) {
phb = pci_alloc_pci_controllerX("PHB HV",
phb_type_hypervisor);
for (bus = 0; bus < 256; bus++) {
int ret = HvCallXm_testBus(bus);
if (ret == 0) {
printk("bus %d appears to exist\n", bus);
phb = pci_alloc_pci_controller(phb_type_hypervisor);
if (phb == NULL) {
printk("PCI: Allocate pci_controller failed.\n");
PCIFR("Allocate pci_controller failed.");
return -1;
}
phb->pci_mem_offset = phb->local_number = BusNumber;
phb->first_busno = BusNumber;
phb->last_busno = BusNumber;
phb->pci_mem_offset = phb->local_number = bus;
phb->first_busno = bus;
phb->last_busno = bus;
phb->ops = &iSeries_pci_ops;
PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",
phb, BusNumber);
PCIFR("Create iSeries PHB controller: %04X", BusNumber);
phb, bus);
PCIFR("Create iSeries PHB controller: %04X", bus);
/* Find and connect the devices. */
iSeries_Scan_PHBs_Slots(phb);
......@@ -256,9 +219,9 @@ unsigned long __init find_and_init_phbs(void)
* Check for Unexpected Return code, a clue that something
* has gone wrong.
*/
else if (RtnCode != 0x0301)
PCIFR("Unexpected Return on Probe(0x%04X): 0x%04X",
BusNumber, RtnCode);
else if (ret != 0x0301)
printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X",
bus, ret);
}
return 0;
}
......@@ -267,17 +230,6 @@ unsigned long __init find_and_init_phbs(void)
* iSeries_pcibios_init
*
* Chance to initialize and structures or variable before PCI Bus walk.
*
* <4>buswalk [swapper : iSeries_pcibios_init Entry.
* <4>buswalk [swapper : IoMmTable Initialized 0xC00000000034BD30
* <4>buswalk [swapper : find_and_init_phbs Entry
* <4>buswalk [swapper : Create iSeries pci_controller:(0xC00000001F5C7000), Bus 0x0017
* <4>buswalk [swapper : Connect EADs: 0x17.00.12 = 0x00
* <4>buswalk [swapper : iSeries_assign_IRQ 0x0017.00.12 = 0x0091
* <4>buswalk [swapper : - allocate and assign IRQ 0x17.00.12 = 0x91
* <4>buswalk [swapper : - FoundDevice: 0x17.28.10 = 0x12AE
* <4>buswalk [swapper : - build_device_node 0x17.28.12
* <4>buswalk [swapper : iSeries_pcibios_init Exit.
*/
void iSeries_pcibios_init(void)
{
......@@ -293,8 +245,8 @@ void iSeries_pcibios_init(void)
*/
void __init pcibios_final_fixup(void)
{
struct pci_dev *PciDev = NULL;
struct iSeries_Device_Node *DeviceNode;
struct pci_dev *pdev = NULL;
struct iSeries_Device_Node *node;
char Buffer[256];
int DeviceCount = 0;
......@@ -303,24 +255,28 @@ void __init pcibios_final_fixup(void)
/* Fix up at the device node and pci_dev relationship */
mf_displaySrc(0xC9000100);
while ((PciDev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, PciDev))
printk("pcibios_final_fixup\n");
while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))
!= NULL) {
DeviceNode = find_Device_Node(PciDev);
if (DeviceNode != NULL) {
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) {
++DeviceCount;
PciDev->sysdata = (void *)DeviceNode;
DeviceNode->PciDev = PciDev;
pdev->sysdata = (void *)node;
node->PciDev = pdev;
PPCDBG(PPCDBG_BUSWALK,
"PciDev 0x%p <==> DevNode 0x%p\n",
PciDev, DeviceNode);
iSeries_allocateDeviceBars(PciDev);
iSeries_Device_Information(PciDev, Buffer,
"pdev 0x%p <==> DevNode 0x%p\n",
pdev, node);
iSeries_allocateDeviceBars(pdev);
iSeries_Device_Information(pdev, Buffer,
sizeof(Buffer));
printk("%d. %s\n", DeviceCount, Buffer);
create_pci_bus_tce_table((unsigned long)DeviceNode);
create_pci_bus_tce_table((unsigned long)node);
} else
printk("PCI: Device Tree not found for 0x%016lX\n",
(unsigned long)PciDev);
(unsigned long)pdev);
}
iSeries_IoMmTable_Status();
iSeries_activate_IRQs();
......@@ -333,9 +289,9 @@ void pcibios_fixup_bus(struct pci_bus *PciBus)
PciBus->number);
}
void pcibios_fixup_resources(struct pci_dev *PciDev)
void pcibios_fixup_resources(struct pci_dev *pdev)
{
PPCDBG(PPCDBG_BUSWALK, "fixup_resources PciDev %p\n", PciDev);
PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev);
}
/*
......@@ -344,11 +300,11 @@ void pcibios_fixup_resources(struct pci_dev *PciDev)
static void iSeries_Scan_PHBs_Slots(struct pci_controller *Phb)
{
struct HvCallPci_DeviceInfo *DevInfo;
HvBusNumber Bus = Phb->local_number; /* System Bus */
HvSubBusNumber SubBus = 0; /* EADs is always 0. */
HvBusNumber bus = Phb->local_number; /* System Bus */
const HvSubBusNumber SubBus = 0; /* EADs is always 0. */
int HvRc = 0;
int IdSel = 1;
int MaxAgents = 8;
int IdSel;
const int MaxAgents = 8;
DevInfo = (struct HvCallPci_DeviceInfo*)
kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
......@@ -358,24 +314,25 @@ static void iSeries_Scan_PHBs_Slots(struct pci_controller *Phb)
/*
* Probe for EADs Bridges
*/
for (IdSel=1; IdSel < MaxAgents; ++IdSel) {
HvRc = HvCallPci_getDeviceInfo(Bus, SubBus, IdSel,
for (IdSel = 1; IdSel < MaxAgents; ++IdSel) {
HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel,
REALADDR(DevInfo),
sizeof(struct HvCallPci_DeviceInfo));
if (HvRc == 0) {
if (DevInfo->deviceType == HvCallPci_NodeDevice)
iSeries_Scan_EADs_Bridge(Bus, SubBus, IdSel);
iSeries_Scan_EADs_Bridge(bus, SubBus, IdSel);
else
printk("PCI: Invalid System Configuration(0x%02X.\n",
DevInfo->deviceType);
printk("PCI: Invalid System Configuration(0x%02X)"
" for bus 0x%02x id 0x%02x.\n",
DevInfo->deviceType, bus, IdSel);
}
else
pci_Log_Error("getDeviceInfo",Bus, SubBus, IdSel,HvRc);
pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc);
}
kfree(DevInfo);
}
static void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus,
static void iSeries_Scan_EADs_Bridge(HvBusNumber bus, HvSubBusNumber SubBus,
int IdSel)
{
struct HvCallPci_BridgeInfo *BridgeInfo;
......@@ -391,26 +348,26 @@ static void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus,
/* Note: hvSubBus and irq is always be 0 at this level! */
for (Function = 0; Function < 8; ++Function) {
AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, 0);
HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0);
if (HvRc == 0) {
printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
bus, IdSel, Function, AgentId);
/* Connect EADs: 0x18.00.12 = 0x00 */
PPCDBG(PPCDBG_BUSWALK,
"PCI:Connect EADs: 0x%02X.%02X.%02X\n",
Bus, SubBus, AgentId);
PCIFR("Connect EADs: 0x%02X.%02X.%02X",
Bus, SubBus, AgentId);
HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId,
bus, SubBus, AgentId);
HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
REALADDR(BridgeInfo),
sizeof(struct HvCallPci_BridgeInfo));
if (HvRc == 0) {
PPCDBG(PPCDBG_BUSWALK,
"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n",
BridgeInfo->busUnitInfo.deviceType,
BridgeInfo->subBusNumber,
BridgeInfo->maxAgents,
BridgeInfo->maxSubBusNumber,
BridgeInfo->logicalSlotNumber);
PCIFR("BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X",
PPCDBG(PPCDBG_BUSWALK,
"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
BridgeInfo->busUnitInfo.deviceType,
BridgeInfo->subBusNumber,
BridgeInfo->maxAgents,
......@@ -420,16 +377,14 @@ static void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus,
if (BridgeInfo->busUnitInfo.deviceType ==
HvCallPci_BridgeDevice) {
/* Scan_Bridge_Slot...: 0x18.00.12 */
iSeries_Scan_Bridge_Slot(Bus,
BridgeInfo);
iSeries_Scan_Bridge_Slot(bus, BridgeInfo);
} else
printk("PCI: Invalid Bridge Configuration(0x%02X)",
BridgeInfo->busUnitInfo.deviceType);
}
}
else if (HvRc != 0x000B)
} else if (HvRc != 0x000B)
pci_Log_Error("EADs Connect",
Bus, SubBus, AgentId, HvRc);
bus, SubBus, AgentId, HvRc);
}
kfree(BridgeInfo);
}
......@@ -440,20 +395,18 @@ static void iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus,
static int iSeries_Scan_Bridge_Slot(HvBusNumber Bus,
struct HvCallPci_BridgeInfo *BridgeInfo)
{
struct iSeries_Device_Node *DeviceNode;
struct iSeries_Device_Node *node;
HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
u16 VendorId = 0;
int HvRc = 0;
u8 Irq = 0;
int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
int FirstSlotId = 0;
/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
Irq = iSeries_allocate_IRQ(Bus, 0, AgentId);
iSeries_assign_IRQ(Irq, Bus, 0, AgentId);
Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
iSeries_assign_IRQ(Irq, Bus, 0, EADsIdSel);
PPCDBG(PPCDBG_BUSWALK,
"PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",
Bus, 0, AgentId, Irq);
......@@ -463,53 +416,42 @@ static int iSeries_Scan_Bridge_Slot(HvBusNumber Bus,
*/
for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
for (Function = 0; Function < 8; ++Function) {
AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvRc = HvCallXm_connectBusUnit(Bus, SubBus,
AgentId, Irq);
if (HvRc == 0) {
HvRc = HvCallPci_configLoad16(Bus, SubBus,
AgentId, PCI_VENDOR_ID,
&VendorId);
if (HvRc == 0) {
/* FoundDevice: 0x18.28.10 = 0x12AE */
PPCDBG(PPCDBG_BUSWALK,
"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
Bus, SubBus, AgentId, VendorId);
HvRc = HvCallPci_configStore8(Bus,
SubBus, AgentId,
PCI_INTERRUPT_LINE, Irq);
if (HvRc != 0)
pci_Log_Error("PciCfgStore Irq Failed!",
Bus, SubBus,
AgentId, HvRc);
++DeviceCount;
DeviceNode = build_device_node(Bus,
SubBus, EADsIdSel,
Function);
DeviceNode->Vendor = VendorId;
DeviceNode->Irq = Irq;
DeviceNode->LogicalSlot =
BridgeInfo->logicalSlotNumber;
PCIFR("Device(%4d): 0x%02X.%02X.%02X 0x%02X 0x%04X",
DeviceCount, Bus, SubBus,
AgentId,
DeviceNode->LogicalSlot,DeviceNode->Vendor);
/*
* On the first device/function,
* assign irq to slot
*/
if (Function == 0) {
FirstSlotId = AgentId;
/* AHT iSeries_assign_IRQ(Irq,
Bus, SubBus, AgentId); */
}
} else
pci_Log_Error("Read Vendor",
Bus, SubBus, AgentId, HvRc);
} else
if (HvRc != 0) {
pci_Log_Error("Connect Bus Unit",
Bus, SubBus, AgentId, HvRc);
Bus, SubBus, AgentId, HvRc);
continue;
}
printk("connected bus unit at bus %d subbus 0x%x agentid 0x%x (idsel=%d func=%d)\n",
Bus, SubBus, AgentId, IdSel, Function);
HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId,
PCI_VENDOR_ID, &VendorId);
if (HvRc != 0) {
pci_Log_Error("Read Vendor",
Bus, SubBus, AgentId, HvRc);
continue;
}
printk("read vendor ID: %x\n", VendorId);
/* FoundDevice: 0x18.28.10 = 0x12AE */
PPCDBG(PPCDBG_BUSWALK,
"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
Bus, SubBus, AgentId, VendorId);
HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId,
PCI_INTERRUPT_LINE, Irq);
if (HvRc != 0)
pci_Log_Error("PciCfgStore Irq Failed!",
Bus, SubBus, AgentId, HvRc);
++DeviceCount;
node = build_device_node(Bus, SubBus, EADsIdSel, Function);
node->Vendor = VendorId;
node->Irq = Irq;
node->LogicalSlot = BridgeInfo->logicalSlotNumber;
} /* for (Function = 0; Function < 8; ++Function) */
} /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */
return HvRc;
......@@ -562,19 +504,16 @@ void *iSeries_memcpy_fromio(void *dest, void *source, size_t count)
/*
* Look down the chain to find the matching Device Device
*/
static struct iSeries_Device_Node *find_Device_Node(struct pci_dev *PciDev)
static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn)
{
struct list_head *Device_Node_Ptr = iSeries_Global_Device_List.next;
int Bus = PciDev->bus->number;
int DevFn = PciDev->devfn;
struct list_head *pos;
while (Device_Node_Ptr != &iSeries_Global_Device_List) {
struct iSeries_Device_Node *DevNode =
(struct iSeries_Device_Node*)Device_Node_Ptr;
list_for_each(pos, &iSeries_Global_Device_List) {
struct iSeries_Device_Node *node =
list_entry(pos, struct iSeries_Device_Node, Device_List);
if ((Bus == ISERIES_BUS(DevNode)) && (DevFn == DevNode->DevFn))
return DevNode;
Device_Node_Ptr = Device_Node_Ptr->next;
if ((bus == ISERIES_BUS(node)) && (devfn == node->DevFn))
return node;
}
return NULL;
}
......@@ -585,90 +524,82 @@ static struct iSeries_Device_Node *find_Device_Node(struct pci_dev *PciDev)
* Sanity Check Node PciDev to passed pci_dev
* If none is found, returns a NULL which the client must handle.
*/
static struct iSeries_Device_Node *get_Device_Node(struct pci_dev *PciDev)
static struct iSeries_Device_Node *get_Device_Node(struct pci_dev *pdev)
{
struct iSeries_Device_Node *Node;
Node = (struct iSeries_Device_Node *)PciDev->sysdata;
if (Node == NULL)
Node = find_Device_Node(PciDev);
else if (Node->PciDev != PciDev)
Node = find_Device_Node(PciDev);
return Node;
struct iSeries_Device_Node *node;
node = pdev->sysdata;
if (node == NULL || node->PciDev != pdev)
node = find_Device_Node(pdev->bus->number, pdev->devfn);
return node;
}
#endif
/*
* Read PCI Config Space Code
* 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.
*/
#if 0
/** BYTE ********************************************************************/
int iSeries_Node_read_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8* ReadValue)
{
u8 ReadData;
if(DevNode == NULL) { return 0x301; }
++Pci_Cfg_Read_Count;
DevNode->ReturnCode = HvCallPci_configLoad8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
Offset,&ReadData);
if(Pci_Trace_Flag == 1) {
PCIFR("RCB: 0x%04X.%02X 0x%04X = 0x%02X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,ReadData);
}
if(DevNode->ReturnCode != 0 ) {
printk("PCI: RCB: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
PCIFR( "RCB: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
}
*ReadValue = ReadData;
return DevNode->ReturnCode;
}
static u64 hv_cfg_read_func[4] = {
HvCallPciConfigLoad8, HvCallPciConfigLoad16,
HvCallPciConfigLoad32, HvCallPciConfigLoad32
};
int iSeries_pci_read_config_byte(struct pci_dev* PciDev, int Offset, u8* ReadValue) {
struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
if(DevNode == NULL) return 0x0301;
return iSeries_Node_read_config_byte( DevNode ,Offset,ReadValue);
}
#endif
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)
{
return PCIBIOS_DEVICE_NOT_FOUND;
}
struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn);
u64 fn;
struct HvCallPci_LoadReturn ret;
/*
* Write PCI Config Space
*/
#if 0
/** BYTE ********************************************************************/
int iSeries_Node_write_config_byte(struct iSeries_Device_Node* DevNode, int Offset, u8 WriteData)
{
++Pci_Cfg_Write_Count;
DevNode->ReturnCode = HvCallPci_configStore8(ISERIES_BUS(DevNode),ISERIES_SUBBUS(DevNode),0x10,
Offset,WriteData);
if(Pci_Trace_Flag == 1) {
PCIFR("WCB: 0x%04X.%02X 0x%04X = 0x%02X",ISERIES_BUS(DevNode),DevNode->DevFn,Offset,WriteData);
}
if(DevNode->ReturnCode != 0 ) {
printk("PCI: WCB: 0x%04X.%02X Error: 0x%04X\n",ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
PCIFR( "WCB: 0x%04X.%02X Error: 0x%04X", ISERIES_BUS(DevNode),DevNode->DevFn,DevNode->ReturnCode);
if (node == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
fn = hv_cfg_read_func[(size - 1) & 3];
HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0);
if (ret.rc != 0) {
*val = ~0;
return PCIBIOS_DEVICE_NOT_FOUND; /* or something */
}
return DevNode->ReturnCode;
}
int iSeries_pci_write_config_byte( struct pci_dev* PciDev,int Offset, u8 WriteValue)
{
struct iSeries_Device_Node* DevNode = get_Device_Node(PciDev);
if(DevNode == NULL) return 0x0301;
return iSeries_Node_write_config_byte( DevNode,Offset,WriteValue);
*val = ret.value;
return 0;
}
#endif
/*
* Write PCI config space
*/
static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 val)
{
return PCIBIOS_DEVICE_NOT_FOUND;
struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn);
u64 fn;
u64 ret;
if (node == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
fn = hv_cfg_write_func[(size - 1) & 3];
ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0);
if (ret != 0)
return PCIBIOS_DEVICE_NOT_FOUND;
return 0;
}
struct pci_ops iSeries_pci_ops = {
static struct pci_ops iSeries_pci_ops = {
.read = iSeries_pci_read_config,
.write = iSeries_pci_write_config
};
......@@ -683,18 +614,15 @@ struct pci_ops iSeries_pci_ops = {
* PCI: Device 23.90 ReadL Retry( 1)
* PCI: Device 23.90 ReadL Retry Successful(1)
*/
int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode,
u64 RtnCode)
static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode,
u64 ret)
{
if (RtnCode != 0) {
if (ret != 0) {
++Pci_Error_Count;
++DevNode->IoRetry;
PCIFR("%s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X",
TextHdr, ISERIES_BUS(DevNode), DevNode->DevFn,
DevNode->IoRetry, (int)RtnCode);
printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",
TextHdr, ISERIES_BUS(DevNode), DevNode->DevFn,
DevNode->IoRetry, (int)RtnCode);
TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn,
DevNode->IoRetry, (int)ret);
/*
* Bump the retry and check for retry count exceeded.
* If, Exceeded, panic the system.
......@@ -711,7 +639,7 @@ int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode,
/* If retry was in progress, log success and rest retry count */
if (DevNode->IoRetry > 0) {
PCIFR("%s: Device 0x%04X:%02X Retry Successful(%2d).",
TextHdr, ISERIES_BUS(DevNode), DevNode->DevFn,
TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn,
DevNode->IoRetry);
DevNode->IoRetry = 0;
}
......@@ -724,16 +652,16 @@ int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode,
* the exposure of being device global.
*/
static inline struct iSeries_Device_Node *xlateIoMmAddress(void *IoAddress,
union HvDsaMap *DsaPtr, u64 *BarOffsetPtr)
u64 *dsaptr, u64 *BarOffsetPtr)
{
unsigned long BaseIoAddr =
(unsigned long)IoAddress - iSeries_Base_Io_Memory;
long TableIndex = BaseIoAddr / iSeries_IoMmTable_Entry_Size;
struct iSeries_Device_Node *DevNode = *(iSeries_IoMmTable + TableIndex);
struct iSeries_Device_Node *DevNode = iSeries_IoMmTable[TableIndex];
if (DevNode != NULL) {
DsaPtr->DsaAddr = ISERIES_DSA(DevNode);
DsaPtr->Dsa.barNumber = *(iSeries_IoBarTable + TableIndex);
int barnum = iSeries_IoBarTable[TableIndex];
*dsaptr = DevNode->DsaAddr.DsaAddr | (barnum << 24);
*BarOffsetPtr = BaseIoAddr % iSeries_IoMmTable_Entry_Size;
} else
panic("PCI: Invalid PCI IoAddress detected!\n");
......@@ -752,61 +680,51 @@ static inline struct iSeries_Device_Node *xlateIoMmAddress(void *IoAddress,
u8 iSeries_Read_Byte(void *IoAddress)
{
u64 BarOffset;
union HvDsaMap DsaData;
struct HvCallPci_LoadReturn Return;
u64 dsa;
struct HvCallPci_LoadReturn ret;
struct iSeries_Device_Node *DevNode =
xlateIoMmAddress(IoAddress, &DsaData, &BarOffset);
xlateIoMmAddress(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad8, &Return, DsaData.DsaAddr,
BarOffset, 0);
} while (CheckReturnCode("RDB", DevNode, Return.rc) != 0);
HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
} while (CheckReturnCode("RDB", DevNode, ret.rc) != 0);
if (Pci_Trace_Flag == 1)
PCIFR("RDB: IoAddress 0x%p = 0x%02X", IoAddress,
(u8)Return.value);
return (u8)Return.value;
return (u8)ret.value;
}
u16 iSeries_Read_Word(void *IoAddress)
{
u64 BarOffset;
union HvDsaMap DsaData;
struct HvCallPci_LoadReturn Return;
u64 dsa;
struct HvCallPci_LoadReturn ret;
struct iSeries_Device_Node *DevNode =
xlateIoMmAddress(IoAddress, &DsaData, &BarOffset);
xlateIoMmAddress(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad16, &Return, DsaData.DsaAddr,
HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
BarOffset, 0);
} while (CheckReturnCode("RDW", DevNode, Return.rc) != 0);
} while (CheckReturnCode("RDW", DevNode, ret.rc) != 0);
if (Pci_Trace_Flag == 1)
PCIFR("RDW: IoAddress 0x%p = 0x%04X", IoAddress,
swab16((u16)Return.value));
return swab16((u16)Return.value);
return swab16((u16)ret.value);
}
u32 iSeries_Read_Long(void *IoAddress)
{
u64 BarOffset;
union HvDsaMap DsaData;
struct HvCallPci_LoadReturn Return;
u64 dsa;
struct HvCallPci_LoadReturn ret;
struct iSeries_Device_Node *DevNode =
xlateIoMmAddress(IoAddress, &DsaData, &BarOffset);
xlateIoMmAddress(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Read_Count;
HvCall3Ret16(HvCallPciBarLoad32, &Return, DsaData.DsaAddr,
HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
BarOffset, 0);
} while (CheckReturnCode("RDL", DevNode, Return.rc) != 0);
} while (CheckReturnCode("RDL", DevNode, ret.rc) != 0);
if (Pci_Trace_Flag == 1)
PCIFR("RDL: IoAddress 0x%p = 0x%04X", IoAddress,
swab32((u32)Return.value));
return swab32((u32)Return.value);
return swab32((u32)ret.value);
}
/*
......@@ -816,55 +734,46 @@ u32 iSeries_Read_Long(void *IoAddress)
* iSeries_Write_Word = Write Word(16 bit)
* iSeries_Write_Long = Write Long(32 bit)
*/
void iSeries_Write_Byte(u8 Data, void *IoAddress)
void iSeries_Write_Byte(u8 data, void *IoAddress)
{
u64 BarOffset;
union HvDsaMap DsaData;
struct HvCallPci_LoadReturn Return;
u64 dsa;
u64 rc;
struct iSeries_Device_Node *DevNode =
xlateIoMmAddress(IoAddress, &DsaData, &BarOffset);
xlateIoMmAddress(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Write_Count;
Return.rc = HvCall4(HvCallPciBarStore8, DsaData.DsaAddr,
BarOffset, Data, 0);
} while (CheckReturnCode("WWB", DevNode, Return.rc) != 0);
if (Pci_Trace_Flag == 1)
PCIFR("WWB: IoAddress 0x%p = 0x%02X", IoAddress, Data);
rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
} while (CheckReturnCode("WWB", DevNode, rc) != 0);
}
void iSeries_Write_Word(u16 Data, void *IoAddress)
void iSeries_Write_Word(u16 data, void *IoAddress)
{
u64 BarOffset;
union HvDsaMap DsaData;
struct HvCallPci_LoadReturn Return;
u64 dsa;
u64 rc;
struct iSeries_Device_Node *DevNode =
xlateIoMmAddress(IoAddress, &DsaData, &BarOffset);
xlateIoMmAddress(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Write_Count;
Return.rc = HvCall4(HvCallPciBarStore16, DsaData.DsaAddr,
BarOffset, swab16(Data), 0);
} while (CheckReturnCode("WWW", DevNode, Return.rc) != 0);
if (Pci_Trace_Flag == 1)
PCIFR("WWW: IoAddress 0x%p = 0x%04X", IoAddress, Data);
rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
} while (CheckReturnCode("WWW", DevNode, rc) != 0);
}
void iSeries_Write_Long(u32 Data, void *IoAddress)
void iSeries_Write_Long(u32 data, void *IoAddress)
{
u64 BarOffset;
union HvDsaMap DsaData;
struct HvCallPci_LoadReturn Return;
u64 dsa;
u64 rc;
struct iSeries_Device_Node *DevNode =
xlateIoMmAddress(IoAddress, &DsaData, &BarOffset);
xlateIoMmAddress(IoAddress, &dsa, &BarOffset);
do {
++Pci_Io_Write_Count;
Return.rc = HvCall4(HvCallPciBarStore32, DsaData.DsaAddr,
BarOffset, swab32(Data), 0);
} while (CheckReturnCode("WWL", DevNode, Return.rc) != 0);
if (Pci_Trace_Flag == 1)
PCIFR("WWL: IoAddress 0x%p = 0x%08X", IoAddress, Data);
rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
} while (CheckReturnCode("WWL", DevNode, rc) != 0);
}
void pcibios_name_device(struct pci_dev *dev)
......
......@@ -36,7 +36,6 @@
#include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/HvTypes.h>
#include <asm/iSeries/mf.h>
#include <asm/flight_recorder.h>
#include <asm/pci.h>
#include <asm/iSeries/iSeries_pci.h>
......
......@@ -589,7 +589,9 @@ int do_IRQ(struct pt_regs *regs)
return 1; /* lets ret_from_int know we can do checks */
}
#else /* CONFIG_PPC_ISERIES */
int do_IRQ(struct pt_regs *regs)
{
int irq, first = 1;
......
......@@ -224,7 +224,11 @@ pci_alloc_pci_controller(enum phb_types controller_type)
struct pci_controller *hose;
char *model;
#ifdef CONFIG_PPC_ISERIES
hose = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
#else
hose = (struct pci_controller *)alloc_bootmem(sizeof(struct pci_controller));
#endif
if(hose == NULL) {
printk(KERN_ERR "PCI: Allocate pci_controller failed.\n");
return NULL;
......@@ -232,6 +236,11 @@ pci_alloc_pci_controller(enum phb_types controller_type)
memset(hose, 0, sizeof(struct pci_controller));
switch(controller_type) {
#ifdef CONFIG_PPC_ISERIES
case phb_type_hypervisor:
model = "PHB HV";
break;
#endif
case phb_type_python:
model = "PHB PY";
break;
......@@ -311,6 +320,7 @@ static int __init pcibios_init(void)
hose->last_busno = bus->subordinate;
}
#ifndef CONFIG_PPC_ISERIES
if (pci_probe_only)
pcibios_claim_of_setup();
else
......@@ -318,6 +328,7 @@ static int __init pcibios_init(void)
pci_assign_unassigned_resources() is able to work
correctly with [partially] allocated PCI tree. */
pci_assign_unassigned_resources();
#endif
/* Call machine dependent fixup */
pcibios_final_fixup();
......@@ -375,9 +386,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
*/
int pci_domain_nr(struct pci_bus *bus)
{
#ifdef CONFIG_PPC_ISERIES
return 0;
#else
struct pci_controller *hose = PCI_GET_PHB_PTR(bus);
return hose->global_number;
#endif
}
EXPORT_SYMBOL(pci_domain_nr);
......@@ -385,11 +400,13 @@ EXPORT_SYMBOL(pci_domain_nr);
/* Set the name of the bus as it appears in /proc/bus/pci */
int pci_name_bus(char *name, struct pci_bus *bus)
{
#ifndef CONFIG_PPC_ISERIES
struct pci_controller *hose = PCI_GET_PHB_PTR(bus);
if (hose->buid)
sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
else
#endif
sprintf(name, "%02x", bus->number);
return 0;
......
/************************************************************************/
/* Provides the Hypervisor PCI calls for iSeries Linux Parition. */
/* Copyright (C) 20yy <Wayne G Holm> <IBM Corporation> */
/* Copyright (C) 2001 <Wayne G Holm> <IBM Corporation> */
/* */
/* 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 */
......@@ -21,40 +21,25 @@
/* Change Activity: */
/* Created, Jan 9, 2001 */
/************************************************************************/
//============================================================================
// Header File Id
// Name______________: HvCallPci.H
//
// Description_______:
//
// This file contains the "hypervisor call" interface which is used to
// drive the hypervisor from SLIC.
//
//============================================================================
#ifndef _HVCALLPCI_H
#define _HVCALLPCI_H
//-------------------------------------------------------------------
// Forward declarations
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// Standard Includes
//-------------------------------------------------------------------
#include <asm/iSeries/HvCallSc.h>
#include <asm/iSeries/HvTypes.h>
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
struct HvCallPci_DsaAddr { // make sure this struct size is 64-bits total
u16 busNumber;
u8 subBusNumber;
u8 deviceId;
/*
* DSA == Direct Select Address
* this struct must be 64 bits in total
*/
struct HvCallPci_DsaAddr {
u16 busNumber; /* PHB index? */
u8 subBusNumber; /* PCI bus number? */
u8 deviceId; /* device and function? */
u8 barNumber;
u8 reserved[3];
};
union HvDsaMap {
u64 DsaAddr;
struct HvCallPci_DsaAddr Dsa;
......@@ -65,12 +50,13 @@ struct HvCallPci_LoadReturn {
u64 value;
};
enum HvCallPci_DeviceType {HvCallPci_NodeDevice = 1,
HvCallPci_SpDevice = 2,
HvCallPci_IopDevice = 3,
HvCallPci_BridgeDevice = 4,
HvCallPci_MultiFunctionDevice = 5,
HvCallPci_IoaDevice = 6
enum HvCallPci_DeviceType {
HvCallPci_NodeDevice = 1,
HvCallPci_SpDevice = 2,
HvCallPci_IopDevice = 3,
HvCallPci_BridgeDevice = 4,
HvCallPci_MultiFunctionDevice = 5,
HvCallPci_IoaDevice = 6
};
......@@ -138,9 +124,9 @@ enum HvCallPci_VpdType {
#define HvCallPciGetBusUnitInfo HvCallPci + 50
//============================================================================
static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber,
u8 deviceId, u32 offset,
u8 *value)
static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber,
u8 deviceId, u32 offset,
u8 *value)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
......@@ -160,9 +146,9 @@ static inline u64 HvCallPci_configLoad8(u16 busNumber, u8 subBusNumber,
return retVal.rc;
}
//============================================================================
static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
u8 deviceId, u32 offset,
u16 *value)
static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
u8 deviceId, u32 offset,
u16 *value)
{
struct HvCallPci_DsaAddr dsa;
struct HvCallPci_LoadReturn retVal;
......
#ifndef _ISERIES_64_PCI_H
#define _ISERIES_64_PCI_H
/************************************************************************/
/* File iSeries_pci.h created by Allan Trautman on Tue Feb 20, 2001. */
/************************************************************************/
/* Define some useful macros for the iSeries pci routines. */
/* Copyright (C) 20yy Allan H Trautman, IBM Corporation */
/* Copyright (C) 2001 Allan H Trautman, IBM Corporation */
/* */
/* 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 */
......@@ -28,77 +29,81 @@
/* Ported to ppc64, May 25, 2001 */
/* End Change Activity */
/************************************************************************/
#include <asm/iSeries/HvCallPci.h>
struct pci_dev; /* For Forward Reference */
struct iSeries_Device_Node;
/************************************************************************/
/* Gets iSeries Bus, SubBus, of DevFn using pci_dev* structure */
/* Gets iSeries Bus, SubBus, DevFn using iSeries_Device_Node structure */
/************************************************************************/
#define ISERIES_BUS(DevPtr) DevPtr->DsaAddr.busNumber
#define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.subBusNumber
#define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.deviceId
#define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn
#define ISERIES_DSA(DevPtr) (*(u64*)&DevPtr->DsaAddr)
#define ISERIES_BUS(DevPtr) DevPtr->DsaAddr.Dsa.busNumber
#define ISERIES_SUBBUS(DevPtr) DevPtr->DsaAddr.Dsa.subBusNumber
#define ISERIES_DEVICE(DevPtr) DevPtr->DsaAddr.Dsa.deviceId
#define ISERIES_DSA(DevPtr) DevPtr->DsaAddr.DsaAddr
#define ISERIES_DEVFUN(DevPtr) DevPtr->DevFn
#define ISERIES_DEVNODE(PciDev) ((struct iSeries_Device_Node*)PciDev->sysdata)
#define EADsMaxAgents 7
/************************************************************************************/
/* Decodes Linux DevFn to iSeries DevFn, bridge device, or function. */
/* For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h */
/************************************************************************************/
#define ISERIES_DECODE_DEVFN(linuxdevfn) (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07))
#define ISERIES_DECODE_DEVICE(linuxdevfn) (((linuxdevfn & 0x38) >> 3) |(((linuxdevfn & 0x40) >> 2) + 0x10))
#define ISERIES_DECODE_FUNCTION(linuxdevfn) (linuxdevfn & 0x07)
/************************************************************************/
/* Decodes Linux DevFn to iSeries DevFn, bridge device, or function. */
/* For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h */
/************************************************************************/
#define ISERIES_PCI_AGENTID(idsel,func) ((idsel & 0x0F) << 4) | (func & 0x07)
#define ISERIES_ENCODE_DEVICE(agentid) ((0x10) | ((agentid&0x20)>>2) | (agentid&07))
#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
#define ISERIES_ENCODE_DEVICE(agentid) ((0x10) | ((agentid&0x20)>>2) | (agentid&07))
/************************************************************************************/
/* Converts Virtual Address to Real Address for Hypervisor calls */
/************************************************************************************/
#define REALADDR(virtaddr) (0x8000000000000000 | (virt_to_absolute((u64)virtaddr) ))
/*
* N.B. the ISERIES_DECODE_* macros are not used anywhere, and I think
* the 0x71 (at least) must be wrong - 0x78 maybe? -- paulus.
*/
#define ISERIES_DECODE_DEVFN(linuxdevfn) (((linuxdevfn & 0x71) << 1) | (linuxdevfn & 0x07))
#define ISERIES_DECODE_DEVICE(linuxdevfn) (((linuxdevfn & 0x38) >> 3) |(((linuxdevfn & 0x40) >> 2) + 0x10))
#define ISERIES_DECODE_FUNCTION(linuxdevfn) (linuxdevfn & 0x07)
/************************************************************************************/
/* Define TRUE and FALSE Values for Al */
/************************************************************************************/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/************************************************************************/
/* Converts Virtual Address to Real Address for Hypervisor calls */
/************************************************************************/
#define REALADDR(virtaddr) (0x8000000000000000 | (virt_to_absolute((u64)virtaddr) ))
/************************************************************************/
/* iSeries Device Information */
/************************************************************************/
struct iSeries_Device_Node {
struct list_head Device_List; /* Must be first for cast to wo*/
struct pci_dev* PciDev; /* Pointer to pci_dev structure*/
struct HvCallPci_DsaAddr DsaAddr;/* Direct Select Address */
/* busNumber,subBusNumber, */
/* deviceId, barNumber */
HvAgentId AgentId; /* Hypervisor DevFn */
int DevFn; /* Linux devfn */
int BarOffset;
int Irq; /* Assigned IRQ */
int ReturnCode; /* Return Code Holder */
int IoRetry; /* Current Retry Count */
int Flags; /* Possible flags(disable/bist)*/
u16 Vendor; /* Vendor ID */
u8 LogicalSlot; /* Hv Slot Index for Tces */
struct TceTable* DevTceTable; /* Device TCE Table */
u8 PhbId; /* Phb Card is on. */
u16 Board; /* Board Number */
u8 FrameId; /* iSeries spcn Frame Id */
char CardLocation[4];/* Char format of planar vpd */
char Location[20]; /* Frame 1, Card C10 */
struct list_head Device_List;
struct pci_dev* PciDev; /* Pointer to pci_dev structure*/
union HvDsaMap DsaAddr; /* Direct Select Address */
/* busNumber,subBusNumber, */
/* deviceId, barNumber */
HvAgentId AgentId; /* Hypervisor DevFn */
int DevFn; /* Linux devfn */
int BarOffset;
int Irq; /* Assigned IRQ */
int ReturnCode; /* Return Code Holder */
int IoRetry; /* Current Retry Count */
int Flags; /* Possible flags(disable/bist)*/
u16 Vendor; /* Vendor ID */
u8 LogicalSlot; /* Hv Slot Index for Tces */
struct TceTable* DevTceTable; /* Device TCE Table */
u8 PhbId; /* Phb Card is on. */
u16 Board; /* Board Number */
u8 FrameId; /* iSeries spcn Frame Id */
char CardLocation[4];/* Char format of planar vpd */
char Location[20]; /* Frame 1, Card C10 */
};
/************************************************************************/
/* Location Data extracted from the VPD list and device info. */
/************************************************************************/
struct LocationDataStruct { /* Location data structure for device */
u16 Bus; /* iSeries Bus Number 0x00*/
u16 Board; /* iSeries Board 0x02*/
......@@ -108,17 +113,14 @@ struct LocationDataStruct { /* Location data structure for device */
u8 Card;
char CardLocation[4];
};
typedef struct LocationDataStruct LocationData;
#define LOCATION_DATA_SIZE 48
/************************************************************************/
/* Flight Recorder tracing */
/************************************************************************/
extern int iSeries_Set_PciTraceFlag(int TraceFlag);
extern int iSeries_Get_PciTraceFlag(void);
/************************************************************************/
/* Functions */
/************************************************************************/
extern LocationData* iSeries_GetLocationData(struct pci_dev* PciDev);
extern int iSeries_Device_Information(struct pci_dev*,char*, int);
extern void iSeries_Get_Location_Code(struct iSeries_Device_Node*);
......
......@@ -41,11 +41,6 @@ static inline unsigned long virt_irq_to_real(unsigned long virt_irq) {
return virt_irq_to_real_map[virt_irq];
}
/*
* This gets called from serial.c, which is now used on
* powermacs as well as prep/chrp boxes.
* Prep and chrp both have cascaded 8259 PICs.
*/
static __inline__ int irq_canonicalize(int irq)
{
return irq;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment