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;
bus = IRQ_TO_BUS(irq);
function = IRQ_TO_FUNC(irq);
deviceId = (IRQ_TO_IDSEL(irq) << 4) + function;
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, 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;
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);
}
}
/*
......@@ -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;
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",
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;
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",
PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
bus, subBus, deviceId, irq);
}
}
/*
......
This diff is collapsed.
......@@ -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,7 +50,8 @@ struct HvCallPci_LoadReturn {
u64 value;
};
enum HvCallPci_DeviceType {HvCallPci_NodeDevice = 1,
enum HvCallPci_DeviceType {
HvCallPci_NodeDevice = 1,
HvCallPci_SpDevice = 2,
HvCallPci_IopDevice = 3,
HvCallPci_BridgeDevice = 4,
......
#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,56 +29,58 @@
/* 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_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_DSA(DevPtr) (*(u64*)&DevPtr->DsaAddr)
#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)
/************************************************************************/
#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))
/************************************************************************************/
/*
* 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)
/************************************************************************/
/* Converts Virtual Address to Real Address for Hypervisor calls */
/************************************************************************************/
#define REALADDR(virtaddr) (0x8000000000000000 | (virt_to_absolute((u64)virtaddr) ))
/************************************************************************/
/************************************************************************************/
/* Define TRUE and FALSE Values for Al */
/************************************************************************************/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#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 list_head Device_List;
struct pci_dev* PciDev; /* Pointer to pci_dev structure*/
struct HvCallPci_DsaAddr DsaAddr;/* Direct Select Address */
union HvDsaMap DsaAddr; /* Direct Select Address */
/* busNumber,subBusNumber, */
/* deviceId, barNumber */
HvAgentId AgentId; /* Hypervisor DevFn */
......@@ -96,9 +99,11 @@ struct iSeries_Device_Node {
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