Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 28716
b: refs/heads/master
c: 0d177df
h: refs/heads/master
v: v3
  • Loading branch information
Stephen Rothwell authored and Paul Mackerras committed May 24, 2006
1 parent e065ef1 commit 8c840ff
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 201 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 66b3851a6947482987b4c05aa781a33696287648
refs/heads/master: 0d177df15d12926dc2ef7c814f317f02de52ce17
7 changes: 4 additions & 3 deletions trunk/arch/powerpc/platforms/iseries/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <asm/iseries/it_lp_queue.h>

#include "irq.h"
#include "pci.h"
#include "call_pci.h"

#if defined(CONFIG_SMP)
Expand Down Expand Up @@ -312,12 +313,12 @@ static hw_irq_controller iSeries_IRQ_handler = {
* Note that sub_bus is always 0 (at the moment at least).
*/
int __init iSeries_allocate_IRQ(HvBusNumber bus,
HvSubBusNumber sub_bus, HvAgentId dev_id)
HvSubBusNumber sub_bus, u32 bsubbus)
{
int virtirq;
unsigned int realirq;
u8 idsel = (dev_id >> 4);
u8 function = dev_id & 7;
u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);

realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
+ function;
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/platforms/iseries/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define _ISERIES_IRQ_H

extern void iSeries_init_IRQ(void);
extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
extern void iSeries_activate_IRQs(void);
extern int iSeries_get_irq(struct pt_regs *);

Expand Down
273 changes: 77 additions & 196 deletions trunk/arch/powerpc/platforms/iseries/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,9 @@
* Forward declares of prototypes.
*/
static struct device_node *find_Device_Node(int bus, int devfn);
static void scan_PHB_slots(struct pci_controller *Phb);
static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info);

LIST_HEAD(iSeries_Global_Device_List);

static int DeviceCount;

static int Pci_Retry_Max = 3; /* Only retry 3 times */
static int Pci_Error_Flag = 1; /* Set Retry Error on. */

Expand Down Expand Up @@ -161,32 +156,6 @@ static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
Error_Text, Bus, SubBus, AgentId, HvRc);
}

/*
* build_device_node(u16 Bus, int SubBus, u8 DevFn)
*/
static struct device_node *build_device_node(HvBusNumber Bus,
HvSubBusNumber SubBus, int AgentId, int Function)
{
struct device_node *node;
struct pci_dn *pdn;

node = kzalloc(sizeof(struct device_node), GFP_KERNEL);
if (node == NULL)
return NULL;
pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
if (pdn == NULL) {
kfree(node);
return NULL;
}
node->data = pdn;
pdn->node = node;
list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List);
pdn->busno = Bus;
pdn->bussubno = SubBus;
pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
return node;
}

/*
* iSeries_pcibios_init
*
Expand All @@ -199,33 +168,86 @@ static struct device_node *build_device_node(HvBusNumber Bus,
void iSeries_pcibios_init(void)
{
struct pci_controller *phb;
HvBusNumber bus;

/* Check all possible buses. */
for (bus = 0; bus < 256; bus++) {
int ret = HvCallXm_testBus(bus);
if (ret == 0) {
printk("bus %d appears to exist\n", bus);

phb = pcibios_alloc_controller(NULL);
if (phb == NULL)
return -ENOMEM;
struct device_node *node;
struct device_node *dn;

for_each_node_by_type(node, "pci") {
HvBusNumber bus;
u32 *busp;

busp = (u32 *)get_property(node, "bus-range", NULL);
if (busp == NULL)
continue;
bus = *busp;
printk("bus %d appears to exist\n", bus);
phb = pcibios_alloc_controller(node);
if (phb == NULL)
continue;

phb->pci_mem_offset = phb->local_number = bus;
phb->first_busno = bus;
phb->last_busno = bus;
phb->ops = &iSeries_pci_ops;

/* Find and connect the devices. */
for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
struct pci_dn *pdn;
u8 irq;
int err;
u32 *agent;
u32 *reg;
u32 *lsn;

reg = (u32 *)get_property(dn, "reg", NULL);
if (reg == NULL) {
printk(KERN_DEBUG "no reg property!\n");
continue;
}
busp = (u32 *)get_property(dn, "linux,subbus", NULL);
if (busp == NULL) {
printk(KERN_DEBUG "no subbus property!\n");
continue;
}
agent = (u32 *)get_property(dn, "linux,agent-id", NULL);
if (agent == NULL) {
printk(KERN_DEBUG "no agent-id\n");
continue;
}
lsn = (u32 *)get_property(dn,
"linux,logical-slot-number", NULL);
if (lsn == NULL) {
printk(KERN_DEBUG "no logical-slot-number\n");
continue;
}

phb->pci_mem_offset = phb->local_number = bus;
phb->first_busno = bus;
phb->last_busno = bus;
phb->ops = &iSeries_pci_ops;
irq = iSeries_allocate_IRQ(bus, 0, *busp);
err = HvCallXm_connectBusUnit(bus, *busp, *agent, irq);
if (err) {
pci_Log_Error("Connect Bus Unit",
bus, *busp, *agent, err);
continue;
}
err = HvCallPci_configStore8(bus, *busp, *agent,
PCI_INTERRUPT_LINE, irq);
if (err) {
pci_Log_Error("PciCfgStore Irq Failed!",
bus, *busp, *agent, err);
continue;
}

/* Find and connect the devices. */
scan_PHB_slots(phb);
pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
if (pdn == NULL)
return;
dn->data = pdn;
pdn->node = dn;
pdn->busno = bus;
pdn->devfn = (reg[0] >> 8) & 0xff;
pdn->bussubno = *busp;
pdn->Irq = irq;
pdn->LogicalSlot = *lsn;
list_add_tail(&pdn->Device_List,
&iSeries_Global_Device_List);
}
/*
* Check for Unexpected Return code, a clue that something
* has gone wrong.
*/
else if (ret != 0x0301)
printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X",
bus, ret);
}
}

Expand Down Expand Up @@ -271,147 +293,6 @@ void pcibios_fixup_resources(struct pci_dev *pdev)
{
}

/*
* Loop through each node function to find usable EADs bridges.
*/
static void scan_PHB_slots(struct pci_controller *Phb)
{
struct HvCallPci_DeviceInfo *DevInfo;
HvBusNumber bus = Phb->local_number; /* System Bus */
const HvSubBusNumber SubBus = 0; /* EADs is always 0. */
int HvRc = 0;
int IdSel;
const int MaxAgents = 8;

DevInfo = kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
if (DevInfo == NULL)
return;

/*
* Probe for EADs Bridges
*/
for (IdSel = 1; IdSel < MaxAgents; ++IdSel) {
HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel,
iseries_hv_addr(DevInfo),
sizeof(struct HvCallPci_DeviceInfo));
if (HvRc == 0) {
if (DevInfo->deviceType == HvCallPci_NodeDevice)
scan_EADS_bridge(bus, SubBus, IdSel);
else
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);
}
kfree(DevInfo);
}

static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
int IdSel)
{
struct HvCallPci_BridgeInfo *BridgeInfo;
HvAgentId AgentId;
int Function;
int HvRc;

BridgeInfo = (struct HvCallPci_BridgeInfo *)
kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL);
if (BridgeInfo == NULL)
return;

/* 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);
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 */
HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
iseries_hv_addr(BridgeInfo),
sizeof(struct HvCallPci_BridgeInfo));
if (HvRc == 0) {
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);
if (BridgeInfo->busUnitInfo.deviceType ==
HvCallPci_BridgeDevice) {
/* Scan_Bridge_Slot...: 0x18.00.12 */
scan_bridge_slot(bus, BridgeInfo);
} else
printk("PCI: Invalid Bridge Configuration(0x%02X)",
BridgeInfo->busUnitInfo.deviceType);
}
} else if (HvRc != 0x000B)
pci_Log_Error("EADs Connect",
bus, SubBus, AgentId, HvRc);
}
kfree(BridgeInfo);
}

/*
* This assumes that the node slot is always on the primary bus!
*/
static int scan_bridge_slot(HvBusNumber Bus,
struct HvCallPci_BridgeInfo *BridgeInfo)
{
struct 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 EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);

/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);

/*
* Connect all functions of any device found.
*/
for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
for (Function = 0; Function < 8; ++Function) {
HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
HvRc = HvCallXm_connectBusUnit(Bus, SubBus,
AgentId, Irq);
if (HvRc != 0) {
pci_Log_Error("Connect Bus Unit",
Bus, SubBus, AgentId, HvRc);
continue;
}

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 */
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);
PCI_DN(node)->Irq = Irq;
PCI_DN(node)->LogicalSlot = BridgeInfo->logicalSlotNumber;

} /* for (Function = 0; Function < 8; ++Function) */
} /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */
return HvRc;
}

/*
* I/0 Memory copy MUST use mmio commands on iSeries
* To do; For performance, include the hv call directly
Expand Down
Loading

0 comments on commit 8c840ff

Please sign in to comment.