diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 12:52:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 12:52:16 -0700 |
commit | b9fa38f75ea7e1f64bc29653ca9758303ce698e4 (patch) | |
tree | 6f6c0232ccbd9c27c923cf5cdcb0a3948e061aa9 /arch/powerpc/platforms | |
parent | 6e18933f2b6156d0a0ec9d5522ab6a6033cf7241 (diff) | |
parent | f360bf0015e5b3e82be61c68e0863b3f98852ee2 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (49 commits)
[POWERPC] Add zImage.iseries to arch/powerpc/boot/.gitignore
[POWERPC] bootwrapper: fix build error on virtex405-head.S
[POWERPC] 4xx: Fix 460GT support to not enable FPU
[POWERPC] 4xx: Add NOR FLASH entries to Canyonlands and Glacier dts
[POWERPC] Xilinx: of_serial support for Xilinx uart 16550.
[POWERPC] Xilinx: boot support for Xilinx uart 16550.
[POWERPC] celleb: Add support for PCI Express
[POWERPC] celleb: Move miscellaneous files for Beat
[POWERPC] celleb: Move a file for SPU on Beat
[POWERPC] celleb: Move files for Beat mmu and iommu
[POWERPC] celleb: Move files for Beat hvcall interfaces
[POWERPC] celleb: Move the SCC related code for celleb
[POWERPC] celleb: Move the files for celleb base support
[POWERPC] celleb: Consolidate io-workarounds code
[POWERPC] cell: Generalize io-workarounds code
[POWERPC] Add CONFIG_PPC_PSERIES_DEBUG to enable debugging for platforms/pseries
[POWERPC] Convert from DBG() to pr_debug() in platforms/pseries/
[POWERPC] Register udbg console early on pseries LPAR
[POWERPC] Mark udbg console as CON_ANYTIME, ie. callable early in boot
[POWERPC] Set udbg_console index to 0
...
Diffstat (limited to 'arch/powerpc/platforms')
48 files changed, 1206 insertions, 768 deletions
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index f38c50b4ce5..87454c52697 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -45,7 +45,6 @@ source "arch/powerpc/platforms/powermac/Kconfig" source "arch/powerpc/platforms/prep/Kconfig" source "arch/powerpc/platforms/maple/Kconfig" source "arch/powerpc/platforms/pasemi/Kconfig" -source "arch/powerpc/platforms/celleb/Kconfig" source "arch/powerpc/platforms/ps3/Kconfig" source "arch/powerpc/platforms/cell/Kconfig" source "arch/powerpc/platforms/8xx/Kconfig" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 5fc7fac10e9..f7efaa925a1 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -220,8 +220,8 @@ config SMP If you don't know what to do here, say N. config NR_CPUS - int "Maximum number of CPUs (2-128)" - range 2 128 + int "Maximum number of CPUs (2-1024)" + range 2 1024 depends on SMP default "32" if PPC64 default "4" diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index a984894466d..423a0234dc3 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -24,5 +24,4 @@ obj-$(CONFIG_PPC_MAPLE) += maple/ obj-$(CONFIG_PPC_PASEMI) += pasemi/ obj-$(CONFIG_PPC_CELL) += cell/ obj-$(CONFIG_PPC_PS3) += ps3/ -obj-$(CONFIG_PPC_CELLEB) += celleb/ obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 2f169991896..3959fcfe731 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -25,6 +25,19 @@ config PPC_IBM_CELL_BLADE select PPC_UDBG_16550 select UDBG_RTAS_CONSOLE +config PPC_CELLEB + bool "Toshiba's Cell Reference Set 'Celleb' Architecture" + depends on PPC_MULTIPLATFORM && PPC64 + select PPC_CELL + select PPC_CELL_NATIVE + select PPC_RTAS + select PPC_INDIRECT_IO + select PPC_OF_PLATFORM_PCI + select HAS_TXX9_SERIAL + select PPC_UDBG_BEAT + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_EHCI_BIG_ENDIAN_MMIO + menu "Cell Broadband Engine options" depends on PPC_CELL diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index c89964c6fb1..c2a7e4e5ddf 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \ cbe_regs.o spider-pic.o \ - pervasive.o pmu.o io-workarounds.o + pervasive.o pmu.o io-workarounds.o \ + spider-pci.o obj-$(CONFIG_CBE_RAS) += ras.o obj-$(CONFIG_CBE_THERM) += cbe_thermal.o @@ -26,3 +27,20 @@ obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ spufs/ obj-$(CONFIG_PCI_MSI) += axon_msi.o + + +# celleb stuff +ifeq ($(CONFIG_PPC_CELLEB),y) +obj-y += celleb_setup.o \ + celleb_pci.o celleb_scc_epci.o \ + celleb_scc_pciex.o \ + celleb_scc_uhc.o \ + io-workarounds.o spider-pci.o \ + beat.o beat_htab.o beat_hvCall.o \ + beat_interrupt.o beat_iommu.o + +obj-$(CONFIG_SMP) += beat_smp.o +obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o +obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o +obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o +endif diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index d95e71dee91..c39f5c225f2 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -123,7 +123,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) return NULL; } - for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) { + for (; dn; dn = of_get_next_parent(dn)) { ph = of_get_property(dn, "msi-translator", NULL); if (ph) break; @@ -169,7 +169,7 @@ static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type) static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) { - struct device_node *dn, *tmp; + struct device_node *dn; struct msi_desc *entry; int len; const u32 *prop; @@ -182,7 +182,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) entry = list_first_entry(&dev->msi_list, struct msi_desc, list); - for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) { + for (; dn; dn = of_get_next_parent(dn)) { if (entry->msi_attrib.is_64) { prop = of_get_property(dn, "msi-address-64", &len); if (prop) diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/cell/beat.c index b64b171f245..48c690ea65d 100644 --- a/arch/powerpc/platforms/celleb/beat.c +++ b/arch/powerpc/platforms/cell/beat.c @@ -33,7 +33,7 @@ #include "beat_wrapper.h" #include "beat.h" -#include "interrupt.h" +#include "beat_interrupt.h" static int beat_pm_poweroff_flag; diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/cell/beat.h index 32c8efcedc8..32c8efcedc8 100644 --- a/arch/powerpc/platforms/celleb/beat.h +++ b/arch/powerpc/platforms/cell/beat.h diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/cell/beat_htab.c index 81467ff055c..81467ff055c 100644 --- a/arch/powerpc/platforms/celleb/htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/cell/beat_hvCall.S index 74c81744894..74c81744894 100644 --- a/arch/powerpc/platforms/celleb/hvCall.S +++ b/arch/powerpc/platforms/cell/beat_hvCall.S diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 69562a86787..192a9350937 100644 --- a/arch/powerpc/platforms/celleb/interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -26,7 +26,7 @@ #include <asm/machdep.h> -#include "interrupt.h" +#include "beat_interrupt.h" #include "beat_wrapper.h" #define MAX_IRQS NR_IRQS diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h index b470fd0051f..b470fd0051f 100644 --- a/arch/powerpc/platforms/celleb/interrupt.h +++ b/arch/powerpc/platforms/cell/beat_interrupt.h diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/cell/beat_iommu.c index 93b0efddd65..93b0efddd65 100644 --- a/arch/powerpc/platforms/celleb/iommu.c +++ b/arch/powerpc/platforms/cell/beat_iommu.c diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/cell/beat_smp.c index a7631250aeb..26efc204c47 100644 --- a/arch/powerpc/platforms/celleb/smp.c +++ b/arch/powerpc/platforms/cell/beat_smp.c @@ -37,7 +37,7 @@ #include <asm/machdep.h> #include <asm/udbg.h> -#include "interrupt.h" +#include "beat_interrupt.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/cell/beat_spu_priv1.c index bcc17f7fe8a..bcc17f7fe8a 100644 --- a/arch/powerpc/platforms/celleb/spu_priv1.c +++ b/arch/powerpc/platforms/cell/beat_spu_priv1.c diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/cell/beat_syscall.h index 8580dc7e179..8580dc7e179 100644 --- a/arch/powerpc/platforms/celleb/beat_syscall.h +++ b/arch/powerpc/platforms/cell/beat_syscall.h diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/cell/beat_udbg.c index 6b418f6b617..6b418f6b617 100644 --- a/arch/powerpc/platforms/celleb/udbg_beat.c +++ b/arch/powerpc/platforms/cell/beat_udbg.c diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/cell/beat_wrapper.h index b47dfda48d0..b47dfda48d0 100644 --- a/arch/powerpc/platforms/celleb/beat_wrapper.h +++ b/arch/powerpc/platforms/cell/beat_wrapper.h diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/cell/celleb_pci.c index 51b390d34e4..f39a3b2a166 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/cell/celleb_pci.c @@ -37,12 +37,11 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/machdep.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#include "pci.h" -#include "interrupt.h" +#include "io-workarounds.h" +#include "celleb_pci.h" #define MAX_PCI_DEVICES 32 #define MAX_PCI_FUNCTIONS 8 @@ -190,7 +189,7 @@ static int celleb_fake_pci_read_config(struct pci_bus *bus, static int celleb_fake_pci_write_config(struct pci_bus *bus, - unsigned int devfn, int where, int size, u32 val) + unsigned int devfn, int where, int size, u32 val) { char *config; struct device_node *node; @@ -457,33 +456,42 @@ static int __init celleb_setup_fake_pci(struct device_node *dev, return 0; } -void __init fake_pci_workaround_init(struct pci_controller *phb) -{ - /** - * We will add fake pci bus to scc_pci_bus for the purpose to improve - * I/O Macro performance. But device-tree and device drivers - * are not ready to use address with a token. - */ - - /* celleb_pci_add_one(phb, NULL); */ -} +static struct celleb_phb_spec celleb_fake_pci_spec __initdata = { + .setup = celleb_setup_fake_pci, +}; static struct of_device_id celleb_phb_match[] __initdata = { { .name = "pci-pseudo", - .data = celleb_setup_fake_pci, + .data = &celleb_fake_pci_spec, }, { .name = "epci", - .data = celleb_setup_epci, + .data = &celleb_epci_spec, + }, { + .name = "pcie", + .data = &celleb_pciex_spec, }, { }, }; +static int __init celleb_io_workaround_init(struct pci_controller *phb, + struct celleb_phb_spec *phb_spec) +{ + if (phb_spec->ops) { + iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init, + phb_spec->iowa_data); + io_workaround_init(); + } + + return 0; +} + int __init celleb_setup_phb(struct pci_controller *phb) { struct device_node *dev = phb->dn; const struct of_device_id *match; - int (*setup_func)(struct device_node *, struct pci_controller *); + struct celleb_phb_spec *phb_spec; + int rc; match = of_match_node(celleb_phb_match, dev); if (!match) @@ -492,8 +500,12 @@ int __init celleb_setup_phb(struct pci_controller *phb) phb_set_bus_ranges(dev, phb); phb->buid = 1; - setup_func = match->data; - return (*setup_func)(dev, phb); + phb_spec = match->data; + rc = (*phb_spec->setup)(dev, phb); + if (rc) + return 1; + + return celleb_io_workaround_init(phb, phb_spec); } int celleb_pci_probe_mode(struct pci_bus *bus) diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/cell/celleb_pci.h index 5d5544ffedd..4cba1523ec5 100644 --- a/arch/powerpc/platforms/celleb/pci.h +++ b/arch/powerpc/platforms/cell/celleb_pci.h @@ -27,16 +27,19 @@ #include <asm/prom.h> #include <asm/ppc-pci.h> +#include "io-workarounds.h" + +struct celleb_phb_spec { + int (*setup)(struct device_node *, struct pci_controller *); + struct ppc_pci_io *ops; + int (*iowa_init)(struct iowa_bus *, void *); + void *iowa_data; +}; + extern int celleb_setup_phb(struct pci_controller *); extern int celleb_pci_probe_mode(struct pci_bus *); -extern int celleb_setup_epci(struct device_node *, struct pci_controller *); - -extern void *celleb_dummy_page_va; -extern int __init celleb_pci_workaround_init(void); -extern void __init celleb_pci_add_one(struct pci_controller *, - void (*)(struct pci_controller *)); -extern void fake_pci_workaround_init(struct pci_controller *); -extern void epci_workaround_init(struct pci_controller *); +extern struct celleb_phb_spec celleb_epci_spec; +extern struct celleb_phb_spec celleb_pciex_spec; #endif /* _CELLEB_PCI_H */ diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/cell/celleb_scc.h index 6be1542a6e6..b596a711c34 100644 --- a/arch/powerpc/platforms/celleb/scc.h +++ b/arch/powerpc/platforms/cell/celleb_scc.h @@ -125,6 +125,93 @@ /* bits for SCC_EPCI_CNTOPT */ #define SCC_EPCI_CNTOPT_O2PMB 0x00000002 +/* SCC PCIEXC SMMIO registers */ +#define PEXCADRS 0x000 +#define PEXCWDATA 0x004 +#define PEXCRDATA 0x008 +#define PEXDADRS 0x010 +#define PEXDCMND 0x014 +#define PEXDWDATA 0x018 +#define PEXDRDATA 0x01c +#define PEXREQID 0x020 +#define PEXTIDMAP 0x024 +#define PEXINTMASK 0x028 +#define PEXINTSTS 0x02c +#define PEXAERRMASK 0x030 +#define PEXAERRSTS 0x034 +#define PEXPRERRMASK 0x040 +#define PEXPRERRSTS 0x044 +#define PEXPRERRID01 0x048 +#define PEXPRERRID23 0x04c +#define PEXVDMASK 0x050 +#define PEXVDSTS 0x054 +#define PEXRCVCPLIDA 0x060 +#define PEXLENERRIDA 0x068 +#define PEXPHYPLLST 0x070 +#define PEXDMRDEN0 0x100 +#define PEXDMRDADR0 0x104 +#define PEXDMRDENX 0x110 +#define PEXDMRDADRX 0x114 +#define PEXECMODE 0xf00 +#define PEXMAEA(n) (0xf50 + (8 * n)) +#define PEXMAEC(n) (0xf54 + (8 * n)) +#define PEXCCRCTRL 0xff0 + +/* SCC PCIEXC bits and shifts for PEXCADRS */ +#define PEXCADRS_BYTE_EN_SHIFT 20 +#define PEXCADRS_CMD_SHIFT 16 +#define PEXCADRS_CMD_READ (0xa << PEXCADRS_CMD_SHIFT) +#define PEXCADRS_CMD_WRITE (0xb << PEXCADRS_CMD_SHIFT) + +/* SCC PCIEXC shifts for PEXDADRS */ +#define PEXDADRS_BUSNO_SHIFT 20 +#define PEXDADRS_DEVNO_SHIFT 15 +#define PEXDADRS_FUNCNO_SHIFT 12 + +/* SCC PCIEXC bits and shifts for PEXDCMND */ +#define PEXDCMND_BYTE_EN_SHIFT 4 +#define PEXDCMND_IO_READ 0x2 +#define PEXDCMND_IO_WRITE 0x3 +#define PEXDCMND_CONFIG_READ 0xa +#define PEXDCMND_CONFIG_WRITE 0xb + +/* SCC PCIEXC bits for PEXPHYPLLST */ +#define PEXPHYPLLST_PEXPHYAPLLST 0x00000001 + +/* SCC PCIEXC bits for PEXECMODE */ +#define PEXECMODE_ALL_THROUGH 0x00000000 +#define PEXECMODE_ALL_8BIT 0x00550155 +#define PEXECMODE_ALL_16BIT 0x00aa02aa + +/* SCC PCIEXC bits for PEXCCRCTRL */ +#define PEXCCRCTRL_PEXIPCOREEN 0x00040000 +#define PEXCCRCTRL_PEXIPCONTEN 0x00020000 +#define PEXCCRCTRL_PEXPHYPLLEN 0x00010000 +#define PEXCCRCTRL_PCIEXCAOCKEN 0x00000100 + +/* SCC PCIEXC port configuration registers */ +#define PEXTCERRCHK 0x21c +#define PEXTAMAPB0 0x220 +#define PEXTAMAPL0 0x224 +#define PEXTAMAPB(n) (PEXTAMAPB0 + 8 * (n)) +#define PEXTAMAPL(n) (PEXTAMAPL0 + 8 * (n)) +#define PEXCHVC0P 0x500 +#define PEXCHVC0NP 0x504 +#define PEXCHVC0C 0x508 +#define PEXCDVC0P 0x50c +#define PEXCDVC0NP 0x510 +#define PEXCDVC0C 0x514 +#define PEXCHVCXP 0x518 +#define PEXCHVCXNP 0x51c +#define PEXCHVCXC 0x520 +#define PEXCDVCXP 0x524 +#define PEXCDVCXNP 0x528 +#define PEXCDVCXC 0x52c +#define PEXCTTRG 0x530 +#define PEXTSCTRL 0x700 +#define PEXTSSTS 0x704 +#define PEXSKPCTRL 0x708 + /* UHC registers */ #define SCC_UHC_CKRCTRL 0xff0 #define SCC_UHC_ECMODE 0xf00 diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/cell/celleb_scc_epci.c index a999b393f6f..08c285b10e3 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/cell/celleb_scc_epci.c @@ -30,23 +30,17 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/prom.h> -#include <asm/machdep.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#include "scc.h" -#include "pci.h" -#include "interrupt.h" +#include "celleb_scc.h" +#include "celleb_pci.h" #define MAX_PCI_DEVICES 32 #define MAX_PCI_FUNCTIONS 8 #define iob() __asm__ __volatile__("eieio; sync":::"memory") -struct epci_private { - dma_addr_t dummy_page_da; -}; - static inline PCI_IO_ADDR celleb_epci_get_epci_base( struct pci_controller *hose) { @@ -71,42 +65,6 @@ static inline PCI_IO_ADDR celleb_epci_get_epci_cfg( return hose->cfg_data; } -static void scc_epci_dummy_read(struct pci_controller *hose) -{ - PCI_IO_ADDR epci_base; - u32 val; - - epci_base = celleb_epci_get_epci_base(hose); - - val = in_be32(epci_base + SCC_EPCI_WATRP); - iosync(); - - return; -} - -void __init epci_workaround_init(struct pci_controller *hose) -{ - PCI_IO_ADDR epci_base; - PCI_IO_ADDR reg; - struct epci_private *private = hose->private_data; - - BUG_ON(!private); - - private->dummy_page_da = dma_map_single(hose->parent, - celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE); - if (private->dummy_page_da == DMA_ERROR_CODE) { - printk(KERN_ERR "EPCI: dummy read disabled. " - "Map dummy page failed.\n"); - return; - } - - celleb_pci_add_one(hose, scc_epci_dummy_read); - epci_base = celleb_epci_get_epci_base(hose); - - reg = epci_base + SCC_EPCI_DUMYRADR; - out_be32(reg, private->dummy_page_da); -} - static inline void clear_and_disable_master_abort_interrupt( struct pci_controller *hose) { @@ -151,10 +109,8 @@ static int celleb_epci_check_abort(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static PCI_IO_ADDR celleb_epci_make_config_addr( - struct pci_bus *bus, - struct pci_controller *hose, - unsigned int devfn, int where) +static PCI_IO_ADDR celleb_epci_make_config_addr(struct pci_bus *bus, + struct pci_controller *hose, unsigned int devfn, int where) { PCI_IO_ADDR addr; @@ -425,8 +381,8 @@ static int __init celleb_epci_init(struct pci_controller *hose) return 0; } -int __init celleb_setup_epci(struct device_node *node, - struct pci_controller *hose) +static int __init celleb_setup_epci(struct device_node *node, + struct pci_controller *hose) { struct resource r; @@ -450,8 +406,7 @@ int __init celleb_setup_epci(struct device_node *node, if (!hose->cfg_addr) goto error; pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n", - r.start, (unsigned long)hose->cfg_addr, - (r.end - r.start + 1)); + r.start, (unsigned long)hose->cfg_addr, (r.end - r.start + 1)); if (of_address_to_resource(node, 2, &r)) goto error; @@ -459,14 +414,7 @@ int __init celleb_setup_epci(struct device_node *node, if (!hose->cfg_data) goto error; pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n", - r.start, (unsigned long)hose->cfg_data, - (r.end - r.start + 1)); - - hose->private_data = kzalloc(sizeof(struct epci_private), GFP_KERNEL); - if (hose->private_data == NULL) { - printk(KERN_ERR "EPCI: no memory for private data.\n"); - goto error; - } + r.start, (unsigned long)hose->cfg_data, (r.end - r.start + 1)); hose->ops = &celleb_epci_ops; celleb_epci_init(hose); @@ -474,8 +422,6 @@ int __init celleb_setup_epci(struct device_node *node, return 0; error: - kfree(hose->private_data); - if (hose->cfg_addr) iounmap(hose->cfg_addr); @@ -483,3 +429,10 @@ error: iounmap(hose->cfg_data); return 1; } + +struct celleb_phb_spec celleb_epci_spec __initdata = { + .setup = celleb_setup_epci, + .ops = &spiderpci_ops, + .iowa_init = &spiderpci_iowa_init, + .iowa_data = (void *)0, +}; diff --git a/arch/powerpc/platforms/cell/celleb_scc_pciex.c b/arch/powerpc/platforms/cell/celleb_scc_pciex.c new file mode 100644 index 00000000000..ab24d94baab --- /dev/null +++ b/arch/powerpc/platforms/cell/celleb_scc_pciex.c @@ -0,0 +1,547 @@ +/* + * Support for Celleb PCI-Express. + * + * (C) Copyright 2007-2008 TOSHIBA CORPORATION + * + * 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. 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/iommu.h> +#include <asm/byteorder.h> + +#include "celleb_scc.h" +#include "celleb_pci.h" + +#define PEX_IN(base, off) in_be32((void *)(base) + (off)) +#define PEX_OUT(base, off, data) out_be32((void *)(base) + (off), (data)) + +static void scc_pciex_io_flush(struct iowa_bus *bus) +{ + (void)PEX_IN(bus->phb->cfg_addr, PEXDMRDEN0); +} + +/* + * Memory space access to device on PCIEX + */ +#define PCIEX_MMIO_READ(name, ret) \ +static ret scc_pciex_##name(const PCI_IO_ADDR addr) \ +{ \ + ret val = __do_##name(addr); \ + scc_pciex_io_flush(iowa_mem_find_bus(addr)); \ + return val; \ +} + +#define PCIEX_MMIO_READ_STR(name) \ +static void scc_pciex_##name(const PCI_IO_ADDR addr, void *buf, \ + unsigned long count) \ +{ \ + __do_##name(addr, buf, count); \ + scc_pciex_io_flush(iowa_mem_find_bus(addr)); \ +} + +PCIEX_MMIO_READ(readb, u8) +PCIEX_MMIO_READ(readw, u16) +PCIEX_MMIO_READ(readl, u32) +PCIEX_MMIO_READ(readq, u64) +PCIEX_MMIO_READ(readw_be, u16) +PCIEX_MMIO_READ(readl_be, u32) +PCIEX_MMIO_READ(readq_be, u64) +PCIEX_MMIO_READ_STR(readsb) +PCIEX_MMIO_READ_STR(readsw) +PCIEX_MMIO_READ_STR(readsl) + +static void scc_pciex_memcpy_fromio(void *dest, const PCI_IO_ADDR src, + unsigned long n) +{ + __do_memcpy_fromio(dest, src, n); + scc_pciex_io_flush(iowa_mem_find_bus(src)); +} + +/* + * I/O port access to devices on PCIEX. + */ + +static inline unsigned long get_bus_address(struct pci_controller *phb, + unsigned long port) +{ + return port - ((unsigned long)(phb->io_base_virt) - _IO_BASE); +} + +static u32 scc_pciex_read_port(struct pci_controller *phb, + unsigned long port, int size) +{ + unsigned int byte_enable; + unsigned int cmd, shift; + unsigned long addr; + u32 data, ret; + + BUG_ON(((port & 0x3ul) + size) > 4); + + addr = get_bus_address(phb, port); + shift = addr & 0x3ul; + byte_enable = ((1 << size) - 1) << shift; + cmd = PEXDCMND_IO_READ | (byte_enable << PEXDCMND_BYTE_EN_SHIFT); + PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul)); + PEX_OUT(phb->cfg_addr, PEXDCMND, cmd); + data = PEX_IN(phb->cfg_addr, PEXDRDATA); + ret = (data >> (shift * 8)) & (0xFFFFFFFF >> ((4 - size) * 8)); + + pr_debug("PCIEX:PIO READ:port=0x%lx, addr=0x%lx, size=%d, be=%x," + " cmd=%x, data=%x, ret=%x\n", port, addr, size, byte_enable, + cmd, data, ret); + + return ret; +} + +static void scc_pciex_write_port(struct pci_controller *phb, + unsigned long port, int size, u32 val) +{ + unsigned int byte_enable; + unsigned int cmd, shift; + unsigned long addr; + u32 data; + + BUG_ON(((port & 0x3ul) + size) > 4); + + addr = get_bus_address(phb, port); + shift = addr & 0x3ul; + byte_enable = ((1 << size) - 1) << shift; + cmd = PEXDCMND_IO_WRITE | (byte_enable << PEXDCMND_BYTE_EN_SHIFT); + data = (val & (0xFFFFFFFF >> (4 - size) * 8)) << (shift * 8); + PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul)); + PEX_OUT(phb->cfg_addr, PEXDCMND, cmd); + PEX_OUT(phb->cfg_addr, PEXDWDATA, data); + + pr_debug("PCIEX:PIO WRITE:port=0x%lx, addr=%lx, size=%d, val=%x," + " be=%x, cmd=%x, data=%x\n", port, addr, size, val, + byte_enable, cmd, data); +} + +static u8 __scc_pciex_inb(struct pci_controller *phb, unsigned long port) +{ + return (u8)scc_pciex_read_port(phb, port, 1); +} + +static u16 __scc_pciex_inw(struct pci_controller *phb, unsigned long port) +{ + u32 data; + if ((port & 0x3ul) < 3) + data = scc_pciex_read_port(phb, port, 2); + else { + u32 d1 = scc_pciex_read_port(phb, port, 1); + u32 d2 = scc_pciex_read_port(phb, port + 1, 1); + data = d1 | (d2 << 8); + } + return (u16)data; +} + +static u32 __scc_pciex_inl(struct pci_controller *phb, unsigned long port) +{ + unsigned int mod = port & 0x3ul; + u32 data; + if (mod == 0) + data = scc_pciex_read_port(phb, port, 4); + else { + u32 d1 = scc_pciex_read_port(phb, port, 4 - mod); + u32 d2 = scc_pciex_read_port(phb, port + 1, mod); + data = d1 | (d2 << (mod * 8)); + } + return data; +} + +static void __scc_pciex_outb(struct pci_controller *phb, + u8 val, unsigned long port) +{ + scc_pciex_write_port(phb, port, 1, (u32)val); +} + +static void __scc_pciex_outw(struct pci_controller *phb, + u16 val, unsigned long port) +{ + if ((port & 0x3ul) < 3) + scc_pciex_write_port(phb, port, 2, (u32)val); + else { + u32 d1 = val & 0x000000FF; + u32 d2 = (val & 0x0000FF00) >> 8; + scc_pciex_write_port(phb, port, 1, d1); + scc_pciex_write_port(phb, port + 1, 1, d2); + } +} + +static void __scc_pciex_outl(struct pci_controller *phb, + u32 val, unsigned long port) +{ + unsigned int mod = port & 0x3ul; + if (mod == 0) + scc_pciex_write_port(phb, port, 4, val); + else { + u32 d1 = val & (0xFFFFFFFFul >> (mod * 8)); + u32 d2 = val >> ((4 - mod) * 8); + scc_pciex_write_port(phb, port, 4 - mod, d1); + scc_pciex_write_port(phb, port + 1, mod, d2); + } +} + +#define PCIEX_PIO_FUNC(size, name) \ +static u##size scc_pciex_in##name(unsigned long port) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(port); \ + u##size data = __scc_pciex_in##name(bus->phb, port); \ + scc_pciex_io_flush(bus); \ + return data; \ +} \ +static void scc_pciex_ins##name(unsigned long p, void *b, unsigned long c) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(p); \ + u##size *dst = b; \ + for (; c != 0; c--, dst++) \ + *dst = cpu_to_le##size(__scc_pciex_in##name(bus->phb, p)); \ + scc_pciex_io_flush(bus); \ +} \ +static void scc_pciex_out##name(u##size val, unsigned long port) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(port); \ + __scc_pciex_out##name(bus->phb, val, port); \ +} \ +static void scc_pciex_outs##name(unsigned long p, const void *b, \ + unsigned long c) \ +{ \ + struct iowa_bus *bus = iowa_pio_find_bus(p); \ + const u##size *src = b; \ + for (; c != 0; c--, src++) \ + __scc_pciex_out##name(bus->phb, le##size##_to_cpu(*src), p); \ +} +#define cpu_to_le8(x) (x) +#define le8_to_cpu(x) (x) +PCIEX_PIO_FUNC(8, b) +PCIEX_PIO_FUNC(16, w) +PCIEX_PIO_FUNC(32, l) + +static struct ppc_pci_io scc_pciex_ops = { + .readb = scc_pciex_readb, + .readw = scc_pciex_readw, + .readl = scc_pciex_readl, + .readq = scc_pciex_readq, + .readw_be = scc_pciex_readw_be, + .readl_be = scc_pciex_readl_be, + .readq_be = scc_pciex_readq_be, + .readsb = scc_pciex_readsb, + .readsw = scc_pciex_readsw, + .readsl = scc_pciex_readsl, + .memcpy_fromio = scc_pciex_memcpy_fromio, + .inb = scc_pciex_inb, + .inw = scc_pciex_inw, + .inl = scc_pciex_inl, + .outb = scc_pciex_outb, + .outw = scc_pciex_outw, + .outl = scc_pciex_outl, + .insb = scc_pciex_insb, + .insw = scc_pciex_insw, + .insl = scc_pciex_insl, + .outsb = scc_pciex_outsb, + .outsw = scc_pciex_outsw, + .outsl = scc_pciex_outsl, +}; + +static int __init scc_pciex_iowa_init(struct iowa_bus *bus, void *data) +{ + dma_addr_t dummy_page_da; + void *dummy_page_va; + + dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!dummy_page_va) { + pr_err("PCIEX:Alloc dummy_page_va failed\n"); + return -1; + } + + dummy_page_da = dma_map_single(bus->phb->parent, dummy_page_va, + PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dummy_page_da)) { + pr_err("PCIEX:Map dummy page failed.\n"); + kfree(dummy_page_va); + return -1; + } + + PEX_OUT(bus->phb->cfg_addr, PEXDMRDADR0, dummy_page_da); + + return 0; +} + +/* + * config space access + */ +#define MK_PEXDADRS(bus_no, dev_no, func_no, addr) \ + ((uint32_t)(((addr) & ~0x3UL) | \ + ((bus_no) << PEXDADRS_BUSNO_SHIFT) | \ + ((dev_no) << PEXDADRS_DEVNO_SHIFT) | \ + ((func_no) << PEXDADRS_FUNCNO_SHIFT))) + +#define MK_PEXDCMND_BYTE_EN(addr, size) \ + ((((0x1 << (size))-1) << ((addr) & 0x3)) << PEXDCMND_BYTE_EN_SHIFT) +#define MK_PEXDCMND(cmd, addr, size) ((cmd) | MK_PEXDCMND_BYTE_EN(addr, size)) + +static uint32_t config_read_pciex_dev(unsigned int *base, + uint64_t bus_no, uint64_t dev_no, uint64_t func_no, + uint64_t off, uint64_t size) +{ + uint32_t ret; + uint32_t addr, cmd; + + addr = MK_PEXDADRS(bus_no, dev_no, func_no, off); + cmd = MK_PEXDCMND(PEXDCMND_CONFIG_READ, off, size); + PEX_OUT(base, PEXDADRS, addr); + PEX_OUT(base, PEXDCMND, cmd); + ret = (PEX_IN(base, PEXDRDATA) + >> ((off & (4-size)) * 8)) & ((0x1 << (size * 8)) - 1); + return ret; +} + +static void config_write_pciex_dev(unsigned int *base, uint64_t bus_no, + uint64_t dev_no, uint64_t func_no, uint64_t off, uint64_t size, + uint32_t data) +{ + uint32_t addr, cmd; + + addr = MK_PEXDADRS(bus_no, dev_no, func_no, off); + cmd = MK_PEXDCMND(PEXDCMND_CONFIG_WRITE, off, size); + PEX_OUT(base, PEXDADRS, addr); + PEX_OUT(base, PEXDCMND, cmd); + PEX_OUT(base, PEXDWDATA, + (data & ((0x1 << (size * 8)) - 1)) << ((off & (4-size)) * 8)); +} + +#define MK_PEXCADRS_BYTE_EN(off, len) \ + ((((0x1 << (len)) - 1) << ((off) & 0x3)) << PEXCADRS_BYTE_EN_SHIFT) +#define MK_PEXCADRS(cmd, addr, size) \ + ((cmd) | MK_PEXCADRS_BYTE_EN(addr, size) | ((addr) & ~0x3)) +static uint32_t config_read_pciex_rc(unsigned int *base, + uint32_t where, uint32_t size) +{ + PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_READ, where, size)); + return (PEX_IN(base, PEXCRDATA) + >> ((where & (4 - size)) * 8)) & ((0x1 << (size * 8)) - 1); +} + +static void config_write_pciex_rc(unsigned int *base, uint32_t where, + uint32_t size, uint32_t val) +{ + uint32_t data; + + data = (val & ((0x1 << (size * 8)) - 1)) << ((where & (4 - size)) * 8); + PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_WRITE, where, size)); + PEX_OUT(base, PEXCWDATA, data); +} + +/* Interfaces */ +/* Note: Work-around + * On SCC PCIEXC, one device is seen on all 32 dev_no. + * As SCC PCIEXC can have only one device on the bus, we look only one dev_no. + * (dev_no = 1) + */ +static int scc_pciex_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int *val) +{ + struct device_node *dn; + struct pci_controller *phb; + + dn = bus->sysdata; + phb = pci_find_hose_for_OF_device(dn); + + if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + if (bus->number == 0 && PCI_SLOT(devfn) == 0) + *val = config_read_pciex_rc(phb->cfg_addr, where, size); + else + *val = config_read_pciex_dev(phb->cfg_addr, bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); + + return PCIBIOS_SUCCESSFUL; +} + +static int scc_pciex_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, unsigned int val) +{ + struct device_node *dn; + struct pci_controller *phb; + + dn = bus->sysdata; + phb = pci_find_hose_for_OF_device(dn); + + if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == 0 && PCI_SLOT(devfn) == 0) + config_write_pciex_rc(phb->cfg_addr, where, size, val); + else + config_write_pciex_dev(phb->cfg_addr, bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops scc_pciex_pci_ops = { + scc_pciex_read_config, + scc_pciex_write_config, +}; + +static void pciex_clear_intr_all(unsigned int *base) +{ + PEX_OUT(base, PEXAERRSTS, 0xffffffff); + PEX_OUT(base, PEXPRERRSTS, 0xffffffff); + PEX_OUT(base, PEXINTSTS, 0xffffffff); +} + +#if 0 +static void pciex_disable_intr_all(unsigned int *base) +{ + PEX_OUT(base, PEXINTMASK, 0x0); + PEX_OUT(base, PEXAERRMASK, 0x0); + PEX_OUT(base, PEXPRERRMASK, 0x0); + PEX_OUT(base, PEXVDMASK, 0x0); +} +#endif + +static void pciex_enable_intr_all(unsigned int *base) +{ + PEX_OUT(base, PEXINTMASK, 0x0000e7f1); + PEX_OUT(base, PEXAERRMASK, 0x03ff01ff); + PEX_OUT(base, PEXPRERRMASK, 0x0001010f); + PEX_OUT(base, PEXVDMASK, 0x00000001); +} + +static void pciex_check_status(unsigned int *base) +{ + uint32_t err = 0; + uint32_t intsts, aerr, prerr, rcvcp, lenerr; + uint32_t maea, maec; + + intsts = PEX_IN(base, PEXINTSTS); + aerr = PEX_IN(base, PEXAERRSTS); + prerr = PEX_IN(base, PEXPRERRSTS); + rcvcp = PEX_IN(base, PEXRCVCPLIDA); + lenerr = PEX_IN(base, PEXLENERRIDA); + + if (intsts || aerr || prerr || rcvcp || lenerr) + err = 1; + + pr_info("PCEXC interrupt!!\n"); + pr_info("PEXINTSTS :0x%08x\n", intsts); + pr_info("PEXAERRSTS :0x%08x\n", aerr); + pr_info("PEXPRERRSTS :0x%08x\n", prerr); + pr_info("PEXRCVCPLIDA :0x%08x\n", rcvcp); + pr_info("PEXLENERRIDA :0x%08x\n", lenerr); + + /* print detail of Protection Error */ + if (intsts & 0x00004000) { + uint32_t i, n; + for (i = 0; i < 4; i++) { + n = 1 << i; + if (prerr & n) { + maea = PEX_IN(base, PEXMAEA(i)); + maec = PEX_IN(base, PEXMAEC(i)); + pr_info("PEXMAEC%d :0x%08x\n", i, maec); + pr_info("PEXMAEA%d :0x%08x\n", i, maea); + } + } + } + + if (err) + pciex_clear_intr_all(base); +} + +static irqreturn_t pciex_handle_internal_irq(int irq, void *dev_id) +{ + struct pci_controller *phb = dev_id; + + pr_debug("PCIEX:pciex_handle_internal_irq(irq=%d)\n", irq); + + BUG_ON(phb->cfg_addr == NULL); + + pciex_check_status(phb->cfg_addr); + + return IRQ_HANDLED; +} + +static __init int celleb_setup_pciex(struct device_node *node, + struct pci_controller *phb) +{ + struct resource r; + struct of_irq oirq; + int virq; + + /* SMMIO registers; used inside this file */ + if (of_address_to_resource(node, 0, &r)) { + pr_err("PCIEXC:Failed to get config resource.\n"); + return 1; + } + phb->cfg_addr = ioremap(r.start, r.end - r.start + 1); + if (!phb->cfg_addr) { + pr_err("PCIEXC:Failed to remap SMMIO region.\n"); + return 1; + } + + /* Not use cfg_data, cmd and data regs are near address reg */ + phb->cfg_data = NULL; + + /* set pci_ops */ + phb->ops = &scc_pciex_pci_ops; + + /* internal interrupt handler */ + if (of_irq_map_one(node, 1, &oirq)) { + pr_err("PCIEXC:Failed to map irq\n"); + goto error; + } + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + if (request_irq(virq, pciex_handle_internal_irq, + IRQF_DISABLED, "pciex", (void *)phb)) { + pr_err("PCIEXC:Failed to request irq\n"); + goto error; + } + + /* enable all interrupts */ + pciex_clear_intr_all(phb->cfg_addr); + pciex_enable_intr_all(phb->cfg_addr); + /* MSI: TBD */ + + return 0; + +error: + phb->cfg_data = NULL; + if (phb->cfg_addr) + iounmap(phb->cfg_addr); + phb->cfg_addr = NULL; + return 1; +} + +struct celleb_phb_spec celleb_pciex_spec __initdata = { + .setup = celleb_setup_pciex, + .ops = &scc_pciex_ops, + .iowa_init = &scc_pciex_iowa_init, +}; diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/cell/celleb_scc_sio.c index 3a16c5b3c46..3a16c5b3c46 100644 --- a/arch/powerpc/platforms/celleb/scc_sio.c +++ b/arch/powerpc/platforms/cell/celleb_scc_sio.c diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/cell/celleb_scc_uhc.c index cb430799408..d63b720bfe3 100644 --- a/arch/powerpc/platforms/celleb/scc_uhc.c +++ b/arch/powerpc/platforms/cell/celleb_scc_uhc.c @@ -25,7 +25,7 @@ #include <asm/io.h> #include <asm/machdep.h> -#include "scc.h" +#include "celleb_scc.h" #define UHC_RESET_WAIT_MAX 10000 diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/cell/celleb_setup.c index f27ae1e3fb5..b11cb30decb 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/cell/celleb_setup.c @@ -56,13 +56,13 @@ #include <asm/rtas.h> #include <asm/cell-regs.h> -#include "interrupt.h" +#include "beat_interrupt.h" #include "beat_wrapper.h" #include "beat.h" -#include "pci.h" -#include "../cell/interrupt.h" -#include "../cell/pervasive.h" -#include "../cell/ras.h" +#include "celleb_pci.h" +#include "interrupt.h" +#include "pervasive.h" +#include "ras.h" static char celleb_machine_type[128] = "Celleb"; @@ -114,8 +114,6 @@ static int __init celleb_publish_devices(void) /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, celleb_bus_ids, NULL); - celleb_pci_workaround_init(); - return 0; } machine_device_initcall(celleb_beat, celleb_publish_devices); diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c index 979d4b67efb..3b84e8be314 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ b/arch/powerpc/platforms/cell/io-workarounds.c @@ -1,6 +1,9 @@ /* + * Support PCI IO workaround + * * Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org> * IBM, Corp. + * (C) Copyright 2007-2008 TOSHIBA CORPORATION * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -9,335 +12,174 @@ #undef DEBUG #include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/pci.h> + #include <asm/io.h> #include <asm/machdep.h> -#include <asm/pci-bridge.h> +#include <asm/pgtable.h> #include <asm/ppc-pci.h> +#include "io-workarounds.h" -#define SPIDER_PCI_REG_BASE 0xd000 -#define SPIDER_PCI_VCI_CNTL_STAT 0x0110 -#define SPIDER_PCI_DUMMY_READ 0x0810 -#define SPIDER_PCI_DUMMY_READ_BASE 0x0814 +#define IOWA_MAX_BUS 8 -/* Undefine that to re-enable bogus prefetch - * - * Without that workaround, the chip will do bogus prefetch past - * page boundary from system memory. This setting will disable that, - * though the documentation is unclear as to the consequences of doing - * so, either purely performances, or possible misbehaviour... It's not - * clear wether the chip can handle unaligned accesses at all without - * prefetching enabled. - * - * For now, things appear to be behaving properly with that prefetching - * disabled and IDE, possibly because IDE isn't doing any unaligned - * access. - */ -#define SPIDER_DISABLE_PREFETCH +static struct iowa_bus iowa_busses[IOWA_MAX_BUS]; +static unsigned int iowa_bus_count; -#define MAX_SPIDERS 3 +static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr) +{ + int i, j; + struct resource *res; + unsigned long vstart, vend; -static struct spider_pci_bus { - void __iomem *regs; - unsigned long mmio_start; - unsigned long mmio_end; - unsigned long pio_vstart; - unsigned long pio_vend; -} spider_pci_busses[MAX_SPIDERS]; -static int spider_pci_count; + for (i = 0; i < iowa_bus_count; i++) { + struct iowa_bus *bus = &iowa_busses[i]; + struct pci_controller *phb = bus->phb; -static struct spider_pci_bus *spider_pci_find(unsigned long vaddr, - unsigned long paddr) -{ - int i; - - for (i = 0; i < spider_pci_count; i++) { - struct spider_pci_bus *bus = &spider_pci_busses[i]; - if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end) - return bus; - if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend) - return bus; + if (vaddr) { + vstart = (unsigned long)phb->io_base_virt; + vend = vstart + phb->pci_io_size - 1; + if ((vaddr >= vstart) && (vaddr <= vend)) + return bus; + } + + if (paddr) + for (j = 0; j < 3; j++) { + res = &phb->mem_resources[j]; + if (paddr >= res->start && paddr <= res->end) + return bus; + } } + return NULL; } -static void spider_io_flush(const volatile void __iomem *addr) +struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr) { - struct spider_pci_bus *bus; + struct iowa_bus *bus; int token; - /* Get platform token (set by ioremap) from address */ token = PCI_GET_ADDR_TOKEN(addr); - /* Fast path if we have a non-0 token, it indicates which bus we - * are on. - * - * If the token is 0, that means either that the ioremap was done - * before we initialized this layer, or it's a PIO operation. We - * fallback to a low path in this case. Hopefully, internal devices - * which are ioremap'ed early should use in_XX/out_XX functions - * instead of the PCI ones and thus not suffer from the slowdown. - * - * Also note that currently, the workaround will not work for areas - * that are not mapped with PTEs (bolted in the hash table). This - * is the case for ioremaps done very early at boot (before - * mem_init_done) and includes the mapping of the ISA IO space. - * - * Fortunately, none of the affected devices is expected to do DMA - * and thus there should be no problem in practice. - * - * In order to improve performances, we only do the PTE search for - * addresses falling in the PHB IO space area. That means it will - * not work for hotplug'ed PHBs but those don't exist with Spider. - */ - if (token && token <= spider_pci_count) - bus = &spider_pci_busses[token - 1]; + if (token && token <= iowa_bus_count) + bus = &iowa_busses[token - 1]; else { unsigned long vaddr, paddr; pte_t *ptep; - /* Fixup physical address */ vaddr = (unsigned long)PCI_FIX_ADDR(addr); + if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) + return NULL; - /* Check if it's in allowed range for PIO */ - if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END) - return; - - /* Try to find a PTE. If not, clear the paddr, we'll do - * a vaddr only lookup (PIO only) - */ ptep = find_linux_pte(init_mm.pgd, vaddr); if (ptep == NULL) paddr = 0; else paddr = pte_pfn(*ptep) << PAGE_SHIFT; + bus = iowa_pci_find(vaddr, paddr); - bus = spider_pci_find(vaddr, paddr); if (bus == NULL) - return; + return NULL; } - /* Now do the workaround - */ - (void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ); + return bus; } -static u8 spider_readb(const volatile void __iomem *addr) +struct iowa_bus *iowa_pio_find_bus(unsigned long port) { - u8 val = __do_readb(addr); - spider_io_flush(addr); - return val; + unsigned long vaddr = (unsigned long)pci_io_base + port; + return iowa_pci_find(vaddr, 0); } -static u16 spider_readw(const volatile void __iomem *addr) -{ - u16 val = __do_readw(addr); - spider_io_flush(addr); - return val; -} -static u32 spider_readl(const volatile void __iomem *addr) -{ - u32 val = __do_readl(addr); - spider_io_flush(addr); - return val; +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \ +static ret iowa_##name at \ +{ \ + struct iowa_bus *bus; \ + bus = iowa_##space##_find_bus(aa); \ + if (bus && bus->ops && bus->ops->name) \ + return bus->ops->name al; \ + return __do_##name al; \ } -static u64 spider_readq(const volatile void __iomem *addr) -{ - u64 val = __do_readq(addr); - spider_io_flush(addr); - return val; +#define DEF_PCI_AC_NORET(name, at, al, space, aa) \ +static void iowa_##name at \ +{ \ + struct iowa_bus *bus; \ + bus = iowa_##space##_find_bus(aa); \ + if (bus && bus->ops && bus->ops->name) { \ + bus->ops->name al; \ + return; \ + } \ + __do_##name al; \ } -static u16 spider_readw_be(const volatile void __iomem *addr) -{ - u16 val = __do_readw_be(addr); - spider_io_flush(addr); - return val; -} +#include <asm/io-defs.h> -static u32 spider_readl_be(const volatile void __iomem *addr) -{ - u32 val = __do_readl_be(addr); - spider_io_flush(addr); - return val; -} +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET -static u64 spider_readq_be(const volatile void __iomem *addr) -{ - u64 val = __do_readq_be(addr); - spider_io_flush(addr); - return val; -} +static struct ppc_pci_io __initdata iowa_pci_io = { -static void spider_readsb(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - __do_readsb(addr, buf, count); - spider_io_flush(addr); -} +#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) .name = iowa_##name, +#define DEF_PCI_AC_NORET(name, at, al, space, aa) .name = iowa_##name, -static void spider_readsw(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - __do_readsw(addr, buf, count); - spider_io_flush(addr); -} +#include <asm/io-defs.h> -static void spider_readsl(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - __do_readsl(addr, buf, count); - spider_io_flush(addr); -} - -static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src, - unsigned long n) -{ - __do_memcpy_fromio(dest, src, n); - spider_io_flush(src); -} +#undef DEF_PCI_AC_RET +#undef DEF_PCI_AC_NORET +}; -static void __iomem * spider_ioremap(unsigned long addr, unsigned long size, - unsigned long flags) +static void __iomem *iowa_ioremap(unsigned long addr, unsigned long size, + unsigned long flags) { - struct spider_pci_bus *bus; + struct iowa_bus *bus; void __iomem *res = __ioremap(addr, size, flags); int busno; - pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n", - addr, size, flags, res); - - bus = spider_pci_find(0, addr); + bus = iowa_pci_find(0, addr); if (bus != NULL) { - busno = bus - spider_pci_busses; - pr_debug(" found bus %d, setting token\n", busno); + busno = bus - iowa_busses; PCI_SET_ADDR_TOKEN(res, busno + 1); } - pr_debug(" result=0x%p\n", res); - return res; } -static void __init spider_pci_setup_chip(struct spider_pci_bus *bus) -{ -#ifdef SPIDER_DISABLE_PREFETCH - u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT); - pr_debug(" PVCI_Control_Status was 0x%08x\n", val); - out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); -#endif - - /* Configure the dummy address for the workaround */ - out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000); -} - -static void __init spider_pci_add_one(struct pci_controller *phb) +/* Regist new bus to support workaround */ +void __init iowa_register_bus(struct pci_controller *phb, + struct ppc_pci_io *ops, + int (*initfunc)(struct iowa_bus *, void *), void *data) { - struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count]; + struct iowa_bus *bus; struct device_node *np = phb->dn; - struct resource rsrc; - void __iomem *regs; - if (spider_pci_count >= MAX_SPIDERS) { - printk(KERN_ERR "Too many spider bridges, workarounds" - " disabled for %s\n", np->full_name); + if (iowa_bus_count >= IOWA_MAX_BUS) { + pr_err("IOWA:Too many pci bridges, " + "workarounds disabled for %s\n", np->full_name); return; } - /* Get the registers for the beast */ - if (of_address_to_resource(np, 0, &rsrc)) { - printk(KERN_ERR "Failed to get registers for spider %s" - " workarounds disabled\n", np->full_name); - return; - } + bus = &iowa_busses[iowa_bus_count]; + bus->phb = phb; + bus->ops = ops; - /* Mask out some useless bits in there to get to the base of the - * spider chip - */ - rsrc.start &= ~0xfffffffful; - - /* Map them */ - regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000); - if (regs == NULL) { - printk(KERN_ERR "Failed to map registers for spider %s" - " workarounds disabled\n", np->full_name); - return; - } - - spider_pci_count++; - - /* We assume spiders only have one MMIO resource */ - bus->mmio_start = phb->mem_resources[0].start; - bus->mmio_end = phb->mem_resources[0].end + 1; - - bus->pio_vstart = (unsigned long)phb->io_base_virt; - bus->pio_vend = bus->pio_vstart + phb->pci_io_size; - - bus->regs = regs; - - printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name); + if (initfunc) + if ((*initfunc)(bus, data)) + return; - pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n", - bus->mmio_start, bus->mmio_end); - pr_debug(" pio (V) = 0x%016lx..0x%016lx\n", - bus->pio_vstart, bus->pio_vend); - pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n", - rsrc.start + SPIDER_PCI_REG_BASE, bus->regs); + iowa_bus_count++; - spider_pci_setup_chip(bus); + pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name); } -static struct ppc_pci_io __initdata spider_pci_io = { - .readb = spider_readb, - .readw = spider_readw, - .readl = spider_readl, - .readq = spider_readq, - .readw_be = spider_readw_be, - .readl_be = spider_readl_be, - .readq_be = spider_readq_be, - .readsb = spider_readsb, - .readsw = spider_readsw, - .readsl = spider_readsl, - .memcpy_fromio = spider_memcpy_fromio, -}; - -static int __init spider_pci_workaround_init(void) +/* enable IO workaround */ +void __init io_workaround_init(void) { - struct pci_controller *phb; - - /* Find spider bridges. We assume they have been all probed - * in setup_arch(). If that was to change, we would need to - * update this code to cope with dynamically added busses - */ - list_for_each_entry(phb, &hose_list, list_node) { - struct device_node *np = phb->dn; - const char *model = of_get_property(np, "model", NULL); - - /* If no model property or name isn't exactly "pci", skip */ - if (model == NULL || strcmp(np->name, "pci")) - continue; - /* If model is not "Spider", skip */ - if (strcmp(model, "Spider")) - continue; - spider_pci_add_one(phb); - } - - /* No Spider PCI found, exit */ - if (spider_pci_count == 0) - return 0; + static int io_workaround_inited; - /* Setup IO callbacks. We only setup MMIO reads. PIO reads will - * fallback to MMIO reads (though without a token, thus slower) - */ - ppc_pci_io = spider_pci_io; - - /* Setup ioremap callback */ - ppc_md.ioremap = spider_ioremap; - - return 0; + if (io_workaround_inited) + return; + ppc_pci_io = iowa_pci_io; + ppc_md.ioremap = iowa_ioremap; + io_workaround_inited = 1; } -machine_arch_initcall(cell, spider_pci_workaround_init); diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/platforms/cell/io-workarounds.h new file mode 100644 index 00000000000..79d8ed3d510 --- /dev/null +++ b/arch/powerpc/platforms/cell/io-workarounds.h @@ -0,0 +1,49 @@ +/* + * Support PCI IO workaround + * + * (C) Copyright 2007-2008 TOSHIBA CORPORATION + * + * 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. 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _IO_WORKAROUNDS_H +#define _IO_WORKAROUNDS_H + +#include <linux/io.h> +#include <asm/pci-bridge.h> + +/* Bus info */ +struct iowa_bus { + struct pci_controller *phb; + struct ppc_pci_io *ops; + void *private; +}; + +void __init io_workaround_init(void); +void __init iowa_register_bus(struct pci_controller *, struct ppc_pci_io *, + int (*)(struct iowa_bus *, void *), void *); +struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR); +struct iowa_bus *iowa_pio_find_bus(unsigned long); + +extern struct ppc_pci_io spiderpci_ops; +extern int spiderpci_iowa_init(struct iowa_bus *, void *); + +#define SPIDER_PCI_REG_BASE 0xd000 +#define SPIDER_PCI_REG_SIZE 0x1000 +#define SPIDER_PCI_VCI_CNTL_STAT 0x0110 +#define SPIDER_PCI_DUMMY_READ 0x0810 +#define SPIDER_PCI_DUMMY_READ_BASE 0x0814 + +#endif /* _IO_WORKAROUNDS_H */ diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 5c531e8f9f6..ab721b50fbb 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -57,6 +57,7 @@ #include "interrupt.h" #include "pervasive.h" #include "ras.h" +#include "io-workarounds.h" #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -117,13 +118,50 @@ static void cell_fixup_pcie_rootcomplex(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex); +static int __devinit cell_setup_phb(struct pci_controller *phb) +{ + const char *model; + struct device_node *np; + + int rc = rtas_setup_phb(phb); + if (rc) + return rc; + + np = phb->dn; + model = of_get_property(np, "model", NULL); + if (model == NULL || strcmp(np->name, "pci")) + return 0; + + /* Setup workarounds for spider */ + if (strcmp(model, "Spider")) + return 0; + + iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init, + (void *)SPIDER_PCI_REG_BASE); + io_workaround_init(); + + return 0; +} + static int __init cell_publish_devices(void) { + struct device_node *root = of_find_node_by_path("/"); + struct device_node *np; int node; /* Publish OF platform devices for southbridge IOs */ of_platform_bus_probe(NULL, NULL, NULL); + /* On spider based blades, we need to manually create the OF + * platform devices for the PCI host bridges + */ + for_each_child_of_node(root, np) { + if (np->type == NULL || (strcmp(np->type, "pci") != 0 && + strcmp(np->type, "pciex") != 0)) + continue; + of_platform_device_create(np, NULL, NULL); + } + /* There is no device for the MIC memory controller, thus we create * a platform device for it to attach the EDAC driver to. */ @@ -132,6 +170,7 @@ static int __init cell_publish_devices(void) continue; platform_device_register_simple("cbe-mic", node, NULL, 0); } + return 0; } machine_subsys_initcall(cell, cell_publish_devices); @@ -213,7 +252,7 @@ static void __init cell_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); - find_and_init_phbs(); + cbe_pervasive_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -249,7 +288,7 @@ define_machine(cell) { .calibrate_decr = generic_calibrate_decr, .progress = cell_progress, .init_IRQ = cell_init_irq, - .pci_setup_phb = rtas_setup_phb, + .pci_setup_phb = cell_setup_phb, #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c new file mode 100644 index 00000000000..418b605ac35 --- /dev/null +++ b/arch/powerpc/platforms/cell/spider-pci.c @@ -0,0 +1,184 @@ +/* + * IO workarounds for PCI on Celleb/Cell platform + * + * (C) Copyright 2006-2007 TOSHIBA CORPORATION + * + * 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. 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/of_platform.h> +#include <linux/io.h> + +#include <asm/ppc-pci.h> +#include <asm/pci-bridge.h> + +#include "io-workarounds.h" + +#define SPIDER_PCI_DISABLE_PREFETCH + +struct spiderpci_iowa_private { + void __iomem *regs; +}; + +static void spiderpci_io_flush(struct iowa_bus *bus) +{ + struct spiderpci_iowa_private *priv; + u32 val; + + priv = bus->private; + val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ); + iosync(); +} + +#define SPIDER_PCI_MMIO_READ(name, ret) \ +static ret spiderpci_##name(const PCI_IO_ADDR addr) \ +{ \ + ret val = __do_##name(addr); \ + spiderpci_io_flush(iowa_mem_find_bus(addr)); \ + return val; \ +} + +#define SPIDER_PCI_MMIO_READ_STR(name) \ +static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \ + unsigned long count) \ +{ \ + __do_##name(addr, buf, count); \ + spiderpci_io_flush(iowa_mem_find_bus(addr)); \ +} + +SPIDER_PCI_MMIO_READ(readb, u8) +SPIDER_PCI_MMIO_READ(readw, u16) +SPIDER_PCI_MMIO_READ(readl, u32) +SPIDER_PCI_MMIO_READ(readq, u64) +SPIDER_PCI_MMIO_READ(readw_be, u16) +SPIDER_PCI_MMIO_READ(readl_be, u32) +SPIDER_PCI_MMIO_READ(readq_be, u64) +SPIDER_PCI_MMIO_READ_STR(readsb) +SPIDER_PCI_MMIO_READ_STR(readsw) +SPIDER_PCI_MMIO_READ_STR(readsl) + +static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src, + unsigned long n) +{ + __do_memcpy_fromio(dest, src, n); + spiderpci_io_flush(iowa_mem_find_bus(src)); +} + +static int __init spiderpci_pci_setup_chip(struct pci_controller *phb, + void __iomem *regs) +{ + void *dummy_page_va; + dma_addr_t dummy_page_da; + +#ifdef SPIDER_PCI_DISABLE_PREFETCH + u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT); + pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val); + out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8); +#endif /* SPIDER_PCI_DISABLE_PREFETCH */ + + /* setup dummy read */ + /* + * On CellBlade, we can't know that which XDR memory is used by + * kmalloc() to allocate dummy_page_va. + * In order to imporve the performance, the XDR which is used to + * allocate dummy_page_va is the nearest the spider-pci. + * We have to select the CBE which is the nearest the spider-pci + * to allocate memory from the best XDR, but I don't know that + * how to do. + * + * Celleb does not have this problem, because it has only one XDR. + */ + dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!dummy_page_va) { + pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n"); + return -1; + } + + dummy_page_da = dma_map_single(phb->parent, dummy_page_va, + PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dummy_page_da)) { + pr_err("SPIDER-IOWA:Map dummy page filed.\n"); + kfree(dummy_page_va); + return -1; + } + + out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da); + + return 0; +} + +int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data) +{ + void __iomem *regs = NULL; + struct spiderpci_iowa_private *priv; + struct device_node *np = bus->phb->dn; + struct resource r; + unsigned long offset = (unsigned long)data; + + pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%s)\n", + np->full_name); + + priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL); + if (!priv) { + pr_err("SPIDERPCI-IOWA:" + "Can't allocate struct spiderpci_iowa_private"); + return -1; + } + + if (of_address_to_resource(np, 0, &r)) { + pr_err("SPIDERPCI-IOWA:Can't get resource.\n"); + goto error; + } + + regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE); + if (!regs) { + pr_err("SPIDERPCI-IOWA:ioremap failed.\n"); + goto error; + } + priv->regs = regs; + bus->private = priv; + + if (spiderpci_pci_setup_chip(bus->phb, regs)) + goto error; + + return 0; + +error: + kfree(priv); + bus->private = NULL; + + if (regs) + iounmap(regs); + + return -1; +} + +struct ppc_pci_io spiderpci_ops = { + .readb = spiderpci_readb, + .readw = spiderpci_readw, + .readl = spiderpci_readl, + .readq = spiderpci_readq, + .readw_be = spiderpci_readw_be, + .readl_be = spiderpci_readl_be, + .readq_be = spiderpci_readq_be, + .readsb = spiderpci_readsb, + .readsw = spiderpci_readsw, + .readsl = spiderpci_readsl, + .memcpy_fromio = spiderpci_memcpy_fromio, +}; + diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig deleted file mode 100644 index 372891edcdd..00000000000 --- a/arch/powerpc/platforms/celleb/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config PPC_CELLEB - bool "Toshiba's Cell Reference Set 'Celleb' Architecture" - depends on PPC_MULTIPLATFORM && PPC64 - select PPC_CELL - select PPC_CELL_NATIVE - select PPC_RTAS - select PPC_INDIRECT_IO - select PPC_OF_PLATFORM_PCI - select HAS_TXX9_SERIAL - select PPC_UDBG_BEAT - select USB_OHCI_BIG_ENDIAN_MMIO - select USB_EHCI_BIG_ENDIAN_MMIO diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile deleted file mode 100644 index 889d43f715e..00000000000 --- a/arch/powerpc/platforms/celleb/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -obj-y += interrupt.o iommu.o setup.o \ - htab.o beat.o hvCall.o pci.o \ - scc_epci.o scc_uhc.o \ - io-workarounds.o - -obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o -obj-$(CONFIG_SERIAL_TXX9) += scc_sio.o -obj-$(CONFIG_SPU_BASE) += spu_priv1.o diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c deleted file mode 100644 index 423339be1ba..00000000000 --- a/arch/powerpc/platforms/celleb/io-workarounds.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Support for Celleb io workarounds - * - * (C) Copyright 2006-2007 TOSHIBA CORPORATION - * - * This file is based to arch/powerpc/platform/cell/io-workarounds.c - * - * 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. 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#undef DEBUG - -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/irq.h> - -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/ppc-pci.h> - -#include "pci.h" - -#define MAX_CELLEB_PCI_BUS 4 - -void *celleb_dummy_page_va; - -static struct celleb_pci_bus { - struct pci_controller *phb; - void (*dummy_read)(struct pci_controller *); -} celleb_pci_busses[MAX_CELLEB_PCI_BUS]; - -static int celleb_pci_count = 0; - -static struct celleb_pci_bus *celleb_pci_find(unsigned long vaddr, - unsigned long paddr) -{ - int i, j; - struct resource *res; - - for (i = 0; i < celleb_pci_count; i++) { - struct celleb_pci_bus *bus = &celleb_pci_busses[i]; - struct pci_controller *phb = bus->phb; - if (paddr) - for (j = 0; j < 3; j++) { - res = &phb->mem_resources[j]; - if (paddr >= res->start && paddr <= res->end) - return bus; - } - res = &phb->io_resource; - if (vaddr && vaddr >= res->start && vaddr <= res->end) - return bus; - } - return NULL; -} - -static void celleb_io_flush(const PCI_IO_ADDR addr) -{ - struct celleb_pci_bus *bus; - int token; - - token = PCI_GET_ADDR_TOKEN(addr); - - if (token && token <= celleb_pci_count) - bus = &celleb_pci_busses[token - 1]; - else { - unsigned long vaddr, paddr; - pte_t *ptep; - - vaddr = (unsigned long)PCI_FIX_ADDR(addr); - if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END) - return; - - ptep = find_linux_pte(init_mm.pgd, vaddr); - if (ptep == NULL) - paddr = 0; - else - paddr = pte_pfn(*ptep) << PAGE_SHIFT; - bus = celleb_pci_find(vaddr, paddr); - - if (bus == NULL) - return; - } - - if (bus->dummy_read) - bus->dummy_read(bus->phb); -} - -static u8 celleb_readb(const PCI_IO_ADDR addr) -{ - u8 val; - val = __do_readb(addr); - celleb_io_flush(addr); - return val; -} - -static u16 celleb_readw(const PCI_IO_ADDR addr) -{ - u16 val; - val = __do_readw(addr); - celleb_io_flush(addr); - return val; -} - -static u32 celleb_readl(const PCI_IO_ADDR addr) -{ - u32 val; - val = __do_readl(addr); - celleb_io_flush(addr); - return val; -} - -static u64 celleb_readq(const PCI_IO_ADDR addr) -{ - u64 val; - val = __do_readq(addr); - celleb_io_flush(addr); - return val; -} - -static u16 celleb_readw_be(const PCI_IO_ADDR addr) -{ - u16 val; - val = __do_readw_be(addr); - celleb_io_flush(addr); - return val; -} - -static u32 celleb_readl_be(const PCI_IO_ADDR addr) -{ - u32 val; - val = __do_readl_be(addr); - celleb_io_flush(addr); - return val; -} - -static u64 celleb_readq_be(const PCI_IO_ADDR addr) -{ - u64 val; - val = __do_readq_be(addr); - celleb_io_flush(addr); - return val; -} - -static void celleb_readsb(const PCI_IO_ADDR addr, - void *buf, unsigned long count) -{ - __do_readsb(addr, buf, count); - celleb_io_flush(addr); -} - -static void celleb_readsw(const PCI_IO_ADDR addr, - void *buf, unsigned long count) -{ - __do_readsw(addr, buf, count); - celleb_io_flush(addr); -} - -static void celleb_readsl(const PCI_IO_ADDR addr, - void *buf, unsigned long count) -{ - __do_readsl(addr, buf, count); - celleb_io_flush(addr); -} - -static void celleb_memcpy_fromio(void *dest, - const PCI_IO_ADDR src, - unsigned long n) -{ - __do_memcpy_fromio(dest, src, n); - celleb_io_flush(src); -} - -static void __iomem *celleb_ioremap(unsigned long addr, - unsigned long size, - unsigned long flags) -{ - struct celleb_pci_bus *bus; - void __iomem *res = __ioremap(addr, size, flags); - int busno; - - bus = celleb_pci_find(0, addr); - if (bus != NULL) { - busno = bus - celleb_pci_busses; - PCI_SET_ADDR_TOKEN(res, busno + 1); - } - return res; -} - -static void celleb_iounmap(volatile void __iomem *addr) -{ - return __iounmap(PCI_FIX_ADDR(addr)); -} - -static struct ppc_pci_io celleb_pci_io __initdata = { - .readb = celleb_readb, - .readw = celleb_readw, - .readl = celleb_readl, - .readq = celleb_readq, - .readw_be = celleb_readw_be, - .readl_be = celleb_readl_be, - .readq_be = celleb_readq_be, - .readsb = celleb_readsb, - .readsw = celleb_readsw, - .readsl = celleb_readsl, - .memcpy_fromio = celleb_memcpy_fromio, -}; - -void __init celleb_pci_add_one(struct pci_controller *phb, - void (*dummy_read)(struct pci_controller *)) -{ - struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count]; - struct device_node *np = phb->dn; - - if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) { - printk(KERN_ERR "Too many pci bridges, workarounds" - " disabled for %s\n", np->full_name); - return; - } - - celleb_pci_count++; - - bus->phb = phb; - bus->dummy_read = dummy_read; -} - -static struct of_device_id celleb_pci_workaround_match[] __initdata = { - { - .name = "pci-pseudo", - .data = fake_pci_workaround_init, - }, { - .name = "epci", - .data = epci_workaround_init, - }, { - }, -}; - -int __init celleb_pci_workaround_init(void) -{ - struct pci_controller *phb; - struct device_node *node; - const struct of_device_id *match; - void (*init_func)(struct pci_controller *); - - celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!celleb_dummy_page_va) { - printk(KERN_ERR "Celleb: dummy read disabled. " - "Alloc celleb_dummy_page_va failed\n"); - return 1; - } - - list_for_each_entry(phb, &hose_list, list_node) { - node = phb->dn; - match = of_match_node(celleb_pci_workaround_match, node); - - if (match) { - init_func = match->data; - (*init_func)(phb); - } - } - - ppc_pci_io = celleb_pci_io; - ppc_md.ioremap = celleb_ioremap; - ppc_md.iounmap = celleb_iounmap; - - return 0; -} diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S index c775cd4b3d6..8ff330d026c 100644 --- a/arch/powerpc/platforms/iseries/exception.S +++ b/arch/powerpc/platforms/iseries/exception.S @@ -59,8 +59,33 @@ system_reset_iSeries: andc r4,r4,r5 mtspr SPRN_CTRLT,r4 +/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ +/* In the UP case we'll yeild() later, and we will not access the paca anyway */ +#ifdef CONFIG_SMP 1: HMT_LOW + LOAD_REG_IMMEDIATE(r23, __secondary_hold_spinloop) + ld r23,0(r23) + sync + LOAD_REG_IMMEDIATE(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,THREAD_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + cmpwi 0,r23,0 /* Keep poking the Hypervisor until */ + bne 2f /* we're released */ + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + b 1b +#endif + +2: + HMT_LOW #ifdef CONFIG_SMP lbz r23,PACAPROCSTART(r13) /* Test if this processor * should start */ @@ -91,7 +116,7 @@ iSeries_secondary_smp_loop: li r0,-1 /* r0=-1 indicates a Hypervisor call */ sc /* Invoke the hypervisor via a system call */ mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */ - b 1b /* If SMP not configured, secondaries + b 2b /* If SMP not configured, secondaries * loop forever */ /*** ISeries-LPAR interrupt handlers ***/ diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index c73379ec914..1d201782d4e 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -25,6 +25,7 @@ #include <linux/syscalls.h> #include <linux/ctype.h> #include <linux/lmb.h> +#include <linux/of.h> #include <asm/prom.h> diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 306a9d07491..07fe5b69b9e 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -34,3 +34,8 @@ config LPARCFG help Provide system capacity information via human readable <key word>=<value> pairs through a /proc/ppc64/lparcfg interface. + +config PPC_PSERIES_DEBUG + depends on PPC_PSERIES && PPC_EARLY_DEBUG + bool "Enable extra debug logging in platforms/pseries" + default y diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index bdae04bb7a0..bd2593ed28d 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -2,6 +2,10 @@ ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif +ifeq ($(CONFIG_PPC_PSERIES_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif + obj-y := lpar.o hvCall.o nvram.o reconfig.o \ setup.o iommu.o ras.o rtasd.o \ firmware.o power.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 550b2f7d2cc..a3fd56b186e 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -39,7 +39,6 @@ #include <asm/ppc-pci.h> #include <asm/rtas.h> -#undef DEBUG /** Overview: * EEH, or "Extended Error Handling" is a PCI bridge technology for diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index 1e83fcd0df3..ce37040af87 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -28,7 +28,6 @@ #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#undef DEBUG /** * The pci address cache subsystem. This subsystem places diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index b765b7c77b6..9d3a40f4597 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -21,17 +21,11 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG #include <asm/firmware.h> #include <asm/prom.h> #include <asm/udbg.h> -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif typedef struct { unsigned long val; @@ -72,7 +66,7 @@ void __init fw_feature_init(const char *hypertas, unsigned long len) const char *s; int i; - DBG(" -> fw_feature_init()\n"); + pr_debug(" -> fw_feature_init()\n"); for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) { for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) { @@ -88,5 +82,5 @@ void __init fw_feature_init(const char *hypertas, unsigned long len) } } - DBG(" <- fw_feature_init()\n"); + pr_debug(" <- fw_feature_init()\n"); } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index a65c7630820..176f1f39d2d 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -47,7 +47,6 @@ #include "plpar_wrappers.h" -#define DBG(fmt...) static void tce_build_pSeries(struct iommu_table *tbl, long index, long npages, unsigned long uaddr, @@ -322,7 +321,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) dn = pci_bus_to_OF_node(bus); - DBG("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name); + pr_debug("pci_dma_bus_setup_pSeries: setting up bus %s\n", dn->full_name); if (bus->self) { /* This is not a root bus, any setup will be done for the @@ -347,7 +346,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) children++; - DBG("Children: %d\n", children); + pr_debug("Children: %d\n", children); /* Calculate amount of DMA window per slot. Each window must be * a power of two (due to pci_alloc_consistent requirements). @@ -361,8 +360,8 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) while (pci->phb->dma_window_size * children > 0x80000000ul) pci->phb->dma_window_size >>= 1; - DBG("No ISA/IDE, window size is 0x%lx\n", - pci->phb->dma_window_size); + pr_debug("No ISA/IDE, window size is 0x%lx\n", + pci->phb->dma_window_size); pci->phb->dma_window_base_cur = 0; return; @@ -387,8 +386,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) while (pci->phb->dma_window_size * children > 0x70000000ul) pci->phb->dma_window_size >>= 1; - DBG("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size); - + pr_debug("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size); } @@ -401,7 +399,8 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) dn = pci_bus_to_OF_node(bus); - DBG("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", dn->full_name); + pr_debug("pci_dma_bus_setup_pSeriesLP: setting up bus %s\n", + dn->full_name); /* Find nearest ibm,dma-window, walking up the device tree */ for (pdn = dn; pdn != NULL; pdn = pdn->parent) { @@ -411,14 +410,14 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) } if (dma_window == NULL) { - DBG(" no ibm,dma-window property !\n"); + pr_debug(" no ibm,dma-window property !\n"); return; } ppci = PCI_DN(pdn); - DBG(" parent is %s, iommu_table: 0x%p\n", - pdn->full_name, ppci->iommu_table); + pr_debug(" parent is %s, iommu_table: 0x%p\n", + pdn->full_name, ppci->iommu_table); if (!ppci->iommu_table) { tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, @@ -426,7 +425,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, bus->number); ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); - DBG(" created table: %p\n", ppci->iommu_table); + pr_debug(" created table: %p\n", ppci->iommu_table); } if (pdn != dn) @@ -439,7 +438,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) struct device_node *dn; struct iommu_table *tbl; - DBG("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev)); + pr_debug("pci_dma_dev_setup_pSeries: %s\n", pci_name(dev)); dn = dev->dev.archdata.of_node; @@ -450,7 +449,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) if (!dev->bus->self) { struct pci_controller *phb = PCI_DN(dn)->phb; - DBG(" --> first child, no bridge. Allocating iommu table.\n"); + pr_debug(" --> first child, no bridge. Allocating iommu table.\n"); tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, phb->node); iommu_table_setparms(phb, dn, tbl); @@ -480,7 +479,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) const void *dma_window = NULL; struct pci_dn *pci; - DBG("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev)); + pr_debug("pci_dma_dev_setup_pSeriesLP: %s\n", pci_name(dev)); /* dev setup for LPAR is a little tricky, since the device tree might * contain the dma-window properties per-device and not neccesarily @@ -489,7 +488,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) * already allocated. */ dn = pci_device_to_OF_node(dev); - DBG(" node is %s\n", dn->full_name); + pr_debug(" node is %s\n", dn->full_name); for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table; pdn = pdn->parent) { @@ -504,13 +503,13 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pci_name(dev), dn? dn->full_name : "<null>"); return; } - DBG(" parent is %s\n", pdn->full_name); + pr_debug(" parent is %s\n", pdn->full_name); /* Check for parent == NULL so we don't try to setup the empty EADS * slots on POWER4 machines. */ if (dma_window == NULL || pdn->parent == NULL) { - DBG(" no dma window for device, linking to parent\n"); + pr_debug(" no dma window for device, linking to parent\n"); dev->dev.archdata.dma_data = PCI_DN(pdn)->iommu_table; return; } @@ -522,9 +521,9 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, pci->phb->bus->number); pci->iommu_table = iommu_init_table(tbl, pci->phb->node); - DBG(" created table: %p\n", pci->iommu_table); + pr_debug(" created table: %p\n", pci->iommu_table); } else { - DBG(" found DMA window, table: %p\n", pci->iommu_table); + pr_debug(" found DMA window, table: %p\n", pci->iommu_table); } dev->dev.archdata.dma_data = pci->iommu_table; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 9235c469449..2cbaedb17f3 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -19,7 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#undef DEBUG_LOW +/* Enables debugging of low-level hash table routines - careful! */ +#undef DEBUG #include <linux/kernel.h> #include <linux/dma-mapping.h> @@ -42,11 +43,6 @@ #include "plpar_wrappers.h" #include "pseries.h" -#ifdef DEBUG_LOW -#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0) -#else -#define DBG_LOW(fmt...) do { } while(0) -#endif /* in hvCall.S */ EXPORT_SYMBOL(plpar_hcall); @@ -196,6 +192,8 @@ void __init udbg_init_debug_lpar(void) udbg_putc = udbg_putcLP; udbg_getc = udbg_getcLP; udbg_getc_poll = udbg_getc_pollLP; + + register_early_udbg_console(); } /* returns 0 if couldn't find or use /chosen/stdout as console */ @@ -288,15 +286,15 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long hpte_v, hpte_r; if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " - "rflags=%lx, vflags=%lx, psize=%d)\n", - hpte_group, va, pa, rflags, vflags, psize); + pr_debug("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " + "rflags=%lx, vflags=%lx, psize=%d)\n", + hpte_group, va, pa, rflags, vflags, psize); hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); + pr_debug(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); /* Now fill in the actual HPTE */ /* Set CEC cookie to 0 */ @@ -313,7 +311,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot); if (unlikely(lpar_rc == H_PTEG_FULL)) { if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" full\n"); + pr_debug(" full\n"); return -1; } @@ -324,11 +322,11 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, */ if (unlikely(lpar_rc != H_SUCCESS)) { if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" lpar err %d\n", lpar_rc); + pr_debug(" lpar err %lu\n", lpar_rc); return -2; } if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW(" -> slot: %d\n", slot & 7); + pr_debug(" -> slot: %lu\n", slot & 7); /* Because of iSeries, we have to pass down the secondary * bucket bit here as well @@ -420,17 +418,17 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, want_v = hpte_encode_avpn(va, psize, ssize); - DBG_LOW(" update: avpnv=%016lx, hash=%016lx, f=%x, psize: %d ... ", - want_v, slot, flags, psize); + pr_debug(" update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...", + want_v, slot, flags, psize); lpar_rc = plpar_pte_protect(flags, slot, want_v); if (lpar_rc == H_NOT_FOUND) { - DBG_LOW("not found !\n"); + pr_debug("not found !\n"); return -1; } - DBG_LOW("ok\n"); + pr_debug("ok\n"); BUG_ON(lpar_rc != H_SUCCESS); @@ -505,8 +503,8 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, unsigned long lpar_rc; unsigned long dummy1, dummy2; - DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d", - slot, va, psize, local); + pr_debug(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", + slot, va, psize, local); want_v = hpte_encode_avpn(va, psize, ssize); lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2); diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index a1ab25c7082..2b548afd100 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -67,8 +67,6 @@ static int ras_check_exception_token; static irqreturn_t ras_epow_interrupt(int irq, void *dev_id); static irqreturn_t ras_error_interrupt(int irq, void *dev_id); -/* #define DEBUG */ - static void request_ras_irqs(struct device_node *np, irq_handler_t handler, @@ -237,7 +235,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id) printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n", *((unsigned long *)&ras_log_buf), status); -#ifndef DEBUG +#ifndef DEBUG_RTAS_POWER_OFF /* Don't actually power off when debugging so we can test * without actually failing while injecting errors. * Error data will not be logged to syslog. diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index e3078ce4151..befadd4f952 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -29,11 +29,6 @@ #include <asm/atomic.h> #include <asm/machdep.h> -#if 0 -#define DEBUG(A...) printk(KERN_ERR A) -#else -#define DEBUG(A...) -#endif static DEFINE_SPINLOCK(rtasd_log_lock); @@ -198,7 +193,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) unsigned long s; int len = 0; - DEBUG("logging event\n"); + pr_debug("rtasd: logging event\n"); if (buf == NULL) return; @@ -409,7 +404,8 @@ static int rtasd(void *unused) daemonize("rtasd"); printk(KERN_DEBUG "RTAS daemon started\n"); - DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); + pr_debug("rtasd: will sleep for %d milliseconds\n", + (30000 / rtas_event_scan_rate)); /* See if we have any error stored in NVRAM */ memset(logdata, 0, rtas_error_log_max); @@ -428,9 +424,9 @@ static int rtasd(void *unused) do_event_scan_all_cpus(1000); if (surveillance_timeout != -1) { - DEBUG("enabling surveillance\n"); + pr_debug("rtasd: enabling surveillance\n"); enable_surveillance(surveillance_timeout); - DEBUG("surveillance enabled\n"); + pr_debug("rtasd: surveillance enabled\n"); } /* Delay should be at least one second since some diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index e5b0ea87016..bec3803f061 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c @@ -38,9 +38,7 @@ #define SCANLOG_HWERROR -1 #define SCANLOG_CONTINUE 1 -#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0) -static int scanlog_debug; static unsigned int ibm_scan_log_dump; /* RTAS token */ static struct proc_dir_entry *proc_ppc64_scan_log_dump; /* The proc file */ @@ -86,14 +84,14 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); - DEBUG("status=%d, data[0]=%x, data[1]=%x, data[2]=%x\n", - status, data[0], data[1], data[2]); + pr_debug("scanlog: status=%d, data[0]=%x, data[1]=%x, " \ + "data[2]=%x\n", status, data[0], data[1], data[2]); switch (status) { case SCANLOG_COMPLETE: - DEBUG("hit eof\n"); + pr_debug("scanlog: hit eof\n"); return 0; case SCANLOG_HWERROR: - DEBUG("hardware error reading scan log data\n"); + pr_debug("scanlog: hardware error reading data\n"); return -EIO; case SCANLOG_CONTINUE: /* We may or may not have data yet */ @@ -110,7 +108,8 @@ static ssize_t scanlog_read(struct file *file, char __user *buf, /* Assume extended busy */ wait_time = rtas_busy_delay_time(status); if (!wait_time) { - printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); + printk(KERN_ERR "scanlog: unknown error " \ + "from rtas: %d\n", status); return -EIO; } } @@ -134,15 +133,9 @@ static ssize_t scanlog_write(struct file * file, const char __user * buf, if (buf) { if (strncmp(stkbuf, "reset", 5) == 0) { - DEBUG("reset scanlog\n"); + pr_debug("scanlog: reset scanlog\n"); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, 0, 0); - DEBUG("rtas returns %d\n", status); - } else if (strncmp(stkbuf, "debugon", 7) == 0) { - printk(KERN_ERR "scanlog: debug on\n"); - scanlog_debug = 1; - } else if (strncmp(stkbuf, "debugoff", 8) == 0) { - printk(KERN_ERR "scanlog: debug off\n"); - scanlog_debug = 0; + pr_debug("scanlog: rtas returns %d\n", status); } } return count; diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f66aa9c3b13..f5d29f5b13c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -16,8 +16,6 @@ * bootup setup stuff.. */ -#undef DEBUG - #include <linux/cpu.h> #include <linux/errno.h> #include <linux/sched.h> @@ -70,11 +68,6 @@ #include "plpar_wrappers.h" #include "pseries.h" -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -326,7 +319,7 @@ static int pseries_set_xdabr(unsigned long dabr) */ static void __init pSeries_init_early(void) { - DBG(" -> pSeries_init_early()\n"); + pr_debug(" -> pSeries_init_early()\n"); if (firmware_has_feature(FW_FEATURE_LPAR)) find_udbg_vterm(); @@ -338,7 +331,7 @@ static void __init pSeries_init_early(void) iommu_init_early_pSeries(); - DBG(" <- pSeries_init_early()\n"); + pr_debug(" <- pSeries_init_early()\n"); } /* @@ -383,7 +376,7 @@ static int __init pSeries_probe(void) of_flat_dt_is_compatible(root, "IBM,CBEA")) return 0; - DBG("pSeries detected, looking for LPAR capability...\n"); + pr_debug("pSeries detected, looking for LPAR capability...\n"); /* Now try to figure out if we are running on LPAR */ of_scan_flat_dt(pSeries_probe_hypertas, NULL); @@ -393,8 +386,8 @@ static int __init pSeries_probe(void) else hpte_init_native(); - DBG("Machine is%s LPAR !\n", - (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); + pr_debug("Machine is%s LPAR !\n", + (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); return 1; } diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index ea4c65917a6..9d8f8c84ab8 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -12,7 +12,6 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG #include <linux/kernel.h> #include <linux/module.h> @@ -51,12 +50,6 @@ #include "plpar_wrappers.h" #include "pseries.h" -#ifdef DEBUG -#include <asm/udbg.h> -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif /* * The primary thread of each non-boot processor is recorded here before @@ -231,7 +224,7 @@ static void __init smp_init_pseries(void) { int i; - DBG(" -> smp_init_pSeries()\n"); + pr_debug(" -> smp_init_pSeries()\n"); /* Mark threads which are still spinning in hold loops. */ if (cpu_has_feature(CPU_FTR_SMT)) { @@ -255,7 +248,7 @@ static void __init smp_init_pseries(void) smp_ops->take_timebase = pSeries_take_timebase; } - DBG(" <- smp_init_pSeries()\n"); + pr_debug(" <- smp_init_pSeries()\n"); } #ifdef CONFIG_MPIC diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 43df53c30aa..ebebc28fe89 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG #include <linux/types.h> #include <linux/threads.h> |