Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 17151
b: refs/heads/master
c: 2bf6a8f
h: refs/heads/master
i:
  17149: 53c3745
  17147: b5784f7
  17143: ca67e6c
  17135: fb19100
  17119: 1fd69a7
  17087: 5a1a2ae
  17023: 4535d02
  16895: a85d3e6
v: v3
  • Loading branch information
Linas Vepstas authored and Paul Mackerras committed Jan 9, 2006
1 parent cb60318 commit d245559
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 2 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: facf07870b6103b8f9b6c872e3cb1032c5185d0b
refs/heads/master: 2bf6a8fa21570f37fd1789610da30f70a05ac5e3
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/platforms/pseries/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \
setup.o iommu.o ras.o rtasd.o
setup.o iommu.o ras.o rtasd.o pci_dlpar.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_XICS) += xics.o
Expand Down
174 changes: 174 additions & 0 deletions trunk/arch/powerpc/platforms/pseries/pci_dlpar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* PCI Dynamic LPAR, PCI Hot Plug and PCI EEH recovery code
* for RPA-compliant PPC64 platform.
* Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
* Copyright (C) 2005 International Business Machines
*
* Updates, 2005, John Rose <johnrose@austin.ibm.com>
* Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
*
* All rights reserved.
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/pci.h>
#include <asm/pci-bridge.h>

static struct pci_bus *
find_bus_among_children(struct pci_bus *bus,
struct device_node *dn)
{
struct pci_bus *child = NULL;
struct list_head *tmp;
struct device_node *busdn;

busdn = pci_bus_to_OF_node(bus);
if (busdn == dn)
return bus;

list_for_each(tmp, &bus->children) {
child = find_bus_among_children(pci_bus_b(tmp), dn);
if (child)
break;
};
return child;
}

struct pci_bus *
pcibios_find_pci_bus(struct device_node *dn)
{
struct pci_dn *pdn = dn->data;

if (!pdn || !pdn->phb || !pdn->phb->bus)
return NULL;

return find_bus_among_children(pdn->phb->bus, dn);
}

/**
* pcibios_remove_pci_devices - remove all devices under this bus
*
* Remove all of the PCI devices under this bus both from the
* linux pci device tree, and from the powerpc EEH address cache.
*/
void
pcibios_remove_pci_devices(struct pci_bus *bus)
{
struct pci_dev *dev, *tmp;

list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
eeh_remove_bus_device(dev);
pci_remove_bus_device(dev);
}
}

/* Must be called before pci_bus_add_devices */
static void
pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
{
struct pci_dev *dev;

list_for_each_entry(dev, &bus->devices, bus_list) {
/*
* Skip already-present devices (which are on the
* global device list.)
*/
if (list_empty(&dev->global_list)) {
int i;

/* Need to setup IOMMU tables */
ppc_md.iommu_dev_setup(dev);

if(fix_bus)
pcibios_fixup_device_resources(dev, bus);
pci_read_irq_line(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];

if (r->parent || !r->start || !r->flags)
continue;
pci_claim_resource(dev, i);
}
}
}
}

static int
pcibios_pci_config_bridge(struct pci_dev *dev)
{
u8 sec_busno;
struct pci_bus *child_bus;
struct pci_dev *child_dev;

/* Get busno of downstream bus */
pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);

/* Add to children of PCI bridge dev->bus */
child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
if (!child_bus) {
printk (KERN_ERR "%s: could not add second bus\n", __FUNCTION__);
return -EIO;
}
sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);

pci_scan_child_bus(child_bus);

list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
eeh_add_device_late(child_dev);
}

/* Fixup new pci devices without touching bus struct */
pcibios_fixup_new_pci_devices(child_bus, 0);

/* Make the discovered devices available */
pci_bus_add_devices(child_bus);
return 0;
}

/**
* pcibios_add_pci_devices - adds new pci devices to bus
*
* This routine will find and fixup new pci devices under
* the indicated bus. This routine presumes that there
* might already be some devices under this bridge, so
* it carefully tries to add only new devices. (And that
* is how this routine differs from other, similar pcibios
* routines.)
*/
void
pcibios_add_pci_devices(struct pci_bus * bus)
{
int slotno, num;
struct pci_dev *dev;
struct device_node *dn = pci_bus_to_OF_node(bus);

eeh_add_device_tree_early(dn);

/* pci_scan_slot should find all children */
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
if (num) {
pcibios_fixup_new_pci_devices(bus, 1);
pci_bus_add_devices(bus);
}

list_for_each_entry(dev, &bus->devices, bus_list) {
eeh_add_device_late (dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
pcibios_pci_config_bridge(dev);
}
}
9 changes: 9 additions & 0 deletions trunk/include/asm-powerpc/pci-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,18 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
return bus->sysdata; /* Must be root bus (PHB) */
}

/** Find the bus corresponding to the indicated device node */
struct pci_bus * pcibios_find_pci_bus(struct device_node *dn);

extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary);

/** 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);

extern int pcibios_remove_root_bus(struct pci_controller *phb);

extern void phbs_remap_io(void);
Expand Down

0 comments on commit d245559

Please sign in to comment.