* 2 of the License, or (at your option) any later version.
*/
-#undef DEBUG
-
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
#include <linux/bootmem.h>
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <asm/pci-bridge.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/ppcdebug.h>
+#include <asm/naca.h>
+#include <asm/iommu.h>
#include <asm/machdep.h>
-#include <asm/udbg.h>
#include "pci.h"
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
unsigned long pci_probe_only = 1;
unsigned long pci_assign_all_buses = 0;
-/*
- * legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch
- * devices we don't have access to.
- */
+/* legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch
+ devices we don't have access to. */
unsigned long io_page_mask;
EXPORT_SYMBOL(io_page_mask);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32);
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
+static void fixup_windbond_82c105(struct pci_dev* dev)
+{
+ /* Assume the windbond 82c105 is the IDE controller on a
+ * 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, ®);
+ /* 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;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105);
+
+void
+pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res)
{
unsigned long offset = 0;
struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
res->start = start;
}
-static spinlock_t hose_spinlock = SPIN_LOCK_UNLOCKED;
+static void phb_set_model(struct pci_controller *hose,
+ enum phb_types controller_type)
+{
+ char *model;
+
+ switch(controller_type) {
+#ifdef CONFIG_PPC_ISERIES
+ case phb_type_hypervisor:
+ model = "PHB HV";
+ break;
+#endif
+ case phb_type_python:
+ model = "PHB PY";
+ break;
+ case phb_type_speedwagon:
+ model = "PHB SW";
+ break;
+ case phb_type_winnipeg:
+ model = "PHB WP";
+ break;
+ case phb_type_apple:
+ model = "PHB APPLE";
+ break;
+ default:
+ model = "PHB UK";
+ break;
+ }
+ if(strlen(model) < 8)
+ strcpy(hose->what,model);
+ else
+ memcpy(hose->what,model,7);
+}
/*
- * pci_controller(phb) initialized common variables.
+ * Allocate pci_controller(phb) initialized common variables.
*/
-void __devinit pci_setup_pci_controller(struct pci_controller *hose)
+struct pci_controller * __init
+pci_alloc_pci_controller(enum phb_types controller_type)
{
+ struct pci_controller *hose;
+
+#ifdef CONFIG_PPC_ISERIES
+ hose = (struct pci_controller *)kmalloc(sizeof(struct pci_controller),
+ GFP_KERNEL);
+#else
+ hose = (struct pci_controller *)alloc_bootmem(sizeof(struct pci_controller));
+#endif
+ if (hose == NULL) {
+ printk(KERN_ERR "PCI: Allocate pci_controller failed.\n");
+ return NULL;
+ }
memset(hose, 0, sizeof(struct pci_controller));
- spin_lock(&hose_spinlock);
+ phb_set_model(hose, controller_type);
+
+ hose->is_dynamic = 0;
+ hose->type = controller_type;
hose->global_number = global_phb_number++;
+
list_add_tail(&hose->list_node, &hose_list);
- spin_unlock(&hose_spinlock);
+
+ return hose;
+}
+
+/*
+ * Dymnamically allocate pci_controller(phb), initialize common variables.
+ */
+struct pci_controller *
+pci_alloc_phb_dynamic(enum phb_types controller_type)
+{
+ struct pci_controller *hose;
+
+ hose = (struct pci_controller *)kmalloc(sizeof(struct pci_controller),
+ GFP_KERNEL);
+ if(hose == NULL) {
+ printk(KERN_ERR "PCI: Allocate pci_controller failed.\n");
+ return NULL;
+ }
+ memset(hose, 0, sizeof(struct pci_controller));
+
+ phb_set_model(hose, controller_type);
+
+ hose->is_dynamic = 1;
+ hose->type = controller_type;
+ hose->global_number = global_phb_number++;
+
+ list_add_tail(&hose->list_node, &hose_list);
+
+ return hose;
}
static void __init pcibios_claim_one_bus(struct pci_bus *b)
{
- struct pci_dev *dev;
+ struct list_head *ld;
struct pci_bus *child_bus;
- list_for_each_entry(dev, &b->devices, bus_list) {
+ 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++) {
#ifndef CONFIG_PPC_ISERIES
static void __init pcibios_claim_of_setup(void)
{
- struct pci_bus *b;
+ struct list_head *lb;
- list_for_each_entry(b, &pci_root_buses, node)
+ 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);
+ }
}
#endif
ppc_md.pcibios_fixup();
/* Cache the location of the ISA bridge (if we have one) */
- ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+ ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
if (ppc64_isabridge_dev != NULL)
printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
*
* Returns negative error code on failure, zero on success.
*/
-static __inline__ int __pci_mmap_make_offset(struct pci_dev *dev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
+static __inline__ int
+__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state)
{
struct pci_controller *hose = PCI_GET_PHB_PTR(dev);
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
* Set vm_flags of VMA, as appropriate for this architecture, for a pci device
* mapping.
*/
-static __inline__ void __pci_mmap_set_flags(struct pci_dev *dev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
+static __inline__ void
+__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state)
{
vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
}
* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
* device mapping.
*/
-static __inline__ void __pci_mmap_set_pgprot(struct pci_dev *dev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state,
- int write_combine)
+static __inline__ void
+__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
{
long prot = pgprot_val(vma->vm_page_prot);
__pci_mmap_set_flags(dev, vma, mmap_state);
__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
- ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ ret = remap_page_range(vma, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
return ret;
static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
unsigned long phb_io_base_phys,
- void __iomem * phb_io_base_virt)
+ void * phb_io_base_virt)
{
struct isa_range *range;
unsigned long pci_addr;
int rlen = 0;
range = (struct isa_range *) get_property(isa_node, "ranges", &rlen);
- if (range == NULL || (rlen < sizeof(struct isa_range))) {
- printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
- "mapping 64k\n");
- __ioremap_explicit(phb_io_base_phys, (unsigned long)phb_io_base_virt,
- 0x10000, _PAGE_NO_CACHE);
+ if (rlen < sizeof(struct isa_range)) {
+ printk(KERN_ERR "unexpected isa range size: %s\n",
+ __FUNCTION__);
return;
}
}
void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
- struct device_node *dev)
+ struct device_node *dev)
{
unsigned int *ranges;
unsigned long size;
cpu_phys_addr = cpu_phys_addr << 32 | ranges[4];
size = (unsigned long)ranges[na+3] << 32 | ranges[na+4];
- if (size == 0)
- continue;
- switch ((ranges[0] >> 24) & 0x3) {
+
+ switch (ranges[0] >> 24) {
case 1: /* I/O space */
hose->io_base_phys = cpu_phys_addr;
hose->pci_io_size = size;
res = &hose->io_resource;
res->flags = IORESOURCE_IO;
res->start = pci_addr;
- DBG("phb%d: IO 0x%lx -> 0x%lx\n", hose->global_number,
- res->start, res->start + size - 1);
break;
case 2: /* memory space */
memno = 0;
res = &hose->mem_resources[memno];
res->flags = IORESOURCE_MEM;
res->start = cpu_phys_addr;
- DBG("phb%d: MEM 0x%lx -> 0x%lx\n", hose->global_number,
- res->start, res->start + size - 1);
}
break;
}
struct device_node *isa_dn;
hose->io_base_virt = reserve_phb_iospace(size);
- DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
+ PPCDBG(PPCDBG_PHBINIT, "phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
hose->global_number, hose->io_base_phys,
(unsigned long) hose->io_base_virt);
hose->io_base_virt = __ioremap(hose->io_base_phys, size,
_PAGE_NO_CACHE);
- DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
+ PPCDBG(PPCDBG_PHBINIT, "phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
hose->global_number, hose->io_base_phys,
(unsigned long) hose->io_base_virt);
res->end += io_virt_offset;
}
-
-static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
- unsigned long *start_virt, unsigned long *size)
-{
- struct pci_controller *hose = PCI_GET_PHB_PTR(bus);
- struct pci_bus_region region;
- struct resource *res;
-
- if (bus->self) {
- res = bus->resource[0];
- pcibios_resource_to_bus(bus->self, ®ion, res);
- *start_phys = hose->io_base_phys + region.start;
- *start_virt = (unsigned long) hose->io_base_virt +
- region.start;
- if (region.end > region.start)
- *size = region.end - region.start + 1;
- else {
- printk("%s(): unexpected region 0x%lx->0x%lx\n",
- __FUNCTION__, region.start, region.end);
- return 1;
- }
-
- } else {
- /* Root Bus */
- res = &hose->io_resource;
- *start_phys = hose->io_base_phys;
- *start_virt = (unsigned long) hose->io_base_virt;
- if (res->end > res->start)
- *size = res->end - res->start + 1;
- else {
- printk("%s(): unexpected region 0x%lx->0x%lx\n",
- __FUNCTION__, res->start, res->end);
- return 1;
- }
- }
-
- return 0;
-}
-
-int unmap_bus_range(struct pci_bus *bus)
-{
- unsigned long start_phys;
- unsigned long start_virt;
- unsigned long size;
-
- if (!bus) {
- printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
- return 1;
- }
-
- if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
- return 1;
- if (iounmap_explicit((void __iomem *) start_virt, size))
- return 1;
-
- return 0;
-}
-EXPORT_SYMBOL(unmap_bus_range);
-
-int remap_bus_range(struct pci_bus *bus)
-{
- unsigned long start_phys;
- unsigned long start_virt;
- unsigned long size;
-
- if (!bus) {
- printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
- return 1;
- }
-
-
- if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
- return 1;
- printk("mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
- if (__ioremap_explicit(start_phys, start_virt, size, _PAGE_NO_CACHE))
- return 1;
-
- return 0;
-}
-EXPORT_SYMBOL(remap_bus_range);
-
-void phbs_remap_io(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- remap_bus_range(hose->bus);
-}
-
-
-/*
+/***********************************************************************
+ * pci_find_hose_for_OF_device
+ *
* This function finds the PHB that matching device_node in the
* OpenFirmware by scanning all the pci_controllers.
- */
+ *
+ ***********************************************************************/
struct pci_controller* pci_find_hose_for_OF_device(struct device_node *node)
{
while (node) {
else
busdn = bus->sysdata; /* must be a phb */
- if (busdn == NULL)
- return 0;
-
/*
* Check to see if there is any of the 8 functions are in the
* device tree. If they are then we need to scan all the
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
if (dev->resource[i].flags & IORESOURCE_IO) {
- unsigned long offset = (unsigned long)hose->io_base_virt
- - pci_io_base;
+ unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
unsigned long start, end, mask;
start = dev->resource[i].start += offset;
void __devinit pcibios_fixup_bus(struct pci_bus *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;
hose->bus = bus;
bus->resource[0] = res = &hose->io_resource;
+ if (!res->flags)
+ BUG(); /* No I/O resource for this PHB? */
- if (res->flags && request_resource(&ioport_resource, res))
+ if (request_resource(&ioport_resource, res))
printk(KERN_ERR "Failed to request IO on "
"PCI domain %d\n", pci_domain_nr(bus));
+
for (i = 0; i < 3; ++i) {
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 "
pcibios_fixup_device_resources(dev, bus);
}
+ /* XXX Need to check why Alpha doesnt do this - Anton */
if (!pci_probe_only)
return;
- list_for_each_entry(dev, &bus->devices, bus_list) {
+ 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);
}
}
EXPORT_SYMBOL(pcibios_fixup_bus);
-/*
- * Reads the interrupt pin to determine if interrupt is use by card.
+/******************************************************************
+ * pci_read_irq_line
+ *
+ * Reads the Interrupt Pin to determine if interrupt is use by card.
* If the interrupt is used, then gets the interrupt line from the
* openfirmware and sets it in the pci_dev and pci_config line.
- */
+ *
+ ******************************************************************/
int pci_read_irq_line(struct pci_dev *pci_dev)
{
u8 intpin;
struct device_node *node;
pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin);
- if (intpin == 0)
- return 0;
-
- node = pci_device_to_OF_node(pci_dev);
- if (node == NULL)
- return -1;
- if (node->n_intrs == 0)
- return -1;
+ if (intpin == 0) {
+ PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Interrupt used by device.\n",
+ pci_name(pci_dev));
+ return 0;
+ }
+ node = pci_device_to_OF_node(pci_dev);
+ if (node == NULL) {
+ PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s Device Node not found.\n",
+ pci_name(pci_dev));
+ return -1;
+ }
+ if (node->n_intrs == 0) {
+ PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s No Device OF interrupts defined.\n",
+ pci_name(pci_dev));
+ return -1;
+ }
pci_dev->irq = node->intrs[0].line;
pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq);
-
+
+ PPCDBG(PPCDBG_BUSWALK,"\tDevice: %s pci_dev->irq = 0x%02X\n",
+ pci_name(pci_dev), pci_dev->irq);
return 0;
}
EXPORT_SYMBOL(pci_read_irq_line);