[PATCH] Separate pci bits out of struct device_node
This patch pulls the PCI-related junk out of struct device_node and puts it in a separate structure, struct pci_dn. The device_node now just has a void * pointer in it, which points to a struct pci_dn for nodes that represent PCI devices. It could potentially be used in future for device-specific data for other sorts of devices, such as virtual I/O devices. Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Родитель
b28d2582ce
Коммит
1635317fac
|
@ -254,6 +254,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
|
||||||
static void __pci_addr_cache_insert_device(struct pci_dev *dev)
|
static void __pci_addr_cache_insert_device(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct device_node *dn;
|
struct device_node *dn;
|
||||||
|
struct pci_dn *pdn;
|
||||||
int i;
|
int i;
|
||||||
int inserted = 0;
|
int inserted = 0;
|
||||||
|
|
||||||
|
@ -265,8 +266,9 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip any devices for which EEH is not enabled. */
|
/* Skip any devices for which EEH is not enabled. */
|
||||||
if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
|
pdn = dn->data;
|
||||||
dn->eeh_mode & EEH_MODE_NOCHECK) {
|
if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
|
||||||
|
pdn->eeh_mode & EEH_MODE_NOCHECK) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printk(KERN_INFO "PCI: skip building address cache for=%s\n",
|
printk(KERN_INFO "PCI: skip building address cache for=%s\n",
|
||||||
pci_name(dev));
|
pci_name(dev));
|
||||||
|
@ -415,6 +417,7 @@ int eeh_unregister_notifier(struct notifier_block *nb)
|
||||||
static int read_slot_reset_state(struct device_node *dn, int rets[])
|
static int read_slot_reset_state(struct device_node *dn, int rets[])
|
||||||
{
|
{
|
||||||
int token, outputs;
|
int token, outputs;
|
||||||
|
struct pci_dn *pdn = dn->data;
|
||||||
|
|
||||||
if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
|
if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
|
||||||
token = ibm_read_slot_reset_state2;
|
token = ibm_read_slot_reset_state2;
|
||||||
|
@ -424,8 +427,8 @@ static int read_slot_reset_state(struct device_node *dn, int rets[])
|
||||||
outputs = 3;
|
outputs = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtas_call(token, 3, outputs, rets, dn->eeh_config_addr,
|
return rtas_call(token, 3, outputs, rets, pdn->eeh_config_addr,
|
||||||
BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
|
BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -534,6 +537,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int rc, reset_state;
|
int rc, reset_state;
|
||||||
struct eeh_event *event;
|
struct eeh_event *event;
|
||||||
|
struct pci_dn *pdn;
|
||||||
|
|
||||||
__get_cpu_var(total_mmio_ffs)++;
|
__get_cpu_var(total_mmio_ffs)++;
|
||||||
|
|
||||||
|
@ -542,14 +546,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
|
||||||
|
|
||||||
if (!dn)
|
if (!dn)
|
||||||
return 0;
|
return 0;
|
||||||
|
pdn = dn->data;
|
||||||
|
|
||||||
/* Access to IO BARs might get this far and still not want checking. */
|
/* Access to IO BARs might get this far and still not want checking. */
|
||||||
if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) ||
|
if (!pdn->eeh_capable || !(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
|
||||||
dn->eeh_mode & EEH_MODE_NOCHECK) {
|
pdn->eeh_mode & EEH_MODE_NOCHECK) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dn->eeh_config_addr) {
|
if (!pdn->eeh_config_addr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +562,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
|
||||||
* If we already have a pending isolation event for this
|
* If we already have a pending isolation event for this
|
||||||
* slot, we know it's bad already, we don't need to check...
|
* slot, we know it's bad already, we don't need to check...
|
||||||
*/
|
*/
|
||||||
if (dn->eeh_mode & EEH_MODE_ISOLATED) {
|
if (pdn->eeh_mode & EEH_MODE_ISOLATED) {
|
||||||
atomic_inc(&eeh_fail_count);
|
atomic_inc(&eeh_fail_count);
|
||||||
if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) {
|
if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) {
|
||||||
/* re-read the slot reset state */
|
/* re-read the slot reset state */
|
||||||
|
@ -582,7 +587,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prevent repeated reports of this failure */
|
/* prevent repeated reports of this failure */
|
||||||
dn->eeh_mode |= EEH_MODE_ISOLATED;
|
pdn->eeh_mode |= EEH_MODE_ISOLATED;
|
||||||
|
|
||||||
reset_state = rets[0];
|
reset_state = rets[0];
|
||||||
|
|
||||||
|
@ -590,9 +595,9 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
|
||||||
memset(slot_errbuf, 0, eeh_error_buf_size);
|
memset(slot_errbuf, 0, eeh_error_buf_size);
|
||||||
|
|
||||||
rc = rtas_call(ibm_slot_error_detail,
|
rc = rtas_call(ibm_slot_error_detail,
|
||||||
8, 1, NULL, dn->eeh_config_addr,
|
8, 1, NULL, pdn->eeh_config_addr,
|
||||||
BUID_HI(dn->phb->buid),
|
BUID_HI(pdn->phb->buid),
|
||||||
BUID_LO(dn->phb->buid), NULL, 0,
|
BUID_LO(pdn->phb->buid), NULL, 0,
|
||||||
virt_to_phys(slot_errbuf),
|
virt_to_phys(slot_errbuf),
|
||||||
eeh_error_buf_size,
|
eeh_error_buf_size,
|
||||||
1 /* Temporary Error */);
|
1 /* Temporary Error */);
|
||||||
|
@ -679,8 +684,9 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
|
||||||
u32 *device_id = (u32 *)get_property(dn, "device-id", NULL);
|
u32 *device_id = (u32 *)get_property(dn, "device-id", NULL);
|
||||||
u32 *regs;
|
u32 *regs;
|
||||||
int enable;
|
int enable;
|
||||||
|
struct pci_dn *pdn = dn->data;
|
||||||
|
|
||||||
dn->eeh_mode = 0;
|
pdn->eeh_mode = 0;
|
||||||
|
|
||||||
if (status && strcmp(status, "ok") != 0)
|
if (status && strcmp(status, "ok") != 0)
|
||||||
return NULL; /* ignore devices with bad status */
|
return NULL; /* ignore devices with bad status */
|
||||||
|
@ -691,7 +697,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
|
||||||
|
|
||||||
/* There is nothing to check on PCI to ISA bridges */
|
/* There is nothing to check on PCI to ISA bridges */
|
||||||
if (dn->type && !strcmp(dn->type, "isa")) {
|
if (dn->type && !strcmp(dn->type, "isa")) {
|
||||||
dn->eeh_mode |= EEH_MODE_NOCHECK;
|
pdn->eeh_mode |= EEH_MODE_NOCHECK;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,7 +714,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
|
||||||
enable = 0;
|
enable = 0;
|
||||||
|
|
||||||
if (!enable)
|
if (!enable)
|
||||||
dn->eeh_mode |= EEH_MODE_NOCHECK;
|
pdn->eeh_mode |= EEH_MODE_NOCHECK;
|
||||||
|
|
||||||
/* Ok... see if this device supports EEH. Some do, some don't,
|
/* Ok... see if this device supports EEH. Some do, some don't,
|
||||||
* and the only way to find out is to check each and every one. */
|
* and the only way to find out is to check each and every one. */
|
||||||
|
@ -721,8 +727,8 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
|
||||||
EEH_ENABLE);
|
EEH_ENABLE);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
eeh_subsystem_enabled = 1;
|
eeh_subsystem_enabled = 1;
|
||||||
dn->eeh_mode |= EEH_MODE_SUPPORTED;
|
pdn->eeh_mode |= EEH_MODE_SUPPORTED;
|
||||||
dn->eeh_config_addr = regs[0];
|
pdn->eeh_config_addr = regs[0];
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name);
|
printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name);
|
||||||
#endif
|
#endif
|
||||||
|
@ -730,10 +736,11 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
|
||||||
|
|
||||||
/* This device doesn't support EEH, but it may have an
|
/* This device doesn't support EEH, but it may have an
|
||||||
* EEH parent, in which case we mark it as supported. */
|
* EEH parent, in which case we mark it as supported. */
|
||||||
if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
|
if (dn->parent && dn->parent->data
|
||||||
|
&& (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
|
||||||
/* Parent supports EEH. */
|
/* Parent supports EEH. */
|
||||||
dn->eeh_mode |= EEH_MODE_SUPPORTED;
|
pdn->eeh_mode |= EEH_MODE_SUPPORTED;
|
||||||
dn->eeh_config_addr = dn->parent->eeh_config_addr;
|
pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -790,11 +797,13 @@ void __init eeh_init(void)
|
||||||
for (phb = of_find_node_by_name(NULL, "pci"); phb;
|
for (phb = of_find_node_by_name(NULL, "pci"); phb;
|
||||||
phb = of_find_node_by_name(phb, "pci")) {
|
phb = of_find_node_by_name(phb, "pci")) {
|
||||||
unsigned long buid;
|
unsigned long buid;
|
||||||
|
struct pci_dn *pci;
|
||||||
|
|
||||||
buid = get_phb_buid(phb);
|
buid = get_phb_buid(phb);
|
||||||
if (buid == 0)
|
if (buid == 0 || phb->data == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
pci = phb->data;
|
||||||
info.buid_lo = BUID_LO(buid);
|
info.buid_lo = BUID_LO(buid);
|
||||||
info.buid_hi = BUID_HI(buid);
|
info.buid_hi = BUID_HI(buid);
|
||||||
traverse_pci_devices(phb, early_enable_eeh, &info);
|
traverse_pci_devices(phb, early_enable_eeh, &info);
|
||||||
|
@ -823,9 +832,9 @@ void eeh_add_device_early(struct device_node *dn)
|
||||||
struct pci_controller *phb;
|
struct pci_controller *phb;
|
||||||
struct eeh_early_enable_info info;
|
struct eeh_early_enable_info info;
|
||||||
|
|
||||||
if (!dn)
|
if (!dn || !dn->data)
|
||||||
return;
|
return;
|
||||||
phb = dn->phb;
|
phb = PCI_DN(dn)->phb;
|
||||||
if (NULL == phb || 0 == phb->buid) {
|
if (NULL == phb || 0 == phb->buid) {
|
||||||
printk(KERN_WARNING "EEH: Expected buid but found none\n");
|
printk(KERN_WARNING "EEH: Expected buid but found none\n");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -438,7 +438,8 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl)
|
||||||
|
|
||||||
void iommu_free_table(struct device_node *dn)
|
void iommu_free_table(struct device_node *dn)
|
||||||
{
|
{
|
||||||
struct iommu_table *tbl = dn->iommu_table;
|
struct pci_dn *pdn = dn->data;
|
||||||
|
struct iommu_table *tbl = pdn->iommu_table;
|
||||||
unsigned long bitmap_sz, i;
|
unsigned long bitmap_sz, i;
|
||||||
unsigned int order;
|
unsigned int order;
|
||||||
|
|
||||||
|
|
|
@ -447,9 +447,9 @@ void __init maple_pci_init(void)
|
||||||
*/
|
*/
|
||||||
if (u3_agp) {
|
if (u3_agp) {
|
||||||
struct device_node *np = u3_agp->arch_data;
|
struct device_node *np = u3_agp->arch_data;
|
||||||
np->busno = 0xf0;
|
PCI_DN(np)->busno = 0xf0;
|
||||||
for (np = np->child; np; np = np->sibling)
|
for (np = np->child; np; np = np->sibling)
|
||||||
np->busno = 0xf0;
|
PCI_DN(np)->busno = 0xf0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell pci.c to use the common resource allocation mecanism */
|
/* Tell pci.c to use the common resource allocation mecanism */
|
||||||
|
|
|
@ -295,7 +295,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
|
||||||
struct iommu_table *tbl,
|
struct iommu_table *tbl,
|
||||||
unsigned int *dma_window)
|
unsigned int *dma_window)
|
||||||
{
|
{
|
||||||
tbl->it_busno = dn->bussubno;
|
tbl->it_busno = PCI_DN(dn)->bussubno;
|
||||||
|
|
||||||
/* TODO: Parse field size properties properly. */
|
/* TODO: Parse field size properties properly. */
|
||||||
tbl->it_size = (((unsigned long)dma_window[4] << 32) |
|
tbl->it_size = (((unsigned long)dma_window[4] << 32) |
|
||||||
|
@ -311,6 +311,7 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
|
||||||
static void iommu_bus_setup_pSeries(struct pci_bus *bus)
|
static void iommu_bus_setup_pSeries(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
struct device_node *dn, *pdn;
|
struct device_node *dn, *pdn;
|
||||||
|
struct pci_dn *pci;
|
||||||
struct iommu_table *tbl;
|
struct iommu_table *tbl;
|
||||||
|
|
||||||
DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);
|
DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self);
|
||||||
|
@ -325,6 +326,7 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dn = pci_bus_to_OF_node(bus);
|
dn = pci_bus_to_OF_node(bus);
|
||||||
|
pci = dn->data;
|
||||||
|
|
||||||
if (!bus->self) {
|
if (!bus->self) {
|
||||||
/* Root bus */
|
/* Root bus */
|
||||||
|
@ -341,18 +343,18 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
|
||||||
* alltogether. This leaves 768MB for the window.
|
* alltogether. This leaves 768MB for the window.
|
||||||
*/
|
*/
|
||||||
DBG("PHB has io-hole, reserving 256MB\n");
|
DBG("PHB has io-hole, reserving 256MB\n");
|
||||||
dn->phb->dma_window_size = 3 << 28;
|
pci->phb->dma_window_size = 3 << 28;
|
||||||
dn->phb->dma_window_base_cur = 1 << 28;
|
pci->phb->dma_window_base_cur = 1 << 28;
|
||||||
} else {
|
} else {
|
||||||
/* 1GB window by default */
|
/* 1GB window by default */
|
||||||
dn->phb->dma_window_size = 1 << 30;
|
pci->phb->dma_window_size = 1 << 30;
|
||||||
dn->phb->dma_window_base_cur = 0;
|
pci->phb->dma_window_base_cur = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
|
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
|
||||||
|
|
||||||
iommu_table_setparms(dn->phb, dn, tbl);
|
iommu_table_setparms(pci->phb, dn, tbl);
|
||||||
dn->iommu_table = iommu_init_table(tbl);
|
pci->iommu_table = iommu_init_table(tbl);
|
||||||
} else {
|
} else {
|
||||||
/* Do a 128MB table at root. This is used for the IDE
|
/* Do a 128MB table at root. This is used for the IDE
|
||||||
* controller on some SMP-mode POWER4 machines. It
|
* controller on some SMP-mode POWER4 machines. It
|
||||||
|
@ -363,16 +365,16 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
|
||||||
* Allocate at offset 128MB to avoid having to deal
|
* Allocate at offset 128MB to avoid having to deal
|
||||||
* with ISA holes; 128MB table for IDE is plenty.
|
* with ISA holes; 128MB table for IDE is plenty.
|
||||||
*/
|
*/
|
||||||
dn->phb->dma_window_size = 1 << 27;
|
pci->phb->dma_window_size = 1 << 27;
|
||||||
dn->phb->dma_window_base_cur = 1 << 27;
|
pci->phb->dma_window_base_cur = 1 << 27;
|
||||||
|
|
||||||
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
|
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
|
||||||
|
|
||||||
iommu_table_setparms(dn->phb, dn, tbl);
|
iommu_table_setparms(pci->phb, dn, tbl);
|
||||||
dn->iommu_table = iommu_init_table(tbl);
|
pci->iommu_table = iommu_init_table(tbl);
|
||||||
|
|
||||||
/* All child buses have 256MB tables */
|
/* All child buses have 256MB tables */
|
||||||
dn->phb->dma_window_size = 1 << 28;
|
pci->phb->dma_window_size = 1 << 28;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pdn = pci_bus_to_OF_node(bus->parent);
|
pdn = pci_bus_to_OF_node(bus->parent);
|
||||||
|
@ -386,12 +388,12 @@ static void iommu_bus_setup_pSeries(struct pci_bus *bus)
|
||||||
|
|
||||||
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
|
tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
|
||||||
|
|
||||||
iommu_table_setparms(dn->phb, dn, tbl);
|
iommu_table_setparms(pci->phb, dn, tbl);
|
||||||
|
|
||||||
dn->iommu_table = iommu_init_table(tbl);
|
pci->iommu_table = iommu_init_table(tbl);
|
||||||
} else {
|
} else {
|
||||||
/* Lower than first child or under python, use parent table */
|
/* Lower than first child or under python, use parent table */
|
||||||
dn->iommu_table = pdn->iommu_table;
|
pci->iommu_table = PCI_DN(pdn)->iommu_table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,6 +403,7 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
struct iommu_table *tbl;
|
struct iommu_table *tbl;
|
||||||
struct device_node *dn, *pdn;
|
struct device_node *dn, *pdn;
|
||||||
|
struct pci_dn *ppci;
|
||||||
unsigned int *dma_window = NULL;
|
unsigned int *dma_window = NULL;
|
||||||
|
|
||||||
DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
|
DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self);
|
||||||
|
@ -419,22 +422,24 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pdn->iommu_table) {
|
ppci = pdn->data;
|
||||||
|
if (!ppci->iommu_table) {
|
||||||
/* Bussubno hasn't been copied yet.
|
/* Bussubno hasn't been copied yet.
|
||||||
* Do it now because iommu_table_setparms_lpar needs it.
|
* Do it now because iommu_table_setparms_lpar needs it.
|
||||||
*/
|
*/
|
||||||
pdn->bussubno = bus->number;
|
|
||||||
|
ppci->bussubno = bus->number;
|
||||||
|
|
||||||
tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
|
tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
||||||
iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
|
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
|
||||||
|
|
||||||
pdn->iommu_table = iommu_init_table(tbl);
|
ppci->iommu_table = iommu_init_table(tbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdn != dn)
|
if (pdn != dn)
|
||||||
dn->iommu_table = pdn->iommu_table;
|
PCI_DN(dn)->iommu_table = ppci->iommu_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,11 +454,11 @@ static void iommu_dev_setup_pSeries(struct pci_dev *dev)
|
||||||
*/
|
*/
|
||||||
mydn = dn = pci_device_to_OF_node(dev);
|
mydn = dn = pci_device_to_OF_node(dev);
|
||||||
|
|
||||||
while (dn && dn->iommu_table == NULL)
|
while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL)
|
||||||
dn = dn->parent;
|
dn = dn->parent;
|
||||||
|
|
||||||
if (dn) {
|
if (dn && dn->data) {
|
||||||
mydn->iommu_table = dn->iommu_table;
|
PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table;
|
||||||
} else {
|
} else {
|
||||||
DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, dev->pretty_name);
|
DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, dev->pretty_name);
|
||||||
}
|
}
|
||||||
|
@ -463,10 +468,11 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
|
||||||
{
|
{
|
||||||
int err = NOTIFY_OK;
|
int err = NOTIFY_OK;
|
||||||
struct device_node *np = node;
|
struct device_node *np = node;
|
||||||
|
struct pci_dn *pci = np->data;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case PSERIES_RECONFIG_REMOVE:
|
case PSERIES_RECONFIG_REMOVE:
|
||||||
if (np->iommu_table &&
|
if (pci->iommu_table &&
|
||||||
get_property(np, "ibm,dma-window", NULL))
|
get_property(np, "ibm,dma-window", NULL))
|
||||||
iommu_free_table(np);
|
iommu_free_table(np);
|
||||||
break;
|
break;
|
||||||
|
@ -486,6 +492,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
|
||||||
struct device_node *pdn, *dn;
|
struct device_node *pdn, *dn;
|
||||||
struct iommu_table *tbl;
|
struct iommu_table *tbl;
|
||||||
int *dma_window = NULL;
|
int *dma_window = NULL;
|
||||||
|
struct pci_dn *pci;
|
||||||
|
|
||||||
DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name);
|
DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name);
|
||||||
|
|
||||||
|
@ -497,8 +504,10 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
|
||||||
*/
|
*/
|
||||||
dn = pci_device_to_OF_node(dev);
|
dn = pci_device_to_OF_node(dev);
|
||||||
|
|
||||||
for (pdn = dn; pdn && !pdn->iommu_table; pdn = pdn->parent) {
|
for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table;
|
||||||
dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL);
|
pdn = pdn->parent) {
|
||||||
|
dma_window = (unsigned int *)
|
||||||
|
get_property(pdn, "ibm,dma-window", NULL);
|
||||||
if (dma_window)
|
if (dma_window)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -515,20 +524,21 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev)
|
||||||
DBG("Found DMA window, allocating table\n");
|
DBG("Found DMA window, allocating table\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pdn->iommu_table) {
|
pci = pdn->data;
|
||||||
|
if (!pci->iommu_table) {
|
||||||
/* iommu_table_setparms_lpar needs bussubno. */
|
/* iommu_table_setparms_lpar needs bussubno. */
|
||||||
pdn->bussubno = pdn->phb->bus->number;
|
pci->bussubno = pci->phb->bus->number;
|
||||||
|
|
||||||
tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
|
tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
||||||
iommu_table_setparms_lpar(pdn->phb, pdn, tbl, dma_window);
|
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
|
||||||
|
|
||||||
pdn->iommu_table = iommu_init_table(tbl);
|
pci->iommu_table = iommu_init_table(tbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdn != dn)
|
if (pdn != dn)
|
||||||
dn->iommu_table = pdn->iommu_table;
|
PCI_DN(dn)->iommu_table = pci->iommu_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iommu_bus_setup_null(struct pci_bus *b) { }
|
static void iommu_bus_setup_null(struct pci_bus *b) { }
|
||||||
|
|
|
@ -837,9 +837,11 @@ int pcibios_scan_all_fns(struct pci_bus *bus, int devfn)
|
||||||
* device tree. If they are then we need to scan all the
|
* device tree. If they are then we need to scan all the
|
||||||
* functions of this slot.
|
* functions of this slot.
|
||||||
*/
|
*/
|
||||||
for (dn = busdn->child; dn; dn = dn->sibling)
|
for (dn = busdn->child; dn; dn = dn->sibling) {
|
||||||
if ((dn->devfn >> 3) == (devfn >> 3))
|
struct pci_dn *pdn = dn->data;
|
||||||
|
if (pdn && (pdn->devfn >> 3) == (devfn >> 3))
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
|
||||||
|
|
||||||
void pci_devs_phb_init(void);
|
void pci_devs_phb_init(void);
|
||||||
void pci_devs_phb_init_dynamic(struct pci_controller *phb);
|
void pci_devs_phb_init_dynamic(struct pci_controller *phb);
|
||||||
struct device_node *fetch_dev_dn(struct pci_dev *dev);
|
|
||||||
|
|
||||||
/* PCI address cache management routines */
|
/* PCI address cache management routines */
|
||||||
void pci_addr_cache_insert_device(struct pci_dev *dev);
|
void pci_addr_cache_insert_device(struct pci_dev *dev);
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/bootmem.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
|
@ -40,16 +42,26 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
|
||||||
struct pci_controller *phb = data;
|
struct pci_controller *phb = data;
|
||||||
int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
|
int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL);
|
||||||
u32 *regs;
|
u32 *regs;
|
||||||
|
struct pci_dn *pdn;
|
||||||
|
|
||||||
dn->phb = phb;
|
if (phb->is_dynamic)
|
||||||
|
pdn = kmalloc(sizeof(*pdn), GFP_KERNEL);
|
||||||
|
else
|
||||||
|
pdn = alloc_bootmem(sizeof(*pdn));
|
||||||
|
if (pdn == NULL)
|
||||||
|
return NULL;
|
||||||
|
memset(pdn, 0, sizeof(*pdn));
|
||||||
|
dn->data = pdn;
|
||||||
|
pdn->node = dn;
|
||||||
|
pdn->phb = phb;
|
||||||
regs = (u32 *)get_property(dn, "reg", NULL);
|
regs = (u32 *)get_property(dn, "reg", NULL);
|
||||||
if (regs) {
|
if (regs) {
|
||||||
/* First register entry is addr (00BBSS00) */
|
/* First register entry is addr (00BBSS00) */
|
||||||
dn->busno = (regs[0] >> 16) & 0xff;
|
pdn->busno = (regs[0] >> 16) & 0xff;
|
||||||
dn->devfn = (regs[0] >> 8) & 0xff;
|
pdn->devfn = (regs[0] >> 8) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
dn->pci_ext_config_space = (type && *type == 1);
|
pdn->pci_ext_config_space = (type && *type == 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +124,15 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
|
||||||
void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
|
void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
|
||||||
{
|
{
|
||||||
struct device_node * dn = (struct device_node *) phb->arch_data;
|
struct device_node * dn = (struct device_node *) phb->arch_data;
|
||||||
|
struct pci_dn *pdn;
|
||||||
|
|
||||||
/* PHB nodes themselves must not match */
|
/* PHB nodes themselves must not match */
|
||||||
dn->devfn = dn->busno = -1;
|
update_dn_pci_info(dn, phb);
|
||||||
dn->phb = phb;
|
pdn = dn->data;
|
||||||
|
if (pdn) {
|
||||||
|
pdn->devfn = pdn->busno = -1;
|
||||||
|
pdn->phb = phb;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update dn->phb ptrs for new phb and children devices */
|
/* Update dn->phb ptrs for new phb and children devices */
|
||||||
traverse_pci_devices(dn, update_dn_pci_info, phb);
|
traverse_pci_devices(dn, update_dn_pci_info, phb);
|
||||||
|
@ -123,14 +140,17 @@ void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Traversal func that looks for a <busno,devfcn> value.
|
* Traversal func that looks for a <busno,devfcn> value.
|
||||||
* If found, the device_node is returned (thus terminating the traversal).
|
* If found, the pci_dn is returned (thus terminating the traversal).
|
||||||
*/
|
*/
|
||||||
static void *is_devfn_node(struct device_node *dn, void *data)
|
static void *is_devfn_node(struct device_node *dn, void *data)
|
||||||
{
|
{
|
||||||
int busno = ((unsigned long)data >> 8) & 0xff;
|
int busno = ((unsigned long)data >> 8) & 0xff;
|
||||||
int devfn = ((unsigned long)data) & 0xff;
|
int devfn = ((unsigned long)data) & 0xff;
|
||||||
|
struct pci_dn *pci = dn->data;
|
||||||
|
|
||||||
return ((devfn == dn->devfn) && (busno == dn->busno)) ? dn : NULL;
|
if (pci && (devfn == pci->devfn) && (busno == pci->busno))
|
||||||
|
return dn;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -149,13 +169,10 @@ static void *is_devfn_node(struct device_node *dn, void *data)
|
||||||
struct device_node *fetch_dev_dn(struct pci_dev *dev)
|
struct device_node *fetch_dev_dn(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct device_node *orig_dn = dev->sysdata;
|
struct device_node *orig_dn = dev->sysdata;
|
||||||
struct pci_controller *phb = orig_dn->phb; /* assume same phb as orig_dn */
|
|
||||||
struct device_node *phb_dn;
|
|
||||||
struct device_node *dn;
|
struct device_node *dn;
|
||||||
unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
|
unsigned long searchval = (dev->bus->number << 8) | dev->devfn;
|
||||||
|
|
||||||
phb_dn = phb->arch_data;
|
dn = traverse_pci_devices(orig_dn, is_devfn_node, (void *)searchval);
|
||||||
dn = traverse_pci_devices(phb_dn, is_devfn_node, (void *)searchval);
|
|
||||||
if (dn)
|
if (dn)
|
||||||
dev->sysdata = dn;
|
dev->sysdata = dn;
|
||||||
return dn;
|
return dn;
|
||||||
|
@ -165,11 +182,13 @@ EXPORT_SYMBOL(fetch_dev_dn);
|
||||||
static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
|
static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
|
||||||
{
|
{
|
||||||
struct device_node *np = node;
|
struct device_node *np = node;
|
||||||
|
struct pci_dn *pci;
|
||||||
int err = NOTIFY_OK;
|
int err = NOTIFY_OK;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case PSERIES_RECONFIG_ADD:
|
case PSERIES_RECONFIG_ADD:
|
||||||
update_dn_pci_info(np, np->parent->phb);
|
pci = np->parent->data;
|
||||||
|
update_dn_pci_info(np, pci->phb);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = NOTIFY_DONE;
|
err = NOTIFY_DONE;
|
||||||
|
|
|
@ -66,7 +66,7 @@ static inline struct iommu_table *devnode_table(struct device *dev)
|
||||||
#endif /* CONFIG_PPC_ISERIES */
|
#endif /* CONFIG_PPC_ISERIES */
|
||||||
|
|
||||||
#ifdef CONFIG_PPC_MULTIPLATFORM
|
#ifdef CONFIG_PPC_MULTIPLATFORM
|
||||||
return PCI_GET_DN(pdev)->iommu_table;
|
return PCI_DN(PCI_GET_DN(pdev))->iommu_table;
|
||||||
#endif /* CONFIG_PPC_MULTIPLATFORM */
|
#endif /* CONFIG_PPC_MULTIPLATFORM */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -674,6 +674,7 @@ void __init pmac_check_ht_link(void)
|
||||||
#if 0 /* Disabled for now */
|
#if 0 /* Disabled for now */
|
||||||
u32 ufreq, freq, ucfg, cfg;
|
u32 ufreq, freq, ucfg, cfg;
|
||||||
struct device_node *pcix_node;
|
struct device_node *pcix_node;
|
||||||
|
struct pci_dn *pdn;
|
||||||
u8 px_bus, px_devfn;
|
u8 px_bus, px_devfn;
|
||||||
struct pci_controller *px_hose;
|
struct pci_controller *px_hose;
|
||||||
|
|
||||||
|
@ -687,9 +688,10 @@ void __init pmac_check_ht_link(void)
|
||||||
printk("No PCI-X bridge found\n");
|
printk("No PCI-X bridge found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
px_hose = pcix_node->phb;
|
pdn = pcix_node->data;
|
||||||
px_bus = pcix_node->busno;
|
px_hose = pdn->phb;
|
||||||
px_devfn = pcix_node->devfn;
|
px_bus = pdn->busno;
|
||||||
|
px_devfn = pdn->devfn;
|
||||||
|
|
||||||
early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
|
early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
|
||||||
early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
|
early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
|
||||||
|
|
|
@ -242,7 +242,7 @@ static int u3_ht_skip_device(struct pci_controller *hose,
|
||||||
else
|
else
|
||||||
busdn = hose->arch_data;
|
busdn = hose->arch_data;
|
||||||
for (dn = busdn->child; dn; dn = dn->sibling)
|
for (dn = busdn->child; dn; dn = dn->sibling)
|
||||||
if (dn->devfn == devfn)
|
if (dn->data && PCI_DN(dn)->devfn == devfn)
|
||||||
break;
|
break;
|
||||||
if (dn == NULL)
|
if (dn == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -746,9 +746,9 @@ void __init pmac_pci_init(void)
|
||||||
*/
|
*/
|
||||||
if (u3_agp) {
|
if (u3_agp) {
|
||||||
struct device_node *np = u3_agp->arch_data;
|
struct device_node *np = u3_agp->arch_data;
|
||||||
np->busno = 0xf0;
|
PCI_DN(np)->busno = 0xf0;
|
||||||
for (np = np->child; np; np = np->sibling)
|
for (np = np->child; np; np = np->sibling)
|
||||||
np->busno = 0xf0;
|
PCI_DN(np)->busno = 0xf0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmac_check_ht_link();
|
pmac_check_ht_link();
|
||||||
|
|
|
@ -1733,6 +1733,7 @@ static void of_node_release(struct kref *kref)
|
||||||
kfree(node->intrs);
|
kfree(node->intrs);
|
||||||
kfree(node->addrs);
|
kfree(node->addrs);
|
||||||
kfree(node->full_name);
|
kfree(node->full_name);
|
||||||
|
kfree(node->data);
|
||||||
kfree(node);
|
kfree(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ static int write_pci_config;
|
||||||
static int ibm_read_pci_config;
|
static int ibm_read_pci_config;
|
||||||
static int ibm_write_pci_config;
|
static int ibm_write_pci_config;
|
||||||
|
|
||||||
static int config_access_valid(struct device_node *dn, int where)
|
static int config_access_valid(struct pci_dn *dn, int where)
|
||||||
{
|
{
|
||||||
if (where < 256)
|
if (where < 256)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -78,15 +78,17 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va
|
||||||
int returnval = -1;
|
int returnval = -1;
|
||||||
unsigned long buid, addr;
|
unsigned long buid, addr;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct pci_dn *pdn;
|
||||||
|
|
||||||
if (!dn)
|
if (!dn || !dn->data)
|
||||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
if (!config_access_valid(dn, where))
|
pdn = dn->data;
|
||||||
|
if (!config_access_valid(pdn, where))
|
||||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
|
||||||
addr = ((where & 0xf00) << 20) | (dn->busno << 16) |
|
addr = ((where & 0xf00) << 20) | (pdn->busno << 16) |
|
||||||
(dn->devfn << 8) | (where & 0xff);
|
(pdn->devfn << 8) | (where & 0xff);
|
||||||
buid = dn->phb->buid;
|
buid = pdn->phb->buid;
|
||||||
if (buid) {
|
if (buid) {
|
||||||
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
|
ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval,
|
||||||
addr, buid >> 32, buid & 0xffffffff, size);
|
addr, buid >> 32, buid & 0xffffffff, size);
|
||||||
|
@ -98,8 +100,8 @@ static int rtas_read_config(struct device_node *dn, int where, int size, u32 *va
|
||||||
if (ret)
|
if (ret)
|
||||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
|
||||||
if (returnval == EEH_IO_ERROR_VALUE(size)
|
if (returnval == EEH_IO_ERROR_VALUE(size) &&
|
||||||
&& eeh_dn_check_failure (dn, NULL))
|
eeh_dn_check_failure (dn, NULL))
|
||||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
|
|
||||||
return PCIBIOS_SUCCESSFUL;
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
@ -118,24 +120,28 @@ static int rtas_pci_read_config(struct pci_bus *bus,
|
||||||
|
|
||||||
/* Search only direct children of the bus */
|
/* Search only direct children of the bus */
|
||||||
for (dn = busdn->child; dn; dn = dn->sibling)
|
for (dn = busdn->child; dn; dn = dn->sibling)
|
||||||
if (dn->devfn == devfn && of_device_available(dn))
|
if (dn->data && PCI_DN(dn)->devfn == devfn
|
||||||
|
&& of_device_available(dn))
|
||||||
return rtas_read_config(dn, where, size, val);
|
return rtas_read_config(dn, where, size, val);
|
||||||
|
|
||||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
|
int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
|
||||||
{
|
{
|
||||||
unsigned long buid, addr;
|
unsigned long buid, addr;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct pci_dn *pdn;
|
||||||
|
|
||||||
if (!dn)
|
if (!dn || !dn->data)
|
||||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
if (!config_access_valid(dn, where))
|
pdn = dn->data;
|
||||||
|
if (!config_access_valid(pdn, where))
|
||||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||||
|
|
||||||
addr = ((where & 0xf00) << 20) | (dn->busno << 16) |
|
addr = ((where & 0xf00) << 20) | (pdn->busno << 16) |
|
||||||
(dn->devfn << 8) | (where & 0xff);
|
(pdn->devfn << 8) | (where & 0xff);
|
||||||
buid = dn->phb->buid;
|
buid = pdn->phb->buid;
|
||||||
if (buid) {
|
if (buid) {
|
||||||
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
|
ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,7 +167,8 @@ static int rtas_pci_write_config(struct pci_bus *bus,
|
||||||
|
|
||||||
/* Search only direct children of the bus */
|
/* Search only direct children of the bus */
|
||||||
for (dn = busdn->child; dn; dn = dn->sibling)
|
for (dn = busdn->child; dn; dn = dn->sibling)
|
||||||
if (dn->devfn == devfn && of_device_available(dn))
|
if (dn->data && PCI_DN(dn)->devfn == devfn
|
||||||
|
&& of_device_available(dn))
|
||||||
return rtas_write_config(dn, where, size, val);
|
return rtas_write_config(dn, where, size, val);
|
||||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
|
@ -747,8 +747,8 @@ asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn)
|
||||||
if (bus == NULL || bus->sysdata == NULL)
|
if (bus == NULL || bus->sysdata == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
hose_node = (struct device_node *)bus->sysdata;
|
hose_node = bus->sysdata;
|
||||||
hose = hose_node->phb;
|
hose = PCI_DN(hose_node)->phb;
|
||||||
|
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case IOBASE_BRIDGE_NUMBER:
|
case IOBASE_BRIDGE_NUMBER:
|
||||||
|
|
|
@ -276,7 +276,7 @@ static void iommu_dev_setup_u3(struct pci_dev *dev)
|
||||||
dn = pci_device_to_OF_node(dev);
|
dn = pci_device_to_OF_node(dev);
|
||||||
|
|
||||||
if (dn)
|
if (dn)
|
||||||
dn->iommu_table = &iommu_table_u3;
|
PCI_DN(dn)->iommu_table = &iommu_table_u3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iommu_bus_setup_u3(struct pci_bus *bus)
|
static void iommu_bus_setup_u3(struct pci_bus *bus)
|
||||||
|
@ -291,7 +291,7 @@ static void iommu_bus_setup_u3(struct pci_bus *bus)
|
||||||
dn = pci_bus_to_OF_node(bus);
|
dn = pci_bus_to_OF_node(bus);
|
||||||
|
|
||||||
if (dn)
|
if (dn)
|
||||||
dn->iommu_table = &iommu_table_u3;
|
PCI_DN(dn)->iommu_table = &iommu_table_u3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iommu_dev_setup_null(struct pci_dev *dev) { }
|
static void iommu_dev_setup_null(struct pci_dev *dev) { }
|
||||||
|
|
|
@ -134,7 +134,8 @@ static void rpadlpar_claim_one_bus(struct pci_bus *b)
|
||||||
static int pci_add_secondary_bus(struct device_node *dn,
|
static int pci_add_secondary_bus(struct device_node *dn,
|
||||||
struct pci_dev *bridge_dev)
|
struct pci_dev *bridge_dev)
|
||||||
{
|
{
|
||||||
struct pci_controller *hose = dn->phb;
|
struct pci_dn *pdn = dn->data;
|
||||||
|
struct pci_controller *hose = pdn->phb;
|
||||||
struct pci_bus *child;
|
struct pci_bus *child;
|
||||||
u8 sec_busno;
|
u8 sec_busno;
|
||||||
|
|
||||||
|
@ -159,7 +160,7 @@ static int pci_add_secondary_bus(struct device_node *dn,
|
||||||
if (hose->last_busno < child->number)
|
if (hose->last_busno < child->number)
|
||||||
hose->last_busno = child->number;
|
hose->last_busno = child->number;
|
||||||
|
|
||||||
dn->bussubno = child->number;
|
pdn->bussubno = child->number;
|
||||||
|
|
||||||
/* ioremap() for child bus, which may or may not succeed */
|
/* ioremap() for child bus, which may or may not succeed */
|
||||||
remap_bus_range(child);
|
remap_bus_range(child);
|
||||||
|
@ -183,11 +184,12 @@ static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
|
||||||
|
|
||||||
static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
|
static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
|
||||||
{
|
{
|
||||||
struct pci_controller *hose = dn->phb;
|
struct pci_dn *pdn = dn->data;
|
||||||
|
struct pci_controller *hose = pdn->phb;
|
||||||
struct pci_dev *dev = NULL;
|
struct pci_dev *dev = NULL;
|
||||||
|
|
||||||
/* Scan phb bus for EADS device, adding new one to bus->devices */
|
/* Scan phb bus for EADS device, adding new one to bus->devices */
|
||||||
if (!pci_scan_single_device(hose->bus, dn->devfn)) {
|
if (!pci_scan_single_device(hose->bus, pdn->devfn)) {
|
||||||
printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__);
|
printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -269,6 +271,7 @@ static int dlpar_remove_root_bus(struct pci_controller *phb)
|
||||||
static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
|
static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
|
||||||
{
|
{
|
||||||
struct slot *slot;
|
struct slot *slot;
|
||||||
|
struct pci_dn *pdn;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (!rpaphp_find_pci_bus(dn))
|
if (!rpaphp_find_pci_bus(dn))
|
||||||
|
@ -285,12 +288,13 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(!dn->phb);
|
pdn = dn->data;
|
||||||
rc = dlpar_remove_root_bus(dn->phb);
|
BUG_ON(!pdn || !pdn->phb);
|
||||||
|
rc = dlpar_remove_root_bus(pdn->phb);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
dn->phb = NULL;
|
pdn->phb = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -299,7 +303,7 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn)
|
||||||
{
|
{
|
||||||
struct pci_controller *phb;
|
struct pci_controller *phb;
|
||||||
|
|
||||||
if (dn->phb) {
|
if (PCI_DN(dn)->phb) {
|
||||||
/* PHB already exists */
|
/* PHB already exists */
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,12 @@ static struct pci_bus *find_bus_among_children(struct pci_bus *bus,
|
||||||
|
|
||||||
struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
|
struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
|
||||||
{
|
{
|
||||||
if (!dn->phb || !dn->phb->bus)
|
struct pci_dn *pdn = dn->data;
|
||||||
|
|
||||||
|
if (!pdn || !pdn->phb || !pdn->phb->bus)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return find_bus_among_children(dn->phb->bus, dn);
|
return find_bus_among_children(pdn->phb->bus, dn);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus);
|
EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus);
|
||||||
|
|
||||||
|
@ -229,7 +231,7 @@ rpaphp_pci_config_slot(struct pci_bus *bus)
|
||||||
if (!dn || !dn->child)
|
if (!dn || !dn->child)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
slotno = PCI_SLOT(dn->child->devfn);
|
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
|
||||||
|
|
||||||
/* pci_scan_slot should find all children */
|
/* pci_scan_slot should find all children */
|
||||||
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
|
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
|
||||||
|
|
|
@ -363,7 +363,7 @@ static void __init offb_init_nodriver(struct device_node *dp)
|
||||||
address = (u_long) dp->addrs[i].address;
|
address = (u_long) dp->addrs[i].address;
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
address += dp->phb->pci_mem_offset;
|
address += ((struct pci_dn *)dp->data)->phb->pci_mem_offset;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* kludge for valkyrie */
|
/* kludge for valkyrie */
|
||||||
|
|
|
@ -48,19 +48,52 @@ struct pci_controller {
|
||||||
unsigned long dma_window_size;
|
unsigned long dma_window_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCI stuff, for nodes representing PCI devices, pointed to
|
||||||
|
* by device_node->data.
|
||||||
|
*/
|
||||||
|
struct pci_controller;
|
||||||
|
struct iommu_table;
|
||||||
|
|
||||||
|
struct pci_dn {
|
||||||
|
int busno; /* for pci devices */
|
||||||
|
int bussubno; /* for pci devices */
|
||||||
|
int devfn; /* for pci devices */
|
||||||
|
int eeh_mode; /* See eeh.h for possible EEH_MODEs */
|
||||||
|
int eeh_config_addr;
|
||||||
|
int eeh_capable; /* from firmware */
|
||||||
|
int eeh_check_count; /* # times driver ignored error */
|
||||||
|
int eeh_freeze_count; /* # times this device froze up. */
|
||||||
|
int eeh_is_bridge; /* device is pci-to-pci bridge */
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
struct device_node *fetch_dev_dn(struct pci_dev *dev);
|
struct device_node *fetch_dev_dn(struct pci_dev *dev);
|
||||||
|
|
||||||
/* Get a device_node from a pci_dev. This code must be fast except in the case
|
/* Get a device_node from a pci_dev. This code must be fast except
|
||||||
* where the sysdata is incorrect and needs to be fixed up (hopefully just once)
|
* 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.
|
||||||
*/
|
*/
|
||||||
static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
|
static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
struct device_node *dn = dev->sysdata;
|
struct device_node *dn = dev->sysdata;
|
||||||
|
struct pci_dn *pdn = dn->data;
|
||||||
|
|
||||||
if (dn->devfn == dev->devfn && dn->busno == dev->bus->number)
|
if (pdn && pdn->devfn == dev->devfn && pdn->busno == dev->bus->number)
|
||||||
return dn; /* fast path. sysdata is good */
|
return dn; /* fast path. sysdata is good */
|
||||||
else
|
return fetch_dev_dn(dev);
|
||||||
return fetch_dev_dn(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
|
static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
|
||||||
|
@ -83,7 +116,7 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
|
||||||
struct device_node *busdn = bus->sysdata;
|
struct device_node *busdn = bus->sysdata;
|
||||||
|
|
||||||
BUG_ON(busdn == NULL);
|
BUG_ON(busdn == NULL);
|
||||||
return busdn->phb;
|
return PCI_DN(busdn)->phb;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -116,14 +116,6 @@ struct property {
|
||||||
struct property *next;
|
struct property *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NOTE: the device_node contains PCI specific info for pci devices.
|
|
||||||
* This perhaps could be hung off the device_node with another struct,
|
|
||||||
* but for now it is directly in the node. The phb ptr is a good
|
|
||||||
* indication of a real PCI node. Other nodes leave these fields zeroed.
|
|
||||||
*/
|
|
||||||
struct pci_controller;
|
|
||||||
struct iommu_table;
|
|
||||||
|
|
||||||
struct device_node {
|
struct device_node {
|
||||||
char *name;
|
char *name;
|
||||||
char *type;
|
char *type;
|
||||||
|
@ -135,16 +127,6 @@ struct device_node {
|
||||||
struct interrupt_info *intrs;
|
struct interrupt_info *intrs;
|
||||||
char *full_name;
|
char *full_name;
|
||||||
|
|
||||||
/* PCI stuff probably doesn't belong here */
|
|
||||||
int busno; /* for pci devices */
|
|
||||||
int bussubno; /* for pci devices */
|
|
||||||
int devfn; /* for pci devices */
|
|
||||||
int eeh_mode; /* See eeh.h for possible EEH_MODEs */
|
|
||||||
int eeh_config_addr;
|
|
||||||
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 property *properties;
|
struct property *properties;
|
||||||
struct device_node *parent;
|
struct device_node *parent;
|
||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
|
@ -154,6 +136,7 @@ struct device_node {
|
||||||
struct proc_dir_entry *pde; /* this node's proc directory */
|
struct proc_dir_entry *pde; /* this node's proc directory */
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
unsigned long _flags;
|
unsigned long _flags;
|
||||||
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct device_node *of_chosen;
|
extern struct device_node *of_chosen;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче