2005-11-19 17:17:32 +08:00
|
|
|
#ifndef _ASM_POWERPC_PCI_BRIDGE_H
|
|
|
|
#define _ASM_POWERPC_PCI_BRIDGE_H
|
2005-12-17 05:43:46 +08:00
|
|
|
#ifdef __KERNEL__
|
2005-11-19 17:17:32 +08:00
|
|
|
|
|
|
|
#ifndef CONFIG_PPC64
|
|
|
|
#include <asm-ppc/pci-bridge.h>
|
|
|
|
#else
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <linux/pci.h>
|
2005-10-10 20:52:26 +08:00
|
|
|
#include <linux/list.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure of a PCI controller (host bridge)
|
|
|
|
*/
|
|
|
|
struct pci_controller {
|
|
|
|
struct pci_bus *bus;
|
|
|
|
char is_dynamic;
|
2006-06-10 18:53:06 +08:00
|
|
|
int node;
|
2005-04-17 06:20:36 +08:00
|
|
|
void *arch_data;
|
|
|
|
struct list_head list_node;
|
|
|
|
|
|
|
|
int first_busno;
|
|
|
|
int last_busno;
|
|
|
|
|
|
|
|
void __iomem *io_base_virt;
|
|
|
|
unsigned long io_base_phys;
|
|
|
|
|
|
|
|
/* Some machines have a non 1:1 mapping of
|
|
|
|
* the PCI memory space in the CPU bus space
|
|
|
|
*/
|
|
|
|
unsigned long pci_mem_offset;
|
|
|
|
unsigned long pci_io_size;
|
|
|
|
|
|
|
|
struct pci_ops *ops;
|
|
|
|
volatile unsigned int __iomem *cfg_addr;
|
2005-10-20 19:10:09 +08:00
|
|
|
volatile void __iomem *cfg_data;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Currently, we limit ourselves to 1 IO range and 3 mem
|
|
|
|
* ranges since the common pci_bus structure can't handle more
|
|
|
|
*/
|
|
|
|
struct resource io_resource;
|
|
|
|
struct resource mem_resources[3];
|
|
|
|
int global_number;
|
|
|
|
int local_number;
|
|
|
|
unsigned long buid;
|
|
|
|
unsigned long dma_window_base_cur;
|
|
|
|
unsigned long dma_window_size;
|
|
|
|
};
|
|
|
|
|
2005-09-06 11:17:54 +08:00
|
|
|
/*
|
|
|
|
* PCI stuff, for nodes representing PCI devices, pointed to
|
|
|
|
* by device_node->data.
|
|
|
|
*/
|
|
|
|
struct pci_controller;
|
|
|
|
struct iommu_table;
|
|
|
|
|
|
|
|
struct pci_dn {
|
2005-11-04 08:55:19 +08:00
|
|
|
int busno; /* pci bus number */
|
|
|
|
int bussubno; /* pci subordinate bus number */
|
|
|
|
int devfn; /* pci device and function number */
|
|
|
|
int class_code; /* pci device class */
|
2005-11-15 13:05:33 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_PSERIES
|
2005-09-06 11:17:54 +08:00
|
|
|
int eeh_mode; /* See eeh.h for possible EEH_MODEs */
|
|
|
|
int eeh_config_addr;
|
2005-11-04 08:53:20 +08:00
|
|
|
int eeh_pe_config_addr; /* new-style partition endpoint address */
|
2005-09-06 11:17:54 +08:00
|
|
|
int eeh_check_count; /* # times driver ignored error */
|
|
|
|
int eeh_freeze_count; /* # times this device froze up. */
|
2005-11-15 13:05:33 +08:00
|
|
|
#endif
|
2005-09-06 11:17:54 +08:00
|
|
|
int pci_ext_config_space; /* for pci devices */
|
|
|
|
struct pci_controller *phb; /* for pci devices */
|
|
|
|
struct iommu_table *iommu_table; /* for phb's or bridges */
|
|
|
|
struct pci_dev *pcidev; /* back-pointer to the pci device */
|
|
|
|
struct device_node *node; /* back-pointer to the device_node */
|
|
|
|
u32 config_space[16]; /* saved PCI config space */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Get the pointer to a device_node's pci_dn */
|
|
|
|
#define PCI_DN(dn) ((struct pci_dn *) (dn)->data)
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
struct device_node *fetch_dev_dn(struct pci_dev *dev);
|
|
|
|
|
2005-09-06 11:17:54 +08:00
|
|
|
/* Get a device_node from a pci_dev. This code must be fast except
|
|
|
|
* in the case where the sysdata is incorrect and needs to be fixed
|
|
|
|
* up (this will only happen once).
|
|
|
|
* In this case the sysdata will have been inherited from a PCI host
|
|
|
|
* bridge or a PCI-PCI bridge further up the tree, so it will point
|
|
|
|
* to a valid struct pci_dn, just not the one we want.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
|
|
|
|
{
|
|
|
|
struct device_node *dn = dev->sysdata;
|
2005-09-06 11:17:54 +08:00
|
|
|
struct pci_dn *pdn = dn->data;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-09-06 11:17:54 +08:00
|
|
|
if (pdn && pdn->devfn == dev->devfn && pdn->busno == dev->bus->number)
|
2005-04-17 06:20:36 +08:00
|
|
|
return dn; /* fast path. sysdata is good */
|
2005-09-06 11:17:54 +08:00
|
|
|
return fetch_dev_dn(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-10-10 20:50:37 +08:00
|
|
|
static inline int pci_device_from_OF_node(struct device_node *np,
|
|
|
|
u8 *bus, u8 *devfn)
|
|
|
|
{
|
|
|
|
if (!PCI_DN(np))
|
|
|
|
return -ENODEV;
|
|
|
|
*bus = PCI_DN(np)->busno;
|
|
|
|
*devfn = PCI_DN(np)->devfn;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
|
|
|
|
{
|
|
|
|
if (bus->self)
|
|
|
|
return pci_device_to_OF_node(bus->self);
|
|
|
|
else
|
|
|
|
return bus->sysdata; /* Must be root bus (PHB) */
|
|
|
|
}
|
|
|
|
|
2005-11-04 08:52:16 +08:00
|
|
|
/** Find the bus corresponding to the indicated device node */
|
|
|
|
struct pci_bus * pcibios_find_pci_bus(struct device_node *dn);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
|
2005-10-22 13:03:21 +08:00
|
|
|
struct device_node *dev, int primary);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-11-04 08:52:16 +08:00
|
|
|
/** Remove all of the PCI devices under this bus */
|
|
|
|
void pcibios_remove_pci_devices(struct pci_bus *bus);
|
|
|
|
|
|
|
|
/** Discover new pci devices under this bus, and add them */
|
|
|
|
void pcibios_add_pci_devices(struct pci_bus * bus);
|
2005-12-14 03:46:36 +08:00
|
|
|
void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus);
|
2005-11-04 08:52:16 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
extern int pcibios_remove_root_bus(struct pci_controller *phb);
|
|
|
|
|
|
|
|
static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
|
|
|
|
{
|
|
|
|
struct device_node *busdn = bus->sysdata;
|
|
|
|
|
|
|
|
BUG_ON(busdn == NULL);
|
2005-09-06 11:17:54 +08:00
|
|
|
return PCI_DN(busdn)->phb;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-11-23 14:56:06 +08:00
|
|
|
extern struct pci_controller*
|
|
|
|
pci_find_hose_for_OF_device(struct device_node* node);
|
|
|
|
|
2005-11-15 13:05:33 +08:00
|
|
|
extern struct pci_controller *
|
|
|
|
pcibios_alloc_controller(struct device_node *dev);
|
|
|
|
extern void pcibios_free_controller(struct pci_controller *phb);
|
|
|
|
|
2005-11-30 13:57:28 +08:00
|
|
|
#ifdef CONFIG_PCI
|
2005-12-15 12:00:57 +08:00
|
|
|
extern unsigned long pci_address_to_pio(phys_addr_t address);
|
2005-11-30 13:57:28 +08:00
|
|
|
#else
|
2005-12-15 12:00:57 +08:00
|
|
|
static inline unsigned long pci_address_to_pio(phys_addr_t address)
|
2005-11-30 13:57:28 +08:00
|
|
|
{
|
2005-12-15 12:00:57 +08:00
|
|
|
return (unsigned long)-1;
|
2005-11-30 13:57:28 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
ppc64: Set up PCI tree from Open Firmware device tree
This adds code which gives us the option on ppc64 of instantiating the
PCI tree (the tree of pci_bus and pci_dev structs) from the Open
Firmware device tree rather than by probing PCI configuration space.
The OF device tree has a node for each PCI device and bridge in the
system, with properties that tell us what addresses the firmware has
configured for them and other details.
There are a couple of reasons why this is needed. First, on systems
with a hypervisor, there is a PCI-PCI bridge per slot under the PCI
host bridges. These PCI-PCI bridges have special isolation features
for virtualization. We can't write to their config space, and we are
not supposed to be reading their config space either. The firmware
tells us about the address ranges that they pass in the OF device
tree.
Secondly, on powermacs, the interrupt controller is in a PCI device
that may be behind a PCI-PCI bridge. If we happened to take an
interrupt just at the point when the device or a bridge on the path to
it was disabled for probing, we would crash when we try to access the
interrupt controller.
I have implemented a platform-specific function which is called for
each PCI bridge (host or PCI-PCI) to say whether the code should look
in the device tree or use normal PCI probing for the devices under
that bridge. On pSeries machines we use the device tree if we're
running under a hypervisor, otherwise we use normal probing. On
powermacs we use normal probing for the AGP bridge, since the device
for the AGP bridge itself isn't shown in the device tree (at least on
my G5), and the device tree for everything else.
This has been tested on a dual G5 powermac, a partition on a POWER5
machine (running under the hypervisor), and a legacy iSeries
partition.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2005-09-12 15:17:36 +08:00
|
|
|
/* Return values for ppc_md.pci_probe_mode function */
|
|
|
|
#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
|
|
|
|
#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
|
|
|
|
#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */
|
|
|
|
|
2006-06-10 18:53:06 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
|
|
|
#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = (NODE))
|
|
|
|
#else
|
|
|
|
#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = -1)
|
|
|
|
#endif
|
|
|
|
|
2005-11-19 17:17:32 +08:00
|
|
|
#endif /* CONFIG_PPC64 */
|
2005-12-17 05:43:46 +08:00
|
|
|
#endif /* __KERNEL__ */
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|