From a2fb23af1c31ad6e0c281e56d385f803229d57fa Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 23:35:04 -0800 Subject: [SPARC64]: Probe PCI bus using OF device tree. Almost entirely taken from the 64-bit PowerPC PCI code. This allowed to eliminate a ton of cruft from the sparc64 PCI layer. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_impl.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'arch/sparc64/kernel/pci_impl.h') diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 971e2bea30b4..ea8a6bd146ae 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -17,20 +17,7 @@ extern struct pci_controller_info *pci_controller_root; extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ -extern void pci_fixup_host_bridge_self(struct pci_bus *pbus); -extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, - struct pci_pbm_info *pbm, - struct device_node *prom_node); -extern void pci_record_assignments(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_assign_unassigned(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_fixup_irq(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, - struct pci_bus *pbus); -extern void pci_setup_busmastering(struct pci_pbm_info *pbm, - struct pci_bus *pbus); +extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_register_legacy_regions(struct resource *io_res, struct resource *mem_res); -- cgit v1.2.3 From 1e8a8cc52daa95e702303ca3ce67955a4c051d7d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 Feb 2007 23:38:38 -0800 Subject: [SPARC64]: Internalize pci_memspace_mask. The only user was bus_dvma_to_mem() which is no longer used by any driver, so kill that, and the export of pci_memspace_mask. The only user now is the PCI mmap support code. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 2 ++ arch/sparc64/kernel/pci_impl.h | 1 + arch/sparc64/kernel/sparc64_ksyms.c | 1 - include/asm-sparc64/io.h | 8 -------- 4 files changed, 3 insertions(+), 9 deletions(-) (limited to 'arch/sparc64/kernel/pci_impl.h') diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 246b8009a2b4..ec0d12a48c2b 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -27,6 +27,8 @@ #include #include +#include "pci_impl.h" + unsigned long pci_memspace_mask = 0xffffffffUL; #ifndef CONFIG_PCI diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index ea8a6bd146ae..c4ba702e1fd9 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -13,6 +13,7 @@ #include extern struct pci_controller_info *pci_controller_root; +extern unsigned long pci_memspace_mask; extern int pci_num_controllers; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index beffc82a1e85..d00f51a5683f 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -212,7 +212,6 @@ EXPORT_SYMBOL(insl); #ifdef CONFIG_PCI EXPORT_SYMBOL(ebus_chain); EXPORT_SYMBOL(isa_chain); -EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index 30b912d8e8bc..ad595b679842 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -24,14 +24,6 @@ extern unsigned long kern_base, kern_size; #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define BIO_VMERGE_BOUNDARY 8192 -/* Different PCI controllers we support have their PCI MEM space - * mapped to an either 2GB (Psycho) or 4GB (Sabre) aligned area, - * so need to chop off the top 33 or 32 bits. - */ -extern unsigned long pci_memspace_mask; - -#define bus_dvma_to_mem(__vaddr) ((__vaddr) & pci_memspace_mask) - static __inline__ u8 _inb(unsigned long addr) { u8 ret; -- cgit v1.2.3 From 9fd8b64761d3fe7e4ef567161be57e4234af5c1c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Mar 2007 21:55:49 -0800 Subject: [SPARC64]: Consolidate PCI mem/io resource determination. It can be done for every PCI configuration using OF properties. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_common.c | 94 +++++++++++++++++++++++++++++++++++++--- arch/sparc64/kernel/pci_impl.h | 8 ++-- arch/sparc64/kernel/pci_psycho.c | 29 ++----------- arch/sparc64/kernel/pci_sabre.c | 38 ++-------------- arch/sparc64/kernel/pci_schizo.c | 81 ++-------------------------------- arch/sparc64/kernel/pci_sun4v.c | 71 +----------------------------- 6 files changed, 103 insertions(+), 218 deletions(-) (limited to 'arch/sparc64/kernel/pci_impl.h') diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 0d3c95df0d95..4945d700a769 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -1,7 +1,6 @@ -/* $Id: pci_common.c,v 1.29 2002/02/01 00:56:03 davem Exp $ - * pci_common.c: PCI controller common support. +/* pci_common.c: PCI controller common support. * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -16,8 +15,8 @@ #include "pci_impl.h" -void pci_register_legacy_regions(struct resource *io_res, - struct resource *mem_res) +static void pci_register_legacy_regions(struct resource *io_res, + struct resource *mem_res) { struct resource *p; @@ -53,6 +52,91 @@ void pci_register_legacy_regions(struct resource *io_res, request_resource(mem_res, p); } +static void pci_register_iommu_region(struct pci_pbm_info *pbm) +{ + u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL); + + if (vdma) { + struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL); + + if (!rp) { + prom_printf("Cannot allocate IOMMU resource.\n"); + prom_halt(); + } + rp->name = "IOMMU"; + rp->start = pbm->mem_space.start + (unsigned long) vdma[0]; + rp->end = rp->start + (unsigned long) vdma[1] - 1UL; + rp->flags = IORESOURCE_BUSY; + request_resource(&pbm->mem_space, rp); + } +} + +void pci_determine_mem_io_space(struct pci_pbm_info *pbm) +{ + int i, saw_mem, saw_io; + + saw_mem = saw_io = 0; + for (i = 0; i < pbm->num_pbm_ranges; i++) { + struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; + unsigned long a; + int type; + + type = (pr->child_phys_hi >> 24) & 0x3; + a = (((unsigned long)pr->parent_phys_hi << 32UL) | + ((unsigned long)pr->parent_phys_lo << 0UL)); + + switch (type) { + case 0: + /* PCI config space, 16MB */ + pbm->config_space = a; + break; + + case 1: + /* 16-bit IO space, 16MB */ + pbm->io_space.start = a; + pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.flags = IORESOURCE_IO; + saw_io = 1; + break; + + case 2: + /* 32-bit MEM space, 2GB */ + pbm->mem_space.start = a; + pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.flags = IORESOURCE_MEM; + saw_mem = 1; + break; + + case 3: + /* XXX 64-bit MEM handling XXX */ + + default: + break; + }; + } + + if (!saw_io || !saw_mem) { + prom_printf("%s: Fatal error, missing %s PBM range.\n", + pbm->name, + (!saw_io ? "IO" : "MEM")); + prom_halt(); + } + + printk("%s: PCI IO[%lx] MEM[%lx]\n", + pbm->name, + pbm->io_space.start, + pbm->mem_space.start); + + pbm->io_space.name = pbm->mem_space.name = pbm->name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); + + pci_register_legacy_regions(&pbm->io_space, + &pbm->mem_space); + pci_register_iommu_region(pbm); +} + /* Generic helper routines for PCI error reporting. */ void pci_scan_for_target_abort(struct pci_controller_info *p, struct pci_pbm_info *pbm, diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index c4ba702e1fd9..c6714548d823 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -1,7 +1,6 @@ -/* $Id: pci_impl.h,v 1.9 2001/06/13 06:34:30 davem Exp $ - * pci_impl.h: Helper definitions for PCI controller support. +/* pci_impl.h: Helper definitions for PCI controller support. * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) */ #ifndef PCI_IMPL_H @@ -19,8 +18,7 @@ extern int pci_num_controllers; /* PCI bus scanning and fixup support. */ extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); -extern void pci_register_legacy_regions(struct resource *io_res, - struct resource *mem_res); +extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); /* Error reporting support. */ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 12ea30d30b2f..c08681b7a44e 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1,7 +1,6 @@ -/* $Id: pci_psycho.c,v 1.33 2002/02/01 00:58:33 davem Exp $ - * pci_psycho.c: PSYCHO/U2P specific PCI controller support. +/* pci_psycho.c: PSYCHO/U2P specific PCI controller support. * - * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ @@ -1072,19 +1071,6 @@ static void psycho_controller_hwinit(struct pci_controller_info *p) psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp); } -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - char *name = pbm->name; - - pbm->io_space.name = pbm->mem_space.name = name; - - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - static void psycho_pbm_strbuf_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a) @@ -1155,13 +1141,9 @@ static void psycho_pbm_init(struct pci_controller_info *p, if (is_pbm_a) { pbm = &p->pbm_A; pbm->pci_first_slot = 1; - pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A; - pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A; } else { pbm = &p->pbm_B; pbm->pci_first_slot = 2; - pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B; - pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B; } pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; @@ -1174,17 +1156,12 @@ static void psycho_pbm_init(struct pci_controller_info *p, if (prop) pbm->chip_revision = *(int *) prop->value; - pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; - pbm->io_space.flags = IORESOURCE_IO; - pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; - pbm->mem_space.flags = IORESOURCE_MEM; + pci_determine_mem_io_space(pbm); pbm->parent = p; pbm->prom_node = dp; pbm->name = dp->full_name; - pbm_register_toplevel_resources(p, pbm); - printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", pbm->name, pbm->chip_version, pbm->chip_revision); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index f4e346092a53..2dad171b54e2 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1045,10 +1045,9 @@ static void sabre_iommu_init(struct pci_controller_info *p, sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); } -static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end) +static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp) { struct pci_pbm_info *pbm; - struct resource *rp; pbm = &p->pbm_A; pbm->name = dp->full_name; @@ -1061,38 +1060,7 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp pbm->pci_first_busno = p->pci_first_busno; pbm->pci_last_busno = p->pci_last_busno; - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE; - pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; - pbm->io_space.flags = IORESOURCE_IO; - - pbm->mem_space.start = (p->pbm_A.controller_regs + SABRE_MEMSPACE); - pbm->mem_space.end = (pbm->mem_space.start + ((1UL << 32UL) - 1UL)); - pbm->mem_space.flags = IORESOURCE_MEM; - - if (request_resource(&ioport_resource, &pbm->io_space) < 0) { - prom_printf("Cannot register Sabre's IO space.\n"); - prom_halt(); - } - if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { - prom_printf("Cannot register Sabre's MEM space.\n"); - prom_halt(); - } - - rp = kmalloc(sizeof(*rp), GFP_KERNEL); - if (!rp) { - prom_printf("Cannot allocate IOMMU resource.\n"); - prom_halt(); - } - rp->name = "IOMMU"; - rp->start = pbm->mem_space.start + (unsigned long) dma_start; - rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL; - rp->flags = IORESOURCE_BUSY; - request_resource(&pbm->mem_space, rp); - - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); + pci_determine_mem_io_space(pbm); } void sabre_init(struct device_node *dp, char *model_name) @@ -1212,5 +1180,5 @@ void sabre_init(struct device_node *dp, char *model_name) /* * Look for APB underneath. */ - sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]); + sabre_pbm_init(p, dp); } diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 332cfd9736b7..79ad2688317b 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1,7 +1,6 @@ -/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $ - * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. +/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. * - * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -1304,79 +1303,6 @@ static void schizo_resource_adjust(struct pci_dev *pdev, res->end += root->start; } -/* Use ranges property to determine where PCI MEM, I/O, and Config - * space are for this PCI bus module. - */ -static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm) -{ - int i, saw_cfg, saw_mem, saw_io; - - saw_cfg = saw_mem = saw_io = 0; - for (i = 0; i < pbm->num_pbm_ranges; i++) { - struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; - unsigned long a; - int type; - - type = (pr->child_phys_hi >> 24) & 0x3; - a = (((unsigned long)pr->parent_phys_hi << 32UL) | - ((unsigned long)pr->parent_phys_lo << 0UL)); - - switch (type) { - case 0: - /* PCI config space, 16MB */ - pbm->config_space = a; - saw_cfg = 1; - break; - - case 1: - /* 16-bit IO space, 16MB */ - pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); - pbm->io_space.flags = IORESOURCE_IO; - saw_io = 1; - break; - - case 2: - /* 32-bit MEM space, 2GB */ - pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); - pbm->mem_space.flags = IORESOURCE_MEM; - saw_mem = 1; - break; - - default: - break; - }; - } - - if (!saw_cfg || !saw_io || !saw_mem) { - prom_printf("%s: Fatal error, missing %s PBM range.\n", - pbm->name, - ((!saw_cfg ? - "CFG" : - (!saw_io ? - "IO" : "MEM")))); - prom_halt(); - } - - printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n", - pbm->name, - pbm->config_space, - pbm->io_space.start, - pbm->mem_space.start); -} - -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - #define SCHIZO_STRBUF_CONTROL (0x02800UL) #define SCHIZO_STRBUF_FLUSH (0x02808UL) #define SCHIZO_STRBUF_FSYNC (0x02810UL) @@ -1679,8 +1605,7 @@ static void schizo_pbm_init(struct pci_controller_info *p, pbm->num_pbm_ranges = (len / sizeof(struct linux_prom_pci_ranges)); - schizo_determine_mem_io_space(pbm); - pbm_register_toplevel_resources(p, pbm); + pci_determine_mem_io_space(pbm); pbm->pbm_intmap = of_get_property(dp, "interrupt-map", &len); if (pbm->pbm_intmap) { diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index eec7def379dc..e1af009617cf 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1,6 +1,6 @@ /* pci_sun4v.c: SUN4V specific PCI controller support. * - * Copyright (C) 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) */ #include @@ -751,72 +751,6 @@ static void pci_sun4v_resource_adjust(struct pci_dev *pdev, res->end += root->start; } -/* Use ranges property to determine where PCI MEM, I/O, and Config - * space are for this PCI bus module. - */ -static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm) -{ - int i, saw_mem, saw_io; - - saw_mem = saw_io = 0; - for (i = 0; i < pbm->num_pbm_ranges; i++) { - struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; - unsigned long a; - int type; - - type = (pr->child_phys_hi >> 24) & 0x3; - a = (((unsigned long)pr->parent_phys_hi << 32UL) | - ((unsigned long)pr->parent_phys_lo << 0UL)); - - switch (type) { - case 1: - /* 16-bit IO space, 16MB */ - pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); - pbm->io_space.flags = IORESOURCE_IO; - saw_io = 1; - break; - - case 2: - /* 32-bit MEM space, 2GB */ - pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); - pbm->mem_space.flags = IORESOURCE_MEM; - saw_mem = 1; - break; - - case 3: - /* XXX 64-bit MEM handling XXX */ - - default: - break; - }; - } - - if (!saw_io || !saw_mem) { - prom_printf("%s: Fatal error, missing %s PBM range.\n", - pbm->name, - (!saw_io ? "IO" : "MEM")); - prom_halt(); - } - - printk("%s: PCI IO[%lx] MEM[%lx]\n", - pbm->name, - pbm->io_space.start, - pbm->mem_space.start); -} - -static void pbm_register_toplevel_resources(struct pci_controller_info *p, - struct pci_pbm_info *pbm) -{ - pbm->io_space.name = pbm->mem_space.name = pbm->name; - - request_resource(&ioport_resource, &pbm->io_space); - request_resource(&iomem_resource, &pbm->mem_space); - pci_register_legacy_regions(&pbm->io_space, - &pbm->mem_space); -} - static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, struct pci_iommu *iommu) { @@ -1396,8 +1330,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node for (i = 0; i < pbm->num_pbm_ranges; i++) pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff; - pci_sun4v_determine_mem_io_space(pbm); - pbm_register_toplevel_resources(p, pbm); + pci_determine_mem_io_space(pbm); prop = of_find_property(dp, "interrupt-map", &len); pbm->pbm_intmap = prop->value; -- cgit v1.2.3 From 97b3cf050b467dda571943ceadff5452bed04549 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 11 Mar 2007 16:42:53 -0700 Subject: [SPARC64]: Add dummy host controller to root of all PCI domains. We fake up a dummy one in all cases because that is the simplest thing to do and it happens to be necessary for hypervisor systems. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 119 +++++++++++++++++++++++++++++---------- arch/sparc64/kernel/pci_impl.h | 9 +++ arch/sparc64/kernel/pci_psycho.c | 7 +++ arch/sparc64/kernel/pci_sabre.c | 12 ++++ arch/sparc64/kernel/pci_schizo.c | 6 ++ arch/sparc64/kernel/pci_sun4v.c | 6 ++ 6 files changed, 129 insertions(+), 30 deletions(-) (limited to 'arch/sparc64/kernel/pci_impl.h') diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 914a216da339..ec5f85b030ef 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -368,7 +368,8 @@ static void pci_parse_of_addrs(struct of_device *op, struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, struct device_node *node, - struct pci_bus *bus, int devfn) + struct pci_bus *bus, int devfn, + int host_controller) { struct dev_archdata *sd; struct pci_dev *dev; @@ -400,47 +401,62 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->devfn = devfn; dev->multifunction = 0; /* maybe a lie? */ - dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); - dev->device = of_getintprop_default(node, "device-id", 0xffff); - dev->subsystem_vendor = - of_getintprop_default(node, "subsystem-vendor-id", 0); - dev->subsystem_device = - of_getintprop_default(node, "subsystem-id", 0); - - dev->cfg_size = pci_cfg_space_size(dev); - + if (host_controller) { + dev->vendor = 0x108e; + dev->device = 0x8000; + dev->subsystem_vendor = 0x0000; + dev->subsystem_device = 0x0000; + dev->cfg_size = 256; + } else { + dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); + dev->device = of_getintprop_default(node, "device-id", 0xffff); + dev->subsystem_vendor = + of_getintprop_default(node, "subsystem-vendor-id", 0); + dev->subsystem_device = + of_getintprop_default(node, "subsystem-id", 0); + + dev->cfg_size = pci_cfg_space_size(dev); + } sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - /* dev->class = of_getintprop_default(node, "class-code", 0); */ - /* We can't actually use the firmware value, we have to read what - * is in the register right now. One reason is that in the case - * of IDE interfaces the firmware can sample the value before the - * the IDE interface is programmed into native mode. - */ - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); - dev->class = class >> 8; - + if (host_controller) { + dev->class = PCI_CLASS_BRIDGE_HOST << 8; + } else { + /* We can't actually use the firmware value, we have + * to read what is in the register right now. One + * reason is that in the case of IDE interfaces the + * firmware can sample the value before the the IDE + * interface is programmed into native mode. + */ + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); + dev->class = class >> 8; + } printk(" class: 0x%x\n", dev->class); dev->current_state = 4; /* unknown power state */ dev->error_state = pci_channel_io_normal; - if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { - /* a PCI-PCI bridge */ + if (host_controller) { dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; dev->rom_base_reg = PCI_ROM_ADDRESS1; - } else if (!strcmp(type, "cardbus")) { - dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + dev->irq = PCI_IRQ_NONE; } else { - dev->hdr_type = PCI_HEADER_TYPE_NORMAL; - dev->rom_base_reg = PCI_ROM_ADDRESS; + if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { + /* a PCI-PCI bridge */ + dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; + dev->rom_base_reg = PCI_ROM_ADDRESS1; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + } else { + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; - dev->irq = sd->op->irqs[0]; - if (dev->irq == 0xffffffff) - dev->irq = PCI_IRQ_NONE; + dev->irq = sd->op->irqs[0]; + if (dev->irq == 0xffffffff) + dev->irq = PCI_IRQ_NONE; + } } - pci_parse_of_addrs(sd->op, node, dev); printk(" adding to system ...\n"); @@ -632,7 +648,7 @@ static void __init pci_of_scan_bus(struct pci_pbm_info *pbm, devfn = (reg[0] >> 8) & 0xff; /* create a new pci_dev for this device */ - dev = of_create_pci_dev(pbm, child, bus, devfn); + dev = of_create_pci_dev(pbm, child, bus, devfn, 0); if (!dev) continue; printk("PCI: dev header type: %x\n", dev->hdr_type); @@ -677,10 +693,49 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) pci_bus_register_of_sysfs(child_bus); } +int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 *value) +{ + static u8 fake_pci_config[] = { + 0x8e, 0x10, /* Vendor: 0x108e (Sun) */ + 0x00, 0x80, /* Device: 0x8000 (PBM) */ + 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */ + 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */ + 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */ + 0x00, /* Cacheline: 0x00 */ + 0x40, /* Latency: 0x40 */ + 0x00, /* Header-Type: 0x00 normal */ + }; + + *value = 0; + if (where >= 0 && where < sizeof(fake_pci_config) && + (where + size) >= 0 && + (where + size) < sizeof(fake_pci_config) && + size <= sizeof(u32)) { + while (size--) { + *value <<= 8; + *value |= fake_pci_config[where + size]; + } + } + + return PCIBIOS_SUCCESSFUL; +} + +int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 value) +{ + return PCIBIOS_SUCCESSFUL; +} + struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) { struct pci_controller_info *p = pbm->parent; struct device_node *node = pbm->prom_node; + struct pci_dev *host_pdev; struct pci_bus *bus; printk("PCI: Scanning PBM %s\n", node->full_name); @@ -698,6 +753,10 @@ struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm) bus->resource[0] = &pbm->io_space; bus->resource[1] = &pbm->mem_space; + /* Create the dummy host bridge and link it in. */ + host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1); + bus->self = host_pdev; + pci_of_scan_bus(pbm, node, bus); pci_bus_add_devices(bus); pci_bus_register_of_sysfs(bus); diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index c6714548d823..1208583fcb83 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -20,6 +20,15 @@ extern int pci_num_controllers; extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); +extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 *value); +extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, + unsigned int devfn, + int where, int size, + u32 value); + /* Error reporting support. */ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 2e5d40a26dbd..154c03290d5d 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -118,6 +118,10 @@ static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); + switch (size) { case 1: *value = 0xff; @@ -171,6 +175,9 @@ static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 1bd7fc7c05e6..a2f129d29c20 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -319,6 +319,12 @@ static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { + struct pci_pbm_info *pbm = bus->sysdata; + + if (bus == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus, devfn, where, + size, value); + if (!bus->number && sabre_out_of_range(devfn)) { switch (size) { case 1: @@ -435,6 +441,12 @@ static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { + struct pci_pbm_info *pbm = bus->sysdata; + + if (bus == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus, devfn, where, + size, value); + if (bus->number) return __sabre_write_pci_cfg(bus, devfn, where, size, value); diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index f1f105af8d3c..322cdbf50eff 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -125,6 +125,9 @@ static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); switch (size) { case 1: *value = 0xff; @@ -178,6 +181,9 @@ static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index a8c12c1e8039..52bd4563492d 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -612,6 +612,9 @@ static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, + size, value); if (pci_sun4v_out_of_range(pbm, bus, device, func)) { ret = ~0UL; } else { @@ -650,6 +653,9 @@ static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; + if (bus_dev == pbm->pci_bus && devfn == 0x00) + return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, + size, value); if (pci_sun4v_out_of_range(pbm, bus, device, func)) { /* Do nothing. */ } else { -- cgit v1.2.3