Commit 601917b5 authored by Anton Blanchard's avatar Anton Blanchard

ppc64: Rework pci probe to be like alpha.

parent 748a82b2
......@@ -71,9 +71,6 @@ extern void openpic_init_IRQ(void);
extern void init_ras_IRQ(void);
extern void find_and_init_phbs(void);
extern void pSeries_pcibios_fixup(void);
extern void pSeries_pcibios_fixup_bus(struct pci_bus *bus);
extern void iSeries_pcibios_fixup(void);
extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
extern int pSeries_set_rtc_time(struct rtc_time *rtc_time);
......@@ -201,7 +198,6 @@ void __init pSeries_init_early(void)
hpte_init_pSeries();
tce_init_pSeries();
pSeries_pcibios_init_early();
#ifdef CONFIG_SMP
smp_init_pSeries();
......@@ -244,15 +240,6 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
}
ppc_md.init_ras_IRQ = init_ras_IRQ;
#ifndef CONFIG_PPC_ISERIES
ppc_md.pcibios_fixup = pSeries_pcibios_fixup;
ppc_md.pcibios_fixup_bus = pSeries_pcibios_fixup_bus;
#else
ppc_md.pcibios_fixup = NULL;
// ppc_md.pcibios_fixup = iSeries_pcibios_fixup;
#endif
ppc_md.init = chrp_init2;
ppc_md.restart = rtas_restart;
......
......@@ -84,8 +84,6 @@ struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev);
struct iSeries_Device_Node* get_Device_Node(struct pci_dev* PciDev);
unsigned long find_and_init_phbs(void);
void fixup_resources(struct pci_dev *dev);
void iSeries_pcibios_fixup(void);
struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ;
void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb);
......@@ -275,7 +273,7 @@ unsigned long __init find_and_init_phbs(void)
return 0;
}
/***********************************************************************
* ppc64_pcibios_init
* iSeries_pcibios_init
*
* Chance to initialize and structures or variable before PCI Bus walk.
*
......@@ -302,9 +300,9 @@ void iSeries_pcibios_init(void)
PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n");
}
/***********************************************************************
* iSeries_pcibios_fixup(void)
* pcibios_final_fixup(void)
***********************************************************************/
void __init iSeries_pcibios_fixup(void)
void __init pcibios_final_fixup(void)
{
struct pci_dev* PciDev;
struct iSeries_Device_Node* DeviceNode;
......@@ -328,8 +326,6 @@ void __init iSeries_pcibios_fixup(void)
iSeries_allocateDeviceBars(PciDev);
PPCDBGCALL(PPCDBG_BUSWALK,dumpPci_Dev(PciDev) );
iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) );
printk("%d. %s\n",DeviceCount,Buffer);
......@@ -345,11 +341,7 @@ void __init iSeries_pcibios_fixup(void)
mf_displaySrc(0xC9000200);
}
/***********************************************************************
* iSeries_pcibios_fixup_bus(int Bus)
*
***********************************************************************/
void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus)
void pcibios_fixup_bus(struct pci_bus* PciBus)
{
PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number);
......@@ -357,12 +349,12 @@ void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus)
/***********************************************************************
* fixup_resources(struct pci_dev *dev)
* pcibios_fixup_resources(struct pci_dev *dev)
*
***********************************************************************/
void fixup_resources(struct pci_dev *PciDev)
void pcibios_fixup_resources(struct pci_dev *PciDev)
{
PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev);
PPCDBG(PPCDBG_BUSWALK,"pcibios_fixup_resources PciDev %p\n",PciDev);
}
......@@ -910,18 +902,3 @@ void iSeries_Write_Long(u32 Data, void* IoAddress)
} while (CheckReturnCode("WWL",DevNode, Return.rc) != 0);
if(Pci_Trace_Flag == 1) PCIFR("WWL: IoAddress 0x%p = 0x%08X",IoAddress, Data);
}
/*
* This is called very early before the page table is setup.
* There are warnings here because of type mismatches.. Okay for now. AHT
*/
void
iSeries_pcibios_init_early(void)
{
//ppc_md.pcibios_read_config_byte = iSeries_Node_read_config_byte;
//ppc_md.pcibios_read_config_word = iSeries_Node_read_config_word;
//ppc_md.pcibios_read_config_dword = iSeries_Node_read_config_dword;
//ppc_md.pcibios_write_config_byte = iSeries_Node_write_config_byte;
//ppc_md.pcibios_write_config_word = iSeries_Node_write_config_word;
//ppc_md.pcibios_write_config_dword = iSeries_Node_write_config_dword;
}
......@@ -62,8 +62,6 @@ void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
pte_t * ptep, unsigned hpteflags, unsigned bolted );
extern void ppcdbg_initialize(void);
extern void iSeries_pcibios_init(void);
extern void iSeries_pcibios_fixup(void);
extern void iSeries_pcibios_fixup_bus(int);
static void iSeries_setup_dprofile(void);
/* Global Variables */
......@@ -317,9 +315,6 @@ iSeries_init_early(void)
ppc_md.get_irq = iSeries_get_irq;
ppc_md.init = NULL;
ppc_md.pcibios_fixup = iSeries_pcibios_fixup;
ppc_md.pcibios_fixup_bus = iSeries_pcibios_fixup_bus;
ppc_md.restart = iSeries_restart;
ppc_md.power_off = iSeries_power_off;
ppc_md.halt = iSeries_halt;
......
......@@ -320,7 +320,6 @@ void pSeriesLP_init_early(void)
#ifdef CONFIG_SMP
smp_init_pSeries();
#endif
pSeries_pcibios_init_early();
/* The keyboard is not useful in the LPAR environment.
* Leave all the interfaces NULL.
......
......@@ -2,6 +2,7 @@
* pSeries_pci.c
*
* Copyright (C) 2001 Dave Engebretsen, IBM Corporation
* Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
*
* pSeries specific routines for PCI.
*
......@@ -51,6 +52,8 @@ static int ibm_write_pci_config;
static int s7a_workaround;
extern unsigned long pci_probe_only;
static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
{
unsigned long returnval = ~0L;
......@@ -371,9 +374,6 @@ struct pci_controller *alloc_phb(struct device_node *dev,
phb->last_busno += (phb->global_number << 8);
}
/* Dump PHB information for Debug */
PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Controller(phb));
return phb;
}
......@@ -423,129 +423,96 @@ unsigned long __init find_and_init_phbs(void)
return 0;
}
void
fixup_resources(struct pci_dev *dev)
void pcibios_name_device(struct pci_dev *dev)
{
int i;
struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
struct device_node *dn;
/* Add IBM loc code (slot) as a prefix to the device names for service */
/*
* Add IBM loc code (slot) as a prefix to the device names for service
*/
dn = pci_device_to_OF_node(dev);
if (dn) {
char *loc_code = get_property(dn, "ibm,loc-code", 0);
if (loc_code) {
int loc_len = strlen(loc_code);
if (loc_len < sizeof(dev->dev.name)) {
memmove(dev->dev.name+loc_len+1, dev->dev.name, sizeof(dev->dev.name)-loc_len-1);
memmove(dev->dev.name+loc_len+1, dev->dev.name,
sizeof(dev->dev.name)-loc_len-1);
memcpy(dev->dev.name, loc_code, loc_len);
dev->dev.name[loc_len] = ' ';
dev->dev.name[sizeof(dev->dev.name)-1] = '\0';
}
}
}
}
PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n");
PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb);
PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset = 0x%016LX\n", phb->pci_io_offset);
PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%016LX\n", phb->pci_mem_offset);
PPCDBG(PPCDBG_PHBINIT, "\tdev->dev.name = %s\n", dev->dev.name);
PPCDBG(PPCDBG_PHBINIT, "\tdev->vendor:device = 0x%04X : 0x%04X\n", dev->vendor, dev->device);
if (phb == NULL)
return;
for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) {
PPCDBG(PPCDBG_PHBINIT, "\tdevice %x.%x[%d] (flags %x) [%lx..%lx]\n",
dev->bus->number, dev->devfn, i,
dev->resource[i].flags,
dev->resource[i].start,
dev->resource[i].end);
if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) {
continue;
}
if (dev->resource[i].start > dev->resource[i].end) {
/* Bogus resource. Just clear it out. */
dev->resource[i].start = dev->resource[i].end = 0;
continue;
}
void __init pcibios_fixup_device_resources(struct pci_dev *dev,
struct pci_bus *bus)
{
/* Update device resources. */
struct pci_controller *hose = PCI_GET_PHB_PTR(bus);
int i;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
if (dev->resource[i].flags & IORESOURCE_IO) {
unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
dev->resource[i].start += offset;
dev->resource[i].end += offset;
PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
dev->resource[i].start, dev->resource[i].end);
} else if (dev->resource[i].flags & IORESOURCE_MEM) {
if (dev->resource[i].start == 0) {
/* Bogus. Probably an unused bridge. */
dev->resource[i].end = 0;
} else {
dev->resource[i].start += phb->pci_mem_offset;
dev->resource[i].end += phb->pci_mem_offset;
}
PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
dev->resource[i].start, dev->resource[i].end);
} else {
continue;
else if (dev->resource[i].flags & IORESOURCE_MEM) {
dev->resource[i].start += hose->pci_mem_offset;
dev->resource[i].end += hose->pci_mem_offset;
}
/* zap the 2nd function of the winbond chip */
if (dev->resource[i].flags & IORESOURCE_IO
&& dev->bus->number == 0 && dev->devfn == 0x81)
dev->resource[i].flags &= ~IORESOURCE_IO;
}
}
void __init pSeries_pcibios_fixup_bus(struct pci_bus *bus)
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
struct pci_controller *hose = PCI_GET_PHB_PTR(bus);
struct list_head *ln;
/* XXX or bus->parent? */
struct pci_dev *dev = bus->self;
struct resource *res;
int i;
if (bus->parent == NULL) {
/* This is a host bridge - fill in its resources */
phb->bus = bus;
bus->resource[0] = res = &phb->io_resource;
if (!dev) {
/* Root bus. */
hose->bus = bus;
bus->resource[0] = res = &hose->io_resource;
if (!res->flags)
BUG(); /* No I/O resource for this PHB? */
if (request_resource(&ioport_resource, res))
printk(KERN_ERR "Failed to request IO"
"on hose %d\n", 0 /* FIXME */);
for (i = 0; i < 3; ++i) {
res = &phb->mem_resources[i];
if (!res->flags) {
if (i == 0)
res = &hose->mem_resources[i];
if (!res->flags && i == 0)
BUG(); /* No memory resource for this PHB? */
}
bus->resource[i+1] = res;
if (res->flags && request_resource(&iomem_resource, res))
printk(KERN_ERR "Failed to request MEM"
"on hose %d\n", 0 /* FIXME */);
}
} else {
} else if (pci_probe_only &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
/* This is a subordinate bridge */
pci_read_bridge_bases(bus);
for (i = 0; i < 4; ++i) {
if ((res = bus->resource[i]) == NULL)
continue;
if (!res->flags)
continue;
if (res == pci_find_parent_resource(bus->self, res)) {
/* Transparent resource -- don't try to "fix" it. */
continue;
}
if (res->flags & IORESOURCE_IO) {
unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
res->start += offset;
res->end += offset;
} else if (phb->pci_mem_offset
&& (res->flags & IORESOURCE_MEM)) {
if (res->start < phb->pci_mem_offset) {
res->start += phb->pci_mem_offset;
res->end += phb->pci_mem_offset;
}
}
pci_read_bridge_bases(bus);
pcibios_fixup_device_resources(dev, bus);
}
/* XXX Need to check why Alpha doesnt do this - Anton */
if (!pci_probe_only)
return;
for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
struct pci_dev *dev = pci_dev_b(ln);
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
pcibios_fixup_device_resources(dev, bus);
}
}
......@@ -562,19 +529,20 @@ static void check_s7a(void)
}
}
void __init
pSeries_pcibios_fixup(void)
extern void chrp_request_regions(void);
void __init pcibios_final_fixup(void)
{
struct pci_dev *dev;
PPCDBG(PPCDBG_PHBINIT, "pSeries_pcibios_fixup: start\n");
check_s7a();
pci_for_each_dev(dev) {
pci_for_each_dev(dev)
pci_read_irq_line(dev);
PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Dev(dev) );
}
chrp_request_regions();
pci_fix_bus_sysdata();
create_tce_tables();
}
/***********************************************************************
......@@ -596,13 +564,3 @@ pci_find_hose_for_OF_device(struct device_node *node)
}
return NULL;
}
/*
* This is called very early before the page table is setup.
*/
void
pSeries_pcibios_init_early(void)
{
ppc_md.pcibios_read_config = rtas_read_config;
ppc_md.pcibios_write_config = rtas_write_config;
}
......@@ -2,6 +2,9 @@
* Port for PPC64 David Engebretsen, IBM Corp.
* Contains common pci routines for ppc64 platform, pSeries and iSeries brands.
*
* Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
* Rework, based on alpha PCI code.
*
* 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
......@@ -30,31 +33,37 @@
#include <asm/ppcdebug.h>
#include <asm/naca.h>
#include <asm/pci_dma.h>
#include <asm/machdep.h>
#include "pci.h"
unsigned long pci_probe_only = 1;
unsigned long pci_assign_all_buses = 0;
unsigned int pcibios_assign_all_busses(void)
{
return pci_assign_all_buses;
}
/* pci_io_base -- the base address from which io bars are offsets.
* This is the lowest I/O base address (so bar values are always positive),
* and it *must* be the start of ISA space if an ISA bus exists because
* ISA drivers use hard coded offsets. If no ISA bus exists a dummy
* page is mapped and isa_io_limit prevents access to it.
*/
unsigned long isa_io_base = 0; /* NULL if no ISA bus */
unsigned long pci_io_base = 0;
unsigned long isa_io_base; /* NULL if no ISA bus */
unsigned long pci_io_base;
static void pcibios_fixup_resources(struct pci_dev* dev);
void pcibios_name_device(struct pci_dev* dev);
void pcibios_final_fixup(void);
static void fixup_broken_pcnet32(struct pci_dev* dev);
static void fixup_windbond_82c105(struct pci_dev* dev);
void fixup_resources(struct pci_dev* dev);
void iSeries_pcibios_init(void);
struct pci_controller* hose_head;
struct pci_controller** hose_tail = &hose_head;
struct pci_controller *hose_head;
struct pci_controller **hose_tail = &hose_head;
int global_phb_number = 0; /* Global phb counter */
struct pci_controller *phbtab[PCI_MAX_PHB];
int global_phb_number; /* Global phb counter */
/* Cached ISA bridge dev. */
struct pci_dev *ppc64_isabridge_dev = NULL;
......@@ -62,7 +71,7 @@ struct pci_dev *ppc64_isabridge_dev = NULL;
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105 },
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device },
{ 0 }
};
......@@ -81,14 +90,21 @@ static void fixup_windbond_82c105(struct pci_dev* dev)
* p610. We should probably be more careful in case
* someone tries to plug in a similar adapter.
*/
int i;
unsigned int reg;
printk("Using INTC for W82c105 IDE controller.\n");
pci_read_config_dword(dev, 0x40, &reg);
/* Enable LEGIRQ to use INTC instead of ISA interrupts */
pci_write_config_dword(dev, 0x40, reg | (1<<11));
}
for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) {
/* zap the 2nd function of the winbond chip */
if (dev->resource[i].flags & IORESOURCE_IO
&& dev->bus->number == 0 && dev->devfn == 0x81)
dev->resource[i].flags &= ~IORESOURCE_IO;
}
}
/* Given an mmio phys address, find a pci device that implements
* this address. This is of course expensive, but only used
......@@ -127,12 +143,30 @@ struct pci_dev *pci_find_dev_by_addr(unsigned long addr)
return NULL;
}
static void
pcibios_fixup_resources(struct pci_dev* dev)
void __devinit
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
{
fixup_resources(dev);
unsigned long offset = 0;
struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
if (!hose)
return;
if (res->flags & IORESOURCE_IO)
offset = (unsigned long)hose->io_base_virt - pci_io_base;
if (res->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
region->start = res->start - offset;
region->end = res->end - offset;
}
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pcibios_resource_to_bus);
#endif
/*
* We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the
......@@ -146,180 +180,38 @@ pcibios_fixup_resources(struct pci_dev* dev)
* but we want to try to avoid allocating at 0x2900-0x2bff
* which might have be mirrored at 0x0100-0x03ff..
*/
void
pcibios_align_resource(void *data, struct resource *res,
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
unsigned long start = res->start;
unsigned long alignto;
if (size > 0x100) {
printk(KERN_ERR "PCI: Can not align I/O Region %s %s because size %ld is too large.\n",
dev->slot_name, res->name, size);
}
if (start & 0x300) {
start = (start + 0x3ff) & ~0x3ff;
res->start = start;
}
}
}
if (res->flags & IORESOURCE_IO) {
unsigned long offset = (unsigned long)hose->io_base_virt -
pci_io_base;
/* Make sure we start at our min on all hoses */
if (start - offset < PCIBIOS_MIN_IO)
start = PCIBIOS_MIN_IO + offset;
/*
* Handle resources of PCI devices. If the world were perfect, we could
* just allocate all the resource regions and do nothing more. It isn't.
* On the other hand, we cannot just re-allocate all devices, as it would
* require us to know lots of host bridge internals. So we attempt to
* keep as much of the original configuration as possible, but tweak it
* when it's found to be wrong.
*
* Known BIOS problems we have to work around:
* - I/O or memory regions not configured
* - regions configured, but not enabled in the command register
* - bogus I/O addresses above 64K used
* - expansion ROMs left enabled (this may sound harmless, but given
* the fact the PCI specs explicitly allow address decoders to be
* shared between expansion ROMs and other resource regions, it's
* at least dangerous)
*
* Our solution:
* (1) Allocate resources for all buses behind PCI-to-PCI bridges.
* This gives us fixed barriers on where we can allocate.
* (2) Allocate resources for all enabled devices. If there is
* a collision, just mark the resource as unallocated. Also
* disable expansion ROMs during this step.
* (3) Try to allocate resources for disabled devices. If the
* resources were assigned correctly, everything goes well,
* if they weren't, they won't disturb allocation of other
* resources.
* (4) Assign new addresses to resources which were either
* not configured at all or misconfigured. If explicitly
* requested by the user, configure expansion ROM address
* as well.
/*
* Put everything into 0x00-0xff region modulo 0x400
*/
if (start & 0x300)
start = (start + 0x3ff) & ~0x3ff;
static void __init
pcibios_allocate_bus_resources(struct list_head *bus_list)
{
struct list_head *ln;
struct pci_bus *bus;
int i;
struct resource *res, *pr;
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
bus = pci_bus_b(ln);
for (i = 0; i < 4; ++i) {
if ((res = bus->resource[i]) == NULL || !res->flags)
continue;
if (bus->parent == NULL)
pr = (res->flags & IORESOURCE_IO)?
&ioport_resource: &iomem_resource;
else
pr = pci_find_parent_resource(bus->self, res);
if (pr == res)
continue; /* transparent bus or undefined */
if (pr && request_resource(pr, res) == 0)
continue;
printk(KERN_ERR "PCI: Cannot allocate resource region "
"%d of PCI bridge %x\n", i, bus->number);
printk(KERN_ERR "PCI: resource is %lx..%lx (%lx), parent %p\n",
res->start, res->end, res->flags, pr);
}
pcibios_allocate_bus_resources(&bus->children);
}
}
static void __init
pcibios_allocate_resources(int pass)
{
struct pci_dev *dev;
int idx, disabled;
u16 command;
struct resource *r, *pr;
pci_for_each_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (r->parent) /* Already allocated */
continue;
if (!r->start) /* Address not assigned at all */
continue;
if (r->flags & IORESOURCE_IO)
disabled = !(command & PCI_COMMAND_IO);
else
disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) {
PPCDBG(PPCDBG_PHBINIT,
"PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
PPCDBG(PPCDBG_PHBINIT,
"PCI: Cannot allocate resource region %d of device %s, pr = 0x%lx\n", idx, dev->slot_name, pr);
if(pr) {
PPCDBG(PPCDBG_PHBINIT,
"PCI: Cannot allocate resource 0x%lx\n", request_resource(pr,r));
}
/* We'll assign a new address later */
r->end -= r->start;
r->start = 0;
}
}
}
if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
/* Turn the ROM off, leave the resource region, but keep it unregistered. */
u32 reg;
r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
}
}
}
}
static void __init
pcibios_assign_resources(void)
{
struct pci_dev *dev;
int idx;
struct resource *r;
pci_for_each_dev(dev) {
int class = dev->class >> 8;
/* Don't touch classless devices and host bridges */
if (!class || class == PCI_CLASS_BRIDGE_HOST)
continue;
for (idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
} else if (res->flags & IORESOURCE_MEM) {
/* Make sure we start at our min on all hoses */
if (start - hose->pci_mem_offset < PCIBIOS_MIN_MEM)
start = PCIBIOS_MIN_MEM + hose->pci_mem_offset;
/*
* We shall assign a new address to this resource,
* either because the BIOS (sic) forgot to do so
* or because we have decided the old address was
* unusable for some reason.
*/
if (!r->start && r->end)
pci_assign_resource(dev, idx);
/* Align to multiple of size of minimum base. */
alignto = max(0x1000UL, align);
start = ALIGN(start, alignto);
}
#if 0 /* don't assign ROMs */
r = &dev->resource[PCI_ROM_RESOURCE];
r->end -= r->start;
r->start = 0;
if (r->end)
pci_assign_resource(dev, PCI_ROM_RESOURCE);
#endif
}
res->start = start;
}
/*
......@@ -359,19 +251,48 @@ pci_alloc_pci_controller(enum phb_types controller_type)
memcpy(hose->what,model,7);
hose->type = controller_type;
hose->global_number = global_phb_number;
phbtab[global_phb_number++] = hose;
*hose_tail = hose;
hose_tail = &hose->next;
return hose;
}
static int __init
pcibios_init(void)
static void __init pcibios_claim_one_bus(struct pci_bus *b)
{
struct list_head *ld;
struct pci_bus *child_bus;
for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
struct pci_dev *dev = pci_dev_b(ld);
int i;
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);
}
}
list_for_each_entry(child_bus, &b->children, node)
pcibios_claim_one_bus(child_bus);
}
static void __init pcibios_claim_of_setup(void)
{
struct list_head *lb;
for (lb = pci_root_buses.next; lb != &pci_root_buses; lb = lb->next) {
struct pci_bus *b = pci_bus_b(lb);
pcibios_claim_one_bus(b);
}
}
static int __init pcibios_init(void)
{
struct pci_controller *hose;
struct pci_bus *bus;
int next_busno;
#ifdef CONFIG_PPC_ISERIES
iSeries_pcibios_init();
......@@ -379,38 +300,26 @@ pcibios_init(void)
//ppc64_boot_msg(0x40, "PCI Probe");
printk("PCI: Probing PCI hardware\n");
PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n");
/* Scan all of the recorded PCI controllers. */
for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
for (hose = hose_head; hose; hose = hose->next) {
hose->last_busno = 0xff;
bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data);
bus = pci_scan_bus(hose->first_busno, hose->ops,
hose->arch_data);
hose->bus = bus;
hose->last_busno = bus->subordinate;
if (next_busno <= hose->last_busno)
next_busno = hose->last_busno+1;
}
/* Call machine dependent fixup */
if (ppc_md.pcibios_fixup) {
ppc_md.pcibios_fixup();
}
/* Allocate and assign resources */
pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
#ifndef CONFIG_PPC_ISERIES
void chrp_request_regions(void);
chrp_request_regions();
pci_fix_bus_sysdata();
if (pci_probe_only)
pcibios_claim_of_setup();
else
/* FIXME: `else' will be removed when
pci_assign_unassigned_resources() is able to work
correctly with [partially] allocated PCI tree. */
pci_assign_unassigned_resources();
create_tce_tables();
PPCDBG(PPCDBG_BUSWALK,"pSeries create_tce_tables()\n");
#endif
/* Call machine dependent fixup */
pcibios_final_fixup();
/* Cache the location of the ISA bridge (if we have one) */
ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
......@@ -418,7 +327,6 @@ pcibios_init(void)
printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name);
printk("PCI: Probing PCI hardware done\n");
PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n");
//ppc64_boot_msg(0x41, "PCI Done");
return 0;
......@@ -426,12 +334,6 @@ pcibios_init(void)
subsys_initcall(pcibios_init);
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
if (ppc_md.pcibios_fixup_bus)
ppc_md.pcibios_fixup_bus(bus);
}
char __init *pcibios_setup(char *str)
{
return str;
......@@ -439,35 +341,29 @@ char __init *pcibios_setup(char *str)
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
int idx;
struct resource *r;
PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n", __FUNCTION__,
dev->slot_name);
u16 cmd, oldcmd;
int i;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
oldcmd = cmd;
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = &dev->resource[i];
/* Only set up the requested stuff */
if (!(mask & (1<<idx)))
if (!(mask & (1<<i)))
continue;
r = &dev->resource[idx];
if (!r->start && r->end) {
printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
if (res->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
if (res->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n",
dev->slot_name, old_cmd, cmd);
PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n",
dev->slot_name);
if (cmd != oldcmd) {
printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
dev->slot_name, cmd);
/* Enable the appropriate bits in the PCI command register. */
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
......@@ -609,112 +505,3 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return ret;
}
/*****************************************************
* Dump Resource information
*****************************************************/
void dumpResources(struct resource* Resource)
{
if(Resource != NULL) {
int Flags = 0x00000F00 & Resource->flags;
if(Resource->start == 0 && Resource->end == 0) return;
else if(Resource->start == Resource->end ) return;
else {
if (Flags == IORESOURCE_IO) udbg_printf("IO.:");
else if(Flags == IORESOURCE_MEM) udbg_printf("MEM:");
else if(Flags == IORESOURCE_IRQ) udbg_printf("IRQ:");
else udbg_printf("0x%02X:",Resource->flags);
}
udbg_printf("0x%016LX / 0x%016LX (0x%08X)\n",
Resource->start, Resource->end, Resource->end - Resource->start);
}
}
int resourceSize(struct resource* Resource)
{
if(Resource->start == 0 && Resource->end == 0) return 0;
else if(Resource->start == Resource->end ) return 0;
else return (Resource->end-1)-Resource->start;
}
/*****************************************************
* Dump PHB information for Debug
*****************************************************/
void dumpPci_Controller(struct pci_controller* phb)
{
udbg_printf("\tpci_controller= 0x%016LX\n", phb);
if (phb != NULL) {
udbg_printf("\twhat & type = %s 0x%02X\n ",phb->what,phb->type);
udbg_printf("\tbus = ");
if (phb->bus != NULL) udbg_printf("0x%02X\n", phb->bus->number);
else udbg_printf("<NULL>\n");
udbg_printf("\tarch_data = 0x%016LX\n", phb->arch_data);
udbg_printf("\tfirst_busno = 0x%02X\n", phb->first_busno);
udbg_printf("\tlast_busno = 0x%02X\n", phb->last_busno);
udbg_printf("\tio_base_virt* = 0x%016LX\n", phb->io_base_virt);
udbg_printf("\tio_base_phys = 0x%016LX\n", phb->io_base_phys);
udbg_printf("\tpci_mem_offset= 0x%016LX\n", phb->pci_mem_offset);
udbg_printf("\tpci_io_offset = 0x%016LX\n", phb->pci_io_offset);
udbg_printf("\tResources\n");
dumpResources(&phb->io_resource);
if (phb->mem_resource_count > 0) dumpResources(&phb->mem_resources[0]);
if (phb->mem_resource_count > 1) dumpResources(&phb->mem_resources[1]);
if (phb->mem_resource_count > 2) dumpResources(&phb->mem_resources[2]);
udbg_printf("\tglobal_num = 0x%02X\n", phb->global_number);
udbg_printf("\tlocal_num = 0x%02X\n", phb->local_number);
}
}
/*****************************************************
* Dump PHB information for Debug
*****************************************************/
void dumpPci_Bus(struct pci_bus* Pci_Bus)
{
int i;
udbg_printf("\tpci_bus = 0x%016LX \n",Pci_Bus);
if (Pci_Bus != NULL) {
udbg_printf("\tnumber = 0x%02X \n",Pci_Bus->number);
udbg_printf("\tprimary = 0x%02X \n",Pci_Bus->primary);
udbg_printf("\tsecondary = 0x%02X \n",Pci_Bus->secondary);
udbg_printf("\tsubordinate = 0x%02X \n",Pci_Bus->subordinate);
for (i=0;i<4;++i) {
if(Pci_Bus->resource[i] == NULL) continue;
if(Pci_Bus->resource[i]->start == 0 && Pci_Bus->resource[i]->end == 0) break;
udbg_printf("\tResources[%d]",i);
dumpResources(Pci_Bus->resource[i]);
}
}
}
/*****************************************************
* Dump Device information for Debug
*****************************************************/
void dumpPci_Dev(struct pci_dev* Pci_Dev)
{
int i;
udbg_printf("\tpci_dev* = 0x%p\n",Pci_Dev);
if ( Pci_Dev == NULL ) return;
udbg_printf("\tname = %s \n",Pci_Dev->dev.name);
udbg_printf("\tbus* = 0x%p\n",Pci_Dev->bus);
udbg_printf("\tsysdata* = 0x%p\n",Pci_Dev->sysdata);
udbg_printf("\tDevice = 0x%4X%02X:%02X.%02X 0x%04X:%04X\n",
PCI_GET_PHB_NUMBER(Pci_Dev),
PCI_GET_BUS_NUMBER(Pci_Dev),
PCI_SLOT(Pci_Dev->devfn),
PCI_FUNC(Pci_Dev->devfn),
Pci_Dev->vendor,
Pci_Dev->device);
udbg_printf("\tHdr/Irq = 0x%02X/0x%02X \n",Pci_Dev->hdr_type,Pci_Dev->irq);
for (i=0;i<DEVICE_COUNT_RESOURCE;++i) {
if (Pci_Dev->resource[i].start == 0 && Pci_Dev->resource[i].end == 0) continue;
udbg_printf("\tResources[%d] ",i);
dumpResources(&Pci_Dev->resource[i]);
}
dumpResources(&Pci_Dev->resource[i]);
}
......@@ -19,18 +19,14 @@ extern struct pci_controller* pci_find_hose_for_OF_device(struct device_node* no
extern struct pci_controller* hose_head;
extern struct pci_controller** hose_tail;
/* PHB's are also in a table. */
#define PCI_MAX_PHB 64
extern int global_phb_number;
extern struct pci_controller *phbtab[];
/*******************************************************************
* Platform functions that are brand specific implementation.
*******************************************************************/
extern unsigned long find_and_init_phbs(void);
extern void ppc64_pcibios_init(void);
extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */
/*******************************************************************
......@@ -46,10 +42,6 @@ void pci_devs_phb_init(void);
void pci_fix_bus_sysdata(void);
struct device_node *fetch_dev_dn(struct pci_dev *dev);
void iSeries_pcibios_init_early(void);
void pSeries_pcibios_init_early(void);
void pSeries_pcibios_init(void);
/*******************************************************************
* Helper macros for extracting data from pci structures.
* PCI_GET_PHB_PTR(struct pci_dev*) returns the Phb pointer.
......@@ -60,12 +52,4 @@ void pSeries_pcibios_init(void);
#define PCI_GET_PHB_NUMBER(dev) (((dev)->bus->number&0x00FFFF00)>>8)
#define PCI_GET_BUS_NUMBER(dev) ((dev)->bus->number&0x0000FF)
/*******************************************************************
* Debugging Routines.
*******************************************************************/
extern void dumpResources(struct resource* Resource);
extern void dumpPci_Controller(struct pci_controller* phb);
extern void dumpPci_Bus(struct pci_bus* Pci_Bus);
extern void dumpPci_Dev(struct pci_dev* Pci_Dev);
#endif /* __PPC_KERNEL_PCI_H__ */
......@@ -90,22 +90,6 @@ struct machdep_calls {
unsigned char (*udbg_getc)(void);
int (*udbg_getc_poll)(void);
/* PCI interfaces */
int (*pcibios_read_config)(struct device_node *dn, int where, int size,
u32 *val);
int (*pcibios_write_config)(struct device_node *dn, int where,
int size, u32 val);
/* Called after scanning the bus, before allocating
* resources
*/
void (*pcibios_fixup)(void);
/* Called for each PCI bus in the system
* when it's probed
*/
void (*pcibios_fixup_bus)(struct pci_bus *);
#ifdef CONFIG_SMP
/* functions for dealing with other cpus */
struct smp_ops_t smp_ops;
......
......@@ -40,7 +40,7 @@ struct pci_controller {
void *io_base_virt;
unsigned long io_base_phys;
/* Some machines (PReP) have a non 1:1 mapping of
/* Some machines have a non 1:1 mapping of
* the PCI memory space in the CPU bus space
*/
unsigned long pci_mem_offset;
......
......@@ -16,11 +16,6 @@
#include <asm/io.h>
#include <asm/prom.h>
static inline int pcibios_assign_all_busses(void)
{
return 0;
}
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM 0x10000000
......@@ -36,7 +31,18 @@ static inline void pcibios_penalize_isa_irq(int irq)
struct pci_dev;
extern char* pci_card_location(struct pci_dev*);
#define HAVE_ARCH_PCI_MWI 1
static inline int pcibios_prep_mwi(struct pci_dev *dev)
{
/*
* pSeries firmware sets cacheline size and hardware treats
* MWI the same as memory write, so we dont change cacheline size
* or the MWI bit.
*/
return 1;
}
extern unsigned int pcibios_assign_all_busses(void);
extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle);
......@@ -52,8 +58,6 @@ extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nents, int direction);
extern void pSeries_pcibios_init_early(void);
static inline void pci_dma_sync_single(struct pci_dev *hwdev,
dma_addr_t dma_handle,
size_t size, int direction)
......@@ -122,9 +126,10 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
*/
#define PCI_DMA_BUS_IS_PHYS (0)
#endif /* __KERNEL__ */
extern void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res);
/* generic pci stuff */
#include <asm-generic/pci.h>
#endif /* __KERNEL__ */
#endif /* __PPC64_PCI_H */
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