diff options
Diffstat (limited to 'arch')
678 files changed, 19279 insertions, 26955 deletions
diff --git a/arch/alpha/include/asm/machvec.h b/arch/alpha/include/asm/machvec.h index 13cd42743810..72dbf2359270 100644 --- a/arch/alpha/include/asm/machvec.h +++ b/arch/alpha/include/asm/machvec.h @@ -90,7 +90,7 @@ struct alpha_machine_vector void (*kill_arch)(int); u8 (*pci_swizzle)(struct pci_dev *, u8 *); - int (*pci_map_irq)(struct pci_dev *, u8, u8); + int (*pci_map_irq)(const struct pci_dev *, u8, u8); struct pci_ops *pci_ops; struct _alpha_agp_info *(*agp_info)(void); diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 082355f159e6..dcb221a4b5be 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -71,6 +71,10 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/alpha/kernel/binfmt_loader.c b/arch/alpha/kernel/binfmt_loader.c index 3fcfad410130..d1f474d1d44d 100644 --- a/arch/alpha/kernel/binfmt_loader.c +++ b/arch/alpha/kernel/binfmt_loader.c @@ -46,6 +46,7 @@ static struct linux_binfmt loader_format = { static int __init init_loader_binfmt(void) { - return insert_binfmt(&loader_format); + insert_binfmt(&loader_format); + return 0; } arch_initcall(init_loader_binfmt); diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index bb7f0c7cb17a..13f0717fc7fe 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -366,7 +366,7 @@ clipper_init_irq(void) */ static int __init -isa_irq_fixup(struct pci_dev *dev, int irq) +isa_irq_fixup(const struct pci_dev *dev, int irq) { u8 irq8; diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/arch/arm/boot/dts/testcases/tests-phandle.dtsi index ec0c4e6212c9..0007d3cd7dc2 100644 --- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi +++ b/arch/arm/boot/dts/testcases/tests-phandle.dtsi @@ -31,6 +31,8 @@ phandle-list-bad-phandle = <12345678 0 0>; phandle-list-bad-args = <&provider2 1 0>, <&provider3 0>; + empty-property; + unterminated-string = [40 41 42 43]; }; }; }; diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index c47d6199b784..f0783be17352 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -51,7 +51,6 @@ union gic_base { }; struct gic_chip_data { - unsigned int irq_offset; union gic_base dist_base; union gic_base cpu_base; #ifdef CONFIG_CPU_PM @@ -61,9 +60,7 @@ struct gic_chip_data { u32 __percpu *saved_ppi_enable; u32 __percpu *saved_ppi_conf; #endif -#ifdef CONFIG_IRQ_DOMAIN - struct irq_domain domain; -#endif + struct irq_domain *domain; unsigned int gic_irqs; #ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *); @@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) irqnr = irqstat & ~0x1c00; if (likely(irqnr > 15 && irqnr < 1021)) { - irqnr = irq_domain_to_irq(&gic->domain, irqnr); + irqnr = irq_find_mapping(gic->domain, irqnr); handle_IRQ(irqnr, regs); continue; } @@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) if (gic_irq == 1023) goto out; - cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); - if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) + cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); + if (unlikely(gic_irq < 32 || gic_irq > 1020)) do_bad_IRQ(cascade_irq, desc); else generic_handle_irq(cascade_irq); @@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) static void __init gic_dist_init(struct gic_chip_data *gic) { - unsigned int i, irq; + unsigned int i; u32 cpumask; unsigned int gic_irqs = gic->gic_irqs; - struct irq_domain *domain = &gic->domain; void __iomem *base = gic_data_dist_base(gic); u32 cpu = cpu_logical_map(smp_processor_id()); @@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic) for (i = 32; i < gic_irqs; i += 32) writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); - /* - * Setup the Linux IRQ subsystem. - */ - irq_domain_for_each_irq(domain, i, irq) { - if (i < 32) { - irq_set_percpu_devid(irq); - irq_set_chip_and_handler(irq, &gic_chip, - handle_percpu_devid_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); - } else { - irq_set_chip_and_handler(irq, &gic_chip, - handle_fasteoi_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - irq_set_chip_data(irq, gic); - } - writel_relaxed(1, base + GIC_DIST_CTRL); } @@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif -#ifdef CONFIG_OF -static int gic_irq_domain_dt_translate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type) +static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + if (hw < 32) { + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, &gic_chip, + handle_percpu_devid_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + } else { + irq_set_chip_and_handler(irq, &gic_chip, + handle_fasteoi_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + irq_set_chip_data(irq, d->host_data); + return 0; +} + +static int gic_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) { if (d->of_node != controller) return -EINVAL; @@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d, *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return 0; } -#endif const struct irq_domain_ops gic_irq_domain_ops = { -#ifdef CONFIG_OF - .dt_translate = gic_irq_domain_dt_translate, -#endif + .map = gic_irq_domain_map, + .xlate = gic_irq_domain_xlate, }; void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, - u32 percpu_offset) + u32 percpu_offset, struct device_node *node) { + irq_hw_number_t hwirq_base; struct gic_chip_data *gic; - struct irq_domain *domain; - int gic_irqs; + int gic_irqs, irq_base; BUG_ON(gic_nr >= MAX_GIC_NR); gic = &gic_data[gic_nr]; - domain = &gic->domain; #ifdef CONFIG_GIC_NON_BANKED if (percpu_offset) { /* Frankein-GIC without banked registers... */ unsigned int cpu; @@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. */ - domain->hwirq_base = 32; + hwirq_base = 32; if (gic_nr == 0) { if ((irq_start & 31) > 0) { - domain->hwirq_base = 16; + hwirq_base = 16; if (irq_start != -1) irq_start = (irq_start & ~31) + 16; } @@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_irqs = 1020; gic->gic_irqs = gic_irqs; - domain->nr_irq = gic_irqs - domain->hwirq_base; - domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, - numa_node_id()); - if (IS_ERR_VALUE(domain->irq_base)) { + gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ + irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); + if (IS_ERR_VALUE(irq_base)) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", irq_start); - domain->irq_base = irq_start; + irq_base = irq_start; } - domain->priv = gic; - domain->ops = &gic_irq_domain_ops; - irq_domain_add(domain); + gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, + hwirq_base, &gic_irq_domain_ops, gic); + if (WARN_ON(!gic->domain)) + return; gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic); @@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) void __iomem *dist_base; u32 percpu_offset; int irq; - struct irq_domain *domain = &gic_data[gic_cnt].domain; if (WARN_ON(!node)) return -ENODEV; @@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; - domain->of_node = of_node_get(node); - - gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset); + gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); if (parent) { irq = irq_of_parse_and_map(node, 0); diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index dcb004a804c7..7a66311f3066 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -56,7 +56,7 @@ struct vic_device { u32 int_enable; u32 soft_int; u32 protect; - struct irq_domain domain; + struct irq_domain *domain; }; /* we cannot allocate memory when VICs are initially registered */ @@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq, v->resume_sources = resume_sources; v->irq = irq; vic_id++; - - v->domain.irq_base = irq; - v->domain.nr_irq = 32; -#ifdef CONFIG_OF_IRQ - v->domain.of_node = of_node_get(node); -#endif /* CONFIG_OF */ - v->domain.ops = &irq_domain_simple_ops; - irq_domain_add(&v->domain); + v->domain = irq_domain_add_legacy(node, 32, irq, 0, + &irq_domain_simple_ops, v); } static void vic_ack_irq(struct irq_data *d) @@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, vic_register(base, irq_start, 0, node); } -static void __init __vic_init(void __iomem *base, unsigned int irq_start, +void __init __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources, struct device_node *node) { @@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) stat = readl_relaxed(vic->base + VIC_IRQ_STATUS); while (stat) { irq = ffs(stat) - 1; - handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs); + handle_IRQ(irq_find_mapping(vic->domain, irq), regs); stat &= ~(1 << irq); handled = 1; } diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 4bdfe0018696..4b1ce6cd477f 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -39,7 +39,7 @@ struct device_node; extern struct irq_chip gic_arch_extn; void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, - u32 offset); + u32 offset, struct device_node *); int gic_of_init(struct device_node *node, struct device_node *parent); void gic_secondary_init(unsigned int); void gic_handle_irq(struct pt_regs *regs); @@ -49,7 +49,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); static inline void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu) { - gic_init_bases(nr, start, dist, cpu, 0); + gic_init_bases(nr, start, dist, cpu, 0, NULL); } #endif diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index f42ebd619590..e14af1a1a320 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h @@ -47,6 +47,8 @@ struct device_node; struct pt_regs; +void __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, + u32 resume_sources, struct device_node *node); void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); int vic_of_init(struct device_node *node, struct device_node *parent); void vic_handle_irq(struct pt_regs *regs); diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index a4edd19dd3d6..8c5e828f484d 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -57,7 +57,7 @@ static inline void *kmap_high_get(struct page *page) #ifdef CONFIG_HIGHMEM extern void *kmap(struct page *page); extern void kunmap(struct page *page); -extern void *__kmap_atomic(struct page *page); +extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(const void *ptr); diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index dec6f9afb3cf..6433cadb6ed4 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -64,5 +64,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/arm/mach-bcmring/dma.c b/arch/arm/mach-bcmring/dma.c index 1024396797e1..e5fd241fccdc 100644 --- a/arch/arm/mach-bcmring/dma.c +++ b/arch/arm/mach-bcmring/dma.c @@ -35,7 +35,6 @@ #include <linux/pfn.h> #include <linux/atomic.h> -#include <linux/sched.h> #include <mach/dma.h> /* ---- Public Variables ------------------------------------------------- */ diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 24203f9a6796..b5c1dae8327f 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -817,23 +817,12 @@ void __init ep93xx_register_i2s(void) #define EP93XX_I2SCLKDIV_MASK (EP93XX_SYSCON_I2SCLKDIV_ORIDE | \ EP93XX_SYSCON_I2SCLKDIV_SPOL) -int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config) +int ep93xx_i2s_acquire(void) { unsigned val; - /* Sanity check */ - if (i2s_pins & ~EP93XX_SYSCON_DEVCFG_I2S_MASK) - return -EINVAL; - if (i2s_config & ~EP93XX_I2SCLKDIV_MASK) - return -EINVAL; - - /* Must have only one of I2SONSSP/I2SONAC97 set */ - if ((i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONSSP) == - (i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONAC97)) - return -EINVAL; - - ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK); - ep93xx_devcfg_set_bits(i2s_pins); + ep93xx_devcfg_set_clear(EP93XX_SYSCON_DEVCFG_I2SONAC97, + EP93XX_SYSCON_DEVCFG_I2S_MASK); /* * This is potentially racy with the clock api for i2s_mclk, sclk and @@ -843,7 +832,7 @@ int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config) */ val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV); val &= ~EP93XX_I2SCLKDIV_MASK; - val |= i2s_config; + val |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL; ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV); return 0; diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index d4c934931f9d..ad63d4be693f 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -59,7 +59,7 @@ void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data); int ep93xx_keypad_acquire_gpio(struct platform_device *pdev); void ep93xx_keypad_release_gpio(struct platform_device *pdev); void ep93xx_register_i2s(void); -int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config); +int ep93xx_i2s_acquire(void); void ep93xx_i2s_release(void); void ep93xx_register_ac97(void); diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 5d602f68a0e8..dfad6538b273 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -34,6 +34,7 @@ config CPU_EXYNOS4210 select ARM_CPU_SUSPEND if PM select S5P_PM if PM select S5P_SLEEP if PM + select PM_GENERIC_DOMAINS help Enable EXYNOS4210 CPU support @@ -74,11 +75,6 @@ config EXYNOS4_SETUP_FIMD0 help Common setup code for FIMD0. -config EXYNOS4_DEV_PD - bool - help - Compile in platform device definitions for Power Domain - config EXYNOS4_DEV_SYSMMU bool help @@ -195,7 +191,6 @@ config MACH_SMDKV310 select EXYNOS4_DEV_AHCI select SAMSUNG_DEV_KEYPAD select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select SAMSUNG_DEV_PWM select EXYNOS4_DEV_USB_OHCI select EXYNOS4_DEV_SYSMMU @@ -243,7 +238,6 @@ config MACH_UNIVERSAL_C210 select S5P_DEV_ONENAND select S5P_DEV_TV select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 @@ -277,7 +271,6 @@ config MACH_NURI select S5P_DEV_USB_EHCI select S5P_SETUP_MIPIPHY select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_SETUP_FIMC select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 @@ -310,7 +303,6 @@ config MACH_ORIGEN select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_PWM select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_DEV_USB_OHCI select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_SDHCI diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 5fc202cdfdb6..d9191f9a7af8 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o @@ -45,7 +46,6 @@ obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o -obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index c59e18871006..6de298c5d2d3 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -402,7 +402,7 @@ void __init exynos4_init_irq(void) gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; if (!of_have_populated_dt()) - gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset); + gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL); #ifdef CONFIG_OF else of_irq_init(exynos4_dt_irq_match); diff --git a/arch/arm/mach-exynos/dev-pd.c b/arch/arm/mach-exynos/dev-pd.c deleted file mode 100644 index 3273f25d6a75..000000000000 --- a/arch/arm/mach-exynos/dev-pd.c +++ /dev/null @@ -1,139 +0,0 @@ -/* linux/arch/arm/mach-exynos4/dev-pd.c - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4 - Power Domain support - * - * 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 - * published by the Free Software Foundation. -*/ - -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/delay.h> - -#include <mach/regs-pmu.h> - -#include <plat/pd.h> - -static int exynos4_pd_enable(struct device *dev) -{ - struct samsung_pd_info *pdata = dev->platform_data; - u32 timeout; - - __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base); - - /* Wait max 1ms */ - timeout = 10; - while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) - != S5P_INT_LOCAL_PWR_EN) { - if (timeout == 0) { - printk(KERN_ERR "Power domain %s enable failed.\n", - dev_name(dev)); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - - return 0; -} - -static int exynos4_pd_disable(struct device *dev) -{ - struct samsung_pd_info *pdata = dev->platform_data; - u32 timeout; - - __raw_writel(0, pdata->base); - - /* Wait max 1ms */ - timeout = 10; - while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) { - if (timeout == 0) { - printk(KERN_ERR "Power domain %s disable failed.\n", - dev_name(dev)); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - - return 0; -} - -struct platform_device exynos4_device_pd[] = { - { - .name = "samsung-pd", - .id = 0, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_MFC_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 1, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_G3D_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 2, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_LCD0_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 3, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_LCD1_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 4, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_TV_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 5, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_CAM_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 6, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_GPS_CONF, - }, - }, - }, -}; diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 435261f83f46..aa37179d776c 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1263,9 +1263,6 @@ static struct platform_device *nuri_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_CAM], &s5p_device_fimc_md, /* NURI Devices */ @@ -1315,14 +1312,6 @@ static void __init nuri_machine_init(void) /* Last */ platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices)); - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev; } MACHINE_START(NURI, "NURI") diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 0679b8ad2d1e..fa5c4a59b0aa 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -621,13 +621,6 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_mfc_r, &s5p_device_mixer, &exynos4_device_ohci, - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_GPS], - &exynos4_device_pd[PD_MFC], &origen_device_gpiokeys, &origen_lcd_hv070wsa, }; @@ -695,13 +688,6 @@ static void __init origen_machine_init(void) platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; - - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); } diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index b2c5557f50e4..5258b8563676 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -277,13 +277,6 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_GPS], &exynos4_device_spdif, &exynos4_device_sysmmu, &samsung_asoc_dma, @@ -336,10 +329,6 @@ static void s5p_tv_setup(void) WARN_ON(gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug")); s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - - /* setup dependencies between TV devices */ - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; } static void __init smdkv310_map_io(void) @@ -379,7 +368,6 @@ static void __init smdkv310_machine_init(void) clk_xusbxti.rate = 24000000; platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; } MACHINE_START(SMDKV310, "SMDKV310") diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 38939956c34f..b2d495b31094 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -971,7 +971,6 @@ static struct platform_device *universal_devices[] __initdata = { &s3c_device_i2c5, &s5p_device_i2c_hdmiphy, &hdmi_fixed_voltage, - &exynos4_device_pd[PD_TV], &s5p_device_hdmi, &s5p_device_sdo, &s5p_device_mixer, @@ -984,9 +983,6 @@ static struct platform_device *universal_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_CAM], &cam_i_core_fixed_reg_dev, &cam_s_if_fixed_reg_dev, &s5p_device_fimc_md, @@ -1005,10 +1001,6 @@ void s5p_tv_setup(void) gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug"); s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - - /* setup dependencies between TV devices */ - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; } static void __init universal_reserve(void) @@ -1042,15 +1034,6 @@ static void __init universal_machine_init(void) /* Last */ platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); - - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev; } MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c new file mode 100644 index 000000000000..0b04af2b13cc --- /dev/null +++ b/arch/arm/mach-exynos/pm_domains.c @@ -0,0 +1,195 @@ +/* + * Exynos Generic power domain support. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Implementation of Exynos specific power domain control which is used in + * conjunction with runtime-pm. Support for both device-tree and non-device-tree + * based power domain support is included. + * + * 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 + * published by the Free Software Foundation. +*/ + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> +#include <linux/delay.h> +#include <linux/of_address.h> + +#include <mach/regs-pmu.h> +#include <plat/devs.h> + +/* + * Exynos specific wrapper around the generic power domain + */ +struct exynos_pm_domain { + void __iomem *base; + char const *name; + bool is_off; + struct generic_pm_domain pd; +}; + +static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct exynos_pm_domain *pd; + void __iomem *base; + u32 timeout, pwr; + char *op; + + pd = container_of(domain, struct exynos_pm_domain, pd); + base = pd->base; + + pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; + __raw_writel(pwr, base); + + /* Wait max 1ms */ + timeout = 10; + + while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN) != pwr) { + if (!timeout) { + op = (power_on) ? "enable" : "disable"; + pr_err("Power domain %s %s failed\n", domain->name, op); + return -ETIMEDOUT; + } + timeout--; + cpu_relax(); + usleep_range(80, 100); + } + return 0; +} + +static int exynos_pd_power_on(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, true); +} + +static int exynos_pd_power_off(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, false); +} + +#define EXYNOS_GPD(PD, BASE, NAME) \ +static struct exynos_pm_domain PD = { \ + .base = (void __iomem *)BASE, \ + .name = NAME, \ + .pd = { \ + .power_off = exynos_pd_power_off, \ + .power_on = exynos_pd_power_on, \ + }, \ +} + +#ifdef CONFIG_OF +static __init int exynos_pm_dt_parse_domains(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + struct exynos_pm_domain *pd; + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + pr_err("%s: failed to allocate memory for domain\n", + __func__); + return -ENOMEM; + } + + if (of_get_property(np, "samsung,exynos4210-pd-off", NULL)) + pd->is_off = true; + pd->name = np->name; + pd->base = of_iomap(np, 0); + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->pd.of_node = np; + pm_genpd_init(&pd->pd, NULL, false); + } + return 0; +} +#else +static __init int exynos_pm_dt_parse_domains(void) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev, + struct exynos_pm_domain *pd) +{ + if (pdev->dev.bus) { + if (pm_genpd_add_device(&pd->pd, &pdev->dev)) + pr_info("%s: error in adding %s device to %s power" + "domain\n", __func__, dev_name(&pdev->dev), + pd->name); + } +} + +EXYNOS_GPD(exynos4_pd_mfc, S5P_PMU_MFC_CONF, "pd-mfc"); +EXYNOS_GPD(exynos4_pd_g3d, S5P_PMU_G3D_CONF, "pd-g3d"); +EXYNOS_GPD(exynos4_pd_lcd0, S5P_PMU_LCD0_CONF, "pd-lcd0"); +EXYNOS_GPD(exynos4_pd_lcd1, S5P_PMU_LCD1_CONF, "pd-lcd1"); +EXYNOS_GPD(exynos4_pd_tv, S5P_PMU_TV_CONF, "pd-tv"); +EXYNOS_GPD(exynos4_pd_cam, S5P_PMU_CAM_CONF, "pd-cam"); +EXYNOS_GPD(exynos4_pd_gps, S5P_PMU_GPS_CONF, "pd-gps"); + +static struct exynos_pm_domain *exynos4_pm_domains[] = { + &exynos4_pd_mfc, + &exynos4_pd_g3d, + &exynos4_pd_lcd0, + &exynos4_pd_lcd1, + &exynos4_pd_tv, + &exynos4_pd_cam, + &exynos4_pd_gps, +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + int idx; + + if (of_have_populated_dt()) + return exynos_pm_dt_parse_domains(); + + for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++) + pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL, + exynos4_pm_domains[idx]->is_off); + +#ifdef CONFIG_S5P_DEV_FIMD0 + exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0); +#endif +#ifdef CONFIG_S5P_DEV_TV + exynos_pm_add_dev_to_genpd(&s5p_device_hdmi, &exynos4_pd_tv); + exynos_pm_add_dev_to_genpd(&s5p_device_mixer, &exynos4_pd_tv); +#endif +#ifdef CONFIG_S5P_DEV_MFC + exynos_pm_add_dev_to_genpd(&s5p_device_mfc, &exynos4_pd_mfc); +#endif +#ifdef CONFIG_S5P_DEV_FIMC0 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC1 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc1, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC2 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc2, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC3 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc3, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS0 + exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS1 + exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam); +#endif + return 0; +} +arch_initcall(exynos4_pm_init_power_domain); + +static __init int exynos_pm_late_initcall(void) +{ + pm_genpd_poweroff_unused(); + return 0; +} +late_initcall(exynos_pm_late_initcall); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 4defb97bbfc8..3919fba52ac8 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -46,7 +46,6 @@ config SOC_IMX21 bool select MACH_MX21 select CPU_ARM926T - select ARCH_MXC_AUDMUX_V1 select IMX_HAVE_DMA_V1 select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -55,7 +54,6 @@ config SOC_IMX25 bool select ARCH_MX25 select CPU_ARM926T - select ARCH_MXC_AUDMUX_V2 select ARCH_MXC_IOMUX_V3 select MXC_AVIC @@ -63,7 +61,6 @@ config SOC_IMX27 bool select MACH_MX27 select CPU_ARM926T - select ARCH_MXC_AUDMUX_V1 select IMX_HAVE_DMA_V1 select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -72,7 +69,6 @@ config SOC_IMX31 bool select CPU_V6 select IMX_HAVE_PLATFORM_MXC_RNGA - select ARCH_MXC_AUDMUX_V2 select MXC_AVIC select SMP_ON_UP if SMP @@ -80,7 +76,6 @@ config SOC_IMX35 bool select CPU_V6 select ARCH_MXC_IOMUX_V3 - select ARCH_MXC_AUDMUX_V2 select HAVE_EPIT select MXC_AVIC select SMP_ON_UP if SMP @@ -89,7 +84,6 @@ config SOC_IMX5 select CPU_V7 select MXC_TZIC select ARCH_MXC_IOMUX_V3 - select ARCH_MXC_AUDMUX_V2 select ARCH_HAS_CPUFREQ select ARCH_MX5 bool diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c index 5db3e1463af7..5f2f91d1798b 100644 --- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c @@ -32,7 +32,6 @@ #include <mach/common.h> #include <mach/iomux-mx27.h> #include <mach/hardware.h> -#include <mach/audmux.h> #include "devices-imx27.h" @@ -306,25 +305,6 @@ void __init eukrea_mbimx27_baseboard_init(void) mxc_gpio_setup_multiple_pins(eukrea_mbimx27_pins, ARRAY_SIZE(eukrea_mbimx27_pins), "MBIMX27"); -#if defined(CONFIG_SND_SOC_EUKREA_TLV320) \ - || defined(CONFIG_SND_SOC_EUKREA_TLV320_MODULE) - /* SSI unit master I2S codec connected to SSI_PINS_4*/ - mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, - MXC_AUDMUX_V1_PCR_SYN | - MXC_AUDMUX_V1_PCR_TFSDIR | - MXC_AUDMUX_V1_PCR_TCLKDIR | - MXC_AUDMUX_V1_PCR_RFSDIR | - MXC_AUDMUX_V1_PCR_RCLKDIR | - MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | - MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | - MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) - ); - mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4, - MXC_AUDMUX_V1_PCR_SYN | - MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) - ); -#endif - imx27_add_imx_uart1(&uart_pdata); imx27_add_imx_uart2(&uart_pdata); #if !defined(MACH_EUKREA_CPUIMX27_USEUART4) diff --git a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c index d817fc80b986..aaa592fdb9ce 100644 --- a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c @@ -37,7 +37,6 @@ #include <mach/hardware.h> #include <mach/common.h> #include <mach/iomux-mx51.h> -#include <mach/audmux.h> #include "devices-imx51.h" diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c index 66e8726253fa..2cf603e11c4f 100644 --- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c @@ -31,7 +31,6 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/mx25.h> -#include <mach/audmux.h> #include "devices-imx25.h" @@ -241,22 +240,6 @@ void __init eukrea_mbimxsd25_baseboard_init(void) ARRAY_SIZE(eukrea_mbimxsd_pads))) printk(KERN_ERR "error setting mbimxsd pads !\n"); -#if defined(CONFIG_SND_SOC_EUKREA_TLV320) - /* SSI unit master I2S codec connected to SSI_AUD5*/ - mxc_audmux_v2_configure_port(0, - MXC_AUDMUX_V2_PTCR_SYN | - MXC_AUDMUX_V2_PTCR_TFSDIR | - MXC_AUDMUX_V2_PTCR_TFSEL(4) | - MXC_AUDMUX_V2_PTCR_TCLKDIR | - MXC_AUDMUX_V2_PTCR_TCSEL(4), - MXC_AUDMUX_V2_PDCR_RXDSEL(4) - ); - mxc_audmux_v2_configure_port(4, - MXC_AUDMUX_V2_PTCR_SYN, - MXC_AUDMUX_V2_PDCR_RXDSEL(0) - ); -#endif - imx25_add_imx_uart1(&uart_pdata); imx25_add_imx_fb(&eukrea_mximxsd_fb_pdata); imx25_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata); diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c index 0f0af02b3182..fd8bf8a425a7 100644 --- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c @@ -38,7 +38,6 @@ #include <mach/hardware.h> #include <mach/common.h> #include <mach/iomux-mx35.h> -#include <mach/audmux.h> #include "devices-imx35.h" @@ -252,22 +251,6 @@ void __init eukrea_mbimxsd35_baseboard_init(void) ARRAY_SIZE(eukrea_mbimxsd_pads))) printk(KERN_ERR "error setting mbimxsd pads !\n"); -#if defined(CONFIG_SND_SOC_EUKREA_TLV320) - /* SSI unit master I2S codec connected to SSI_AUD4 */ - mxc_audmux_v2_configure_port(0, - MXC_AUDMUX_V2_PTCR_SYN | - MXC_AUDMUX_V2_PTCR_TFSDIR | - MXC_AUDMUX_V2_PTCR_TFSEL(3) | - MXC_AUDMUX_V2_PTCR_TCLKDIR | - MXC_AUDMUX_V2_PTCR_TCSEL(3), - MXC_AUDMUX_V2_PDCR_RXDSEL(3) - ); - mxc_audmux_v2_configure_port(3, - MXC_AUDMUX_V2_PTCR_SYN, - MXC_AUDMUX_V2_PDCR_RXDSEL(0) - ); -#endif - imx35_add_imx_uart1(&uart_pdata); imx35_add_ipu_core(&mx3_ipu_data); imx35_add_mx3_sdc_fb(&mx3fb_pdata); diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index e6bad17b908c..1e03ef42faa0 100644 --- a/arch/arm/mach-imx/imx51-dt.c +++ b/arch/arm/mach-imx/imx51-dt.c @@ -47,7 +47,7 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = { static int __init imx51_tzic_add_irq_domain(struct device_node *np, struct device_node *interrupt_parent) { - irq_domain_add_simple(np, 0); + irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); return 0; } @@ -57,7 +57,7 @@ static int __init imx51_gpio_add_irq_domain(struct device_node *np, static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS; gpio_irq_base -= 32; - irq_domain_add_simple(np, gpio_irq_base); + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); return 0; } diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c index 05ebb3e68679..fd5be0f20fbb 100644 --- a/arch/arm/mach-imx/imx53-dt.c +++ b/arch/arm/mach-imx/imx53-dt.c @@ -51,7 +51,7 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = { static int __init imx53_tzic_add_irq_domain(struct device_node *np, struct device_node *interrupt_parent) { - irq_domain_add_simple(np, 0); + irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); return 0; } @@ -61,7 +61,7 @@ static int __init imx53_gpio_add_irq_domain(struct device_node *np, static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS; gpio_irq_base -= 32; - irq_domain_add_simple(np, gpio_irq_base); + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); return 0; } diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c index c2766ae02b4f..428459fbca4b 100644 --- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@ -263,6 +263,7 @@ static void __init visstrim_m10_board_init(void) imx27_add_fec(NULL); imx_add_gpio_keys(&visstrim_gpio_keys_platform_data); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx_add_platform_device("mx27vis", 0, NULL, 0, NULL, 0); } static void __init visstrim_m10_timer_init(void) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index c25728106917..6075d4d62dd6 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -97,7 +97,8 @@ static int __init imx6q_gpio_add_irq_domain(struct device_node *np, static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS; gpio_irq_base -= 32; - irq_domain_add_simple(np, gpio_irq_base); + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, + NULL); return 0; } diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c index d3b9c6b5edde..541152e450c4 100644 --- a/arch/arm/mach-imx/mach-pca100.c +++ b/arch/arm/mach-imx/mach-pca100.c @@ -36,7 +36,6 @@ #include <mach/hardware.h> #include <mach/iomux-mx27.h> #include <asm/mach/time.h> -#include <mach/audmux.h> #include <mach/irqs.h> #include <mach/ulpi.h> @@ -359,18 +358,6 @@ static void __init pca100_init(void) imx27_soc_init(); - /* SSI unit */ - mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, - MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */ - MXC_AUDMUX_V1_PCR_TFCSEL(3) | - MXC_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */ - MXC_AUDMUX_V1_PCR_RXDSEL(3)); - mxc_audmux_v1_configure_port(3, - MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */ - MXC_AUDMUX_V1_PCR_TFCSEL(0) | - MXC_AUDMUX_V1_PCR_TFSDIR | - MXC_AUDMUX_V1_PCR_RXDSEL(0)); - ret = mxc_gpio_setup_multiple_pins(pca100_pins, ARRAY_SIZE(pca100_pins), "PCA100"); if (ret) diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index e48854b9d990..5fddf94cc969 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -32,6 +32,8 @@ #include <linux/usb/ulpi.h> #include <linux/gfp.h> #include <linux/memblock.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> #include <media/soc_camera.h> @@ -570,6 +572,11 @@ static int __init pcm037_otg_mode(char *options) } __setup("otg_mode=", pcm037_otg_mode); +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vdd33a", "smsc911x"), + REGULATOR_SUPPLY("vddvario", "smsc911x"), +}; + /* * Board specific initialization. */ @@ -579,6 +586,8 @@ static void __init pcm037_init(void) imx31_soc_init(); + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + mxc_iomux_set_gpr(MUX_PGP_UH2, 1); mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins), diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c index 06dc106519ae..237474fcca23 100644 --- a/arch/arm/mach-imx/mach-pcm043.c +++ b/arch/arm/mach-imx/mach-pcm043.c @@ -37,7 +37,6 @@ #include <mach/common.h> #include <mach/iomux-mx35.h> #include <mach/ulpi.h> -#include <mach/audmux.h> #include "devices-imx35.h" @@ -362,18 +361,6 @@ static void __init pcm043_init(void) mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads)); - mxc_audmux_v2_configure_port(3, - MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ - MXC_AUDMUX_V2_PTCR_TFSEL(0) | - MXC_AUDMUX_V2_PTCR_TFSDIR, - MXC_AUDMUX_V2_PDCR_RXDSEL(0)); - - mxc_audmux_v2_configure_port(0, - MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ - MXC_AUDMUX_V2_PTCR_TCSEL(3) | - MXC_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */ - MXC_AUDMUX_V2_PDCR_RXDSEL(3)); - imx35_add_fec(NULL); platform_add_devices(devices, ARRAY_SIZE(devices)); imx35_add_imx2_wdt(NULL); diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c index 3f05dfebacc9..14d540edfd1e 100644 --- a/arch/arm/mach-imx/mm-imx21.c +++ b/arch/arm/mach-imx/mm-imx21.c @@ -75,6 +75,10 @@ void __init mx21_init_irq(void) mxc_init_irq(MX21_IO_ADDRESS(MX21_AVIC_BASE_ADDR)); } +static const struct resource imx21_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX21_AUDMUX_BASE_ADDR, SZ_4K), +}; + void __init imx21_soc_init(void) { mxc_register_gpio("imx21-gpio", 0, MX21_GPIO1_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0); @@ -85,4 +89,6 @@ void __init imx21_soc_init(void) mxc_register_gpio("imx21-gpio", 5, MX21_GPIO6_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0); imx_add_imx_dma(); + platform_device_register_simple("imx21-audmux", 0, imx21_audmux_res, + ARRAY_SIZE(imx21_audmux_res)); } diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c index cc4d152bd9bd..153b457acdc0 100644 --- a/arch/arm/mach-imx/mm-imx25.c +++ b/arch/arm/mach-imx/mm-imx25.c @@ -83,6 +83,10 @@ static struct sdma_platform_data imx25_sdma_pdata __initdata = { .script_addrs = &imx25_sdma_script, }; +static const struct resource imx25_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX25_AUDMUX_BASE_ADDR, SZ_16K), +}; + void __init imx25_soc_init(void) { /* i.mx25 has the i.mx31 type gpio */ @@ -93,4 +97,7 @@ void __init imx25_soc_init(void) /* i.mx25 has the i.mx35 type sdma */ imx_add_imx_sdma("imx35-sdma", MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata); + /* i.mx25 has the i.mx31 type audmux */ + platform_device_register_simple("imx31-audmux", 0, imx25_audmux_res, + ARRAY_SIZE(imx25_audmux_res)); } diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c index 96dd1f5ea7bd..8cb3f5e3e569 100644 --- a/arch/arm/mach-imx/mm-imx27.c +++ b/arch/arm/mach-imx/mm-imx27.c @@ -75,6 +75,10 @@ void __init mx27_init_irq(void) mxc_init_irq(MX27_IO_ADDRESS(MX27_AVIC_BASE_ADDR)); } +static const struct resource imx27_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX27_AUDMUX_BASE_ADDR, SZ_4K), +}; + void __init imx27_soc_init(void) { /* i.mx27 has the i.mx21 type gpio */ @@ -86,4 +90,7 @@ void __init imx27_soc_init(void) mxc_register_gpio("imx21-gpio", 5, MX27_GPIO6_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0); imx_add_imx_dma(); + /* imx27 has the imx21 type audmux */ + platform_device_register_simple("imx21-audmux", 0, imx27_audmux_res, + ARRAY_SIZE(imx27_audmux_res)); } diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c index 31807d2a8b7b..2530c151b7b3 100644 --- a/arch/arm/mach-imx/mm-imx3.c +++ b/arch/arm/mach-imx/mm-imx3.c @@ -158,6 +158,10 @@ static struct sdma_platform_data imx31_sdma_pdata __initdata = { .script_addrs = &imx31_to2_sdma_script, }; +static const struct resource imx31_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX31_AUDMUX_BASE_ADDR, SZ_16K), +}; + void __init imx31_soc_init(void) { int to_version = mx31_revision() >> 4; @@ -175,6 +179,8 @@ void __init imx31_soc_init(void) } imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata); + platform_device_register_simple("imx31-audmux", 0, imx31_audmux_res, + ARRAY_SIZE(imx31_audmux_res)); } #endif /* ifdef CONFIG_SOC_IMX31 */ @@ -241,6 +247,10 @@ static struct sdma_platform_data imx35_sdma_pdata __initdata = { .script_addrs = &imx35_to2_sdma_script, }; +static const struct resource imx35_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX35_AUDMUX_BASE_ADDR, SZ_16K), +}; + void __init imx35_soc_init(void) { int to_version = mx35_revision() >> 4; @@ -259,5 +269,8 @@ void __init imx35_soc_init(void) } imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata); + /* i.mx35 has the i.mx31 type audmux */ + platform_device_register_simple("imx31-audmux", 0, imx35_audmux_res, + ARRAY_SIZE(imx35_audmux_res)); } #endif /* ifdef CONFIG_SOC_IMX35 */ diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index bc17dfea3817..90d7880bb372 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -170,6 +170,18 @@ static struct sdma_platform_data imx53_sdma_pdata __initdata = { .script_addrs = &imx53_sdma_script, }; +static const struct resource imx50_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX50_AUDMUX_BASE_ADDR, SZ_16K), +}; + +static const struct resource imx51_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX51_AUDMUX_BASE_ADDR, SZ_16K), +}; + +static const struct resource imx53_audmux_res[] __initconst = { + DEFINE_RES_MEM(MX53_AUDMUX_BASE_ADDR, SZ_16K), +}; + void __init imx50_soc_init(void) { /* i.mx50 has the i.mx31 type gpio */ @@ -179,6 +191,10 @@ void __init imx50_soc_init(void) mxc_register_gpio("imx31-gpio", 3, MX50_GPIO4_BASE_ADDR, SZ_16K, MX50_INT_GPIO4_LOW, MX50_INT_GPIO4_HIGH); mxc_register_gpio("imx31-gpio", 4, MX50_GPIO5_BASE_ADDR, SZ_16K, MX50_INT_GPIO5_LOW, MX50_INT_GPIO5_HIGH); mxc_register_gpio("imx31-gpio", 5, MX50_GPIO6_BASE_ADDR, SZ_16K, MX50_INT_GPIO6_LOW, MX50_INT_GPIO6_HIGH); + + /* i.mx50 has the i.mx31 type audmux */ + platform_device_register_simple("imx31-audmux", 0, imx50_audmux_res, + ARRAY_SIZE(imx50_audmux_res)); } void __init imx51_soc_init(void) @@ -191,6 +207,9 @@ void __init imx51_soc_init(void) /* i.mx51 has the i.mx35 type sdma */ imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata); + /* i.mx51 has the i.mx31 type audmux */ + platform_device_register_simple("imx31-audmux", 0, imx51_audmux_res, + ARRAY_SIZE(imx51_audmux_res)); } void __init imx53_soc_init(void) @@ -206,4 +225,7 @@ void __init imx53_soc_init(void) /* i.mx53 has the i.mx35 type sdma */ imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata); + /* i.mx53 has the i.mx31 type audmux */ + platform_device_register_simple("imx31-audmux", 0, imx53_audmux_res, + ARRAY_SIZE(imx53_audmux_res)); } diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c index 01f8c8992880..7e99c3f340fc 100644 --- a/arch/arm/mach-kirkwood/openrd-setup.c +++ b/arch/arm/mach-kirkwood/openrd-setup.c @@ -83,6 +83,11 @@ static struct i2c_board_info i2c_board_info[] __initdata = { }, }; +static struct platform_device openrd_client_audio_device = { + .name = "openrd-client-audio", + .id = -1, +}; + static int __initdata uart1; static int __init sd_uart_selection(char *str) @@ -172,6 +177,7 @@ static void __init openrd_init(void) kirkwood_i2c_init(); if (machine_is_openrd_client() || machine_is_openrd_ultimate()) { + platform_device_register(&openrd_client_audio_device); i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info)); kirkwood_audio_init(); diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c index 966b2b3bb813..f9d2a11b7f96 100644 --- a/arch/arm/mach-kirkwood/t5325-setup.c +++ b/arch/arm/mach-kirkwood/t5325-setup.c @@ -106,6 +106,11 @@ static struct platform_device hp_t5325_button_device = { } }; +static struct platform_device hp_t5325_audio_device = { + .name = "t5325-audio", + .id = -1, +}; + static unsigned int hp_t5325_mpp_config[] __initdata = { MPP0_NF_IO2, MPP1_SPI_MOSI, @@ -179,6 +184,7 @@ static void __init hp_t5325_init(void) kirkwood_sata_init(&hp_t5325_sata_data); kirkwood_ehci_init(); platform_device_register(&hp_t5325_button_device); + platform_device_register(&hp_t5325_audio_device); i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info)); kirkwood_audio_init(); diff --git a/arch/arm/mach-ks8695/leds.c b/arch/arm/mach-ks8695/leds.c index d6f6502ac9b5..4bd707547293 100644 --- a/arch/arm/mach-ks8695/leds.c +++ b/arch/arm/mach-ks8695/leds.c @@ -11,7 +11,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/gpio.h> #include <asm/leds.h> #include <mach/devices.h> diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index 0a113424632c..962e71169750 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -80,12 +80,8 @@ static struct of_device_id msm_dt_gic_match[] __initdata = { static void __init msm8x60_dt_init(void) { - struct device_node *node; - - node = of_find_matching_node_by_address(NULL, msm_dt_gic_match, - MSM8X60_QGIC_DIST_PHYS); - if (node) - irq_domain_add_simple(node, GIC_SPI_START); + irq_domain_generate_simple(msm_dt_gic_match, MSM8X60_QGIC_DIST_PHYS, + GIC_SPI_START); if (of_machine_is_compatible("qcom,msm8660-surf")) { printk(KERN_INFO "Init surf UART registers\n"); diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 4f8d66f044e7..922ab0dc2bcd 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -37,7 +37,6 @@ comment "OMAP Board Type" config MACH_OMAP_INNOVATOR bool "TI Innovator" depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX) - select OMAP_MCBSP help TI OMAP 1510 or 1610 Innovator board support. Say Y here if you have such a board. @@ -45,7 +44,6 @@ config MACH_OMAP_INNOVATOR config MACH_OMAP_H2 bool "TI H2 Support" depends on ARCH_OMAP1 && ARCH_OMAP16XX - select OMAP_MCBSP help TI OMAP 1610/1611B H2 board support. Say Y here if you have such a board. @@ -72,7 +70,6 @@ config MACH_HERALD config MACH_OMAP_OSK bool "TI OSK Support" depends on ARCH_OMAP1 && ARCH_OMAP16XX - select OMAP_MCBSP help TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here if you have such a board. diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 11c85cd2731a..9923f92b5450 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -6,7 +6,9 @@ obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o -obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o +ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),) +obj-y += mcbsp.o +endif obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index 1d76a63c0983..187b2fe132e9 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -28,7 +28,6 @@ #include <plat/mux.h> #include <plat/mmc.h> #include <plat/omap7xx.h> -#include <plat/mcbsp.h> #include "clock.h" @@ -250,16 +249,8 @@ static struct platform_device omap_pcm = { .id = -1, }; -OMAP_MCBSP_PLATFORM_DEVICE(1); -OMAP_MCBSP_PLATFORM_DEVICE(2); -OMAP_MCBSP_PLATFORM_DEVICE(3); - static void omap_init_audio(void) { - platform_device_register(&omap_mcbsp1); - platform_device_register(&omap_mcbsp2); - if (!cpu_is_omap7xx()) - platform_device_register(&omap_mcbsp3); platform_device_register(&omap_pcm); } diff --git a/arch/arm/mach-omap1/lcd_dma.c b/arch/arm/mach-omap1/lcd_dma.c index 453809359ba6..4c5ce7d829c2 100644 --- a/arch/arm/mach-omap1/lcd_dma.c +++ b/arch/arm/mach-omap1/lcd_dma.c @@ -117,7 +117,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror); void omap_set_lcd_dma_b1_vxres(unsigned long vxres) { if (cpu_is_omap15xx()) { - printk(KERN_ERR "DMA virtual resulotion is not supported " + printk(KERN_ERR "DMA virtual resolution is not supported " "in 1510 mode\n"); BUG(); } diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c index 91f9abbd3250..3e8410a99990 100644 --- a/arch/arm/mach-omap1/mcbsp.c +++ b/arch/arm/mach-omap1/mcbsp.c @@ -420,18 +420,6 @@ static int __init omap1_mcbsp_init(void) return -ENODEV; if (cpu_is_omap7xx()) - omap_mcbsp_count = OMAP7XX_MCBSP_COUNT; - else if (cpu_is_omap15xx()) - omap_mcbsp_count = OMAP15XX_MCBSP_COUNT; - else if (cpu_is_omap16xx()) - omap_mcbsp_count = OMAP16XX_MCBSP_COUNT; - - mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), - GFP_KERNEL); - if (!mcbsp_ptr) - return -ENOMEM; - - if (cpu_is_omap7xx()) omap_mcbsp_register_board_cfg(omap7xx_mcbsp_res_0, OMAP7XX_MCBSP_RES_SZ, omap7xx_mcbsp_pdata, @@ -449,7 +437,7 @@ static int __init omap1_mcbsp_init(void) omap16xx_mcbsp_pdata, OMAP16XX_MCBSP_COUNT); - return omap_mcbsp_init(); + return 0; } arch_initcall(omap1_mcbsp_init); diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index bd76394ccaf8..06326a6e460d 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -17,7 +17,9 @@ obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common) obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common) -obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o +ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),) +obj-y += mcbsp.o +endif obj-$(CONFIG_TWL4030_CORE) += omap_twl.o diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 4e9071589bfb..90c76d340fb3 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -41,6 +41,7 @@ #include <video/omap-panel-nokia-dsi.h> #include <video/omap-panel-picodlp.h> #include <linux/wl12xx.h> +#include <linux/platform_data/omap-abe-twl6040.h> #include "mux.h" #include "hsmmc.h" @@ -378,12 +379,40 @@ static struct platform_device sdp4430_dmic_codec = { .id = -1, }; +static struct omap_abe_twl6040_data sdp4430_abe_audio_data = { + .card_name = "SDP4430", + .has_hs = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + .has_hf = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + .has_ep = 1, + .has_aux = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + .has_vibra = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + + .has_dmic = 1, + .has_hsmic = 1, + .has_mainmic = 1, + .has_submic = 1, + .has_afm = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + + .jack_detection = 1, + /* MCLK input is 38.4MHz */ + .mclk_freq = 38400000, +}; + +static struct platform_device sdp4430_abe_audio = { + .name = "omap-abe-twl6040", + .id = -1, + .dev = { + .platform_data = &sdp4430_abe_audio_data, + }, +}; + static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, &sdp4430_leds_pwm, &sdp4430_vbat, &sdp4430_dmic_codec, + &sdp4430_abe_audio, }; static struct omap_musb_board_data musb_board_data = { diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index ad497620539b..45fdfe2bd9d5 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -68,7 +68,7 @@ static void __init omap_generic_init(void) { struct device_node *node = of_find_matching_node(NULL, intc_match); if (node) - irq_domain_add_simple(node, 0); + irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL); omap_sdrc_init(NULL, NULL); diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 28fc271f7031..e4415917693f 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -28,6 +28,7 @@ #include <linux/regulator/machine.h> #include <linux/regulator/fixed.h> #include <linux/wl12xx.h> +#include <linux/platform_data/omap-abe-twl6040.h> #include <mach/hardware.h> #include <asm/hardware/gic.h> @@ -91,9 +92,34 @@ static struct platform_device leds_gpio = { }, }; +static struct omap_abe_twl6040_data panda_abe_audio_data = { + /* Audio out */ + .has_hs = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + /* HandsFree through expasion connector */ + .has_hf = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + /* PandaBoard: FM TX, PandaBoardES: can be connected to audio out */ + .has_aux = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + /* PandaBoard: FM RX, PandaBoardES: audio in */ + .has_afm = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT, + /* No jack detection. */ + .jack_detection = 0, + /* MCLK input is 38.4MHz */ + .mclk_freq = 38400000, + +}; + +static struct platform_device panda_abe_audio = { + .name = "omap-abe-twl6040", + .id = -1, + .dev = { + .platform_data = &panda_abe_audio_data, + }, +}; + static struct platform_device *panda_devices[] __initdata = { &leds_gpio, &wl1271_device, + &panda_abe_audio, }; static const struct usbhs_omap_board_data usbhs_bdata __initconst = { @@ -252,8 +278,25 @@ static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers) return 0; } +static struct twl4030_codec_data twl6040_codec = { + /* single-step ramp for headset and handsfree */ + .hs_left_step = 0x0f, + .hs_right_step = 0x0f, + .hf_left_step = 0x1d, + .hf_right_step = 0x1d, +}; + +static struct twl4030_audio_data twl6040_audio = { + .codec = &twl6040_codec, + .audpwron_gpio = 127, + .naudint_irq = OMAP44XX_IRQ_SYS_2N, + .irq_base = TWL6040_CODEC_IRQ_BASE, +}; + /* Panda board uses the common PMIC configuration */ -static struct twl4030_platform_data omap4_panda_twldata; +static struct twl4030_platform_data omap4_panda_twldata = { + .audio = &twl6040_audio, +}; /* * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM @@ -485,6 +528,20 @@ void omap4_panda_display_init(void) omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); } +static void omap4_panda_init_rev(void) +{ + if (cpu_is_omap443x()) { + /* PandaBoard 4430 */ + /* ASoC audio configuration */ + panda_abe_audio_data.card_name = "PandaBoard"; + panda_abe_audio_data.has_hsmic = 1; + } else { + /* PandaBoard ES */ + /* ASoC audio configuration */ + panda_abe_audio_data.card_name = "PandaBoardES"; + } +} + static void __init omap4_panda_init(void) { int package = OMAP_PACKAGE_CBS; @@ -498,6 +555,7 @@ static void __init omap4_panda_init(void) if (ret) pr_err("error setting wl12xx data: %d\n", ret); + omap4_panda_init_rev(); omap4_panda_i2c_init(); platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices)); platform_device_register(&omap_vwlan_device); diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 283d11eae693..e9fae652cd04 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -26,7 +26,6 @@ #include <plat/tc.h> #include <plat/board.h> -#include <plat/mcbsp.h> #include <plat/mmc.h> #include <plat/dma.h> #include <plat/omap_hwmod.h> @@ -304,29 +303,8 @@ static struct platform_device omap_pcm = { .id = -1, }; -/* - * OMAP2420 has 2 McBSP ports - * OMAP2430 has 5 McBSP ports - * OMAP3 has 5 McBSP ports - * OMAP4 has 4 McBSP ports - */ -OMAP_MCBSP_PLATFORM_DEVICE(1); -OMAP_MCBSP_PLATFORM_DEVICE(2); -OMAP_MCBSP_PLATFORM_DEVICE(3); -OMAP_MCBSP_PLATFORM_DEVICE(4); -OMAP_MCBSP_PLATFORM_DEVICE(5); - static void omap_init_audio(void) { - platform_device_register(&omap_mcbsp1); - platform_device_register(&omap_mcbsp2); - if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) { - platform_device_register(&omap_mcbsp3); - platform_device_register(&omap_mcbsp4); - } - if (cpu_is_omap243x() || cpu_is_omap34xx()) - platform_device_register(&omap_mcbsp5); - platform_device_register(&omap_pcm); } diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index fb4bcf81a183..ecc039e794db 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -34,7 +34,7 @@ #include "cm2xxx_3xxx.h" #include "cm-regbits-34xx.h" -/* McBSP internal signal muxing function */ +/* McBSP1 internal signal muxing function for OMAP2/3 */ static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal, const char *src) { @@ -65,6 +65,42 @@ static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal, return 0; } +/* McBSP4 internal signal muxing function for OMAP4 */ +#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX (1 << 31) +#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX (1 << 30) +static int omap4_mcbsp4_mux_rx_clk(struct device *dev, const char *signal, + const char *src) +{ + u32 v; + + /* + * In CONTROL_MCBSPLP register only bit 30 (CLKR mux), and bit 31 (FSR + * mux) is used */ + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP); + + if (!strcmp(signal, "clkr")) { + if (!strcmp(src, "clkr")) + v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX; + else if (!strcmp(src, "clkx")) + v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX; + else + return -EINVAL; + } else if (!strcmp(signal, "fsr")) { + if (!strcmp(src, "fsr")) + v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX; + else if (!strcmp(src, "fsx")) + v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX; + else + return -EINVAL; + } else { + return -EINVAL; + } + + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP); + + return 0; +} + /* McBSP CLKS source switching function */ static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk, const char *src) @@ -146,9 +182,15 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused) pdata->has_ccr = true; } pdata->set_clk_src = omap2_mcbsp_set_clk_src; - if (id == 1) + + /* On OMAP2/3 the McBSP1 port has 6 pin configuration */ + if (id == 1 && oh->class->rev < MCBSP_CONFIG_TYPE4) pdata->mux_signal = omap2_mcbsp1_mux_rx_clk; + /* On OMAP4 the McBSP4 port has 6 pin configuration */ + if (id == 4 && oh->class->rev == MCBSP_CONFIG_TYPE4) + pdata->mux_signal = omap4_mcbsp4_mux_rx_clk; + if (oh->class->rev == MCBSP_CONFIG_TYPE3) { if (id == 2) /* The FIFO has 1024 + 256 locations */ @@ -180,7 +222,6 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused) name, oh->name); return PTR_ERR(pdev); } - omap_mcbsp_count++; return 0; } @@ -188,11 +229,6 @@ static int __init omap2_mcbsp_init(void) { omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL); - mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), - GFP_KERNEL); - if (!mcbsp_ptr) - return -ENOMEM; - - return omap_mcbsp_init(); + return 0; } arch_initcall(omap2_mcbsp_init); diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c index a104d5a80e11..e52108c9aaea 100644 --- a/arch/arm/mach-orion5x/db88f5281-setup.c +++ b/arch/arm/mach-orion5x/db88f5281-setup.c @@ -214,7 +214,7 @@ void __init db88f5281_pci_preinit(void) if (gpio_direction_input(pin) == 0) { irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); } else { - printk(KERN_ERR "db88f5281_pci_preinit faield to " + printk(KERN_ERR "db88f5281_pci_preinit failed to " "set_irq_type pin %d\n", pin); gpio_free(pin); } @@ -227,7 +227,7 @@ void __init db88f5281_pci_preinit(void) if (gpio_direction_input(pin) == 0) { irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); } else { - printk(KERN_ERR "db88f5281_pci_preinit faield " + printk(KERN_ERR "db88f5281_pci_preinit failed " "to set_irq_type pin %d\n", pin); gpio_free(pin); } diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c index 96438b6b2022..e3ce61711478 100644 --- a/arch/arm/mach-orion5x/rd88f5182-setup.c +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c @@ -149,7 +149,7 @@ void __init rd88f5182_pci_preinit(void) if (gpio_direction_input(pin) == 0) { irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); } else { - printk(KERN_ERR "rd88f5182_pci_preinit faield to " + printk(KERN_ERR "rd88f5182_pci_preinit failed to " "set_irq_type pin %d\n", pin); gpio_free(pin); } @@ -162,7 +162,7 @@ void __init rd88f5182_pci_preinit(void) if (gpio_direction_input(pin) == 0) { irq_set_irq_type(gpio_to_irq(pin), IRQ_TYPE_LEVEL_LOW); } else { - printk(KERN_ERR "rd88f5182_pci_preinit faield to " + printk(KERN_ERR "rd88f5182_pci_preinit failed to " "set_irq_type pin %d\n", pin); gpio_free(pin); } diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index d93ceef4a50a..37c2de9b6f26 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -68,7 +68,7 @@ void __init sirfsoc_of_irq_init(void) if (!sirfsoc_intc_base) panic("unable to map intc cpu registers\n"); - irq_domain_add_simple(np, 0); + irq_domain_add_legacy(np, 32, 0, 0, &irq_domain_simple_ops, NULL); of_node_put(np); diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index cd3c97e2ee75..32a30f38ba0c 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -102,6 +102,7 @@ static struct wm8962_pdata wm8962_pdata __initdata = { 0x8000 | WM8962_GPIO_FN_DMICDAT, WM8962_GPIO_FN_IRQ, /* Open drain mode */ }, + .in4_dc_measure = true, }; static struct wm9081_pdata wm9081_pdata __initdata = { diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index b4718b00e827..8f6da7f134b3 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -737,26 +737,18 @@ fsi_set_rate_end: return ret; } -static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) -{ - int ret; - - if (is_porta) - ret = fsi_ak4642_set_rate(dev, rate, enable); - else - ret = fsi_hdmi_set_rate(dev, rate, enable); - - return ret; -} - static struct sh_fsi_platform_info fsi_info = { - .porta_flags = SH_FSI_BRS_INV, - - .portb_flags = SH_FSI_BRS_INV | - SH_FSI_BRM_INV | - SH_FSI_LRS_INV | - SH_FSI_FMT_SPDIF, - .set_rate = fsi_set_rate, + .port_a = { + .flags = SH_FSI_BRS_INV, + .set_rate = fsi_ak4642_set_rate, + }, + .port_b = { + .flags = SH_FSI_BRS_INV | + SH_FSI_BRM_INV | + SH_FSI_LRS_INV | + SH_FSI_FMT_SPDIF, + .set_rate = fsi_hdmi_set_rate, + }, }; static struct resource fsi_resources[] = { diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 7b53cda41851..d99e780dffca 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -860,7 +860,7 @@ static int __fsi_set_round_rate(struct clk *clk, long rate, int enable) return clk_enable(clk); } -static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) +static int fsi_b_set_rate(struct device *dev, int rate, int enable) { struct clk *fsib_clk; struct clk *fdiv_clk = &sh7372_fsidivb_clk; @@ -869,10 +869,6 @@ static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable) int ackmd_bpfmd; int ret; - /* FSIA is slave mode. nothing to do here */ - if (is_porta) - return 0; - /* clock start */ switch (rate) { case 44100: @@ -916,14 +912,16 @@ fsi_set_rate_end: } static struct sh_fsi_platform_info fsi_info = { - .porta_flags = SH_FSI_BRS_INV, - - .portb_flags = SH_FSI_BRS_INV | + .port_a = { + .flags = SH_FSI_BRS_INV, + }, + .port_b = { + .flags = SH_FSI_BRS_INV | SH_FSI_BRM_INV | SH_FSI_LRS_INV | SH_FSI_FMT_SPDIF, - - .set_rate = fsi_set_rate, + .set_rate = fsi_b_set_rate, + } }; static struct resource fsi_resources[] = { diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index a83cf51fc099..cccf91b8fae1 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1043,6 +1043,8 @@ void __init sh7372_add_standard_devices(void) sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device); sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device); sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device); + sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device); + sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device); } void __init sh7372_add_early_devices(void) diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index a5e46b4ade20..4f7f5182dd4d 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -469,7 +469,7 @@ void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs, if (pmx_driver.base) { ret = pmx_register(&pmx_driver); if (ret) - printk(KERN_ERR "padmux: registeration failed. err no" + printk(KERN_ERR "padmux: registration failed. err no" ": %d\n", ret); /* Free Mapping, device selection already done */ iounmap(pmx_driver.base); diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index 9004cf9f01bf..febaa6fcfb6a 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -303,6 +303,6 @@ void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs, ret = pmx_register(&pmx_driver); if (ret) - printk(KERN_ERR "padmux: registeration failed. err no: %d\n", + printk(KERN_ERR "padmux: registration failed. err no: %d\n", ret); } diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index ee29bef43074..deaaf199612c 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -550,6 +550,6 @@ void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs, ret = pmx_register(&pmx_driver); if (ret) - printk(KERN_ERR "padmux: registeration failed. err no: %d\n", + printk(KERN_ERR "padmux: registration failed. err no: %d\n", ret); } diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 1fa26d9a1a68..ea49bd93c6b9 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/io.h> +#include <linux/module.h> #include <mach/iomap.h> @@ -58,6 +59,7 @@ unsigned long long tegra_chip_uid(void) hi = fuse_readl(FUSE_UID_HIGH); return (hi << 32ull) | lo; } +EXPORT_SYMBOL(tegra_chip_uid); int tegra_sku_id(void) { diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c index 5140deeddf7b..a38f80238ea9 100644 --- a/arch/arm/mach-u300/i2c.c +++ b/arch/arm/mach-u300/i2c.c @@ -60,7 +60,6 @@ static struct regulator_consumer_supply supply_ldo_c[] = { */ static struct regulator_consumer_supply supply_ldo_d[] = { { - .dev = NULL, .supply = "vana15", /* Powers the SoC (CPU etc) */ }, }; @@ -92,7 +91,6 @@ static struct regulator_consumer_supply supply_ldo_k[] = { */ static struct regulator_consumer_supply supply_ldo_ext[] = { { - .dev = NULL, .supply = "vext", /* External power */ }, }; diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 02b7b9303f3b..008ce22b9a06 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -98,8 +98,11 @@ static const struct of_device_id sic_of_match[] __initconst = { void __init versatile_init_irq(void) { - vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0); - irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START); + struct device_node *np; + + np = of_find_matching_node_by_address(NULL, vic_of_match, + VERSATILE_VIC_BASE); + __vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np); writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c index d2852e1635b1..d130a5ece5d5 100644 --- a/arch/arm/mm/copypage-fa.c +++ b/arch/arm/mm/copypage-fa.c @@ -44,11 +44,11 @@ void fa_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); fa_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -58,7 +58,7 @@ void fa_copy_user_highpage(struct page *to, struct page *from, */ void fa_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -77,7 +77,7 @@ void fa_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns fa_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c index ac163de7dc01..49ee0c1a7209 100644 --- a/arch/arm/mm/copypage-feroceon.c +++ b/arch/arm/mm/copypage-feroceon.c @@ -72,17 +72,17 @@ void feroceon_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); flush_cache_page(vma, vaddr, page_to_pfn(from)); feroceon_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } void feroceon_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile ("\ mov r1, %2 \n\ mov r2, #0 \n\ @@ -102,7 +102,7 @@ void feroceon_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns feroceon_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v3.c b/arch/arm/mm/copypage-v3.c index f72303e1d804..3935bddd4769 100644 --- a/arch/arm/mm/copypage-v3.c +++ b/arch/arm/mm/copypage-v3.c @@ -42,11 +42,11 @@ void v3_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); v3_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -56,7 +56,7 @@ void v3_copy_user_highpage(struct page *to, struct page *from, */ void v3_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\n\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -72,7 +72,7 @@ void v3_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v3_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 7d0a8c230342..ec8c3befb9c8 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -71,7 +71,7 @@ mc_copy_user_page(void *from, void *to) void v4_mc_copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr, struct vm_area_struct *vma) { - void *kto = kmap_atomic(to, KM_USER1); + void *kto = kmap_atomic(to); if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); @@ -85,7 +85,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from, raw_spin_unlock(&minicache_lock); - kunmap_atomic(kto, KM_USER1); + kunmap_atomic(kto); } /* @@ -93,7 +93,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from, */ void v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -111,7 +111,7 @@ void v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v4_mc_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c index cb589cbb2b6c..067d0fdd630c 100644 --- a/arch/arm/mm/copypage-v4wb.c +++ b/arch/arm/mm/copypage-v4wb.c @@ -52,12 +52,12 @@ void v4wb_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); flush_cache_page(vma, vaddr, page_to_pfn(from)); v4wb_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -67,7 +67,7 @@ void v4wb_copy_user_highpage(struct page *to, struct page *from, */ void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -86,7 +86,7 @@ void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v4wb_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c index 30c7d048a324..b85c5da2e510 100644 --- a/arch/arm/mm/copypage-v4wt.c +++ b/arch/arm/mm/copypage-v4wt.c @@ -48,11 +48,11 @@ void v4wt_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); v4wt_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -62,7 +62,7 @@ void v4wt_copy_user_highpage(struct page *to, struct page *from, */ void v4wt_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -79,7 +79,7 @@ void v4wt_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v4wt_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index 3d9a1552cef6..8b03a5814d00 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -38,11 +38,11 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to, { void *kto, *kfrom; - kfrom = kmap_atomic(from, KM_USER0); - kto = kmap_atomic(to, KM_USER1); + kfrom = kmap_atomic(from); + kto = kmap_atomic(to); copy_page(kto, kfrom); - kunmap_atomic(kto, KM_USER1); - kunmap_atomic(kfrom, KM_USER0); + kunmap_atomic(kto); + kunmap_atomic(kfrom); } /* @@ -51,9 +51,9 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to, */ static void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr) { - void *kaddr = kmap_atomic(page, KM_USER0); + void *kaddr = kmap_atomic(page); clear_page(kaddr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } /* diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index f9cde0702f1e..03a2042aced5 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -75,12 +75,12 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); flush_cache_page(vma, vaddr, page_to_pfn(from)); xsc3_mc_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -90,7 +90,7 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, */ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile ("\ mov r1, %2 \n\ mov r2, #0 \n\ @@ -105,7 +105,7 @@ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns xsc3_mc_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 610c24ced310..439d106ae638 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -93,7 +93,7 @@ mc_copy_user_page(void *from, void *to) void xscale_mc_copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr, struct vm_area_struct *vma) { - void *kto = kmap_atomic(to, KM_USER1); + void *kto = kmap_atomic(to); if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); @@ -107,7 +107,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from, raw_spin_unlock(&minicache_lock); - kunmap_atomic(kto, KM_USER1); + kunmap_atomic(kto); } /* @@ -116,7 +116,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from, void xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile( "mov r1, %2 \n\ mov r2, #0 \n\ @@ -133,7 +133,7 @@ xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3", "ip"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns xscale_mc_user_fns __initdata = { diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 807c0573abbe..5a21505d7550 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -36,7 +36,7 @@ void kunmap(struct page *page) } EXPORT_SYMBOL(kunmap); -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned int idx; unsigned long vaddr; @@ -81,7 +81,7 @@ void *__kmap_atomic(struct page *page) return (void *)vaddr; } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 5dc7d127a40f..245a55a0a5bb 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -32,7 +32,6 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <asm/memblock.h> #include "mm.h" diff --git a/arch/arm/plat-mxc/3ds_debugboard.c b/arch/arm/plat-mxc/3ds_debugboard.c index f0ba0726306c..d1e31fa1b0c3 100644 --- a/arch/arm/plat-mxc/3ds_debugboard.c +++ b/arch/arm/plat-mxc/3ds_debugboard.c @@ -16,6 +16,8 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/smsc911x.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> #include <mach/hardware.h> @@ -148,6 +150,11 @@ static struct irq_chip expio_irq_chip = { .irq_unmask = expio_unmask_irq, }; +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vdd33a", "smsc911x"), + REGULATOR_SUPPLY("vddvario", "smsc911x"), +}; + int __init mxc_expio_init(u32 base, u32 p_irq) { int i; @@ -188,6 +195,8 @@ int __init mxc_expio_init(u32 base, u32 p_irq) irq_set_chained_handler(p_irq, mxc_expio_irq_handler); /* Register Lan device on the debugboard */ + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + smsc911x_resources[0].start = LAN9217_BASE_ADDR(base); smsc911x_resources[0].end = LAN9217_BASE_ADDR(base) + 0x100 - 1; platform_device_register(&smsc_lan9217_device); diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index dcebb1230f7f..c722f9ce6918 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -88,12 +88,6 @@ config IMX_HAVE_IOMUX_V1 config ARCH_MXC_IOMUX_V3 bool -config ARCH_MXC_AUDMUX_V1 - bool - -config ARCH_MXC_AUDMUX_V2 - bool - config IRAM_ALLOC bool select GENERIC_ALLOCATOR diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 076db84f3e31..e81290c27c65 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -14,8 +14,6 @@ obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o obj-$(CONFIG_MXC_PWM) += pwm.o obj-$(CONFIG_MXC_ULPI) += ulpi.o obj-$(CONFIG_MXC_USE_EPIT) += epit.o -obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o -obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o ifdef CONFIG_SND_IMX_SOC diff --git a/arch/arm/plat-mxc/audmux-v1.c b/arch/arm/plat-mxc/audmux-v1.c deleted file mode 100644 index 1180bef7664b..000000000000 --- a/arch/arm/plat-mxc/audmux-v1.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> - * - * Initial development of this code was funded by - * Phytec Messtechnik GmbH, http://www.phytec.de - * - * 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. - */ - -#include <linux/module.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <mach/audmux.h> -#include <mach/hardware.h> - -static void __iomem *audmux_base; - -static unsigned char port_mapping[] = { - 0x0, 0x4, 0x8, 0x10, 0x14, 0x1c, -}; - -int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr) -{ - if (!audmux_base) { - printk("%s: not configured\n", __func__); - return -ENOSYS; - } - - if (port >= ARRAY_SIZE(port_mapping)) - return -EINVAL; - - writel(pcr, audmux_base + port_mapping[port]); - - return 0; -} -EXPORT_SYMBOL_GPL(mxc_audmux_v1_configure_port); - -static int mxc_audmux_v1_init(void) -{ -#ifdef CONFIG_MACH_MX21 - if (cpu_is_mx21()) - audmux_base = MX21_IO_ADDRESS(MX21_AUDMUX_BASE_ADDR); - else -#endif -#ifdef CONFIG_MACH_MX27 - if (cpu_is_mx27()) - audmux_base = MX27_IO_ADDRESS(MX27_AUDMUX_BASE_ADDR); - else -#endif - (void)0; - - return 0; -} - -postcore_initcall(mxc_audmux_v1_init); diff --git a/arch/arm/plat-mxc/audmux-v2.c b/arch/arm/plat-mxc/audmux-v2.c deleted file mode 100644 index 8cced35009bd..000000000000 --- a/arch/arm/plat-mxc/audmux-v2.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> - * - * Initial development of this code was funded by - * Phytec Messtechnik GmbH, http://www.phytec.de - * - * 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. - */ - -#include <linux/module.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/debugfs.h> -#include <linux/slab.h> -#include <mach/audmux.h> -#include <mach/hardware.h> - -static struct clk *audmux_clk; -static void __iomem *audmux_base; - -#define MXC_AUDMUX_V2_PTCR(x) ((x) * 8) -#define MXC_AUDMUX_V2_PDCR(x) ((x) * 8 + 4) - -#ifdef CONFIG_DEBUG_FS -static struct dentry *audmux_debugfs_root; - -static int audmux_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -/* There is an annoying discontinuity in the SSI numbering with regard - * to the Linux number of the devices */ -static const char *audmux_port_string(int port) -{ - switch (port) { - case MX31_AUDMUX_PORT1_SSI0: - return "imx-ssi.0"; - case MX31_AUDMUX_PORT2_SSI1: - return "imx-ssi.1"; - case MX31_AUDMUX_PORT3_SSI_PINS_3: - return "SSI3"; - case MX31_AUDMUX_PORT4_SSI_PINS_4: - return "SSI4"; - case MX31_AUDMUX_PORT5_SSI_PINS_5: - return "SSI5"; - case MX31_AUDMUX_PORT6_SSI_PINS_6: - return "SSI6"; - default: - return "UNKNOWN"; - } -} - -static ssize_t audmux_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - ssize_t ret; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - int port = (int)file->private_data; - u32 pdcr, ptcr; - - if (!buf) - return -ENOMEM; - - if (audmux_clk) - clk_enable(audmux_clk); - - ptcr = readl(audmux_base + MXC_AUDMUX_V2_PTCR(port)); - pdcr = readl(audmux_base + MXC_AUDMUX_V2_PDCR(port)); - - if (audmux_clk) - clk_disable(audmux_clk); - - ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", - pdcr, ptcr); - - if (ptcr & MXC_AUDMUX_V2_PTCR_TFSDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "TxFS output from %s, ", - audmux_port_string((ptcr >> 27) & 0x7)); - else - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "TxFS input, "); - - if (ptcr & MXC_AUDMUX_V2_PTCR_TCLKDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "TxClk output from %s", - audmux_port_string((ptcr >> 22) & 0x7)); - else - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "TxClk input"); - - ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); - - if (ptcr & MXC_AUDMUX_V2_PTCR_SYN) { - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "Port is symmetric"); - } else { - if (ptcr & MXC_AUDMUX_V2_PTCR_RFSDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "RxFS output from %s, ", - audmux_port_string((ptcr >> 17) & 0x7)); - else - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "RxFS input, "); - - if (ptcr & MXC_AUDMUX_V2_PTCR_RCLKDIR) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "RxClk output from %s", - audmux_port_string((ptcr >> 12) & 0x7)); - else - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "RxClk input"); - } - - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "\nData received from %s\n", - audmux_port_string((pdcr >> 13) & 0x7)); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - - kfree(buf); - - return ret; -} - -static const struct file_operations audmux_debugfs_fops = { - .open = audmux_open_file, - .read = audmux_read_file, - .llseek = default_llseek, -}; - -static void audmux_debugfs_init(void) -{ - int i; - char buf[20]; - - audmux_debugfs_root = debugfs_create_dir("audmux", NULL); - if (!audmux_debugfs_root) { - pr_warning("Failed to create AUDMUX debugfs root\n"); - return; - } - - for (i = 1; i < 8; i++) { - snprintf(buf, sizeof(buf), "ssi%d", i); - if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, - (void *)i, &audmux_debugfs_fops)) - pr_warning("Failed to create AUDMUX port %d debugfs file\n", - i); - } -} -#else -static inline void audmux_debugfs_init(void) -{ -} -#endif - -int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, - unsigned int pdcr) -{ - if (!audmux_base) - return -ENOSYS; - - if (audmux_clk) - clk_enable(audmux_clk); - - writel(ptcr, audmux_base + MXC_AUDMUX_V2_PTCR(port)); - writel(pdcr, audmux_base + MXC_AUDMUX_V2_PDCR(port)); - - if (audmux_clk) - clk_disable(audmux_clk); - - return 0; -} -EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port); - -static int mxc_audmux_v2_init(void) -{ - int ret; - if (cpu_is_mx51()) { - audmux_base = MX51_IO_ADDRESS(MX51_AUDMUX_BASE_ADDR); - } else if (cpu_is_mx31()) { - audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR); - } else if (cpu_is_mx35()) { - audmux_clk = clk_get(NULL, "audmux"); - if (IS_ERR(audmux_clk)) { - ret = PTR_ERR(audmux_clk); - printk(KERN_ERR "%s: cannot get clock: %d\n", __func__, - ret); - return ret; - } - audmux_base = MX35_IO_ADDRESS(MX35_AUDMUX_BASE_ADDR); - } else if (cpu_is_mx25()) { - audmux_clk = clk_get(NULL, "audmux"); - if (IS_ERR(audmux_clk)) { - ret = PTR_ERR(audmux_clk); - printk(KERN_ERR "%s: cannot get clock: %d\n", __func__, - ret); - return ret; - } - audmux_base = MX25_IO_ADDRESS(MX25_AUDMUX_BASE_ADDR); - } - - audmux_debugfs_init(); - - return 0; -} - -postcore_initcall(mxc_audmux_v2_init); diff --git a/arch/arm/plat-mxc/include/mach/audmux.h b/arch/arm/plat-mxc/include/mach/audmux.h deleted file mode 100644 index 6fda788ed0e9..000000000000 --- a/arch/arm/plat-mxc/include/mach/audmux.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __MACH_AUDMUX_H -#define __MACH_AUDMUX_H - -#define MX27_AUDMUX_HPCR1_SSI0 0 -#define MX27_AUDMUX_HPCR2_SSI1 1 -#define MX27_AUDMUX_HPCR3_SSI_PINS_4 2 -#define MX27_AUDMUX_PPCR1_SSI_PINS_1 3 -#define MX27_AUDMUX_PPCR2_SSI_PINS_2 4 -#define MX27_AUDMUX_PPCR3_SSI_PINS_3 5 - -#define MX31_AUDMUX_PORT1_SSI0 0 -#define MX31_AUDMUX_PORT2_SSI1 1 -#define MX31_AUDMUX_PORT3_SSI_PINS_3 2 -#define MX31_AUDMUX_PORT4_SSI_PINS_4 3 -#define MX31_AUDMUX_PORT5_SSI_PINS_5 4 -#define MX31_AUDMUX_PORT6_SSI_PINS_6 5 - -#define MX51_AUDMUX_PORT1_SSI0 0 -#define MX51_AUDMUX_PORT2_SSI1 1 -#define MX51_AUDMUX_PORT3 2 -#define MX51_AUDMUX_PORT4 3 -#define MX51_AUDMUX_PORT5 4 -#define MX51_AUDMUX_PORT6 5 -#define MX51_AUDMUX_PORT7 6 - -/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */ -#define MXC_AUDMUX_V1_PCR_INMMASK(x) ((x) & 0xff) -#define MXC_AUDMUX_V1_PCR_INMEN (1 << 8) -#define MXC_AUDMUX_V1_PCR_TXRXEN (1 << 10) -#define MXC_AUDMUX_V1_PCR_SYN (1 << 12) -#define MXC_AUDMUX_V1_PCR_RXDSEL(x) (((x) & 0x7) << 13) -#define MXC_AUDMUX_V1_PCR_RFCSEL(x) (((x) & 0xf) << 20) -#define MXC_AUDMUX_V1_PCR_RCLKDIR (1 << 24) -#define MXC_AUDMUX_V1_PCR_RFSDIR (1 << 25) -#define MXC_AUDMUX_V1_PCR_TFCSEL(x) (((x) & 0xf) << 26) -#define MXC_AUDMUX_V1_PCR_TCLKDIR (1 << 30) -#define MXC_AUDMUX_V1_PCR_TFSDIR (1 << 31) - -/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */ -#define MXC_AUDMUX_V2_PTCR_TFSDIR (1 << 31) -#define MXC_AUDMUX_V2_PTCR_TFSEL(x) (((x) & 0xf) << 27) -#define MXC_AUDMUX_V2_PTCR_TCLKDIR (1 << 26) -#define MXC_AUDMUX_V2_PTCR_TCSEL(x) (((x) & 0xf) << 22) -#define MXC_AUDMUX_V2_PTCR_RFSDIR (1 << 21) -#define MXC_AUDMUX_V2_PTCR_RFSEL(x) (((x) & 0xf) << 17) -#define MXC_AUDMUX_V2_PTCR_RCLKDIR (1 << 16) -#define MXC_AUDMUX_V2_PTCR_RCSEL(x) (((x) & 0xf) << 12) -#define MXC_AUDMUX_V2_PTCR_SYN (1 << 11) - -#define MXC_AUDMUX_V2_PDCR_RXDSEL(x) (((x) & 0x7) << 13) -#define MXC_AUDMUX_V2_PDCR_TXRXEN (1 << 12) -#define MXC_AUDMUX_V2_PDCR_MODE(x) (((x) & 0x3) << 8) -#define MXC_AUDMUX_V2_PDCR_INMMASK(x) ((x) & 0xff) - -int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr); - -int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, - unsigned int pdcr); - -#endif /* __MACH_AUDMUX_H */ diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index aa59f4247dc5..8f81503a4df7 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -110,14 +110,6 @@ config OMAP_MUX_WARNINGS to change the pin multiplexing setup. When there are no warnings printed, it's safe to deselect OMAP_MUX for your product. -config OMAP_MCBSP - bool "McBSP support" - depends on ARCH_OMAP - default y - help - Say Y here if you want support for the OMAP Multichannel - Buffered Serial Port. - config OMAP_MBOX_FWK tristate "Mailbox framework support" depends on ARCH_OMAP diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 9a584614e7e6..c0fe2757b695 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -17,8 +17,6 @@ obj-$(CONFIG_ARCH_OMAP2) += omap_device.o obj-$(CONFIG_ARCH_OMAP3) += omap_device.o obj-$(CONFIG_ARCH_OMAP4) += omap_device.o -obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o - obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 8fa74e2c9d6e..18814127809a 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -27,271 +27,10 @@ #include <linux/spinlock.h> #include <linux/clk.h> -/* macro for building platform_device for McBSP ports */ -#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr) \ -static struct platform_device omap_mcbsp##port_nr = { \ - .name = "omap-mcbsp-dai", \ - .id = port_nr - 1, \ -} - #define MCBSP_CONFIG_TYPE2 0x2 #define MCBSP_CONFIG_TYPE3 0x3 #define MCBSP_CONFIG_TYPE4 0x4 -/* McBSP register numbers. Register address offset = num * reg_step */ -enum { - /* Common registers */ - OMAP_MCBSP_REG_SPCR2 = 4, - OMAP_MCBSP_REG_SPCR1, - OMAP_MCBSP_REG_RCR2, - OMAP_MCBSP_REG_RCR1, - OMAP_MCBSP_REG_XCR2, - OMAP_MCBSP_REG_XCR1, - OMAP_MCBSP_REG_SRGR2, - OMAP_MCBSP_REG_SRGR1, - OMAP_MCBSP_REG_MCR2, - OMAP_MCBSP_REG_MCR1, - OMAP_MCBSP_REG_RCERA, - OMAP_MCBSP_REG_RCERB, - OMAP_MCBSP_REG_XCERA, - OMAP_MCBSP_REG_XCERB, - OMAP_MCBSP_REG_PCR0, - OMAP_MCBSP_REG_RCERC, - OMAP_MCBSP_REG_RCERD, - OMAP_MCBSP_REG_XCERC, - OMAP_MCBSP_REG_XCERD, - OMAP_MCBSP_REG_RCERE, - OMAP_MCBSP_REG_RCERF, - OMAP_MCBSP_REG_XCERE, - OMAP_MCBSP_REG_XCERF, - OMAP_MCBSP_REG_RCERG, - OMAP_MCBSP_REG_RCERH, - OMAP_MCBSP_REG_XCERG, - OMAP_MCBSP_REG_XCERH, - - /* OMAP1-OMAP2420 registers */ - OMAP_MCBSP_REG_DRR2 = 0, - OMAP_MCBSP_REG_DRR1, - OMAP_MCBSP_REG_DXR2, - OMAP_MCBSP_REG_DXR1, - - /* OMAP2430 and onwards */ - OMAP_MCBSP_REG_DRR = 0, - OMAP_MCBSP_REG_DXR = 2, - OMAP_MCBSP_REG_SYSCON = 35, - OMAP_MCBSP_REG_THRSH2, - OMAP_MCBSP_REG_THRSH1, - OMAP_MCBSP_REG_IRQST = 40, - OMAP_MCBSP_REG_IRQEN, - OMAP_MCBSP_REG_WAKEUPEN, - OMAP_MCBSP_REG_XCCR, - OMAP_MCBSP_REG_RCCR, - OMAP_MCBSP_REG_XBUFFSTAT, - OMAP_MCBSP_REG_RBUFFSTAT, - OMAP_MCBSP_REG_SSELCR, -}; - -/* OMAP3 sidetone control registers */ -#define OMAP_ST_REG_REV 0x00 -#define OMAP_ST_REG_SYSCONFIG 0x10 -#define OMAP_ST_REG_IRQSTATUS 0x18 -#define OMAP_ST_REG_IRQENABLE 0x1C -#define OMAP_ST_REG_SGAINCR 0x24 -#define OMAP_ST_REG_SFIRCR 0x28 -#define OMAP_ST_REG_SSELCR 0x2C - -/************************** McBSP SPCR1 bit definitions ***********************/ -#define RRST 0x0001 -#define RRDY 0x0002 -#define RFULL 0x0004 -#define RSYNC_ERR 0x0008 -#define RINTM(value) ((value)<<4) /* bits 4:5 */ -#define ABIS 0x0040 -#define DXENA 0x0080 -#define CLKSTP(value) ((value)<<11) /* bits 11:12 */ -#define RJUST(value) ((value)<<13) /* bits 13:14 */ -#define ALB 0x8000 -#define DLB 0x8000 - -/************************** McBSP SPCR2 bit definitions ***********************/ -#define XRST 0x0001 -#define XRDY 0x0002 -#define XEMPTY 0x0004 -#define XSYNC_ERR 0x0008 -#define XINTM(value) ((value)<<4) /* bits 4:5 */ -#define GRST 0x0040 -#define FRST 0x0080 -#define SOFT 0x0100 -#define FREE 0x0200 - -/************************** McBSP PCR bit definitions *************************/ -#define CLKRP 0x0001 -#define CLKXP 0x0002 -#define FSRP 0x0004 -#define FSXP 0x0008 -#define DR_STAT 0x0010 -#define DX_STAT 0x0020 -#define CLKS_STAT 0x0040 -#define SCLKME 0x0080 -#define CLKRM 0x0100 -#define CLKXM 0x0200 -#define FSRM 0x0400 -#define FSXM 0x0800 -#define RIOEN 0x1000 -#define XIOEN 0x2000 -#define IDLE_EN 0x4000 - -/************************** McBSP RCR1 bit definitions ************************/ -#define RWDLEN1(value) ((value)<<5) /* Bits 5:7 */ -#define RFRLEN1(value) ((value)<<8) /* Bits 8:14 */ - -/************************** McBSP XCR1 bit definitions ************************/ -#define XWDLEN1(value) ((value)<<5) /* Bits 5:7 */ -#define XFRLEN1(value) ((value)<<8) /* Bits 8:14 */ - -/*************************** McBSP RCR2 bit definitions ***********************/ -#define RDATDLY(value) (value) /* Bits 0:1 */ -#define RFIG 0x0004 -#define RCOMPAND(value) ((value)<<3) /* Bits 3:4 */ -#define RWDLEN2(value) ((value)<<5) /* Bits 5:7 */ -#define RFRLEN2(value) ((value)<<8) /* Bits 8:14 */ -#define RPHASE 0x8000 - -/*************************** McBSP XCR2 bit definitions ***********************/ -#define XDATDLY(value) (value) /* Bits 0:1 */ -#define XFIG 0x0004 -#define XCOMPAND(value) ((value)<<3) /* Bits 3:4 */ -#define XWDLEN2(value) ((value)<<5) /* Bits 5:7 */ -#define XFRLEN2(value) ((value)<<8) /* Bits 8:14 */ -#define XPHASE 0x8000 - -/************************* McBSP SRGR1 bit definitions ************************/ -#define CLKGDV(value) (value) /* Bits 0:7 */ -#define FWID(value) ((value)<<8) /* Bits 8:15 */ - -/************************* McBSP SRGR2 bit definitions ************************/ -#define FPER(value) (value) /* Bits 0:11 */ -#define FSGM 0x1000 -#define CLKSM 0x2000 -#define CLKSP 0x4000 -#define GSYNC 0x8000 - -/************************* McBSP MCR1 bit definitions *************************/ -#define RMCM 0x0001 -#define RCBLK(value) ((value)<<2) /* Bits 2:4 */ -#define RPABLK(value) ((value)<<5) /* Bits 5:6 */ -#define RPBBLK(value) ((value)<<7) /* Bits 7:8 */ - -/************************* McBSP MCR2 bit definitions *************************/ -#define XMCM(value) (value) /* Bits 0:1 */ -#define XCBLK(value) ((value)<<2) /* Bits 2:4 */ -#define XPABLK(value) ((value)<<5) /* Bits 5:6 */ -#define XPBBLK(value) ((value)<<7) /* Bits 7:8 */ - -/*********************** McBSP XCCR bit definitions *************************/ -#define EXTCLKGATE 0x8000 -#define PPCONNECT 0x4000 -#define DXENDLY(value) ((value)<<12) /* Bits 12:13 */ -#define XFULL_CYCLE 0x0800 -#define DILB 0x0020 -#define XDMAEN 0x0008 -#define XDISABLE 0x0001 - -/********************** McBSP RCCR bit definitions *************************/ -#define RFULL_CYCLE 0x0800 -#define RDMAEN 0x0008 -#define RDISABLE 0x0001 - -/********************** McBSP SYSCONFIG bit definitions ********************/ -#define CLOCKACTIVITY(value) ((value)<<8) -#define SIDLEMODE(value) ((value)<<3) -#define ENAWAKEUP 0x0004 -#define SOFTRST 0x0002 - -/********************** McBSP SSELCR bit definitions ***********************/ -#define SIDETONEEN 0x0400 - -/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/ -#define ST_AUTOIDLE 0x0001 - -/********************** McBSP Sidetone SGAINCR bit definitions *************/ -#define ST_CH1GAIN(value) ((value<<16)) /* Bits 16:31 */ -#define ST_CH0GAIN(value) (value) /* Bits 0:15 */ - -/********************** McBSP Sidetone SFIRCR bit definitions **************/ -#define ST_FIRCOEFF(value) (value) /* Bits 0:15 */ - -/********************** McBSP Sidetone SSELCR bit definitions **************/ -#define ST_COEFFWRDONE 0x0004 -#define ST_COEFFWREN 0x0002 -#define ST_SIDETONEEN 0x0001 - -/********************** McBSP DMA operating modes **************************/ -#define MCBSP_DMA_MODE_ELEMENT 0 -#define MCBSP_DMA_MODE_THRESHOLD 1 -#define MCBSP_DMA_MODE_FRAME 2 - -/********************** McBSP WAKEUPEN bit definitions *********************/ -#define XEMPTYEOFEN 0x4000 -#define XRDYEN 0x0400 -#define XEOFEN 0x0200 -#define XFSXEN 0x0100 -#define XSYNCERREN 0x0080 -#define RRDYEN 0x0008 -#define REOFEN 0x0004 -#define RFSREN 0x0002 -#define RSYNCERREN 0x0001 - -/* CLKR signal muxing options */ -#define CLKR_SRC_CLKR 0 -#define CLKR_SRC_CLKX 1 - -/* FSR signal muxing options */ -#define FSR_SRC_FSR 0 -#define FSR_SRC_FSX 1 - -/* McBSP functional clock sources */ -#define MCBSP_CLKS_PRCM_SRC 0 -#define MCBSP_CLKS_PAD_SRC 1 - -/* we don't do multichannel for now */ -struct omap_mcbsp_reg_cfg { - u16 spcr2; - u16 spcr1; - u16 rcr2; - u16 rcr1; - u16 xcr2; - u16 xcr1; - u16 srgr2; - u16 srgr1; - u16 mcr2; - u16 mcr1; - u16 pcr0; - u16 rcerc; - u16 rcerd; - u16 xcerc; - u16 xcerd; - u16 rcere; - u16 rcerf; - u16 xcere; - u16 xcerf; - u16 rcerg; - u16 rcerh; - u16 xcerg; - u16 xcerh; - u16 xccr; - u16 rccr; -}; - -typedef enum { - OMAP_MCBSP_WORD_8 = 0, - OMAP_MCBSP_WORD_12, - OMAP_MCBSP_WORD_16, - OMAP_MCBSP_WORD_20, - OMAP_MCBSP_WORD_24, - OMAP_MCBSP_WORD_32, -} omap_mcbsp_word_length; - /* Platform specific configuration */ struct omap_mcbsp_ops { void (*request)(unsigned int); @@ -312,43 +51,6 @@ struct omap_mcbsp_platform_data { int (*mux_signal)(struct device *dev, const char *signal, const char *src); }; -struct omap_mcbsp_st_data { - void __iomem *io_base_st; - bool running; - bool enabled; - s16 taps[128]; /* Sidetone filter coefficients */ - int nr_taps; /* Number of filter coefficients in use */ - s16 ch0gain; - s16 ch1gain; -}; - -struct omap_mcbsp { - struct device *dev; - unsigned long phys_base; - unsigned long phys_dma_base; - void __iomem *io_base; - u8 id; - u8 free; - - int rx_irq; - int tx_irq; - - /* DMA stuff */ - u8 dma_rx_sync; - u8 dma_tx_sync; - - /* Protect the field .free, while checking if the mcbsp is in use */ - spinlock_t lock; - struct omap_mcbsp_platform_data *pdata; - struct clk *fclk; - struct omap_mcbsp_st_data *st_data; - int dma_op_mode; - u16 max_tx_thres; - u16 max_rx_thres; - void *reg_cache; - int reg_cache_size; -}; - /** * omap_mcbsp_dev_attr - OMAP McBSP device attributes for omap_hwmod * @sidetone: name of the sidetone device @@ -357,39 +59,4 @@ struct omap_mcbsp_dev_attr { const char *sidetone; }; -extern struct omap_mcbsp **mcbsp_ptr; -extern int omap_mcbsp_count; - -int omap_mcbsp_init(void); -void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config); -void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold); -void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold); -u16 omap_mcbsp_get_max_tx_threshold(unsigned int id); -u16 omap_mcbsp_get_max_rx_threshold(unsigned int id); -u16 omap_mcbsp_get_fifo_size(unsigned int id); -u16 omap_mcbsp_get_tx_delay(unsigned int id); -u16 omap_mcbsp_get_rx_delay(unsigned int id); -int omap_mcbsp_get_dma_op_mode(unsigned int id); -int omap_mcbsp_request(unsigned int id); -void omap_mcbsp_free(unsigned int id); -void omap_mcbsp_start(unsigned int id, int tx, int rx); -void omap_mcbsp_stop(unsigned int id, int tx, int rx); - -/* McBSP functional clock source changing function */ -extern int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id); - -/* McBSP signal muxing API */ -void omap2_mcbsp1_mux_clkr_src(u8 mux); -void omap2_mcbsp1_mux_fsr_src(u8 mux); - -int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream); -int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream); - -/* Sidetone specific API */ -int omap_st_set_chgain(unsigned int id, int channel, s16 chgain); -int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain); -int omap_st_enable(unsigned int id); -int omap_st_disable(unsigned int id); -int omap_st_is_enabled(unsigned int id); - #endif diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c deleted file mode 100644 index 4b15cd7926d7..000000000000 --- a/arch/arm/plat-omap/mcbsp.c +++ /dev/null @@ -1,1361 +0,0 @@ -/* - * linux/arch/arm/plat-omap/mcbsp.c - * - * Copyright (C) 2004 Nokia Corporation - * Author: Samuel Ortiz <samuel.ortiz@nokia.com> - * - * - * 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 - * published by the Free Software Foundation. - * - * Multichannel mode not supported. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> - -#include <plat/mcbsp.h> -#include <linux/pm_runtime.h> - -struct omap_mcbsp **mcbsp_ptr; -int omap_mcbsp_count; - -#define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) -#define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; - -static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) -{ - void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; - - if (mcbsp->pdata->reg_size == 2) { - ((u16 *)mcbsp->reg_cache)[reg] = (u16)val; - __raw_writew((u16)val, addr); - } else { - ((u32 *)mcbsp->reg_cache)[reg] = val; - __raw_writel(val, addr); - } -} - -static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) -{ - void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step; - - if (mcbsp->pdata->reg_size == 2) { - return !from_cache ? __raw_readw(addr) : - ((u16 *)mcbsp->reg_cache)[reg]; - } else { - return !from_cache ? __raw_readl(addr) : - ((u32 *)mcbsp->reg_cache)[reg]; - } -} - -static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) -{ - __raw_writel(val, mcbsp->st_data->io_base_st + reg); -} - -static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) -{ - return __raw_readl(mcbsp->st_data->io_base_st + reg); -} - -#define MCBSP_READ(mcbsp, reg) \ - omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) -#define MCBSP_WRITE(mcbsp, reg, val) \ - omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) -#define MCBSP_READ_CACHE(mcbsp, reg) \ - omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) - -#define MCBSP_ST_READ(mcbsp, reg) \ - omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg) -#define MCBSP_ST_WRITE(mcbsp, reg, val) \ - omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val) - -static void omap_mcbsp_dump_reg(u8 id) -{ - struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id); - - dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); - dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", - MCBSP_READ(mcbsp, DRR2)); - dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", - MCBSP_READ(mcbsp, DRR1)); - dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", - MCBSP_READ(mcbsp, DXR2)); - dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", - MCBSP_READ(mcbsp, DXR1)); - dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", - MCBSP_READ(mcbsp, SPCR2)); - dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", - MCBSP_READ(mcbsp, SPCR1)); - dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", - MCBSP_READ(mcbsp, RCR2)); - dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", - MCBSP_READ(mcbsp, RCR1)); - dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", - MCBSP_READ(mcbsp, XCR2)); - dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", - MCBSP_READ(mcbsp, XCR1)); - dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", - MCBSP_READ(mcbsp, SRGR2)); - dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", - MCBSP_READ(mcbsp, SRGR1)); - dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", - MCBSP_READ(mcbsp, PCR0)); - dev_dbg(mcbsp->dev, "***********************\n"); -} - -static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) -{ - struct omap_mcbsp *mcbsp_tx = dev_id; - u16 irqst_spcr2; - - irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2); - dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); - - if (irqst_spcr2 & XSYNC_ERR) { - dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n", - irqst_spcr2); - /* Writing zero to XSYNC_ERR clears the IRQ */ - MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2)); - } - - return IRQ_HANDLED; -} - -static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) -{ - struct omap_mcbsp *mcbsp_rx = dev_id; - u16 irqst_spcr1; - - irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1); - dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); - - if (irqst_spcr1 & RSYNC_ERR) { - dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n", - irqst_spcr1); - /* Writing zero to RSYNC_ERR clears the IRQ */ - MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1)); - } - - return IRQ_HANDLED; -} - -/* - * omap_mcbsp_config simply write a config to the - * appropriate McBSP. - * You either call this function or set the McBSP registers - * by yourself before calling omap_mcbsp_start(). - */ -void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - mcbsp = id_to_mcbsp_ptr(id); - - dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", - mcbsp->id, mcbsp->phys_base); - - /* We write the given config */ - MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); - MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); - MCBSP_WRITE(mcbsp, RCR2, config->rcr2); - MCBSP_WRITE(mcbsp, RCR1, config->rcr1); - MCBSP_WRITE(mcbsp, XCR2, config->xcr2); - MCBSP_WRITE(mcbsp, XCR1, config->xcr1); - MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); - MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); - MCBSP_WRITE(mcbsp, MCR2, config->mcr2); - MCBSP_WRITE(mcbsp, MCR1, config->mcr1); - MCBSP_WRITE(mcbsp, PCR0, config->pcr0); - if (mcbsp->pdata->has_ccr) { - MCBSP_WRITE(mcbsp, XCCR, config->xccr); - MCBSP_WRITE(mcbsp, RCCR, config->rccr); - } -} -EXPORT_SYMBOL(omap_mcbsp_config); - -/** - * omap_mcbsp_dma_params - returns the dma channel number - * @id - mcbsp id - * @stream - indicates the direction of data flow (rx or tx) - * - * Returns the dma channel number for the rx channel or tx channel - * based on the value of @stream for the requested mcbsp given by @id - */ -int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - if (stream) - return mcbsp->dma_rx_sync; - else - return mcbsp->dma_tx_sync; -} -EXPORT_SYMBOL(omap_mcbsp_dma_ch_params); - -/** - * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register - * @id - mcbsp id - * @stream - indicates the direction of data flow (rx or tx) - * - * Returns the address of mcbsp data transmit register or data receive register - * to be used by DMA for transferring/receiving data based on the value of - * @stream for the requested mcbsp given by @id - */ -int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream) -{ - struct omap_mcbsp *mcbsp; - int data_reg; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - if (mcbsp->pdata->reg_size == 2) { - if (stream) - data_reg = OMAP_MCBSP_REG_DRR1; - else - data_reg = OMAP_MCBSP_REG_DXR1; - } else { - if (stream) - data_reg = OMAP_MCBSP_REG_DRR; - else - data_reg = OMAP_MCBSP_REG_DXR; - } - - return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; -} -EXPORT_SYMBOL(omap_mcbsp_dma_reg_params); - -static void omap_st_on(struct omap_mcbsp *mcbsp) -{ - unsigned int w; - - if (mcbsp->pdata->enable_st_clock) - mcbsp->pdata->enable_st_clock(mcbsp->id, 1); - - /* Enable McBSP Sidetone */ - w = MCBSP_READ(mcbsp, SSELCR); - MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); - - /* Enable Sidetone from Sidetone Core */ - w = MCBSP_ST_READ(mcbsp, SSELCR); - MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); -} - -static void omap_st_off(struct omap_mcbsp *mcbsp) -{ - unsigned int w; - - w = MCBSP_ST_READ(mcbsp, SSELCR); - MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); - - w = MCBSP_READ(mcbsp, SSELCR); - MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); - - if (mcbsp->pdata->enable_st_clock) - mcbsp->pdata->enable_st_clock(mcbsp->id, 0); -} - -static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) -{ - u16 val, i; - - val = MCBSP_ST_READ(mcbsp, SSELCR); - - if (val & ST_COEFFWREN) - MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); - - MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN); - - for (i = 0; i < 128; i++) - MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]); - - i = 0; - - val = MCBSP_ST_READ(mcbsp, SSELCR); - while (!(val & ST_COEFFWRDONE) && (++i < 1000)) - val = MCBSP_ST_READ(mcbsp, SSELCR); - - MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); - - if (i == 1000) - dev_err(mcbsp->dev, "McBSP FIR load error!\n"); -} - -static void omap_st_chgain(struct omap_mcbsp *mcbsp) -{ - u16 w; - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - w = MCBSP_ST_READ(mcbsp, SSELCR); - - MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \ - ST_CH1GAIN(st_data->ch1gain)); -} - -int omap_st_set_chgain(unsigned int id, int channel, s16 chgain) -{ - struct omap_mcbsp *mcbsp; - struct omap_mcbsp_st_data *st_data; - int ret = 0; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - - mcbsp = id_to_mcbsp_ptr(id); - st_data = mcbsp->st_data; - - if (!st_data) - return -ENOENT; - - spin_lock_irq(&mcbsp->lock); - if (channel == 0) - st_data->ch0gain = chgain; - else if (channel == 1) - st_data->ch1gain = chgain; - else - ret = -EINVAL; - - if (st_data->enabled) - omap_st_chgain(mcbsp); - spin_unlock_irq(&mcbsp->lock); - - return ret; -} -EXPORT_SYMBOL(omap_st_set_chgain); - -int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain) -{ - struct omap_mcbsp *mcbsp; - struct omap_mcbsp_st_data *st_data; - int ret = 0; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - - mcbsp = id_to_mcbsp_ptr(id); - st_data = mcbsp->st_data; - - if (!st_data) - return -ENOENT; - - spin_lock_irq(&mcbsp->lock); - if (channel == 0) - *chgain = st_data->ch0gain; - else if (channel == 1) - *chgain = st_data->ch1gain; - else - ret = -EINVAL; - spin_unlock_irq(&mcbsp->lock); - - return ret; -} -EXPORT_SYMBOL(omap_st_get_chgain); - -static int omap_st_start(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - if (st_data && st_data->enabled && !st_data->running) { - omap_st_fir_write(mcbsp, st_data->taps); - omap_st_chgain(mcbsp); - - if (!mcbsp->free) { - omap_st_on(mcbsp); - st_data->running = 1; - } - } - - return 0; -} - -int omap_st_enable(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - struct omap_mcbsp_st_data *st_data; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - - mcbsp = id_to_mcbsp_ptr(id); - st_data = mcbsp->st_data; - - if (!st_data) - return -ENODEV; - - spin_lock_irq(&mcbsp->lock); - st_data->enabled = 1; - omap_st_start(mcbsp); - spin_unlock_irq(&mcbsp->lock); - - return 0; -} -EXPORT_SYMBOL(omap_st_enable); - -static int omap_st_stop(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - if (st_data && st_data->running) { - if (!mcbsp->free) { - omap_st_off(mcbsp); - st_data->running = 0; - } - } - - return 0; -} - -int omap_st_disable(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - struct omap_mcbsp_st_data *st_data; - int ret = 0; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - - mcbsp = id_to_mcbsp_ptr(id); - st_data = mcbsp->st_data; - - if (!st_data) - return -ENODEV; - - spin_lock_irq(&mcbsp->lock); - omap_st_stop(mcbsp); - st_data->enabled = 0; - spin_unlock_irq(&mcbsp->lock); - - return ret; -} -EXPORT_SYMBOL(omap_st_disable); - -int omap_st_is_enabled(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - struct omap_mcbsp_st_data *st_data; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - - mcbsp = id_to_mcbsp_ptr(id); - st_data = mcbsp->st_data; - - if (!st_data) - return -ENODEV; - - - return st_data->enabled; -} -EXPORT_SYMBOL(omap_st_is_enabled); - -/* - * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. - * The threshold parameter is 1 based, and it is converted (threshold - 1) - * for the THRSH2 register. - */ -void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - mcbsp = id_to_mcbsp_ptr(id); - if (mcbsp->pdata->buffer_size == 0) - return; - - if (threshold && threshold <= mcbsp->max_tx_thres) - MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); -} -EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); - -/* - * omap_mcbsp_set_rx_threshold configures the receive threshold in words. - * The threshold parameter is 1 based, and it is converted (threshold - 1) - * for the THRSH1 register. - */ -void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - mcbsp = id_to_mcbsp_ptr(id); - if (mcbsp->pdata->buffer_size == 0) - return; - - if (threshold && threshold <= mcbsp->max_rx_thres) - MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); -} -EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold); - -/* - * omap_mcbsp_get_max_tx_thres just return the current configured - * maximum threshold for transmission - */ -u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - return mcbsp->max_tx_thres; -} -EXPORT_SYMBOL(omap_mcbsp_get_max_tx_threshold); - -/* - * omap_mcbsp_get_max_rx_thres just return the current configured - * maximum threshold for reception - */ -u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - return mcbsp->max_rx_thres; -} -EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold); - -u16 omap_mcbsp_get_fifo_size(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - return mcbsp->pdata->buffer_size; -} -EXPORT_SYMBOL(omap_mcbsp_get_fifo_size); - -/* - * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO - */ -u16 omap_mcbsp_get_tx_delay(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - u16 buffstat; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - if (mcbsp->pdata->buffer_size == 0) - return 0; - - /* Returns the number of free locations in the buffer */ - buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); - - /* Number of slots are different in McBSP ports */ - return mcbsp->pdata->buffer_size - buffstat; -} -EXPORT_SYMBOL(omap_mcbsp_get_tx_delay); - -/* - * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO - * to reach the threshold value (when the DMA will be triggered to read it) - */ -u16 omap_mcbsp_get_rx_delay(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - u16 buffstat, threshold; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - if (mcbsp->pdata->buffer_size == 0) - return 0; - - /* Returns the number of used locations in the buffer */ - buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); - /* RX threshold */ - threshold = MCBSP_READ(mcbsp, THRSH1); - - /* Return the number of location till we reach the threshold limit */ - if (threshold <= buffstat) - return 0; - else - return threshold - buffstat; -} -EXPORT_SYMBOL(omap_mcbsp_get_rx_delay); - -/* - * omap_mcbsp_get_dma_op_mode just return the current configured - * operating mode for the mcbsp channel - */ -int omap_mcbsp_get_dma_op_mode(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - int dma_op_mode; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%u)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - dma_op_mode = mcbsp->dma_op_mode; - - return dma_op_mode; -} -EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode); - -int omap_mcbsp_request(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - void *reg_cache; - int err; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return -ENODEV; - } - mcbsp = id_to_mcbsp_ptr(id); - - reg_cache = kzalloc(mcbsp->reg_cache_size, GFP_KERNEL); - if (!reg_cache) { - return -ENOMEM; - } - - spin_lock(&mcbsp->lock); - if (!mcbsp->free) { - dev_err(mcbsp->dev, "McBSP%d is currently in use\n", - mcbsp->id); - err = -EBUSY; - goto err_kfree; - } - - mcbsp->free = false; - mcbsp->reg_cache = reg_cache; - spin_unlock(&mcbsp->lock); - - if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) - mcbsp->pdata->ops->request(id); - - pm_runtime_get_sync(mcbsp->dev); - - /* Enable wakeup behavior */ - if (mcbsp->pdata->has_wakeup) - MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); - - /* - * Make sure that transmitter, receiver and sample-rate generator are - * not running before activating IRQs. - */ - MCBSP_WRITE(mcbsp, SPCR1, 0); - MCBSP_WRITE(mcbsp, SPCR2, 0); - - err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, - 0, "McBSP", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request TX IRQ %d " - "for McBSP%d\n", mcbsp->tx_irq, - mcbsp->id); - goto err_clk_disable; - } - - if (mcbsp->rx_irq) { - err = request_irq(mcbsp->rx_irq, - omap_mcbsp_rx_irq_handler, - 0, "McBSP", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request RX IRQ %d " - "for McBSP%d\n", mcbsp->rx_irq, - mcbsp->id); - goto err_free_irq; - } - } - - return 0; -err_free_irq: - free_irq(mcbsp->tx_irq, (void *)mcbsp); -err_clk_disable: - if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(id); - - /* Disable wakeup behavior */ - if (mcbsp->pdata->has_wakeup) - MCBSP_WRITE(mcbsp, WAKEUPEN, 0); - - pm_runtime_put_sync(mcbsp->dev); - - spin_lock(&mcbsp->lock); - mcbsp->free = true; - mcbsp->reg_cache = NULL; -err_kfree: - spin_unlock(&mcbsp->lock); - kfree(reg_cache); - - return err; -} -EXPORT_SYMBOL(omap_mcbsp_request); - -void omap_mcbsp_free(unsigned int id) -{ - struct omap_mcbsp *mcbsp; - void *reg_cache; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - mcbsp = id_to_mcbsp_ptr(id); - - if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(id); - - /* Disable wakeup behavior */ - if (mcbsp->pdata->has_wakeup) - MCBSP_WRITE(mcbsp, WAKEUPEN, 0); - - pm_runtime_put_sync(mcbsp->dev); - - if (mcbsp->rx_irq) - free_irq(mcbsp->rx_irq, (void *)mcbsp); - free_irq(mcbsp->tx_irq, (void *)mcbsp); - - reg_cache = mcbsp->reg_cache; - - spin_lock(&mcbsp->lock); - if (mcbsp->free) - dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); - else - mcbsp->free = true; - mcbsp->reg_cache = NULL; - spin_unlock(&mcbsp->lock); - - if (reg_cache) - kfree(reg_cache); -} -EXPORT_SYMBOL(omap_mcbsp_free); - -/* - * Here we start the McBSP, by enabling transmitter, receiver or both. - * If no transmitter or receiver is active prior calling, then sample-rate - * generator and frame sync are started. - */ -void omap_mcbsp_start(unsigned int id, int tx, int rx) -{ - struct omap_mcbsp *mcbsp; - int enable_srg = 0; - u16 w; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - mcbsp = id_to_mcbsp_ptr(id); - - if (mcbsp->st_data) - omap_st_start(mcbsp); - - /* Only enable SRG, if McBSP is master */ - w = MCBSP_READ_CACHE(mcbsp, PCR0); - if (w & (FSXM | FSRM | CLKXM | CLKRM)) - enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | - MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); - - if (enable_srg) { - /* Start the sample generator */ - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); - } - - /* Enable transmitter and receiver */ - tx &= 1; - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w | tx); - - rx &= 1; - w = MCBSP_READ_CACHE(mcbsp, SPCR1); - MCBSP_WRITE(mcbsp, SPCR1, w | rx); - - /* - * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec - * REVISIT: 100us may give enough time for two CLKSRG, however - * due to some unknown PM related, clock gating etc. reason it - * is now at 500us. - */ - udelay(500); - - if (enable_srg) { - /* Start frame sync */ - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); - } - - if (mcbsp->pdata->has_ccr) { - /* Release the transmitter and receiver */ - w = MCBSP_READ_CACHE(mcbsp, XCCR); - w &= ~(tx ? XDISABLE : 0); - MCBSP_WRITE(mcbsp, XCCR, w); - w = MCBSP_READ_CACHE(mcbsp, RCCR); - w &= ~(rx ? RDISABLE : 0); - MCBSP_WRITE(mcbsp, RCCR, w); - } - - /* Dump McBSP Regs */ - omap_mcbsp_dump_reg(id); -} -EXPORT_SYMBOL(omap_mcbsp_start); - -void omap_mcbsp_stop(unsigned int id, int tx, int rx) -{ - struct omap_mcbsp *mcbsp; - int idle; - u16 w; - - if (!omap_mcbsp_check_valid_id(id)) { - printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); - return; - } - - mcbsp = id_to_mcbsp_ptr(id); - - /* Reset transmitter */ - tx &= 1; - if (mcbsp->pdata->has_ccr) { - w = MCBSP_READ_CACHE(mcbsp, XCCR); - w |= (tx ? XDISABLE : 0); - MCBSP_WRITE(mcbsp, XCCR, w); - } - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); - - /* Reset receiver */ - rx &= 1; - if (mcbsp->pdata->has_ccr) { - w = MCBSP_READ_CACHE(mcbsp, RCCR); - w |= (rx ? RDISABLE : 0); - MCBSP_WRITE(mcbsp, RCCR, w); - } - w = MCBSP_READ_CACHE(mcbsp, SPCR1); - MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); - - idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | - MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); - - if (idle) { - /* Reset the sample rate generator */ - w = MCBSP_READ_CACHE(mcbsp, SPCR2); - MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); - } - - if (mcbsp->st_data) - omap_st_stop(mcbsp); -} -EXPORT_SYMBOL(omap_mcbsp_stop); - -int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id) -{ - struct omap_mcbsp *mcbsp; - const char *src; - - if (!omap_mcbsp_check_valid_id(id)) { - pr_err("%s: Invalid id (%d)\n", __func__, id + 1); - return -EINVAL; - } - mcbsp = id_to_mcbsp_ptr(id); - - if (fck_src_id == MCBSP_CLKS_PAD_SRC) - src = "clks_ext"; - else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) - src = "clks_fclk"; - else - return -EINVAL; - - if (mcbsp->pdata->set_clk_src) - return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src); - else - return -EINVAL; -} -EXPORT_SYMBOL(omap2_mcbsp_set_clks_src); - -void omap2_mcbsp1_mux_clkr_src(u8 mux) -{ - struct omap_mcbsp *mcbsp; - const char *src; - - if (mux == CLKR_SRC_CLKR) - src = "clkr"; - else if (mux == CLKR_SRC_CLKX) - src = "clkx"; - else - return; - - mcbsp = id_to_mcbsp_ptr(0); - if (mcbsp->pdata->mux_signal) - mcbsp->pdata->mux_signal(mcbsp->dev, "clkr", src); -} -EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src); - -void omap2_mcbsp1_mux_fsr_src(u8 mux) -{ - struct omap_mcbsp *mcbsp; - const char *src; - - if (mux == FSR_SRC_FSR) - src = "fsr"; - else if (mux == FSR_SRC_FSX) - src = "fsx"; - else - return; - - mcbsp = id_to_mcbsp_ptr(0); - if (mcbsp->pdata->mux_signal) - mcbsp->pdata->mux_signal(mcbsp->dev, "fsr", src); -} -EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src); - -#define max_thres(m) (mcbsp->pdata->buffer_size) -#define valid_threshold(m, val) ((val) <= max_thres(m)) -#define THRESHOLD_PROP_BUILDER(prop) \ -static ssize_t prop##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ - \ - return sprintf(buf, "%u\n", mcbsp->prop); \ -} \ - \ -static ssize_t prop##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t size) \ -{ \ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ - unsigned long val; \ - int status; \ - \ - status = strict_strtoul(buf, 0, &val); \ - if (status) \ - return status; \ - \ - if (!valid_threshold(mcbsp, val)) \ - return -EDOM; \ - \ - mcbsp->prop = val; \ - return size; \ -} \ - \ -static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); - -THRESHOLD_PROP_BUILDER(max_tx_thres); -THRESHOLD_PROP_BUILDER(max_rx_thres); - -static const char *dma_op_modes[] = { - "element", "threshold", "frame", -}; - -static ssize_t dma_op_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - int dma_op_mode, i = 0; - ssize_t len = 0; - const char * const *s; - - dma_op_mode = mcbsp->dma_op_mode; - - for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { - if (dma_op_mode == i) - len += sprintf(buf + len, "[%s] ", *s); - else - len += sprintf(buf + len, "%s ", *s); - } - len += sprintf(buf + len, "\n"); - - return len; -} - -static ssize_t dma_op_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - const char * const *s; - int i = 0; - - for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) - if (sysfs_streq(buf, *s)) - break; - - if (i == ARRAY_SIZE(dma_op_modes)) - return -EINVAL; - - spin_lock_irq(&mcbsp->lock); - if (!mcbsp->free) { - size = -EBUSY; - goto unlock; - } - mcbsp->dma_op_mode = i; - -unlock: - spin_unlock_irq(&mcbsp->lock); - - return size; -} - -static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); - -static const struct attribute *additional_attrs[] = { - &dev_attr_max_tx_thres.attr, - &dev_attr_max_rx_thres.attr, - &dev_attr_dma_op_mode.attr, - NULL, -}; - -static const struct attribute_group additional_attr_group = { - .attrs = (struct attribute **)additional_attrs, -}; - -static ssize_t st_taps_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - ssize_t status = 0; - int i; - - spin_lock_irq(&mcbsp->lock); - for (i = 0; i < st_data->nr_taps; i++) - status += sprintf(&buf[status], (i ? ", %d" : "%d"), - st_data->taps[i]); - if (i) - status += sprintf(&buf[status], "\n"); - spin_unlock_irq(&mcbsp->lock); - - return status; -} - -static ssize_t st_taps_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - int val, tmp, status, i = 0; - - spin_lock_irq(&mcbsp->lock); - memset(st_data->taps, 0, sizeof(st_data->taps)); - st_data->nr_taps = 0; - - do { - status = sscanf(buf, "%d%n", &val, &tmp); - if (status < 0 || status == 0) { - size = -EINVAL; - goto out; - } - if (val < -32768 || val > 32767) { - size = -EINVAL; - goto out; - } - st_data->taps[i++] = val; - buf += tmp; - if (*buf != ',') - break; - buf++; - } while (1); - - st_data->nr_taps = i; - -out: - spin_unlock_irq(&mcbsp->lock); - - return size; -} - -static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store); - -static const struct attribute *sidetone_attrs[] = { - &dev_attr_st_taps.attr, - NULL, -}; - -static const struct attribute_group sidetone_attr_group = { - .attrs = (struct attribute **)sidetone_attrs, -}; - -static int __devinit omap_st_add(struct omap_mcbsp *mcbsp, - struct resource *res) -{ - struct omap_mcbsp_st_data *st_data; - int err; - - st_data = kzalloc(sizeof(*mcbsp->st_data), GFP_KERNEL); - if (!st_data) { - err = -ENOMEM; - goto err1; - } - - st_data->io_base_st = ioremap(res->start, resource_size(res)); - if (!st_data->io_base_st) { - err = -ENOMEM; - goto err2; - } - - err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group); - if (err) - goto err3; - - mcbsp->st_data = st_data; - return 0; - -err3: - iounmap(st_data->io_base_st); -err2: - kfree(st_data); -err1: - return err; - -} - -static void __devexit omap_st_remove(struct omap_mcbsp *mcbsp) -{ - struct omap_mcbsp_st_data *st_data = mcbsp->st_data; - - sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group); - iounmap(st_data->io_base_st); - kfree(st_data); -} - -/* - * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. - * 730 has only 2 McBSP, and both of them are MPU peripherals. - */ -static int __devinit omap_mcbsp_probe(struct platform_device *pdev) -{ - struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data; - struct omap_mcbsp *mcbsp; - int id = pdev->id - 1; - struct resource *res; - int ret = 0; - - if (!pdata) { - dev_err(&pdev->dev, "McBSP device initialized without" - "platform data\n"); - ret = -EINVAL; - goto exit; - } - - dev_dbg(&pdev->dev, "Initializing OMAP McBSP (%d).\n", pdev->id); - - if (id >= omap_mcbsp_count) { - dev_err(&pdev->dev, "Invalid McBSP device id (%d)\n", id); - ret = -EINVAL; - goto exit; - } - - mcbsp = kzalloc(sizeof(struct omap_mcbsp), GFP_KERNEL); - if (!mcbsp) { - ret = -ENOMEM; - goto exit; - } - - spin_lock_init(&mcbsp->lock); - mcbsp->id = id + 1; - mcbsp->free = true; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - if (!res) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "%s:mcbsp%d has invalid memory" - "resource\n", __func__, pdev->id); - ret = -ENOMEM; - goto exit; - } - } - mcbsp->phys_base = res->start; - mcbsp->reg_cache_size = resource_size(res); - mcbsp->io_base = ioremap(res->start, resource_size(res)); - if (!mcbsp->io_base) { - ret = -ENOMEM; - goto err_ioremap; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); - if (!res) - mcbsp->phys_dma_base = mcbsp->phys_base; - else - mcbsp->phys_dma_base = res->start; - - mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); - mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); - - /* From OMAP4 there will be a single irq line */ - if (mcbsp->tx_irq == -ENXIO) - mcbsp->tx_irq = platform_get_irq(pdev, 0); - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!res) { - dev_err(&pdev->dev, "%s:mcbsp%d has invalid rx DMA channel\n", - __func__, pdev->id); - ret = -ENODEV; - goto err_res; - } - mcbsp->dma_rx_sync = res->start; - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!res) { - dev_err(&pdev->dev, "%s:mcbsp%d has invalid tx DMA channel\n", - __func__, pdev->id); - ret = -ENODEV; - goto err_res; - } - mcbsp->dma_tx_sync = res->start; - - mcbsp->fclk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(mcbsp->fclk)) { - ret = PTR_ERR(mcbsp->fclk); - dev_err(&pdev->dev, "unable to get fck: %d\n", ret); - goto err_res; - } - - mcbsp->pdata = pdata; - mcbsp->dev = &pdev->dev; - mcbsp_ptr[id] = mcbsp; - platform_set_drvdata(pdev, mcbsp); - pm_runtime_enable(mcbsp->dev); - - mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; - if (mcbsp->pdata->buffer_size) { - /* - * Initially configure the maximum thresholds to a safe value. - * The McBSP FIFO usage with these values should not go under - * 16 locations. - * If the whole FIFO without safety buffer is used, than there - * is a possibility that the DMA will be not able to push the - * new data on time, causing channel shifts in runtime. - */ - mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10; - mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10; - - ret = sysfs_create_group(&mcbsp->dev->kobj, - &additional_attr_group); - if (ret) { - dev_err(mcbsp->dev, - "Unable to create additional controls\n"); - goto err_thres; - } - } else { - mcbsp->max_tx_thres = -EINVAL; - mcbsp->max_rx_thres = -EINVAL; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone"); - if (res) { - ret = omap_st_add(mcbsp, res); - if (ret) { - dev_err(mcbsp->dev, - "Unable to create sidetone controls\n"); - goto err_st; - } - } - - return 0; - -err_st: - if (mcbsp->pdata->buffer_size) - sysfs_remove_group(&mcbsp->dev->kobj, - &additional_attr_group); -err_thres: - clk_put(mcbsp->fclk); -err_res: - iounmap(mcbsp->io_base); -err_ioremap: - kfree(mcbsp); -exit: - return ret; -} - -static int __devexit omap_mcbsp_remove(struct platform_device *pdev) -{ - struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - if (mcbsp) { - - if (mcbsp->pdata && mcbsp->pdata->ops && - mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(mcbsp->id); - - if (mcbsp->pdata->buffer_size) - sysfs_remove_group(&mcbsp->dev->kobj, - &additional_attr_group); - - if (mcbsp->st_data) - omap_st_remove(mcbsp); - - clk_put(mcbsp->fclk); - - iounmap(mcbsp->io_base); - kfree(mcbsp); - } - - return 0; -} - -static struct platform_driver omap_mcbsp_driver = { - .probe = omap_mcbsp_probe, - .remove = __devexit_p(omap_mcbsp_remove), - .driver = { - .name = "omap-mcbsp", - }, -}; - -int __init omap_mcbsp_init(void) -{ - /* Register the McBSP driver */ - return platform_driver_register(&omap_mcbsp_driver); -} diff --git a/arch/arm/plat-s3c24xx/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c index 68296b1fe7e5..699f93171297 100644 --- a/arch/arm/plat-s3c24xx/pm-simtec.c +++ b/arch/arm/plat-s3c24xx/pm-simtec.c @@ -52,7 +52,7 @@ static __init int pm_simtec_init(void) !machine_is_aml_m5900()) return 0; - printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n"); + printk(KERN_INFO "Simtec Board Power Management" COPYRIGHT "\n"); gstatus4 = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30; gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28; diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index 247b88c760be..a473f8c6a9aa 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -64,5 +64,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index 26e67f0f0051..3c64b2894c13 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig @@ -12,6 +12,7 @@ config TMS320C6X select HAVE_GENERIC_HARDIRQS select HAVE_MEMBLOCK select HAVE_SPARSE_IRQ + select IRQ_DOMAIN select OF select OF_EARLY_FLATTREE diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h index a6ae3c9d9c40..f13b78d5e1ca 100644 --- a/arch/c6x/include/asm/irq.h +++ b/arch/c6x/include/asm/irq.h @@ -13,6 +13,7 @@ #ifndef _ASM_C6X_IRQ_H #define _ASM_C6X_IRQ_H +#include <linux/irqdomain.h> #include <linux/threads.h> #include <linux/list.h> #include <linux/radix-tree.h> @@ -41,253 +42,9 @@ /* This number is used when no interrupt has been assigned */ #define NO_IRQ 0 -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -/* Interrupt controller "host" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The host - * structure is generally created by the PIC code for a given PIC instance - * (though a host can cover more than one PIC if they have a flat number - * model). It's the host callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures are fairly agnostic to the fact that - * we use an open firmware device-tree. We do have references to struct - * device_node in two places: in irq_find_host() to find the host matching - * a given interrupt controller node, and of course as an argument to its - * counterpart host->ops->match() callback. However, those are treated as - * generic pointers by the core and the fact that it's actually a device-node - * pointer is purely a convention between callers and implementation. This - * code could thus be used on other architectures by replacing those two - * by some sort of arch-specific void * "token" used to identify interrupt - * controllers. - */ -struct irq_host; -struct radix_tree_root; -struct device_node; - -/* Functions below are provided by the host and called whenever a new mapping - * is created or an old mapping is disposed. The host can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_host_ops { - /* Match an interrupt controller device node to a host, returns - * 1 on a match - */ - int (*match)(struct irq_host *h, struct device_node *node); - - /* Create or update a mapping between a virtual irq number and a hw - * irq number. This is called only once for a given mapping. - */ - int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - - /* Dispose of such a mapping */ - void (*unmap)(struct irq_host *h, unsigned int virq); - - /* Translate device-tree interrupt specifier from raw format coming - * from the firmware to a irq_hw_number_t (interrupt line number) and - * type (sense) that can be passed to set_irq_type(). In the absence - * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() - * will return the hw number in the first cell and IRQ_TYPE_NONE for - * the type (which amount to keeping whatever default value the - * interrupt controller has for that line) - */ - int (*xlate)(struct irq_host *h, struct device_node *ctrler, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); -}; - -struct irq_host { - struct list_head link; - - /* type of reverse mapping technique */ - unsigned int revmap_type; -#define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */ -#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ -#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ -#define IRQ_HOST_MAP_TREE 3 /* radix tree */ - union { - struct { - unsigned int size; - unsigned int *revmap; - } linear; - struct radix_tree_root tree; - } revmap_data; - struct irq_host_ops *ops; - void *host_data; - irq_hw_number_t inval_irq; - - /* Optional device node pointer */ - struct device_node *of_node; -}; - struct irq_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); -extern bool virq_is_host(unsigned int virq, struct irq_host *host); - -/** - * irq_alloc_host - Allocate a new irq_host data structure - * @of_node: optional device-tree node of the interrupt controller - * @revmap_type: type of reverse mapping to use - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map - * @ops: map/unmap host callbacks - * @inval_irq: provide a hw number in that host space that is always invalid - * - * Allocates and initialize and irq_host structure. Note that in the case of - * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns - * for all legacy interrupts except 0 (which is always the invalid irq for - * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated - * later during boot automatically (the reverse mapping will use the slow path - * until that happens). - */ -extern struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq); - - -/** - * irq_find_host - Locates a host for a given device node - * @node: device-tree node of the interrupt controller - */ -extern struct irq_host *irq_find_host(struct device_node *node); - - -/** - * irq_set_default_host - Set a "default" host - * @host: default host pointer - * - * For convenience, it's possible to set a "default" host that will be used - * whenever NULL is passed to irq_create_mapping(). It makes life easier for - * platforms that want to manipulate a few hard coded interrupt numbers that - * aren't properly represented in the device-tree. - */ -extern void irq_set_default_host(struct irq_host *host); - - -/** - * irq_set_virq_count - Set the maximum number of virt irqs - * @count: number of linux virtual irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -extern void irq_set_virq_count(unsigned int count); - - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - - -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_find_mapping - Find a linux virq from an hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a slow path, for use by generic code. It's expected that an - * irq controller implementation directly calls the appropriate low level - * mapping function. - */ -extern unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_create_direct_mapping - Allocate a virq for direct mapping - * @host: host to allocate the virq for or NULL for default host - * - * This routine is used for irq controllers which can choose the hardware - * interrupt numbers they generate. In such a case it's simplest to use - * the linux virq as the hardware interrupt number. - */ -extern unsigned int irq_create_direct_mapping(struct irq_host *host); - -/** - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. - * @host: host owning this hardware interrupt - * @virq: linux irq number - * @hwirq: hardware irq number in that host space - * - * This is for use by irq controllers that use a radix tree reverse - * mapping for fast lookup. - */ -extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq); - -/** - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses radix tree - * revmaps - */ -extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_linear_revmap - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses linear - * revmaps. It does fallback to the slow path if the revmap doesn't exist - * yet and will create the revmap entry with appropriate locking - */ - -extern unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq); - - - -/** - * irq_alloc_virt - Allocate virtual irq numbers - * @host: host owning these new virtual irqs - * @count: number of consecutive numbers to allocate - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping - * - * This is a low level function that is used internally by irq_create_mapping() - * and that can be used by some irq controllers implementations for things - * like allocating ranges of numbers for MSIs. The revmaps are left untouched. - */ -extern unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint); - -/** - * irq_free_virt - Free virtual irq numbers - * @virq: virtual irq number of the first interrupt to free - * @count: number of interrupts to free - * - * This function is the opposite of irq_alloc_virt. It will not clear reverse - * maps, this should be done previously by unmap'ing the interrupt. In fact, - * all interrupts covered by the range being freed should have been unmapped - * prior to calling this. - */ -extern void irq_free_virt(unsigned int virq, unsigned int count); extern void __init init_pic_c64xplus(void); diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c index 0929e4b2b244..d77bcfdf0d8e 100644 --- a/arch/c6x/kernel/irq.c +++ b/arch/c6x/kernel/irq.c @@ -73,10 +73,10 @@ asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs) set_irq_regs(old_regs); } -static struct irq_host *core_host; +static struct irq_domain *core_domain; -static int core_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) +static int core_domain_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) { if (hw < 4 || hw >= NR_PRIORITY_IRQS) return -EINVAL; @@ -86,8 +86,9 @@ static int core_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops core_host_ops = { - .map = core_host_map, +static const struct irq_domain_ops core_domain_ops = { + .map = core_domain_map, + .xlate = irq_domain_xlate_onecell, }; void __init init_IRQ(void) @@ -100,10 +101,11 @@ void __init init_IRQ(void) np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic"); if (np != NULL) { /* create the core host */ - core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0, - &core_host_ops, 0); - if (core_host) - irq_set_default_host(core_host); + core_domain = irq_domain_add_legacy(np, NR_PRIORITY_IRQS, + 0, 0, &core_domain_ops, + NULL); + if (core_domain) + irq_set_default_host(core_domain); of_node_put(np); } @@ -128,601 +130,15 @@ int arch_show_interrupts(struct seq_file *p, int prec) return 0; } -/* - * IRQ controller and virtual interrupts - */ - -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { - irq_hw_number_t hwirq; - struct irq_host *host; -}; - -static LIST_HEAD(irq_hosts); -static DEFINE_RAW_SPINLOCK(irq_big_lock); -static DEFINE_MUTEX(revmap_trees_mutex); -static struct irq_map_entry irq_map[NR_IRQS]; -static unsigned int irq_virq_count = NR_IRQS; -static struct irq_host *irq_default_host; - irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { - return irq_map[d->irq].hwirq; + return d->hwirq; } EXPORT_SYMBOL_GPL(irqd_to_hwirq); irq_hw_number_t virq_to_hw(unsigned int virq) { - return irq_map[virq].hwirq; + struct irq_data *irq_data = irq_get_irq_data(virq); + return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; } EXPORT_SYMBOL_GPL(virq_to_hw); - -bool virq_is_host(unsigned int virq, struct irq_host *host) -{ - return irq_map[virq].host == host; -} -EXPORT_SYMBOL_GPL(virq_is_host); - -static int default_irq_host_match(struct irq_host *h, struct device_node *np) -{ - return h->of_node != NULL && h->of_node == np; -} - -struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq) -{ - struct irq_host *host; - unsigned int size = sizeof(struct irq_host); - unsigned int i; - unsigned int *rmap; - unsigned long flags; - - /* Allocate structure and revmap table if using linear mapping */ - if (revmap_type == IRQ_HOST_MAP_LINEAR) - size += revmap_arg * sizeof(unsigned int); - host = kzalloc(size, GFP_KERNEL); - if (host == NULL) - return NULL; - - /* Fill structure */ - host->revmap_type = revmap_type; - host->inval_irq = inval_irq; - host->ops = ops; - host->of_node = of_node_get(of_node); - - if (host->ops->match == NULL) - host->ops->match = default_irq_host_match; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* Check for the priority controller. */ - if (revmap_type == IRQ_HOST_MAP_PRIORITY) { - if (irq_map[0].host != NULL) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - of_node_put(host->of_node); - kfree(host); - return NULL; - } - irq_map[0].host = host; - } - - list_add(&host->link, &irq_hosts); - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - - /* Additional setups per revmap type */ - switch (revmap_type) { - case IRQ_HOST_MAP_PRIORITY: - /* 0 is always the invalid number for priority */ - host->inval_irq = 0; - /* setup us as the host for all priority interrupts */ - for (i = 1; i < NR_PRIORITY_IRQS; i++) { - irq_map[i].hwirq = i; - smp_wmb(); - irq_map[i].host = host; - smp_wmb(); - - ops->map(host, i, i); - } - break; - case IRQ_HOST_MAP_LINEAR: - rmap = (unsigned int *)(host + 1); - for (i = 0; i < revmap_arg; i++) - rmap[i] = NO_IRQ; - host->revmap_data.linear.size = revmap_arg; - smp_wmb(); - host->revmap_data.linear.revmap = rmap; - break; - case IRQ_HOST_MAP_TREE: - INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); - break; - default: - break; - } - - pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); - - return host; -} - -struct irq_host *irq_find_host(struct device_node *node) -{ - struct irq_host *h, *found = NULL; - unsigned long flags; - - /* We might want to match the legacy controller last since - * it might potentially be set to match all interrupts in - * the absence of a device node. This isn't a problem so far - * yet though... - */ - raw_spin_lock_irqsave(&irq_big_lock, flags); - list_for_each_entry(h, &irq_hosts, link) - if (h->ops->match(h, node)) { - found = h; - break; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_host *host) -{ - pr_debug("irq: Default host set to @0x%p\n", host); - - irq_default_host = host; -} - -void irq_set_virq_count(unsigned int count) -{ - pr_debug("irq: Trying to set virq count to %d\n", count); - - BUG_ON(count < NR_PRIORITY_IRQS); - if (count < NR_IRQS) - irq_virq_count = count; -} - -static int irq_setup_virq(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - int res; - - res = irq_alloc_desc_at(virq, 0); - if (res != virq) { - pr_debug("irq: -> allocating desc failed\n"); - goto error; - } - - /* map it */ - smp_wmb(); - irq_map[virq].hwirq = hwirq; - smp_mb(); - - if (host->ops->map(host, virq, hwirq)) { - pr_debug("irq: -> mapping failed, freeing\n"); - goto errdesc; - } - - irq_clear_status_flags(virq, IRQ_NOREQUEST); - - return 0; - -errdesc: - irq_free_descs(virq, 1); -error: - irq_free_virt(virq, 1); - return -1; -} - -unsigned int irq_create_direct_mapping(struct irq_host *host) -{ - unsigned int virq; - - if (host == NULL) - host = irq_default_host; - - BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); - - virq = irq_alloc_virt(host, 1, 0); - if (virq == NO_IRQ) { - pr_debug("irq: create_direct virq allocation failed\n"); - return NO_IRQ; - } - - pr_debug("irq: create_direct obtained virq %d\n", virq); - - if (irq_setup_virq(host, virq, virq)) - return NO_IRQ; - - return virq; -} - -unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int virq, hint; - - pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) { - printk(KERN_WARNING "irq_create_mapping called for" - " NULL host, hwirq=%lx\n", hwirq); - WARN_ON(1); - return NO_IRQ; - } - pr_debug("irq: -> using host @%p\n", host); - - /* Check if mapping already exists */ - virq = irq_find_mapping(host, hwirq); - if (virq != NO_IRQ) { - pr_debug("irq: -> existing mapping on virq %d\n", virq); - return virq; - } - - /* Allocate a virtual interrupt number */ - hint = hwirq % irq_virq_count; - virq = irq_alloc_virt(host, 1, hint); - if (virq == NO_IRQ) { - pr_debug("irq: -> virq allocation failed\n"); - return NO_IRQ; - } - - if (irq_setup_virq(host, virq, hwirq)) - return NO_IRQ; - - pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", - hwirq, host->of_node ? host->of_node->full_name : "null", virq); - - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - unsigned int virq; - - if (controller == NULL) - host = irq_default_host; - else - host = irq_find_host(controller); - if (host == NULL) { - printk(KERN_WARNING "irq: no irq host found for %s !\n", - controller->full_name); - return NO_IRQ; - } - - /* If host has no translation, then we assume interrupt line */ - if (host->ops->xlate == NULL) - hwirq = intspec[0]; - else { - if (host->ops->xlate(host, controller, intspec, intsize, - &hwirq, &type)) - return NO_IRQ; - } - - /* Create mapping */ - virq = irq_create_mapping(host, hwirq); - if (virq == NO_IRQ) - return virq; - - /* Set type if specified and different than the current one */ - if (type != IRQ_TYPE_NONE && - type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - -void irq_dispose_mapping(unsigned int virq) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - - if (virq == NO_IRQ) - return; - - /* Never unmap priority interrupts */ - if (virq < NR_PRIORITY_IRQS) - return; - - host = irq_map[virq].host; - if (WARN_ON(host == NULL)) - return; - - irq_set_status_flags(virq, IRQ_NOREQUEST); - - /* remove chip and handler */ - irq_set_chip_and_handler(virq, NULL, NULL); - - /* Make sure it's completed */ - synchronize_irq(virq); - - /* Tell the PIC about it */ - if (host->ops->unmap) - host->ops->unmap(host, virq); - smp_mb(); - - /* Clear reverse map */ - hwirq = irq_map[virq].hwirq; - switch (host->revmap_type) { - case IRQ_HOST_MAP_LINEAR: - if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; - break; - case IRQ_HOST_MAP_TREE: - mutex_lock(&revmap_trees_mutex); - radix_tree_delete(&host->revmap_data.tree, hwirq); - mutex_unlock(&revmap_trees_mutex); - break; - } - - /* Destroy map */ - smp_mb(); - irq_map[virq].hwirq = host->inval_irq; - - irq_free_descs(virq, 1); - /* Free it */ - irq_free_virt(virq, 1); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int i; - unsigned int hint = hwirq % irq_virq_count; - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) - return NO_IRQ; - - /* Slow path does a linear search of the map */ - i = hint; - do { - if (irq_map[i].host == host && - irq_map[i].hwirq == hwirq) - return i; - i++; - if (i >= irq_virq_count) - i = 4; - } while (i != hint); - return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); - -unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq) -{ - struct irq_map_entry *ptr; - unsigned int virq; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) - return irq_find_mapping(host, hwirq); - - /* - * The ptr returned references the static global irq_map. - * but freeing an irq can delete nodes along the path to - * do the lookup via call_rcu. - */ - rcu_read_lock(); - ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); - rcu_read_unlock(); - - /* - * If found in radix tree, then fine. - * Else fallback to linear lookup - this should not happen in practice - * as it means that we failed to insert the node in the radix tree. - */ - if (ptr) - virq = ptr - irq_map; - else - virq = irq_find_mapping(host, hwirq); - - return virq; -} - -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) - return; - - if (virq != NO_IRQ) { - mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, - &irq_map[virq]); - mutex_unlock(&revmap_trees_mutex); - } -} - -unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int *revmap; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) - return irq_find_mapping(host, hwirq); - - /* Check revmap bounds */ - if (unlikely(hwirq >= host->revmap_data.linear.size)) - return irq_find_mapping(host, hwirq); - - /* Check if revmap was allocated */ - revmap = host->revmap_data.linear.revmap; - if (unlikely(revmap == NULL)) - return irq_find_mapping(host, hwirq); - - /* Fill up revmap with slow path if no mapping found */ - if (unlikely(revmap[hwirq] == NO_IRQ)) - revmap[hwirq] = irq_find_mapping(host, hwirq); - - return revmap[hwirq]; -} - -unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint) -{ - unsigned long flags; - unsigned int i, j, found = NO_IRQ; - - if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS)) - return NO_IRQ; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* Use hint for 1 interrupt if any */ - if (count == 1 && hint >= NR_PRIORITY_IRQS && - hint < irq_virq_count && irq_map[hint].host == NULL) { - found = hint; - goto hint_found; - } - - /* Look for count consecutive numbers in the allocatable - * (non-legacy) space - */ - for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) { - if (irq_map[i].host != NULL) - j = 0; - else - j++; - - if (j == count) { - found = i - count + 1; - break; - } - } - if (found == NO_IRQ) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return NO_IRQ; - } - hint_found: - for (i = found; i < (found + count); i++) { - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = host; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} - -void irq_free_virt(unsigned int virq, unsigned int count) -{ - unsigned long flags; - unsigned int i; - - WARN_ON(virq < NR_PRIORITY_IRQS); - WARN_ON(count == 0 || (virq + count) > irq_virq_count); - - if (virq < NR_PRIORITY_IRQS) { - if (virq + count < NR_PRIORITY_IRQS) - return; - count -= NR_PRIORITY_IRQS - virq; - virq = NR_PRIORITY_IRQS; - } - - if (count > irq_virq_count || virq > irq_virq_count - count) { - if (virq > irq_virq_count) - return; - count = irq_virq_count - virq; - } - - raw_spin_lock_irqsave(&irq_big_lock, flags); - for (i = virq; i < (virq + count); i++) { - struct irq_host *host; - - host = irq_map[i].host; - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = NULL; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); -} - -#ifdef CONFIG_VIRQ_DEBUG -static int virq_debug_show(struct seq_file *m, void *private) -{ - unsigned long flags; - struct irq_desc *desc; - const char *p; - static const char none[] = "none"; - void *data; - int i; - - seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", - "chip name", "chip data", "host name"); - - for (i = 1; i < nr_irqs; i++) { - desc = irq_to_desc(i); - if (!desc) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - if (desc->action && desc->action->handler) { - struct irq_chip *chip; - - seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", irq_map[i].hwirq); - - chip = irq_desc_get_chip(desc); - if (chip && chip->name) - p = chip->name; - else - p = none; - seq_printf(m, "%-15s ", p); - - data = irq_desc_get_chip_data(desc); - seq_printf(m, "0x%16p ", data); - - if (irq_map[i].host && irq_map[i].host->of_node) - p = irq_map[i].host->of_node->full_name; - else - p = none; - seq_printf(m, "%s\n", p); - } - - raw_spin_unlock_irqrestore(&desc->lock, flags); - } - - return 0; -} - -static int virq_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, virq_debug_show, inode->i_private); -} - -static const struct file_operations virq_debug_fops = { - .open = virq_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init irq_debugfs_init(void) -{ - if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, - NULL, &virq_debug_fops) == NULL) - return -ENOMEM; - - return 0; -} -device_initcall(irq_debugfs_init); -#endif /* CONFIG_VIRQ_DEBUG */ diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 7c37a947fb1c..c1c4e2ae3f85 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -48,7 +48,7 @@ struct megamod_regs { }; struct megamod_pic { - struct irq_host *irqhost; + struct irq_domain *irqhost; struct megamod_regs __iomem *regs; raw_spinlock_t lock; @@ -116,7 +116,7 @@ static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc) } } -static int megamod_map(struct irq_host *h, unsigned int virq, +static int megamod_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct megamod_pic *pic = h->host_data; @@ -136,21 +136,9 @@ static int megamod_map(struct irq_host *h, unsigned int virq, return 0; } -static int megamod_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ - /* megamod intspecs must have 1 cell */ - BUG_ON(intsize != 1); - *out_hwirq = intspec[0]; - *out_type = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops megamod_host_ops = { +static const struct irq_domain_ops megamod_domain_ops = { .map = megamod_map, - .xlate = megamod_xlate, + .xlate = irq_domain_xlate_onecell, }; static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output) @@ -223,9 +211,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np) return NULL; } - pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - NR_COMBINERS * 32, &megamod_host_ops, - IRQ_UNMAPPED); + pic->irqhost = irq_domain_add_linear(np, NR_COMBINERS * 32, + &megamod_domain_ops, pic); if (!pic->irqhost) { pr_err("%s: Could not alloc host.\n", np->full_name); goto error_free; diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index e269264df7c4..ae52825021af 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -66,6 +66,10 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/highmem.h b/arch/frv/include/asm/highmem.h index a8d6565d415d..716956a5317b 100644 --- a/arch/frv/include/asm/highmem.h +++ b/arch/frv/include/asm/highmem.h @@ -157,7 +157,7 @@ static inline void kunmap_atomic_primary(void *kvaddr, enum km_type type) pagefault_enable(); } -void *__kmap_atomic(struct page *page); +void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); #endif /* !__ASSEMBLY__ */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index ce80fdadcce5..a5b1d7dbb205 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -64,6 +64,10 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c index fd7fcd4c2e33..31902c9d5be5 100644 --- a/arch/frv/mm/highmem.c +++ b/arch/frv/mm/highmem.c @@ -37,7 +37,7 @@ struct page *kmap_atomic_to_page(void *ptr) return virt_to_page(ptr); } -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned long paddr; int type; @@ -64,7 +64,7 @@ void *__kmap_atomic(struct page *page) return NULL; } } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index cf1daab6f27e..ec4554e7b04b 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -64,5 +64,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index e343357f80b9..a63218e1f6c9 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -182,7 +182,7 @@ simeth_probe1(void) unsigned char mac_addr[ETH_ALEN]; struct simeth_local *local; struct net_device *dev; - int fd, i, err, rc; + int fd, err, rc; /* * XXX Fix me @@ -223,12 +223,8 @@ simeth_probe1(void) panic("%s: out of interrupt vectors!\n", __func__); dev->irq = rc; - printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr", - dev->name, simeth_device, local->simfd); - for(i = 0; i < ETH_ALEN; i++) { - printk(" %2.2x", dev->dev_addr[i]); - } - printk(", IRQ %d\n", dev->irq); + printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr=%pm, IRQ %d\n", + dev->name, simeth_device, local->simfd, dev->dev_addr, dev->irq); return 0; } diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 4b03664e3fb5..41fc28a4a18a 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -73,5 +73,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/ia64/xen/irq_xen.c b/arch/ia64/xen/irq_xen.c index b279e142c633..3bb12230721f 100644 --- a/arch/ia64/xen/irq_xen.c +++ b/arch/ia64/xen/irq_xen.c @@ -58,7 +58,7 @@ xen_free_irq_vector(int vector) irq_op.vector = vector; if (HYPERVISOR_physdev_op(PHYSDEVOP_free_irq_vector, &irq_op)) - printk(KERN_WARNING "%s: xen_free_irq_vecotr fail vector=%d\n", + printk(KERN_WARNING "%s: xen_free_irq_vector fail vector=%d\n", __func__, vector); } diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index e8b8c5bb053c..a15f40b52783 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -64,5 +64,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index ae413d4a8bb7..d318c606c888 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -7,6 +7,7 @@ config M68K select GENERIC_IRQ_SHOW select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS select GENERIC_CPU_DEVICES + select FPU if MMU config RWSEM_GENERIC_SPINLOCK bool @@ -24,9 +25,6 @@ config ARCH_HAS_ILOG2_U64 config GENERIC_CLOCKEVENTS bool -config GENERIC_CMOS_UPDATE - def_bool !MMU - config GENERIC_GPIO bool @@ -67,6 +65,9 @@ config CPU_HAS_NO_MULDIV64 config CPU_HAS_ADDRESS_SPACES bool +config FPU + bool + config HZ int default 1000 if CLEOPATRA diff --git a/arch/m68k/include/asm/m5206sim.h b/arch/m68k/include/asm/m5206sim.h index 9015eadd5c00..69722366b084 100644 --- a/arch/m68k/include/asm/m5206sim.h +++ b/arch/m68k/include/asm/m5206sim.h @@ -100,11 +100,11 @@ #define MCFDMA_BASE1 (MCF_MBAR + 0x240) /* Base address DMA 1 */ #if defined(CONFIG_NETtel) -#define MCFUART_BASE1 0x180 /* Base address of UART1 */ -#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x180) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x140) /* Base address UART1 */ #else -#define MCFUART_BASE1 0x140 /* Base address of UART1 */ -#define MCFUART_BASE2 0x180 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x140) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x180) /* Base address UART1 */ #endif /* @@ -112,6 +112,8 @@ */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ +#define MCF_IRQ_UART0 73 /* UART0 */ +#define MCF_IRQ_UART1 74 /* UART1 */ /* * Generic GPIO diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h index eda62de7e607..17f2aab9cf97 100644 --- a/arch/m68k/include/asm/m520xsim.h +++ b/arch/m68k/include/asm/m520xsim.h @@ -48,8 +48,21 @@ #define MCFINT_UART1 27 /* Interrupt number for UART1 */ #define MCFINT_UART2 28 /* Interrupt number for UART2 */ #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ +#define MCFINT_FECRX0 36 /* Interrupt number for FEC RX */ +#define MCFINT_FECTX0 40 /* Interrupt number for FEC RX */ +#define MCFINT_FECENTC0 42 /* Interrupt number for FEC RX */ #define MCFINT_PIT1 4 /* Interrupt number for PIT1 (PIT0 in processor) */ +#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) +#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) +#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) + +#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) +#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) +#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) + +#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) + /* * SDRAM configuration registers. */ @@ -144,15 +157,25 @@ /* * UART module. */ -#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ -#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ -#define MCFUART_BASE3 0xFC068000 /* Base address of UART2 */ +#define MCFUART_BASE0 0xFC060000 /* Base address of UART0 */ +#define MCFUART_BASE1 0xFC064000 /* Base address of UART1 */ +#define MCFUART_BASE2 0xFC068000 /* Base address of UART2 */ /* * FEC module. */ -#define MCFFEC_BASE 0xFC030000 /* Base of FEC ethernet */ -#define MCFFEC_SIZE 0x800 /* Register set size */ +#define MCFFEC_BASE0 0xFC030000 /* Base of FEC ethernet */ +#define MCFFEC_SIZE0 0x800 /* Register set size */ + +/* + * QSPI module. + */ +#define MCFQSPI_BASE 0xFC05C000 /* Base of QSPI module */ +#define MCFQSPI_SIZE 0x40 /* Register set size */ + +#define MCFQSPI_CS0 46 +#define MCFQSPI_CS1 47 +#define MCFQSPI_CS2 27 /* * Reset Control Unit. diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h index 6235921eca4e..075062d4eecd 100644 --- a/arch/m68k/include/asm/m523xsim.h +++ b/arch/m68k/include/asm/m523xsim.h @@ -35,8 +35,23 @@ #define MCFINT_VECBASE 64 /* Vector base number */ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ -#define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ +#define MCFINT_UART1 14 /* Interrupt number for UART1 */ +#define MCFINT_UART2 15 /* Interrupt number for UART2 */ #define MCFINT_QSPI 18 /* Interrupt number for QSPI */ +#define MCFINT_FECRX0 23 /* Interrupt number for FEC */ +#define MCFINT_FECTX0 27 /* Interrupt number for FEC */ +#define MCFINT_FECENTC0 29 /* Interrupt number for FEC */ +#define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ + +#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) +#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) +#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) + +#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) +#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) +#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) + +#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) /* * SDRAM configuration registers. @@ -50,8 +65,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR 0x110000 -#define MCF_RSR 0x110001 +#define MCF_RCR (MCF_IPSBAR + 0x110000) +#define MCF_RSR (MCF_IPSBAR + 0x110001) #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ @@ -59,15 +74,26 @@ /* * UART module. */ -#define MCFUART_BASE1 (MCF_IPSBAR + 0x200) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x240) -#define MCFUART_BASE3 (MCF_IPSBAR + 0x280) +#define MCFUART_BASE0 (MCF_IPSBAR + 0x200) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x240) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x280) /* * FEC ethernet module. */ -#define MCFFEC_BASE (MCF_IPSBAR + 0x1000) -#define MCFFEC_SIZE 0x800 +#define MCFFEC_BASE0 (MCF_IPSBAR + 0x1000) +#define MCFFEC_SIZE0 0x800 + +/* + * QSPI module. + */ +#define MCFQSPI_BASE (MCF_IPSBAR + 0x340) +#define MCFQSPI_SIZE 0x40 + +#define MCFQSPI_CS0 91 +#define MCFQSPI_CS1 92 +#define MCFQSPI_CS2 103 +#define MCFQSPI_CS3 99 /* * GPIO module. diff --git a/arch/m68k/include/asm/m5249sim.h b/arch/m68k/include/asm/m5249sim.h index 805714ca8d7d..7f0c2c3660fd 100644 --- a/arch/m68k/include/asm/m5249sim.h +++ b/arch/m68k/include/asm/m5249sim.h @@ -76,8 +76,19 @@ /* * UART module. */ -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ + +/* + * QSPI module. + */ +#define MCFQSPI_BASE (MCF_MBAR + 0x300) /* Base address QSPI */ +#define MCFQSPI_SIZE 0x40 /* Register set size */ + +#define MCFQSPI_CS0 29 +#define MCFQSPI_CS1 24 +#define MCFQSPI_CS2 21 +#define MCFQSPI_CS3 22 /* * DMA unit base addresses. @@ -108,6 +119,9 @@ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ +#define MCF_IRQ_UART0 73 /* UART0 */ +#define MCF_IRQ_UART1 74 /* UART1 */ + /* * General purpose IO registers (in MBAR2). */ diff --git a/arch/m68k/include/asm/m5272sim.h b/arch/m68k/include/asm/m5272sim.h index 759c2b07a994..a58f1760d858 100644 --- a/arch/m68k/include/asm/m5272sim.h +++ b/arch/m68k/include/asm/m5272sim.h @@ -68,8 +68,8 @@ #define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */ #define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */ -#define MCFUART_BASE1 0x100 /* Base address of UART1 */ -#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x100) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x140) /* Base address UART1 */ #define MCFSIM_PACNT (MCF_MBAR + 0x80) /* Port A Control (r/w) */ #define MCFSIM_PADDR (MCF_MBAR + 0x84) /* Port A Direction (r/w) */ @@ -88,6 +88,9 @@ #define MCFTIMER_BASE3 (MCF_MBAR + 0x240) /* Base address TIMER4 */ #define MCFTIMER_BASE4 (MCF_MBAR + 0x260) /* Base address TIMER3 */ +#define MCFFEC_BASE0 (MCF_MBAR + 0x840) /* Base FEC ethernet */ +#define MCFFEC_SIZE0 0x1d0 + /* * Define system peripheral IRQ usage. */ @@ -101,8 +104,8 @@ #define MCF_IRQ_TIMER2 70 /* Timer 2 */ #define MCF_IRQ_TIMER3 71 /* Timer 3 */ #define MCF_IRQ_TIMER4 72 /* Timer 4 */ -#define MCF_IRQ_UART1 73 /* UART 1 */ -#define MCF_IRQ_UART2 74 /* UART 2 */ +#define MCF_IRQ_UART0 73 /* UART 0 */ +#define MCF_IRQ_UART1 74 /* UART 1 */ #define MCF_IRQ_PLIP 75 /* PLIC 2Khz Periodic */ #define MCF_IRQ_PLIA 76 /* PLIC Asynchronous */ #define MCF_IRQ_USB0 77 /* USB Endpoint 0 */ @@ -114,9 +117,9 @@ #define MCF_IRQ_USB6 83 /* USB Endpoint 6 */ #define MCF_IRQ_USB7 84 /* USB Endpoint 7 */ #define MCF_IRQ_DMA 85 /* DMA Controller */ -#define MCF_IRQ_ERX 86 /* Ethernet Receiver */ -#define MCF_IRQ_ETX 87 /* Ethernet Transmitter */ -#define MCF_IRQ_ENTC 88 /* Ethernet Non-Time Critical */ +#define MCF_IRQ_FECRX0 86 /* Ethernet Receiver */ +#define MCF_IRQ_FECTX0 87 /* Ethernet Transmitter */ +#define MCF_IRQ_FECENTC0 88 /* Ethernet Non-Time Critical */ #define MCF_IRQ_QSPI 89 /* Queued Serial Interface */ #define MCF_IRQ_EINT5 90 /* External Interrupt 5 */ #define MCF_IRQ_EINT6 91 /* External Interrupt 6 */ diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h index 758810ef91ec..83db8106f50a 100644 --- a/arch/m68k/include/asm/m527xsim.h +++ b/arch/m68k/include/asm/m527xsim.h @@ -38,8 +38,29 @@ #define MCFINT_UART1 14 /* Interrupt number for UART1 */ #define MCFINT_UART2 15 /* Interrupt number for UART2 */ #define MCFINT_QSPI 18 /* Interrupt number for QSPI */ +#define MCFINT_FECRX0 23 /* Interrupt number for FEC0 */ +#define MCFINT_FECTX0 27 /* Interrupt number for FEC0 */ +#define MCFINT_FECENTC0 29 /* Interrupt number for FEC0 */ #define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ +#define MCFINT2_VECBASE 128 /* Vector base number 2 */ +#define MCFINT2_FECRX1 23 /* Interrupt number for FEC1 */ +#define MCFINT2_FECTX1 27 /* Interrupt number for FEC1 */ +#define MCFINT2_FECENTC1 29 /* Interrupt number for FEC1 */ + +#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) +#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) +#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) + +#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) +#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) +#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) +#define MCF_IRQ_FECRX1 (MCFINT2_VECBASE + MCFINT2_FECRX1) +#define MCF_IRQ_FECTX1 (MCFINT2_VECBASE + MCFINT2_FECTX1) +#define MCF_IRQ_FECENTC1 (MCFINT2_VECBASE + MCFINT2_FECENTC1) + +#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) + /* * SDRAM configuration registers. */ @@ -72,9 +93,9 @@ /* * UART module. */ -#define MCFUART_BASE1 (MCF_IPSBAR + 0x200) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x240) -#define MCFUART_BASE3 (MCF_IPSBAR + 0x280) +#define MCFUART_BASE0 (MCF_IPSBAR + 0x200) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x240) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x280) /* * FEC ethernet module. @@ -84,6 +105,28 @@ #define MCFFEC_BASE1 (MCF_IPSBAR + 0x1800) #define MCFFEC_SIZE1 0x800 +/* + * QSPI module. + */ +#define MCFQSPI_BASE (MCF_IPSBAR + 0x340) +#define MCFQSPI_SIZE 0x40 + +#ifdef CONFIG_M5271 +#define MCFQSPI_CS0 91 +#define MCFQSPI_CS1 92 +#define MCFQSPI_CS2 99 +#define MCFQSPI_CS3 103 +#endif +#ifdef CONFIG_M5275 +#define MCFQSPI_CS0 59 +#define MCFQSPI_CS1 60 +#define MCFQSPI_CS2 61 +#define MCFQSPI_CS3 62 +#endif + +/* + * GPIO module. + */ #ifdef CONFIG_M5271 #define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000) #define MCFGPIO_PODR_DATAH (MCF_IPSBAR + 0x100001) @@ -285,8 +328,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR 0x110000 -#define MCF_RSR 0x110001 +#define MCF_RCR (MCF_IPSBAR + 0x110000) +#define MCF_RSR (MCF_IPSBAR + 0x110001) #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h index d798bd5df56c..569476fba18c 100644 --- a/arch/m68k/include/asm/m528xsim.h +++ b/arch/m68k/include/asm/m528xsim.h @@ -35,9 +35,24 @@ #define MCFINT_VECBASE 64 /* Vector base number */ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ +#define MCFINT_UART1 14 /* Interrupt number for UART1 */ +#define MCFINT_UART2 15 /* Interrupt number for UART2 */ #define MCFINT_QSPI 18 /* Interrupt number for QSPI */ +#define MCFINT_FECRX0 23 /* Interrupt number for FEC */ +#define MCFINT_FECTX0 27 /* Interrupt number for FEC */ +#define MCFINT_FECENTC0 29 /* Interrupt number for FEC */ #define MCFINT_PIT1 55 /* Interrupt number for PIT1 */ +#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) +#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) +#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) + +#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) +#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) +#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) + +#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) + /* * SDRAM configuration registers. */ @@ -58,15 +73,26 @@ /* * UART module. */ -#define MCFUART_BASE1 (MCF_IPSBAR + 0x00000200) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x00000240) -#define MCFUART_BASE3 (MCF_IPSBAR + 0x00000280) +#define MCFUART_BASE0 (MCF_IPSBAR + 0x00000200) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x00000240) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x00000280) /* * FEC ethernet module. */ -#define MCFFEC_BASE (MCF_IPSBAR + 0x00001000) -#define MCFFEC_SIZE 0x800 +#define MCFFEC_BASE0 (MCF_IPSBAR + 0x00001000) +#define MCFFEC_SIZE0 0x800 + +/* + * QSPI module. + */ +#define MCFQSPI_IOBASE (MCF_IPSBAR + 0x340) +#define MCFQSPI_SIZE 0x40 + +#define MCFQSPI_CS0 147 +#define MCFQSPI_CS1 148 +#define MCFQSPI_CS2 149 +#define MCFQSPI_CS3 150 /* * GPIO registers @@ -246,8 +272,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR 0x110000 -#define MCF_RSR 0x110001 +#define MCF_RCR (MCF_IPSBAR + 0x110000) +#define MCF_RSR (MCF_IPSBAR + 0x110001) #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ diff --git a/arch/m68k/include/asm/m5307sim.h b/arch/m68k/include/asm/m5307sim.h index 8f8609fcc9b8..3bc3adaa7ee0 100644 --- a/arch/m68k/include/asm/m5307sim.h +++ b/arch/m68k/include/asm/m5307sim.h @@ -117,11 +117,11 @@ * UART module. */ #if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) -#define MCFUART_BASE1 0x200 /* Base address of UART1 */ -#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x200) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x1c0) /* Base address UART1 */ #else -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ #endif /* @@ -176,6 +176,8 @@ */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ +#define MCF_IRQ_UART0 73 /* UART0 */ +#define MCF_IRQ_UART1 74 /* UART1 */ /****************************************************************************/ #endif /* m5307sim_h */ diff --git a/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h index ba4cc784f574..29b66e21413a 100644 --- a/arch/m68k/include/asm/m532xsim.h +++ b/arch/m68k/include/asm/m532xsim.h @@ -24,6 +24,19 @@ #define MCFINT_UART1 27 /* Interrupt number for UART1 */ #define MCFINT_UART2 28 /* Interrupt number for UART2 */ #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ +#define MCFINT_FECRX0 36 /* Interrupt number for FEC */ +#define MCFINT_FECTX0 40 /* Interrupt number for FEC */ +#define MCFINT_FECENTC0 42 /* Interrupt number for FEC */ + +#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) +#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) +#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) + +#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) +#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) +#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) + +#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) #define MCF_WTM_WCR MCF_REG16(0xFC098000) @@ -82,9 +95,25 @@ /* * UART module. */ -#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ -#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ -#define MCFUART_BASE3 0xFC068000 /* Base address of UART3 */ +#define MCFUART_BASE0 0xFC060000 /* Base address of UART1 */ +#define MCFUART_BASE1 0xFC064000 /* Base address of UART2 */ +#define MCFUART_BASE2 0xFC068000 /* Base address of UART3 */ + +/* + * FEC module. + */ +#define MCFFEC_BASE0 0xFC030000 /* Base address of FEC0 */ +#define MCFFEC_SIZE0 0x800 /* Size of FEC0 region */ + +/* + * QSPI module. + */ +#define MCFQSPI_BASE 0xFC058000 /* Base address of QSPI */ +#define MCFQSPI_SIZE 0x40 /* Size of QSPI region */ + +#define MCFQSPI_CS0 84 +#define MCFQSPI_CS1 85 +#define MCFQSPI_CS2 86 /* * Timer module. diff --git a/arch/m68k/include/asm/m5407sim.h b/arch/m68k/include/asm/m5407sim.h index 51e00b00b8a6..79f58dd6a83d 100644 --- a/arch/m68k/include/asm/m5407sim.h +++ b/arch/m68k/include/asm/m5407sim.h @@ -85,8 +85,8 @@ #define MCFTIMER_BASE1 (MCF_MBAR + 0x140) /* Base of TIMER1 */ #define MCFTIMER_BASE2 (MCF_MBAR + 0x180) /* Base of TIMER2 */ -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ #define MCFSIM_PADDR (MCF_MBAR + 0x244) #define MCFSIM_PADAT (MCF_MBAR + 0x248) @@ -139,6 +139,8 @@ */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ +#define MCF_IRQ_UART0 73 /* UART0 */ +#define MCF_IRQ_UART1 74 /* UART1 */ /****************************************************************************/ #endif /* m5407sim_h */ diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h index 1ed8bfb02772..ae56b8848a9d 100644 --- a/arch/m68k/include/asm/m54xxsim.h +++ b/arch/m68k/include/asm/m54xxsim.h @@ -31,16 +31,20 @@ /* * UART module. */ -#define MCFUART_BASE1 0x8600 /* Base address of UART1 */ -#define MCFUART_BASE2 0x8700 /* Base address of UART2 */ -#define MCFUART_BASE3 0x8800 /* Base address of UART3 */ -#define MCFUART_BASE4 0x8900 /* Base address of UART4 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x8600) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x8700) /* Base address UART1 */ +#define MCFUART_BASE2 (MCF_MBAR + 0x8800) /* Base address UART2 */ +#define MCFUART_BASE3 (MCF_MBAR + 0x8900) /* Base address UART3 */ /* * Define system peripheral IRQ usage. */ -#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */ -#define MCF_IRQ_PROFILER (64 + 53) /* Slice Timer 1 */ +#define MCF_IRQ_TIMER (MCFINT_VECBASE + 54) /* Slice Timer 0 */ +#define MCF_IRQ_PROFILER (MCFINT_VECBASE + 53) /* Slice Timer 1 */ +#define MCF_IRQ_UART0 (MCFINT_VECBASE + 35) +#define MCF_IRQ_UART1 (MCFINT_VECBASE + 34) +#define MCF_IRQ_UART2 (MCFINT_VECBASE + 33) +#define MCF_IRQ_UART3 (MCFINT_VECBASE + 32) /* * Generic GPIO support diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h index 789f3b2de0e9..825c1c813196 100644 --- a/arch/m68k/include/asm/machdep.h +++ b/arch/m68k/include/asm/machdep.h @@ -22,8 +22,6 @@ extern unsigned int (*mach_get_ss)(void); extern int (*mach_get_rtc_pll)(struct rtc_pll_info *); extern int (*mach_set_rtc_pll)(struct rtc_pll_info *); extern int (*mach_set_clock_mmss)(unsigned long); -extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour, - int *min, int *sec); extern void (*mach_reset)( void ); extern void (*mach_halt)( void ); extern void (*mach_power_off)( void ); @@ -35,9 +33,8 @@ extern void (*mach_l2_flush) (int); extern void (*mach_beep) (unsigned int, unsigned int); /* Hardware clock functions */ -extern void hw_timer_init(void); +extern void hw_timer_init(irq_handler_t handler); extern unsigned long hw_timer_offset(void); -extern irqreturn_t arch_timer_interrupt(int irq, void *dummy); extern void config_BSP(char *command, int len); diff --git a/arch/m68k/include/asm/mcfqspi.h b/arch/m68k/include/asm/mcfqspi.h index 7fe631972f1f..7b51416ccae2 100644 --- a/arch/m68k/include/asm/mcfqspi.h +++ b/arch/m68k/include/asm/mcfqspi.h @@ -21,17 +21,6 @@ #ifndef mcfqspi_h #define mcfqspi_h -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) -#define MCFQSPI_IOBASE (MCF_IPSBAR + 0x340) -#elif defined(CONFIG_M5249) -#define MCFQSPI_IOBASE (MCF_MBAR + 0x300) -#elif defined(CONFIG_M520x) -#define MCFQSPI_IOBASE 0xFC05C000 -#elif defined(CONFIG_M532x) -#define MCFQSPI_IOBASE 0xFC058000 -#endif -#define MCFQSPI_IOSIZE 0x40 - /** * struct mcfqspi_cs_control - chip select control for the coldfire qspi driver * @setup: setup the control; allocate gpio's, etc. May be NULL. diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h index 2abedff0a694..2d3bc774b3c5 100644 --- a/arch/m68k/include/asm/mcfuart.h +++ b/arch/m68k/include/asm/mcfuart.h @@ -41,7 +41,10 @@ struct mcf_platform_uart { #define MCFUART_UTF 0x28 /* Transmitter FIFO (r/w) */ #define MCFUART_URF 0x2c /* Receiver FIFO (r/w) */ #define MCFUART_UFPD 0x30 /* Frac Prec. Divider (r/w) */ -#else +#endif +#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ + defined(CONFIG_M5249) || defined(CONFIG_M5307) || \ + defined(CONFIG_M5407) #define MCFUART_UIVR 0x30 /* Interrupt Vector (r/w) */ #endif #define MCFUART_UIPR 0x34 /* Input Port (r) */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index d4708ce466e0..d1be684edf97 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -64,5 +64,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 6cf4bd6e34f8..c54ef927e483 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -1,5 +1,378 @@ +/* + * linux/arch/m68k/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/smp.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/user.h> +#include <linux/reboot.h> +#include <linux/init_task.h> +#include <linux/mqueue.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/traps.h> +#include <asm/machdep.h> +#include <asm/setup.h> +#include <asm/pgtable.h> + + +asmlinkage void ret_from_fork(void); + + +/* + * Return saved PC from a blocked thread + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; + /* Check whether the thread is blocked in resume() */ + if (in_sched_functions(sw->retpc)) + return ((unsigned long *)sw->a6)[1]; + else + return sw->retpc; +} + +/* + * The idle loop on an m68k.. + */ +static void default_idle(void) +{ + if (!need_resched()) +#if defined(MACH_ATARI_ONLY) + /* block out HSYNC on the atari (falcon) */ + __asm__("stop #0x2200" : : : "cc"); +#else + __asm__("stop #0x2000" : : : "cc"); +#endif +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) + idle(); + schedule_preempt_disabled(); + } +} + +void machine_restart(char * __unused) +{ + if (mach_reset) + mach_reset(); + for (;;); +} + +void machine_halt(void) +{ + if (mach_halt) + mach_halt(); + for (;;); +} + +void machine_power_off(void) +{ + if (mach_power_off) + mach_power_off(); + for (;;); +} + +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL(pm_power_off); + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", + regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); + printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a2, regs->a1); + printk("A0: %08lx D5: %08lx D4: %08lx\n", + regs->a0, regs->d5, regs->d4); + printk("D3: %08lx D2: %08lx D1: %08lx\n", + regs->d3, regs->d2, regs->d1); + if (!(regs->sr & PS_S)) + printk("USP: %08lx\n", rdusp()); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + int pid; + mm_segment_t fs; + + fs = get_fs(); + set_fs (KERNEL_DS); + + { + register long retval __asm__ ("d0"); + register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; + + retval = __NR_clone; + __asm__ __volatile__ + ("clrl %%d2\n\t" + "trap #0\n\t" /* Linux/m68k system call */ + "tstl %0\n\t" /* child or parent */ + "jne 1f\n\t" /* parent - jump */ +#ifdef CONFIG_MMU + "lea %%sp@(%c7),%6\n\t" /* reload current */ + "movel %6@,%6\n\t" +#endif + "movel %3,%%sp@-\n\t" /* push argument */ + "jsr %4@\n\t" /* call fn */ + "movel %0,%%d1\n\t" /* pass exit value */ + "movel %2,%%d0\n\t" /* exit */ + "trap #0\n" + "1:" + : "+d" (retval) + : "i" (__NR_clone), "i" (__NR_exit), + "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), + "i" (-THREAD_SIZE) + : "d2"); + + pid = retval; + } + + set_fs (fs); + return pid; +} +EXPORT_SYMBOL(kernel_thread); + +void flush_thread(void) +{ + current->thread.fs = __USER_DS; +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + unsigned long zero = 0; + asm volatile("frestore %0": :"m" (zero)); + } +#endif +} + +/* + * "m68k_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int m68k_fork(struct pt_regs *regs) +{ #ifdef CONFIG_MMU -#include "process_mm.c" + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); #else -#include "process_no.c" + return -EINVAL; #endif +} + +asmlinkage int m68k_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, + NULL, NULL); +} + +asmlinkage int m68k_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + /* syscall2 puts clone_flags in d1 and usp in d2 */ + clone_flags = regs->d1; + newsp = regs->d2; + parent_tidptr = (int __user *)regs->d3; + child_tidptr = (int __user *)regs->d4; + if (!newsp) + newsp = rdusp(); + return do_fork(clone_flags, newsp, regs, 0, + parent_tidptr, child_tidptr); +} + +int copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long *retp; + + childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; + + *childregs = *regs; + childregs->d0 = 0; + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->retpc = (unsigned long)ret_from_fork; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childstack; + + if (clone_flags & CLONE_SETTLS) + task_thread_info(p)->tp_value = regs->d5; + + /* + * Must save the current SFC/DFC value, NOT the value when + * the parent was last descheduled - RGH 10-08-96 + */ + p->thread.fs = get_fs().seg; + +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { + if (CPU_IS_COLDFIRE) { + asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" + "fmovel %/fpiar,%1\n\t" + "fmovel %/fpcr,%2\n\t" + "fmovel %/fpsr,%3" + : + : "m" (p->thread.fp[0]), + "m" (p->thread.fpcntl[0]), + "m" (p->thread.fpcntl[1]), + "m" (p->thread.fpcntl[2]) + : "memory"); + } else { + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : + : "m" (p->thread.fp[0]), + "m" (p->thread.fpcntl[0]) + : "memory"); + } + } + + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } +#endif /* CONFIG_FPU */ + + return 0; +} + +/* Fill in the fpu structure for a core dump. */ +#ifdef CONFIG_FPU +int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) +{ + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } + + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; + + if (CPU_IS_COLDFIRE) { + asm volatile ("fmovel %/fpiar,%0\n\t" + "fmovel %/fpcr,%1\n\t" + "fmovel %/fpsr,%2\n\t" + "fmovemd %/fp0-%/fp7,%3" + : + : "m" (fpu->fpcntl[0]), + "m" (fpu->fpcntl[1]), + "m" (fpu->fpcntl[2]), + "m" (fpu->fpregs[0]) + : "memory"); + } else { + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + : + : "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + : + : "m" (fpu->fpregs[0]) + : "memory"); + } + + return 1; +} +EXPORT_SYMBOL(dump_fpu); +#endif /* CONFIG_FPU */ + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) &name; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + return error; + error = do_execve(filename, argv, envp, regs); + putname(filename); + return error; +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)task_stack_page(p); + fp = ((struct switch_stack *)p->thread.ksp)->a6; + do { + if (fp < stack_page+sizeof(struct thread_info) || + fp >= 8184+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); + return 0; +} diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c deleted file mode 100644 index fe4186b5fc32..000000000000 --- a/arch/m68k/kernel/process_mm.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * linux/arch/m68k/kernel/process.c - * - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/smp.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/reboot.h> -#include <linux/init_task.h> -#include <linux/mqueue.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/machdep.h> -#include <asm/setup.h> -#include <asm/pgtable.h> - - -asmlinkage void ret_from_fork(void); - - -/* - * Return saved PC from a blocked thread - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; - /* Check whether the thread is blocked in resume() */ - if (in_sched_functions(sw->retpc)) - return ((unsigned long *)sw->a6)[1]; - else - return sw->retpc; -} - -/* - * The idle loop on an m68k.. - */ -static void default_idle(void) -{ - if (!need_resched()) -#if defined(MACH_ATARI_ONLY) - /* block out HSYNC on the atari (falcon) */ - __asm__("stop #0x2200" : : : "cc"); -#else - __asm__("stop #0x2000" : : : "cc"); -#endif -} - -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ - /* endless idle loop with no priority at all */ - while (1) { - while (!need_resched()) - idle(); - schedule_preempt_disabled(); - } -} - -void machine_restart(char * __unused) -{ - if (mach_reset) - mach_reset(); - for (;;); -} - -void machine_halt(void) -{ - if (mach_halt) - mach_halt(); - for (;;); -} - -void machine_power_off(void) -{ - if (mach_power_off) - mach_power_off(); - for (;;); -} - -void (*pm_power_off)(void) = machine_power_off; -EXPORT_SYMBOL(pm_power_off); - -void show_regs(struct pt_regs * regs) -{ - printk("\n"); - printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", - regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); - printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", - regs->orig_d0, regs->d0, regs->a2, regs->a1); - printk("A0: %08lx D5: %08lx D4: %08lx\n", - regs->a0, regs->d5, regs->d4); - printk("D3: %08lx D2: %08lx D1: %08lx\n", - regs->d3, regs->d2, regs->d1); - if (!(regs->sr & PS_S)) - printk("USP: %08lx\n", rdusp()); -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - mm_segment_t fs; - - fs = get_fs(); - set_fs (KERNEL_DS); - - { - register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; - - retval = __NR_clone; - __asm__ __volatile__ - ("clrl %%d2\n\t" - "trap #0\n\t" /* Linux/m68k system call */ - "tstl %0\n\t" /* child or parent */ - "jne 1f\n\t" /* parent - jump */ - "lea %%sp@(%c7),%6\n\t" /* reload current */ - "movel %6@,%6\n\t" - "movel %3,%%sp@-\n\t" /* push argument */ - "jsr %4@\n\t" /* call fn */ - "movel %0,%%d1\n\t" /* pass exit value */ - "movel %2,%%d0\n\t" /* exit */ - "trap #0\n" - "1:" - : "+d" (retval) - : "i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), - "i" (-THREAD_SIZE) - : "d2"); - - pid = retval; - } - - set_fs (fs); - return pid; -} -EXPORT_SYMBOL(kernel_thread); - -void flush_thread(void) -{ - unsigned long zero = 0; - - current->thread.fs = __USER_DS; - if (!FPU_IS_EMU) - asm volatile("frestore %0": :"m" (zero)); -} - -/* - * "m68k_fork()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - */ - -asmlinkage int m68k_fork(struct pt_regs *regs) -{ - return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); -} - -asmlinkage int m68k_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, - NULL, NULL); -} - -asmlinkage int m68k_clone(struct pt_regs *regs) -{ - unsigned long clone_flags; - unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; - - /* syscall2 puts clone_flags in d1 and usp in d2 */ - clone_flags = regs->d1; - newsp = regs->d2; - parent_tidptr = (int __user *)regs->d3; - child_tidptr = (int __user *)regs->d4; - if (!newsp) - newsp = rdusp(); - return do_fork(clone_flags, newsp, regs, 0, - parent_tidptr, child_tidptr); -} - -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct * p, struct pt_regs * regs) -{ - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long *retp; - - childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; - - p->thread.usp = usp; - p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; - - /* - * Must save the current SFC/DFC value, NOT the value when - * the parent was last descheduled - RGH 10-08-96 - */ - p->thread.fs = get_fs().seg; - - if (!FPU_IS_EMU) { - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); - - if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { - if (CPU_IS_COLDFIRE) { - asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" - "fmovel %/fpiar,%1\n\t" - "fmovel %/fpcr,%2\n\t" - "fmovel %/fpsr,%3" - : - : "m" (p->thread.fp[0]), - "m" (p->thread.fpcntl[0]), - "m" (p->thread.fpcntl[1]), - "m" (p->thread.fpcntl[2]) - : "memory"); - } else { - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : - : "m" (p->thread.fp[0]), - "m" (p->thread.fpcntl[0]) - : "memory"); - } - } - - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); - } - - return 0; -} - -/* Fill in the fpu structure for a core dump. */ - -int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) -{ - char fpustate[216]; - - if (FPU_IS_EMU) { - int i; - - memcpy(fpu->fpcntl, current->thread.fpcntl, 12); - memcpy(fpu->fpregs, current->thread.fp, 96); - /* Convert internal fpu reg representation - * into long double format - */ - for (i = 0; i < 24; i += 3) - fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | - ((fpu->fpregs[i] & 0x0000ffff) << 16); - return 1; - } - - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) - return 0; - - if (CPU_IS_COLDFIRE) { - asm volatile ("fmovel %/fpiar,%0\n\t" - "fmovel %/fpcr,%1\n\t" - "fmovel %/fpsr,%2\n\t" - "fmovemd %/fp0-%/fp7,%3" - : - : "m" (fpu->fpcntl[0]), - "m" (fpu->fpcntl[1]), - "m" (fpu->fpcntl[2]), - "m" (fpu->fpregs[0]) - : "memory"); - } else { - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" - : - : "m" (fpu->fpcntl[0]) - : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" - : - : "m" (fpu->fpregs[0]) - : "memory"); - } - - return 1; -} -EXPORT_SYMBOL(dump_fpu); - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - int error; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long fp, pc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - stack_page = (unsigned long)task_stack_page(p); - fp = ((struct switch_stack *)p->thread.ksp)->a6; - do { - if (fp < stack_page+sizeof(struct thread_info) || - fp >= 8184+stack_page) - return 0; - pc = ((unsigned long *)fp)[1]; - if (!in_sched_functions(pc)) - return pc; - fp = *(unsigned long *) fp; - } while (count++ < 16); - return 0; -} diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c deleted file mode 100644 index f7fe6c348595..000000000000 --- a/arch/m68k/kernel/process_no.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/process.c - * - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - * - * uClinux changes - * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com> - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/fs.h> -#include <linux/slab.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/machdep.h> -#include <asm/setup.h> -#include <asm/pgtable.h> - -asmlinkage void ret_from_fork(void); - -/* - * The following aren't currently used. - */ -void (*pm_idle)(void); -EXPORT_SYMBOL(pm_idle); - -void (*pm_power_off)(void); -EXPORT_SYMBOL(pm_power_off); - -/* - * The idle loop on an m68knommu.. - */ -static void default_idle(void) -{ - local_irq_disable(); - while (!need_resched()) { - /* This stop will re-enable interrupts */ - __asm__("stop #0x2000" : : : "cc"); - local_irq_disable(); - } - local_irq_enable(); -} - -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ - /* endless idle loop with no priority at all */ - while (1) { - idle(); - schedule_preempt_disabled(); - } -} - -void machine_restart(char * __unused) -{ - if (mach_reset) - mach_reset(); - for (;;); -} - -void machine_halt(void) -{ - if (mach_halt) - mach_halt(); - for (;;); -} - -void machine_power_off(void) -{ - if (mach_power_off) - mach_power_off(); - for (;;); -} - -void show_regs(struct pt_regs * regs) -{ - printk(KERN_NOTICE "\n"); - printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", - regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); - printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", - regs->orig_d0, regs->d0, regs->a2, regs->a1); - printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n", - regs->a0, regs->d5, regs->d4); - printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n", - regs->d3, regs->d2, regs->d1); - if (!(regs->sr & PS_S)) - printk(KERN_NOTICE "USP: %08lx\n", rdusp()); -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int retval; - long clone_arg = flags | CLONE_VM; - mm_segment_t fs; - - fs = get_fs(); - set_fs(KERNEL_DS); - - __asm__ __volatile__ ( - "movel %%sp, %%d2\n\t" - "movel %5, %%d1\n\t" - "movel %1, %%d0\n\t" - "trap #0\n\t" - "cmpl %%sp, %%d2\n\t" - "jeq 1f\n\t" - "movel %3, %%sp@-\n\t" - "jsr %4@\n\t" - "movel %2, %%d0\n\t" - "trap #0\n" - "1:\n\t" - "movel %%d0, %0\n" - : "=d" (retval) - : "i" (__NR_clone), - "i" (__NR_exit), - "a" (arg), - "a" (fn), - "a" (clone_arg) - : "cc", "%d0", "%d1", "%d2"); - - set_fs(fs); - return retval; -} -EXPORT_SYMBOL(kernel_thread); - -void flush_thread(void) -{ -#ifdef CONFIG_FPU - unsigned long zero = 0; -#endif - - current->thread.fs = __USER_DS; -#ifdef CONFIG_FPU - if (!FPU_IS_EMU) - asm volatile (".chip 68k/68881\n\t" - "frestore %0\n\t" - ".chip 68k" : : "m" (zero)); -#endif -} - -/* - * "m68k_fork()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - */ - -asmlinkage int m68k_fork(struct pt_regs *regs) -{ - /* fork almost works, enough to trick you into looking elsewhere :-( */ - return(-EINVAL); -} - -asmlinkage int m68k_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); -} - -asmlinkage int m68k_clone(struct pt_regs *regs) -{ - unsigned long clone_flags; - unsigned long newsp; - - /* syscall2 puts clone_flags in d1 and usp in d2 */ - clone_flags = regs->d1; - newsp = regs->d2; - if (!newsp) - newsp = rdusp(); - return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); -} - -int copy_thread(unsigned long clone_flags, - unsigned long usp, unsigned long topstk, - struct task_struct * p, struct pt_regs * regs) -{ - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long *retp; - - childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; - - p->thread.usp = usp; - p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; - - /* - * Must save the current SFC/DFC value, NOT the value when - * the parent was last descheduled - RGH 10-08-96 - */ - p->thread.fs = get_fs().seg; - -#ifdef CONFIG_FPU - if (!FPU_IS_EMU) { - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); - - if (p->thread.fpstate[0]) - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) - : "memory"); - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); - } -#endif - - return 0; -} - -/* Fill in the fpu structure for a core dump. */ - -int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) -{ -#ifdef CONFIG_FPU - char fpustate[216]; - - if (FPU_IS_EMU) { - int i; - - memcpy(fpu->fpcntl, current->thread.fpcntl, 12); - memcpy(fpu->fpregs, current->thread.fp, 96); - /* Convert internal fpu reg representation - * into long double format - */ - for (i = 0; i < 24; i += 3) - fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | - ((fpu->fpregs[i] & 0x0000ffff) << 16); - return 1; - } - - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!fpustate[0]) - return 0; - - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" - :: "m" (fpu->fpcntl[0]) - : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" - :: "m" (fpu->fpregs[0]) - : "memory"); -#endif - return 1; -} -EXPORT_SYMBOL(dump_fpu); - -/* - * Generic dumping code. Used for panic and debug. - */ -void dump(struct pt_regs *fp) -{ - unsigned long *sp; - unsigned char *tp; - int i; - - printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); - printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); - - if (current->mm) { - printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", - (int) current->mm->start_code, - (int) current->mm->end_code, - (int) current->mm->start_data, - (int) current->mm->end_data, - (int) current->mm->end_data, - (int) current->mm->brk); - printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", - (int) current->mm->start_stack, - (int)(((unsigned long) current) + THREAD_SIZE)); - } - - printk(KERN_EMERG "PC: %08lx\n", fp->pc); - printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp); - printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", - fp->d0, fp->d1, fp->d2, fp->d3); - printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", - fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n", - (unsigned int) rdusp(), fp); - - printk(KERN_EMERG "\nCODE:"); - tp = ((unsigned char *) fp->pc) - 0x20; - for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { - if ((i % 0x10) == 0) - printk(KERN_EMERG "%p: ", tp + i); - printk("%08x ", (int) *sp++); - } - printk(KERN_EMERG "\n"); - - printk(KERN_EMERG "KERNEL STACK:"); - tp = ((unsigned char *) fp) - 0x40; - for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { - if ((i % 0x10) == 0) - printk(KERN_EMERG "%p: ", tp + i); - printk("%08x ", (int) *sp++); - } - printk(KERN_EMERG "\n"); - - printk(KERN_EMERG "USER STACK:"); - tp = (unsigned char *) (rdusp() - 0x10); - for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { - if ((i % 0x10) == 0) - printk(KERN_EMERG "%p: ", tp + i); - printk("%08x ", (int) *sp++); - } - printk(KERN_EMERG "\n"); -} - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char *name, - const char *const *argv, - const char *const *envp) -{ - int error; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long fp, pc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - stack_page = (unsigned long)p; - fp = ((struct switch_stack *)p->thread.ksp)->a6; - do { - if (fp < stack_page+sizeof(struct thread_info) || - fp >= THREAD_SIZE-8+stack_page) - return 0; - pc = ((unsigned long *)fp)[1]; - if (!in_sched_functions(pc)) - return pc; - fp = *(unsigned long *) fp; - } while (count++ < 16); - return 0; -} - -/* - * Return saved PC of a blocked thread. - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; - - /* Check whether the thread is blocked in resume() */ - if (in_sched_functions(sw->retpc)) - return ((unsigned long *)sw->a6)[1]; - else - return sw->retpc; -} - diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 07a417550e94..149a05f8b9ee 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -1,5 +1,305 @@ +/* + * linux/arch/m68k/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of + * this archive for more details. + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/user.h> +#include <linux/signal.h> +#include <linux/tracehook.h> + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/processor.h> + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x001f + +/* sets the trace bits. */ +#define TRACE_BITS 0xC000 +#define T1_BIT 0x8000 +#define T0_BIT 0x4000 + +/* Find the stack offset for a register, relative to thread.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static const int regoff[] = { + [0] = PT_REG(d1), + [1] = PT_REG(d2), + [2] = PT_REG(d3), + [3] = PT_REG(d4), + [4] = PT_REG(d5), + [5] = SW_REG(d6), + [6] = SW_REG(d7), + [7] = PT_REG(a0), + [8] = PT_REG(a1), + [9] = PT_REG(a2), + [10] = SW_REG(a3), + [11] = SW_REG(a4), + [12] = SW_REG(a5), + [13] = SW_REG(a6), + [14] = PT_REG(d0), + [15] = -1, + [16] = PT_REG(orig_d0), + [17] = PT_REG(sr), + [18] = PT_REG(pc), +}; + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return 0; + /* Need to take stkadj into account. */ + if (regno == PT_SR || regno == PT_PC) { + long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); + addr = (unsigned long *) ((unsigned long)addr + stkadj); + /* The sr is actually a 16 bit register. */ + if (regno == PT_SR) + return *(unsigned short *)addr; + } + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return -1; + /* Need to take stkadj into account. */ + if (regno == PT_SR || regno == PT_PC) { + long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); + addr = (unsigned long *) ((unsigned long)addr + stkadj); + /* The sr is actually a 16 bit register. */ + if (regno == PT_SR) { + *(unsigned short *)addr = data; + return 0; + } + } + *addr = data; + return 0; +} + +/* + * Make sure the single step bit is not set. + */ +static inline void singlestep_disable(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp); + clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); +} + +/* + * Called by kernel/ptrace.c when detaching.. + */ +void ptrace_disable(struct task_struct *child) +{ + singlestep_disable(child); +} + +void user_enable_single_step(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp | T1_BIT); + set_tsk_thread_flag(child, TIF_DELAYED_TRACE); +} + #ifdef CONFIG_MMU -#include "ptrace_mm.c" -#else -#include "ptrace_no.c" +void user_enable_block_step(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp | T0_BIT); +} #endif + +void user_disable_single_step(struct task_struct *child) +{ + singlestep_disable(child); +} + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + unsigned long tmp; + int i, ret = 0; + int regno = addr >> 2; /* temporary hack. */ + unsigned long __user *datap = (unsigned long __user *) data; + + switch (request) { + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: + if (addr & 3) + goto out_eio; + + if (regno >= 0 && regno < 19) { + tmp = get_reg(child, regno); + } else if (regno >= 21 && regno < 49) { + tmp = child->thread.fp[regno - 21]; + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#ifndef CONFIG_MMU + } else if (regno == 49) { + tmp = child->mm->start_code; + } else if (regno == 50) { + tmp = child->mm->start_data; + } else if (regno == 51) { + tmp = child->mm->end_code; +#endif + } else + goto out_eio; + ret = put_user(tmp, datap); + break; + + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area */ + if (addr & 3) + goto out_eio; + + if (regno == PT_SR) { + data &= SR_MASK; + data |= get_reg(child, PT_SR) & ~SR_MASK; + } + if (regno >= 0 && regno < 19) { + if (put_reg(child, regno, data)) + goto out_eio; + } else if (regno >= 21 && regno < 48) { + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { + data <<= 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } + child->thread.fp[regno - 21] = data; + } else + goto out_eio; + break; + + case PTRACE_GETREGS: /* Get all gp regs from the child. */ + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + ret = put_user(tmp, datap); + if (ret) + break; + datap++; + } + break; + + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + for (i = 0; i < 19; i++) { + ret = get_user(tmp, datap); + if (ret) + break; + if (i == PT_SR) { + tmp &= SR_MASK; + tmp |= get_reg(child, PT_SR) & ~SR_MASK; + } + put_reg(child, i, tmp); + datap++; + } + break; + + case PTRACE_GETFPREGS: /* Get the child FPU state. */ + if (copy_to_user(datap, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_SETFPREGS: /* Set the child FPU state. */ + if (copy_from_user(&child->thread.fp, datap, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_GET_THREAD_AREA: + ret = put_user(task_thread_info(child)->tp_value, datap); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +out_eio: + return -EIO; +} + +asmlinkage void syscall_trace(void) +{ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + +#ifdef CONFIG_COLDFIRE +asmlinkage int syscall_trace_enter(void) +{ + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(task_pt_regs(current)); + return ret; +} + +asmlinkage void syscall_trace_leave(void) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(task_pt_regs(current), 0); +} +#endif /* CONFIG_COLDFIRE */ diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c deleted file mode 100644 index 7bc999b73529..000000000000 --- a/arch/m68k/kernel/ptrace_mm.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * linux/arch/m68k/kernel/ptrace.c - * - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of - * this archive for more details. - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/signal.h> -#include <linux/tracehook.h> - -#include <asm/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/processor.h> - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in the SR the user has access to. */ -/* 1 = access 0 = no access */ -#define SR_MASK 0x001f - -/* sets the trace bits. */ -#define TRACE_BITS 0xC000 -#define T1_BIT 0x8000 -#define T0_BIT 0x4000 - -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) -#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ - - sizeof(struct switch_stack)) -/* Mapping from PT_xxx to the stack offset at which the register is - saved. Notice that usp has no stack-slot and needs to be treated - specially (see get_reg/put_reg below). */ -static const int regoff[] = { - [0] = PT_REG(d1), - [1] = PT_REG(d2), - [2] = PT_REG(d3), - [3] = PT_REG(d4), - [4] = PT_REG(d5), - [5] = SW_REG(d6), - [6] = SW_REG(d7), - [7] = PT_REG(a0), - [8] = PT_REG(a1), - [9] = PT_REG(a2), - [10] = SW_REG(a3), - [11] = SW_REG(a4), - [12] = SW_REG(a5), - [13] = SW_REG(a6), - [14] = PT_REG(d0), - [15] = -1, - [16] = PT_REG(orig_d0), - [17] = PT_REG(sr), - [18] = PT_REG(pc), -}; - -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, int regno) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return 0; - /* Need to take stkadj into account. */ - if (regno == PT_SR || regno == PT_PC) { - long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); - addr = (unsigned long *) ((unsigned long)addr + stkadj); - /* The sr is actually a 16 bit register. */ - if (regno == PT_SR) - return *(unsigned short *)addr; - } - return *addr; -} - -/* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, int regno, - unsigned long data) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return -1; - /* Need to take stkadj into account. */ - if (regno == PT_SR || regno == PT_PC) { - long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); - addr = (unsigned long *) ((unsigned long)addr + stkadj); - /* The sr is actually a 16 bit register. */ - if (regno == PT_SR) { - *(unsigned short *)addr = data; - return 0; - } - } - *addr = data; - return 0; -} - -/* - * Make sure the single step bit is not set. - */ -static inline void singlestep_disable(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp); - clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); -} - -/* - * Called by kernel/ptrace.c when detaching.. - */ -void ptrace_disable(struct task_struct *child) -{ - singlestep_disable(child); -} - -void user_enable_single_step(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp | T1_BIT); - set_tsk_thread_flag(child, TIF_DELAYED_TRACE); -} - -void user_enable_block_step(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp | T0_BIT); -} - -void user_disable_single_step(struct task_struct *child) -{ - singlestep_disable(child); -} - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - unsigned long tmp; - int i, ret = 0; - int regno = addr >> 2; /* temporary hack. */ - unsigned long __user *datap = (unsigned long __user *) data; - - switch (request) { - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - if (addr & 3) - goto out_eio; - - if (regno >= 0 && regno < 19) { - tmp = get_reg(child, regno); - } else if (regno >= 21 && regno < 49) { - tmp = child->thread.fp[regno - 21]; - /* Convert internal fpu reg representation - * into long double format - */ - if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) - tmp = ((tmp & 0xffff0000) << 15) | - ((tmp & 0x0000ffff) << 16); - } else - goto out_eio; - ret = put_user(tmp, datap); - break; - - case PTRACE_POKEUSR: - /* write the word at location addr in the USER area */ - if (addr & 3) - goto out_eio; - - if (regno == PT_SR) { - data &= SR_MASK; - data |= get_reg(child, PT_SR) & ~SR_MASK; - } - if (regno >= 0 && regno < 19) { - if (put_reg(child, regno, data)) - goto out_eio; - } else if (regno >= 21 && regno < 48) { - /* Convert long double format - * into internal fpu reg representation - */ - if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { - data <<= 15; - data = (data & 0xffff0000) | - ((data & 0x0000ffff) >> 1); - } - child->thread.fp[regno - 21] = data; - } else - goto out_eio; - break; - - case PTRACE_GETREGS: /* Get all gp regs from the child. */ - for (i = 0; i < 19; i++) { - tmp = get_reg(child, i); - ret = put_user(tmp, datap); - if (ret) - break; - datap++; - } - break; - - case PTRACE_SETREGS: /* Set all gp regs in the child. */ - for (i = 0; i < 19; i++) { - ret = get_user(tmp, datap); - if (ret) - break; - if (i == PT_SR) { - tmp &= SR_MASK; - tmp |= get_reg(child, PT_SR) & ~SR_MASK; - } - put_reg(child, i, tmp); - datap++; - } - break; - - case PTRACE_GETFPREGS: /* Get the child FPU state. */ - if (copy_to_user(datap, &child->thread.fp, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - - case PTRACE_SETFPREGS: /* Set the child FPU state. */ - if (copy_from_user(&child->thread.fp, datap, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - - case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, datap); - break; - - default: - ret = ptrace_request(child, request, addr, data); - break; - } - - return ret; -out_eio: - return -EIO; -} - -asmlinkage void syscall_trace(void) -{ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} - -#ifdef CONFIG_COLDFIRE -asmlinkage int syscall_trace_enter(void) -{ - int ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(task_pt_regs(current)); - return ret; -} - -asmlinkage void syscall_trace_leave(void) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(task_pt_regs(current), 0); -} -#endif /* CONFIG_COLDFIRE */ diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c deleted file mode 100644 index 6709fb707335..000000000000 --- a/arch/m68k/kernel/ptrace_no.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/ptrace.c - * - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of - * this archive for more details. - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/signal.h> -#include <linux/tracehook.h> - -#include <asm/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/processor.h> - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in the SR the user has access to. */ -/* 1 = access 0 = no access */ -#define SR_MASK 0x001f - -/* sets the trace bits. */ -#define TRACE_BITS 0x8000 - -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) -#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ - - sizeof(struct switch_stack)) -/* Mapping from PT_xxx to the stack offset at which the register is - saved. Notice that usp has no stack-slot and needs to be treated - specially (see get_reg/put_reg below). */ -static int regoff[] = { - PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4), - PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0), - PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4), - SW_REG(a5), SW_REG(a6), PT_REG(d0), -1, - PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), -}; - -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, int regno) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return 0; - return *addr; -} - -/* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, int regno, - unsigned long data) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); - else - return -1; - *addr = data; - return 0; -} - -void user_enable_single_step(struct task_struct *task) -{ - unsigned long srflags; - srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16); - put_reg(task, PT_SR, srflags); -} - -void user_disable_single_step(struct task_struct *task) -{ - unsigned long srflags; - srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16); - put_reg(task, PT_SR, srflags); -} - -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. - */ -void ptrace_disable(struct task_struct *child) -{ - /* make sure the single step bit is not set. */ - user_disable_single_step(child); -} - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - int ret; - int regno = addr >> 2; - unsigned long __user *datap = (unsigned long __user *) data; - - switch (request) { - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr > sizeof(struct user) - 3) - break; - - tmp = 0; /* Default return condition */ - ret = -EIO; - if (regno < 19) { - tmp = get_reg(child, regno); - if (regno == PT_SR) - tmp >>= 16; - } else if (regno >= 21 && regno < 49) { - tmp = child->thread.fp[regno - 21]; - } else if (regno == 49) { - tmp = child->mm->start_code; - } else if (regno == 50) { - tmp = child->mm->start_data; - } else if (regno == 51) { - tmp = child->mm->end_code; - } else - break; - ret = put_user(tmp, datap); - break; - } - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr > sizeof(struct user) - 3) - break; - - if (regno == PT_SR) { - data &= SR_MASK; - data <<= 16; - data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } - if (regno < 19) { - if (put_reg(child, regno, data)) - break; - ret = 0; - break; - } - if (regno >= 21 && regno < 48) - { - child->thread.fp[regno - 21] = data; - ret = 0; - } - break; - - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - int i; - unsigned long tmp; - for (i = 0; i < 19; i++) { - tmp = get_reg(child, i); - if (i == PT_SR) - tmp >>= 16; - if (put_user(tmp, datap)) { - ret = -EFAULT; - break; - } - datap++; - } - ret = 0; - break; - } - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - int i; - unsigned long tmp; - for (i = 0; i < 19; i++) { - if (get_user(tmp, datap)) { - ret = -EFAULT; - break; - } - if (i == PT_SR) { - tmp &= SR_MASK; - tmp <<= 16; - tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } - put_reg(child, i, tmp); - datap++; - } - ret = 0; - break; - } - -#ifdef PTRACE_GETFPREGS - case PTRACE_GETFPREGS: { /* Get the child FPU state. */ - ret = 0; - if (copy_to_user(datap, &child->thread.fp, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - } -#endif - -#ifdef PTRACE_SETFPREGS - case PTRACE_SETFPREGS: { /* Set the child FPU state. */ - ret = 0; - if (copy_from_user(&child->thread.fp, datap, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - } -#endif - - case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, datap); - break; - - default: - ret = ptrace_request(child, request, addr, data); - break; - } - return ret; -} - -asmlinkage int syscall_trace_enter(void) -{ - int ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(task_pt_regs(current)); - return ret; -} - -asmlinkage void syscall_trace_leave(void) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(task_pt_regs(current), 0); -} diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index ca3df0dc7e88..7dc186b7a85f 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -31,6 +31,7 @@ #include <linux/init.h> #include <linux/initrd.h> #include <linux/root_dev.h> +#include <linux/rtc.h> #include <asm/setup.h> #include <asm/irq.h> @@ -47,7 +48,9 @@ EXPORT_SYMBOL(memory_end); char __initdata command_line[COMMAND_LINE_SIZE]; /* machine dependent timer functions */ +void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL; int (*mach_set_clock_mmss)(unsigned long); +int (*mach_hwclk) (int, struct rtc_time*); /* machine dependent reboot functions */ void (*mach_reset)(void); diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 75ab79b3bdeb..d7deb7fc7eb5 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -1,5 +1,111 @@ -#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE) -#include "time_mm.c" -#else -#include "time_no.c" -#endif +/* + * linux/arch/m68k/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the m68k-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/irq_regs.h> + +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/profile.h> + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "xtime_update()" routine every clocktick + */ +static irqreturn_t timer_interrupt(int irq, void *dummy) +{ + xtime_update(1); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); + +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; + dist = period / 4; + } + } +#endif /* CONFIG_HEARTBEAT */ + return IRQ_HANDLED; +} + +void read_persistent_clock(struct timespec *ts) +{ + struct rtc_time time; + ts->tv_sec = 0; + ts->tv_nsec = 0; + + if (mach_hwclk) { + mach_hwclk(0, &time); + + if ((time.tm_year += 1900) < 1970) + time.tm_year += 100; + ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, + time.tm_hour, time.tm_min, time.tm_sec); + } +} + +void __init time_init(void) +{ + mach_sched_init(timer_interrupt); +} + +#ifdef CONFIG_M68KCLASSIC + +u32 arch_gettimeoffset(void) +{ + return mach_gettimeoffset() * 1000; +} + +static int __init rtc_init(void) +{ + struct platform_device *pdev; + + if (!mach_hwclk) + return -ENODEV; + + pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} + +module_init(rtc_init); + +#endif /* CONFIG_M68KCLASSIC */ diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c deleted file mode 100644 index 18b34ee5db3b..000000000000 --- a/arch/m68k/kernel/time_mm.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * linux/arch/m68k/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file contains the m68k-specific time handling details. - * Most of the stuff is located in the machine specific files. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/rtc.h> -#include <linux/platform_device.h> - -#include <asm/machdep.h> -#include <asm/io.h> -#include <asm/irq_regs.h> - -#include <linux/time.h> -#include <linux/timex.h> -#include <linux/profile.h> - -static inline int set_rtc_mmss(unsigned long nowtime) -{ - if (mach_set_clock_mmss) - return mach_set_clock_mmss (nowtime); - return -1; -} - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "xtime_update()" routine every clocktick - */ -static irqreturn_t timer_interrupt(int irq, void *dummy) -{ - xtime_update(1); - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); - -#ifdef CONFIG_HEARTBEAT - /* use power LED as a heartbeat instead -- much more useful - for debugging -- based on the version for PReP by Cort */ - /* acts like an actual heart beat -- ie thump-thump-pause... */ - if (mach_heartbeat) { - static unsigned cnt = 0, period = 0, dist = 0; - - if (cnt == 0 || cnt == dist) - mach_heartbeat( 1 ); - else if (cnt == 7 || cnt == dist+7) - mach_heartbeat( 0 ); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; - dist = period / 4; - } - } -#endif /* CONFIG_HEARTBEAT */ - return IRQ_HANDLED; -} - -void read_persistent_clock(struct timespec *ts) -{ - struct rtc_time time; - ts->tv_sec = 0; - ts->tv_nsec = 0; - - if (mach_hwclk) { - mach_hwclk(0, &time); - - if ((time.tm_year += 1900) < 1970) - time.tm_year += 100; - ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, - time.tm_hour, time.tm_min, time.tm_sec); - } -} - -void __init time_init(void) -{ - mach_sched_init(timer_interrupt); -} - -u32 arch_gettimeoffset(void) -{ - return mach_gettimeoffset() * 1000; -} - -static int __init rtc_init(void) -{ - struct platform_device *pdev; - - if (!mach_hwclk) - return -ENODEV; - - pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - return 0; -} - -module_init(rtc_init); diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c deleted file mode 100644 index 3ef0f7768dcd..000000000000 --- a/arch/m68k/kernel/time_no.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file contains the m68k-specific time handling details. - * Most of the stuff is located in the machine specific files. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/profile.h> -#include <linux/time.h> -#include <linux/timex.h> - -#include <asm/machdep.h> -#include <asm/irq_regs.h> - -#define TICK_SIZE (tick_nsec / 1000) - -/* machine dependent timer functions */ -void (*mach_gettod)(int*, int*, int*, int*, int*, int*); - -static inline int set_rtc_mmss(unsigned long nowtime) -{ - if (mach_set_clock_mmss) - return mach_set_clock_mmss (nowtime); - return -1; -} - -#ifndef CONFIG_GENERIC_CLOCKEVENTS -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "xtime_update()" routine every clocktick - */ -irqreturn_t arch_timer_interrupt(int irq, void *dummy) -{ - - if (current->pid) - profile_tick(CPU_PROFILING); - - xtime_update(1); - - update_process_times(user_mode(get_irq_regs())); - - return(IRQ_HANDLED); -} -#endif - -static unsigned long read_rtc_mmss(void) -{ - unsigned int year, mon, day, hour, min, sec; - - if (mach_gettod) { - mach_gettod(&year, &mon, &day, &hour, &min, &sec); - if ((year += 1900) < 1970) - year += 100; - } else { - year = 1970; - mon = day = 1; - hour = min = sec = 0; - } - - - return mktime(year, mon, day, hour, min, sec); -} - -void read_persistent_clock(struct timespec *ts) -{ - ts->tv_sec = read_rtc_mmss(); - ts->tv_nsec = 0; -} - -int update_persistent_clock(struct timespec now) -{ - return set_rtc_mmss(now.tv_sec); -} - -void time_init(void) -{ - hw_timer_init(); -} diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds index 8e66ccb0935e..40e02d9c38b4 100644 --- a/arch/m68k/kernel/vmlinux-nommu.lds +++ b/arch/m68k/kernel/vmlinux-nommu.lds @@ -1,195 +1,93 @@ /* * vmlinux.lds.S -- master linker script for m68knommu arch * - * (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com> + * (C) Copyright 2002-2012, Greg Ungerer <gerg@snapgear.com> * * This linker script is equipped to build either ROM loaded or RAM * run kernels. */ -#include <asm-generic/vmlinux.lds.h> -#include <asm/page.h> -#include <asm/thread_info.h> - #if defined(CONFIG_RAMKERNEL) -#define RAM_START CONFIG_KERNELBASE -#define RAM_LENGTH (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE) -#define TEXT ram -#define DATA ram -#define INIT ram -#define BSSS ram -#endif -#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL) -#define RAM_START CONFIG_RAMBASE -#define RAM_LENGTH CONFIG_RAMSIZE -#define ROMVEC_START CONFIG_ROMVEC -#define ROMVEC_LENGTH CONFIG_ROMVECSIZE -#define ROM_START CONFIG_ROMSTART -#define ROM_LENGTH CONFIG_ROMSIZE -#define TEXT rom -#define DATA ram -#define INIT ram -#define BSSS ram +#define KTEXT_ADDR CONFIG_KERNELBASE #endif - -#ifndef DATA_ADDR -#define DATA_ADDR +#if defined(CONFIG_ROMKERNEL) +#define KTEXT_ADDR CONFIG_ROMSTART +#define KDATA_ADDR CONFIG_KERNELBASE +#define LOAD_OFFSET KDATA_ADDR + (ADDR(.text) + SIZEOF(.text)) #endif +#include <asm/page.h> +#include <asm/thread_info.h> +#include <asm-generic/vmlinux.lds.h> OUTPUT_ARCH(m68k) ENTRY(_start) -MEMORY { - ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH -#ifdef ROM_START - romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH - rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH -#endif -} - jiffies = jiffies_64 + 4; SECTIONS { -#ifdef ROMVEC_START - . = ROMVEC_START ; +#ifdef CONFIG_ROMVEC + . = CONFIG_ROMVEC; .romvec : { - __rom_start = . ; + __rom_start = .; _romvec = .; + *(.romvec) *(.data..initvect) - } > romvec + } #endif + . = KTEXT_ADDR; + + _text = .; + _stext = .; .text : { - _text = .; - _stext = . ; HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT - *(.text..lock) *(.fixup) + . = ALIGN(16); + } + _etext = .; + +#ifdef KDATA_ADDR + . = KDATA_ADDR; +#endif + + _sdata = .; + RO_DATA_SECTION(PAGE_SIZE) + RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) + _edata = .; - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - - *(.rodata) *(.rodata.*) - *(__vermagic) /* Kernel version magic */ - *(.rodata1) - *(.rodata.str1.1) - - /* Kernel symbol table: Normal symbols */ - . = ALIGN(4); - __start___ksymtab = .; - *(SORT(___ksymtab+*)) - __stop___ksymtab = .; - - /* Kernel symbol table: GPL-only symbols */ - __start___ksymtab_gpl = .; - *(SORT(___ksymtab_gpl+*)) - __stop___ksymtab_gpl = .; - - /* Kernel symbol table: Normal unused symbols */ - __start___ksymtab_unused = .; - *(SORT(___ksymtab_unused+*)) - __stop___ksymtab_unused = .; - - /* Kernel symbol table: GPL-only unused symbols */ - __start___ksymtab_unused_gpl = .; - *(SORT(___ksymtab_unused_gpl+*)) - __stop___ksymtab_unused_gpl = .; - - /* Kernel symbol table: GPL-future symbols */ - __start___ksymtab_gpl_future = .; - *(SORT(___ksymtab_gpl_future+*)) - __stop___ksymtab_gpl_future = .; - - /* Kernel symbol table: Normal symbols */ - __start___kcrctab = .; - *(SORT(___kcrctab+*)) - __stop___kcrctab = .; - - /* Kernel symbol table: GPL-only symbols */ - __start___kcrctab_gpl = .; - *(SORT(___kcrctab_gpl+*)) - __stop___kcrctab_gpl = .; - - /* Kernel symbol table: Normal unused symbols */ - __start___kcrctab_unused = .; - *(SORT(___kcrctab_unused+*)) - __stop___kcrctab_unused = .; - - /* Kernel symbol table: GPL-only unused symbols */ - __start___kcrctab_unused_gpl = .; - *(SORT(___kcrctab_unused_gpl+*)) - __stop___kcrctab_unused_gpl = .; - - /* Kernel symbol table: GPL-future symbols */ - __start___kcrctab_gpl_future = .; - *(SORT(___kcrctab_gpl_future+*)) - __stop___kcrctab_gpl_future = .; - - /* Kernel symbol table: strings */ - *(__ksymtab_strings) - - /* Built-in module parameters */ - . = ALIGN(4) ; - __start___param = .; - *(__param) - __stop___param = .; - - /* Built-in module versions */ - . = ALIGN(4) ; - __start___modver = .; - *(__modver) - __stop___modver = .; - - . = ALIGN(4) ; - _etext = . ; - } > TEXT - - .data DATA_ADDR : { - . = ALIGN(4); - _sdata = . ; - DATA_DATA - CACHELINE_ALIGNED_DATA(32) - PAGE_ALIGNED_DATA(PAGE_SIZE) - *(.data..shared_aligned) - INIT_TASK_DATA(THREAD_SIZE) - _edata = . ; - } > DATA + EXCEPTION_TABLE(16) + NOTES + . = ALIGN(PAGE_SIZE); + __init_begin = .; + INIT_TEXT_SECTION(PAGE_SIZE) + INIT_DATA_SECTION(16) + PERCPU_SECTION(16) .m68k_fixup : { __start_fixup = .; *(.m68k_fixup) __stop_fixup = .; - } > DATA - NOTES > DATA - - .init.text : { - . = ALIGN(PAGE_SIZE); - __init_begin = .; - } > INIT - INIT_TEXT_SECTION(PAGE_SIZE) > INIT - INIT_DATA_SECTION(16) > INIT + } .init.data : { . = ALIGN(PAGE_SIZE); __init_end = .; - } > INIT - - .bss : { - . = ALIGN(4); - _sbss = . ; - *(.bss) - *(COMMON) - . = ALIGN(4) ; - _ebss = . ; - _end = . ; - } > BSSS + } + + _sbss = .; + BSS_SECTION(0, 0, 0) + _ebss = .; + + _end = .; + + STABS_DEBUG + .comment 0 : { *(.comment) } + /* Sections to be discarded */ DISCARDS } diff --git a/arch/m68k/platform/5206/config.c b/arch/m68k/platform/5206/config.c index 6fa3f800277a..6bfbeebd231b 100644 --- a/arch/m68k/platform/5206/config.c +++ b/arch/m68k/platform/5206/config.c @@ -16,83 +16,6 @@ #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> - -/***************************************************************************/ - -static struct mcf_platform_uart m5206_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = 73, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = 74, - }, - { }, -}; - -static struct platform_device m5206_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m5206_uart_platform, -}; - -static struct platform_device *m5206_devices[] __initdata = { - &m5206_uart, -}; - -/***************************************************************************/ - -static void __init m5206_uart_init_line(int line, int irq) -{ - if (line == 0) { - writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); - writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART0); - } else if (line == 1) { - writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); - writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART1); - } -} - -static void __init m5206_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m5206_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m5206_uart_init_line(line, m5206_uart_platform[line].irq); -} - -/***************************************************************************/ - -static void __init m5206_timers_init(void) -{ - /* Timer1 is always used as system timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER1ICR); - mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); - -#ifdef CONFIG_HIGHPROFILE - /* Timer2 is to be used as a high speed profile timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER2ICR); - mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); -#endif -} - -/***************************************************************************/ - -void m5206_cpu_reset(void) -{ - local_irq_disable(); - /* Set watchdog to soft reset, and enabled */ - __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); - for (;;) - /* wait for watchdog to timeout */; -} /***************************************************************************/ @@ -104,9 +27,7 @@ void __init config_BSP(char *commandp, int size) commandp[size-1] = 0; #endif /* CONFIG_NETtel */ - mach_reset = m5206_cpu_reset; - m5206_timers_init(); - m5206_uarts_init(); + mach_sched_init = hw_timer_init; /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -115,13 +36,3 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ - -static int __init init_BSP(void) -{ - platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/arch/m68k/platform/520x/config.c b/arch/m68k/platform/520x/config.c index 8a98683f1b15..235947844f27 100644 --- a/arch/m68k/platform/520x/config.c +++ b/arch/m68k/platform/520x/config.c @@ -15,194 +15,14 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -static struct mcf_platform_uart m520x_uart_platform[] = { - { - .mapbase = MCFUART_BASE1, - .irq = MCFINT_VECBASE + MCFINT_UART0, - }, - { - .mapbase = MCFUART_BASE2, - .irq = MCFINT_VECBASE + MCFINT_UART1, - }, - { - .mapbase = MCFUART_BASE3, - .irq = MCFINT_VECBASE + MCFINT_UART2, - }, - { }, -}; - -static struct platform_device m520x_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m520x_uart_platform, -}; - -static struct resource m520x_fec_resources[] = { - { - .start = MCFFEC_BASE, - .end = MCFFEC_BASE + MCFFEC_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = 64 + 36, - .end = 64 + 36, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 40, - .end = 64 + 40, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 42, - .end = 64 + 42, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m520x_fec = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(m520x_fec_resources), - .resource = m520x_fec_resources, -}; - -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) -static struct resource m520x_qspi_resources[] = { - { - .start = MCFQSPI_IOBASE, - .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCFINT_VECBASE + MCFINT_QSPI, - .end = MCFINT_VECBASE + MCFINT_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -#define MCFQSPI_CS0 46 -#define MCFQSPI_CS1 47 -#define MCFQSPI_CS2 27 - -static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - - return 0; - -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void m520x_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, cs_high); - break; - } -} - -static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, !cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, !cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, !cs_high); - break; - } -} - -static struct mcfqspi_cs_control m520x_cs_control = { - .setup = m520x_cs_setup, - .teardown = m520x_cs_teardown, - .select = m520x_cs_select, - .deselect = m520x_cs_deselect, -}; - -static struct mcfqspi_platform_data m520x_qspi_data = { - .bus_num = 0, - .num_chipselect = 3, - .cs_control = &m520x_cs_control, -}; - -static struct platform_device m520x_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(m520x_qspi_resources), - .resource = m520x_qspi_resources, - .dev.platform_data = &m520x_qspi_data, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m520x_qspi_init(void) { @@ -214,54 +34,28 @@ static void __init m520x_qspi_init(void) par &= 0x00ff; writew(par, MCF_GPIO_PAR_UART); } -#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ - -static struct platform_device *m520x_devices[] __initdata = { - &m520x_uart, - &m520x_fec, -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - &m520x_qspi, -#endif -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m520x_uart_init_line(int line, int irq) +static void __init m520x_uarts_init(void) { u16 par; u8 par2; - switch (line) { - case 0: - par = readw(MCF_GPIO_PAR_UART); - par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | - MCF_GPIO_PAR_UART_PAR_URXD0; - writew(par, MCF_GPIO_PAR_UART); - break; - case 1: - par = readw(MCF_GPIO_PAR_UART); - par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | - MCF_GPIO_PAR_UART_PAR_URXD1; - writew(par, MCF_GPIO_PAR_UART); - break; - case 2: - par2 = readb(MCF_GPIO_PAR_FECI2C); - par2 &= ~0x0F; - par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | - MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; - writeb(par2, MCF_GPIO_PAR_FECI2C); - break; - } -} - -static void __init m520x_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m520x_uart_platform); - int line; + /* UART0 and UART1 GPIO pin setup */ + par = readw(MCF_GPIO_PAR_UART); + par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | MCF_GPIO_PAR_UART_PAR_URXD0; + par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | MCF_GPIO_PAR_UART_PAR_URXD1; + writew(par, MCF_GPIO_PAR_UART); - for (line = 0; (line < nrlines); line++) - m520x_uart_init_line(line, m520x_uart_platform[line].irq); + /* UART1 GPIO pin setup */ + par2 = readb(MCF_GPIO_PAR_FECI2C); + par2 &= ~0x0F; + par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | + MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; + writeb(par2, MCF_GPIO_PAR_FECI2C); } /***************************************************************************/ @@ -280,32 +74,14 @@ static void __init m520x_fec_init(void) /***************************************************************************/ -static void m520x_cpu_reset(void) -{ - local_irq_disable(); - __raw_writeb(MCF_RCR_SWRESET, MCF_RCR); -} - -/***************************************************************************/ - void __init config_BSP(char *commandp, int size) { - mach_reset = m520x_cpu_reset; + mach_sched_init = hw_timer_init; m520x_uarts_init(); m520x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m520x_qspi_init(); #endif } /***************************************************************************/ - -static int __init init_BSP(void) -{ - platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/arch/m68k/platform/523x/config.c b/arch/m68k/platform/523x/config.c index 71f4436ec809..c8b405d5a961 100644 --- a/arch/m68k/platform/523x/config.c +++ b/arch/m68k/platform/523x/config.c @@ -16,215 +16,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -static struct mcf_platform_uart m523x_uart_platform[] = { - { - .mapbase = MCFUART_BASE1, - .irq = MCFINT_VECBASE + MCFINT_UART0, - }, - { - .mapbase = MCFUART_BASE2, - .irq = MCFINT_VECBASE + MCFINT_UART0 + 1, - }, - { - .mapbase = MCFUART_BASE3, - .irq = MCFINT_VECBASE + MCFINT_UART0 + 2, - }, - { }, -}; - -static struct platform_device m523x_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m523x_uart_platform, -}; - -static struct resource m523x_fec_resources[] = { - { - .start = MCFFEC_BASE, - .end = MCFFEC_BASE + MCFFEC_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = 64 + 23, - .end = 64 + 23, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 27, - .end = 64 + 27, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 29, - .end = 64 + 29, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m523x_fec = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(m523x_fec_resources), - .resource = m523x_fec_resources, -}; - -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) -static struct resource m523x_qspi_resources[] = { - { - .start = MCFQSPI_IOBASE, - .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCFINT_VECBASE + MCFINT_QSPI, - .end = MCFINT_VECBASE + MCFINT_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -#define MCFQSPI_CS0 91 -#define MCFQSPI_CS1 92 -#define MCFQSPI_CS2 103 -#define MCFQSPI_CS3 99 - -static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - - status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); - goto fail3; - } - status = gpio_direction_output(MCFQSPI_CS3, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); - goto fail4; - } - - return 0; - -fail4: - gpio_free(MCFQSPI_CS3); -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ - gpio_free(MCFQSPI_CS3); - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void m523x_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, cs_high); - break; - case 3: - gpio_set_value(MCFQSPI_CS3, cs_high); - break; - } -} - -static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, !cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, !cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, !cs_high); - break; - case 3: - gpio_set_value(MCFQSPI_CS3, !cs_high); - break; - } -} - -static struct mcfqspi_cs_control m523x_cs_control = { - .setup = m523x_cs_setup, - .teardown = m523x_cs_teardown, - .select = m523x_cs_select, - .deselect = m523x_cs_deselect, -}; - -static struct mcfqspi_platform_data m523x_qspi_data = { - .bus_num = 0, - .num_chipselect = 4, - .cs_control = &m523x_cs_control, -}; - -static struct platform_device m523x_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(m523x_qspi_resources), - .resource = m523x_qspi_resources, - .dev.platform_data = &m523x_qspi_data, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m523x_qspi_init(void) { @@ -237,15 +35,8 @@ static void __init m523x_qspi_init(void) par &= 0x3f3f; writew(par, MCFGPIO_PAR_TIMER); } -#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -static struct platform_device *m523x_devices[] __initdata = { - &m523x_uart, - &m523x_fec, -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - &m523x_qspi, -#endif -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ @@ -263,31 +54,13 @@ static void __init m523x_fec_init(void) /***************************************************************************/ -static void m523x_cpu_reset(void) -{ - local_irq_disable(); - __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR); -} - -/***************************************************************************/ - void __init config_BSP(char *commandp, int size) { - mach_reset = m523x_cpu_reset; -} - -/***************************************************************************/ - -static int __init init_BSP(void) -{ + mach_sched_init = hw_timer_init; m523x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m523x_qspi_init(); #endif - platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices)); - return 0; } -arch_initcall(init_BSP); - /***************************************************************************/ diff --git a/arch/m68k/platform/5249/config.c b/arch/m68k/platform/5249/config.c index ceb31e5744a6..bbf05135bb98 100644 --- a/arch/m68k/platform/5249/config.c +++ b/arch/m68k/platform/5249/config.c @@ -12,34 +12,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> +#include <linux/platform_device.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -static struct mcf_platform_uart m5249_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = 73, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = 74, - }, - { }, -}; - -static struct platform_device m5249_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m5249_uart_platform, -}; - #ifdef CONFIG_M5249C3 static struct resource m5249_smc91x_resources[] = { @@ -64,153 +43,15 @@ static struct platform_device m5249_smc91x = { #endif /* CONFIG_M5249C3 */ -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) -static struct resource m5249_qspi_resources[] = { - { - .start = MCFQSPI_IOBASE, - .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCF_IRQ_QSPI, - .end = MCF_IRQ_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -#define MCFQSPI_CS0 29 -#define MCFQSPI_CS1 24 -#define MCFQSPI_CS2 21 -#define MCFQSPI_CS3 22 - -static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - - status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); - goto fail3; - } - status = gpio_direction_output(MCFQSPI_CS3, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); - goto fail4; - } - - return 0; - -fail4: - gpio_free(MCFQSPI_CS3); -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ - gpio_free(MCFQSPI_CS3); - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void m5249_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, cs_high); - break; - case 3: - gpio_set_value(MCFQSPI_CS3, cs_high); - break; - } -} - -static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, !cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, !cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, !cs_high); - break; - case 3: - gpio_set_value(MCFQSPI_CS3, !cs_high); - break; - } -} - -static struct mcfqspi_cs_control m5249_cs_control = { - .setup = m5249_cs_setup, - .teardown = m5249_cs_teardown, - .select = m5249_cs_select, - .deselect = m5249_cs_deselect, +static struct platform_device *m5249_devices[] __initdata = { +#ifdef CONFIG_M5249C3 + &m5249_smc91x, +#endif }; -static struct mcfqspi_platform_data m5249_qspi_data = { - .bus_num = 0, - .num_chipselect = 4, - .cs_control = &m5249_cs_control, -}; +/***************************************************************************/ -static struct platform_device m5249_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(m5249_qspi_resources), - .resource = m5249_qspi_resources, - .dev.platform_data = &m5249_qspi_data, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m5249_qspi_init(void) { @@ -219,42 +60,8 @@ static void __init m5249_qspi_init(void) MCF_MBAR + MCFSIM_QSPIICR); mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI); } -#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ - -static struct platform_device *m5249_devices[] __initdata = { - &m5249_uart, -#ifdef CONFIG_M5249C3 - &m5249_smc91x, -#endif -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - &m5249_qspi, -#endif -}; - -/***************************************************************************/ - -static void __init m5249_uart_init_line(int line, int irq) -{ - if (line == 0) { - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); - writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART0); - } else if (line == 1) { - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); - writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART1); - } -} - -static void __init m5249_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m5249_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m5249_uart_init_line(line, m5249_uart_platform[line].irq); -} +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ @@ -276,43 +83,14 @@ static void __init m5249_smc91x_init(void) /***************************************************************************/ -static void __init m5249_timers_init(void) -{ - /* Timer1 is always used as system timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER1ICR); - mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); - -#ifdef CONFIG_HIGHPROFILE - /* Timer2 is to be used as a high speed profile timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER2ICR); - mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); -#endif -} - -/***************************************************************************/ - -void m5249_cpu_reset(void) -{ - local_irq_disable(); - /* Set watchdog to soft reset, and enabled */ - __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); - for (;;) - /* wait for watchdog to timeout */; -} - -/***************************************************************************/ - void __init config_BSP(char *commandp, int size) { - mach_reset = m5249_cpu_reset; - m5249_timers_init(); - m5249_uarts_init(); + mach_sched_init = hw_timer_init; + #ifdef CONFIG_M5249C3 m5249_smc91x_init(); #endif -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m5249_qspi_init(); #endif } diff --git a/arch/m68k/platform/5272/config.c b/arch/m68k/platform/5272/config.c index 65bb582734e1..e68bc7a148eb 100644 --- a/arch/m68k/platform/5272/config.c +++ b/arch/m68k/platform/5272/config.c @@ -30,84 +30,18 @@ unsigned char ledbank = 0xff; /***************************************************************************/ -static struct mcf_platform_uart m5272_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = MCF_IRQ_UART1, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = MCF_IRQ_UART2, - }, - { }, -}; - -static struct platform_device m5272_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m5272_uart_platform, -}; - -static struct resource m5272_fec_resources[] = { - { - .start = MCF_MBAR + 0x840, - .end = MCF_MBAR + 0x840 + 0x1cf, - .flags = IORESOURCE_MEM, - }, - { - .start = MCF_IRQ_ERX, - .end = MCF_IRQ_ERX, - .flags = IORESOURCE_IRQ, - }, - { - .start = MCF_IRQ_ETX, - .end = MCF_IRQ_ETX, - .flags = IORESOURCE_IRQ, - }, - { - .start = MCF_IRQ_ENTC, - .end = MCF_IRQ_ENTC, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m5272_fec = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(m5272_fec_resources), - .resource = m5272_fec_resources, -}; - -static struct platform_device *m5272_devices[] __initdata = { - &m5272_uart, - &m5272_fec, -}; - -/***************************************************************************/ - -static void __init m5272_uart_init_line(int line, int irq) +static void __init m5272_uarts_init(void) { u32 v; - if ((line >= 0) && (line < 2)) { - /* Enable the output lines for the serial ports */ - v = readl(MCF_MBAR + MCFSIM_PBCNT); - v = (v & ~0x000000ff) | 0x00000055; - writel(v, MCF_MBAR + MCFSIM_PBCNT); - - v = readl(MCF_MBAR + MCFSIM_PDCNT); - v = (v & ~0x000003fc) | 0x000002a8; - writel(v, MCF_MBAR + MCFSIM_PDCNT); - } -} - -static void __init m5272_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m5272_uart_platform); - int line; + /* Enable the output lines for the serial ports */ + v = readl(MCF_MBAR + MCFSIM_PBCNT); + v = (v & ~0x000000ff) | 0x00000055; + writel(v, MCF_MBAR + MCFSIM_PBCNT); - for (line = 0; (line < nrlines); line++) - m5272_uart_init_line(line, m5272_uart_platform[line].irq); + v = readl(MCF_MBAR + MCFSIM_PDCNT); + v = (v & ~0x000003fc) | 0x000002a8; + writel(v, MCF_MBAR + MCFSIM_PDCNT); } /***************************************************************************/ @@ -146,6 +80,7 @@ void __init config_BSP(char *commandp, int size) #endif mach_reset = m5272_cpu_reset; + mach_sched_init = hw_timer_init; } /***************************************************************************/ @@ -167,7 +102,6 @@ static int __init init_BSP(void) { m5272_uarts_init(); fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status); - platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices)); return 0; } diff --git a/arch/m68k/platform/527x/config.c b/arch/m68k/platform/527x/config.c index 3ebc769cefda..7ed848c3b848 100644 --- a/arch/m68k/platform/527x/config.c +++ b/arch/m68k/platform/527x/config.c @@ -16,253 +16,14 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -static struct mcf_platform_uart m527x_uart_platform[] = { - { - .mapbase = MCFUART_BASE1, - .irq = MCFINT_VECBASE + MCFINT_UART0, - }, - { - .mapbase = MCFUART_BASE2, - .irq = MCFINT_VECBASE + MCFINT_UART1, - }, - { - .mapbase = MCFUART_BASE3, - .irq = MCFINT_VECBASE + MCFINT_UART2, - }, - { }, -}; - -static struct platform_device m527x_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m527x_uart_platform, -}; - -static struct resource m527x_fec0_resources[] = { - { - .start = MCFFEC_BASE0, - .end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = 64 + 23, - .end = 64 + 23, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 27, - .end = 64 + 27, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 29, - .end = 64 + 29, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct resource m527x_fec1_resources[] = { - { - .start = MCFFEC_BASE1, - .end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = 128 + 23, - .end = 128 + 23, - .flags = IORESOURCE_IRQ, - }, - { - .start = 128 + 27, - .end = 128 + 27, - .flags = IORESOURCE_IRQ, - }, - { - .start = 128 + 29, - .end = 128 + 29, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m527x_fec[] = { - { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(m527x_fec0_resources), - .resource = m527x_fec0_resources, - }, - { - .name = "fec", - .id = 1, - .num_resources = ARRAY_SIZE(m527x_fec1_resources), - .resource = m527x_fec1_resources, - }, -}; - -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) -static struct resource m527x_qspi_resources[] = { - { - .start = MCFQSPI_IOBASE, - .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCFINT_VECBASE + MCFINT_QSPI, - .end = MCFINT_VECBASE + MCFINT_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -#if defined(CONFIG_M5271) -#define MCFQSPI_CS0 91 -#define MCFQSPI_CS1 92 -#define MCFQSPI_CS2 99 -#define MCFQSPI_CS3 103 -#elif defined(CONFIG_M5275) -#define MCFQSPI_CS0 59 -#define MCFQSPI_CS1 60 -#define MCFQSPI_CS2 61 -#define MCFQSPI_CS3 62 -#endif - -static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - - status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); - goto fail3; - } - status = gpio_direction_output(MCFQSPI_CS3, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); - goto fail4; - } - - return 0; - -fail4: - gpio_free(MCFQSPI_CS3); -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ - gpio_free(MCFQSPI_CS3); - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void m527x_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, cs_high); - break; - case 3: - gpio_set_value(MCFQSPI_CS3, cs_high); - break; - } -} - -static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, !cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, !cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, !cs_high); - break; - case 3: - gpio_set_value(MCFQSPI_CS3, !cs_high); - break; - } -} - -static struct mcfqspi_cs_control m527x_cs_control = { - .setup = m527x_cs_setup, - .teardown = m527x_cs_teardown, - .select = m527x_cs_select, - .deselect = m527x_cs_deselect, -}; - -static struct mcfqspi_platform_data m527x_qspi_data = { - .bus_num = 0, - .num_chipselect = 4, - .cs_control = &m527x_cs_control, -}; - -static struct platform_device m527x_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(m527x_qspi_resources), - .resource = m527x_qspi_resources, - .dev.platform_data = &m527x_qspi_data, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m527x_qspi_init(void) { @@ -280,50 +41,23 @@ static void __init m527x_qspi_init(void) writew(0x003e, MCFGPIO_PAR_QSPI); #endif } -#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -static struct platform_device *m527x_devices[] __initdata = { - &m527x_uart, - &m527x_fec[0], -#ifdef CONFIG_FEC2 - &m527x_fec[1], -#endif -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - &m527x_qspi, -#endif -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m527x_uart_init_line(int line, int irq) +static void __init m527x_uarts_init(void) { u16 sepmask; - if ((line < 0) || (line > 2)) - return; - /* * External Pin Mask Setting & Enable External Pin for Interface */ sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); - if (line == 0) - sepmask |= UART0_ENABLE_MASK; - else if (line == 1) - sepmask |= UART1_ENABLE_MASK; - else if (line == 2) - sepmask |= UART2_ENABLE_MASK; + sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | UART2_ENABLE_MASK; writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART); } -static void __init m527x_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m527x_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m527x_uart_init_line(line, m527x_uart_platform[line].irq); -} - /***************************************************************************/ static void __init m527x_fec_init(void) @@ -353,32 +87,14 @@ static void __init m527x_fec_init(void) /***************************************************************************/ -static void m527x_cpu_reset(void) -{ - local_irq_disable(); - __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR); -} - -/***************************************************************************/ - void __init config_BSP(char *commandp, int size) { - mach_reset = m527x_cpu_reset; + mach_sched_init = hw_timer_init; m527x_uarts_init(); m527x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m527x_qspi_init(); #endif } /***************************************************************************/ - -static int __init init_BSP(void) -{ - platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/arch/m68k/platform/528x/config.c b/arch/m68k/platform/528x/config.c index 7abe77a2f3e3..d4492926614c 100644 --- a/arch/m68k/platform/528x/config.c +++ b/arch/m68k/platform/528x/config.c @@ -17,229 +17,33 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -static struct mcf_platform_uart m528x_uart_platform[] = { - { - .mapbase = MCFUART_BASE1, - .irq = MCFINT_VECBASE + MCFINT_UART0, - }, - { - .mapbase = MCFUART_BASE2, - .irq = MCFINT_VECBASE + MCFINT_UART0 + 1, - }, - { - .mapbase = MCFUART_BASE3, - .irq = MCFINT_VECBASE + MCFINT_UART0 + 2, - }, - { }, -}; - -static struct platform_device m528x_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m528x_uart_platform, -}; - -static struct resource m528x_fec_resources[] = { - { - .start = MCFFEC_BASE, - .end = MCFFEC_BASE + MCFFEC_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = 64 + 23, - .end = 64 + 23, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 27, - .end = 64 + 27, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 29, - .end = 64 + 29, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m528x_fec = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(m528x_fec_resources), - .resource = m528x_fec_resources, -}; - -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) -static struct resource m528x_qspi_resources[] = { - { - .start = MCFQSPI_IOBASE, - .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCFINT_VECBASE + MCFINT_QSPI, - .end = MCFINT_VECBASE + MCFINT_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -#define MCFQSPI_CS0 147 -#define MCFQSPI_CS1 148 -#define MCFQSPI_CS2 149 -#define MCFQSPI_CS3 150 - -static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - - status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); - goto fail3; - } - status = gpio_direction_output(MCFQSPI_CS3, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); - goto fail4; - } - - return 0; - -fail4: - gpio_free(MCFQSPI_CS3); -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ - gpio_free(MCFQSPI_CS3); - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void m528x_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high); -} - -static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high); -} - -static struct mcfqspi_cs_control m528x_cs_control = { - .setup = m528x_cs_setup, - .teardown = m528x_cs_teardown, - .select = m528x_cs_select, - .deselect = m528x_cs_deselect, -}; - -static struct mcfqspi_platform_data m528x_qspi_data = { - .bus_num = 0, - .num_chipselect = 4, - .cs_control = &m528x_cs_control, -}; - -static struct platform_device m528x_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(m528x_qspi_resources), - .resource = m528x_qspi_resources, - .dev.platform_data = &m528x_qspi_data, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m528x_qspi_init(void) { /* setup Port QS for QSPI with gpio CS control */ __raw_writeb(0x07, MCFGPIO_PQSPAR); } -#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -static struct platform_device *m528x_devices[] __initdata = { - &m528x_uart, - &m528x_fec, -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - &m528x_qspi, -#endif -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m528x_uart_init_line(int line, int irq) +static void __init m528x_uarts_init(void) { u8 port; - if ((line < 0) || (line > 2)) - return; - /* make sure PUAPAR is set for UART0 and UART1 */ - if (line < 2) { - port = readb(MCF5282_GPIO_PUAPAR); - port |= (0x03 << (line * 2)); - writeb(port, MCF5282_GPIO_PUAPAR); - } -} - -static void __init m528x_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m528x_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m528x_uart_init_line(line, m528x_uart_platform[line].irq); + port = readb(MCF5282_GPIO_PUAPAR); + port |= 0x03 | (0x03 << 2); + writeb(port, MCF5282_GPIO_PUAPAR); } /***************************************************************************/ @@ -256,14 +60,6 @@ static void __init m528x_fec_init(void) /***************************************************************************/ -static void m528x_cpu_reset(void) -{ - local_irq_disable(); - __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR); -} - -/***************************************************************************/ - #ifdef CONFIG_WILDFIRE void wildfire_halt(void) { @@ -299,22 +95,12 @@ void __init config_BSP(char *commandp, int size) #ifdef CONFIG_WILDFIREMOD mach_halt = wildfiremod_halt; #endif -} - -/***************************************************************************/ - -static int __init init_BSP(void) -{ - mach_reset = m528x_cpu_reset; + mach_sched_init = hw_timer_init; m528x_uarts_init(); m528x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m528x_qspi_init(); #endif - platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices)); - return 0; } -arch_initcall(init_BSP); - /***************************************************************************/ diff --git a/arch/m68k/platform/5307/config.c b/arch/m68k/platform/5307/config.c index 00900ac06a9c..a568d2870d15 100644 --- a/arch/m68k/platform/5307/config.c +++ b/arch/m68k/platform/5307/config.c @@ -16,7 +16,6 @@ #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> #include <asm/mcfwdebug.h> /***************************************************************************/ @@ -29,82 +28,6 @@ unsigned char ledbank = 0xff; /***************************************************************************/ -static struct mcf_platform_uart m5307_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = 73, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = 74, - }, - { }, -}; - -static struct platform_device m5307_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m5307_uart_platform, -}; - -static struct platform_device *m5307_devices[] __initdata = { - &m5307_uart, -}; - -/***************************************************************************/ - -static void __init m5307_uart_init_line(int line, int irq) -{ - if (line == 0) { - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); - writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART0); - } else if (line == 1) { - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); - writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART1); - } -} - -static void __init m5307_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m5307_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m5307_uart_init_line(line, m5307_uart_platform[line].irq); -} - -/***************************************************************************/ - -static void __init m5307_timers_init(void) -{ - /* Timer1 is always used as system timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER1ICR); - mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); - -#ifdef CONFIG_HIGHPROFILE - /* Timer2 is to be used as a high speed profile timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER2ICR); - mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); -#endif -} - -/***************************************************************************/ - -void m5307_cpu_reset(void) -{ - local_irq_disable(); - /* Set watchdog to soft reset, and enabled */ - __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); - for (;;) - /* wait for watchdog to timeout */; -} - -/***************************************************************************/ - void __init config_BSP(char *commandp, int size) { #if defined(CONFIG_NETtel) || \ @@ -114,9 +37,7 @@ void __init config_BSP(char *commandp, int size) commandp[size-1] = 0; #endif - mach_reset = m5307_cpu_reset; - m5307_timers_init(); - m5307_uarts_init(); + mach_sched_init = hw_timer_init; /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -135,13 +56,3 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ - -static int __init init_BSP(void) -{ - platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/arch/m68k/platform/532x/config.c b/arch/m68k/platform/532x/config.c index ca51323f957b..2bec3477b739 100644 --- a/arch/m68k/platform/532x/config.c +++ b/arch/m68k/platform/532x/config.c @@ -21,214 +21,33 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> #include <asm/mcfdma.h> #include <asm/mcfwdebug.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -static struct mcf_platform_uart m532x_uart_platform[] = { - { - .mapbase = MCFUART_BASE1, - .irq = MCFINT_VECBASE + MCFINT_UART0, - }, - { - .mapbase = MCFUART_BASE2, - .irq = MCFINT_VECBASE + MCFINT_UART1, - }, - { - .mapbase = MCFUART_BASE3, - .irq = MCFINT_VECBASE + MCFINT_UART2, - }, - { }, -}; - -static struct platform_device m532x_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m532x_uart_platform, -}; - -static struct resource m532x_fec_resources[] = { - { - .start = 0xfc030000, - .end = 0xfc0307ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 64 + 36, - .end = 64 + 36, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 40, - .end = 64 + 40, - .flags = IORESOURCE_IRQ, - }, - { - .start = 64 + 42, - .end = 64 + 42, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device m532x_fec = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(m532x_fec_resources), - .resource = m532x_fec_resources, -}; - -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) -static struct resource m532x_qspi_resources[] = { - { - .start = MCFQSPI_IOBASE, - .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCFINT_VECBASE + MCFINT_QSPI, - .end = MCFINT_VECBASE + MCFINT_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -#define MCFQSPI_CS0 84 -#define MCFQSPI_CS1 85 -#define MCFQSPI_CS2 86 - -static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - - return 0; - -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void m532x_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high); -} - -static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high); -} - -static struct mcfqspi_cs_control m532x_cs_control = { - .setup = m532x_cs_setup, - .teardown = m532x_cs_teardown, - .select = m532x_cs_select, - .deselect = m532x_cs_deselect, -}; - -static struct mcfqspi_platform_data m532x_qspi_data = { - .bus_num = 0, - .num_chipselect = 3, - .cs_control = &m532x_cs_control, -}; - -static struct platform_device m532x_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(m532x_qspi_resources), - .resource = m532x_qspi_resources, - .dev.platform_data = &m532x_qspi_data, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m532x_qspi_init(void) { /* setup QSPS pins for QSPI with gpio CS control */ writew(0x01f0, MCF_GPIO_PAR_QSPI); } -#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ - -static struct platform_device *m532x_devices[] __initdata = { - &m532x_uart, - &m532x_fec, -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - &m532x_qspi, -#endif -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m532x_uart_init_line(int line, int irq) -{ - if (line == 0) { - /* GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x000F; - } else if (line == 1) { - /* GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x0FF0; - } -} - static void __init m532x_uarts_init(void) { - const int nrlines = ARRAY_SIZE(m532x_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m532x_uart_init_line(line, m532x_uart_platform[line].irq); + /* UART GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x0FFF; } + /***************************************************************************/ static void __init m532x_fec_init(void) @@ -242,14 +61,6 @@ static void __init m532x_fec_init(void) /***************************************************************************/ -static void m532x_cpu_reset(void) -{ - local_irq_disable(); - __raw_writeb(MCF_RCR_SWRESET, MCF_RCR); -} - -/***************************************************************************/ - void __init config_BSP(char *commandp, int size) { #if !defined(CONFIG_BOOTPARAM) @@ -263,6 +74,13 @@ void __init config_BSP(char *commandp, int size) } #endif + mach_sched_init = hw_timer_init; + m532x_uarts_init(); + m532x_fec_init(); +#ifdef CONFIG_SPI_COLDFIRE_QSPI + m532x_qspi_init(); +#endif + #ifdef CONFIG_BDM_DISABLE /* * Disable the BDM clocking. This also turns off most of the rest of @@ -274,21 +92,6 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ - -static int __init init_BSP(void) -{ - m532x_uarts_init(); - m532x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) - m532x_qspi_init(); -#endif - platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ /* Board initialization */ /***************************************************************************/ /* diff --git a/arch/m68k/platform/5407/config.c b/arch/m68k/platform/5407/config.c index 70ea789a400c..bb6c746ae819 100644 --- a/arch/m68k/platform/5407/config.c +++ b/arch/m68k/platform/5407/config.c @@ -16,91 +16,12 @@ #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> - -/***************************************************************************/ - -static struct mcf_platform_uart m5407_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = 73, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = 74, - }, - { }, -}; - -static struct platform_device m5407_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m5407_uart_platform, -}; - -static struct platform_device *m5407_devices[] __initdata = { - &m5407_uart, -}; - -/***************************************************************************/ - -static void __init m5407_uart_init_line(int line, int irq) -{ - if (line == 0) { - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); - writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART0); - } else if (line == 1) { - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); - writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); - mcf_mapirq2imr(irq, MCFINTC_UART1); - } -} - -static void __init m5407_uarts_init(void) -{ - const int nrlines = ARRAY_SIZE(m5407_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m5407_uart_init_line(line, m5407_uart_platform[line].irq); -} - -/***************************************************************************/ - -static void __init m5407_timers_init(void) -{ - /* Timer1 is always used as system timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER1ICR); - mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); - -#ifdef CONFIG_HIGHPROFILE - /* Timer2 is to be used as a high speed profile timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER2ICR); - mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); -#endif -} - -/***************************************************************************/ - -void m5407_cpu_reset(void) -{ - local_irq_disable(); - /* set watchdog to soft reset, and enabled */ - __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); - for (;;) - /* wait for watchdog to timeout */; -} /***************************************************************************/ void __init config_BSP(char *commandp, int size) { - mach_reset = m5407_cpu_reset; - m5407_timers_init(); - m5407_uarts_init(); + mach_sched_init = hw_timer_init; /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -110,13 +31,3 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ - -static int __init init_BSP(void) -{ - platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/arch/m68k/platform/54xx/config.c b/arch/m68k/platform/54xx/config.c index ee043540bfa2..2081c6cbb3de 100644 --- a/arch/m68k/platform/54xx/config.c +++ b/arch/m68k/platform/54xx/config.c @@ -27,64 +27,17 @@ /***************************************************************************/ -static struct mcf_platform_uart m54xx_uart_platform[] = { - { - .mapbase = MCF_MBAR + MCFUART_BASE1, - .irq = 64 + 35, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE2, - .irq = 64 + 34, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE3, - .irq = 64 + 33, - }, - { - .mapbase = MCF_MBAR + MCFUART_BASE4, - .irq = 64 + 32, - }, -}; - -static struct platform_device m54xx_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = m54xx_uart_platform, -}; - -static struct platform_device *m54xx_devices[] __initdata = { - &m54xx_uart, -}; - - -/***************************************************************************/ - -static void __init m54xx_uart_init_line(int line, int irq) -{ - int rts_cts; - - /* enable io pins */ - switch (line) { - case 0: - rts_cts = 0; break; - case 1: - rts_cts = MCF_PAR_PSC_RTS_RTS; break; - case 2: - rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break; - case 3: - rts_cts = 0; break; - } - __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD, - MCF_MBAR + MCF_PAR_PSC(line)); -} - static void __init m54xx_uarts_init(void) { - const int nrlines = ARRAY_SIZE(m54xx_uart_platform); - int line; - - for (line = 0; (line < nrlines); line++) - m54xx_uart_init_line(line, m54xx_uart_platform[line].irq); + /* enable io pins */ + __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, + MCF_MBAR + MCF_PAR_PSC(0)); + __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS, + MCF_MBAR + MCF_PAR_PSC(1)); + __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS | + MCF_PAR_PSC_CTS_CTS, MCF_MBAR + MCF_PAR_PSC(2)); + __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, + MCF_MBAR + MCF_PAR_PSC(3)); } /***************************************************************************/ @@ -145,18 +98,8 @@ void __init config_BSP(char *commandp, int size) mmu_context_init(); #endif mach_reset = mcf54xx_reset; + mach_sched_init = hw_timer_init; m54xx_uarts_init(); } /***************************************************************************/ - -static int __init init_BSP(void) -{ - - platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices)); - return 0; -} - -arch_initcall(init_BSP); - -/***************************************************************************/ diff --git a/arch/m68k/platform/68328/config.c b/arch/m68k/platform/68328/config.c index d70bf2623db1..44b866544314 100644 --- a/arch/m68k/platform/68328/config.c +++ b/arch/m68k/platform/68328/config.c @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/rtc.h> #include <asm/system.h> #include <asm/machdep.h> #include <asm/MC68328.h> @@ -26,7 +27,7 @@ /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); +int m68328_hwclk(int set, struct rtc_time *t); /***************************************************************************/ @@ -48,7 +49,7 @@ void config_BSP(char *command, int len) printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n"); printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n"); - mach_gettod = m68328_timer_gettod; + mach_hwclk = m68328_hwclk; mach_reset = m68328_reset; } diff --git a/arch/m68k/platform/68328/ints.c b/arch/m68k/platform/68328/ints.c index 4bd456531f91..b3810febb3e3 100644 --- a/arch/m68k/platform/68328/ints.c +++ b/arch/m68k/platform/68328/ints.c @@ -68,8 +68,6 @@ asmlinkage irqreturn_t inthandler5(void); asmlinkage irqreturn_t inthandler6(void); asmlinkage irqreturn_t inthandler7(void); -extern e_vector *_ramvec; - /* The 68k family did not have a good way to determine the source * of interrupts until later in the family. The EC000 core does * not provide the vector number on the stack, we vector everything diff --git a/arch/m68k/platform/68328/timers.c b/arch/m68k/platform/68328/timers.c index f2678866067b..b15ddef1ec76 100644 --- a/arch/m68k/platform/68328/timers.c +++ b/arch/m68k/platform/68328/timers.c @@ -20,6 +20,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/clocksource.h> +#include <linux/rtc.h> #include <asm/setup.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -119,14 +120,17 @@ void hw_timer_init(void) /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec) +int m68328_hwclk(int set, struct rtc_time *t) { - long now = RTCTIME; - - *year = *mon = *day = 1; - *hour = (now >> 24) % 24; - *min = (now >> 16) % 60; - *sec = now % 60; + if (!set) { + long now = RTCTIME; + t->tm_year = t->tm_mon = t->tm_mday = 1; + t->tm_hour = (now >> 24) % 24; + t->tm_min = (now >> 16) % 60; + t->tm_sec = now % 60; + } + + return 0; } /***************************************************************************/ diff --git a/arch/m68k/platform/68360/config.c b/arch/m68k/platform/68360/config.c index 9dd5bca38749..599a5949f320 100644 --- a/arch/m68k/platform/68360/config.c +++ b/arch/m68k/platform/68360/config.c @@ -103,11 +103,6 @@ void hw_timer_init(void) pquicc->timer_tgcr = tgcr_save; } -void BSP_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ -} - int BSP_set_clock_mmss(unsigned long nowtime) { #if 0 @@ -181,6 +176,5 @@ void config_BSP(char *command, int len) scc1_hwaddr = "\00\01\02\03\04\05"; #endif - mach_gettod = BSP_gettod; - mach_reset = BSP_reset; + mach_reset = BSP_reset; } diff --git a/arch/m68k/platform/68360/ints.c b/arch/m68k/platform/68360/ints.c index 7b40202d9638..8cd42692331b 100644 --- a/arch/m68k/platform/68360/ints.c +++ b/arch/m68k/platform/68360/ints.c @@ -32,8 +32,6 @@ asmlinkage void trap(void); asmlinkage void bad_interrupt(void); asmlinkage void inthandler(void); -extern void *_ramvec[]; - static void intc_irq_unmask(struct irq_data *d) { pquicc->intr_cimr |= (1 << d->irq); diff --git a/arch/m68k/platform/68EZ328/config.c b/arch/m68k/platform/68EZ328/config.c index 1be1a16f6896..dd2c53554341 100644 --- a/arch/m68k/platform/68EZ328/config.c +++ b/arch/m68k/platform/68EZ328/config.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/rtc.h> #include <asm/system.h> #include <asm/pgtable.h> #include <asm/machdep.h> @@ -25,7 +26,7 @@ /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); +int m68328_hwclk(int set, struct rtc_time *t); /***************************************************************************/ @@ -69,7 +70,7 @@ void config_BSP(char *command, int len) else command[0] = 0; #endif - mach_gettod = m68328_timer_gettod; + mach_hwclk = m68328_hwclk; mach_reset = m68ez328_reset; } diff --git a/arch/m68k/platform/68VZ328/config.c b/arch/m68k/platform/68VZ328/config.c index eabaabe8af36..25ec673edc25 100644 --- a/arch/m68k/platform/68VZ328/config.c +++ b/arch/m68k/platform/68VZ328/config.c @@ -20,6 +20,7 @@ #include <linux/netdevice.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/rtc.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -33,7 +34,7 @@ /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); +int m68328_hwclk(int set, struct rtc_time *t); /***************************************************************************/ /* Init Drangon Engine hardware */ @@ -181,7 +182,7 @@ void config_BSP(char *command, int size) init_hardware(command, size); - mach_gettod = m68328_timer_gettod; + mach_hwclk = m68328_hwclk; mach_reset = m68vz328_reset; } diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile index a8967baabd72..a0815c61dec1 100644 --- a/arch/m68k/platform/coldfire/Makefile +++ b/arch/m68k/platform/coldfire/Makefile @@ -14,18 +14,18 @@ asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 -obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o -obj-$(CONFIG_M5206) += timers.o intc.o -obj-$(CONFIG_M5206e) += timers.o intc.o -obj-$(CONFIG_M520x) += pit.o intc-simr.o -obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o -obj-$(CONFIG_M5249) += timers.o intc.o -obj-$(CONFIG_M527x) += pit.o intc-2.o +obj-$(CONFIG_COLDFIRE) += cache.o clk.o device.o dma.o entry.o vectors.o +obj-$(CONFIG_M5206) += timers.o intc.o reset.o +obj-$(CONFIG_M5206e) += timers.o intc.o reset.o +obj-$(CONFIG_M520x) += pit.o intc-simr.o reset.o +obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o reset.o +obj-$(CONFIG_M5249) += timers.o intc.o reset.o +obj-$(CONFIG_M527x) += pit.o intc-2.o reset.o obj-$(CONFIG_M5272) += timers.o -obj-$(CONFIG_M528x) += pit.o intc-2.o -obj-$(CONFIG_M5307) += timers.o intc.o -obj-$(CONFIG_M532x) += timers.o intc-simr.o -obj-$(CONFIG_M5407) += timers.o intc.o +obj-$(CONFIG_M528x) += pit.o intc-2.o reset.o +obj-$(CONFIG_M5307) += timers.o intc.o reset.o +obj-$(CONFIG_M532x) += timers.o intc-simr.o reset.o +obj-$(CONFIG_M5407) += timers.o intc.o reset.o obj-$(CONFIG_M54xx) += sltimers.o intc-2.o obj-y += pinmux.o gpio.o diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c new file mode 100644 index 000000000000..fa50c48292ff --- /dev/null +++ b/arch/m68k/platform/coldfire/device.c @@ -0,0 +1,318 @@ +/* + * device.c -- common ColdFire SoC device support + * + * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> +#include <asm/traps.h> +#include <asm/coldfire.h> +#include <asm/mcfsim.h> +#include <asm/mcfuart.h> +#include <asm/mcfqspi.h> + +/* + * All current ColdFire parts contain from 2, 3 or 4 UARTS. + */ +static struct mcf_platform_uart mcf_uart_platform_data[] = { + { + .mapbase = MCFUART_BASE0, + .irq = MCF_IRQ_UART0, + }, + { + .mapbase = MCFUART_BASE1, + .irq = MCF_IRQ_UART1, + }, +#ifdef MCFUART_BASE2 + { + .mapbase = MCFUART_BASE2, + .irq = MCF_IRQ_UART2, + }, +#endif +#ifdef MCFUART_BASE3 + { + .mapbase = MCFUART_BASE3, + .irq = MCF_IRQ_UART3, + }, +#endif + { }, +}; + +static struct platform_device mcf_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = mcf_uart_platform_data, +}; + +#ifdef CONFIG_FEC +/* + * Some ColdFire cores contain the Fast Ethernet Controller (FEC) + * block. It is Freescale's own hardware block. Some ColdFires + * have 2 of these. + */ +static struct resource mcf_fec0_resources[] = { + { + .start = MCFFEC_BASE0, + .end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF_IRQ_FECRX0, + .end = MCF_IRQ_FECRX0, + .flags = IORESOURCE_IRQ, + }, + { + .start = MCF_IRQ_FECTX0, + .end = MCF_IRQ_FECTX0, + .flags = IORESOURCE_IRQ, + }, + { + .start = MCF_IRQ_FECENTC0, + .end = MCF_IRQ_FECENTC0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mcf_fec0 = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(mcf_fec0_resources), + .resource = mcf_fec0_resources, +}; + +#ifdef MCFFEC_BASE1 +static struct resource mcf_fec1_resources[] = { + { + .start = MCFFEC_BASE1, + .end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF_IRQ_FECRX1, + .end = MCF_IRQ_FECRX1, + .flags = IORESOURCE_IRQ, + }, + { + .start = MCF_IRQ_FECTX1, + .end = MCF_IRQ_FECTX1, + .flags = IORESOURCE_IRQ, + }, + { + .start = MCF_IRQ_FECENTC1, + .end = MCF_IRQ_FECENTC1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mcf_fec1 = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(mcf_fec1_resources), + .resource = mcf_fec1_resources, +}; +#endif /* MCFFEC_BASE1 */ +#endif /* CONFIG_FEC */ + +#ifdef CONFIG_SPI_COLDFIRE_QSPI +/* + * The ColdFire QSPI module is an SPI protocol hardware block used + * on a number of different ColdFire CPUs. + */ +static struct resource mcf_qspi_resources[] = { + { + .start = MCFQSPI_BASE, + .end = MCFQSPI_BASE + MCFQSPI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF_IRQ_QSPI, + .end = MCF_IRQ_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + +#ifdef MCFQSPI_CS3 + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + gpio_free(MCFQSPI_CS3); + goto fail3; + } +#endif + + return 0; + +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ +#ifdef MCFQSPI_CS3 + gpio_free(MCFQSPI_CS3); +#endif + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void mcf_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; +#ifdef MCFQSPI_CS3 + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; +#endif + } +} + +static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; +#ifdef MCFQSPI_CS3 + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; +#endif + } +} + +static struct mcfqspi_cs_control mcf_cs_control = { + .setup = mcf_cs_setup, + .teardown = mcf_cs_teardown, + .select = mcf_cs_select, + .deselect = mcf_cs_deselect, +}; + +static struct mcfqspi_platform_data mcf_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &mcf_cs_control, +}; + +static struct platform_device mcf_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(mcf_qspi_resources), + .resource = mcf_qspi_resources, + .dev.platform_data = &mcf_qspi_data, +}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ + +static struct platform_device *mcf_devices[] __initdata = { + &mcf_uart, +#ifdef CONFIG_FEC + &mcf_fec0, +#ifdef MCFFEC_BASE1 + &mcf_fec1, +#endif +#endif +#ifdef CONFIG_SPI_COLDFIRE_QSPI + &mcf_qspi, +#endif +}; + +/* + * Some ColdFire UARTs let you set the IRQ line to use. + */ +static void __init mcf_uart_set_irq(void) +{ +#ifdef MCFUART_UIVR + /* UART0 interrupt setup */ + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); + writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR); + mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0); + + /* UART1 interrupt setup */ + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); + writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR); + mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1); +#endif +} + +static int __init mcf_init_devices(void) +{ + mcf_uart_set_irq(); + platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices)); + return 0; +} + +arch_initcall(mcf_init_devices); + diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S index 38f04a3f6207..c3db70ed33b3 100644 --- a/arch/m68k/platform/coldfire/head.S +++ b/arch/m68k/platform/coldfire/head.S @@ -158,6 +158,10 @@ _start: #if defined(CONFIG_UBOOT) movel %sp,_init_sp /* save initial stack pointer */ #endif +#ifdef CONFIG_MBAR + movel #CONFIG_MBAR+1,%d0 /* configured MBAR address */ + movec %d0,%MBAR /* set it */ +#endif /* * Do any platform or board specific setup now. Most boards diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c index 02663d25822d..e62dbbcb10f6 100644 --- a/arch/m68k/platform/coldfire/pit.c +++ b/arch/m68k/platform/coldfire/pit.c @@ -149,7 +149,7 @@ static struct clocksource pit_clk = { /***************************************************************************/ -void hw_timer_init(void) +void hw_timer_init(irq_handler_t handler) { cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); diff --git a/arch/m68k/platform/coldfire/reset.c b/arch/m68k/platform/coldfire/reset.c new file mode 100644 index 000000000000..933e54eacc69 --- /dev/null +++ b/arch/m68k/platform/coldfire/reset.c @@ -0,0 +1,50 @@ +/* + * reset.c -- common ColdFire SoC reset support + * + * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <asm/machdep.h> +#include <asm/coldfire.h> +#include <asm/mcfsim.h> + +/* + * There are 2 common methods amongst the ColdFure parts for reseting + * the CPU. But there are couple of exceptions, the 5272 and the 547x + * have something completely special to them, and we let their specific + * subarch code handle them. + */ + +#ifdef MCFSIM_SYPCR +static void mcf_cpu_reset(void) +{ + local_irq_disable(); + /* Set watchdog to soft reset, and enabled */ + __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); + for (;;) + /* wait for watchdog to timeout */; +} +#endif + +#ifdef MCF_RCR +static void mcf_cpu_reset(void) +{ + local_irq_disable(); + __raw_writeb(MCF_RCR_SWRESET, MCF_RCR); +} +#endif + +static int __init mcf_setup_reset(void) +{ + mach_reset = mcf_cpu_reset; + return 0; +} + +arch_initcall(mcf_setup_reset); diff --git a/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c index 54e1452f853a..2027fc20b876 100644 --- a/arch/m68k/platform/coldfire/sltimers.c +++ b/arch/m68k/platform/coldfire/sltimers.c @@ -81,12 +81,14 @@ void mcfslt_profile_init(void) static u32 mcfslt_cycles_per_jiffy; static u32 mcfslt_cnt; +static irq_handler_t timer_interrupt; + static irqreturn_t mcfslt_tick(int irq, void *dummy) { /* Reset Slice Timer 0 */ __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR)); mcfslt_cnt += mcfslt_cycles_per_jiffy; - return arch_timer_interrupt(irq, dummy); + return timer_interrupt(irq, dummy); } static struct irqaction mcfslt_timer_irq = { @@ -121,7 +123,7 @@ static struct clocksource mcfslt_clk = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -void hw_timer_init(void) +void hw_timer_init(irq_handler_t handler) { mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ; /* @@ -136,6 +138,7 @@ void hw_timer_init(void) /* initialize mcfslt_cnt knowing that slice timers count down */ mcfslt_cnt = mcfslt_cycles_per_jiffy; + timer_interrupt = handler; setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq); clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK); diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c index 0d90da32fcdb..ed96ce50d79f 100644 --- a/arch/m68k/platform/coldfire/timers.c +++ b/arch/m68k/platform/coldfire/timers.c @@ -47,6 +47,27 @@ void coldfire_profile_init(void); static u32 mcftmr_cycles_per_jiffy; static u32 mcftmr_cnt; +static irq_handler_t timer_interrupt; + +/***************************************************************************/ + +static void init_timer_irq(void) +{ +#ifdef MCFSIM_ICR_AUTOVEC + /* Timer1 is always used as system timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER1ICR); + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); + +#ifdef CONFIG_HIGHPROFILE + /* Timer2 is to be used as a high speed profile timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER2ICR); + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); +#endif +#endif /* MCFSIM_ICR_AUTOVEC */ +} + /***************************************************************************/ static irqreturn_t mcftmr_tick(int irq, void *dummy) @@ -55,7 +76,7 @@ static irqreturn_t mcftmr_tick(int irq, void *dummy) __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); mcftmr_cnt += mcftmr_cycles_per_jiffy; - return arch_timer_interrupt(irq, dummy); + return timer_interrupt(irq, dummy); } /***************************************************************************/ @@ -94,7 +115,7 @@ static struct clocksource mcftmr_clk = { /***************************************************************************/ -void hw_timer_init(void) +void hw_timer_init(irq_handler_t handler) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); mcftmr_cycles_per_jiffy = FREQ / HZ; @@ -110,6 +131,8 @@ void hw_timer_init(void) clocksource_register_hz(&mcftmr_clk, FREQ); + timer_interrupt = handler; + init_timer_irq(); setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq); #ifdef CONFIG_HIGHPROFILE diff --git a/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c index 3a7cc524ecd3..a4dbdecbec7a 100644 --- a/arch/m68k/platform/coldfire/vectors.c +++ b/arch/m68k/platform/coldfire/vectors.c @@ -33,8 +33,6 @@ asmlinkage void dbginterrupt_c(struct frame *fp) /***************************************************************************/ -extern e_vector *_ramvec; - /* Assembler routines */ asmlinkage void buserr(void); asmlinkage void trap(void); diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index c8d6efb99dbf..11060fa87da3 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -14,6 +14,7 @@ config MICROBLAZE select TRACING_SUPPORT select OF select OF_EARLY_FLATTREE + select IRQ_DOMAIN select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/microblaze/include/asm/hardirq.h b/arch/microblaze/include/asm/hardirq.h index cd1ac9aad56c..fb3c05a0cbbf 100644 --- a/arch/microblaze/include/asm/hardirq.h +++ b/arch/microblaze/include/asm/hardirq.h @@ -1,17 +1 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_HARDIRQ_H -#define _ASM_MICROBLAZE_HARDIRQ_H - -/* should be defined in each interrupt controller driver */ -extern unsigned int get_irq(struct pt_regs *regs); - #include <asm-generic/hardirq.h> - -#endif /* _ASM_MICROBLAZE_HARDIRQ_H */ diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index a175132e4496..bab3b1393ad4 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h @@ -9,49 +9,13 @@ #ifndef _ASM_MICROBLAZE_IRQ_H #define _ASM_MICROBLAZE_IRQ_H - -/* - * Linux IRQ# is currently offset by one to map to the hardware - * irq number. So hardware IRQ0 maps to Linux irq 1. - */ -#define NO_IRQ_OFFSET 1 -#define IRQ_OFFSET NO_IRQ_OFFSET -#define NR_IRQS (32 + IRQ_OFFSET) +#define NR_IRQS (32 + 1) #include <asm-generic/irq.h> -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -extern unsigned int nr_irq; - struct pt_regs; extern void do_IRQ(struct pt_regs *regs); -/** FIXME - not implement - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ - return; -} - -struct irq_host; - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq); +/* should be defined in each interrupt controller driver */ +extern unsigned int get_irq(void); #endif /* _ASM_MICROBLAZE_IRQ_H */ diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 44b177e2ab12..ad120672cee5 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -9,6 +9,7 @@ */ #include <linux/init.h> +#include <linux/irqdomain.h> #include <linux/irq.h> #include <asm/page.h> #include <linux/io.h> @@ -25,8 +26,6 @@ static unsigned int intc_baseaddr; #define INTC_BASE intc_baseaddr #endif -unsigned int nr_irq; - /* No one else should require these constants, so define them locally here. */ #define ISR 0x00 /* Interrupt Status Register */ #define IPR 0x04 /* Interrupt Pending Register */ @@ -84,24 +83,45 @@ static struct irq_chip intc_dev = { .irq_mask_ack = intc_mask_ack, }; -unsigned int get_irq(struct pt_regs *regs) +static struct irq_domain *root_domain; + +unsigned int get_irq(void) { - int irq; + unsigned int hwirq, irq = -1; - /* - * NOTE: This function is the one that needs to be improved in - * order to handle multiple interrupt controllers. It currently - * is hardcoded to check for interrupts only on the first INTC. - */ - irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET; - pr_debug("get_irq: %d\n", irq); + hwirq = in_be32(INTC_BASE + IVR); + if (hwirq != -1U) + irq = irq_find_mapping(root_domain, hwirq); + + pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq); return irq; } +int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + u32 intr_mask = (u32)d->host_data; + + if (intr_mask & (1 << hw)) { + irq_set_chip_and_handler_name(irq, &intc_dev, + handle_edge_irq, "edge"); + irq_clear_status_flags(irq, IRQ_LEVEL); + } else { + irq_set_chip_and_handler_name(irq, &intc_dev, + handle_level_irq, "level"); + irq_set_status_flags(irq, IRQ_LEVEL); + } + return 0; +} + +static const struct irq_domain_ops xintc_irq_domain_ops = { + .xlate = irq_domain_xlate_onetwocell, + .map = xintc_map, +}; + void __init init_IRQ(void) { - u32 i, intr_mask; + u32 nr_irq, intr_mask; struct device_node *intc = NULL; #ifdef CONFIG_SELFMOD_INTC unsigned int intc_baseaddr = 0; @@ -146,16 +166,9 @@ void __init init_IRQ(void) /* Turn on the Master Enable. */ out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); - for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) { - if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) { - irq_set_chip_and_handler_name(i, &intc_dev, - handle_edge_irq, "edge"); - irq_clear_status_flags(i, IRQ_LEVEL); - } else { - irq_set_chip_and_handler_name(i, &intc_dev, - handle_level_irq, "level"); - irq_set_status_flags(i, IRQ_LEVEL); - } - irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET; - } + /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm + * lazy and Michal can clean it up to something nicer when he tests + * and commits this patch. ~~gcl */ + root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, + (void *)intr_mask); } diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index bbebcae72c02..ace700afbfdf 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs) trace_hardirqs_off(); irq_enter(); - irq = get_irq(regs); + irq = get_irq(); next_irq: BUG_ON(!irq); - /* Substract 1 because of get_irq */ - generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET); + generic_handle_irq(irq); - irq = get_irq(regs); - if (irq) { + irq = get_irq(); + if (irq != -1U) { pr_debug("next irq: %d\n", irq); ++concurrent_irq; goto next_irq; @@ -48,18 +47,3 @@ next_irq: set_irq_regs(old_regs); trace_hardirqs_on(); } - -/* MS: There is no any advance mapping mechanism. We are using simple 32bit - intc without any cascades or any connection that's why mapping is 1:1 */ -unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) -{ - return hwirq + IRQ_OFFSET; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0] + IRQ_OFFSET; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 604cd9dd1333..70e6d0b41ab4 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p) unflatten_device_tree(); - /* NOTE I think that this function is not necessary to call */ - /* irq_early_init(); */ setup_cpuinfo(); microblaze_cache_init(); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5ab6e89603c5..edbbae17e820 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2327,6 +2327,7 @@ config USE_OF bool "Flattened Device Tree support" select OF select OF_EARLY_FLATTREE + select IRQ_DOMAIN help Include support for flattened device tree machine descriptions. diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile index 4add17349ff9..4389de182eb4 100644 --- a/arch/mips/bcm47xx/Makefile +++ b/arch/mips/bcm47xx/Makefile @@ -3,5 +3,5 @@ # under Linux. # -obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o +obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c index a84e3bb7387f..d43ceff5be47 100644 --- a/arch/mips/bcm47xx/nvram.c +++ b/arch/mips/bcm47xx/nvram.c @@ -107,8 +107,7 @@ int nvram_getenv(char *name, char *val, size_t val_len) value = eq + 1; if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) { - snprintf(val, val_len, "%s", value); - return 0; + return snprintf(val, val_len, "%s", value); } } return NVRAM_ERR_ENVNOTFOUND; diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index aab6b0c40a75..19780aa91708 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -3,7 +3,7 @@ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> * Copyright (C) 2006 Michael Buesch <m@bues.ch> * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> - * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> * * 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 @@ -85,156 +85,7 @@ static void bcm47xx_machine_halt(void) } #ifdef CONFIG_BCM47XX_SSB -#define READ_FROM_NVRAM(_outvar, name, buf) \ - if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\ - sprom->_outvar = simple_strtoul(buf, NULL, 0); - -#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \ - if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \ - nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\ - sprom->_outvar = simple_strtoul(buf, NULL, 0); - -static inline int nvram_getprefix(const char *prefix, char *name, - char *buf, int len) -{ - if (prefix) { - char key[100]; - - snprintf(key, sizeof(key), "%s%s", prefix, name); - return nvram_getenv(key, buf, len); - } - - return nvram_getenv(name, buf, len); -} - -static u32 nvram_getu32(const char *name, char *buf, int len) -{ - int rv; - char key[100]; - u16 var0, var1; - - snprintf(key, sizeof(key), "%s0", name); - rv = nvram_getenv(key, buf, len); - /* return 0 here so this looks like unset */ - if (rv < 0) - return 0; - var0 = simple_strtoul(buf, NULL, 0); - - snprintf(key, sizeof(key), "%s1", name); - rv = nvram_getenv(key, buf, len); - if (rv < 0) - return 0; - var1 = simple_strtoul(buf, NULL, 0); - return var1 << 16 | var0; -} - -static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) -{ - char buf[100]; - u32 boardflags; - - memset(sprom, 0, sizeof(struct ssb_sprom)); - - sprom->revision = 1; /* Fallback: Old hardware does not define this. */ - READ_FROM_NVRAM(revision, "sromrev", buf); - if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 || - nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0) - nvram_parse_macaddr(buf, sprom->il0mac); - if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0) - nvram_parse_macaddr(buf, sprom->et0mac); - if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0) - nvram_parse_macaddr(buf, sprom->et1mac); - READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf); - READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf); - READ_FROM_NVRAM(et0mdcport, "et0mdcport", buf); - READ_FROM_NVRAM(et1mdcport, "et1mdcport", buf); - READ_FROM_NVRAM(board_rev, "boardrev", buf); - READ_FROM_NVRAM(country_code, "ccode", buf); - READ_FROM_NVRAM(ant_available_a, "aa5g", buf); - READ_FROM_NVRAM(ant_available_bg, "aa2g", buf); - READ_FROM_NVRAM(pa0b0, "pa0b0", buf); - READ_FROM_NVRAM(pa0b1, "pa0b1", buf); - READ_FROM_NVRAM(pa0b2, "pa0b2", buf); - READ_FROM_NVRAM(pa1b0, "pa1b0", buf); - READ_FROM_NVRAM(pa1b1, "pa1b1", buf); - READ_FROM_NVRAM(pa1b2, "pa1b2", buf); - READ_FROM_NVRAM(pa1lob0, "pa1lob0", buf); - READ_FROM_NVRAM(pa1lob2, "pa1lob1", buf); - READ_FROM_NVRAM(pa1lob1, "pa1lob2", buf); - READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf); - READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf); - READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf); - READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf); - READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf); - READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf); - READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf); - READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf); - READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf); - READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf); - READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf); - READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf); - READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf); - READ_FROM_NVRAM(tri2g, "tri2g", buf); - READ_FROM_NVRAM(tri5gl, "tri5gl", buf); - READ_FROM_NVRAM(tri5g, "tri5g", buf); - READ_FROM_NVRAM(tri5gh, "tri5gh", buf); - READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf); - READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf); - READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf); - READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf); - READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf); - READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf); - READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf); - READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf); - READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf); - READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf); - READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf); - READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf); - READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf); - READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf); - READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf); - READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf); - READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf); - READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf); - READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf); - READ_FROM_NVRAM(rssismc2g, "rssismc2g", buf); - READ_FROM_NVRAM(rssismf2g, "rssismf2g", buf); - READ_FROM_NVRAM(bxa2g, "bxa2g", buf); - READ_FROM_NVRAM(rssisav5g, "rssisav5g", buf); - READ_FROM_NVRAM(rssismc5g, "rssismc5g", buf); - READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf); - READ_FROM_NVRAM(bxa5g, "bxa5g", buf); - READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf); - - sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf)); - sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf)); - sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf)); - sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf)); - - READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf); - READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf); - READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf); - READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf); - memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24, - sizeof(sprom->antenna_gain.ghz5)); - - if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) { - boardflags = simple_strtoul(buf, NULL, 0); - if (boardflags) { - sprom->boardflags_lo = (boardflags & 0x0000FFFFU); - sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16; - } - } - if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) { - boardflags = simple_strtoul(buf, NULL, 0); - if (boardflags) { - sprom->boardflags2_lo = (boardflags & 0x0000FFFFU); - sprom->boardflags2_hi = (boardflags & 0xFFFF0000U) >> 16; - } - } -} - -int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) { char prefix[10]; @@ -251,7 +102,7 @@ int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out) } static int bcm47xx_get_invariants(struct ssb_bus *bus, - struct ssb_init_invariants *iv) + struct ssb_init_invariants *iv) { char buf[20]; @@ -281,7 +132,7 @@ static void __init bcm47xx_register_ssb(void) char buf[100]; struct ssb_mipscore *mcore; - err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom); + err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom_ssb); if (err) printk(KERN_WARNING "bcm47xx: someone else already registered" " a ssb SPROM callback handler (err %d)\n", err); @@ -308,10 +159,41 @@ static void __init bcm47xx_register_ssb(void) #endif #ifdef CONFIG_BCM47XX_BCMA +static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) +{ + char prefix[10]; + struct bcma_device *core; + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + snprintf(prefix, sizeof(prefix), "pci/%u/%u/", + bus->host_pci->bus->number + 1, + PCI_SLOT(bus->host_pci->devfn)); + bcm47xx_fill_sprom(out, prefix); + return 0; + case BCMA_HOSTTYPE_SOC: + bcm47xx_fill_sprom_ethernet(out, NULL); + core = bcma_find_core(bus, BCMA_CORE_80211); + if (core) { + snprintf(prefix, sizeof(prefix), "sb/%u/", + core->core_index); + bcm47xx_fill_sprom(out, prefix); + } + return 0; + default: + pr_warn("bcm47xx: unable to fill SPROM for given bustype.\n"); + return -EINVAL; + } +} + static void __init bcm47xx_register_bcma(void) { int err; + err = bcma_arch_register_fallback_sprom(&bcm47xx_get_sprom_bcma); + if (err) + pr_warn("bcm47xx: someone else already registered a bcma SPROM callback handler (err %d)\n", err); + err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) panic("Failed to initialize BCMA bus (err %d)", err); diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c new file mode 100644 index 000000000000..5c8dcd2a8a93 --- /dev/null +++ b/arch/mips/bcm47xx/sprom.c @@ -0,0 +1,620 @@ +/* + * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2006 Michael Buesch <m@bues.ch> + * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> + * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <bcm47xx.h> +#include <nvram.h> + +static void create_key(const char *prefix, const char *postfix, + const char *name, char *buf, int len) +{ + if (prefix && postfix) + snprintf(buf, len, "%s%s%s", prefix, name, postfix); + else if (prefix) + snprintf(buf, len, "%s%s", prefix, name); + else if (postfix) + snprintf(buf, len, "%s%s", name, postfix); + else + snprintf(buf, len, "%s", name); +} + +#define NVRAM_READ_VAL(type) \ +static void nvram_read_ ## type (const char *prefix, \ + const char *postfix, const char *name, \ + type *val, type allset) \ +{ \ + char buf[100]; \ + char key[40]; \ + int err; \ + type var; \ + \ + create_key(prefix, postfix, name, key, sizeof(key)); \ + \ + err = nvram_getenv(key, buf, sizeof(buf)); \ + if (err < 0) \ + return; \ + err = kstrto ## type (buf, 0, &var); \ + if (err) { \ + pr_warn("can not parse nvram name %s with value %s" \ + " got %i", key, buf, err); \ + return; \ + } \ + if (allset && var == allset) \ + return; \ + *val = var; \ +} + +NVRAM_READ_VAL(u8) +NVRAM_READ_VAL(s8) +NVRAM_READ_VAL(u16) +NVRAM_READ_VAL(u32) + +#undef NVRAM_READ_VAL + +static void nvram_read_u32_2(const char *prefix, const char *name, + u16 *val_lo, u16 *val_hi) +{ + char buf[100]; + char key[40]; + int err; + u32 val; + + create_key(prefix, NULL, name, key, sizeof(key)); + + err = nvram_getenv(key, buf, sizeof(buf)); + if (err < 0) + return; + err = kstrtou32(buf, 0, &val); + if (err) { + pr_warn("can not parse nvram name %s with value %s got %i", + key, buf, err); + return; + } + *val_lo = (val & 0x0000FFFFU); + *val_hi = (val & 0xFFFF0000U) >> 16; +} + +static void nvram_read_leddc(const char *prefix, const char *name, + u8 *leddc_on_time, u8 *leddc_off_time) +{ + char buf[100]; + char key[40]; + int err; + u32 val; + + create_key(prefix, NULL, name, key, sizeof(key)); + + err = nvram_getenv(key, buf, sizeof(buf)); + if (err < 0) + return; + err = kstrtou32(buf, 0, &val); + if (err) { + pr_warn("can not parse nvram name %s with value %s got %i", + key, buf, err); + return; + } + + if (val == 0xffff || val == 0xffffffff) + return; + + *leddc_on_time = val & 0xff; + *leddc_off_time = (val >> 16) & 0xff; +} + +static void nvram_read_macaddr(const char *prefix, const char *name, + u8 (*val)[6]) +{ + char buf[100]; + char key[40]; + int err; + + create_key(prefix, NULL, name, key, sizeof(key)); + + err = nvram_getenv(key, buf, sizeof(buf)); + if (err < 0) + return; + nvram_parse_macaddr(buf, *val); +} + +static void nvram_read_alpha2(const char *prefix, const char *name, + char (*val)[2]) +{ + char buf[10]; + char key[40]; + int err; + + create_key(prefix, NULL, name, key, sizeof(key)); + + err = nvram_getenv(key, buf, sizeof(buf)); + if (err < 0) + return; + if (buf[0] == '0') + return; + if (strlen(buf) > 2) { + pr_warn("alpha2 is too long %s", buf); + return; + } + memcpy(val, buf, sizeof(val)); +} + +static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom, + const char *prefix) +{ + nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0); + nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0); + nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff); + nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff); + nvram_read_u8(prefix, NULL, "ledbh2", &sprom->gpio2, 0xff); + nvram_read_u8(prefix, NULL, "ledbh3", &sprom->gpio3, 0xff); + nvram_read_u8(prefix, NULL, "aa2g", &sprom->ant_available_bg, 0); + nvram_read_u8(prefix, NULL, "aa5g", &sprom->ant_available_a, 0); + nvram_read_s8(prefix, NULL, "ag0", &sprom->antenna_gain.a0, 0); + nvram_read_s8(prefix, NULL, "ag1", &sprom->antenna_gain.a1, 0); + nvram_read_alpha2(prefix, "ccode", &sprom->alpha2); +} + +static void bcm47xx_fill_sprom_r12389(struct ssb_sprom *sprom, + const char *prefix) +{ + nvram_read_u16(prefix, NULL, "pa0b0", &sprom->pa0b0, 0); + nvram_read_u16(prefix, NULL, "pa0b1", &sprom->pa0b1, 0); + nvram_read_u16(prefix, NULL, "pa0b2", &sprom->pa0b2, 0); + nvram_read_u8(prefix, NULL, "pa0itssit", &sprom->itssi_bg, 0); + nvram_read_u8(prefix, NULL, "pa0maxpwr", &sprom->maxpwr_bg, 0); + nvram_read_u16(prefix, NULL, "pa1b0", &sprom->pa1b0, 0); + nvram_read_u16(prefix, NULL, "pa1b1", &sprom->pa1b1, 0); + nvram_read_u16(prefix, NULL, "pa1b2", &sprom->pa1b2, 0); + nvram_read_u8(prefix, NULL, "pa1itssit", &sprom->itssi_a, 0); + nvram_read_u8(prefix, NULL, "pa1maxpwr", &sprom->maxpwr_a, 0); +} + +static void bcm47xx_fill_sprom_r1(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u16(prefix, NULL, "boardflags", &sprom->boardflags_lo, 0); + nvram_read_u8(prefix, NULL, "cc", &sprom->country_code, 0); +} + +static void bcm47xx_fill_sprom_r2389(struct ssb_sprom *sprom, + const char *prefix) +{ + nvram_read_u8(prefix, NULL, "opo", &sprom->opo, 0); + nvram_read_u16(prefix, NULL, "pa1lob0", &sprom->pa1lob0, 0); + nvram_read_u16(prefix, NULL, "pa1lob1", &sprom->pa1lob1, 0); + nvram_read_u16(prefix, NULL, "pa1lob2", &sprom->pa1lob2, 0); + nvram_read_u16(prefix, NULL, "pa1hib0", &sprom->pa1hib0, 0); + nvram_read_u16(prefix, NULL, "pa1hib1", &sprom->pa1hib1, 0); + nvram_read_u16(prefix, NULL, "pa1hib2", &sprom->pa1hib2, 0); + nvram_read_u8(prefix, NULL, "pa1lomaxpwr", &sprom->maxpwr_al, 0); + nvram_read_u8(prefix, NULL, "pa1himaxpwr", &sprom->maxpwr_ah, 0); +} + +static void bcm47xx_fill_sprom_r2(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, + &sprom->boardflags_hi); + nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0); +} + +static void bcm47xx_fill_sprom_r389(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u8(prefix, NULL, "bxa2g", &sprom->bxa2g, 0); + nvram_read_u8(prefix, NULL, "rssisav2g", &sprom->rssisav2g, 0); + nvram_read_u8(prefix, NULL, "rssismc2g", &sprom->rssismc2g, 0); + nvram_read_u8(prefix, NULL, "rssismf2g", &sprom->rssismf2g, 0); + nvram_read_u8(prefix, NULL, "bxa5g", &sprom->bxa5g, 0); + nvram_read_u8(prefix, NULL, "rssisav5g", &sprom->rssisav5g, 0); + nvram_read_u8(prefix, NULL, "rssismc5g", &sprom->rssismc5g, 0); + nvram_read_u8(prefix, NULL, "rssismf5g", &sprom->rssismf5g, 0); + nvram_read_u8(prefix, NULL, "tri2g", &sprom->tri2g, 0); + nvram_read_u8(prefix, NULL, "tri5g", &sprom->tri5g, 0); + nvram_read_u8(prefix, NULL, "tri5gl", &sprom->tri5gl, 0); + nvram_read_u8(prefix, NULL, "tri5gh", &sprom->tri5gh, 0); + nvram_read_s8(prefix, NULL, "rxpo2g", &sprom->rxpo2g, 0); + nvram_read_s8(prefix, NULL, "rxpo5g", &sprom->rxpo5g, 0); +} + +static void bcm47xx_fill_sprom_r3(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, + &sprom->boardflags_hi); + nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0); + nvram_read_u8(prefix, NULL, "regrev", &sprom->regrev, 0); + nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time, + &sprom->leddc_off_time); +} + +static void bcm47xx_fill_sprom_r4589(struct ssb_sprom *sprom, + const char *prefix) +{ + nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo, + &sprom->boardflags_hi); + nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo, + &sprom->boardflags2_hi); + nvram_read_u16(prefix, NULL, "boardtype", &sprom->board_type, 0); + nvram_read_u8(prefix, NULL, "regrev", &sprom->regrev, 0); + nvram_read_s8(prefix, NULL, "ag2", &sprom->antenna_gain.a2, 0); + nvram_read_s8(prefix, NULL, "ag3", &sprom->antenna_gain.a3, 0); + nvram_read_u8(prefix, NULL, "txchain", &sprom->txchain, 0xf); + nvram_read_u8(prefix, NULL, "rxchain", &sprom->rxchain, 0xf); + nvram_read_u8(prefix, NULL, "antswitch", &sprom->antswitch, 0xff); + nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time, + &sprom->leddc_off_time); +} + +static void bcm47xx_fill_sprom_r458(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u16(prefix, NULL, "cck2gpo", &sprom->cck2gpo, 0); + nvram_read_u32(prefix, NULL, "ofdm2gpo", &sprom->ofdm2gpo, 0); + nvram_read_u32(prefix, NULL, "ofdm5gpo", &sprom->ofdm5gpo, 0); + nvram_read_u32(prefix, NULL, "ofdm5glpo", &sprom->ofdm5glpo, 0); + nvram_read_u32(prefix, NULL, "ofdm5ghpo", &sprom->ofdm5ghpo, 0); + nvram_read_u16(prefix, NULL, "cddpo", &sprom->cddpo, 0); + nvram_read_u16(prefix, NULL, "stbcpo", &sprom->stbcpo, 0); + nvram_read_u16(prefix, NULL, "bw40po", &sprom->bw40po, 0); + nvram_read_u16(prefix, NULL, "bwduppo", &sprom->bwduppo, 0); + nvram_read_u16(prefix, NULL, "mcs2gpo0", &sprom->mcs2gpo[0], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo1", &sprom->mcs2gpo[1], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo2", &sprom->mcs2gpo[2], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo3", &sprom->mcs2gpo[3], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo4", &sprom->mcs2gpo[4], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo5", &sprom->mcs2gpo[5], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo6", &sprom->mcs2gpo[6], 0); + nvram_read_u16(prefix, NULL, "mcs2gpo7", &sprom->mcs2gpo[7], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo0", &sprom->mcs5gpo[0], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo1", &sprom->mcs5gpo[1], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo2", &sprom->mcs5gpo[2], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo3", &sprom->mcs5gpo[3], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo4", &sprom->mcs5gpo[4], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo5", &sprom->mcs5gpo[5], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo6", &sprom->mcs5gpo[6], 0); + nvram_read_u16(prefix, NULL, "mcs5gpo7", &sprom->mcs5gpo[7], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo0", &sprom->mcs5glpo[0], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo1", &sprom->mcs5glpo[1], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo2", &sprom->mcs5glpo[2], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo3", &sprom->mcs5glpo[3], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo4", &sprom->mcs5glpo[4], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo5", &sprom->mcs5glpo[5], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo6", &sprom->mcs5glpo[6], 0); + nvram_read_u16(prefix, NULL, "mcs5glpo7", &sprom->mcs5glpo[7], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo0", &sprom->mcs5ghpo[0], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo1", &sprom->mcs5ghpo[1], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo2", &sprom->mcs5ghpo[2], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo3", &sprom->mcs5ghpo[3], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo4", &sprom->mcs5ghpo[4], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo5", &sprom->mcs5ghpo[5], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo6", &sprom->mcs5ghpo[6], 0); + nvram_read_u16(prefix, NULL, "mcs5ghpo7", &sprom->mcs5ghpo[7], 0); +} + +static void bcm47xx_fill_sprom_r45(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u8(prefix, NULL, "txpid2ga0", &sprom->txpid2g[0], 0); + nvram_read_u8(prefix, NULL, "txpid2ga1", &sprom->txpid2g[1], 0); + nvram_read_u8(prefix, NULL, "txpid2ga2", &sprom->txpid2g[2], 0); + nvram_read_u8(prefix, NULL, "txpid2ga3", &sprom->txpid2g[3], 0); + nvram_read_u8(prefix, NULL, "txpid5ga0", &sprom->txpid5g[0], 0); + nvram_read_u8(prefix, NULL, "txpid5ga1", &sprom->txpid5g[1], 0); + nvram_read_u8(prefix, NULL, "txpid5ga2", &sprom->txpid5g[2], 0); + nvram_read_u8(prefix, NULL, "txpid5ga3", &sprom->txpid5g[3], 0); + nvram_read_u8(prefix, NULL, "txpid5gla0", &sprom->txpid5gl[0], 0); + nvram_read_u8(prefix, NULL, "txpid5gla1", &sprom->txpid5gl[1], 0); + nvram_read_u8(prefix, NULL, "txpid5gla2", &sprom->txpid5gl[2], 0); + nvram_read_u8(prefix, NULL, "txpid5gla3", &sprom->txpid5gl[3], 0); + nvram_read_u8(prefix, NULL, "txpid5gha0", &sprom->txpid5gh[0], 0); + nvram_read_u8(prefix, NULL, "txpid5gha1", &sprom->txpid5gh[1], 0); + nvram_read_u8(prefix, NULL, "txpid5gha2", &sprom->txpid5gh[2], 0); + nvram_read_u8(prefix, NULL, "txpid5gha3", &sprom->txpid5gh[3], 0); +} + +static void bcm47xx_fill_sprom_r89(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u8(prefix, NULL, "tssipos2g", &sprom->fem.ghz2.tssipos, 0); + nvram_read_u8(prefix, NULL, "extpagain2g", + &sprom->fem.ghz2.extpa_gain, 0); + nvram_read_u8(prefix, NULL, "pdetrange2g", + &sprom->fem.ghz2.pdet_range, 0); + nvram_read_u8(prefix, NULL, "triso2g", &sprom->fem.ghz2.tr_iso, 0); + nvram_read_u8(prefix, NULL, "antswctl2g", &sprom->fem.ghz2.antswlut, 0); + nvram_read_u8(prefix, NULL, "tssipos5g", &sprom->fem.ghz5.tssipos, 0); + nvram_read_u8(prefix, NULL, "extpagain5g", + &sprom->fem.ghz5.extpa_gain, 0); + nvram_read_u8(prefix, NULL, "pdetrange5g", + &sprom->fem.ghz5.pdet_range, 0); + nvram_read_u8(prefix, NULL, "triso5g", &sprom->fem.ghz5.tr_iso, 0); + nvram_read_u8(prefix, NULL, "antswctl5g", &sprom->fem.ghz5.antswlut, 0); + nvram_read_u8(prefix, NULL, "tempthresh", &sprom->tempthresh, 0); + nvram_read_u8(prefix, NULL, "tempoffset", &sprom->tempoffset, 0); + nvram_read_u16(prefix, NULL, "rawtempsense", &sprom->rawtempsense, 0); + nvram_read_u8(prefix, NULL, "measpower", &sprom->measpower, 0); + nvram_read_u8(prefix, NULL, "tempsense_slope", + &sprom->tempsense_slope, 0); + nvram_read_u8(prefix, NULL, "tempcorrx", &sprom->tempcorrx, 0); + nvram_read_u8(prefix, NULL, "tempsense_option", + &sprom->tempsense_option, 0); + nvram_read_u8(prefix, NULL, "freqoffset_corr", + &sprom->freqoffset_corr, 0); + nvram_read_u8(prefix, NULL, "iqcal_swp_dis", &sprom->iqcal_swp_dis, 0); + nvram_read_u8(prefix, NULL, "hw_iqcal_en", &sprom->hw_iqcal_en, 0); + nvram_read_u8(prefix, NULL, "elna2g", &sprom->elna2g, 0); + nvram_read_u8(prefix, NULL, "elna5g", &sprom->elna5g, 0); + nvram_read_u8(prefix, NULL, "phycal_tempdelta", + &sprom->phycal_tempdelta, 0); + nvram_read_u8(prefix, NULL, "temps_period", &sprom->temps_period, 0); + nvram_read_u8(prefix, NULL, "temps_hysteresis", + &sprom->temps_hysteresis, 0); + nvram_read_u8(prefix, NULL, "measpower1", &sprom->measpower1, 0); + nvram_read_u8(prefix, NULL, "measpower2", &sprom->measpower2, 0); + nvram_read_u8(prefix, NULL, "rxgainerr2ga0", + &sprom->rxgainerr2ga[0], 0); + nvram_read_u8(prefix, NULL, "rxgainerr2ga1", + &sprom->rxgainerr2ga[1], 0); + nvram_read_u8(prefix, NULL, "rxgainerr2ga2", + &sprom->rxgainerr2ga[2], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gla0", + &sprom->rxgainerr5gla[0], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gla1", + &sprom->rxgainerr5gla[1], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gla2", + &sprom->rxgainerr5gla[2], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gma0", + &sprom->rxgainerr5gma[0], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gma1", + &sprom->rxgainerr5gma[1], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gma2", + &sprom->rxgainerr5gma[2], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gha0", + &sprom->rxgainerr5gha[0], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gha1", + &sprom->rxgainerr5gha[1], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gha2", + &sprom->rxgainerr5gha[2], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gua0", + &sprom->rxgainerr5gua[0], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gua1", + &sprom->rxgainerr5gua[1], 0); + nvram_read_u8(prefix, NULL, "rxgainerr5gua2", + &sprom->rxgainerr5gua[2], 0); + nvram_read_u8(prefix, NULL, "noiselvl2ga0", &sprom->noiselvl2ga[0], 0); + nvram_read_u8(prefix, NULL, "noiselvl2ga1", &sprom->noiselvl2ga[1], 0); + nvram_read_u8(prefix, NULL, "noiselvl2ga2", &sprom->noiselvl2ga[2], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gla0", + &sprom->noiselvl5gla[0], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gla1", + &sprom->noiselvl5gla[1], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gla2", + &sprom->noiselvl5gla[2], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gma0", + &sprom->noiselvl5gma[0], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gma1", + &sprom->noiselvl5gma[1], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gma2", + &sprom->noiselvl5gma[2], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gha0", + &sprom->noiselvl5gha[0], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gha1", + &sprom->noiselvl5gha[1], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gha2", + &sprom->noiselvl5gha[2], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gua0", + &sprom->noiselvl5gua[0], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gua1", + &sprom->noiselvl5gua[1], 0); + nvram_read_u8(prefix, NULL, "noiselvl5gua2", + &sprom->noiselvl5gua[2], 0); + nvram_read_u8(prefix, NULL, "pcieingress_war", + &sprom->pcieingress_war, 0); +} + +static void bcm47xx_fill_sprom_r9(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_u16(prefix, NULL, "cckbw202gpo", &sprom->cckbw202gpo, 0); + nvram_read_u16(prefix, NULL, "cckbw20ul2gpo", &sprom->cckbw20ul2gpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw202gpo", + &sprom->legofdmbw202gpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw20ul2gpo", + &sprom->legofdmbw20ul2gpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw205glpo", + &sprom->legofdmbw205glpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw20ul5glpo", + &sprom->legofdmbw20ul5glpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw205gmpo", + &sprom->legofdmbw205gmpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw20ul5gmpo", + &sprom->legofdmbw20ul5gmpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw205ghpo", + &sprom->legofdmbw205ghpo, 0); + nvram_read_u32(prefix, NULL, "legofdmbw20ul5ghpo", + &sprom->legofdmbw20ul5ghpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw202gpo", &sprom->mcsbw202gpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw20ul2gpo", &sprom->mcsbw20ul2gpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw402gpo", &sprom->mcsbw402gpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw205glpo", &sprom->mcsbw205glpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw20ul5glpo", + &sprom->mcsbw20ul5glpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw405glpo", &sprom->mcsbw405glpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw205gmpo", &sprom->mcsbw205gmpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw20ul5gmpo", + &sprom->mcsbw20ul5gmpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw405gmpo", &sprom->mcsbw405gmpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw205ghpo", &sprom->mcsbw205ghpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw20ul5ghpo", + &sprom->mcsbw20ul5ghpo, 0); + nvram_read_u32(prefix, NULL, "mcsbw405ghpo", &sprom->mcsbw405ghpo, 0); + nvram_read_u16(prefix, NULL, "mcs32po", &sprom->mcs32po, 0); + nvram_read_u16(prefix, NULL, "legofdm40duppo", + &sprom->legofdm40duppo, 0); + nvram_read_u8(prefix, NULL, "sar2g", &sprom->sar2g, 0); + nvram_read_u8(prefix, NULL, "sar5g", &sprom->sar5g, 0); +} + +static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom, + const char *prefix) +{ + char postfix[2]; + int i; + + for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { + struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i]; + snprintf(postfix, sizeof(postfix), "%i", i); + nvram_read_u8(prefix, postfix, "maxp2ga", + &pwr_info->maxpwr_2g, 0); + nvram_read_u8(prefix, postfix, "itt2ga", + &pwr_info->itssi_2g, 0); + nvram_read_u8(prefix, postfix, "itt5ga", + &pwr_info->itssi_5g, 0); + nvram_read_u16(prefix, postfix, "pa2gw0a", + &pwr_info->pa_2g[0], 0); + nvram_read_u16(prefix, postfix, "pa2gw1a", + &pwr_info->pa_2g[1], 0); + nvram_read_u16(prefix, postfix, "pa2gw2a", + &pwr_info->pa_2g[2], 0); + nvram_read_u8(prefix, postfix, "maxp5ga", + &pwr_info->maxpwr_5g, 0); + nvram_read_u8(prefix, postfix, "maxp5gha", + &pwr_info->maxpwr_5gh, 0); + nvram_read_u8(prefix, postfix, "maxp5gla", + &pwr_info->maxpwr_5gl, 0); + nvram_read_u16(prefix, postfix, "pa5gw0a", + &pwr_info->pa_5g[0], 0); + nvram_read_u16(prefix, postfix, "pa5gw1a", + &pwr_info->pa_5g[1], 0); + nvram_read_u16(prefix, postfix, "pa5gw2a", + &pwr_info->pa_5g[2], 0); + nvram_read_u16(prefix, postfix, "pa5glw0a", + &pwr_info->pa_5gl[0], 0); + nvram_read_u16(prefix, postfix, "pa5glw1a", + &pwr_info->pa_5gl[1], 0); + nvram_read_u16(prefix, postfix, "pa5glw2a", + &pwr_info->pa_5gl[2], 0); + nvram_read_u16(prefix, postfix, "pa5ghw0a", + &pwr_info->pa_5gh[0], 0); + nvram_read_u16(prefix, postfix, "pa5ghw1a", + &pwr_info->pa_5gh[1], 0); + nvram_read_u16(prefix, postfix, "pa5ghw2a", + &pwr_info->pa_5gh[2], 0); + } +} + +static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom, + const char *prefix) +{ + char postfix[2]; + int i; + + for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) { + struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i]; + snprintf(postfix, sizeof(postfix), "%i", i); + nvram_read_u16(prefix, postfix, "pa2gw3a", + &pwr_info->pa_2g[3], 0); + nvram_read_u16(prefix, postfix, "pa5gw3a", + &pwr_info->pa_5g[3], 0); + nvram_read_u16(prefix, postfix, "pa5glw3a", + &pwr_info->pa_5gl[3], 0); + nvram_read_u16(prefix, postfix, "pa5ghw3a", + &pwr_info->pa_5gh[3], 0); + } +} + +void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix) +{ + nvram_read_macaddr(prefix, "et0macaddr", &sprom->et0mac); + nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0); + nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0); + + nvram_read_macaddr(prefix, "et1macaddr", &sprom->et1mac); + nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0); + nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0); + + nvram_read_macaddr(prefix, "macaddr", &sprom->il0mac); + nvram_read_macaddr(prefix, "il0macaddr", &sprom->il0mac); +} + +void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) +{ + memset(sprom, 0, sizeof(struct ssb_sprom)); + + bcm47xx_fill_sprom_ethernet(sprom, prefix); + + nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0); + + switch (sprom->revision) { + case 1: + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r12389(sprom, prefix); + bcm47xx_fill_sprom_r1(sprom, prefix); + break; + case 2: + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r12389(sprom, prefix); + bcm47xx_fill_sprom_r2389(sprom, prefix); + bcm47xx_fill_sprom_r2(sprom, prefix); + break; + case 3: + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r12389(sprom, prefix); + bcm47xx_fill_sprom_r2389(sprom, prefix); + bcm47xx_fill_sprom_r389(sprom, prefix); + bcm47xx_fill_sprom_r3(sprom, prefix); + break; + case 4: + case 5: + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r4589(sprom, prefix); + bcm47xx_fill_sprom_r458(sprom, prefix); + bcm47xx_fill_sprom_r45(sprom, prefix); + bcm47xx_fill_sprom_path_r4589(sprom, prefix); + bcm47xx_fill_sprom_path_r45(sprom, prefix); + break; + case 8: + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r12389(sprom, prefix); + bcm47xx_fill_sprom_r2389(sprom, prefix); + bcm47xx_fill_sprom_r389(sprom, prefix); + bcm47xx_fill_sprom_r4589(sprom, prefix); + bcm47xx_fill_sprom_r458(sprom, prefix); + bcm47xx_fill_sprom_r89(sprom, prefix); + bcm47xx_fill_sprom_path_r4589(sprom, prefix); + break; + case 9: + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r12389(sprom, prefix); + bcm47xx_fill_sprom_r2389(sprom, prefix); + bcm47xx_fill_sprom_r389(sprom, prefix); + bcm47xx_fill_sprom_r4589(sprom, prefix); + bcm47xx_fill_sprom_r89(sprom, prefix); + bcm47xx_fill_sprom_r9(sprom, prefix); + bcm47xx_fill_sprom_path_r4589(sprom, prefix); + break; + default: + pr_warn("Unsupported SPROM revision %d detected. Will extract" + " v1\n", sprom->revision); + sprom->revision = 1; + bcm47xx_fill_sprom_r1234589(sprom, prefix); + bcm47xx_fill_sprom_r12389(sprom, prefix); + bcm47xx_fill_sprom_r1(sprom, prefix); + } +} diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index d209f85d87bb..356b05583e14 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -33,7 +33,7 @@ static void bcm6348_a1_reboot(void) u32 reg; /* soft reset all blocks */ - printk(KERN_INFO "soft-reseting all blocks ...\n"); + printk(KERN_INFO "soft-resetting all blocks ...\n"); reg = bcm_perf_readl(PERF_SOFTRESET_REG); reg &= ~SOFTRESET_6348_ALL; bcm_perf_writel(reg, PERF_SOFTRESET_REG); diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 77e644082a3b..2d91888c9b74 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -47,7 +47,7 @@ extern void kunmap_high(struct page *page); extern void *kmap(struct page *page); extern void kunmap(struct page *page); -extern void *__kmap_atomic(struct page *page); +extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 2354c870a63a..fb698dc09bc9 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -11,15 +11,12 @@ #include <linux/linkage.h> #include <linux/smp.h> +#include <linux/irqdomain.h> #include <asm/mipsmtregs.h> #include <irq.h> -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - #ifdef CONFIG_I8259 static inline int irq_canonicalize(int irq) { diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h index de95e0723e2b..5ecaf47b34d2 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h @@ -44,4 +44,7 @@ union bcm47xx_bus { extern union bcm47xx_bus bcm47xx_bus; extern enum bcm47xx_bus_type bcm47xx_bus_type; +void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix); +void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix); + #endif /* __ASM_BCM47XX_H */ diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h index 184d5ecb5f51..69ef3efe06e7 100644 --- a/arch/mips/include/asm/mach-bcm47xx/nvram.h +++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h @@ -37,7 +37,7 @@ struct nvram_header { extern int nvram_getenv(char *name, char *val, size_t val_len); -static inline void nvram_parse_macaddr(char *buf, u8 *macaddr) +static inline void nvram_parse_macaddr(char *buf, u8 macaddr[6]) { if (strchr(buf, ':')) sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index ad5c0a7a02a7..a2ed6fdad4e0 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -84,6 +84,10 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #ifdef __KERNEL__ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 639e3ce6c264..9a91fe9de696 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -418,6 +418,11 @@ static struct platform_device qi_lb60_charger_device = { }, }; +/* audio */ +static struct platform_device qi_lb60_audio_device = { + .name = "qi-lb60-audio", + .id = -1, +}; static struct platform_device *jz_platform_devices[] __initdata = { &jz4740_udc_device, @@ -434,6 +439,7 @@ static struct platform_device *jz_platform_devices[] __initdata = { &qi_lb60_gpio_keys, &qi_lb60_pwm_beeper, &qi_lb60_charger_device, + &qi_lb60_audio_device, }; static void __init board_gpio_setup(void) diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 6b8b4208481e..558b5395795d 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start, } #endif -/* - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# - * - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are - * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not - * supported. - */ -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - void __init early_init_devtree(void *params) { /* Setup flat device-tree pointer */ diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 4f9eb0b23036..c97087d12d07 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -498,7 +498,7 @@ static inline void local_r4k_flush_cache_page(void *args) if (map_coherent) vaddr = kmap_coherent(page, addr); else - vaddr = kmap_atomic(page, KM_USER0); + vaddr = kmap_atomic(page); addr = (unsigned long)vaddr; } @@ -521,7 +521,7 @@ static inline void local_r4k_flush_cache_page(void *args) if (map_coherent) kunmap_coherent(); else - kunmap_atomic(vaddr, KM_USER0); + kunmap_atomic(vaddr); } } diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 3634c7ea06ac..aff57057a949 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -41,7 +41,7 @@ EXPORT_SYMBOL(kunmap); * kmaps are appropriate for short, tight code paths only. */ -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned long vaddr; int idx, type; @@ -62,7 +62,7 @@ void *__kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 3b3ffd439cd7..1a85ba92eb5c 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -207,21 +207,21 @@ void copy_user_highpage(struct page *to, struct page *from, { void *vfrom, *vto; - vto = kmap_atomic(to, KM_USER1); + vto = kmap_atomic(to); if (cpu_has_dc_aliases && page_mapped(from) && !Page_dcache_dirty(from)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); kunmap_coherent(); } else { - vfrom = kmap_atomic(from, KM_USER0); + vfrom = kmap_atomic(from); copy_page(vto, vfrom); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); } if ((!cpu_has_ic_fills_f_dc) || pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) flush_data_cache_page((unsigned long)vto); - kunmap_atomic(vto, KM_USER1); + kunmap_atomic(vto); /* Make sure this page is cleared on other CPU's too before using it */ smp_wmb(); } diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c index 400535a955d0..c682468010c5 100644 --- a/arch/mips/pci/pci-bcm47xx.c +++ b/arch/mips/pci/pci-bcm47xx.c @@ -25,6 +25,7 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/ssb/ssb.h> +#include <linux/bcma/bcma.h> #include <bcm47xx.h> int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) @@ -32,15 +33,12 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return 0; } -int pcibios_plat_dev_init(struct pci_dev *dev) -{ #ifdef CONFIG_BCM47XX_SSB +static int bcm47xx_pcibios_plat_dev_init_ssb(struct pci_dev *dev) +{ int res; u8 slot, pin; - if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB) - return 0; - res = ssb_pcibios_plat_dev_init(dev); if (res < 0) { printk(KERN_ALERT "PCI: Failed to init device %s\n", @@ -60,6 +58,47 @@ int pcibios_plat_dev_init(struct pci_dev *dev) } dev->irq = res; + return 0; +} #endif + +#ifdef CONFIG_BCM47XX_BCMA +static int bcm47xx_pcibios_plat_dev_init_bcma(struct pci_dev *dev) +{ + int res; + + res = bcma_core_pci_plat_dev_init(dev); + if (res < 0) { + printk(KERN_ALERT "PCI: Failed to init device %s\n", + pci_name(dev)); + return res; + } + + res = bcma_core_pci_pcibios_map_irq(dev); + + /* IRQ-0 and IRQ-1 are software interrupts. */ + if (res < 2) { + printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n", + pci_name(dev)); + return res; + } + + dev->irq = res; return 0; } +#endif + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +#ifdef CONFIG_BCM47XX_SSB + if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_SSB) + return bcm47xx_pcibios_plat_dev_init_ssb(dev); + else +#endif +#ifdef CONFIG_BCM47XX_BCMA + if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) + return bcm47xx_pcibios_plat_dev_init_bcma(dev); + else +#endif + return 0; +} diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h index bfe2d88604d9..7c137cd8aa37 100644 --- a/arch/mn10300/include/asm/highmem.h +++ b/arch/mn10300/include/asm/highmem.h @@ -70,7 +70,7 @@ static inline void kunmap(struct page *page) * be used in IRQ contexts, so in some (very limited) cases we need * it. */ -static inline unsigned long __kmap_atomic(struct page *page) +static inline unsigned long kmap_atomic(struct page *page) { unsigned long vaddr; int idx, type; diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 876356d78522..820463a484b8 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -64,5 +64,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h index e1f3fe26606c..bbb34e5343a2 100644 --- a/arch/openrisc/include/asm/prom.h +++ b/arch/openrisc/include/asm/prom.h @@ -24,6 +24,7 @@ #include <linux/types.h> #include <asm/irq.h> +#include <linux/irqdomain.h> #include <linux/atomic.h> #include <linux/of_irq.h> #include <linux/of_fdt.h> @@ -63,15 +64,6 @@ extern const void *of_get_mac_address(struct device_node *np); struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -/* This routine is here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes. We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_OPENRISC_PROM_H */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index da601dd34c05..9f21ab0c02e3 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -140,7 +140,7 @@ static inline void *kmap(struct page *page) #define kunmap(page) kunmap_parisc(page_address(page)) -static inline void *__kmap_atomic(struct page *page) +static inline void *kmap_atomic(struct page *page) { pagefault_disable(); return page_address(page); diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index d28c51b61067..1b52c2c31a7a 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -63,6 +63,11 @@ #define SO_WIFI_STATUS 0x4022 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 0x4023 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 0x4024 + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1919634a9b32..d219ebecabf0 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -134,7 +134,9 @@ config PPC select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQ + select SPARSE_IRQ select IRQ_PER_CPU + select IRQ_DOMAIN select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL select IRQ_FORCED_THREADING @@ -376,13 +378,16 @@ config CRASH_DUMP The same kernel binary can be used as production kernel and dump capture kernel. -config PHYP_DUMP - bool "Hypervisor-assisted dump (EXPERIMENTAL)" - depends on PPC_PSERIES && EXPERIMENTAL +config FA_DUMP + bool "Firmware-assisted dump" + depends on PPC64 && PPC_RTAS && CRASH_DUMP help - Hypervisor-assisted dump is meant to be a kdump replacement - offering robustness and speed not possible without system - hypervisor assistance. + A robust mechanism to get reliable kernel crash dump with + assistance from firmware. This approach does not use kexec, + instead firmware assists in booting the kdump kernel + while preserving memory contents. Firmware-assisted dump + is meant to be a kdump replacement offering robustness and + speed not possible without system firmware assistance. If unsure, say "N" @@ -611,7 +616,7 @@ endmenu config ISA_DMA_API bool - default !PPC_ISERIES || PCI + default PCI menu "Bus options" diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 4ccb2a009f74..72d55dbc6119 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -196,13 +196,6 @@ config PPC_EARLY_DEBUG_MAPLE help Select this to enable early debugging for Maple. -config PPC_EARLY_DEBUG_ISERIES - bool "iSeries HV Console" - depends on PPC_ISERIES - help - Select this to enable early debugging for legacy iSeries. You need - to hit "Ctrl-x Ctrl-x" to see the messages on the console. - config PPC_EARLY_DEBUG_PAS_REALMODE bool "PA Semi real mode" depends on PPC_PASEMI diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index b8b105c01c64..6524c6e21896 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -157,6 +157,7 @@ core-y += arch/powerpc/kernel/ \ arch/powerpc/net/ core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_KVM) += arch/powerpc/kvm/ +core-$(CONFIG_PERF_EVENTS) += arch/powerpc/perf/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 8844a17ce8ed..e8461cb18d04 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -184,7 +184,6 @@ image-$(CONFIG_PPC_EFIKA) += zImage.chrp image-$(CONFIG_PPC_PMAC) += zImage.pmac image-$(CONFIG_PPC_HOLLY) += dtbImage.holly image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800 -image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage image-$(CONFIG_EPAPR_BOOT) += zImage.epapr @@ -247,7 +246,7 @@ image-$(CONFIG_ASP834x) += dtbImage.asp834x-redboot image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \ - cuImage.mpc8548cds \ + cuImage.mpc8548cds_32b \ cuImage.mpc8555cds image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \ @@ -311,12 +310,6 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb $(obj)/vmlinux.strip: vmlinux $(STRIP) -s -R .comment $< -o $@ -# The iseries hypervisor won't take an ET_DYN executable, so this -# changes the type (byte 17) in the file to ET_EXEC (2). -$(obj)/zImage.iseries: vmlinux - $(STRIP) -s -R .comment $< -o $@ - printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17 - $(obj)/uImage: vmlinux $(wrapperbits) $(call if_changed,wrap,uboot) @@ -364,7 +357,7 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) # anything not in $(targets) clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ - zImage.iseries zImage.miboot zImage.pmac zImage.pseries \ + zImage.miboot zImage.pmac zImage.pseries \ zImage.maple simpleImage.* otheros.bld *.dtb # clean up files cached by wrapper diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts new file mode 100644 index 000000000000..fabe7b7d5f13 --- /dev/null +++ b/arch/powerpc/boot/dts/a4m072.dts @@ -0,0 +1,168 @@ +/* + * a4m072 board Device Tree Source + * + * Copyright (C) 2011 DENX Software Engineering GmbH + * Heiko Schocher <hs@denx.de> + * + * Copyright (C) 2007 Semihalf + * Marian Balakowicz <m8@semihalf.com> + * + * 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. + */ + +/include/ "mpc5200b.dtsi" + +/ { + model = "anonymous,a4m072"; + compatible = "anonymous,a4m072"; + + soc5200@f0000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc5200b-immr"; + ranges = <0 0xf0000000 0x0000c000>; + reg = <0xf0000000 0x00000100>; + bus-frequency = <0>; /* From boot loader */ + system-frequency = <0>; /* From boot loader */ + + cdm@200 { + fsl,init-ext-48mhz-en = <0x0>; + fsl,init-fd-enable = <0x01>; + fsl,init-fd-counters = <0x3333>; + }; + + timer@600 { + fsl,has-wdt; + }; + + gpt3: timer@630 { /* General Purpose Timer in GPIO mode */ + compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpt4: timer@640 { /* General Purpose Timer in GPIO mode */ + compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpt5: timer@650 { /* General Purpose Timer in GPIO mode */ + compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + spi@f00 { + status = "disabled"; + }; + + psc@2000 { + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + reg = <0x2000 0x100>; + interrupts = <2 1 0>; + }; + + psc@2200 { + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + reg = <0x2200 0x100>; + interrupts = <2 2 0>; + }; + + psc@2400 { + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + reg = <0x2400 0x100>; + interrupts = <2 3 0>; + }; + + psc@2600 { + status = "disabled"; + }; + + psc@2800 { + status = "disabled"; + }; + + psc@2c00 { + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + reg = <0x2c00 0x100>; + interrupts = <2 4 0>; + }; + + ethernet@3000 { + phy-handle = <&phy0>; + }; + + mdio@3000 { + phy0: ethernet-phy@1f { + reg = <0x1f>; + interrupts = <1 2 0>; /* IRQ 2 active low */ + }; + }; + + i2c@3d00 { + status = "disabled"; + }; + + i2c@3d40 { + hwmon@2e { + compatible = "nsc,lm87"; + reg = <0x2e>; + }; + rtc@51 { + compatible = "nxp,rtc8564"; + reg = <0x51>; + }; + }; + }; + + localbus { + compatible = "fsl,mpc5200b-lpb","simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0xfe000000 0x02000000 + 1 0 0x62000000 0x00400000 + 2 0 0x64000000 0x00200000 + 3 0 0x66000000 0x01000000 + 6 0 0x68000000 0x01000000 + 7 0 0x6a000000 0x00000004>; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x02000000>; + bank-width = <2>; + #size-cells = <1>; + #address-cells = <1>; + }; + sram0@1,0 { + compatible = "mtd-ram"; + reg = <1 0x00000 0x00400000>; + bank-width = <2>; + }; + }; + + pci@f0000d00 { + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + compatible = "fsl,mpc5200-pci"; + reg = <0xf0000d00 0x100>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x16 */ + 0xc000 0 0 1 &mpc5200_pic 1 3 3 + 0xc000 0 0 2 &mpc5200_pic 1 3 3 + 0xc000 0 0 3 &mpc5200_pic 1 3 3 + 0xc000 0 0 4 &mpc5200_pic 1 3 3>; + clock-frequency = <0>; /* From boot loader */ + interrupts = <2 8 0 2 9 0 2 10 0>; + bus-range = <0 0>; + ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000 + 0x02000000 0 0x90000000 0x90000000 0 0x10000000 + 0x01000000 0 0x00000000 0xa0000000 0 0x01000000>; + }; +}; diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts index 2a56a0dbd1f7..7bda373f10ef 100644 --- a/arch/powerpc/boot/dts/bluestone.dts +++ b/arch/powerpc/boot/dts/bluestone.dts @@ -33,7 +33,7 @@ aliases { ethernet0 = &EMAC0; serial0 = &UART0; - //serial1 = &UART1; --gcl missing UART1 label + serial1 = &UART1; }; cpus { @@ -52,7 +52,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; - //next-level-cache = <&L2C0>; --gcl missing L2C0 label + next-level-cache = <&L2C0>; }; }; @@ -117,6 +117,16 @@ dcr-reg = <0x00c 0x002>; }; + L2C0: l2c { + compatible = "ibm,l2-cache-apm82181", "ibm,l2-cache"; + dcr-reg = <0x020 0x008 + 0x030 0x008>; + cache-line-size = <32>; + cache-size = <262144>; + interrupt-parent = <&UIC1>; + interrupts = <11 1>; + }; + plb { compatible = "ibm,plb4"; #address-cells = <2>; @@ -182,6 +192,53 @@ reg = <0x001a0000 0x00060000>; }; }; + + ndfc@1,0 { + compatible = "ibm,ndfc"; + reg = <0x00000003 0x00000000 0x00002000>; + ccr = <0x00001000>; + bank-settings = <0x80002222>; + #address-cells = <1>; + #size-cells = <1>; + /* 2Gb Nand Flash */ + nand { + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "firmware"; + reg = <0x00000000 0x00C00000>; + }; + partition@c00000 { + label = "environment"; + reg = <0x00C00000 0x00B00000>; + }; + partition@1700000 { + label = "kernel"; + reg = <0x01700000 0x00E00000>; + }; + partition@2500000 { + label = "root"; + reg = <0x02500000 0x08200000>; + }; + partition@a700000 { + label = "device-tree"; + reg = <0x0A700000 0x00B00000>; + }; + partition@b200000 { + label = "config"; + reg = <0x0B200000 0x00D00000>; + }; + partition@bf00000 { + label = "diag"; + reg = <0x0BF00000 0x00C00000>; + }; + partition@cb00000 { + label = "vendor"; + reg = <0x0CB00000 0x3500000>; + }; + }; + }; }; UART0: serial@ef600300 { @@ -195,11 +252,36 @@ interrupts = <0x1 0x4>; }; + UART1: serial@ef600400 { + device_type = "serial"; + compatible = "ns16550"; + reg = <0xef600400 0x00000008>; + virtual-reg = <0xef600400>; + clock-frequency = <0>; /* Filled in by U-Boot */ + current-speed = <0>; /* Filled in by U-Boot */ + interrupt-parent = <&UIC0>; + interrupts = <0x1 0x4>; + }; + IIC0: i2c@ef600700 { compatible = "ibm,iic"; reg = <0xef600700 0x00000014>; interrupt-parent = <&UIC0>; interrupts = <0x2 0x4>; + #address-cells = <1>; + #size-cells = <0>; + rtc@68 { + compatible = "stm,m41t80"; + reg = <0x68>; + interrupt-parent = <&UIC0>; + interrupts = <0x9 0x8>; + }; + sttm@4C { + compatible = "adm,adm1032"; + reg = <0x4C>; + interrupt-parent = <&UIC1>; + interrupts = <0x1E 0x8>; /* CPU_THERNAL_L */ + }; }; IIC1: i2c@ef600800 { @@ -222,7 +304,7 @@ EMAC0: ethernet@ef600c00 { device_type = "network"; - compatible = "ibm,emac4sync"; + compatible = "ibm,emac-apm821xx", "ibm,emac4sync"; interrupt-parent = <&EMAC0>; interrupts = <0x0 0x1>; #interrupt-cells = <1>; @@ -250,5 +332,46 @@ }; }; + PCIE0: pciex@d00000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb-pciex-apm821xx", "ibm,plb-pciex"; + primary; + port = <0x0>; /* port number */ + reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */ + 0x0000000c 0x08010000 0x00001000>; /* Registers */ + dcr-reg = <0x100 0x020>; + sdr-base = <0x300>; + + /* Outbound ranges, one memory and one IO, + * later cannot be changed + */ + ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 + 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000 + 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; + + /* Inbound 2GB range starting at 0 */ + dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; + + /* This drives busses 40 to 0x7f */ + bus-range = <0x40 0x7f>; + + /* Legacy interrupts (note the weird polarity, the bridge seems + * to invert PCIe legacy interrupts). + * We are de-swizzling here because the numbers are actually for + * port of the root complex virtual P2P bridge. But I want + * to avoid putting a node for it in the tree, so the numbers + * below are basically de-swizzled numbers. + * The real slot is on idsel 0, so the swizzling is 1:1 + */ + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = < + 0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */ + 0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */ + 0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */ + 0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>; + }; }; }; diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi index b37da56018b6..c8b2daa40ac8 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi @@ -202,7 +202,7 @@ /include/ "pq3-etsec1-timer-0.dtsi" usb@22000 { - compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; + compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; reg = <0x22000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -210,7 +210,7 @@ }; usb@23000 { - compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; + compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; reg = <0x23000 0x1000>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi index 9d8023a69d7d..579d76cb8e32 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi @@ -89,6 +89,21 @@ }; }; +&rio { + compatible = "fsl,srio"; + interrupts = <48 2 0 0>; + #address-cells = <2>; + #size-cells = <2>; + fsl,srio-rmu-handle = <&rmu>; + ranges; + + port1 { + #address-cells = <2>; + #size-cells = <2>; + cell-index = <1>; + }; +}; + &soc { #address-cells = <1>; #size-cells = <1>; @@ -134,6 +149,7 @@ /include/ "pq3-sec2.1-0.dtsi" /include/ "pq3-mpic.dtsi" +/include/ "pq3-rmu-0.dtsi" global-utilities@e0000 { compatible = "fsl,mpc8548-guts"; diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi index 289f1218d755..720422d83529 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi @@ -43,7 +43,9 @@ serial0 = &serial0; serial1 = &serial1; ethernet0 = &enet0; - ethernet1 = &enet2; + ethernet1 = &enet1; + ethernet2 = &enet2; + ethernet3 = &enet3; pci0 = &pci0; pci1 = &pci1; pci2 = &pci2; diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi index a97d1263372c..0bde9ee8afaf 100644 --- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi @@ -156,6 +156,9 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" + usb@22000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-esdhc-0.dtsi" sdhc@2e000 { compatible = "fsl,p1010-esdhc", "fsl,esdhc"; diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi index 5de5fc351314..68cc5e7f6477 100644 --- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi @@ -142,7 +142,13 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" + usb@22000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-usb2-dr-1.dtsi" + usb@23000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-esdhc-0.dtsi" sdhc@2e000 { diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi index 38ba54d1e32e..4252ef85fb7a 100644 --- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi @@ -142,8 +142,15 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" + usb@22000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-esdhc-0.dtsi" + sdhc@2e000 { + sdhci,auto-cmd12; + }; + /include/ "pq3-sec3.3-0.dtsi" /include/ "pq3-mpic.dtsi" diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi index ff9ed1d87929..06216b8c0af5 100644 --- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi @@ -35,7 +35,11 @@ &lbc { #address-cells = <2>; #size-cells = <1>; - compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; + /* + * The localbus on the P1022 is not a simple-bus because of the eLBC + * pin muxing when the DIU is enabled. + */ + compatible = "fsl,p1022-elbc", "fsl,elbc"; interrupts = <19 2 0 0>; }; @@ -199,7 +203,13 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" + usb@22000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-usb2-dr-1.dtsi" + usb@23000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-esdhc-0.dtsi" sdhc@2e000 { diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi index b06bb4cc1fe8..941fa159cefb 100644 --- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi @@ -142,6 +142,9 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" + usb@22000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; crypto: crypto@300000 { compatible = "fsl,sec-v4.2", "fsl,sec-v4.0"; diff --git a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi index 332e9e75e6c2..884e01bcb243 100644 --- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi @@ -171,6 +171,9 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" + usb@22000 { + compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; + }; /include/ "pq3-etsec1-0.dtsi" /include/ "pq3-etsec1-timer-0.dtsi" diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi index 234a399ddeb2..531eab82c6c9 100644 --- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi @@ -309,12 +309,14 @@ /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" usb0: usb@210000 { + compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; phy_type = "utmi"; port0; }; /include/ "qoriq-usb2-dr-0.dtsi" usb1: usb@211000 { + compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; dr_mode = "host"; phy_type = "utmi"; }; diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi index d41d08de7f7e..af4ebc8009e3 100644 --- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi @@ -336,12 +336,14 @@ /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" usb0: usb@210000 { + compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph"; phy_type = "utmi"; port0; }; /include/ "qoriq-usb2-dr-0.dtsi" usb1: usb@211000 { + compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; dr_mode = "host"; phy_type = "utmi"; }; diff --git a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi index a63edd195ae5..b3e56929eee2 100644 --- a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi @@ -291,6 +291,12 @@ /include/ "qoriq-duart-1.dtsi" /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" + usb@210000 { + compatible = "fsl-usb2-mph-v2.2", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; + }; /include/ "qoriq-usb2-dr-0.dtsi" + usb@211000 { + compatible = "fsl-usb2-dr-v2.2", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; + }; /include/ "qoriq-sec4.1-0.dtsi" }; diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi index 914074b91a85..64b6abea8464 100644 --- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi @@ -339,12 +339,14 @@ /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" usb0: usb@210000 { + compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; phy_type = "utmi"; port0; }; /include/ "qoriq-usb2-dr-0.dtsi" usb1: usb@211000 { + compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; dr_mode = "host"; phy_type = "utmi"; }; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi index a1979ae334a7..3b0650a98478 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-2012 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,6 +41,7 @@ ethernet@24000 { compatible = "gianfar"; reg = <0x24000 0x1000>; ranges = <0x0 0x24000 0x1000>; + fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>; }; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi index 4c4fdde1ec2a..96693b41f0f1 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-2012 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,6 +41,7 @@ ethernet@25000 { compatible = "gianfar"; reg = <0x25000 0x1000>; ranges = <0x0 0x25000 0x1000>; + fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>; }; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi index 4b8ab438668a..6b3fab19da1f 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-2012 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,6 +41,7 @@ ethernet@26000 { compatible = "gianfar"; reg = <0x26000 0x1000>; ranges = <0x0 0x26000 0x1000>; + fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>; }; diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi index 40c9137729ae..0da592d93ddd 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-2012 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,6 +41,7 @@ ethernet@27000 { compatible = "gianfar"; reg = <0x27000 0x1000>; ranges = <0x0 0x27000 0x1000>; + fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 0 0 38 2 0 0 39 2 0 0>; }; diff --git a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi index 5c8046065844..fdedf7b1fe0f 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi @@ -39,6 +39,9 @@ mpic: pic@40000 { reg = <0x40000 0x40000>; compatible = "fsl,mpic"; device_type = "open-pic"; + big-endian; + single-cpu-affinity; + last-interrupt-source = <255>; }; timer@41100 { diff --git a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi index bf957a7fca2a..d4c9d5daab21 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi @@ -33,32 +33,32 @@ */ crypto@30000 { - compatible = "fsl,sec4.4", "fsl,sec4.0"; + compatible = "fsl,sec-v4.4", "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x30000 0x10000>; interrupts = <58 2 0 0>; sec_jr0: jr@1000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr1: jr@2000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x2000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr2: jr@3000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x3000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr3: jr@4000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x4000 0x1000>; interrupts = <45 2 0 0>; }; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi index b9bada6a87dc..08f42271f86a 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi @@ -53,7 +53,7 @@ timer@41100 { msi0: msi@41600 { compatible = "fsl,mpic-msi"; - reg = <0x41600 0x200>; + reg = <0x41600 0x200 0x44140 4>; msi-available-ranges = <0 0x100>; interrupts = < 0xe0 0 0 0 @@ -68,7 +68,7 @@ msi0: msi@41600 { msi1: msi@41800 { compatible = "fsl,mpic-msi"; - reg = <0x41800 0x200>; + reg = <0x41800 0x200 0x45140 4>; msi-available-ranges = <0 0x100>; interrupts = < 0xe8 0 0 0 @@ -83,7 +83,7 @@ msi1: msi@41800 { msi2: msi@41a00 { compatible = "fsl,mpic-msi"; - reg = <0x41a00 0x200>; + reg = <0x41a00 0x200 0x46140 4>; msi-available-ranges = <0 0x100>; interrupts = < 0xf0 0 0 0 diff --git a/arch/powerpc/boot/dts/ge_imp3a.dts b/arch/powerpc/boot/dts/ge_imp3a.dts new file mode 100644 index 000000000000..fefae416a097 --- /dev/null +++ b/arch/powerpc/boot/dts/ge_imp3a.dts @@ -0,0 +1,255 @@ +/* + * GE IMP3A Device Tree Source + * + * Copyright 2010-2011 GE Intelligent Platforms Embedded Systems, Inc. + * + * 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. + * + * Based on: P2020 DS Device Tree Source + * Copyright 2009 Freescale Semiconductor Inc. + */ + +/include/ "fsl/p2020si-pre.dtsi" + +/ { + model = "GE_IMP3A"; + compatible = "ge,imp3a"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@fef05000 { + reg = <0 0xfef05000 0 0x1000>; + + ranges = <0x0 0x0 0x0 0xff000000 0x01000000 + 0x1 0x0 0x0 0xe0000000 0x08000000 + 0x2 0x0 0x0 0xe8000000 0x08000000 + 0x3 0x0 0x0 0xfc100000 0x00020000 + 0x4 0x0 0x0 0xfc000000 0x00008000 + 0x5 0x0 0x0 0xfc008000 0x00008000 + 0x6 0x0 0x0 0xfee00000 0x00040000 + 0x7 0x0 0x0 0xfee80000 0x00040000>; + + /* nor@0,0 is a mirror of part of the memory in nor@1,0 + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ge,imp3a-firmware-mirror", "cfi-flash"; + reg = <0x0 0x0 0x1000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + label = "firmware"; + reg = <0x0 0x1000000>; + read-only; + }; + }; + */ + + nor@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "ge,imp3a-paged-flash", "cfi-flash"; + reg = <0x1 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + label = "user"; + reg = <0x0 0x7800000>; + }; + + partition@7800000 { + label = "firmware"; + reg = <0x7800000 0x800000>; + read-only; + }; + }; + + nvram@3,0 { + device_type = "nvram"; + compatible = "simtek,stk14ca8"; + reg = <0x3 0x0 0x20000>; + }; + + fpga@4,0 { + compatible = "ge,imp3a-fpga-regs"; + reg = <0x4 0x0 0x20>; + }; + + gef_pic: pic@4,20 { + #interrupt-cells = <1>; + interrupt-controller; + device_type = "interrupt-controller"; + compatible = "ge,imp3a-fpga-pic", "gef,fpga-pic-1.00"; + reg = <0x4 0x20 0x20>; + interrupts = <6 7 0 0>; + }; + + gef_gpio: gpio@4,400 { + #gpio-cells = <2>; + compatible = "ge,imp3a-gpio"; + reg = <0x4 0x400 0x24>; + gpio-controller; + }; + + wdt@4,800 { + compatible = "ge,imp3a-fpga-wdt", "gef,fpga-wdt-1.00", + "gef,fpga-wdt"; + reg = <0x4 0x800 0x8>; + interrupts = <10 4>; + interrupt-parent = <&gef_pic>; + }; + + /* Second watchdog available, driver currently supports one. + wdt@4,808 { + compatible = "gef,imp3a-fpga-wdt", "gef,fpga-wdt-1.00", + "gef,fpga-wdt"; + reg = <0x4 0x808 0x8>; + interrupts = <9 4>; + interrupt-parent = <&gef_pic>; + }; + */ + + nand@6,0 { + compatible = "fsl,elbc-fcm-nand"; + reg = <0x6 0x0 0x40000>; + }; + + nand@7,0 { + compatible = "fsl,elbc-fcm-nand"; + reg = <0x7 0x0 0x40000>; + }; + }; + + soc: soc@fef00000 { + ranges = <0x0 0 0xfef00000 0x100000>; + + i2c@3000 { + hwmon@48 { + compatible = "national,lm92"; + reg = <0x48>; + }; + + hwmon@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; + + rtc@51 { + compatible = "epson,rx8581"; + reg = <0x51>; + }; + + eti@6b { + compatible = "dallas,ds1682"; + reg = <0x6b>; + }; + }; + + usb@22000 { + phy_type = "ulpi"; + dr_mode = "host"; + }; + + mdio@24520 { + phy0: ethernet-phy@0 { + interrupt-parent = <&gef_pic>; + interrupts = <0xc 0x4>; + reg = <0x1>; + }; + phy1: ethernet-phy@1 { + interrupt-parent = <&gef_pic>; + interrupts = <0xb 0x4>; + reg = <0x2>; + }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + status = "disabled"; + }; + + enet0: ethernet@24000 { + tbi-handle = <&tbi0>; + phy-handle = <&phy0>; + phy-connection-type = "gmii"; + }; + + enet1: ethernet@25000 { + tbi-handle = <&tbi1>; + phy-handle = <&phy1>; + phy-connection-type = "gmii"; + }; + + enet2: ethernet@26000 { + status = "disabled"; + }; + }; + + pci0: pcie@fef08000 { + ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xfe020000 0x0 0x10000>; + reg = <0 0xfef08000 0 0x1000>; + + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x10000>; + }; + }; + + pci1: pcie@fef09000 { + reg = <0 0xfef09000 0 0x1000>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xfe010000 0x0 0x10000>; + + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x10000>; + }; + + }; + + pci2: pcie@fef0a000 { + reg = <0 0xfef0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xfe000000 0x0 0x10000>; + + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x10000>; + }; + }; +}; + +/include/ "fsl/p2020si-post.dtsi" diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index c0e450a551bf..81dd513d6308 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -405,6 +405,10 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi-phy@2 { + device_type = "tbi-phy"; + reg = <0x2>; + }; }; qeic: interrupt-controller@80 { diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index c15881574fdc..19736222a0b9 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts @@ -1,7 +1,7 @@ /* * MPC8536 DS Device Tree Source * - * Copyright 2008 Freescale Semiconductor, Inc. + * Copyright 2008, 2011 Freescale Semiconductor, Inc. * * 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 @@ -34,6 +34,10 @@ lbc: localbus@ffe05000 { reg = <0 0xffe05000 0 0x1000>; + + ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 + 0x2 0x0 0x0 0xffa00000 0x00040000 + 0x3 0x0 0x0 0xffdf0000 0x00008000>; }; board_soc: soc: soc@ffe00000 { diff --git a/arch/powerpc/boot/dts/mpc8536ds.dtsi b/arch/powerpc/boot/dts/mpc8536ds.dtsi index 1462e4cf49d7..cc46dbd9746d 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8536ds.dtsi @@ -32,6 +32,99 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + reg = <0x0 0x03000000>; + label = "ramdisk-nor"; + }; + + partition@3000000 { + reg = <0x03000000 0x00e00000>; + label = "diagnostic-nor"; + read-only; + }; + + partition@3e00000 { + reg = <0x03e00000 0x00200000>; + label = "dink-nor"; + read-only; + }; + + partition@4000000 { + reg = <0x04000000 0x00400000>; + label = "kernel-nor"; + }; + + partition@4400000 { + reg = <0x04400000 0x03b00000>; + label = "fs-nor"; + }; + + partition@7f00000 { + reg = <0x07f00000 0x00080000>; + label = "dtb-nor"; + }; + + partition@7f80000 { + reg = <0x07f80000 0x00080000>; + label = "u-boot-nor"; + read-only; + }; + }; + + nand@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8536-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x2 0x0 0x40000>; + + partition@0 { + reg = <0x0 0x02000000>; + label = "u-boot-nand"; + read-only; + }; + + partition@2000000 { + reg = <0x02000000 0x10000000>; + label = "fs-nand"; + }; + + partition@12000000 { + reg = <0x12000000 0x08000000>; + label = "ramdisk-nand"; + }; + + partition@1a000000 { + reg = <0x1a000000 0x04000000>; + label = "kernel-nand"; + }; + + partition@1e000000 { + reg = <0x1e000000 0x01000000>; + label = "dtb-nand"; + }; + + partition@1f000000 { + reg = <0x1f000000 0x21000000>; + label = "empty-nand"; + }; + }; + + board-control@3,0 { + compatible = "fsl,mpc8536ds-fpga-pixis"; + reg = <0x3 0x0 0x8000>; + }; +}; + &board_soc { i2c@3100 { rtc@68 { diff --git a/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/arch/powerpc/boot/dts/mpc8536ds_36b.dts index 8f4b929b1d1d..f8a3b3413176 100644 --- a/arch/powerpc/boot/dts/mpc8536ds_36b.dts +++ b/arch/powerpc/boot/dts/mpc8536ds_36b.dts @@ -1,7 +1,7 @@ /* * MPC8536DS Device Tree Source (36-bit address map) * - * Copyright 2008-2009 Freescale Semiconductor, Inc. + * Copyright 2008-2009, 2011 Freescale Semiconductor, Inc. * * 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 @@ -33,7 +33,11 @@ }; lbc: localbus@ffe05000 { - reg = <0 0xffe05000 0 0x1000>; + reg = <0xf 0xffe05000 0 0x1000>; + + ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 + 0x2 0x0 0xf 0xffa00000 0x00040000 + 0x3 0x0 0xf 0xffdf0000 0x00008000>; }; board_soc: soc: soc@fffe00000 { diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts deleted file mode 100644 index 07b8dae0f46e..000000000000 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ /dev/null @@ -1,306 +0,0 @@ -/* - * MPC8548 CDS Device Tree Source - * - * Copyright 2006, 2008 Freescale Semiconductor Inc. - * - * 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. - */ - -/include/ "fsl/mpc8548si-pre.dtsi" - -/ { - model = "MPC8548CDS"; - compatible = "MPC8548CDS", "MPC85xxCDS"; - - aliases { - ethernet0 = &enet0; - ethernet1 = &enet1; - ethernet2 = &enet2; - ethernet3 = &enet3; - serial0 = &serial0; - serial1 = &serial1; - pci0 = &pci0; - pci1 = &pci1; - pci2 = &pci2; - }; - - memory { - device_type = "memory"; - reg = <0 0 0x0 0x8000000>; // 128M at 0x0 - }; - - lbc: localbus@e0005000 { - reg = <0 0xe0005000 0 0x1000>; - }; - - soc: soc8548@e0000000 { - ranges = <0 0x0 0xe0000000 0x100000>; - - i2c@3000 { - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; - - eeprom@56 { - compatible = "atmel,24c64"; - reg = <0x56>; - }; - - eeprom@57 { - compatible = "atmel,24c64"; - reg = <0x57>; - }; - }; - - i2c@3100 { - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; - }; - - enet0: ethernet@24000 { - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - }; - - mdio@24520 { - phy0: ethernet-phy@0 { - interrupts = <5 1 0 0>; - reg = <0x0>; - device_type = "ethernet-phy"; - }; - phy1: ethernet-phy@1 { - interrupts = <5 1 0 0>; - reg = <0x1>; - device_type = "ethernet-phy"; - }; - phy2: ethernet-phy@2 { - interrupts = <5 1 0 0>; - reg = <0x2>; - device_type = "ethernet-phy"; - }; - phy3: ethernet-phy@3 { - interrupts = <5 1 0 0>; - reg = <0x3>; - device_type = "ethernet-phy"; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet1: ethernet@25000 { - tbi-handle = <&tbi1>; - phy-handle = <&phy1>; - }; - - mdio@25520 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet2: ethernet@26000 { - tbi-handle = <&tbi2>; - phy-handle = <&phy2>; - }; - - mdio@26520 { - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet3: ethernet@27000 { - tbi-handle = <&tbi3>; - phy-handle = <&phy3>; - }; - - mdio@27520 { - tbi3: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - }; - - pci0: pci@e0008000 { - reg = <0 0xe0008000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000 - 0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>; - clock-frequency = <66666666>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - /* IDSEL 0x4 (PCIX Slot 2) */ - 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x5 (PCIX Slot 3) */ - 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 - 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 - 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 - 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 - - /* IDSEL 0x6 (PCIX Slot 4) */ - 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 - 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 - 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 - 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 - - /* IDSEL 0x8 (PCIX Slot 5) */ - 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0xC (Tsi310 bridge) */ - 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x14 (Slot 2) */ - 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x15 (Slot 3) */ - 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 - 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 - 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 - 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 - - /* IDSEL 0x16 (Slot 4) */ - 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 - 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 - 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 - 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 - - /* IDSEL 0x18 (Slot 5) */ - 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ - 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; - - pci_bridge@1c { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x00 (PrPMC Site) */ - 0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x04 (VIA chip) */ - 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x05 (8139) */ - 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 - - /* IDSEL 0x06 (Slot 6) */ - 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 - 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 - 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 - 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 - - /* IDESL 0x07 (Slot 7) */ - 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0 - 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0 - 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0 - 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>; - - reg = <0xe000 0x0 0x0 0x0 0x0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x80000>; - clock-frequency = <33333333>; - - isa@4 { - device_type = "isa"; - #interrupt-cells = <2>; - #size-cells = <1>; - #address-cells = <2>; - reg = <0x2000 0x0 0x0 0x0 0x0>; - ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - interrupt-controller; - device_type = "interrupt-controller"; - reg = <0x1 0x20 0x2 - 0x1 0xa0 0x2 - 0x1 0x4d0 0x2>; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <0 1 0 0>; - interrupt-parent = <&mpic>; - }; - - rtc@70 { - compatible = "pnpPNP,b00"; - reg = <0x1 0x70 0x2>; - }; - }; - }; - }; - - pci1: pci@e0009000 { - reg = <0 0xe0009000 0 0x1000>; - ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000 - 0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>; - clock-frequency = <66666666>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 - 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; - }; - - pci2: pcie@e000a000 { - reg = <0 0xe000a000 0 0x1000>; - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "fsl/mpc8548si-post.dtsi" diff --git a/arch/powerpc/boot/dts/mpc8548cds.dtsi b/arch/powerpc/boot/dts/mpc8548cds.dtsi new file mode 100644 index 000000000000..c61f525e4740 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds.dtsi @@ -0,0 +1,306 @@ +/* + * MPC8548CDS Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&board_lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x01000000>; + bank-width = <2>; + device-width = <2>; + + partition@0 { + reg = <0x0 0x0b00000>; + label = "ramdisk-nor"; + }; + + partition@300000 { + reg = <0x0b00000 0x0400000>; + label = "kernel-nor"; + }; + + partition@700000 { + reg = <0x0f00000 0x060000>; + label = "dtb-nor"; + }; + + partition@760000 { + reg = <0x0f60000 0x020000>; + label = "env-nor"; + read-only; + }; + + partition@780000 { + reg = <0x0f80000 0x080000>; + label = "u-boot-nor"; + read-only; + }; + }; + + board-control@1,0 { + compatible = "fsl,mpc8548cds-fpga"; + reg = <0x1 0x0 0x1000>; + }; +}; + +&board_soc { + i2c@3000 { + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + }; + + eeprom@57 { + compatible = "atmel,24c64"; + reg = <0x57>; + }; + }; + + i2c@3100 { + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + enet0: ethernet@24000 { + tbi-handle = <&tbi0>; + phy-handle = <&phy0>; + }; + + mdio@24520 { + phy0: ethernet-phy@0 { + interrupts = <5 1 0 0>; + reg = <0x0>; + device_type = "ethernet-phy"; + }; + phy1: ethernet-phy@1 { + interrupts = <5 1 0 0>; + reg = <0x1>; + device_type = "ethernet-phy"; + }; + phy2: ethernet-phy@2 { + interrupts = <5 1 0 0>; + reg = <0x2>; + device_type = "ethernet-phy"; + }; + phy3: ethernet-phy@3 { + interrupts = <5 1 0 0>; + reg = <0x3>; + device_type = "ethernet-phy"; + }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet1: ethernet@25000 { + tbi-handle = <&tbi1>; + phy-handle = <&phy1>; + }; + + mdio@25520 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet2: ethernet@26000 { + tbi-handle = <&tbi2>; + phy-handle = <&phy2>; + }; + + mdio@26520 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet3: ethernet@27000 { + tbi-handle = <&tbi3>; + phy-handle = <&phy3>; + }; + + mdio@27520 { + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; +}; + +&board_pci0 { + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x4 (PCIX Slot 2) */ + 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x5 (PCIX Slot 3) */ + 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 + 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 + 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 + 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 + + /* IDSEL 0x6 (PCIX Slot 4) */ + 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 + 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 + 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 + 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 + + /* IDSEL 0x8 (PCIX Slot 5) */ + 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0xC (Tsi310 bridge) */ + 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x14 (Slot 2) */ + 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x15 (Slot 3) */ + 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 + 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 + 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 + 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 + + /* IDSEL 0x16 (Slot 4) */ + 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 + 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 + 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 + 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 + + /* IDSEL 0x18 (Slot 5) */ + 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ + 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; + + pci_bridge@1c { + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x00 (PrPMC Site) */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x04 (VIA chip) */ + 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x05 (8139) */ + 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 + + /* IDSEL 0x06 (Slot 6) */ + 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 + 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 + 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 + 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 + + /* IDESL 0x07 (Slot 7) */ + 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0 + 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0 + 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0 + 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>; + + reg = <0xe000 0x0 0x0 0x0 0x0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x80000>; + clock-frequency = <33333333>; + + isa@4 { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = <0x2000 0x0 0x0 0x0 0x0>; + ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + interrupt-controller; + device_type = "interrupt-controller"; + reg = <0x1 0x20 0x2 + 0x1 0xa0 0x2 + 0x1 0x4d0 0x2>; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <0 1 0 0>; + interrupt-parent = <&mpic>; + }; + + rtc@70 { + compatible = "pnpPNP,b00"; + reg = <0x1 0x70 0x2>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/mpc8548cds_32b.dts b/arch/powerpc/boot/dts/mpc8548cds_32b.dts new file mode 100644 index 000000000000..6fd63163fc6b --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds_32b.dts @@ -0,0 +1,86 @@ +/* + * MPC8548 CDS Device Tree Source (32-bit address map) + * + * Copyright 2006, 2008, 2011-2012 Freescale Semiconductor Inc. + * + * 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. + */ + +/include/ "fsl/mpc8548si-pre.dtsi" + +/ { + model = "MPC8548CDS"; + compatible = "MPC8548CDS", "MPC85xxCDS"; + + memory { + device_type = "memory"; + reg = <0 0 0x0 0x8000000>; // 128M at 0x0 + }; + + board_lbc: lbc: localbus@e0005000 { + reg = <0 0xe0005000 0 0x1000>; + + ranges = <0x0 0x0 0x0 0xff000000 0x01000000 + 0x1 0x0 0x0 0xf8004000 0x00001000>; + + }; + + board_soc: soc: soc8548@e0000000 { + ranges = <0 0x0 0xe0000000 0x100000>; + }; + + board_pci0: pci0: pci@e0008000 { + reg = <0 0xe0008000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000 + 0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>; + clock-frequency = <66666666>; + }; + + pci1: pci@e0009000 { + reg = <0 0xe0009000 0 0x1000>; + ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000 + 0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>; + clock-frequency = <66666666>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x15 */ + 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 + 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; + }; + + pci2: pcie@e000a000 { + reg = <0 0xe000a000 0 0x1000>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + rio: rapidio@e00c0000 { + reg = <0x0 0xe00c0000 0x0 0x20000>; + port1 { + ranges = <0x0 0x0 0x0 0xc0000000 0x0 0x20000000>; + }; + }; +}; + +/* + * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings + * for interrupt-map & interrupt-map-mask. + */ + +/include/ "fsl/mpc8548si-post.dtsi" +/include/ "mpc8548cds.dtsi" diff --git a/arch/powerpc/boot/dts/mpc8548cds_36b.dts b/arch/powerpc/boot/dts/mpc8548cds_36b.dts new file mode 100644 index 000000000000..10e551b11bd6 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds_36b.dts @@ -0,0 +1,86 @@ +/* + * MPC8548 CDS Device Tree Source (36-bit address map) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * 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. + */ + +/include/ "fsl/mpc8548si-pre.dtsi" + +/ { + model = "MPC8548CDS"; + compatible = "MPC8548CDS", "MPC85xxCDS"; + + memory { + device_type = "memory"; + reg = <0 0 0x0 0x8000000>; // 128M at 0x0 + }; + + board_lbc: lbc: localbus@fe0005000 { + reg = <0xf 0xe0005000 0 0x1000>; + + ranges = <0x0 0x0 0xf 0xff000000 0x01000000 + 0x1 0x0 0xf 0xf8004000 0x00001000>; + + }; + + board_soc: soc: soc8548@fe0000000 { + ranges = <0 0xf 0xe0000000 0x100000>; + }; + + board_pci0: pci0: pci@fe0008000 { + reg = <0xf 0xe0008000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x10000000 + 0x1000000 0x0 0x00000000 0xf 0xe2000000 0x0 0x800000>; + clock-frequency = <66666666>; + }; + + pci1: pci@fe0009000 { + reg = <0xf 0xe0009000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x10000000 0x0 0x10000000 + 0x1000000 0x0 0x00000000 0xf 0xe2800000 0x0 0x800000>; + clock-frequency = <66666666>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x15 */ + 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 + 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; + }; + + pci2: pcie@fe000a000 { + reg = <0xf 0xe000a000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xe3000000 0x0 0x100000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + rio: rapidio@fe00c0000 { + reg = <0xf 0xe00c0000 0x0 0x20000>; + port1 { + ranges = <0x0 0x0 0xc 0x40000000 0x0 0x20000000>; + }; + }; +}; + +/* + * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings + * for interrupt-map & interrupt-map-mask. + */ + +/include/ "fsl/mpc8548si-post.dtsi" +/include/ "mpc8548cds.dtsi" diff --git a/arch/powerpc/boot/dts/mpc8572ds.dtsi b/arch/powerpc/boot/dts/mpc8572ds.dtsi index c3d4fac0532a..14178944e220 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8572ds.dtsi @@ -41,37 +41,47 @@ bank-width = <2>; device-width = <1>; - ramdisk@0 { + partition@0 { reg = <0x0 0x03000000>; - read-only; + label = "ramdisk-nor"; }; - diagnostic@3000000 { + partition@3000000 { reg = <0x03000000 0x00e00000>; + label = "diagnostic-nor"; read-only; }; - dink@3e00000 { + partition@3e00000 { reg = <0x03e00000 0x00200000>; + label = "dink-nor"; read-only; }; - kernel@4000000 { + partition@4000000 { reg = <0x04000000 0x00400000>; - read-only; + label = "kernel-nor"; }; - jffs2@4400000 { + partition@4400000 { reg = <0x04400000 0x03b00000>; + label = "fs-nor"; + }; + + partition@7f00000 { + reg = <0x07f00000 0x00060000>; + label = "dtb-nor"; }; - dtb@7f00000 { - reg = <0x07f00000 0x00080000>; + partition@7f60000 { + reg = <0x07f60000 0x00020000>; + label = "env-nor"; read-only; }; - u-boot@7f80000 { + partition@7f80000 { reg = <0x07f80000 0x00080000>; + label = "u-boot-nor"; read-only; }; }; @@ -83,31 +93,35 @@ "fsl,elbc-fcm-nand"; reg = <0x2 0x0 0x40000>; - u-boot@0 { + partition@0 { reg = <0x0 0x02000000>; + label = "u-boot-nand"; read-only; }; - jffs2@2000000 { + partition@2000000 { reg = <0x02000000 0x10000000>; + label = "fs-nand"; }; - ramdisk@12000000 { + partition@12000000 { reg = <0x12000000 0x08000000>; - read-only; + label = "ramdisk-nand"; }; - kernel@1a000000 { + partition@1a000000 { reg = <0x1a000000 0x04000000>; + label = "kernel-nand"; }; - dtb@1e000000 { + partition@1e000000 { reg = <0x1e000000 0x01000000>; - read-only; + label = "dtb-nand"; }; - empty@1f000000 { + partition@1f000000 { reg = <0x1f000000 0x21000000>; + label = "empty-nand"; }; }; diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi index d4c4a7730285..49776143a1b8 100644 --- a/arch/powerpc/boot/dts/p1010rdb.dtsi +++ b/arch/powerpc/boot/dts/p1010rdb.dtsi @@ -138,7 +138,7 @@ #size-cells = <1>; compatible = "spansion,s25sl12801"; reg = <0>; - spi-max-frequency = <50000000>; + spi-max-frequency = <40000000>; partition@0 { /* 1MB for u-boot Bootloader Image */ @@ -196,7 +196,7 @@ }; tbi-phy@3 { - device-type = "tbi-phy"; + device_type = "tbi-phy"; reg = <0x3>; }; }; diff --git a/arch/powerpc/boot/dts/p1020rdb-pc.dtsi b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi new file mode 100644 index 000000000000..c952cd37cf6d --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi @@ -0,0 +1,247 @@ +/* + * P1020 RDB-PC Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x1000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* This location must not be altered */ + /* 256KB for Vitesse 7385 Switch firmware */ + reg = <0x0 0x00040000>; + label = "NOR Vitesse-7385 Firmware"; + read-only; + }; + + partition@40000 { + /* 256KB for DTB Image */ + reg = <0x00040000 0x00040000>; + label = "NOR DTB Image"; + }; + + partition@80000 { + /* 3.5 MB for Linux Kernel Image */ + reg = <0x00080000 0x00380000>; + label = "NOR Linux Kernel Image"; + }; + + partition@400000 { + /* 11MB for JFFS2 based Root file System */ + reg = <0x00400000 0x00b00000>; + label = "NOR JFFS2 Root File System"; + }; + + partition@f00000 { + /* This location must not be altered */ + /* 512KB for u-boot Bootloader Image */ + /* 512KB for u-boot Environment Variables */ + reg = <0x00f00000 0x00100000>; + label = "NOR U-Boot Image"; + read-only; + }; + }; + + nand@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1020-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x1 0x0 0x40000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND DTB Image"; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND Linux Kernel Image"; + }; + + partition@600000 { + /* 4MB for Compressed Root file System Image */ + reg = <0x00600000 0x00400000>; + label = "NAND Compressed RFS Image"; + }; + + partition@a00000 { + /* 7MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00700000>; + label = "NAND JFFS2 Root File System"; + }; + + partition@1100000 { + /* 15MB for JFFS2 based Root file System */ + reg = <0x01100000 0x00f00000>; + label = "NAND Writable User area"; + }; + }; + + L2switch@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "vitesse-7385"; + reg = <0x2 0x0 0x20000>; + }; + + cpld@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cpld"; + reg = <0x3 0x0 0x20000>; + read-only; + }; +}; + +&soc { + i2c@3000 { + rtc@68 { + compatible = "pericom,pt7c4338"; + reg = <0x68>; + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl12801"; + reg = <0>; + spi-max-frequency = <40000000>; /* input clock */ + + partition@u-boot { + /* 512KB for u-boot Bootloader Image */ + reg = <0x0 0x00080000>; + label = "u-boot"; + read-only; + }; + + partition@dtb { + /* 512KB for DTB Image*/ + reg = <0x00080000 0x00080000>; + label = "dtb"; + }; + + partition@kernel { + /* 4MB for Linux Kernel Image */ + reg = <0x00100000 0x00400000>; + label = "kernel"; + }; + + partition@fs { + /* 4MB for Compressed RFS Image */ + reg = <0x00500000 0x00400000>; + label = "file system"; + }; + + partition@jffs-fs { + /* 7MB for JFFS2 based RFS */ + reg = <0x00900000 0x00700000>; + label = "file system jffs2"; + }; + }; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. + usb@23000 { + phy_type = "ulpi"; + }; + */ + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1>; + reg = <0x1>; + }; + + tbi0: tbi-phy@11 { + device_type = "tbi-phy"; + reg = <0x11>; + }; + }; + + mdio@25000 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + phy-handle = <&phy0>; + tbi-handle = <&tbi1>; + phy-connection-type = "sgmii"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts new file mode 100644 index 000000000000..4de69b726dc5 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts @@ -0,0 +1,90 @@ +/* + * P1020 RDB-PC Device Tree Source (32-bit address map) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1020si-pre.dtsi" +/ { + model = "fsl,P1020RDB-PC"; + compatible = "fsl,P1020RDB-PC"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ + ranges = <0x0 0x0 0x0 0xef000000 0x01000000 + 0x1 0x0 0x0 0xff800000 0x00040000 + 0x2 0x0 0x0 0xffb00000 0x00020000 + 0x3 0x0 0x0 0xffa00000 0x00020000>; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "p1020rdb-pc.dtsi" +/include/ "fsl/p1020si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts new file mode 100644 index 000000000000..5237da7441bc --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts @@ -0,0 +1,90 @@ +/* + * P1020 RDB-PC Device Tree Source (36-bit address map) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1020si-pre.dtsi" +/ { + model = "fsl,P1020RDB-PC"; + compatible = "fsl,P1020RDB-PC"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@fffe05000 { + reg = <0xf 0xffe05000 0 0x1000>; + + /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ + ranges = <0x0 0x0 0xf 0xef000000 0x01000000 + 0x1 0x0 0xf 0xff800000 0x00040000 + 0x2 0x0 0xf 0xffb00000 0x00040000 + 0x3 0x0 0xf 0xffa00000 0x00020000>; + }; + + soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; + }; + + pci0: pcie@fffe09000 { + reg = <0xf 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "p1020rdb-pc.dtsi" +/include/ "fsl/p1020si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts new file mode 100644 index 000000000000..f411515937ec --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts @@ -0,0 +1,64 @@ +/* + * P1020 RDB-PC Core0 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb, + * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. + * + * Please note to add "-b 0" for core0's dts compiling. + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * 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. + */ + +/include/ "p1020rdb-pc_32b.dts" + +/ { + model = "fsl,P1020RDB-PC"; + compatible = "fsl,P1020RDB-PC"; + + aliases { + ethernet1 = &enet1; + ethernet2 = &enet2; + serial0 = &serial0; + pci0 = &pci0; + pci1 = &pci1; + }; + + cpus { + PowerPC,P1020@1 { + status = "disabled"; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + status = "disabled"; + }; + + soc@ffe00000 { + serial1: serial@4600 { + status = "disabled"; + }; + + enet0: ethernet@b0000 { + status = "disabled"; + }; + + mpic: pic@40000 { + protected-sources = < + 42 29 30 34 /* serial1, enet0-queue-group0 */ + 17 18 24 45 /* enet0-queue-group1, crypto */ + >; + pic-no-reset; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts new file mode 100644 index 000000000000..a91335ad82c2 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts @@ -0,0 +1,142 @@ +/* + * P1020 RDB-PC Core1 Device Tree Source in CAMP mode. + * + * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache + * can be shared, all the other devices must be assigned to one core only. + * This dts allows core1 to have l2, eth0, crypto. + * + * Please note to add "-b 1" for core1's dts compiling. + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * 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. + */ + +/include/ "p1020rdb-pc_32b.dts" + +/ { + model = "fsl,P1020RDB-PC"; + compatible = "fsl,P1020RDB-PC"; + + aliases { + ethernet0 = &enet0; + serial0 = &serial1; + }; + + cpus { + PowerPC,P1020@0 { + status = "disabled"; + }; + }; + + memory { + device_type = "memory"; + }; + + localbus@ffe05000 { + status = "disabled"; + }; + + soc@ffe00000 { + ecm-law@0 { + status = "disabled"; + }; + + ecm@1000 { + status = "disabled"; + }; + + memory-controller@2000 { + status = "disabled"; + }; + + i2c@3000 { + status = "disabled"; + }; + + i2c@3100 { + status = "disabled"; + }; + + serial0: serial@4500 { + status = "disabled"; + }; + + spi@7000 { + status = "disabled"; + }; + + gpio: gpio-controller@f000 { + status = "disabled"; + }; + + dma@21300 { + status = "disabled"; + }; + + mdio@24000 { + status = "disabled"; + }; + + mdio@25000 { + status = "disabled"; + }; + + enet1: ethernet@b1000 { + status = "disabled"; + }; + + enet2: ethernet@b2000 { + status = "disabled"; + }; + + usb@22000 { + status = "disabled"; + }; + + sdhci@2e000 { + status = "disabled"; + }; + + mpic: pic@40000 { + protected-sources = < + 16 /* ecm, mem, L2, pci0, pci1 */ + 43 42 59 /* i2c, serial0, spi */ + 47 63 62 /* gpio, tdm */ + 20 21 22 23 /* dma */ + 03 02 /* mdio */ + 35 36 40 /* enet1-queue-group0 */ + 51 52 67 /* enet1-queue-group1 */ + 31 32 33 /* enet2-queue-group0 */ + 25 26 27 /* enet2-queue-group1 */ + 28 72 58 /* usb, sdhci, crypto */ + 0xb0 0xb1 0xb2 /* message */ + 0xb3 0xb4 0xb5 + 0xb6 0xb7 + 0xe0 0xe1 0xe2 /* msi */ + 0xe3 0xe4 0xe5 + 0xe6 0xe7 /* sdhci, crypto , pci */ + >; + pic-no-reset; + }; + + msi@41600 { + status = "disabled"; + }; + + global-utilities@e0000 { //global utilities block + status = "disabled"; + }; + }; + + pci0: pcie@ffe09000 { + status = "disabled"; + }; + + pci1: pcie@ffe0a000 { + status = "disabled"; + }; +}; diff --git a/arch/powerpc/boot/dts/p1021rdb.dts b/arch/powerpc/boot/dts/p1021rdb.dts new file mode 100644 index 000000000000..90b6b4caa273 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb.dts @@ -0,0 +1,96 @@ +/* + * P1021 RDB Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1021si-pre.dtsi" +/ { + model = "fsl,P1021RDB"; + compatible = "fsl,P1021RDB-PC"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ + ranges = <0x0 0x0 0x0 0xef000000 0x01000000 + 0x1 0x0 0x0 0xff800000 0x00040000 + 0x2 0x0 0x0 0xffb00000 0x00020000>; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + qe: qe@ffe80000 { + ranges = <0x0 0x0 0xffe80000 0x40000>; + reg = <0 0xffe80000 0 0x480>; + brg-frequency = <0>; + bus-frequency = <0>; + }; +}; + +/include/ "p1021rdb.dtsi" +/include/ "fsl/p1021si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1021rdb.dtsi b/arch/powerpc/boot/dts/p1021rdb.dtsi new file mode 100644 index 000000000000..b973461ab751 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb.dtsi @@ -0,0 +1,236 @@ +/* + * P1021 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x1000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* This location must not be altered */ + /* 256KB for Vitesse 7385 Switch firmware */ + reg = <0x0 0x00040000>; + label = "NOR Vitesse-7385 Firmware"; + read-only; + }; + + partition@40000 { + /* 256KB for DTB Image */ + reg = <0x00040000 0x00040000>; + label = "NOR DTB Image"; + }; + + partition@80000 { + /* 3.5 MB for Linux Kernel Image */ + reg = <0x00080000 0x00380000>; + label = "NOR Linux Kernel Image"; + }; + + partition@400000 { + /* 11MB for JFFS2 based Root file System */ + reg = <0x00400000 0x00b00000>; + label = "NOR JFFS2 Root File System"; + }; + + partition@f00000 { + /* This location must not be altered */ + /* 512KB for u-boot Bootloader Image */ + /* 512KB for u-boot Environment Variables */ + reg = <0x00f00000 0x00100000>; + label = "NOR U-Boot Image"; + }; + }; + + nand@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1021-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x1 0x0 0x40000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND DTB Image"; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND Linux Kernel Image"; + }; + + partition@600000 { + /* 4MB for Compressed Root file System Image */ + reg = <0x00600000 0x00400000>; + label = "NAND Compressed RFS Image"; + }; + + partition@a00000 { + /* 7MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00700000>; + label = "NAND JFFS2 Root File System"; + }; + + partition@1100000 { + /* 15MB for User Writable Area */ + reg = <0x01100000 0x00f00000>; + label = "NAND Writable User area"; + }; + }; + + L2switch@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "vitesse-7385"; + reg = <0x2 0x0 0x20000>; + }; +}; + +&soc { + i2c@3000 { + rtc@68 { + compatible = "pericom,pt7c4338"; + reg = <0x68>; + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl12801"; + reg = <0>; + spi-max-frequency = <40000000>; /* input clock */ + + partition@u-boot { + /* 512KB for u-boot Bootloader Image */ + reg = <0x0 0x00080000>; + label = "SPI Flash U-Boot Image"; + read-only; + }; + + partition@dtb { + /* 512KB for DTB Image */ + reg = <0x00080000 0x00080000>; + label = "SPI Flash DTB Image"; + }; + + partition@kernel { + /* 4MB for Linux Kernel Image */ + reg = <0x00100000 0x00400000>; + label = "SPI Flash Linux Kernel Image"; + }; + + partition@fs { + /* 4MB for Compressed RFS Image */ + reg = <0x00500000 0x00400000>; + label = "SPI Flash Compressed RFSImage"; + }; + + partition@jffs-fs { + /* 7MB for JFFS2 based RFS */ + reg = <0x00900000 0x00700000>; + label = "SPI Flash JFFS2 RFS"; + }; + }; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1 0 0>; + reg = <0x0>; + }; + + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1 0 0>; + reg = <0x1>; + }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25000 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26000 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + phy-handle = <&phy0>; + tbi-handle = <&tbi1>; + phy-connection-type = "sgmii"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + tbi-handle = <&tbi2>; + phy-connection-type = "rgmii-id"; + }; +}; diff --git a/arch/powerpc/boot/dts/p1021rdb_36b.dts b/arch/powerpc/boot/dts/p1021rdb_36b.dts new file mode 100644 index 000000000000..ea6d8b5fa10b --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb_36b.dts @@ -0,0 +1,96 @@ +/* + * P1021 RDB Device Tree Source (36-bit address map) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1021si-pre.dtsi" +/ { + model = "fsl,P1021RDB"; + compatible = "fsl,P1021RDB-PC"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@fffe05000 { + reg = <0xf 0xffe05000 0 0x1000>; + + /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ + ranges = <0x0 0x0 0xf 0xef000000 0x01000000 + 0x1 0x0 0xf 0xff800000 0x00040000 + 0x2 0x0 0xf 0xffb00000 0x00020000>; + }; + + soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; + }; + + pci0: pcie@fffe09000 { + ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + reg = <0xf 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xc0000000 + 0x2000000 0x0 0xc0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + qe: qe@fffe80000 { + ranges = <0x0 0xf 0xffe80000 0x40000>; + reg = <0xf 0xffe80000 0 0x480>; + brg-frequency = <0>; + bus-frequency = <0>; + }; +}; + +/include/ "p1021rdb.dtsi" +/include/ "fsl/p1021si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts deleted file mode 100644 index ef95717db4bc..000000000000 --- a/arch/powerpc/boot/dts/p1022ds.dts +++ /dev/null @@ -1,274 +0,0 @@ -/* - * P1022 DS 36Bit Physical Address Map Device Tree Source - * - * Copyright 2010 Freescale Semiconductor, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -/include/ "fsl/p1022si-pre.dtsi" -/ { - model = "fsl,P1022DS"; - compatible = "fsl,P1022DS"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@fffe05000 { - reg = <0xf 0xffe05000 0 0x1000>; - ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 - 0x1 0x0 0xf 0xe0000000 0x08000000 - 0x2 0x0 0xf 0xff800000 0x00040000 - 0x3 0x0 0xf 0xffdf0000 0x00008000>; - - /* - * This node is used to access the pixis via "indirect" mode, - * which is done by writing the pixis register index to chip - * select 0 and the value to/from chip select 1. Indirect - * mode is the only way to access the pixis when DIU video - * is enabled. Note that this assumes that the first column - * of the 'ranges' property above is the chip select number. - */ - board-control@0,0 { - compatible = "fsl,p1022ds-indirect-pixis"; - reg = <0x0 0x0 1 /* CS0 */ - 0x1 0x0 1>; /* CS1 */ - }; - - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x8000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - reg = <0x0 0x03000000>; - label = "ramdisk-nor"; - read-only; - }; - - partition@3000000 { - reg = <0x03000000 0x00e00000>; - label = "diagnostic-nor"; - read-only; - }; - - partition@3e00000 { - reg = <0x03e00000 0x00200000>; - label = "dink-nor"; - read-only; - }; - - partition@4000000 { - reg = <0x04000000 0x00400000>; - label = "kernel-nor"; - read-only; - }; - - partition@4400000 { - reg = <0x04400000 0x03b00000>; - label = "jffs2-nor"; - }; - - partition@7f00000 { - reg = <0x07f00000 0x00080000>; - label = "dtb-nor"; - read-only; - }; - - partition@7f80000 { - reg = <0x07f80000 0x00080000>; - label = "u-boot-nor"; - read-only; - }; - }; - - nand@2,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,elbc-fcm-nand"; - reg = <0x2 0x0 0x40000>; - - partition@0 { - reg = <0x0 0x02000000>; - label = "u-boot-nand"; - read-only; - }; - - partition@2000000 { - reg = <0x02000000 0x10000000>; - label = "jffs2-nand"; - }; - - partition@12000000 { - reg = <0x12000000 0x10000000>; - label = "ramdisk-nand"; - read-only; - }; - - partition@22000000 { - reg = <0x22000000 0x04000000>; - label = "kernel-nand"; - }; - - partition@26000000 { - reg = <0x26000000 0x01000000>; - label = "dtb-nand"; - read-only; - }; - - partition@27000000 { - reg = <0x27000000 0x19000000>; - label = "reserved-nand"; - }; - }; - - board-control@3,0 { - compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; - reg = <3 0 0x30>; - interrupt-parent = <&mpic>; - /* - * IRQ8 is generated if the "EVENT" switch is pressed - * and PX_CTL[EVESEL] is set to 00. - */ - interrupts = <8 8 0 0>; - }; - }; - - soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - - i2c@3100 { - wm8776:codec@1a { - compatible = "wlf,wm8776"; - reg = <0x1a>; - /* - * clock-frequency will be set by U-Boot if - * the clock is enabled. - */ - }; - }; - - spi@7000 { - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,s25sl12801"; - reg = <0>; - spi-max-frequency = <40000000>; /* input clock */ - - partition@0 { - label = "u-boot-spi"; - reg = <0x00000000 0x00100000>; - read-only; - }; - partition@100000 { - label = "kernel-spi"; - reg = <0x00100000 0x00500000>; - read-only; - }; - partition@600000 { - label = "dtb-spi"; - reg = <0x00600000 0x00100000>; - read-only; - }; - partition@700000 { - label = "file system-spi"; - reg = <0x00700000 0x00900000>; - }; - }; - }; - - ssi@15000 { - fsl,mode = "i2s-slave"; - codec-handle = <&wm8776>; - fsl,ssi-asynchronous; - }; - - usb@22000 { - phy_type = "ulpi"; - }; - - usb@23000 { - status = "disabled"; - }; - - mdio@24000 { - phy0: ethernet-phy@0 { - interrupts = <3 1 0 0>; - reg = <0x1>; - }; - phy1: ethernet-phy@1 { - interrupts = <9 1 0 0>; - reg = <0x2>; - }; - tbi-phy@2 { - device_type = "tbi-phy"; - reg = <0x2>; - }; - }; - - ethernet@b0000 { - phy-handle = <&phy0>; - phy-connection-type = "rgmii-id"; - }; - - ethernet@b1000 { - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; - }; - - pci0: pcie@fffe09000 { - reg = <0xf 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; - pcie@0 { - reg = <0x0 0x0 0x0 0x0 0x0>; - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci2: pcie@fffe0b000 { - reg = <0xf 0xffe0b000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "fsl/p1022si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi new file mode 100644 index 000000000000..7cdb505036bb --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds.dtsi @@ -0,0 +1,234 @@ +/* + * P1022 DS Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&board_lbc { + /* + * This node is used to access the pixis via "indirect" mode, + * which is done by writing the pixis register index to chip + * select 0 and the value to/from chip select 1. Indirect + * mode is the only way to access the pixis when DIU video + * is enabled. Note that this assumes that the first column + * of the 'ranges' property above is the chip select number. + */ + board-control@0,0 { + compatible = "fsl,p1022ds-indirect-pixis"; + reg = <0x0 0x0 1 /* CS0 */ + 0x1 0x0 1>; /* CS1 */ + interrupt-parent = <&mpic>; + interrupts = <8 0 0 0>; + }; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + reg = <0x0 0x03000000>; + label = "ramdisk-nor"; + read-only; + }; + + partition@3000000 { + reg = <0x03000000 0x00e00000>; + label = "diagnostic-nor"; + read-only; + }; + + partition@3e00000 { + reg = <0x03e00000 0x00200000>; + label = "dink-nor"; + read-only; + }; + + partition@4000000 { + reg = <0x04000000 0x00400000>; + label = "kernel-nor"; + read-only; + }; + + partition@4400000 { + reg = <0x04400000 0x03b00000>; + label = "jffs2-nor"; + }; + + partition@7f00000 { + reg = <0x07f00000 0x00080000>; + label = "dtb-nor"; + read-only; + }; + + partition@7f80000 { + reg = <0x07f80000 0x00080000>; + label = "u-boot-nor"; + read-only; + }; + }; + + nand@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elbc-fcm-nand"; + reg = <0x2 0x0 0x40000>; + + partition@0 { + reg = <0x0 0x02000000>; + label = "u-boot-nand"; + read-only; + }; + + partition@2000000 { + reg = <0x02000000 0x10000000>; + label = "jffs2-nand"; + }; + + partition@12000000 { + reg = <0x12000000 0x10000000>; + label = "ramdisk-nand"; + read-only; + }; + + partition@22000000 { + reg = <0x22000000 0x04000000>; + label = "kernel-nand"; + }; + + partition@26000000 { + reg = <0x26000000 0x01000000>; + label = "dtb-nand"; + read-only; + }; + + partition@27000000 { + reg = <0x27000000 0x19000000>; + label = "reserved-nand"; + }; + }; + + board-control@3,0 { + compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; + reg = <3 0 0x30>; + interrupt-parent = <&mpic>; + /* + * IRQ8 is generated if the "EVENT" switch is pressed + * and PX_CTL[EVESEL] is set to 00. + */ + interrupts = <8 0 0 0>; + }; +}; + +&board_soc { + i2c@3100 { + wm8776:codec@1a { + compatible = "wlf,wm8776"; + reg = <0x1a>; + /* + * clock-frequency will be set by U-Boot if + * the clock is enabled. + */ + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl12801"; + reg = <0>; + spi-max-frequency = <40000000>; /* input clock */ + + partition@0 { + label = "u-boot-spi"; + reg = <0x00000000 0x00100000>; + read-only; + }; + partition@100000 { + label = "kernel-spi"; + reg = <0x00100000 0x00500000>; + read-only; + }; + partition@600000 { + label = "dtb-spi"; + reg = <0x00600000 0x00100000>; + read-only; + }; + partition@700000 { + label = "file system-spi"; + reg = <0x00700000 0x00900000>; + }; + }; + }; + + ssi@15000 { + fsl,mode = "i2s-slave"; + codec-handle = <&wm8776>; + fsl,ssi-asynchronous; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + usb@23000 { + status = "disabled"; + }; + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupts = <3 1 0 0>; + reg = <0x1>; + }; + phy1: ethernet-phy@1 { + interrupts = <9 1 0 0>; + reg = <0x2>; + }; + tbi-phy@2 { + device_type = "tbi-phy"; + reg = <0x2>; + }; + }; + + ethernet@b0000 { + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + }; + + ethernet@b1000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; +}; diff --git a/arch/powerpc/boot/dts/p1022ds_32b.dts b/arch/powerpc/boot/dts/p1022ds_32b.dts new file mode 100644 index 000000000000..d96cae00a9e3 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds_32b.dts @@ -0,0 +1,103 @@ +/* + * P1022 DS 32-bit Physical Address Map Device Tree Source + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1022si-pre.dtsi" +/ { + model = "fsl,P1022DS"; + compatible = "fsl,P1022DS"; + + memory { + device_type = "memory"; + }; + + board_lbc: lbc: localbus@ffe05000 { + ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 + 0x1 0x0 0x0 0xe0000000 0x08000000 + 0x2 0x0 0x0 0xff800000 0x00040000 + 0x3 0x0 0x0 0xffdf0000 0x00008000>; + reg = <0x0 0xffe05000 0 0x1000>; + }; + + board_soc: soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0x0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; + reg = <0 0xffe0a000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci2: pcie@ffe0b000 { + ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + reg = <0 0xffe0b000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "fsl/p1022si-post.dtsi" +/include/ "p1022ds.dtsi" diff --git a/arch/powerpc/boot/dts/p1022ds_36b.dts b/arch/powerpc/boot/dts/p1022ds_36b.dts new file mode 100644 index 000000000000..f7aacce40bf6 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds_36b.dts @@ -0,0 +1,103 @@ +/* + * P1022 DS 36-bit Physical Address Map Device Tree Source + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1022si-pre.dtsi" +/ { + model = "fsl,P1022DS"; + compatible = "fsl,P1022DS"; + + memory { + device_type = "memory"; + }; + + board_lbc: lbc: localbus@fffe05000 { + ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 + 0x1 0x0 0xf 0xe0000000 0x08000000 + 0x2 0x0 0xf 0xff800000 0x00040000 + 0x3 0x0 0xf 0xffdf0000 0x00008000>; + reg = <0xf 0xffe05000 0 0x1000>; + }; + + board_soc: soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; + }; + + pci0: pcie@fffe09000 { + ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + reg = <0xf 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@fffe0a000 { + ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; + reg = <0xf 0xffe0a000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci2: pcie@fffe0b000 { + ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + reg = <0xf 0xffe0b000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "fsl/p1022si-post.dtsi" +/include/ "p1022ds.dtsi" diff --git a/arch/powerpc/boot/dts/p1025rdb.dtsi b/arch/powerpc/boot/dts/p1025rdb.dtsi new file mode 100644 index 000000000000..cf3676fc714b --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb.dtsi @@ -0,0 +1,286 @@ +/* + * P1025 RDB Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x1000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* This location must not be altered */ + /* 256KB for Vitesse 7385 Switch firmware */ + reg = <0x0 0x00040000>; + label = "NOR Vitesse-7385 Firmware"; + read-only; + }; + + partition@40000 { + /* 256KB for DTB Image */ + reg = <0x00040000 0x00040000>; + label = "NOR DTB Image"; + }; + + partition@80000 { + /* 3.5 MB for Linux Kernel Image */ + reg = <0x00080000 0x00380000>; + label = "NOR Linux Kernel Image"; + }; + + partition@400000 { + /* 11MB for JFFS2 based Root file System */ + reg = <0x00400000 0x00b00000>; + label = "NOR JFFS2 Root File System"; + }; + + partition@f00000 { + /* This location must not be altered */ + /* 512KB for u-boot Bootloader Image */ + /* 512KB for u-boot Environment Variables */ + reg = <0x00f00000 0x00100000>; + label = "NOR U-Boot Image"; + read-only; + }; + }; + + nand@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1025-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x1 0x0 0x40000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND DTB Image"; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND Linux Kernel Image"; + }; + + partition@600000 { + /* 4MB for Compressed Root file System Image */ + reg = <0x00600000 0x00400000>; + label = "NAND Compressed RFS Image"; + }; + + partition@a00000 { + /* 7MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00700000>; + label = "NAND JFFS2 Root File System"; + }; + + partition@1100000 { + /* 15MB for JFFS2 based Root file System */ + reg = <0x01100000 0x00f00000>; + label = "NAND Writable User area"; + }; + }; + +}; + +&soc { + i2c@3000 { + rtc@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl12801"; + reg = <0>; + spi-max-frequency = <40000000>; /* input clock */ + + partition@u-boot { + /* 512KB for u-boot Bootloader Image */ + reg = <0x0 0x00080000>; + label = "u-boot"; + read-only; + }; + + partition@dtb { + /* 512KB for DTB Image */ + reg = <0x00080000 0x00080000>; + label = "dtb"; + }; + + partition@kernel { + /* 4MB for Linux Kernel Image */ + reg = <0x00100000 0x00400000>; + label = "kernel"; + }; + + partition@fs { + /* 4MB for Compressed RFS Image */ + reg = <0x00500000 0x00400000>; + label = "file system"; + }; + + partition@jffs-fs { + /* 7MB for JFFS2 based RFS */ + reg = <0x00900000 0x00700000>; + label = "file system jffs2"; + }; + }; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + /* USB2 is shared with localbus, so it must be disabled + by default. We can't put 'status = "disabled";' here + since U-Boot doesn't clear the status property when + it enables USB2. OTOH, U-Boot does create a new node + when there isn't any. So, just comment it out. + usb@23000 { + phy_type = "ulpi"; + }; + */ + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <3 1>; + reg = <0x0>; + }; + + phy1: ethernet-phy@1 { + interrupt-parent = <&mpic>; + interrupts = <2 1>; + reg = <0x1>; + }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25000 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26000 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@b0000 { + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + + }; + + enet1: ethernet@b1000 { + phy-handle = <&phy0>; + tbi-handle = <&tbi1>; + phy-connection-type = "sgmii"; + }; + + enet2: ethernet@b2000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + + par_io@e0100 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe0100 0x60>; + ranges = <0x0 0xe0100 0x60>; + device_type = "par_io"; + num-ports = <3>; + pio1: ucc_pin@01 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */ + 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9 */ + 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */ + 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */ + 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */ + 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */ + 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */ + 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */ + 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */ + 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */ + 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */ + 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */ + 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */ + 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */ + 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */ + 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */ + }; + + pio2: ucc_pin@02 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ + 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ + 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */ + 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */ + 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */ + 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */ + 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */ + 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */ + 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */ + 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */ + }; + }; +}; diff --git a/arch/powerpc/boot/dts/p1025rdb_32b.dts b/arch/powerpc/boot/dts/p1025rdb_32b.dts new file mode 100644 index 000000000000..ac5729c14eda --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb_32b.dts @@ -0,0 +1,135 @@ +/* + * P1025 RDB Device Tree Source (32-bit address map) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1021si-pre.dtsi" +/ { + model = "fsl,P1025RDB"; + compatible = "fsl,P1025RDB"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + /* NOR, NAND Flashes */ + ranges = <0x0 0x0 0x0 0xef000000 0x01000000 + 0x1 0x0 0x0 0xff800000 0x00040000>; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + qe: qe@ffe80000 { + ranges = <0x0 0x0 0xffe80000 0x40000>; + reg = <0 0xffe80000 0 0x480>; + brg-frequency = <0>; + bus-frequency = <0>; + status = "disabled"; /* no firmware loaded */ + + enet3: ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + rx-clock-name = "clk12"; + tx-clock-name = "clk9"; + pio-handle = <&pio1>; + phy-handle = <&qe_phy0>; + phy-connection-type = "mii"; + }; + + mdio@2120 { + qe_phy0: ethernet-phy@0 { + interrupt-parent = <&mpic>; + interrupts = <4 1 0 0>; + reg = <0x6>; + device_type = "ethernet-phy"; + }; + qe_phy1: ethernet-phy@03 { + interrupt-parent = <&mpic>; + interrupts = <5 1 0 0>; + reg = <0x3>; + device_type = "ethernet-phy"; + }; + tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet4: ucc@2400 { + device_type = "network"; + compatible = "ucc_geth"; + rx-clock-name = "none"; + tx-clock-name = "clk13"; + pio-handle = <&pio2>; + phy-handle = <&qe_phy1>; + phy-connection-type = "rmii"; + }; + }; +}; + +/include/ "p1025rdb.dtsi" +/include/ "fsl/p1021si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p1025rdb_36b.dts b/arch/powerpc/boot/dts/p1025rdb_36b.dts new file mode 100644 index 000000000000..4ce4bfa0eda4 --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb_36b.dts @@ -0,0 +1,88 @@ +/* + * P1025 RDB Device Tree Source (36-bit address map) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1021si-pre.dtsi" +/ { + model = "fsl,P1025RDB"; + compatible = "fsl,P1025RDB"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@fffe05000 { + reg = <0xf 0xffe05000 0 0x1000>; + + /* NOR, NAND Flashes */ + ranges = <0x0 0x0 0xf 0xef000000 0x01000000 + 0x1 0x0 0xf 0xff800000 0x00040000>; + }; + + soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; + }; + + pci0: pcie@fffe09000 { + reg = <0xf 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xe 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "p1025rdb.dtsi" +/include/ "fsl/p1021si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p2020rdb-pc.dtsi b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi new file mode 100644 index 000000000000..c21d1c7d16cd --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi @@ -0,0 +1,241 @@ +/* + * P2020 RDB-PC Device Tree Source stub (no addresses or top-level ranges) + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +&lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x1000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* This location must not be altered */ + /* 256KB for Vitesse 7385 Switch firmware */ + reg = <0x0 0x00040000>; + label = "NOR Vitesse-7385 Firmware"; + read-only; + }; + + partition@40000 { + /* 256KB for DTB Image */ + reg = <0x00040000 0x00040000>; + label = "NOR DTB Image"; + }; + + partition@80000 { + /* 3.5 MB for Linux Kernel Image */ + reg = <0x00080000 0x00380000>; + label = "NOR Linux Kernel Image"; + }; + + partition@400000 { + /* 11MB for JFFS2 based Root file System */ + reg = <0x00400000 0x00b00000>; + label = "NOR JFFS2 Root File System"; + }; + + partition@f00000 { + /* This location must not be altered */ + /* 512KB for u-boot Bootloader Image */ + /* 512KB for u-boot Environment Variables */ + reg = <0x00f00000 0x00100000>; + label = "NOR U-Boot Image"; + read-only; + }; + }; + + nand@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p2020-fcm-nand", + "fsl,elbc-fcm-nand"; + reg = <0x1 0x0 0x40000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + + partition@100000 { + /* 1MB for DTB Image */ + reg = <0x00100000 0x00100000>; + label = "NAND DTB Image"; + }; + + partition@200000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00200000 0x00400000>; + label = "NAND Linux Kernel Image"; + }; + + partition@600000 { + /* 4MB for Compressed Root file System Image */ + reg = <0x00600000 0x00400000>; + label = "NAND Compressed RFS Image"; + }; + + partition@a00000 { + /* 7MB for JFFS2 based Root file System */ + reg = <0x00a00000 0x00700000>; + label = "NAND JFFS2 Root File System"; + }; + + partition@1100000 { + /* 15MB for JFFS2 based Root file System */ + reg = <0x01100000 0x00f00000>; + label = "NAND Writable User area"; + }; + }; + + L2switch@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "vitesse-7385"; + reg = <0x2 0x0 0x20000>; + }; + + cpld@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cpld"; + reg = <0x3 0x0 0x20000>; + read-only; + }; +}; + +&soc { + i2c@3000 { + rtc@68 { + compatible = "pericom,pt7c4338"; + reg = <0x68>; + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,m25p80"; + reg = <0>; + spi-max-frequency = <40000000>; + + partition@0 { + /* 512KB for u-boot Bootloader Image */ + reg = <0x0 0x00080000>; + label = "SPI U-Boot Image"; + read-only; + }; + + partition@80000 { + /* 512KB for DTB Image */ + reg = <0x00080000 0x00080000>; + label = "SPI DTB Image"; + }; + + partition@100000 { + /* 4MB for Linux Kernel Image */ + reg = <0x00100000 0x00400000>; + label = "SPI Linux Kernel Image"; + }; + + partition@500000 { + /* 4MB for Compressed RFS Image */ + reg = <0x00500000 0x00400000>; + label = "SPI Compressed RFS Image"; + }; + + partition@900000 { + /* 7MB for JFFS2 based RFS */ + reg = <0x00900000 0x00700000>; + label = "SPI JFFS2 RFS"; + }; + }; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + mdio@24520 { + phy0: ethernet-phy@0 { + interrupts = <3 1 0 0>; + reg = <0x0>; + }; + phy1: ethernet-phy@1 { + interrupts = <2 1 0 0>; + reg = <0x1>; + }; + }; + + mdio@25520 { + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + status = "disabled"; + }; + + ptp_clock@24e00 { + fsl,tclk-period = <5>; + fsl,tmr-prsc = <200>; + fsl,tmr-add = <0xCCCCCCCD>; + fsl,tmr-fiper1 = <0x3B9AC9FB>; + fsl,tmr-fiper2 = <0x0001869B>; + fsl,max-adj = <249999999>; + }; + + enet0: ethernet@24000 { + fixed-link = <1 1 1000 0 0>; + phy-connection-type = "rgmii-id"; + }; + + enet1: ethernet@25000 { + tbi-handle = <&tbi0>; + phy-handle = <&phy0>; + phy-connection-type = "sgmii"; + }; + + enet2: ethernet@26000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; +}; diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts new file mode 100644 index 000000000000..852e5b27485d --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts @@ -0,0 +1,96 @@ +/* + * P2020 RDB-PC 32Bit Physical Address Map Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p2020si-pre.dtsi" + +/ { + model = "fsl,P2020RDB"; + compatible = "fsl,P2020RDB-PC"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@ffe05000 { + reg = <0 0xffe05000 0 0x1000>; + + /* NOR and NAND Flashes */ + ranges = <0x0 0x0 0x0 0xef000000 0x01000000 + 0x1 0x0 0x0 0xff800000 0x00040000 + 0x2 0x0 0x0 0xffb00000 0x00020000 + 0x3 0x0 0x0 0xffa00000 0x00020000>; + }; + + soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + }; + + pci0: pcie@ffe08000 { + reg = <0 0xffe08000 0 0x1000>; + status = "disabled"; + }; + + pci1: pcie@ffe09000 { + reg = <0 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci2: pcie@ffe0a000 { + reg = <0 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "p2020rdb-pc.dtsi" +/include/ "fsl/p2020si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts new file mode 100644 index 000000000000..b5a56ca51cf7 --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts @@ -0,0 +1,96 @@ +/* + * P2020 RDB-PC 36Bit Physical Address Map Device Tree Source + * + * Copyright 2011 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p2020si-pre.dtsi" + +/ { + model = "fsl,P2020RDB"; + compatible = "fsl,P2020RDB-PC"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@fffe05000 { + reg = <0xf 0xffe05000 0 0x1000>; + + /* NOR and NAND Flashes */ + ranges = <0x0 0x0 0xf 0xef000000 0x01000000 + 0x1 0x0 0xf 0xff800000 0x00040000 + 0x2 0x0 0xf 0xffb00000 0x00020000 + 0x3 0x0 0xf 0xffa00000 0x00020000>; + }; + + soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; + }; + + pci0: pcie@fffe08000 { + reg = <0xf 0xffe08000 0 0x1000>; + status = "disabled"; + }; + + pci1: pcie@fffe09000 { + reg = <0xf 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci2: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "p2020rdb-pc.dtsi" +/include/ "fsl/p2020si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts index eb8a6aa2bda5..153bc76bb48e 100644 --- a/arch/powerpc/boot/dts/p2020rdb.dts +++ b/arch/powerpc/boot/dts/p2020rdb.dts @@ -34,7 +34,7 @@ /* NOR and NAND Flashes */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xffa00000 0x00040000 + 0x1 0x0 0x0 0xff800000 0x00040000 0x2 0x0 0x0 0xffb00000 0x00020000>; nor@0,0 { @@ -157,7 +157,7 @@ #size-cells = <1>; compatible = "spansion,s25sl12801"; reg = <0>; - spi-max-frequency = <50000000>; + spi-max-frequency = <40000000>; partition@0 { /* 512KB for u-boot Bootloader Image */ diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index f090e6d2907e..6761c746048d 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -144,6 +144,7 @@ tmp=$tmpdir/zImage.$$.o ksection=.kernel:vmlinux.strip isection=.kernel:initrd link_address='0x400000' +make_space=y case "$platform" in pseries) @@ -210,6 +211,7 @@ ps3) ksection=.kernel:vmlinux.bin isection=.kernel:initrd link_address='' + make_space=n pie= ;; ep88xc|ep405|ep8248e) @@ -278,17 +280,19 @@ else rm -f $vmz.$$ fi -# Round the size to next higher MB limit -round_size=$(((strip_size + 0xfffff) & 0xfff00000)) +if [ "$make_space" = "y" ]; then + # Round the size to next higher MB limit + round_size=$(((strip_size + 0xfffff) & 0xfff00000)) -round_size=0x$(printf "%x" $round_size) -link_addr=$(printf "%d" $link_address) + round_size=0x$(printf "%x" $round_size) + link_addr=$(printf "%d" $link_address) -if [ $link_addr -lt $strip_size ]; then - echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \ - "overlaps the address of the wrapper($link_address)" - echo "INFO: Fixing the link_address of wrapper to ($round_size)" - link_address=$round_size + if [ $link_addr -lt $strip_size ]; then + echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \ + "overlaps the address of the wrapper($link_address)" + echo "INFO: Fixing the link_address of wrapper to ($round_size)" + link_address=$round_size + fi fi vmz="$vmz$gzip" diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig new file mode 100644 index 000000000000..f8c51a4ab995 --- /dev/null +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig @@ -0,0 +1,257 @@ +CONFIG_PPC_85xx=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_SPARSE_IRQ=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_NET_NS is not set +CONFIG_SYSFS_DEPRECATED=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_PERF_EVENTS=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_GE_IMP3A=y +CONFIG_QUICC_ENGINE=y +CONFIG_QE_GPIO=y +CONFIG_CPM2=y +CONFIG_HIGHMEM=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_HZ_1000=y +CONFIG_PREEMPT=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=m +CONFIG_MATH_EMULATION=y +CONFIG_IRQ_ALL_CPUS=y +CONFIG_FORCE_MAX_ZONEORDER=17 +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCI_MSI=y +CONFIG_PCCARD=y +# CONFIG_PCMCIA_LOAD_CIS is not set +CONFIG_YENTA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET6_AH=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NET_PKTGEN=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_FSL_ELBC=y +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=131072 +CONFIG_MISC_DEVICES=y +CONFIG_DS1682=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_SIL24=y +# CONFIG_ATA_SFF is not set +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_NETCONSOLE=y +CONFIG_NETPOLL_TRAP=y +CONFIG_TUN=m +# CONFIG_NET_VENDOR_3COM is not set +CONFIG_FS_ENET=y +CONFIG_UCC_GETH=y +CONFIG_GIANFAR=y +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_QE=m +CONFIG_NVRAM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_CPM=m +CONFIG_I2C_MPC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GE_FPGA=y +CONFIG_SENSORS_LM90=y +CONFIG_SENSORS_LM92=y +CONFIG_WATCHDOG=y +CONFIG_GEF_WDT=y +CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_HID_DRAGONRISE=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_ZEROPLUS=y +CONFIG_USB=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_FSL=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PPC_OF_BE=y +CONFIG_USB_OHCI_HCD_PPC_OF_LE=y +CONFIG_USB_STORAGE=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_EDAC_MPC85XX=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_INTF_PROC is not set +CONFIG_RTC_DRV_RX8581=y +CONFIG_DMADEVICES=y +CONFIG_FSL_DMA=y +# CONFIG_NET_DMA is not set +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT4_FS=y +CONFIG_FUSE_FS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=850 +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_NTFS_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_NFSD_V4=y +CONFIG_CIFS=m +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=y +CONFIG_CRC_CCITT=y +CONFIG_CRC_T10DIF=y +CONFIG_LIBCRC32C=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DEV_TALITOS=y diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index d41857a5152d..da731c2fe984 100644 --- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig @@ -131,6 +131,7 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GE_FPGA=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig index 38303ec11bcd..2149360a1e62 100644 --- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig @@ -132,6 +132,7 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GE_FPGA=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 98533973d20f..af2e8e1edba6 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig @@ -183,6 +183,8 @@ CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GE_FPGA=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig deleted file mode 100644 index 27c46d679968..000000000000 --- a/arch/powerpc/configs/iseries_defconfig +++ /dev/null @@ -1,236 +0,0 @@ -CONFIG_PPC64=y -CONFIG_SMP=y -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_AUDIT=y -CONFIG_AUDITSYSCALL=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_BLK_DEV_INITRD=y -# CONFIG_COMPAT_BRK is not set -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -# CONFIG_PPC_PSERIES is not set -CONFIG_LPARCFG=y -CONFIG_PPC_ISERIES=y -CONFIG_VIODASD=y -CONFIG_VIOCD=m -CONFIG_VIOTAPE=m -# CONFIG_PPC_PMAC is not set -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IRQ_ALL_CPUS=y -# CONFIG_MIGRATION is not set -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_XFRM_SUB_POLICY=y -CONFIG_NET_KEY=m -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_NET_IPIP=y -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_MODE_BEET=m -# CONFIG_INET_LRO is not set -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -CONFIG_NETFILTER_NETLINK_QUEUE=m -CONFIG_NETFILTER_NETLINK_LOG=m -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_EVENTS=y -# CONFIG_NF_CT_PROTO_SCTP is not set -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=m -CONFIG_NETFILTER_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_DSCP=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_IPRANGE=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_OWNER=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_RATEEST=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_TIME=m -CONFIG_NF_CONNTRACK_IPV4=m -CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_PROC_DEVICETREE=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=65536 -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCSI_FC_ATTRS=y -CONFIG_SCSI_SAS_LIBSAS=m -CONFIG_SCSI_IBMVSCSI=m -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_RAID0=y -CONFIG_MD_RAID1=y -CONFIG_MD_RAID10=m -CONFIG_MD_MULTIPATH=m -CONFIG_MD_FAULTY=m -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=m -CONFIG_DM_SNAPSHOT=m -CONFIG_DM_MIRROR=m -CONFIG_DM_ZERO=m -CONFIG_NETDEVICES=y -CONFIG_DUMMY=m -CONFIG_BONDING=m -CONFIG_TUN=m -CONFIG_NET_ETHERNET=y -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -CONFIG_E100=y -CONFIG_ACENIC=m -CONFIG_E1000=m -CONFIG_ISERIES_VETH=y -CONFIG_PPP=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_NETCONSOLE=y -CONFIG_NETPOLL_TRAP=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_ICOM=m -# CONFIG_HW_RANDOM is not set -CONFIG_GEN_RTC=y -CONFIG_RAW_DRIVER=y -# CONFIG_HWMON is not set -# CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT2_FS_XIP=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=y -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y -CONFIG_JFS_FS=m -CONFIG_JFS_POSIX_ACL=y -CONFIG_JFS_SECURITY=y -CONFIG_XFS_FS=m -CONFIG_XFS_POSIX_ACL=y -CONFIG_GFS2_FS=m -CONFIG_AUTOFS_FS=m -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_NFSD=m -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_RPCSEC_GSS_SPKM3=m -CONFIG_CIFS=m -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_DLM=m -CONFIG_CRC_T10DIF=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_LATENCYTOP=y -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_DEBUG_STACK_USAGE=y -CONFIG_CRYPTO_NULL=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SEED=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -# CONFIG_CRYPTO_ANSI_CPRNG is not set -# CONFIG_CRYPTO_HW is not set diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig index 2a1320fb2723..6640a35bebb7 100644 --- a/arch/powerpc/configs/mpc5200_defconfig +++ b/arch/powerpc/configs/mpc5200_defconfig @@ -1,8 +1,8 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -13,15 +13,12 @@ CONFIG_PPC_EFIKA=y CONFIG_PPC_LITE5200=y CONFIG_PPC_MEDIA5200=y CONFIG_PPC_MPC5200_BUGFIX=y -CONFIG_PPC_MPC5200_GPIO=y CONFIG_PPC_MPC5200_LPBFIFO=m # CONFIG_PPC_PMAC is not set CONFIG_PPC_BESTCOMM=y CONFIG_SIMPLE_GPIO=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y -CONFIG_SPARSE_IRQ=y -CONFIG_PM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -36,23 +33,20 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y -CONFIG_MTD_CONCAT=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_OF_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_RAM=y CONFIG_MTD_ROM=y CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_PLATRAM=y CONFIG_MTD_UBI=m CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT24=y CONFIG_SCSI_TGT=y CONFIG_BLK_DEV_SD=y @@ -61,11 +55,10 @@ CONFIG_ATA=y CONFIG_PATA_MPC52xx=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y -CONFIG_LXT_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FEC_MPC52xx=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_AMD_PHY=y +CONFIG_LXT_PHY=y +CONFIG_FIXED_PHY=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set @@ -80,11 +73,17 @@ CONFIG_SPI_GPIO=m CONFIG_SPI_MPC52xx=m CONFIG_SPI_MPC52xx_PSC=m CONFIG_SPI_SPIDEV=m +CONFIG_GPIO_SYSFS=y +CONFIG_SENSORS_LM80=y +CONFIG_SENSORS_LM87=m CONFIG_WATCHDOG=y +CONFIG_MFD_SM501=m CONFIG_DRM=y CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y +CONFIG_FB_FOREIGN_ENDIAN=y CONFIG_FB_RADEON=y +CONFIG_FB_SM501=m # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y @@ -124,10 +123,11 @@ CONFIG_USB_STORAGE=y CONFIG_NEW_LEDS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_DS1374=y +CONFIG_RTC_DRV_PCF8563=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -145,5 +145,4 @@ CONFIG_PRINTK_TIME=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index f37a2ab48881..5fb0c8a94811 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -1,4 +1,5 @@ CONFIG_PPC_85xx=y +CONFIG_PHYS_64BIT=y CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index abdcd317cda7..fb51bc90edd2 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -1,4 +1,5 @@ CONFIG_PPC_85xx=y +CONFIG_PHYS_64BIT=y CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_EXPERIMENTAL=y diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h index 5ab0b71531be..9d92ba04b033 100644 --- a/arch/powerpc/include/asm/abs_addr.h +++ b/arch/powerpc/include/asm/abs_addr.h @@ -17,7 +17,6 @@ #include <asm/types.h> #include <asm/page.h> #include <asm/prom.h> -#include <asm/firmware.h> struct mschunks_map { unsigned long num_chunks; @@ -46,30 +45,12 @@ static inline unsigned long addr_to_chunk(unsigned long addr) static inline unsigned long phys_to_abs(unsigned long pa) { - unsigned long chunk; - - /* This is a no-op on non-iSeries */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return pa; - - chunk = addr_to_chunk(pa); - - if (chunk < mschunks_map.num_chunks) - chunk = mschunks_map.mapping[chunk]; - - return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK); + return pa; } /* Convenience macros */ #define virt_to_abs(va) phys_to_abs(__pa(va)) #define abs_to_virt(aa) __va(aa) -/* - * Converts Virtual Address to Real Address for - * Legacy iSeries Hypervisor calls - */ -#define iseries_hv_addr(virtaddr) \ - (0x8000000000000000UL | virt_to_abs(virtaddr)) - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_ABS_ADDR_H */ diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 02e41b53488d..14174e838ad9 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -212,6 +212,36 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return t; } +/** + * atomic_inc_not_zero - increment unless the number is zero + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1, so long as @v is non-zero. + * Returns non-zero if @v was non-zero, and zero otherwise. + */ +static __inline__ int atomic_inc_not_zero(atomic_t *v) +{ + int t1, t2; + + __asm__ __volatile__ ( + PPC_ATOMIC_ENTRY_BARRIER +"1: lwarx %0,0,%2 # atomic_inc_not_zero\n\ + cmpwi 0,%0,0\n\ + beq- 2f\n\ + addic %1,%0,1\n" + PPC405_ERR77(0,%2) +" stwcx. %1,0,%2\n\ + bne- 1b\n" + PPC_ATOMIC_EXIT_BARRIER + "\n\ +2:" + : "=&r" (t1), "=&r" (t2) + : "r" (&v->counter) + : "cc", "xer", "memory"); + + return t1; +} +#define atomic_inc_not_zero(v) atomic_inc_not_zero((v)) #define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) #define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) @@ -467,7 +497,34 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) return t != u; } -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +/** + * atomic_inc64_not_zero - increment unless the number is zero + * @v: pointer of type atomic64_t + * + * Atomically increments @v by 1, so long as @v is non-zero. + * Returns non-zero if @v was non-zero, and zero otherwise. + */ +static __inline__ long atomic64_inc_not_zero(atomic64_t *v) +{ + long t1, t2; + + __asm__ __volatile__ ( + PPC_ATOMIC_ENTRY_BARRIER +"1: ldarx %0,0,%2 # atomic64_inc_not_zero\n\ + cmpdi 0,%0,0\n\ + beq- 2f\n\ + addic %1,%0,1\n\ + stdcx. %1,0,%2\n\ + bne- 1b\n" + PPC_ATOMIC_EXIT_BARRIER + "\n\ +2:" + : "=&r" (t1), "=&r" (t2) + : "r" (&v->counter) + : "cc", "xer", "memory"); + + return t1; +} #endif /* __powerpc64__ */ diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index ad55a1ccb9fb..b9219e99bd2a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -390,6 +390,10 @@ extern const char *powerpc_base_platform; CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ CPU_FTR_DEBUG_LVL_EXC) +#define CPU_FTRS_E6500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ + CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ + CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ + CPU_FTR_DEBUG_LVL_EXC) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) /* 64-bit CPUs */ @@ -442,7 +446,7 @@ extern const char *powerpc_base_platform; #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2) +#define CPU_FTRS_POSSIBLE (CPU_FTRS_E6500 | CPU_FTRS_E5500 | CPU_FTRS_A2) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ @@ -483,7 +487,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | - CPU_FTRS_E5500 | + CPU_FTRS_E5500 | CPU_FTRS_E6500 | #endif 0, }; @@ -491,7 +495,7 @@ enum { #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2) +#define CPU_FTRS_ALWAYS (CPU_FTRS_E6500 & CPU_FTRS_E5500 & CPU_FTRS_A2) #else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ @@ -528,7 +532,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & - CPU_FTRS_E5500 & + CPU_FTRS_E5500 & CPU_FTRS_E6500 & #endif CPU_FTRS_POSSIBLE, }; diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index d57c08acedfc..63d5ca49cece 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h @@ -31,6 +31,9 @@ struct dev_archdata { #ifdef CONFIG_SWIOTLB dma_addr_t max_direct_dma_addr; #endif +#ifdef CONFIG_EEH + struct eeh_dev *edev; +#endif }; struct pdev_archdata { diff --git a/arch/powerpc/include/asm/dma.h b/arch/powerpc/include/asm/dma.h index a7e06e25c708..adadb9943610 100644 --- a/arch/powerpc/include/asm/dma.h +++ b/arch/powerpc/include/asm/dma.h @@ -34,8 +34,6 @@ /* Doesn't really apply... */ #define MAX_DMA_ADDRESS (~0UL) -#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) - #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER #define dma_outb outb_p #else @@ -354,7 +352,5 @@ extern int isa_dma_bridge_buggy; #define isa_dma_bridge_buggy (0) #endif -#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_DMA_H */ diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 66ea9b8b95c5..d60f99814ffb 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -1,6 +1,6 @@ /* - * eeh.h * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. + * Copyright 2001-2012 IBM 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 @@ -31,44 +31,105 @@ struct device_node; #ifdef CONFIG_EEH -extern int eeh_subsystem_enabled; +/* + * The struct is used to trace EEH state for the associated + * PCI device node or PCI device. In future, it might + * represent PE as well so that the EEH device to form + * another tree except the currently existing tree of PCI + * buses and PCI devices + */ +#define EEH_MODE_SUPPORTED (1<<0) /* EEH supported on the device */ +#define EEH_MODE_NOCHECK (1<<1) /* EEH check should be skipped */ +#define EEH_MODE_ISOLATED (1<<2) /* The device has been isolated */ +#define EEH_MODE_RECOVERING (1<<3) /* Recovering the device */ +#define EEH_MODE_IRQ_DISABLED (1<<4) /* Interrupt disabled */ + +struct eeh_dev { + int mode; /* EEH mode */ + int class_code; /* Class code of the device */ + int config_addr; /* Config address */ + int pe_config_addr; /* PE config address */ + int check_count; /* Times of ignored error */ + int freeze_count; /* Times of froze up */ + int false_positives; /* Times of reported #ff's */ + u32 config_space[16]; /* Saved PCI config space */ + struct pci_controller *phb; /* Associated PHB */ + struct device_node *dn; /* Associated device node */ + struct pci_dev *pdev; /* Associated PCI device */ +}; + +static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev) +{ + return edev->dn; +} + +static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) +{ + return edev->pdev; +} -/* Values for eeh_mode bits in device_node */ -#define EEH_MODE_SUPPORTED (1<<0) -#define EEH_MODE_NOCHECK (1<<1) -#define EEH_MODE_ISOLATED (1<<2) -#define EEH_MODE_RECOVERING (1<<3) -#define EEH_MODE_IRQ_DISABLED (1<<4) +/* + * The struct is used to trace the registered EEH operation + * callback functions. Actually, those operation callback + * functions are heavily platform dependent. That means the + * platform should register its own EEH operation callback + * functions before any EEH further operations. + */ +#define EEH_OPT_DISABLE 0 /* EEH disable */ +#define EEH_OPT_ENABLE 1 /* EEH enable */ +#define EEH_OPT_THAW_MMIO 2 /* MMIO enable */ +#define EEH_OPT_THAW_DMA 3 /* DMA enable */ +#define EEH_STATE_UNAVAILABLE (1 << 0) /* State unavailable */ +#define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */ +#define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */ +#define EEH_STATE_MMIO_ACTIVE (1 << 3) /* Active MMIO */ +#define EEH_STATE_DMA_ACTIVE (1 << 4) /* Active DMA */ +#define EEH_STATE_MMIO_ENABLED (1 << 5) /* MMIO enabled */ +#define EEH_STATE_DMA_ENABLED (1 << 6) /* DMA enabled */ +#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */ +#define EEH_RESET_HOT 1 /* Hot reset */ +#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */ +#define EEH_LOG_TEMP 1 /* EEH temporary error log */ +#define EEH_LOG_PERM 2 /* EEH permanent error log */ + +struct eeh_ops { + char *name; + int (*init)(void); + int (*set_option)(struct device_node *dn, int option); + int (*get_pe_addr)(struct device_node *dn); + int (*get_state)(struct device_node *dn, int *state); + int (*reset)(struct device_node *dn, int option); + int (*wait_state)(struct device_node *dn, int max_wait); + int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len); + int (*configure_bridge)(struct device_node *dn); + int (*read_config)(struct device_node *dn, int where, int size, u32 *val); + int (*write_config)(struct device_node *dn, int where, int size, u32 val); +}; + +extern struct eeh_ops *eeh_ops; +extern int eeh_subsystem_enabled; -/* Max number of EEH freezes allowed before we consider the device - * to be permanently disabled. */ +/* + * Max number of EEH freezes allowed before we consider the device + * to be permanently disabled. + */ #define EEH_MAX_ALLOWED_FREEZES 5 +void * __devinit eeh_dev_init(struct device_node *dn, void *data); +void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); +void __init eeh_dev_phb_init(void); void __init eeh_init(void); +#ifdef CONFIG_PPC_PSERIES +int __init eeh_pseries_init(void); +#endif +int __init eeh_ops_register(struct eeh_ops *ops); +int __exit eeh_ops_unregister(const char *name); unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val); int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); void __init pci_addr_cache_build(void); - -/** - * eeh_add_device_early - * eeh_add_device_late - * - * Perform eeh initialization for devices added after boot. - * Call eeh_add_device_early before doing any i/o to the - * device (including config space i/o). Call eeh_add_device_late - * to finish the eeh setup for this device. - */ void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_tree_late(struct pci_bus *); - -/** - * eeh_remove_device_recursive - undo EEH for device & children. - * @dev: pci device to be removed - * - * As above, this removes the device; it also removes child - * pci devices as well. - */ void eeh_remove_bus_device(struct pci_dev *); /** @@ -87,8 +148,25 @@ void eeh_remove_bus_device(struct pci_dev *); #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) #else /* !CONFIG_EEH */ + +static inline void *eeh_dev_init(struct device_node *dn, void *data) +{ + return NULL; +} + +static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } + +static inline void eeh_dev_phb_init(void) { } + static inline void eeh_init(void) { } +#ifdef CONFIG_PPC_PSERIES +static inline int eeh_pseries_init(void) +{ + return 0; +} +#endif /* CONFIG_PPC_PSERIES */ + static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) { return val; diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h index cc3cb04539ac..c68b012b7797 100644 --- a/arch/powerpc/include/asm/eeh_event.h +++ b/arch/powerpc/include/asm/eeh_event.h @@ -1,6 +1,4 @@ /* - * eeh_event.h - * * 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 @@ -22,32 +20,19 @@ #define ASM_POWERPC_EEH_EVENT_H #ifdef __KERNEL__ -/** EEH event -- structure holding pci controller data that describes - * a change in the isolation status of a PCI slot. A pointer - * to this struct is passed as the data pointer in a notify callback. +/* + * structure holding pci controller data that describes a + * change in the isolation status of a PCI slot. A pointer + * to this struct is passed as the data pointer in a notify + * callback. */ struct eeh_event { - struct list_head list; - struct device_node *dn; /* struct device node */ - struct pci_dev *dev; /* affected device */ + struct list_head list; /* to form event queue */ + struct eeh_dev *edev; /* EEH device */ }; -/** - * eeh_send_failure_event - generate a PCI error event - * @dev pci device - * - * This routine builds a PCI error event which will be delivered - * to all listeners on the eeh_notifier_chain. - * - * This routine can be called within an interrupt context; - * the actual event will be delivered in a normal context - * (from a workqueue). - */ -int eeh_send_failure_event (struct device_node *dn, - struct pci_dev *dev); - -/* Main recovery function */ -struct pci_dn * handle_eeh_events (struct eeh_event *); +int eeh_send_failure_event(struct eeh_dev *edev); +struct eeh_dev *handle_eeh_events(struct eeh_event *); #endif /* __KERNEL__ */ #endif /* ASM_POWERPC_EEH_EVENT_H */ diff --git a/arch/powerpc/include/asm/ehv_pic.h b/arch/powerpc/include/asm/ehv_pic.h index a9e1f4f796f6..dc7d48e3ea90 100644 --- a/arch/powerpc/include/asm/ehv_pic.h +++ b/arch/powerpc/include/asm/ehv_pic.h @@ -25,7 +25,7 @@ struct ehv_pic { /* The remapper for this EHV_PIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; /* The "linux" controller struct */ struct irq_chip hc_irq; diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 8057f4f6980f..548da3aa0a30 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -232,23 +232,30 @@ label##_hv: \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ EXC_HV, KVMTEST, vec) -#define __SOFTEN_TEST(h) \ +/* This associate vector numbers with bits in paca->irq_happened */ +#define SOFTEN_VALUE_0x500 PACA_IRQ_EE +#define SOFTEN_VALUE_0x502 PACA_IRQ_EE +#define SOFTEN_VALUE_0x900 PACA_IRQ_DEC +#define SOFTEN_VALUE_0x982 PACA_IRQ_DEC + +#define __SOFTEN_TEST(h, vec) \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi r10,0; \ + li r10,SOFTEN_VALUE_##vec; \ beq masked_##h##interrupt -#define _SOFTEN_TEST(h) __SOFTEN_TEST(h) +#define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec) #define SOFTEN_TEST_PR(vec) \ KVMTEST_PR(vec); \ - _SOFTEN_TEST(EXC_STD) + _SOFTEN_TEST(EXC_STD, vec) #define SOFTEN_TEST_HV(vec) \ KVMTEST(vec); \ - _SOFTEN_TEST(EXC_HV) + _SOFTEN_TEST(EXC_HV, vec) #define SOFTEN_TEST_HV_201(vec) \ KVMTEST(vec); \ - _SOFTEN_TEST(EXC_STD) + _SOFTEN_TEST(EXC_STD, vec) #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ HMT_MEDIUM; \ @@ -272,73 +279,55 @@ label##_hv: \ _MASKABLE_EXCEPTION_PSERIES(vec, label, \ EXC_HV, SOFTEN_TEST_HV) -#ifdef CONFIG_PPC_ISERIES -#define DISABLE_INTS \ - li r11,0; \ - stb r11,PACASOFTIRQEN(r13); \ -BEGIN_FW_FTR_SECTION; \ - stb r11,PACAHARDIRQEN(r13); \ -END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ - TRACE_DISABLE_INTS; \ -BEGIN_FW_FTR_SECTION; \ - mfmsr r10; \ - ori r10,r10,MSR_EE; \ - mtmsrd r10,1; \ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#else -#define DISABLE_INTS \ - li r11,0; \ - stb r11,PACASOFTIRQEN(r13); \ - stb r11,PACAHARDIRQEN(r13); \ - TRACE_DISABLE_INTS -#endif /* CONFIG_PPC_ISERIES */ +/* + * Our exception common code can be passed various "additions" + * to specify the behaviour of interrupts, whether to kick the + * runlatch, etc... + */ + +/* Exception addition: Hard disable interrupts */ +#define DISABLE_INTS SOFT_DISABLE_INTS(r10,r11) +/* Exception addition: Keep interrupt state */ #define ENABLE_INTS \ + ld r11,PACAKMSR(r13); \ ld r12,_MSR(r1); \ - mfmsr r11; \ rlwimi r11,r12,0,MSR_EE; \ mtmsrd r11,1 -#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - DISABLE_INTS; \ - bl .save_nvgprs; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except +#define ADD_NVGPRS \ + bl .save_nvgprs + +#define RUNLATCH_ON \ +BEGIN_FTR_SECTION \ + clrrdi r3,r1,THREAD_SHIFT; \ + ld r4,TI_LOCAL_FLAGS(r3); \ + andi. r0,r4,_TLF_RUNLATCH; \ + beql ppc64_runlatch_on_trampoline; \ +END_FTR_SECTION_IFSET(CPU_FTR_CTRL) + +#define EXCEPTION_COMMON(trap, label, hdlr, ret, additions) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + additions; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b ret + +#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ + EXCEPTION_COMMON(trap, label, hdlr, ret_from_except, \ + ADD_NVGPRS;DISABLE_INTS) /* * Like STD_EXCEPTION_COMMON, but for exceptions that can occur - * in the idle task and therefore need the special idle handling. + * in the idle task and therefore need the special idle handling + * (finish nap and runlatch) */ -#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - FINISH_NAP; \ - DISABLE_INTS; \ - bl .save_nvgprs; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except - -#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - FINISH_NAP; \ - DISABLE_INTS; \ -BEGIN_FTR_SECTION \ - bl .ppc64_runlatch_on; \ -END_FTR_SECTION_IFSET(CPU_FTR_CTRL) \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except_lite +#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr) \ + EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \ + FINISH_NAP;RUNLATCH_ON;DISABLE_INTS) /* * When the idle code in power4_idle puts the CPU into NAP mode, diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h new file mode 100644 index 000000000000..88dbf9659185 --- /dev/null +++ b/arch/powerpc/include/asm/fadump.h @@ -0,0 +1,218 @@ +/* + * Firmware Assisted dump header file. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2011 IBM Corporation + * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> + */ + +#ifndef __PPC64_FA_DUMP_H__ +#define __PPC64_FA_DUMP_H__ + +#ifdef CONFIG_FA_DUMP + +/* + * The RMA region will be saved for later dumping when kernel crashes. + * RMA is Real Mode Area, the first block of logical memory address owned + * by logical partition, containing the storage that may be accessed with + * translate off. + */ +#define RMA_START 0x0 +#define RMA_END (ppc64_rma_size) + +/* + * On some Power systems where RMO is 128MB, it still requires minimum of + * 256MB for kernel to boot successfully. When kdump infrastructure is + * configured to save vmcore over network, we run into OOM issue while + * loading modules related to network setup. Hence we need aditional 64M + * of memory to avoid OOM issue. + */ +#define MIN_BOOT_MEM (((RMA_END < (0x1UL << 28)) ? (0x1UL << 28) : RMA_END) \ + + (0x1UL << 26)) + +#define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt) + +#ifndef ELF_CORE_EFLAGS +#define ELF_CORE_EFLAGS 0 +#endif + +/* Firmware provided dump sections */ +#define FADUMP_CPU_STATE_DATA 0x0001 +#define FADUMP_HPTE_REGION 0x0002 +#define FADUMP_REAL_MODE_REGION 0x0011 + +/* Dump request flag */ +#define FADUMP_REQUEST_FLAG 0x00000001 + +/* FAD commands */ +#define FADUMP_REGISTER 1 +#define FADUMP_UNREGISTER 2 +#define FADUMP_INVALIDATE 3 + +/* Dump status flag */ +#define FADUMP_ERROR_FLAG 0x2000 + +#define FADUMP_CPU_ID_MASK ((1UL << 32) - 1) + +#define CPU_UNKNOWN (~((u32)0)) + +/* Utility macros */ +#define SKIP_TO_NEXT_CPU(reg_entry) \ +({ \ + while (reg_entry->reg_id != REG_ID("CPUEND")) \ + reg_entry++; \ + reg_entry++; \ +}) + +/* Kernel Dump section info */ +struct fadump_section { + u32 request_flag; + u16 source_data_type; + u16 error_flags; + u64 source_address; + u64 source_len; + u64 bytes_dumped; + u64 destination_address; +}; + +/* ibm,configure-kernel-dump header. */ +struct fadump_section_header { + u32 dump_format_version; + u16 dump_num_sections; + u16 dump_status_flag; + u32 offset_first_dump_section; + + /* Fields for disk dump option. */ + u32 dd_block_size; + u64 dd_block_offset; + u64 dd_num_blocks; + u32 dd_offset_disk_path; + + /* Maximum time allowed to prevent an automatic dump-reboot. */ + u32 max_time_auto; +}; + +/* + * Firmware Assisted dump memory structure. This structure is required for + * registering future kernel dump with power firmware through rtas call. + * + * No disk dump option. Hence disk dump path string section is not included. + */ +struct fadump_mem_struct { + struct fadump_section_header header; + + /* Kernel dump sections */ + struct fadump_section cpu_state_data; + struct fadump_section hpte_region; + struct fadump_section rmr_region; +}; + +/* Firmware-assisted dump configuration details. */ +struct fw_dump { + unsigned long cpu_state_data_size; + unsigned long hpte_region_size; + unsigned long boot_memory_size; + unsigned long reserve_dump_area_start; + unsigned long reserve_dump_area_size; + /* cmd line option during boot */ + unsigned long reserve_bootvar; + + unsigned long fadumphdr_addr; + unsigned long cpu_notes_buf; + unsigned long cpu_notes_buf_size; + + int ibm_configure_kernel_dump; + + unsigned long fadump_enabled:1; + unsigned long fadump_supported:1; + unsigned long dump_active:1; + unsigned long dump_registered:1; +}; + +/* + * Copy the ascii values for first 8 characters from a string into u64 + * variable at their respective indexes. + * e.g. + * The string "FADMPINF" will be converted into 0x4641444d50494e46 + */ +static inline u64 str_to_u64(const char *str) +{ + u64 val = 0; + int i; + + for (i = 0; i < sizeof(val); i++) + val = (*str) ? (val << 8) | *str++ : val << 8; + return val; +} +#define STR_TO_HEX(x) str_to_u64(x) +#define REG_ID(x) str_to_u64(x) + +#define FADUMP_CRASH_INFO_MAGIC STR_TO_HEX("FADMPINF") +#define REGSAVE_AREA_MAGIC STR_TO_HEX("REGSAVE") + +/* The firmware-assisted dump format. + * + * The register save area is an area in the partition's memory used to preserve + * the register contents (CPU state data) for the active CPUs during a firmware + * assisted dump. The dump format contains register save area header followed + * by register entries. Each list of registers for a CPU starts with + * "CPUSTRT" and ends with "CPUEND". + */ + +/* Register save area header. */ +struct fadump_reg_save_area_header { + u64 magic_number; + u32 version; + u32 num_cpu_offset; +}; + +/* Register entry. */ +struct fadump_reg_entry { + u64 reg_id; + u64 reg_value; +}; + +/* fadump crash info structure */ +struct fadump_crash_info_header { + u64 magic_number; + u64 elfcorehdr_addr; + u32 crashing_cpu; + struct pt_regs regs; + struct cpumask cpu_online_mask; +}; + +/* Crash memory ranges */ +#define INIT_CRASHMEM_RANGES (INIT_MEMBLOCK_REGIONS + 2) + +struct fad_crash_memory_ranges { + unsigned long long base; + unsigned long long size; +}; + +extern int early_init_dt_scan_fw_dump(unsigned long node, + const char *uname, int depth, void *data); +extern int fadump_reserve_mem(void); +extern int setup_fadump(void); +extern int is_fadump_active(void); +extern void crash_fadump(struct pt_regs *, const char *); +extern void fadump_cleanup(void); + +extern void vmcore_cleanup(void); +#else /* CONFIG_FA_DUMP */ +static inline int is_fadump_active(void) { return 0; } +static inline void crash_fadump(struct pt_regs *regs, const char *str) { } +#endif +#endif diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 14db29b18d0e..ad0b751b0d78 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -41,7 +41,6 @@ #define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000) #define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000) #define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000) -#define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000) #define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000) #define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000) #define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) @@ -65,8 +64,6 @@ enum { FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, FW_FEATURE_PSERIES_ALWAYS = 0, - FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, - FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2, FW_FEATURE_POWERNV_ALWAYS = 0, FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1, @@ -79,9 +76,6 @@ enum { #ifdef CONFIG_PPC_PSERIES FW_FEATURE_PSERIES_POSSIBLE | #endif -#ifdef CONFIG_PPC_ISERIES - FW_FEATURE_ISERIES_POSSIBLE | -#endif #ifdef CONFIG_PPC_POWERNV FW_FEATURE_POWERNV_POSSIBLE | #endif @@ -99,9 +93,6 @@ enum { #ifdef CONFIG_PPC_PSERIES FW_FEATURE_PSERIES_ALWAYS & #endif -#ifdef CONFIG_PPC_ISERIES - FW_FEATURE_ISERIES_ALWAYS & -#endif #ifdef CONFIG_PPC_POWERNV FW_FEATURE_POWERNV_ALWAYS & #endif diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index bebd12463ec9..ce04530d2000 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -4,7 +4,7 @@ * Authors: Jeff Brown * Timur Tabi <timur@freescale.com> * - * Copyright 2004,2007 Freescale Semiconductor, Inc + * Copyright 2004,2007,2012 Freescale Semiconductor, Inc * * 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 @@ -114,6 +114,10 @@ struct ccsr_guts_86xx { __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ } __attribute__ ((packed)); + +/* Alternate function signal multiplex control */ +#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x)) + #ifdef CONFIG_PPC_86xx #define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */ diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index dbc264010d0b..caaf6e00630d 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -79,7 +79,7 @@ static inline void kunmap(struct page *page) kunmap_high(page); } -static inline void *__kmap_atomic(struct page *page) +static inline void *kmap_atomic(struct page *page) { return kmap_atomic_prot(page, kmap_prot); } diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index bb712c9488b3..51010bfc792e 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -11,6 +11,27 @@ #include <asm/ptrace.h> #include <asm/processor.h> +#ifdef CONFIG_PPC64 + +/* + * PACA flags in paca->irq_happened. + * + * This bits are set when interrupts occur while soft-disabled + * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS + * is set whenever we manually hard disable. + */ +#define PACA_IRQ_HARD_DIS 0x01 +#define PACA_IRQ_DBELL 0x02 +#define PACA_IRQ_EE 0x04 +#define PACA_IRQ_DEC 0x08 /* Or FIT */ +#define PACA_IRQ_EE_EDGE 0x10 /* BookE only */ + +#endif /* CONFIG_PPC64 */ + +#ifndef __ASSEMBLY__ + +extern void __replay_interrupt(unsigned int vector); + extern void timer_interrupt(struct pt_regs *); #ifdef CONFIG_PPC64 @@ -42,7 +63,6 @@ static inline unsigned long arch_local_irq_disable(void) } extern void arch_local_irq_restore(unsigned long); -extern void iseries_handle_interrupts(void); static inline void arch_local_irq_enable(void) { @@ -68,16 +88,33 @@ static inline bool arch_irqs_disabled(void) #define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory"); #define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory"); #else -#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) -#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) +#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) +#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) #endif -#define hard_irq_disable() \ - do { \ - __hard_irq_disable(); \ - get_paca()->soft_enabled = 0; \ - get_paca()->hard_enabled = 0; \ - } while(0) +static inline void hard_irq_disable(void) +{ + __hard_irq_disable(); + get_paca()->soft_enabled = 0; + get_paca()->irq_happened |= PACA_IRQ_HARD_DIS; +} + +/* + * This is called by asynchronous interrupts to conditionally + * re-enable hard interrupts when soft-disabled after having + * cleared the source of the interrupt + */ +static inline void may_hard_irq_enable(void) +{ + get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS; + if (!(get_paca()->irq_happened & PACA_IRQ_EE)) + __hard_irq_enable(); +} + +static inline bool arch_irq_disabled_regs(struct pt_regs *regs) +{ + return !regs->softe; +} #else /* CONFIG_PPC64 */ @@ -139,6 +176,13 @@ static inline bool arch_irqs_disabled(void) #define hard_irq_disable() arch_local_irq_disable() +static inline bool arch_irq_disabled_regs(struct pt_regs *regs) +{ + return !(regs->msr & MSR_EE); +} + +static inline void may_hard_irq_enable(void) { } + #endif /* CONFIG_PPC64 */ #define ARCH_IRQ_INIT_FLAGS IRQ_NOREQUEST @@ -149,5 +193,6 @@ static inline bool arch_irqs_disabled(void) */ struct irq_chip; +#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HW_IRQ_H */ diff --git a/arch/powerpc/include/asm/i8259.h b/arch/powerpc/include/asm/i8259.h index 105ade297aad..c3fdfbd5a673 100644 --- a/arch/powerpc/include/asm/i8259.h +++ b/arch/powerpc/include/asm/i8259.h @@ -6,7 +6,7 @@ extern void i8259_init(struct device_node *node, unsigned long intack_addr); extern unsigned int i8259_irq(void); -extern struct irq_host *i8259_get_host(void); +extern struct irq_domain *i8259_get_host(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_I8259_H */ diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index c0e1bc319e35..fe0b09dceb7d 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ +#include <linux/irqdomain.h> #include <linux/threads.h> #include <linux/list.h> #include <linux/radix-tree.h> @@ -35,258 +36,12 @@ extern atomic_t ppc_n_lost_interrupts; /* Total number of virq in the platform */ #define NR_IRQS CONFIG_NR_IRQS -/* Number of irqs reserved for the legacy controller */ -#define NUM_ISA_INTERRUPTS 16 - /* Same thing, used by the generic IRQ code */ #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -/* Interrupt controller "host" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The host - * structure is generally created by the PIC code for a given PIC instance - * (though a host can cover more than one PIC if they have a flat number - * model). It's the host callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures are fairly agnostic to the fact that - * we use an open firmware device-tree. We do have references to struct - * device_node in two places: in irq_find_host() to find the host matching - * a given interrupt controller node, and of course as an argument to its - * counterpart host->ops->match() callback. However, those are treated as - * generic pointers by the core and the fact that it's actually a device-node - * pointer is purely a convention between callers and implementation. This - * code could thus be used on other architectures by replacing those two - * by some sort of arch-specific void * "token" used to identify interrupt - * controllers. - */ -struct irq_host; -struct radix_tree_root; - -/* Functions below are provided by the host and called whenever a new mapping - * is created or an old mapping is disposed. The host can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_host_ops { - /* Match an interrupt controller device node to a host, returns - * 1 on a match - */ - int (*match)(struct irq_host *h, struct device_node *node); - - /* Create or update a mapping between a virtual irq number and a hw - * irq number. This is called only once for a given mapping. - */ - int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - - /* Dispose of such a mapping */ - void (*unmap)(struct irq_host *h, unsigned int virq); - - /* Translate device-tree interrupt specifier from raw format coming - * from the firmware to a irq_hw_number_t (interrupt line number) and - * type (sense) that can be passed to set_irq_type(). In the absence - * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() - * will return the hw number in the first cell and IRQ_TYPE_NONE for - * the type (which amount to keeping whatever default value the - * interrupt controller has for that line) - */ - int (*xlate)(struct irq_host *h, struct device_node *ctrler, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); -}; - -struct irq_host { - struct list_head link; - - /* type of reverse mapping technique */ - unsigned int revmap_type; -#define IRQ_HOST_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */ -#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ -#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ -#define IRQ_HOST_MAP_TREE 3 /* radix tree */ - union { - struct { - unsigned int size; - unsigned int *revmap; - } linear; - struct radix_tree_root tree; - } revmap_data; - struct irq_host_ops *ops; - void *host_data; - irq_hw_number_t inval_irq; - - /* Optional device node pointer */ - struct device_node *of_node; -}; - struct irq_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); -extern bool virq_is_host(unsigned int virq, struct irq_host *host); - -/** - * irq_alloc_host - Allocate a new irq_host data structure - * @of_node: optional device-tree node of the interrupt controller - * @revmap_type: type of reverse mapping to use - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map - * @ops: map/unmap host callbacks - * @inval_irq: provide a hw number in that host space that is always invalid - * - * Allocates and initialize and irq_host structure. Note that in the case of - * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns - * for all legacy interrupts except 0 (which is always the invalid irq for - * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated - * later during boot automatically (the reverse mapping will use the slow path - * until that happens). - */ -extern struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq); - - -/** - * irq_find_host - Locates a host for a given device node - * @node: device-tree node of the interrupt controller - */ -extern struct irq_host *irq_find_host(struct device_node *node); - - -/** - * irq_set_default_host - Set a "default" host - * @host: default host pointer - * - * For convenience, it's possible to set a "default" host that will be used - * whenever NULL is passed to irq_create_mapping(). It makes life easier for - * platforms that want to manipulate a few hard coded interrupt numbers that - * aren't properly represented in the device-tree. - */ -extern void irq_set_default_host(struct irq_host *host); - - -/** - * irq_set_virq_count - Set the maximum number of virt irqs - * @count: number of linux virtual irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -extern void irq_set_virq_count(unsigned int count); - - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - - -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_find_mapping - Find a linux virq from an hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a slow path, for use by generic code. It's expected that an - * irq controller implementation directly calls the appropriate low level - * mapping function. - */ -extern unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_create_direct_mapping - Allocate a virq for direct mapping - * @host: host to allocate the virq for or NULL for default host - * - * This routine is used for irq controllers which can choose the hardware - * interrupt numbers they generate. In such a case it's simplest to use - * the linux virq as the hardware interrupt number. - */ -extern unsigned int irq_create_direct_mapping(struct irq_host *host); - -/** - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. - * @host: host owning this hardware interrupt - * @virq: linux irq number - * @hwirq: hardware irq number in that host space - * - * This is for use by irq controllers that use a radix tree reverse - * mapping for fast lookup. - */ -extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq); - -/** - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses radix tree - * revmaps - */ -extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_linear_revmap - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses linear - * revmaps. It does fallback to the slow path if the revmap doesn't exist - * yet and will create the revmap entry with appropriate locking - */ - -extern unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq); - - - -/** - * irq_alloc_virt - Allocate virtual irq numbers - * @host: host owning these new virtual irqs - * @count: number of consecutive numbers to allocate - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping - * - * This is a low level function that is used internally by irq_create_mapping() - * and that can be used by some irq controllers implementations for things - * like allocating ranges of numbers for MSIs. The revmaps are left untouched. - */ -extern unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint); - -/** - * irq_free_virt - Free virtual irq numbers - * @virq: virtual irq number of the first interrupt to free - * @count: number of interrupts to free - * - * This function is the opposite of irq_alloc_virt. It will not clear reverse - * maps, this should be done previously by unmap'ing the interrupt. In fact, - * all interrupts covered by the range being freed should have been unmapped - * prior to calling this. - */ -extern void irq_free_virt(unsigned int virq, unsigned int count); /** * irq_early_init - Init irq remapping subsystem diff --git a/arch/powerpc/include/asm/irqflags.h b/arch/powerpc/include/asm/irqflags.h index b0b06d85788d..6f9b6e23dc5a 100644 --- a/arch/powerpc/include/asm/irqflags.h +++ b/arch/powerpc/include/asm/irqflags.h @@ -39,24 +39,31 @@ #define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) #define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) -#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) \ - cmpdi en,0; \ - bne 95f; \ - stb en,PACASOFTIRQEN(r13); \ - TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) \ - b skip; \ -95: TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) \ - li en,1; -#define TRACE_AND_RESTORE_IRQ(en) \ - TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f); \ - stb en,PACASOFTIRQEN(r13); \ -96: +/* + * This is used by assembly code to soft-disable interrupts + */ +#define SOFT_DISABLE_INTS(__rA, __rB) \ + lbz __rA,PACASOFTIRQEN(r13); \ + lbz __rB,PACAIRQHAPPENED(r13); \ + cmpwi cr0,__rA,0; \ + li __rA,0; \ + ori __rB,__rB,PACA_IRQ_HARD_DIS; \ + stb __rB,PACAIRQHAPPENED(r13); \ + beq 44f; \ + stb __rA,PACASOFTIRQEN(r13); \ + TRACE_DISABLE_INTS; \ +44: + #else #define TRACE_ENABLE_INTS #define TRACE_DISABLE_INTS -#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) -#define TRACE_AND_RESTORE_IRQ(en) \ - stb en,PACASOFTIRQEN(r13) + +#define SOFT_DISABLE_INTS(__rA, __rB) \ + lbz __rA,PACAIRQHAPPENED(r13); \ + li __rB,0; \ + ori __rA,__rA,PACA_IRQ_HARD_DIS; \ + stb __rB,PACASOFTIRQEN(r13); \ + stb __rA,PACAIRQHAPPENED(r13) #endif #endif diff --git a/arch/powerpc/include/asm/iseries/alpaca.h b/arch/powerpc/include/asm/iseries/alpaca.h deleted file mode 100644 index c0cce6727a69..000000000000 --- a/arch/powerpc/include/asm/iseries/alpaca.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright © 2008 Stephen Rothwell IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_ALPACA_H -#define _ASM_POWERPC_ISERIES_ALPACA_H - -/* - * This is the part of the paca that the iSeries hypervisor - * needs to be statically initialised. Immediately after boot - * we switch to the normal Linux paca. - */ -struct alpaca { - struct lppaca *lppaca_ptr; /* Pointer to LpPaca for PLIC */ - const void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */ -}; - -#endif /* _ASM_POWERPC_ISERIES_ALPACA_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_call.h b/arch/powerpc/include/asm/iseries/hv_call.h deleted file mode 100644 index 162d653ad51f..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ -#ifndef _ASM_POWERPC_ISERIES_HV_CALL_H -#define _ASM_POWERPC_ISERIES_HV_CALL_H - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/paca.h> - -/* Type of yield for HvCallBaseYieldProcessor */ -#define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ -#define HvCall_YieldToActive 1 /* Yield until all active procs have run */ -#define HvCall_YieldToProc 2 /* Yield until the specified processor has run */ - -/* interrupt masks for setEnabledInterrupts */ -#define HvCall_MaskIPI 0x00000001 -#define HvCall_MaskLpEvent 0x00000002 -#define HvCall_MaskLpProd 0x00000004 -#define HvCall_MaskTimeout 0x00000008 - -/* Log buffer formats */ -#define HvCall_LogBuffer_ASCII 0 -#define HvCall_LogBuffer_EBCDIC 1 - -#define HvCallBaseAckDeferredInts HvCallBase + 0 -#define HvCallBaseCpmPowerOff HvCallBase + 1 -#define HvCallBaseGetHwPatch HvCallBase + 2 -#define HvCallBaseReIplSpAttn HvCallBase + 3 -#define HvCallBaseSetASR HvCallBase + 4 -#define HvCallBaseSetASRAndRfi HvCallBase + 5 -#define HvCallBaseSetIMR HvCallBase + 6 -#define HvCallBaseSendIPI HvCallBase + 7 -#define HvCallBaseTerminateMachine HvCallBase + 8 -#define HvCallBaseTerminateMachineSrc HvCallBase + 9 -#define HvCallBaseProcessPlicInterrupts HvCallBase + 10 -#define HvCallBaseIsPrimaryCpmOrMsdIpl HvCallBase + 11 -#define HvCallBaseSetVirtualSIT HvCallBase + 12 -#define HvCallBaseVaryOffThisProcessor HvCallBase + 13 -#define HvCallBaseVaryOffMemoryChunk HvCallBase + 14 -#define HvCallBaseVaryOffInteractivePercentage HvCallBase + 15 -#define HvCallBaseSendLpProd HvCallBase + 16 -#define HvCallBaseSetEnabledInterrupts HvCallBase + 17 -#define HvCallBaseYieldProcessor HvCallBase + 18 -#define HvCallBaseVaryOffSharedProcUnits HvCallBase + 19 -#define HvCallBaseSetVirtualDecr HvCallBase + 20 -#define HvCallBaseClearLogBuffer HvCallBase + 21 -#define HvCallBaseGetLogBufferCodePage HvCallBase + 22 -#define HvCallBaseGetLogBufferFormat HvCallBase + 23 -#define HvCallBaseGetLogBufferLength HvCallBase + 24 -#define HvCallBaseReadLogBuffer HvCallBase + 25 -#define HvCallBaseSetLogBufferFormatAndCodePage HvCallBase + 26 -#define HvCallBaseWriteLogBuffer HvCallBase + 27 -#define HvCallBaseRouter28 HvCallBase + 28 -#define HvCallBaseRouter29 HvCallBase + 29 -#define HvCallBaseRouter30 HvCallBase + 30 -#define HvCallBaseSetDebugBus HvCallBase + 31 - -#define HvCallCcSetDABR HvCallCc + 7 - -static inline void HvCall_setVirtualDecr(void) -{ - /* - * Ignore any error return codes - most likely means that the - * target value for the LP has been increased and this vary off - * would bring us below the new target. - */ - HvCall0(HvCallBaseSetVirtualDecr); -} - -static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) -{ - HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm); -} - -static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) -{ - HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); -} - -static inline void HvCall_setLogBufferFormatAndCodepage(int format, - u32 codePage) -{ - HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); -} - -extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); - -static inline void HvCall_sendIPI(struct paca_struct *targetPaca) -{ - HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); -} - -#endif /* _ASM_POWERPC_ISERIES_HV_CALL_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_call_event.h b/arch/powerpc/include/asm/iseries/hv_call_event.h deleted file mode 100644 index cc029d388e11..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_event.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ -#ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H -#define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H - -#include <linux/types.h> -#include <linux/dma-mapping.h> - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/abs_addr.h> - -struct HvLpEvent; - -typedef u8 HvLpEvent_Type; -typedef u8 HvLpEvent_AckInd; -typedef u8 HvLpEvent_AckType; - -typedef u8 HvLpDma_Direction; -typedef u8 HvLpDma_AddressType; - -typedef u64 HvLpEvent_Rc; -typedef u64 HvLpDma_Rc; - -#define HvCallEventAckLpEvent HvCallEvent + 0 -#define HvCallEventCancelLpEvent HvCallEvent + 1 -#define HvCallEventCloseLpEventPath HvCallEvent + 2 -#define HvCallEventDmaBufList HvCallEvent + 3 -#define HvCallEventDmaSingle HvCallEvent + 4 -#define HvCallEventDmaToSp HvCallEvent + 5 -#define HvCallEventGetOverflowLpEvents HvCallEvent + 6 -#define HvCallEventGetSourceLpInstanceId HvCallEvent + 7 -#define HvCallEventGetTargetLpInstanceId HvCallEvent + 8 -#define HvCallEventOpenLpEventPath HvCallEvent + 9 -#define HvCallEventSetLpEventStack HvCallEvent + 10 -#define HvCallEventSignalLpEvent HvCallEvent + 11 -#define HvCallEventSignalLpEventParms HvCallEvent + 12 -#define HvCallEventSetInterLpQueueIndex HvCallEvent + 13 -#define HvCallEventSetLpEventQueueInterruptProc HvCallEvent + 14 -#define HvCallEventRouter15 HvCallEvent + 15 - -static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex) -{ - HvCall1(HvCallEventGetOverflowLpEvents, queueIndex); -} - -static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex) -{ - HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex); -} - -static inline void HvCallEvent_setLpEventStack(u8 queueIndex, - char *eventStackAddr, u32 eventStackSize) -{ - HvCall3(HvCallEventSetLpEventStack, queueIndex, - virt_to_abs(eventStackAddr), eventStackSize); -} - -static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex, - u16 lpLogicalProcIndex) -{ - HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex, - lpLogicalProcIndex); -} - -static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event) -{ - return HvCall1(HvCallEventSignalLpEvent, virt_to_abs(event)); -} - -static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, - HvLpEvent_Type type, u16 subtype, HvLpEvent_AckInd ackInd, - HvLpEvent_AckType ackType, HvLpInstanceId sourceInstanceId, - HvLpInstanceId targetInstanceId, u64 correlationToken, - u64 eventData1, u64 eventData2, u64 eventData3, - u64 eventData4, u64 eventData5) -{ - /* Pack the misc bits into a single Dword to pass to PLIC */ - union { - struct { - u8 ack_and_target; - u8 type; - u16 subtype; - HvLpInstanceId src_inst; - HvLpInstanceId target_inst; - } parms; - u64 dword; - } packed; - - packed.parms.ack_and_target = (ackType << 7) | (ackInd << 6) | targetLp; - packed.parms.type = type; - packed.parms.subtype = subtype; - packed.parms.src_inst = sourceInstanceId; - packed.parms.target_inst = targetInstanceId; - - return HvCall7(HvCallEventSignalLpEventParms, packed.dword, - correlationToken, eventData1, eventData2, - eventData3, eventData4, eventData5); -} - -extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag); -extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle); -extern dma_addr_t iseries_hv_map(void *vaddr, size_t size, - enum dma_data_direction direction); -extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction); - -static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event) -{ - return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event)); -} - -static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event) -{ - return HvCall1(HvCallEventCancelLpEvent, virt_to_abs(event)); -} - -static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId( - HvLpIndex targetLp, HvLpEvent_Type type) -{ - return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type); -} - -static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId( - HvLpIndex targetLp, HvLpEvent_Type type) -{ - return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type); -} - -static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp, - HvLpEvent_Type type) -{ - HvCall2(HvCallEventOpenLpEventPath, targetLp, type); -} - -static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp, - HvLpEvent_Type type) -{ - HvCall2(HvCallEventCloseLpEventPath, targetLp, type); -} - -static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, - HvLpIndex remoteLp, HvLpDma_Direction direction, - HvLpInstanceId localInstanceId, - HvLpInstanceId remoteInstanceId, - HvLpDma_AddressType localAddressType, - HvLpDma_AddressType remoteAddressType, - /* Do these need to be converted to absolute addresses? */ - u64 localBufList, u64 remoteBufList, u32 transferLength) -{ - /* Pack the misc bits into a single Dword to pass to PLIC */ - union { - struct { - u8 flags; - HvLpIndex remote; - u8 type; - u8 reserved; - HvLpInstanceId local_inst; - HvLpInstanceId remote_inst; - } parms; - u64 dword; - } packed; - - packed.parms.flags = (direction << 7) | - (localAddressType << 6) | (remoteAddressType << 5); - packed.parms.remote = remoteLp; - packed.parms.type = type; - packed.parms.reserved = 0; - packed.parms.local_inst = localInstanceId; - packed.parms.remote_inst = remoteInstanceId; - - return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList, - remoteBufList, transferLength); -} - -static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote, - u32 length, HvLpDma_Direction dir) -{ - return HvCall4(HvCallEventDmaToSp, virt_to_abs(local), remote, - length, dir); -} - -#endif /* _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_call_sc.h b/arch/powerpc/include/asm/iseries/hv_call_sc.h deleted file mode 100644 index f5d210959250..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_sc.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_HV_CALL_SC_H -#define _ASM_POWERPC_ISERIES_HV_CALL_SC_H - -#include <linux/types.h> - -#define HvCallBase 0x8000000000000000ul -#define HvCallCc 0x8001000000000000ul -#define HvCallCfg 0x8002000000000000ul -#define HvCallEvent 0x8003000000000000ul -#define HvCallHpt 0x8004000000000000ul -#define HvCallPci 0x8005000000000000ul -#define HvCallSm 0x8007000000000000ul -#define HvCallXm 0x8009000000000000ul - -extern u64 HvCall0(u64); -extern u64 HvCall1(u64, u64); -extern u64 HvCall2(u64, u64, u64); -extern u64 HvCall3(u64, u64, u64, u64); -extern u64 HvCall4(u64, u64, u64, u64, u64); -extern u64 HvCall5(u64, u64, u64, u64, u64, u64); -extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); -extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); - -extern u64 HvCall0Ret16(u64, void *); -extern u64 HvCall1Ret16(u64, void *, u64); -extern u64 HvCall2Ret16(u64, void *, u64, u64); -extern u64 HvCall3Ret16(u64, void *, u64, u64, u64); -extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); -extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); -extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); -extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); - -#endif /* _ASM_POWERPC_ISERIES_HV_CALL_SC_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_call_xm.h b/arch/powerpc/include/asm/iseries/hv_call_xm.h deleted file mode 100644 index 392ac3f54df0..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_xm.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from SLIC. - */ -#ifndef _ASM_POWERPC_ISERIES_HV_CALL_XM_H -#define _ASM_POWERPC_ISERIES_HV_CALL_XM_H - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -#define HvCallXmGetTceTableParms HvCallXm + 0 -#define HvCallXmTestBus HvCallXm + 1 -#define HvCallXmConnectBusUnit HvCallXm + 2 -#define HvCallXmLoadTod HvCallXm + 8 -#define HvCallXmTestBusUnit HvCallXm + 9 -#define HvCallXmSetTce HvCallXm + 11 -#define HvCallXmSetTces HvCallXm + 13 - -static inline void HvCallXm_getTceTableParms(u64 cb) -{ - HvCall1(HvCallXmGetTceTableParms, cb); -} - -static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) -{ - return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce); -} - -static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, - u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4) -{ - return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces, - tce1, tce2, tce3, tce4); -} - -static inline u64 HvCallXm_testBus(u16 busNumber) -{ - return HvCall1(HvCallXmTestBus, busNumber); -} - -static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, - u8 deviceId) -{ - return HvCall2(HvCallXmTestBusUnit, busNumber, - (subBusNumber << 8) | deviceId); -} - -static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, - u8 deviceId, u64 interruptToken) -{ - return HvCall5(HvCallXmConnectBusUnit, busNumber, - (subBusNumber << 8) | deviceId, interruptToken, 0, - 0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */); -} - -static inline u64 HvCallXm_loadTod(void) -{ - return HvCall0(HvCallXmLoadTod); -} - -#endif /* _ASM_POWERPC_ISERIES_HV_CALL_XM_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_lp_config.h b/arch/powerpc/include/asm/iseries/hv_lp_config.h deleted file mode 100644 index a006fd1e4a2c..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_lp_config.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H -#define _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H - -/* - * This file contains the interface to the LPAR configuration data - * to determine which resources should be allocated to each partition. - */ - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -enum { - HvCallCfg_Cur = 0, - HvCallCfg_Init = 1, - HvCallCfg_Max = 2, - HvCallCfg_Min = 3 -}; - -#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 -#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 -#define HvCallCfgGetMsChunks HvCallCfg + 9 -#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 -#define HvCallCfgGetSharedProcUnits HvCallCfg + 21 -#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 -#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 -#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 - -extern HvLpIndex HvLpConfig_getLpIndex_outline(void); -extern HvLpIndex HvLpConfig_getLpIndex(void); -extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void); - -static inline u64 HvLpConfig_getMsChunks(void) -{ - return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(), - HvCallCfg_Cur); -} - -static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) -{ - return HvCall0(HvCallCfgGetSystemPhysicalProcessors); -} - -static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) -{ - return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); -} - -static inline u64 HvLpConfig_getPhysicalProcessors(void) -{ - return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), - HvCallCfg_Cur); -} - -static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) -{ - return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex()); -} - -static inline u64 HvLpConfig_getSharedProcUnits(void) -{ - return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), - HvCallCfg_Cur); -} - -static inline u64 HvLpConfig_getMaxSharedProcUnits(void) -{ - return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), - HvCallCfg_Max); -} - -static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) -{ - return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), - HvCallCfg_Max); -} - -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( - HvLpIndex lp) -{ - /* - * This is a new function in V5R1 so calls to this on older - * hypervisors will return -1 - */ - u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); - if (retVal == -1) - retVal = 0; - return retVal; -} - -static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) -{ - return HvLpConfig_getVirtualLanIndexMapForLp( - HvLpConfig_getLpIndex_outline()); -} - -static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, - HvLpIndex lp2) -{ - HvLpVirtualLanIndexMap virtualLanIndexMap1 = - HvLpConfig_getVirtualLanIndexMapForLp(lp1); - HvLpVirtualLanIndexMap virtualLanIndexMap2 = - HvLpConfig_getVirtualLanIndexMapForLp(lp2); - return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0); -} - -static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) -{ - return HvCall1(HvCallCfgGetHostingLpIndex, lp); -} - -#endif /* _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_lp_event.h b/arch/powerpc/include/asm/iseries/hv_lp_event.h deleted file mode 100644 index 8f5da7d77202..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_lp_event.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* This file contains the class for HV events in the system. */ - -#ifndef _ASM_POWERPC_ISERIES_HV_LP_EVENT_H -#define _ASM_POWERPC_ISERIES_HV_LP_EVENT_H - -#include <asm/types.h> -#include <asm/ptrace.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_event.h> - -/* - * HvLpEvent is the structure for Lp Event messages passed between - * partitions through PLIC. - */ - -struct HvLpEvent { - u8 flags; /* Event flags x00-x00 */ - u8 xType; /* Type of message x01-x01 */ - u16 xSubtype; /* Subtype for event x02-x03 */ - u8 xSourceLp; /* Source LP x04-x04 */ - u8 xTargetLp; /* Target LP x05-x05 */ - u8 xSizeMinus1; /* Size of Derived class - 1 x06-x06 */ - u8 xRc; /* RC for Ack flows x07-x07 */ - u16 xSourceInstanceId; /* Source sides instance id x08-x09 */ - u16 xTargetInstanceId; /* Target sides instance id x0A-x0B */ - union { - u32 xSubtypeData; /* Data usable by the subtype x0C-x0F */ - u16 xSubtypeDataShort[2]; /* Data as 2 shorts */ - u8 xSubtypeDataChar[4]; /* Data as 4 chars */ - } x; - - u64 xCorrelationToken; /* Unique value for source/type x10-x17 */ -}; - -typedef void (*LpEventHandler)(struct HvLpEvent *); - -/* Register a handler for an event type - returns 0 on success */ -extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType, - LpEventHandler hdlr); - -/* - * Unregister a handler for an event type - * - * This call will sleep until the handler being removed is guaranteed to - * be no longer executing on any CPU. Do not call with locks held. - * - * returns 0 on success - * Unregister will fail if there are any paths open for the type - */ -extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType); - -/* - * Open an Lp Event Path for an event type - * returns 0 on success - * openPath will fail if there is no handler registered for the event type. - * The lpIndex specified is the partition index for the target partition - * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero) - */ -extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex); - -/* - * Close an Lp Event Path for a type and partition - * returns 0 on success - */ -extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex); - -#define HvLpEvent_Type_Hypervisor 0 -#define HvLpEvent_Type_MachineFac 1 -#define HvLpEvent_Type_SessionMgr 2 -#define HvLpEvent_Type_SpdIo 3 -#define HvLpEvent_Type_VirtualBus 4 -#define HvLpEvent_Type_PciIo 5 -#define HvLpEvent_Type_RioIo 6 -#define HvLpEvent_Type_VirtualLan 7 -#define HvLpEvent_Type_VirtualIo 8 -#define HvLpEvent_Type_NumTypes 9 - -#define HvLpEvent_Rc_Good 0 -#define HvLpEvent_Rc_BufferNotAvailable 1 -#define HvLpEvent_Rc_Cancelled 2 -#define HvLpEvent_Rc_GenericError 3 -#define HvLpEvent_Rc_InvalidAddress 4 -#define HvLpEvent_Rc_InvalidPartition 5 -#define HvLpEvent_Rc_InvalidSize 6 -#define HvLpEvent_Rc_InvalidSubtype 7 -#define HvLpEvent_Rc_InvalidSubtypeData 8 -#define HvLpEvent_Rc_InvalidType 9 -#define HvLpEvent_Rc_PartitionDead 10 -#define HvLpEvent_Rc_PathClosed 11 -#define HvLpEvent_Rc_SubtypeError 12 - -#define HvLpEvent_Function_Ack 0 -#define HvLpEvent_Function_Int 1 - -#define HvLpEvent_AckInd_NoAck 0 -#define HvLpEvent_AckInd_DoAck 1 - -#define HvLpEvent_AckType_ImmediateAck 0 -#define HvLpEvent_AckType_DeferredAck 1 - -#define HV_LP_EVENT_INT 0x01 -#define HV_LP_EVENT_DO_ACK 0x02 -#define HV_LP_EVENT_DEFERRED_ACK 0x04 -#define HV_LP_EVENT_VALID 0x80 - -#define HvLpDma_Direction_LocalToRemote 0 -#define HvLpDma_Direction_RemoteToLocal 1 - -#define HvLpDma_AddressType_TceIndex 0 -#define HvLpDma_AddressType_RealAddress 1 - -#define HvLpDma_Rc_Good 0 -#define HvLpDma_Rc_Error 1 -#define HvLpDma_Rc_PartitionDead 2 -#define HvLpDma_Rc_PathClosed 3 -#define HvLpDma_Rc_InvalidAddress 4 -#define HvLpDma_Rc_InvalidLength 5 - -static inline int hvlpevent_is_valid(struct HvLpEvent *h) -{ - return h->flags & HV_LP_EVENT_VALID; -} - -static inline void hvlpevent_invalidate(struct HvLpEvent *h) -{ - h->flags &= ~ HV_LP_EVENT_VALID; -} - -static inline int hvlpevent_is_int(struct HvLpEvent *h) -{ - return h->flags & HV_LP_EVENT_INT; -} - -static inline int hvlpevent_is_ack(struct HvLpEvent *h) -{ - return !hvlpevent_is_int(h); -} - -static inline int hvlpevent_need_ack(struct HvLpEvent *h) -{ - return h->flags & HV_LP_EVENT_DO_ACK; -} - -#endif /* _ASM_POWERPC_ISERIES_HV_LP_EVENT_H */ diff --git a/arch/powerpc/include/asm/iseries/hv_types.h b/arch/powerpc/include/asm/iseries/hv_types.h deleted file mode 100644 index c3e6d2a1d1c3..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_types.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_HV_TYPES_H -#define _ASM_POWERPC_ISERIES_HV_TYPES_H - -/* - * General typedefs for the hypervisor. - */ - -#include <asm/types.h> - -typedef u8 HvLpIndex; -typedef u16 HvLpInstanceId; -typedef u64 HvLpTOD; -typedef u64 HvLpSystemSerialNum; -typedef u8 HvLpDeviceSerialNum[12]; -typedef u16 HvLpSanHwSet; -typedef u16 HvLpBus; -typedef u16 HvLpBoard; -typedef u16 HvLpCard; -typedef u8 HvLpDeviceType[4]; -typedef u8 HvLpDeviceModel[3]; -typedef u64 HvIoToken; -typedef u8 HvLpName[8]; -typedef u32 HvIoId; -typedef u64 HvRealMemoryIndex; -typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */ -typedef u16 HvLpVrmIndex; -typedef u32 HvXmGenerationId; -typedef u8 HvLpBusPool; -typedef u8 HvLpSharedPoolIndex; -typedef u16 HvLpSharedProcUnitsX100; -typedef u8 HvLpVirtualLanIndex; -typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */ -typedef u16 HvBusNumber; /* Hypervisor Bus Number */ -typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */ -typedef u8 HvAgentId; /* Hypervisor DevFn */ - - -#define HVMAXARCHITECTEDLPS 32 -#define HVMAXARCHITECTEDVIRTUALLANS 16 -#define HVMAXARCHITECTEDVIRTUALDISKS 32 -#define HVMAXARCHITECTEDVIRTUALCDROMS 8 -#define HVMAXARCHITECTEDVIRTUALTAPES 8 -#define HVCHUNKSIZE (256 * 1024) -#define HVPAGESIZE (4 * 1024) -#define HVLPMINMEGSPRIMARY 256 -#define HVLPMINMEGSSECONDARY 64 -#define HVCHUNKSPERMEG 4 -#define HVPAGESPERMEG 256 -#define HVPAGESPERCHUNK 64 - -#define HvLpIndexInvalid ((HvLpIndex)0xff) - -/* - * Enums for the sub-components under PLIC - * Used in HvCall and HvPrimaryCall - */ -enum { - HvCallCompId = 0, - HvCallCpuCtlsCompId = 1, - HvCallCfgCompId = 2, - HvCallEventCompId = 3, - HvCallHptCompId = 4, - HvCallPciCompId = 5, - HvCallSlmCompId = 6, - HvCallSmCompId = 7, - HvCallSpdCompId = 8, - HvCallXmCompId = 9, - HvCallRioCompId = 10, - HvCallRsvd3CompId = 11, - HvCallRsvd2CompId = 12, - HvCallRsvd1CompId = 13, - HvCallMaxCompId = 14, - HvPrimaryCallCompId = 0, - HvPrimaryCallCfgCompId = 1, - HvPrimaryCallPciCompId = 2, - HvPrimaryCallSmCompId = 3, - HvPrimaryCallSpdCompId = 4, - HvPrimaryCallXmCompId = 5, - HvPrimaryCallRioCompId = 6, - HvPrimaryCallRsvd7CompId = 7, - HvPrimaryCallRsvd6CompId = 8, - HvPrimaryCallRsvd5CompId = 9, - HvPrimaryCallRsvd4CompId = 10, - HvPrimaryCallRsvd3CompId = 11, - HvPrimaryCallRsvd2CompId = 12, - HvPrimaryCallRsvd1CompId = 13, - HvPrimaryCallMaxCompId = HvCallMaxCompId -}; - -struct HvLpBufferList { - u64 addr; - u64 len; -}; - -#endif /* _ASM_POWERPC_ISERIES_HV_TYPES_H */ diff --git a/arch/powerpc/include/asm/iseries/iommu.h b/arch/powerpc/include/asm/iseries/iommu.h deleted file mode 100644 index 1b9692c60899..000000000000 --- a/arch/powerpc/include/asm/iseries/iommu.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _ASM_POWERPC_ISERIES_IOMMU_H -#define _ASM_POWERPC_ISERIES_IOMMU_H - -/* - * Copyright (C) 2005 Stephen Rothwell, IBM 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., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - */ - -struct pci_dev; -struct vio_dev; -struct device_node; -struct iommu_table; - -/* Get table parameters from HV */ -extern void iommu_table_getparms_iSeries(unsigned long busno, - unsigned char slotno, unsigned char virtbus, - struct iommu_table *tbl); - -extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev); -extern void iommu_vio_init(void); - -#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */ diff --git a/arch/powerpc/include/asm/iseries/it_lp_queue.h b/arch/powerpc/include/asm/iseries/it_lp_queue.h deleted file mode 100644 index 428278838821..000000000000 --- a/arch/powerpc/include/asm/iseries/it_lp_queue.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H -#define _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H - -/* - * This control block defines the simple LP queue structure that is - * shared between the hypervisor (PLIC) and the OS in order to send - * events to an LP. - */ - -#include <asm/types.h> -#include <asm/ptrace.h> - -#define IT_LP_MAX_QUEUES 8 - -#define IT_LP_NOT_USED 0 /* Queue will not be used by PLIC */ -#define IT_LP_DEDICATED_IO 1 /* Queue dedicated to IO processor specified */ -#define IT_LP_DEDICATED_LP 2 /* Queue dedicated to LP specified */ -#define IT_LP_SHARED 3 /* Queue shared for both IO and LP */ - -#define IT_LP_EVENT_STACK_SIZE 4096 -#define IT_LP_EVENT_MAX_SIZE 256 -#define IT_LP_EVENT_ALIGN 64 - -struct hvlpevent_queue { -/* - * The hq_current_event is the pointer to the next event stack entry - * that will become valid. The OS must peek at this entry to determine - * if it is valid. PLIC will set the valid indicator as the very last - * store into that entry. - * - * When the OS has completed processing of the event then it will mark - * the event as invalid so that PLIC knows it can store into that event - * location again. - * - * If the event stack fills and there are overflow events, then PLIC - * will set the hq_overflow_pending flag in which case the OS will - * have to fetch the additional LP events once they have drained the - * event stack. - * - * The first 16-bytes are known by both the OS and PLIC. The remainder - * of the cache line is for use by the OS. - */ - u8 hq_overflow_pending; /* 0x00 Overflow events are pending */ - u8 hq_status; /* 0x01 DedicatedIo or DedicatedLp or NotUsed */ - u16 hq_proc_index; /* 0x02 Logical Proc Index for correlation */ - u8 hq_reserved1[12]; /* 0x04 */ - char *hq_current_event; /* 0x10 */ - char *hq_last_event; /* 0x18 */ - char *hq_event_stack; /* 0x20 */ - u8 hq_index; /* 0x28 unique sequential index. */ - u8 hq_reserved2[3]; /* 0x29-2b */ - spinlock_t hq_lock; -}; - -extern struct hvlpevent_queue hvlpevent_queue; - -extern int hvlpevent_is_pending(void); -extern void process_hvlpevents(void); -extern void setup_hvlpevent_queue(void); - -#endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */ diff --git a/arch/powerpc/include/asm/iseries/lpar_map.h b/arch/powerpc/include/asm/iseries/lpar_map.h deleted file mode 100644 index 5e9f3e128ee2..000000000000 --- a/arch/powerpc/include/asm/iseries/lpar_map.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_LPAR_MAP_H -#define _ASM_POWERPC_ISERIES_LPAR_MAP_H - -#ifndef __ASSEMBLY__ - -#include <asm/types.h> - -#endif - -/* - * The iSeries hypervisor will set up mapping for one or more - * ESID/VSID pairs (in SLB/segment registers) and will set up - * mappings of one or more ranges of pages to VAs. - * We will have the hypervisor set up the ESID->VSID mapping - * for the four kernel segments (C-F). With shared processors, - * the hypervisor will clear all segment registers and reload - * these four whenever the processor is switched from one - * partition to another. - */ - -/* The Vsid and Esid identified below will be used by the hypervisor - * to set up a memory mapping for part of the load area before giving - * control to the Linux kernel. The load area is 64 MB, but this must - * not attempt to map the whole load area. The Hashed Page Table may - * need to be located within the load area (if the total partition size - * is 64 MB), but cannot be mapped. Typically, this should specify - * to map half (32 MB) of the load area. - * - * The hypervisor will set up page table entries for the number of - * pages specified. - * - * In 32-bit mode, the hypervisor will load all four of the - * segment registers (identified by the low-order four bits of the - * Esid field. In 64-bit mode, the hypervisor will load one SLB - * entry to map the Esid to the Vsid. -*/ - -#define HvEsidsToMap 2 -#define HvRangesToMap 1 - -/* Hypervisor initially maps 32MB of the load area */ -#define HvPagesToMap 8192 - -#ifndef __ASSEMBLY__ -struct LparMap { - u64 xNumberEsids; // Number of ESID/VSID pairs - u64 xNumberRanges; // Number of VA ranges to map - u64 xSegmentTableOffs; // Page number within load area of seg table - u64 xRsvd[5]; - struct { - u64 xKernelEsid; // Esid used to map kernel load - u64 xKernelVsid; // Vsid used to map kernel load - } xEsids[HvEsidsToMap]; - struct { - u64 xPages; // Number of pages to be mapped - u64 xOffset; // Offset from start of load area - u64 xVPN; // Virtual Page Number - } xRanges[HvRangesToMap]; -}; - -extern const struct LparMap xLparMap; - -#endif /* __ASSEMBLY__ */ - -/* the fixed address where the LparMap exists */ -#define LPARMAP_PHYS 0x7000 - -#endif /* _ASM_POWERPC_ISERIES_LPAR_MAP_H */ diff --git a/arch/powerpc/include/asm/iseries/mf.h b/arch/powerpc/include/asm/iseries/mf.h deleted file mode 100644 index eb851a9c9e5c..000000000000 --- a/arch/powerpc/include/asm/iseries/mf.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2001 Troy D. Armstrong IBM Corporation - * Copyright (C) 2004 Stephen Rothwell IBM Corporation - * - * This modules exists as an interface between a Linux secondary partition - * running on an iSeries and the primary partition's Virtual Service - * Processor (VSP) object. The VSP has final authority over powering on/off - * all partitions in the iSeries. It also provides miscellaneous low-level - * machine facility type operations. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ASM_POWERPC_ISERIES_MF_H -#define _ASM_POWERPC_ISERIES_MF_H - -#include <linux/types.h> - -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_event.h> - -struct rtc_time; - -typedef void (*MFCompleteHandler)(void *clientToken, int returnCode); - -extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type, - unsigned size, unsigned amount, MFCompleteHandler hdlr, - void *userToken); -extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type, - unsigned count, MFCompleteHandler hdlr, void *userToken); - -extern void mf_power_off(void); -extern void mf_reboot(char *cmd); - -extern void mf_display_src(u32 word); -extern void mf_display_progress(u16 value); - -extern void mf_init(void); - -#endif /* _ASM_POWERPC_ISERIES_MF_H */ diff --git a/arch/powerpc/include/asm/iseries/vio.h b/arch/powerpc/include/asm/iseries/vio.h deleted file mode 100644 index f9ac0d00b951..000000000000 --- a/arch/powerpc/include/asm/iseries/vio.h +++ /dev/null @@ -1,265 +0,0 @@ -/* -*- linux-c -*- - * - * iSeries Virtual I/O Message Path header - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * - * (C) Copyright 2000 IBM Corporation - * - * This header file is used by the iSeries virtual I/O device - * drivers. It defines the interfaces to the common functions - * (implemented in drivers/char/viopath.h) as well as defining - * common functions and structures. Currently (at the time I - * wrote this comment) the iSeries virtual I/O device drivers - * that use this are - * drivers/block/viodasd.c - * drivers/char/viocons.c - * drivers/char/viotape.c - * drivers/cdrom/viocd.c - * - * The iSeries virtual ethernet support (veth.c) uses a whole - * different set of functions. - * - * 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) anyu 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#ifndef _ASM_POWERPC_ISERIES_VIO_H -#define _ASM_POWERPC_ISERIES_VIO_H - -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> - -/* - * iSeries virtual I/O events use the subtype field in - * HvLpEvent to figure out what kind of vio event is coming - * in. We use a table to route these, and this defines - * the maximum number of distinct subtypes - */ -#define VIO_MAX_SUBTYPES 8 - -#define VIOMAXBLOCKDMA 12 - -struct open_data { - u64 disk_size; - u16 max_disk; - u16 cylinders; - u16 tracks; - u16 sectors; - u16 bytes_per_sector; -}; - -struct rw_data { - u64 offset; - struct { - u32 token; - u32 reserved; - u64 len; - } dma_info[VIOMAXBLOCKDMA]; -}; - -struct vioblocklpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - union { - struct open_data open_data; - struct rw_data rw_data; - u64 changed; - } u; -}; - -#define vioblockflags_ro 0x0001 - -enum vioblocksubtype { - vioblockopen = 0x0001, - vioblockclose = 0x0002, - vioblockread = 0x0003, - vioblockwrite = 0x0004, - vioblockflush = 0x0005, - vioblockcheck = 0x0007 -}; - -struct viocdlpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - u32 token; - u64 offset; /* On open, max number of disks */ - u64 len; /* On open, size of the disk */ - u32 block_size; /* Only set on open */ - u32 media_size; /* Only set on open */ -}; - -enum viocdsubtype { - viocdopen = 0x0001, - viocdclose = 0x0002, - viocdread = 0x0003, - viocdwrite = 0x0004, - viocdlockdoor = 0x0005, - viocdgetinfo = 0x0006, - viocdcheck = 0x0007 -}; - -struct viotapelpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_type_result; - u16 tape; - u16 flags; - u32 token; - u64 len; - union { - struct { - u32 tape_op; - u32 count; - } op; - struct { - u32 type; - u32 resid; - u32 dsreg; - u32 gstat; - u32 erreg; - u32 file_no; - u32 block_no; - } get_status; - struct { - u32 block_no; - } get_pos; - } u; -}; - -enum viotapesubtype { - viotapeopen = 0x0001, - viotapeclose = 0x0002, - viotaperead = 0x0003, - viotapewrite = 0x0004, - viotapegetinfo = 0x0005, - viotapeop = 0x0006, - viotapegetpos = 0x0007, - viotapesetpos = 0x0008, - viotapegetstatus = 0x0009 -}; - -/* - * Each subtype can register a handler to process their events. - * The handler must have this interface. - */ -typedef void (vio_event_handler_t) (struct HvLpEvent * event); - -extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq); -extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq); -extern int vio_setHandler(int subtype, vio_event_handler_t * beh); -extern int vio_clearHandler(int subtype); -extern int viopath_isactive(HvLpIndex lp); -extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp); -extern HvLpInstanceId viopath_targetinst(HvLpIndex lp); -extern void vio_set_hostlp(void); -extern void *vio_get_event_buffer(int subtype); -extern void vio_free_event_buffer(int subtype, void *buffer); - -extern struct vio_dev *vio_create_viodasd(u32 unit); - -extern HvLpIndex viopath_hostLp; -extern HvLpIndex viopath_ourLp; - -#define VIOCHAR_MAX_DATA 200 - -#define VIOMAJOR_SUBTYPE_MASK 0xff00 -#define VIOMINOR_SUBTYPE_MASK 0x00ff -#define VIOMAJOR_SUBTYPE_SHIFT 8 - -#define VIOVERSION 0x0101 - -/* - * This is the general structure for VIO errors; each module should have - * a table of them, and each table should be terminated by an entry of - * { 0, 0, NULL }. Then, to find a specific error message, a module - * should pass its local table and the return code. - */ -struct vio_error_entry { - u16 rc; - int errno; - const char *msg; -}; -extern const struct vio_error_entry *vio_lookup_rc( - const struct vio_error_entry *local_table, u16 rc); - -enum viosubtypes { - viomajorsubtype_monitor = 0x0100, - viomajorsubtype_blockio = 0x0200, - viomajorsubtype_chario = 0x0300, - viomajorsubtype_config = 0x0400, - viomajorsubtype_cdio = 0x0500, - viomajorsubtype_tape = 0x0600, - viomajorsubtype_scsi = 0x0700 -}; - -enum vioconfigsubtype { - vioconfigget = 0x0001, -}; - -enum viorc { - viorc_good = 0x0000, - viorc_noConnection = 0x0001, - viorc_noReceiver = 0x0002, - viorc_noBufferAvailable = 0x0003, - viorc_invalidMessageType = 0x0004, - viorc_invalidRange = 0x0201, - viorc_invalidToken = 0x0202, - viorc_DMAError = 0x0203, - viorc_useError = 0x0204, - viorc_releaseError = 0x0205, - viorc_invalidDisk = 0x0206, - viorc_openRejected = 0x0301 -}; - -/* - * The structure of the events that flow between us and OS/400 for chario - * events. You can't mess with this unless the OS/400 side changes too. - */ -struct viocharlpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 subtype_result_code; - u8 virtual_device; - u8 len; - u8 data[VIOCHAR_MAX_DATA]; -}; - -#define VIOCHAR_WINDOW 10 - -enum viocharsubtype { - viocharopen = 0x0001, - viocharclose = 0x0002, - viochardata = 0x0003, - viocharack = 0x0004, - viocharconfig = 0x0005 -}; - -enum viochar_rc { - viochar_rc_ebusy = 1 -}; - -#endif /* _ASM_POWERPC_ISERIES_VIO_H */ diff --git a/arch/powerpc/include/asm/keylargo.h b/arch/powerpc/include/asm/keylargo.h index fc195d0b3c34..2156315d8a90 100644 --- a/arch/powerpc/include/asm/keylargo.h +++ b/arch/powerpc/include/asm/keylargo.h @@ -21,7 +21,7 @@ #define KEYLARGO_FCR4 0x48 #define KEYLARGO_FCR5 0x4c /* Pangea only */ -/* K2 aditional FCRs */ +/* K2 additional FCRs */ #define K2_FCR6 0x34 #define K2_FCR7 0x30 #define K2_FCR8 0x2c diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index e0298d26ce5d..a76254af0aaa 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -41,15 +41,7 @@ * We only have to have statically allocated lppaca structs on * legacy iSeries, which supports at most 64 cpus. */ -#ifdef CONFIG_PPC_ISERIES -#if NR_CPUS < 64 -#define NR_LPPACAS NR_CPUS -#else -#define NR_LPPACAS 64 -#endif -#else /* not iSeries */ #define NR_LPPACAS 1 -#endif /* The Hypervisor barfs if the lppaca crosses a page boundary. A 1k diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 67b4d9837236..c65b9294376e 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -255,7 +255,7 @@ struct mpic struct device_node *node; /* The remapper for this MPIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; /* The "linux" controller struct */ struct irq_chip hc_irq; @@ -273,7 +273,6 @@ struct mpic unsigned int isu_size; unsigned int isu_shift; unsigned int isu_mask; - unsigned int irq_count; /* Number of sources */ unsigned int num_sources; /* default senses array */ @@ -349,8 +348,6 @@ struct mpic #define MPIC_U3_HT_IRQS 0x00000004 /* Broken IPI registers (autodetected) */ #define MPIC_BROKEN_IPI 0x00000008 -/* MPIC wants a reset */ -#define MPIC_WANTS_RESET 0x00000010 /* Spurious vector requires EOI */ #define MPIC_SPV_EOI 0x00000020 /* No passthrough disable */ @@ -363,15 +360,11 @@ struct mpic #define MPIC_ENABLE_MCK 0x00000200 /* Disable bias among target selection, spread interrupts evenly */ #define MPIC_NO_BIAS 0x00000400 -/* Ignore NIRQS as reported by FRR */ -#define MPIC_BROKEN_FRR_NIRQS 0x00000800 /* Destination only supports a single CPU at a time */ #define MPIC_SINGLE_DEST_CPU 0x00001000 /* Enable CoreInt delivery of interrupts */ #define MPIC_ENABLE_COREINT 0x00002000 -/* Disable resetting of the MPIC. - * NOTE: This flag trumps MPIC_WANTS_RESET. - */ +/* Do not reset the MPIC during initialization */ #define MPIC_NO_RESET 0x00004000 /* Freescale MPIC (compatible includes "fsl,mpic") */ #define MPIC_FSL 0x00008000 diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h new file mode 100644 index 000000000000..3ec37dc9003e --- /dev/null +++ b/arch/powerpc/include/asm/mpic_msgr.h @@ -0,0 +1,132 @@ +/* + * Copyright 2011-2012, Meador Inge, Mentor Graphics 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; version 2 of the + * License. + * + */ + +#ifndef _ASM_MPIC_MSGR_H +#define _ASM_MPIC_MSGR_H + +#include <linux/types.h> +#include <linux/spinlock.h> + +struct mpic_msgr { + u32 __iomem *base; + u32 __iomem *mer; + int irq; + unsigned char in_use; + raw_spinlock_t lock; + int num; +}; + +/* Get a message register + * + * @reg_num: the MPIC message register to get + * + * A pointer to the message register is returned. If + * the message register asked for is already in use, then + * EBUSY is returned. If the number given is not associated + * with an actual message register, then ENODEV is returned. + * Successfully getting the register marks it as in use. + */ +extern struct mpic_msgr *mpic_msgr_get(unsigned int reg_num); + +/* Relinquish a message register + * + * @msgr: the message register to return + * + * Disables the given message register and marks it as free. + * After this call has completed successully the message + * register is available to be acquired by a call to + * mpic_msgr_get. + */ +extern void mpic_msgr_put(struct mpic_msgr *msgr); + +/* Enable a message register + * + * @msgr: the message register to enable + * + * The given message register is enabled for sending + * messages. + */ +extern void mpic_msgr_enable(struct mpic_msgr *msgr); + +/* Disable a message register + * + * @msgr: the message register to disable + * + * The given message register is disabled for sending + * messages. + */ +extern void mpic_msgr_disable(struct mpic_msgr *msgr); + +/* Write a message to a message register + * + * @msgr: the message register to write to + * @message: the message to write + * + * The given 32-bit message is written to the given message + * register. Writing to an enabled message registers fires + * an interrupt. + */ +static inline void mpic_msgr_write(struct mpic_msgr *msgr, u32 message) +{ + out_be32(msgr->base, message); +} + +/* Read a message from a message register + * + * @msgr: the message register to read from + * + * Returns the 32-bit value currently in the given message register. + * Upon reading the register any interrupts for that register are + * cleared. + */ +static inline u32 mpic_msgr_read(struct mpic_msgr *msgr) +{ + return in_be32(msgr->base); +} + +/* Clear a message register + * + * @msgr: the message register to clear + * + * Clears any interrupts associated with the given message register. + */ +static inline void mpic_msgr_clear(struct mpic_msgr *msgr) +{ + (void) mpic_msgr_read(msgr); +} + +/* Set the destination CPU for the message register + * + * @msgr: the message register whose destination is to be set + * @cpu_num: the Linux CPU number to bind the message register to + * + * Note that the CPU number given is the CPU number used by the kernel + * and *not* the actual hardware CPU number. + */ +static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr, + u32 cpu_num) +{ + out_be32(msgr->base, 1 << get_hard_smp_processor_id(cpu_num)); +} + +/* Get the IRQ number for the message register + * @msgr: the message register whose IRQ is to be returned + * + * Returns the IRQ number associated with the given message register. + * NO_IRQ is returned if this message register is not capable of + * receiving interrupts. What message register can and cannot receive + * interrupts is specified in the device tree for the system. + */ +static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr) +{ + return msgr->irq; +} + +#endif diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 269c05a36d91..daf813fea91f 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -132,7 +132,7 @@ struct paca_struct { u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ u8 soft_enabled; /* irq soft-enable flag */ - u8 hard_enabled; /* set if irqs are enabled in MSR */ + u8 irq_happened; /* irq happened while soft-disabled */ u8 io_sync; /* writel() needs spin_unlock sync */ u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ u8 nap_state_lost; /* NV GPR values lost in power7_idle */ diff --git a/arch/powerpc/include/asm/phyp_dump.h b/arch/powerpc/include/asm/phyp_dump.h deleted file mode 100644 index fa74c6c3e106..000000000000 --- a/arch/powerpc/include/asm/phyp_dump.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Hypervisor-assisted dump - * - * Linas Vepstas, Manish Ahuja 2008 - * Copyright 2008 IBM Corp. - * - * 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. - */ - -#ifndef _PPC64_PHYP_DUMP_H -#define _PPC64_PHYP_DUMP_H - -#ifdef CONFIG_PHYP_DUMP - -/* The RMR region will be saved for later dumping - * whenever the kernel crashes. Set this to 256MB. */ -#define PHYP_DUMP_RMR_START 0x0 -#define PHYP_DUMP_RMR_END (1UL<<28) - -struct phyp_dump { - /* Memory that is reserved during very early boot. */ - unsigned long init_reserve_start; - unsigned long init_reserve_size; - /* cmd line options during boot */ - unsigned long reserve_bootvar; - unsigned long phyp_dump_at_boot; - /* Check status during boot if dump supported, active & present*/ - unsigned long phyp_dump_configured; - unsigned long phyp_dump_is_active; - /* store cpu & hpte size */ - unsigned long cpu_state_size; - unsigned long hpte_region_size; - /* previous scratch area values */ - unsigned long reserved_scratch_addr; - unsigned long reserved_scratch_size; -}; - -extern struct phyp_dump *phyp_dump_info; - -int early_init_dt_scan_phyp_dump(unsigned long node, - const char *uname, int depth, void *data); - -#endif /* CONFIG_PHYP_DUMP */ -#endif /* _PPC64_PHYP_DUMP_H */ diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 6d422979ebaf..e660b37aa7d0 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -47,92 +47,21 @@ extern int rtas_setup_phb(struct pci_controller *phb); extern unsigned long pci_probe_only; -/* ---- EEH internal-use-only related routines ---- */ #ifdef CONFIG_EEH +void pci_addr_cache_build(void); void pci_addr_cache_insert_device(struct pci_dev *dev); void pci_addr_cache_remove_device(struct pci_dev *dev); -void pci_addr_cache_build(void); -struct pci_dev *pci_get_device_by_addr(unsigned long addr); - -/** - * eeh_slot_error_detail -- record and EEH error condition to the log - * @pdn: pci device node - * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE - * - * Obtains the EEH error details from the RTAS subsystem, - * and then logs these details with the RTAS error log system. - */ -#define EEH_LOG_TEMP_FAILURE 1 -#define EEH_LOG_PERM_FAILURE 2 -void eeh_slot_error_detail (struct pci_dn *pdn, int severity); - -/** - * rtas_pci_enable - enable IO transfers for this slot - * @pdn: pci device node - * @function: either EEH_THAW_MMIO or EEH_THAW_DMA - * - * Enable I/O transfers to this slot - */ -#define EEH_THAW_MMIO 2 -#define EEH_THAW_DMA 3 -int rtas_pci_enable(struct pci_dn *pdn, int function); - -/** - * rtas_set_slot_reset -- unfreeze a frozen slot - * @pdn: pci device node - * - * Clear the EEH-frozen condition on a slot. This routine - * does this by asserting the PCI #RST line for 1/8th of - * a second; this routine will sleep while the adapter is - * being reset. - * - * Returns a non-zero value if the reset failed. - */ -int rtas_set_slot_reset (struct pci_dn *); -int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs); - -/** - * eeh_restore_bars - Restore device configuration info. - * @pdn: pci device node - * - * A reset of a PCI device will clear out its config space. - * This routines will restore the config space for this - * device, and is children, to values previously obtained - * from the firmware. - */ -void eeh_restore_bars(struct pci_dn *); - -/** - * rtas_configure_bridge -- firmware initialization of pci bridge - * @pdn: pci device node - * - * Ask the firmware to configure all PCI bridges devices - * located behind the indicated node. Required after a - * pci device reset. Does essentially the same hing as - * eeh_restore_bars, but for brdges, and lets firmware - * do the work. - */ -void rtas_configure_bridge(struct pci_dn *); - +struct pci_dev *pci_addr_cache_get_device(unsigned long addr); +void eeh_slot_error_detail(struct eeh_dev *edev, int severity); +int eeh_pci_enable(struct eeh_dev *edev, int function); +int eeh_reset_pe(struct eeh_dev *); +void eeh_restore_bars(struct eeh_dev *); int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); - -/** - * eeh_mark_slot -- set mode flags for pertition endpoint - * @pdn: pci device node - * - * mark and clear slots: find "partition endpoint" PE and set or - * clear the flags for each subnode of the PE. - */ -void eeh_mark_slot (struct device_node *dn, int mode_flag); -void eeh_clear_slot (struct device_node *dn, int mode_flag); - -/** - * find_device_pe -- Find the associated "Partiationable Endpoint" PE - * @pdn: pci device node - */ -struct device_node * find_device_pe(struct device_node *dn); +void eeh_mark_slot(struct device_node *dn, int mode_flag); +void eeh_clear_slot(struct device_node *dn, int mode_flag); +struct device_node *eeh_find_device_pe(struct device_node *dn); void eeh_sysfs_add_device(struct pci_dev *pdev); void eeh_sysfs_remove_device(struct pci_dev *pdev); diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 368f72f79808..50f73aa2ba21 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -60,6 +60,8 @@ BEGIN_FW_FTR_SECTION; \ cmpd cr1,r11,r10; \ beq+ cr1,33f; \ bl .accumulate_stolen_time; \ + ld r12,_MSR(r1); \ + andi. r10,r12,MSR_PR; /* Restore cr0 (coming from user) */ \ 33: \ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7fdc2c0b7fa0..b1a215eabef6 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1079,30 +1079,12 @@ #define proc_trap() asm volatile("trap") -#ifdef CONFIG_PPC64 - -extern void ppc64_runlatch_on(void); -extern void __ppc64_runlatch_off(void); - -#define ppc64_runlatch_off() \ - do { \ - if (cpu_has_feature(CPU_FTR_CTRL) && \ - test_thread_flag(TIF_RUNLATCH)) \ - __ppc64_runlatch_off(); \ - } while (0) +#define __get_SP() ({unsigned long sp; \ + asm volatile("mr %0,1": "=r" (sp)); sp;}) extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); -#else -#define ppc64_runlatch_on() -#define ppc64_runlatch_off() - -#endif /* CONFIG_PPC64 */ - -#define __get_SP() ({unsigned long sp; \ - asm volatile("mr %0,1": "=r" (sp)); sp;}) - struct pt_regs; extern void ppc_save_regs(struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 500fe1dc43e6..8a97aa7289d3 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -62,6 +62,7 @@ #define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */ #define SPRN_MAS8 0x155 /* MMU Assist Register 8 */ #define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */ +#define SPRN_TLB1PS 0x159 /* TLB 1 Page Size Register */ #define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */ #define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */ #define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */ diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 2fc2af8fbf59..3d5179bb122f 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -71,5 +71,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index f9611bd69ed2..7124fc06ad47 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -23,7 +23,6 @@ #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/hvcall.h> -#include <asm/iseries/hv_call.h> #endif #include <asm/asm-compat.h> #include <asm/synch.h> @@ -95,12 +94,12 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) * value. */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +#if defined(CONFIG_PPC_SPLPAR) /* We only yield to the hypervisor if we are in shared processor mode */ #define SHARED_PROCESSOR (get_lppaca()->shared_proc) extern void __spin_yield(arch_spinlock_t *lock); extern void __rw_yield(arch_rwlock_t *lock); -#else /* SPLPAR || ISERIES */ +#else /* SPLPAR */ #define __spin_yield(x) barrier() #define __rw_yield(x) barrier() #define SHARED_PROCESSOR 0 diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h index c377457d1b89..a02883d5af43 100644 --- a/arch/powerpc/include/asm/system.h +++ b/arch/powerpc/include/asm/system.h @@ -550,5 +550,43 @@ extern void reloc_got2(unsigned long); extern struct dentry *powerpc_debugfs_root; +#ifdef CONFIG_PPC64 + +extern void __ppc64_runlatch_on(void); +extern void __ppc64_runlatch_off(void); + +/* + * We manually hard enable-disable, this is called + * in the idle loop and we don't want to mess up + * with soft-disable/enable & interrupt replay. + */ +#define ppc64_runlatch_off() \ + do { \ + if (cpu_has_feature(CPU_FTR_CTRL) && \ + test_thread_local_flags(_TLF_RUNLATCH)) { \ + unsigned long msr = mfmsr(); \ + __hard_irq_disable(); \ + __ppc64_runlatch_off(); \ + if (msr & MSR_EE) \ + __hard_irq_enable(); \ + } \ + } while (0) + +#define ppc64_runlatch_on() \ + do { \ + if (cpu_has_feature(CPU_FTR_CTRL) && \ + !test_thread_local_flags(_TLF_RUNLATCH)) { \ + unsigned long msr = mfmsr(); \ + __hard_irq_disable(); \ + __ppc64_runlatch_on(); \ + if (msr & MSR_EE) \ + __hard_irq_enable(); \ + } \ + } while (0) +#else +#define ppc64_runlatch_on() +#define ppc64_runlatch_off() +#endif /* CONFIG_PPC64 */ + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SYSTEM_H */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 964714940961..4a741c7efd02 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -110,7 +110,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NOERROR 12 /* Force successful syscall return */ #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ #define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */ -#define TIF_RUNLATCH 16 /* Is the runlatch enabled? */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) @@ -141,11 +140,13 @@ static inline struct thread_info *current_thread_info(void) #define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */ #define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */ #define TLF_LAZY_MMU 3 /* tlb_batch is active */ +#define TLF_RUNLATCH 4 /* Is the runlatch enabled? */ #define _TLF_NAPPING (1 << TLF_NAPPING) #define _TLF_SLEEPING (1 << TLF_SLEEPING) #define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK) #define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU) +#define _TLF_RUNLATCH (1 << TLF_RUNLATCH) #ifndef __ASSEMBLY__ #define HAVE_SET_RESTORE_SIGMASK 1 @@ -156,6 +157,12 @@ static inline void set_restore_sigmask(void) set_bit(TIF_SIGPENDING, &ti->flags); } +static inline bool test_thread_local_flags(unsigned int flags) +{ + struct thread_info *ti = current_thread_info(); + return (ti->local_flags & flags) != 0; +} + #ifdef CONFIG_PPC64 #define is_32bit_task() (test_thread_flag(TIF_32BIT)) #else diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 7eb10fb96cd0..2136f58a54e8 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -18,11 +18,6 @@ #include <linux/percpu.h> #include <asm/processor.h> -#ifdef CONFIG_PPC_ISERIES -#include <asm/paca.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call.h> -#endif /* time.c */ extern unsigned long tb_ticks_per_jiffy; @@ -167,15 +162,6 @@ static inline void set_dec(int val) #ifndef CONFIG_BOOKE --val; #endif -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES) && - get_lppaca()->shared_proc) { - get_lppaca()->virtual_decr = val; - if (get_dec() > val) - HvCall_setVirtualDecr(); - return; - } -#endif mtspr(SPRN_DEC, val); #endif /* not 40x or 8xx_CPU6 */ } @@ -217,7 +203,6 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); #endif extern void secondary_cpu_time_init(void); -extern void iSeries_time_init_early(void); DECLARE_PER_CPU(u64, decrementers_next_tb); diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index c48de98ba94e..4ae9a09c3b89 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -86,7 +86,7 @@ struct ics { extern unsigned int xics_default_server; extern unsigned int xics_default_distrib_server; extern unsigned int xics_interrupt_server_size; -extern struct irq_host *xics_host; +extern struct irq_domain *xics_host; struct xics_cppr { unsigned char stack[MAX_NUM_PRIORITIES]; diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index ee728e433aa2..f5808a35688c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif @@ -113,15 +114,6 @@ obj-$(CONFIG_PPC_IO_WORKAROUNDS) += io-workarounds.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o -obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o - -obj-$(CONFIG_PPC_PERF_CTRS) += perf_event.o -obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ - power5+-pmu.o power6-pmu.o power7-pmu.o -obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o - -obj-$(CONFIG_FSL_EMB_PERF_EVENT) += perf_event_fsl_emb.o -obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 04caee7d9bc1..cc492e48ddfa 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -46,9 +46,6 @@ #include <asm/hvcall.h> #include <asm/xics.h> #endif -#ifdef CONFIG_PPC_ISERIES -#include <asm/iseries/alpaca.h> -#endif #ifdef CONFIG_PPC_POWERNV #include <asm/opal.h> #endif @@ -147,7 +144,7 @@ int main(void) DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase)); DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr)); DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled)); - DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled)); + DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); #ifdef CONFIG_PPC_MM_SLICES DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct, @@ -384,17 +381,6 @@ int main(void) DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); #endif -#ifdef CONFIG_PPC_ISERIES - /* the assembler miscalculates the VSID values */ - DEFINE(PAGE_OFFSET_ESID, GET_ESID(PAGE_OFFSET)); - DEFINE(PAGE_OFFSET_VSID, KERNEL_VSID(PAGE_OFFSET)); - DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START)); - DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START)); - - /* alpaca */ - DEFINE(ALPACA_SIZE, sizeof(struct alpaca)); -#endif - DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); DEFINE(PTE_SIZE, sizeof(pte_t)); diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 81db9e2a8a20..138ae183c440 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1816,7 +1816,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .platform = "ppc440", }, { /* 464 in APM821xx */ - .pvr_mask = 0xffffff00, + .pvr_mask = 0xfffffff0, .pvr_value = 0x12C41C80, .cpu_name = "APM821XX", .cpu_features = CPU_FTRS_44X, @@ -2019,6 +2019,24 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_e500mc, .platform = "ppce5500", }, + { /* e6500 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x80400000, + .cpu_name = "e6500", + .cpu_features = CPU_FTRS_E6500, + .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, + .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS | + MMU_FTR_USE_TLBILX, + .icache_bsize = 64, + .dcache_bsize = 64, + .num_pmcs = 4, + .oprofile_cpu_type = "ppc/e6500", + .oprofile_type = PPC_OPROFILE_FSL_EMB, + .cpu_setup = __setup_cpu_e5500, + .cpu_restore = __restore_cpu_e5500, + .machine_check = machine_check_e500mc, + .platform = "ppce6500", + }, #ifdef CONFIG_PPC32 { /* default match */ .pvr_mask = 0x00000000, diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 2cc451aaaca7..5b25c8060fd6 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -37,6 +37,8 @@ void doorbell_exception(struct pt_regs *regs) irq_enter(); + may_hard_irq_enable(); + smp_ipi_demux(); irq_exit(); diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 866462cbe2d8..f8a7a1a1a9f4 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -32,6 +32,7 @@ #include <asm/ptrace.h> #include <asm/irqflags.h> #include <asm/ftrace.h> +#include <asm/hw_irq.h> /* * System calls. @@ -115,39 +116,33 @@ BEGIN_FW_FTR_SECTION END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */ -#ifdef CONFIG_TRACE_IRQFLAGS - bl .trace_hardirqs_on - REST_GPR(0,r1) - REST_4GPRS(3,r1) - REST_2GPRS(7,r1) - addi r9,r1,STACK_FRAME_OVERHEAD - ld r12,_MSR(r1) -#endif /* CONFIG_TRACE_IRQFLAGS */ - li r10,1 - stb r10,PACASOFTIRQEN(r13) - stb r10,PACAHARDIRQEN(r13) - std r10,SOFTE(r1) -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - /* Hack for handling interrupts when soft-enabling on iSeries */ - cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ - andi. r10,r12,MSR_PR /* from kernel */ - crand 4*cr0+eq,4*cr1+eq,4*cr0+eq - bne 2f - b hardware_interrupt_entry -2: -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif /* CONFIG_PPC_ISERIES */ + /* + * A syscall should always be called with interrupts enabled + * so we just unconditionally hard-enable here. When some kind + * of irq tracing is used, we additionally check that condition + * is correct + */ +#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_BUG) + lbz r10,PACASOFTIRQEN(r13) + xori r10,r10,1 +1: tdnei r10,0 + EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING +#endif - /* Hard enable interrupts */ #ifdef CONFIG_PPC_BOOK3E wrteei 1 #else - mfmsr r11 + ld r11,PACAKMSR(r13) ori r11,r11,MSR_EE mtmsrd r11,1 #endif /* CONFIG_PPC_BOOK3E */ + /* We do need to set SOFTE in the stack frame or the return + * from interrupt will be painful + */ + li r10,1 + std r10,SOFTE(r1) + #ifdef SHOW_SYSCALLS bl .do_show_syscall REST_GPR(0,r1) @@ -198,16 +193,14 @@ syscall_exit: andi. r10,r8,MSR_RI beq- unrecov_restore #endif - - /* Disable interrupts so current_thread_info()->flags can't change, + /* + * Disable interrupts so current_thread_info()->flags can't change, * and so that we don't get interrupted after loading SRR0/1. */ #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - mfmsr r10 - rldicl r10,r10,48,1 - rotldi r10,r10,16 + ld r10,PACAKMSR(r13) mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ @@ -319,7 +312,7 @@ syscall_exit_work: #ifdef CONFIG_PPC_BOOK3E wrteei 1 #else - mfmsr r10 + ld r10,PACAKMSR(r13) ori r10,r10,MSR_EE mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ @@ -565,10 +558,8 @@ _GLOBAL(ret_from_except_lite) #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - mfmsr r10 /* Get current interrupt state */ - rldicl r9,r10,48,1 /* clear MSR_EE */ - rotldi r9,r9,16 - mtmsrd r9,1 /* Update machine state */ + ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ + mtmsrd r10,1 /* Update machine state */ #endif /* CONFIG_PPC_BOOK3E */ #ifdef CONFIG_PREEMPT @@ -591,25 +582,74 @@ _GLOBAL(ret_from_except_lite) ld r4,TI_FLAGS(r9) andi. r0,r4,_TIF_USER_WORK_MASK bne do_work -#endif +#endif /* !CONFIG_PREEMPT */ + .globl fast_exc_return_irq +fast_exc_return_irq: restore: -BEGIN_FW_FTR_SECTION + /* + * This is the main kernel exit path, we first check if we + * have to change our interrupt state. + */ ld r5,SOFTE(r1) -FW_FTR_SECTION_ELSE - b .Liseries_check_pending_irqs -ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) -2: - TRACE_AND_RESTORE_IRQ(r5); + lbz r6,PACASOFTIRQEN(r13) + cmpwi cr1,r5,0 + cmpw cr0,r5,r6 + beq cr0,4f + + /* We do, handle disable first, which is easy */ + bne cr1,3f; + li r0,0 + stb r0,PACASOFTIRQEN(r13); + TRACE_DISABLE_INTS + b 4f - /* extract EE bit and use it to restore paca->hard_enabled */ - ld r3,_MSR(r1) - rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ - stb r4,PACAHARDIRQEN(r13) +3: /* + * We are about to soft-enable interrupts (we are hard disabled + * at this point). We check if there's anything that needs to + * be replayed first. + */ + lbz r0,PACAIRQHAPPENED(r13) + cmpwi cr0,r0,0 + bne- restore_check_irq_replay + /* + * Get here when nothing happened while soft-disabled, just + * soft-enable and move-on. We will hard-enable as a side + * effect of rfi + */ +restore_no_replay: + TRACE_ENABLE_INTS + li r0,1 + stb r0,PACASOFTIRQEN(r13); + + /* + * Final return path. BookE is handled in a different file + */ +4: #ifdef CONFIG_PPC_BOOK3E b .exception_return_book3e #else + /* + * Clear the reservation. If we know the CPU tracks the address of + * the reservation then we can potentially save some cycles and use + * a larx. On POWER6 and POWER7 this is significantly faster. + */ +BEGIN_FTR_SECTION + stdcx. r0,0,r1 /* to clear the reservation */ +FTR_SECTION_ELSE + ldarx r4,0,r1 +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + + /* + * Some code path such as load_up_fpu or altivec return directly + * here. They run entirely hard disabled and do not alter the + * interrupt state. They also don't use lwarx/stwcx. and thus + * are known not to leave dangling reservations. + */ + .globl fast_exception_return +fast_exception_return: + ld r3,_MSR(r1) ld r4,_CTR(r1) ld r0,_LINK(r1) mtctr r4 @@ -623,28 +663,18 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) beq- unrecov_restore /* - * Clear the reservation. If we know the CPU tracks the address of - * the reservation then we can potentially save some cycles and use - * a larx. On POWER6 and POWER7 this is significantly faster. - */ -BEGIN_FTR_SECTION - stdcx. r0,0,r1 /* to clear the reservation */ -FTR_SECTION_ELSE - ldarx r4,0,r1 -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) - - /* * Clear RI before restoring r13. If we are returning to * userspace and we take an exception after restoring r13, * we end up corrupting the userspace r13 value. */ - mfmsr r4 - andc r4,r4,r0 /* r0 contains MSR_RI here */ + ld r4,PACAKMSR(r13) /* Get kernel MSR without EE */ + andc r4,r4,r0 /* r0 contains MSR_RI here */ mtmsrd r4,1 /* * r13 is our per cpu area, only restore it if we are returning to - * userspace + * userspace the value stored in the stack frame may belong to + * another CPU. */ andi. r0,r3,MSR_PR beq 1f @@ -669,30 +699,55 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) #endif /* CONFIG_PPC_BOOK3E */ -.Liseries_check_pending_irqs: -#ifdef CONFIG_PPC_ISERIES - ld r5,SOFTE(r1) - cmpdi 0,r5,0 - beq 2b - /* Check for pending interrupts (iSeries) */ - ld r3,PACALPPACAPTR(r13) - ld r3,LPPACAANYINT(r3) - cmpdi r3,0 - beq+ 2b /* skip do_IRQ if no interrupts */ - - li r3,0 - stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */ -#ifdef CONFIG_TRACE_IRQFLAGS - bl .trace_hardirqs_off - mfmsr r10 -#endif - ori r10,r10,MSR_EE - mtmsrd r10 /* hard-enable again */ - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_IRQ - b .ret_from_except_lite /* loop back and handle more */ -#endif + /* + * Something did happen, check if a re-emit is needed + * (this also clears paca->irq_happened) + */ +restore_check_irq_replay: + /* XXX: We could implement a fast path here where we check + * for irq_happened being just 0x01, in which case we can + * clear it and return. That means that we would potentially + * miss a decrementer having wrapped all the way around. + * + * Still, this might be useful for things like hash_page + */ + bl .__check_irq_replay + cmpwi cr0,r3,0 + beq restore_no_replay + + /* + * We need to re-emit an interrupt. We do so by re-using our + * existing exception frame. We first change the trap value, + * but we need to ensure we preserve the low nibble of it + */ + ld r4,_TRAP(r1) + clrldi r4,r4,60 + or r4,r4,r3 + std r4,_TRAP(r1) + /* + * Then find the right handler and call it. Interrupts are + * still soft-disabled and we keep them that way. + */ + cmpwi cr0,r3,0x500 + bne 1f + addi r3,r1,STACK_FRAME_OVERHEAD; + bl .do_IRQ + b .ret_from_except +1: cmpwi cr0,r3,0x900 + bne 1f + addi r3,r1,STACK_FRAME_OVERHEAD; + bl .timer_interrupt + b .ret_from_except +#ifdef CONFIG_PPC_BOOK3E +1: cmpwi cr0,r3,0x280 + bne 1f + addi r3,r1,STACK_FRAME_OVERHEAD; + bl .doorbell_exception + b .ret_from_except +#endif /* CONFIG_PPC_BOOK3E */ +1: b .ret_from_except /* What else to do here ? */ + do_work: #ifdef CONFIG_PREEMPT andi. r0,r3,MSR_PR /* Returning to user mode? */ @@ -705,31 +760,22 @@ do_work: crandc eq,cr1*4+eq,eq bne restore - /* Here we are preempting the current task. - * - * Ensure interrupts are soft-disabled. We also properly mark - * the PACA to reflect the fact that they are hard-disabled - * and trace the change + /* + * Here we are preempting the current task. We want to make + * sure we are soft-disabled first */ - li r0,0 - stb r0,PACASOFTIRQEN(r13) - stb r0,PACAHARDIRQEN(r13) - TRACE_DISABLE_INTS - - /* Call the scheduler with soft IRQs off */ + SOFT_DISABLE_INTS(r3,r4) 1: bl .preempt_schedule_irq /* Hard-disable interrupts again (and update PACA) */ #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - mfmsr r10 - rldicl r10,r10,48,1 - rotldi r10,r10,16 + ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ - li r0,0 - stb r0,PACAHARDIRQEN(r13) + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) /* Re-test flags and eventually loop */ clrrdi r9,r1,THREAD_SHIFT @@ -751,14 +797,12 @@ user_work: andi. r0,r4,_TIF_NEED_RESCHED beq 1f - li r5,1 - TRACE_AND_RESTORE_IRQ(r5); + bl .restore_interrupts bl .schedule b .ret_from_except_lite 1: bl .save_nvgprs - li r5,1 - TRACE_AND_RESTORE_IRQ(r5); + bl .restore_interrupts addi r3,r1,STACK_FRAME_OVERHEAD bl .do_notify_resume b .ret_from_except diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 429983c06f91..7215cc2495df 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -24,6 +24,7 @@ #include <asm/ptrace.h> #include <asm/ppc-opcode.h> #include <asm/mmu.h> +#include <asm/hw_irq.h> /* XXX This will ultimately add space for a special exception save * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... @@ -77,59 +78,55 @@ #define SPRN_MC_SRR1 SPRN_MCSRR1 #define NORMAL_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, GEN, addition##_GEN) + EXCEPTION_PROLOG(n, GEN, addition##_GEN(n)) #define CRIT_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, CRIT, addition##_CRIT) + EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n)) #define DBG_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, DBG, addition##_DBG) + EXCEPTION_PROLOG(n, DBG, addition##_DBG(n)) #define MC_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, MC, addition##_MC) + EXCEPTION_PROLOG(n, MC, addition##_MC(n)) /* Variants of the "addition" argument for the prolog */ -#define PROLOG_ADDITION_NONE_GEN -#define PROLOG_ADDITION_NONE_CRIT -#define PROLOG_ADDITION_NONE_DBG -#define PROLOG_ADDITION_NONE_MC +#define PROLOG_ADDITION_NONE_GEN(n) +#define PROLOG_ADDITION_NONE_CRIT(n) +#define PROLOG_ADDITION_NONE_DBG(n) +#define PROLOG_ADDITION_NONE_MC(n) -#define PROLOG_ADDITION_MASKABLE_GEN \ +#define PROLOG_ADDITION_MASKABLE_GEN(n) \ lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ cmpwi cr0,r11,0; /* yes -> go out of line */ \ - beq masked_interrupt_book3e; + beq masked_interrupt_book3e_##n -#define PROLOG_ADDITION_2REGS_GEN \ +#define PROLOG_ADDITION_2REGS_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); \ std r15,PACA_EXGEN+EX_R15(r13) -#define PROLOG_ADDITION_1REG_GEN \ +#define PROLOG_ADDITION_1REG_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); -#define PROLOG_ADDITION_2REGS_CRIT \ +#define PROLOG_ADDITION_2REGS_CRIT(n) \ std r14,PACA_EXCRIT+EX_R14(r13); \ std r15,PACA_EXCRIT+EX_R15(r13) -#define PROLOG_ADDITION_2REGS_DBG \ +#define PROLOG_ADDITION_2REGS_DBG(n) \ std r14,PACA_EXDBG+EX_R14(r13); \ std r15,PACA_EXDBG+EX_R15(r13) -#define PROLOG_ADDITION_2REGS_MC \ +#define PROLOG_ADDITION_2REGS_MC(n) \ std r14,PACA_EXMC+EX_R14(r13); \ std r15,PACA_EXMC+EX_R15(r13) -#define PROLOG_ADDITION_DOORBELL_GEN \ - lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ - cmpwi cr0,r11,0; /* yes -> go out of line */ \ - beq masked_doorbell_book3e - /* Core exception code for all exceptions except TLB misses. * XXX: Needs to make SPRN_SPRG_GEN depend on exception type */ #define EXCEPTION_COMMON(n, excf, ints) \ +exc_##n##_common: \ std r0,GPR0(r1); /* save r0 in stackframe */ \ std r2,GPR2(r1); /* save r2 in stackframe */ \ SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ @@ -167,20 +164,21 @@ std r0,RESULT(r1); /* clear regs->result */ \ ints; -/* Variants for the "ints" argument */ +/* Variants for the "ints" argument. This one does nothing when we want + * to keep interrupts in their original state + */ #define INTS_KEEP -#define INTS_DISABLE_SOFT \ - stb r0,PACASOFTIRQEN(r13); /* mark interrupts soft-disabled */ \ - TRACE_DISABLE_INTS; -#define INTS_DISABLE_HARD \ - stb r0,PACAHARDIRQEN(r13); /* and hard disabled */ -#define INTS_DISABLE_ALL \ - INTS_DISABLE_SOFT \ - INTS_DISABLE_HARD - -/* This is called by exceptions that used INTS_KEEP (that is did not clear - * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE - * to it's previous value + +/* This second version is meant for exceptions that don't immediately + * hard-enable. We set a bit in paca->irq_happened to ensure that + * a subsequent call to arch_local_irq_restore() will properly + * hard-enable and avoid the fast-path + */ +#define INTS_DISABLE SOFT_DISABLE_INTS(r3,r4) + +/* This is called by exceptions that used INTS_KEEP (that did not touch + * irq indicators in the PACA). This will restore MSR:EE to it's previous + * value * * XXX In the long run, we may want to open-code it in order to separate the * load from the wrtee, thus limiting the latency caused by the dependency @@ -238,7 +236,7 @@ exc_##n##_bad_stack: \ #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ START_EXCEPTION(label); \ NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ - EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \ + EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \ ack(r8); \ CHECK_NAPPING(); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ @@ -289,7 +287,7 @@ interrupt_end_book3e: /* Critical Input Interrupt */ START_EXCEPTION(critical_input); CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL) +// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -300,7 +298,7 @@ interrupt_end_book3e: /* Machine Check Interrupt */ START_EXCEPTION(machine_check); CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL) +// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE) // bl special_reg_save_mc // addi r3,r1,STACK_FRAME_OVERHEAD // CHECK_NAPPING(); @@ -313,7 +311,7 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS) mfspr r14,SPRN_DEAR mfspr r15,SPRN_ESR - EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP) + EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE) b storage_fault_common /* Instruction Storage Interrupt */ @@ -321,7 +319,7 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS) li r15,0 mr r14,r10 - EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP) + EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE) b storage_fault_common /* External Input Interrupt */ @@ -339,12 +337,11 @@ interrupt_end_book3e: START_EXCEPTION(program); NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG) mfspr r14,SPRN_ESR - EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT) + EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD ld r14,PACA_EXGEN+EX_R14(r13) bl .save_nvgprs - INTS_RESTORE_HARD bl .program_check_exception b .ret_from_except @@ -353,15 +350,16 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE) /* we can probably do a shorter exception entry for that one... */ EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP) - bne 1f /* if from user, just load it up */ + ld r12,_MSR(r1) + andi. r0,r12,MSR_PR; + beq- 1f + bl .load_up_fpu + b fast_exception_return +1: INTS_DISABLE bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - INTS_RESTORE_HARD bl .kernel_fp_unavailable_exception - BUG_OPCODE -1: ld r12,_MSR(r1) - bl .load_up_fpu - b fast_exception_return + b .ret_from_except /* Decrementer Interrupt */ MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC) @@ -372,7 +370,7 @@ interrupt_end_book3e: /* Watchdog Timer Interrupt */ START_EXCEPTION(watchdog); CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL) +// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -391,10 +389,9 @@ interrupt_end_book3e: /* Auxiliary Processor Unavailable Interrupt */ START_EXCEPTION(ap_unavailable); NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) - EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP) - addi r3,r1,STACK_FRAME_OVERHEAD + EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE) bl .save_nvgprs - INTS_RESTORE_HARD + addi r3,r1,STACK_FRAME_OVERHEAD bl .unknown_exception b .ret_from_except @@ -450,7 +447,7 @@ interrupt_end_book3e: mfspr r15,SPRN_SPRG_CRIT_SCRATCH mtspr SPRN_SPRG_GEN_SCRATCH,r15 mfspr r14,SPRN_DBSR - EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL) + EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r14 @@ -465,7 +462,7 @@ kernel_dbg_exc: /* Debug exception as a debug interrupt*/ START_EXCEPTION(debug_debug); - DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) + DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS) /* * If there is a single step or branch-taken exception in an @@ -515,7 +512,7 @@ kernel_dbg_exc: mfspr r15,SPRN_SPRG_DBG_SCRATCH mtspr SPRN_SPRG_GEN_SCRATCH,r15 mfspr r14,SPRN_DBSR - EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) + EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r14 @@ -525,21 +522,20 @@ kernel_dbg_exc: bl .DebugException b .ret_from_except - MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) - -/* Doorbell interrupt */ - START_EXCEPTION(doorbell) - NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL) - EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL) - CHECK_NAPPING() + START_EXCEPTION(perfmon); + NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE) addi r3,r1,STACK_FRAME_OVERHEAD - bl .doorbell_exception + bl .performance_monitor_exception b .ret_from_except_lite +/* Doorbell interrupt */ + MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE) + /* Doorbell critical Interrupt */ START_EXCEPTION(doorbell_crit); - CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) + CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE) +// EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -547,36 +543,114 @@ kernel_dbg_exc: // b ret_from_crit_except b . +/* Guest Doorbell */ MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) - MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) - MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) - MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) +/* Guest Doorbell critical Interrupt */ + START_EXCEPTION(guest_doorbell_crit); + CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE) +// EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE) +// bl special_reg_save_crit +// CHECK_NAPPING(); +// addi r3,r1,STACK_FRAME_OVERHEAD +// bl .guest_doorbell_critical_exception +// b ret_from_crit_except + b . + +/* Hypervisor call */ + START_EXCEPTION(hypercall); + NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .save_nvgprs + INTS_RESTORE_HARD + bl .unknown_exception + b .ret_from_except + +/* Embedded Hypervisor priviledged */ + START_EXCEPTION(ehpriv); + NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .save_nvgprs + INTS_RESTORE_HARD + bl .unknown_exception + b .ret_from_except /* - * An interrupt came in while soft-disabled; clear EE in SRR1, - * clear paca->hard_enabled and return. + * An interrupt came in while soft-disabled; We mark paca->irq_happened + * accordingly and if the interrupt is level sensitive, we hard disable */ -masked_doorbell_book3e: - mtcr r10 - /* Resend the doorbell to fire again when ints enabled */ - mfspr r10,SPRN_PIR - PPC_MSGSND(r10) - b masked_interrupt_book3e_common -masked_interrupt_book3e: +masked_interrupt_book3e_0x500: + /* XXX When adding support for EPR, use PACA_IRQ_EE_EDGE */ + li r11,PACA_IRQ_EE + b masked_interrupt_book3e_full_mask + +masked_interrupt_book3e_0x900: + ACK_DEC(r11); + li r11,PACA_IRQ_DEC + b masked_interrupt_book3e_no_mask +masked_interrupt_book3e_0x980: + ACK_FIT(r11); + li r11,PACA_IRQ_DEC + b masked_interrupt_book3e_no_mask +masked_interrupt_book3e_0x280: +masked_interrupt_book3e_0x2c0: + li r11,PACA_IRQ_DBELL + b masked_interrupt_book3e_no_mask + +masked_interrupt_book3e_no_mask: + mtcr r10 + lbz r10,PACAIRQHAPPENED(r13) + or r10,r10,r11 + stb r10,PACAIRQHAPPENED(r13) + b 1f +masked_interrupt_book3e_full_mask: mtcr r10 -masked_interrupt_book3e_common: - stb r11,PACAHARDIRQEN(r13) + lbz r10,PACAIRQHAPPENED(r13) + or r10,r10,r11 + stb r10,PACAIRQHAPPENED(r13) mfspr r10,SPRN_SRR1 rldicl r11,r10,48,1 /* clear MSR_EE */ rotldi r10,r11,16 mtspr SPRN_SRR1,r10 - ld r10,PACA_EXGEN+EX_R10(r13); /* restore registers */ +1: ld r10,PACA_EXGEN+EX_R10(r13); ld r11,PACA_EXGEN+EX_R11(r13); mfspr r13,SPRN_SPRG_GEN_SCRATCH; rfi b . +/* + * Called from arch_local_irq_enable when an interrupt needs + * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280 + * to indicate the kind of interrupt. MSR:EE is already off. + * We generate a stackframe like if a real interrupt had happened. + * + * Note: While MSR:EE is off, we need to make sure that _MSR + * in the generated frame has EE set to 1 or the exception + * handler will not properly re-enable them. + */ +_GLOBAL(__replay_interrupt) + /* We are going to jump to the exception common code which + * will retrieve various register values from the PACA which + * we don't give a damn about. + */ + mflr r10 + mfmsr r11 + mfcr r4 + mtspr SPRN_SPRG_GEN_SCRATCH,r13; + std r1,PACA_EXGEN+EX_R1(r13); + stw r4,PACA_EXGEN+EX_CR(r13); + ori r11,r11,MSR_EE + subi r1,r1,INT_FRAME_SIZE; + cmpwi cr0,r3,0x500 + beq exc_0x500_common + cmpwi cr0,r3,0x900 + beq exc_0x900_common + cmpwi cr0,r3,0x280 + beq exc_0x280_common + blr + /* * This is called from 0x300 and 0x400 handlers after the prologs with @@ -591,7 +665,6 @@ storage_fault_common: mr r5,r15 ld r14,PACA_EXGEN+EX_R14(r13) ld r15,PACA_EXGEN+EX_R15(r13) - INTS_RESTORE_HARD bl .do_page_fault cmpdi r3,0 bne- 1f @@ -680,6 +753,8 @@ BAD_STACK_TRAMPOLINE(0x000) BAD_STACK_TRAMPOLINE(0x100) BAD_STACK_TRAMPOLINE(0x200) BAD_STACK_TRAMPOLINE(0x260) +BAD_STACK_TRAMPOLINE(0x280) +BAD_STACK_TRAMPOLINE(0x2a0) BAD_STACK_TRAMPOLINE(0x2c0) BAD_STACK_TRAMPOLINE(0x2e0) BAD_STACK_TRAMPOLINE(0x300) @@ -697,11 +772,10 @@ BAD_STACK_TRAMPOLINE(0xa00) BAD_STACK_TRAMPOLINE(0xb00) BAD_STACK_TRAMPOLINE(0xc00) BAD_STACK_TRAMPOLINE(0xd00) +BAD_STACK_TRAMPOLINE(0xd08) BAD_STACK_TRAMPOLINE(0xe00) BAD_STACK_TRAMPOLINE(0xf00) BAD_STACK_TRAMPOLINE(0xf20) -BAD_STACK_TRAMPOLINE(0x2070) -BAD_STACK_TRAMPOLINE(0x2080) .globl bad_stack_book3e bad_stack_book3e: diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 15c5a4f6de01..2d0868a4e2f0 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -12,6 +12,7 @@ * */ +#include <asm/hw_irq.h> #include <asm/exception-64s.h> #include <asm/ptrace.h> @@ -19,7 +20,7 @@ * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code * 0x0100 - 0x2fff : pSeries Interrupt prologs - * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs + * 0x3000 - 0x5fff : interrupt support common interrupt prologs * 0x6000 - 0x6fff : Initial (CPU0) segment table * 0x7000 - 0x7fff : FWNMI data area * 0x8000 - : Early init and support code @@ -356,34 +357,60 @@ do_stab_bolted_pSeries: KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) /* - * An interrupt came in while soft-disabled; clear EE in SRR1, - * clear paca->hard_enabled and return. + * An interrupt came in while soft-disabled. We set paca->irq_happened, + * then, if it was a decrementer interrupt, we bump the dec to max and + * and return, else we hard disable and return. This is called with + * r10 containing the value to OR to the paca field. */ -masked_interrupt: - stb r10,PACAHARDIRQEN(r13) - mtcrf 0x80,r9 - ld r9,PACA_EXGEN+EX_R9(r13) - mfspr r10,SPRN_SRR1 - rldicl r10,r10,48,1 /* clear MSR_EE */ - rotldi r10,r10,16 - mtspr SPRN_SRR1,r10 - ld r10,PACA_EXGEN+EX_R10(r13) - GET_SCRATCH0(r13) - rfid +#define MASKED_INTERRUPT(_H) \ +masked_##_H##interrupt: \ + std r11,PACA_EXGEN+EX_R11(r13); \ + lbz r11,PACAIRQHAPPENED(r13); \ + or r11,r11,r10; \ + stb r11,PACAIRQHAPPENED(r13); \ + andi. r10,r10,PACA_IRQ_DEC; \ + beq 1f; \ + lis r10,0x7fff; \ + ori r10,r10,0xffff; \ + mtspr SPRN_DEC,r10; \ + b 2f; \ +1: mfspr r10,SPRN_##_H##SRR1; \ + rldicl r10,r10,48,1; /* clear MSR_EE */ \ + rotldi r10,r10,16; \ + mtspr SPRN_##_H##SRR1,r10; \ +2: mtcrf 0x80,r9; \ + ld r9,PACA_EXGEN+EX_R9(r13); \ + ld r10,PACA_EXGEN+EX_R10(r13); \ + ld r11,PACA_EXGEN+EX_R11(r13); \ + GET_SCRATCH0(r13); \ + ##_H##rfid; \ b . + + MASKED_INTERRUPT() + MASKED_INTERRUPT(H) -masked_Hinterrupt: - stb r10,PACAHARDIRQEN(r13) - mtcrf 0x80,r9 - ld r9,PACA_EXGEN+EX_R9(r13) - mfspr r10,SPRN_HSRR1 - rldicl r10,r10,48,1 /* clear MSR_EE */ - rotldi r10,r10,16 - mtspr SPRN_HSRR1,r10 - ld r10,PACA_EXGEN+EX_R10(r13) - GET_SCRATCH0(r13) - hrfid - b . +/* + * Called from arch_local_irq_enable when an interrupt needs + * to be resent. r3 contains 0x500 or 0x900 to indicate which + * kind of interrupt. MSR:EE is already off. We generate a + * stackframe like if a real interrupt had happened. + * + * Note: While MSR:EE is off, we need to make sure that _MSR + * in the generated frame has EE set to 1 or the exception + * handler will not properly re-enable them. + */ +_GLOBAL(__replay_interrupt) + /* We are going to jump to the exception common code which + * will retrieve various register values from the PACA which + * we don't give a damn about, so we don't bother storing them. + */ + mfmsr r12 + mflr r11 + mfcr r9 + ori r12,r12,MSR_EE + andi. r3,r3,0x0800 + bne decrementer_common + b hardware_interrupt_common #ifdef CONFIG_PPC_PSERIES /* @@ -458,14 +485,15 @@ machine_check_common: bl .machine_check_exception b .ret_from_except - STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) + STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) + STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) - STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) + STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) #ifdef CONFIG_ALTIVEC STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) @@ -482,6 +510,9 @@ machine_check_common: system_call_entry: b system_call_common +ppc64_runlatch_on_trampoline: + b .__ppc64_runlatch_on + /* * Here we have detected that the kernel stack pointer is bad. * R9 contains the saved CR, r13 points to the paca, @@ -555,6 +586,8 @@ data_access_common: mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) + DISABLE_INTS + ld r12,_MSR(r1) ld r3,PACA_EXGEN+EX_DAR(r13) lwz r4,PACA_EXGEN+EX_DSISR(r13) li r5,0x300 @@ -569,6 +602,7 @@ h_data_storage_common: stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) bl .save_nvgprs + DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD bl .unknown_exception b .ret_from_except @@ -577,6 +611,8 @@ h_data_storage_common: .globl instruction_access_common instruction_access_common: EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) + DISABLE_INTS + ld r12,_MSR(r1) ld r3,_NIP(r1) andis. r4,r12,0x5820 li r5,0x400 @@ -672,12 +708,6 @@ _GLOBAL(slb_miss_realmode) ld r10,PACA_EXSLB+EX_LR(r13) ld r3,PACA_EXSLB+EX_R3(r13) lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - ld r11,PACALPPACAPTR(r13) - ld r11,LPPACASRR0(r11) /* get SRR0 value */ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif /* CONFIG_PPC_ISERIES */ mtlr r10 @@ -690,12 +720,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ .machine pop -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - mtspr SPRN_SRR0,r11 - mtspr SPRN_SRR1,r12 -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) ld r11,PACA_EXSLB+EX_R11(r13) @@ -704,13 +728,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) rfid b . /* prevent speculative execution */ -2: -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - b unrecov_slb -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif /* CONFIG_PPC_ISERIES */ - mfspr r11,SPRN_SRR0 +2: mfspr r11,SPRN_SRR0 ld r10,PACAKBASE(r13) LOAD_HANDLER(r10,unrecov_slb) mtspr SPRN_SRR0,r10 @@ -727,20 +745,6 @@ unrecov_slb: bl .unrecoverable_exception b 1b - .align 7 - .globl hardware_interrupt_common - .globl hardware_interrupt_entry -hardware_interrupt_common: - EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN) - FINISH_NAP -hardware_interrupt_entry: - DISABLE_INTS -BEGIN_FTR_SECTION - bl .ppc64_runlatch_on -END_FTR_SECTION_IFSET(CPU_FTR_CTRL) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_IRQ - b .ret_from_except_lite #ifdef CONFIG_PPC_970_NAP power4_fixup_nap: @@ -785,8 +789,8 @@ fp_unavailable_common: EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) bne 1f /* if from user, just load it up */ bl .save_nvgprs + DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS bl .kernel_fp_unavailable_exception BUG_OPCODE 1: bl .load_up_fpu @@ -805,8 +809,8 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif bl .save_nvgprs + DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS bl .altivec_unavailable_exception b .ret_from_except @@ -816,13 +820,14 @@ vsx_unavailable_common: EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) #ifdef CONFIG_VSX BEGIN_FTR_SECTION - bne .load_up_vsx + beq 1f + b .load_up_vsx 1: END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif bl .save_nvgprs + DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS bl .vsx_unavailable_exception b .ret_from_except @@ -831,66 +836,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) __end_handlers: /* - * Return from an exception with minimal checks. - * The caller is assumed to have done EXCEPTION_PROLOG_COMMON. - * If interrupts have been enabled, or anything has been - * done that might have changed the scheduling status of - * any task or sent any task a signal, you should use - * ret_from_except or ret_from_except_lite instead of this. - */ -fast_exc_return_irq: /* restores irq state too */ - ld r3,SOFTE(r1) - TRACE_AND_RESTORE_IRQ(r3); - ld r12,_MSR(r1) - rldicl r4,r12,49,63 /* get MSR_EE to LSB */ - stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ - b 1f - - .globl fast_exception_return -fast_exception_return: - ld r12,_MSR(r1) -1: ld r11,_NIP(r1) - andi. r3,r12,MSR_RI /* check if RI is set */ - beq- unrecov_fer - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING - andi. r3,r12,MSR_PR - beq 2f - ACCOUNT_CPU_USER_EXIT(r3, r4) -2: -#endif - - ld r3,_CCR(r1) - ld r4,_LINK(r1) - ld r5,_CTR(r1) - ld r6,_XER(r1) - mtcr r3 - mtlr r4 - mtctr r5 - mtxer r6 - REST_GPR(0, r1) - REST_8GPRS(2, r1) - - mfmsr r10 - rldicl r10,r10,48,1 /* clear EE */ - rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */ - mtmsrd r10,1 - - mtspr SPRN_SRR1,r12 - mtspr SPRN_SRR0,r11 - REST_4GPRS(10, r1) - ld r1,GPR1(r1) - rfid - b . /* prevent speculative execution */ - -unrecov_fer: - bl .save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b 1b - - -/* * Hash table stuff */ .align 7 @@ -912,28 +857,6 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */ bne 77f /* then don't call hash_page now */ - - /* - * On iSeries, we soft-disable interrupts here, then - * hard-enable interrupts so that the hash_page code can spin on - * the hash_table_lock without problems on a shared processor. - */ - DISABLE_INTS - - /* - * Currently, trace_hardirqs_off() will be called by DISABLE_INTS - * and will clobber volatile registers when irq tracing is enabled - * so we need to reload them. It may be possible to be smarter here - * and move the irq tracing elsewhere but let's keep it simple for - * now - */ -#ifdef CONFIG_TRACE_IRQFLAGS - ld r3,_DAR(r1) - ld r4,_DSISR(r1) - ld r5,_TRAP(r1) - ld r12,_MSR(r1) - clrrdi r5,r5,4 -#endif /* CONFIG_TRACE_IRQFLAGS */ /* * We need to set the _PAGE_USER bit if MSR_PR is set or if we are * accessing a userspace segment (even from the kernel). We assume @@ -951,62 +874,25 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) * r4 contains the required access permissions * r5 contains the trap number * - * at return r3 = 0 for success + * at return r3 = 0 for success, 1 for page fault, negative for error */ bl .hash_page /* build HPTE if possible */ cmpdi r3,0 /* see if hash_page succeeded */ -BEGIN_FW_FTR_SECTION - /* - * If we had interrupts soft-enabled at the point where the - * DSI/ISI occurred, and an interrupt came in during hash_page, - * handle it now. - * We jump to ret_from_except_lite rather than fast_exception_return - * because ret_from_except_lite will check for and handle pending - * interrupts if necessary. - */ - beq 13f -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) - -BEGIN_FW_FTR_SECTION - /* - * Here we have interrupts hard-disabled, so it is sufficient - * to restore paca->{soft,hard}_enable and get out. - */ + /* Success */ beq fast_exc_return_irq /* Return from exception on success */ -END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) - - /* For a hash failure, we don't bother re-enabling interrupts */ - ble- 12f - - /* - * hash_page couldn't handle it, set soft interrupt enable back - * to what it was before the trap. Note that .arch_local_irq_restore - * handles any interrupts pending at this point. - */ - ld r3,SOFTE(r1) - TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f) - bl .arch_local_irq_restore - b 11f -/* We have a data breakpoint exception - handle it */ -handle_dabr_fault: - bl .save_nvgprs - ld r4,_DAR(r1) - ld r5,_DSISR(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_dabr - b .ret_from_except_lite + /* Error */ + blt- 13f /* Here we have a page fault that hash_page can't handle. */ handle_page_fault: - ENABLE_INTS 11: ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD bl .do_page_fault cmpdi r3,0 - beq+ 13f + beq+ 12f bl .save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD @@ -1014,12 +900,20 @@ handle_page_fault: bl .bad_page_fault b .ret_from_except -13: b .ret_from_except_lite +/* We have a data breakpoint exception - handle it */ +handle_dabr_fault: + bl .save_nvgprs + ld r4,_DAR(r1) + ld r5,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_dabr +12: b .ret_from_except_lite + /* We have a page fault that hash_page could handle but HV refused * the PTE insertion */ -12: bl .save_nvgprs +13: bl .save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD ld r4,_DAR(r1) @@ -1141,51 +1035,19 @@ _GLOBAL(do_stab_bolted) .= 0x7000 .globl fwnmi_data_area fwnmi_data_area: -#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ - /* iSeries does not use the FWNMI stuff, so it is safe to put - * this here, even if we later allow kernels that will boot on - * both pSeries and iSeries */ -#ifdef CONFIG_PPC_ISERIES - . = LPARMAP_PHYS - .globl xLparMap -xLparMap: - .quad HvEsidsToMap /* xNumberEsids */ - .quad HvRangesToMap /* xNumberRanges */ - .quad STAB0_PAGE /* xSegmentTableOffs */ - .zero 40 /* xRsvd */ - /* xEsids (HvEsidsToMap entries of 2 quads) */ - .quad PAGE_OFFSET_ESID /* xKernelEsid */ - .quad PAGE_OFFSET_VSID /* xKernelVsid */ - .quad VMALLOC_START_ESID /* xKernelEsid */ - .quad VMALLOC_START_VSID /* xKernelVsid */ - /* xRanges (HvRangesToMap entries of 3 quads) */ - .quad HvPagesToMap /* xPages */ - .quad 0 /* xOffset */ - .quad PAGE_OFFSET_VSID << (SID_SHIFT - HW_PAGE_SHIFT) /* xVPN */ - -#endif /* CONFIG_PPC_ISERIES */ - -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* pseries and powernv need to keep the whole page from * 0x7000 to 0x8000 free for use by the firmware */ . = 0x8000 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ -/* - * Space for CPU0's segment table. - * - * On iSeries, the hypervisor must fill in at least one entry before - * we get control (with relocate on). The address is given to the hv - * as a page number (see xLparMap above), so this must be at a - * fixed address (the linker can't compute (u64)&initial_stab >> - * PAGE_SHIFT). - */ - . = STAB0_OFFSET /* 0x8000 */ +/* Space for CPU0's segment table */ + .balign 4096 .globl initial_stab initial_stab: .space 4096 + #ifdef CONFIG_PPC_POWERNV _GLOBAL(opal_mc_secondary_handler) HMT_MEDIUM diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c new file mode 100644 index 000000000000..cfe7a38708c3 --- /dev/null +++ b/arch/powerpc/kernel/fadump.c @@ -0,0 +1,1315 @@ +/* + * Firmware Assisted dump: A robust mechanism to get reliable kernel crash + * dump with assistance from firmware. This approach does not use kexec, + * instead firmware assists in booting the kdump kernel while preserving + * memory contents. The most of the code implementation has been adapted + * from phyp assisted dump implementation written by Linas Vepstas and + * Manish Ahuja + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright 2011 IBM Corporation + * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> + */ + +#undef DEBUG +#define pr_fmt(fmt) "fadump: " fmt + +#include <linux/string.h> +#include <linux/memblock.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/crash_dump.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> + +#include <asm/page.h> +#include <asm/prom.h> +#include <asm/rtas.h> +#include <asm/fadump.h> + +static struct fw_dump fw_dump; +static struct fadump_mem_struct fdm; +static const struct fadump_mem_struct *fdm_active; + +static DEFINE_MUTEX(fadump_mutex); +struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES]; +int crash_mem_ranges; + +/* Scan the Firmware Assisted dump configuration details. */ +int __init early_init_dt_scan_fw_dump(unsigned long node, + const char *uname, int depth, void *data) +{ + __be32 *sections; + int i, num_sections; + unsigned long size; + const int *token; + + if (depth != 1 || strcmp(uname, "rtas") != 0) + return 0; + + /* + * Check if Firmware Assisted dump is supported. if yes, check + * if dump has been initiated on last reboot. + */ + token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL); + if (!token) + return 0; + + fw_dump.fadump_supported = 1; + fw_dump.ibm_configure_kernel_dump = *token; + + /* + * The 'ibm,kernel-dump' rtas node is present only if there is + * dump data waiting for us. + */ + fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL); + if (fdm_active) + fw_dump.dump_active = 1; + + /* Get the sizes required to store dump data for the firmware provided + * dump sections. + * For each dump section type supported, a 32bit cell which defines + * the ID of a supported section followed by two 32 bit cells which + * gives teh size of the section in bytes. + */ + sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", + &size); + + if (!sections) + return 0; + + num_sections = size / (3 * sizeof(u32)); + + for (i = 0; i < num_sections; i++, sections += 3) { + u32 type = (u32)of_read_number(sections, 1); + + switch (type) { + case FADUMP_CPU_STATE_DATA: + fw_dump.cpu_state_data_size = + of_read_ulong(§ions[1], 2); + break; + case FADUMP_HPTE_REGION: + fw_dump.hpte_region_size = + of_read_ulong(§ions[1], 2); + break; + } + } + return 1; +} + +int is_fadump_active(void) +{ + return fw_dump.dump_active; +} + +/* Print firmware assisted dump configurations for debugging purpose. */ +static void fadump_show_config(void) +{ + pr_debug("Support for firmware-assisted dump (fadump): %s\n", + (fw_dump.fadump_supported ? "present" : "no support")); + + if (!fw_dump.fadump_supported) + return; + + pr_debug("Fadump enabled : %s\n", + (fw_dump.fadump_enabled ? "yes" : "no")); + pr_debug("Dump Active : %s\n", + (fw_dump.dump_active ? "yes" : "no")); + pr_debug("Dump section sizes:\n"); + pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size); + pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size); + pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size); +} + +static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm, + unsigned long addr) +{ + if (!fdm) + return 0; + + memset(fdm, 0, sizeof(struct fadump_mem_struct)); + addr = addr & PAGE_MASK; + + fdm->header.dump_format_version = 0x00000001; + fdm->header.dump_num_sections = 3; + fdm->header.dump_status_flag = 0; + fdm->header.offset_first_dump_section = + (u32)offsetof(struct fadump_mem_struct, cpu_state_data); + + /* + * Fields for disk dump option. + * We are not using disk dump option, hence set these fields to 0. + */ + fdm->header.dd_block_size = 0; + fdm->header.dd_block_offset = 0; + fdm->header.dd_num_blocks = 0; + fdm->header.dd_offset_disk_path = 0; + + /* set 0 to disable an automatic dump-reboot. */ + fdm->header.max_time_auto = 0; + + /* Kernel dump sections */ + /* cpu state data section. */ + fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG; + fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA; + fdm->cpu_state_data.source_address = 0; + fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size; + fdm->cpu_state_data.destination_address = addr; + addr += fw_dump.cpu_state_data_size; + + /* hpte region section */ + fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG; + fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION; + fdm->hpte_region.source_address = 0; + fdm->hpte_region.source_len = fw_dump.hpte_region_size; + fdm->hpte_region.destination_address = addr; + addr += fw_dump.hpte_region_size; + + /* RMA region section */ + fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG; + fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION; + fdm->rmr_region.source_address = RMA_START; + fdm->rmr_region.source_len = fw_dump.boot_memory_size; + fdm->rmr_region.destination_address = addr; + addr += fw_dump.boot_memory_size; + + return addr; +} + +/** + * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM + * + * Function to find the largest memory size we need to reserve during early + * boot process. This will be the size of the memory that is required for a + * kernel to boot successfully. + * + * This function has been taken from phyp-assisted dump feature implementation. + * + * returns larger of 256MB or 5% rounded down to multiples of 256MB. + * + * TODO: Come up with better approach to find out more accurate memory size + * that is required for a kernel to boot successfully. + * + */ +static inline unsigned long fadump_calculate_reserve_size(void) +{ + unsigned long size; + + /* + * Check if the size is specified through fadump_reserve_mem= cmdline + * option. If yes, then use that. + */ + if (fw_dump.reserve_bootvar) + return fw_dump.reserve_bootvar; + + /* divide by 20 to get 5% of value */ + size = memblock_end_of_DRAM() / 20; + + /* round it down in multiples of 256 */ + size = size & ~0x0FFFFFFFUL; + + /* Truncate to memory_limit. We don't want to over reserve the memory.*/ + if (memory_limit && size > memory_limit) + size = memory_limit; + + return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM); +} + +/* + * Calculate the total memory size required to be reserved for + * firmware-assisted dump registration. + */ +static unsigned long get_fadump_area_size(void) +{ + unsigned long size = 0; + + size += fw_dump.cpu_state_data_size; + size += fw_dump.hpte_region_size; + size += fw_dump.boot_memory_size; + size += sizeof(struct fadump_crash_info_header); + size += sizeof(struct elfhdr); /* ELF core header.*/ + size += sizeof(struct elf_phdr); /* place holder for cpu notes */ + /* Program headers for crash memory regions. */ + size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2); + + size = PAGE_ALIGN(size); + return size; +} + +int __init fadump_reserve_mem(void) +{ + unsigned long base, size, memory_boundary; + + if (!fw_dump.fadump_enabled) + return 0; + + if (!fw_dump.fadump_supported) { + printk(KERN_INFO "Firmware-assisted dump is not supported on" + " this hardware\n"); + fw_dump.fadump_enabled = 0; + return 0; + } + /* + * Initialize boot memory size + * If dump is active then we have already calculated the size during + * first kernel. + */ + if (fdm_active) + fw_dump.boot_memory_size = fdm_active->rmr_region.source_len; + else + fw_dump.boot_memory_size = fadump_calculate_reserve_size(); + + /* + * Calculate the memory boundary. + * If memory_limit is less than actual memory boundary then reserve + * the memory for fadump beyond the memory_limit and adjust the + * memory_limit accordingly, so that the running kernel can run with + * specified memory_limit. + */ + if (memory_limit && memory_limit < memblock_end_of_DRAM()) { + size = get_fadump_area_size(); + if ((memory_limit + size) < memblock_end_of_DRAM()) + memory_limit += size; + else + memory_limit = memblock_end_of_DRAM(); + printk(KERN_INFO "Adjusted memory_limit for firmware-assisted" + " dump, now %#016llx\n", + (unsigned long long)memory_limit); + } + if (memory_limit) + memory_boundary = memory_limit; + else + memory_boundary = memblock_end_of_DRAM(); + + if (fw_dump.dump_active) { + printk(KERN_INFO "Firmware-assisted dump is active.\n"); + /* + * If last boot has crashed then reserve all the memory + * above boot_memory_size so that we don't touch it until + * dump is written to disk by userspace tool. This memory + * will be released for general use once the dump is saved. + */ + base = fw_dump.boot_memory_size; + size = memory_boundary - base; + memblock_reserve(base, size); + printk(KERN_INFO "Reserved %ldMB of memory at %ldMB " + "for saving crash dump\n", + (unsigned long)(size >> 20), + (unsigned long)(base >> 20)); + + fw_dump.fadumphdr_addr = + fdm_active->rmr_region.destination_address + + fdm_active->rmr_region.source_len; + pr_debug("fadumphdr_addr = %p\n", + (void *) fw_dump.fadumphdr_addr); + } else { + /* Reserve the memory at the top of memory. */ + size = get_fadump_area_size(); + base = memory_boundary - size; + memblock_reserve(base, size); + printk(KERN_INFO "Reserved %ldMB of memory at %ldMB " + "for firmware-assisted dump\n", + (unsigned long)(size >> 20), + (unsigned long)(base >> 20)); + } + fw_dump.reserve_dump_area_start = base; + fw_dump.reserve_dump_area_size = size; + return 1; +} + +/* Look for fadump= cmdline option. */ +static int __init early_fadump_param(char *p) +{ + if (!p) + return 1; + + if (strncmp(p, "on", 2) == 0) + fw_dump.fadump_enabled = 1; + else if (strncmp(p, "off", 3) == 0) + fw_dump.fadump_enabled = 0; + + return 0; +} +early_param("fadump", early_fadump_param); + +/* Look for fadump_reserve_mem= cmdline option */ +static int __init early_fadump_reserve_mem(char *p) +{ + if (p) + fw_dump.reserve_bootvar = memparse(p, &p); + return 0; +} +early_param("fadump_reserve_mem", early_fadump_reserve_mem); + +static void register_fw_dump(struct fadump_mem_struct *fdm) +{ + int rc; + unsigned int wait_time; + + pr_debug("Registering for firmware-assisted kernel dump...\n"); + + /* TODO: Add upper time limit for the delay */ + do { + rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, + FADUMP_REGISTER, fdm, + sizeof(struct fadump_mem_struct)); + + wait_time = rtas_busy_delay_time(rc); + if (wait_time) + mdelay(wait_time); + + } while (wait_time); + + switch (rc) { + case -1: + printk(KERN_ERR "Failed to register firmware-assisted kernel" + " dump. Hardware Error(%d).\n", rc); + break; + case -3: + printk(KERN_ERR "Failed to register firmware-assisted kernel" + " dump. Parameter Error(%d).\n", rc); + break; + case -9: + printk(KERN_ERR "firmware-assisted kernel dump is already " + " registered."); + fw_dump.dump_registered = 1; + break; + case 0: + printk(KERN_INFO "firmware-assisted kernel dump registration" + " is successful\n"); + fw_dump.dump_registered = 1; + break; + } +} + +void crash_fadump(struct pt_regs *regs, const char *str) +{ + struct fadump_crash_info_header *fdh = NULL; + + if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr) + return; + + fdh = __va(fw_dump.fadumphdr_addr); + crashing_cpu = smp_processor_id(); + fdh->crashing_cpu = crashing_cpu; + crash_save_vmcoreinfo(); + + if (regs) + fdh->regs = *regs; + else + ppc_save_regs(&fdh->regs); + + fdh->cpu_online_mask = *cpu_online_mask; + + /* Call ibm,os-term rtas call to trigger firmware assisted dump */ + rtas_os_term((char *)str); +} + +#define GPR_MASK 0xffffff0000000000 +static inline int fadump_gpr_index(u64 id) +{ + int i = -1; + char str[3]; + + if ((id & GPR_MASK) == REG_ID("GPR")) { + /* get the digits at the end */ + id &= ~GPR_MASK; + id >>= 24; + str[2] = '\0'; + str[1] = id & 0xff; + str[0] = (id >> 8) & 0xff; + sscanf(str, "%d", &i); + if (i > 31) + i = -1; + } + return i; +} + +static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id, + u64 reg_val) +{ + int i; + + i = fadump_gpr_index(reg_id); + if (i >= 0) + regs->gpr[i] = (unsigned long)reg_val; + else if (reg_id == REG_ID("NIA")) + regs->nip = (unsigned long)reg_val; + else if (reg_id == REG_ID("MSR")) + regs->msr = (unsigned long)reg_val; + else if (reg_id == REG_ID("CTR")) + regs->ctr = (unsigned long)reg_val; + else if (reg_id == REG_ID("LR")) + regs->link = (unsigned long)reg_val; + else if (reg_id == REG_ID("XER")) + regs->xer = (unsigned long)reg_val; + else if (reg_id == REG_ID("CR")) + regs->ccr = (unsigned long)reg_val; + else if (reg_id == REG_ID("DAR")) + regs->dar = (unsigned long)reg_val; + else if (reg_id == REG_ID("DSISR")) + regs->dsisr = (unsigned long)reg_val; +} + +static struct fadump_reg_entry* +fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs) +{ + memset(regs, 0, sizeof(struct pt_regs)); + + while (reg_entry->reg_id != REG_ID("CPUEND")) { + fadump_set_regval(regs, reg_entry->reg_id, + reg_entry->reg_value); + reg_entry++; + } + reg_entry++; + return reg_entry; +} + +static u32 *fadump_append_elf_note(u32 *buf, char *name, unsigned type, + void *data, size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) + 3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void fadump_final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs) +{ + struct elf_prstatus prstatus; + + memset(&prstatus, 0, sizeof(prstatus)); + /* + * FIXME: How do i get PID? Do I really need it? + * prstatus.pr_pid = ???? + */ + elf_core_copy_kernel_regs(&prstatus.pr_reg, regs); + buf = fadump_append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, + &prstatus, sizeof(prstatus)); + return buf; +} + +static void fadump_update_elfcore_header(char *bufp) +{ + struct elfhdr *elf; + struct elf_phdr *phdr; + + elf = (struct elfhdr *)bufp; + bufp += sizeof(struct elfhdr); + + /* First note is a place holder for cpu notes info. */ + phdr = (struct elf_phdr *)bufp; + + if (phdr->p_type == PT_NOTE) { + phdr->p_paddr = fw_dump.cpu_notes_buf; + phdr->p_offset = phdr->p_paddr; + phdr->p_filesz = fw_dump.cpu_notes_buf_size; + phdr->p_memsz = fw_dump.cpu_notes_buf_size; + } + return; +} + +static void *fadump_cpu_notes_buf_alloc(unsigned long size) +{ + void *vaddr; + struct page *page; + unsigned long order, count, i; + + order = get_order(size); + vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order); + if (!vaddr) + return NULL; + + count = 1 << order; + page = virt_to_page(vaddr); + for (i = 0; i < count; i++) + SetPageReserved(page + i); + return vaddr; +} + +static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size) +{ + struct page *page; + unsigned long order, count, i; + + order = get_order(size); + count = 1 << order; + page = virt_to_page(vaddr); + for (i = 0; i < count; i++) + ClearPageReserved(page + i); + __free_pages(page, order); +} + +/* + * Read CPU state dump data and convert it into ELF notes. + * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be + * used to access the data to allow for additional fields to be added without + * affecting compatibility. Each list of registers for a CPU starts with + * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes, + * 8 Byte ASCII identifier and 8 Byte register value. The register entry + * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part + * of register value. For more details refer to PAPR document. + * + * Only for the crashing cpu we ignore the CPU dump data and get exact + * state from fadump crash info structure populated by first kernel at the + * time of crash. + */ +static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm) +{ + struct fadump_reg_save_area_header *reg_header; + struct fadump_reg_entry *reg_entry; + struct fadump_crash_info_header *fdh = NULL; + void *vaddr; + unsigned long addr; + u32 num_cpus, *note_buf; + struct pt_regs regs; + int i, rc = 0, cpu = 0; + + if (!fdm->cpu_state_data.bytes_dumped) + return -EINVAL; + + addr = fdm->cpu_state_data.destination_address; + vaddr = __va(addr); + + reg_header = vaddr; + if (reg_header->magic_number != REGSAVE_AREA_MAGIC) { + printk(KERN_ERR "Unable to read register save area.\n"); + return -ENOENT; + } + pr_debug("--------CPU State Data------------\n"); + pr_debug("Magic Number: %llx\n", reg_header->magic_number); + pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset); + + vaddr += reg_header->num_cpu_offset; + num_cpus = *((u32 *)(vaddr)); + pr_debug("NumCpus : %u\n", num_cpus); + vaddr += sizeof(u32); + reg_entry = (struct fadump_reg_entry *)vaddr; + + /* Allocate buffer to hold cpu crash notes. */ + fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t); + fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size); + note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size); + if (!note_buf) { + printk(KERN_ERR "Failed to allocate 0x%lx bytes for " + "cpu notes buffer\n", fw_dump.cpu_notes_buf_size); + return -ENOMEM; + } + fw_dump.cpu_notes_buf = __pa(note_buf); + + pr_debug("Allocated buffer for cpu notes of size %ld at %p\n", + (num_cpus * sizeof(note_buf_t)), note_buf); + + if (fw_dump.fadumphdr_addr) + fdh = __va(fw_dump.fadumphdr_addr); + + for (i = 0; i < num_cpus; i++) { + if (reg_entry->reg_id != REG_ID("CPUSTRT")) { + printk(KERN_ERR "Unable to read CPU state data\n"); + rc = -ENOENT; + goto error_out; + } + /* Lower 4 bytes of reg_value contains logical cpu id */ + cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK; + if (!cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) { + SKIP_TO_NEXT_CPU(reg_entry); + continue; + } + pr_debug("Reading register data for cpu %d...\n", cpu); + if (fdh && fdh->crashing_cpu == cpu) { + regs = fdh->regs; + note_buf = fadump_regs_to_elf_notes(note_buf, ®s); + SKIP_TO_NEXT_CPU(reg_entry); + } else { + reg_entry++; + reg_entry = fadump_read_registers(reg_entry, ®s); + note_buf = fadump_regs_to_elf_notes(note_buf, ®s); + } + } + fadump_final_note(note_buf); + + pr_debug("Updating elfcore header (%llx) with cpu notes\n", + fdh->elfcorehdr_addr); + fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr)); + return 0; + +error_out: + fadump_cpu_notes_buf_free((unsigned long)__va(fw_dump.cpu_notes_buf), + fw_dump.cpu_notes_buf_size); + fw_dump.cpu_notes_buf = 0; + fw_dump.cpu_notes_buf_size = 0; + return rc; + +} + +/* + * Validate and process the dump data stored by firmware before exporting + * it through '/proc/vmcore'. + */ +static int __init process_fadump(const struct fadump_mem_struct *fdm_active) +{ + struct fadump_crash_info_header *fdh; + int rc = 0; + + if (!fdm_active || !fw_dump.fadumphdr_addr) + return -EINVAL; + + /* Check if the dump data is valid. */ + if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) || + (fdm_active->cpu_state_data.error_flags != 0) || + (fdm_active->rmr_region.error_flags != 0)) { + printk(KERN_ERR "Dump taken by platform is not valid\n"); + return -EINVAL; + } + if ((fdm_active->rmr_region.bytes_dumped != + fdm_active->rmr_region.source_len) || + !fdm_active->cpu_state_data.bytes_dumped) { + printk(KERN_ERR "Dump taken by platform is incomplete\n"); + return -EINVAL; + } + + /* Validate the fadump crash info header */ + fdh = __va(fw_dump.fadumphdr_addr); + if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { + printk(KERN_ERR "Crash info header is not valid.\n"); + return -EINVAL; + } + + rc = fadump_build_cpu_notes(fdm_active); + if (rc) + return rc; + + /* + * We are done validating dump info and elfcore header is now ready + * to be exported. set elfcorehdr_addr so that vmcore module will + * export the elfcore header through '/proc/vmcore'. + */ + elfcorehdr_addr = fdh->elfcorehdr_addr; + + return 0; +} + +static inline void fadump_add_crash_memory(unsigned long long base, + unsigned long long end) +{ + if (base == end) + return; + + pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n", + crash_mem_ranges, base, end - 1, (end - base)); + crash_memory_ranges[crash_mem_ranges].base = base; + crash_memory_ranges[crash_mem_ranges].size = end - base; + crash_mem_ranges++; +} + +static void fadump_exclude_reserved_area(unsigned long long start, + unsigned long long end) +{ + unsigned long long ra_start, ra_end; + + ra_start = fw_dump.reserve_dump_area_start; + ra_end = ra_start + fw_dump.reserve_dump_area_size; + + if ((ra_start < end) && (ra_end > start)) { + if ((start < ra_start) && (end > ra_end)) { + fadump_add_crash_memory(start, ra_start); + fadump_add_crash_memory(ra_end, end); + } else if (start < ra_start) { + fadump_add_crash_memory(start, ra_start); + } else if (ra_end < end) { + fadump_add_crash_memory(ra_end, end); + } + } else + fadump_add_crash_memory(start, end); +} + +static int fadump_init_elfcore_header(char *bufp) +{ + struct elfhdr *elf; + + elf = (struct elfhdr *) bufp; + bufp += sizeof(struct elfhdr); + memcpy(elf->e_ident, ELFMAG, SELFMAG); + elf->e_ident[EI_CLASS] = ELF_CLASS; + elf->e_ident[EI_DATA] = ELF_DATA; + elf->e_ident[EI_VERSION] = EV_CURRENT; + elf->e_ident[EI_OSABI] = ELF_OSABI; + memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); + elf->e_type = ET_CORE; + elf->e_machine = ELF_ARCH; + elf->e_version = EV_CURRENT; + elf->e_entry = 0; + elf->e_phoff = sizeof(struct elfhdr); + elf->e_shoff = 0; + elf->e_flags = ELF_CORE_EFLAGS; + elf->e_ehsize = sizeof(struct elfhdr); + elf->e_phentsize = sizeof(struct elf_phdr); + elf->e_phnum = 0; + elf->e_shentsize = 0; + elf->e_shnum = 0; + elf->e_shstrndx = 0; + + return 0; +} + +/* + * Traverse through memblock structure and setup crash memory ranges. These + * ranges will be used create PT_LOAD program headers in elfcore header. + */ +static void fadump_setup_crash_memory_ranges(void) +{ + struct memblock_region *reg; + unsigned long long start, end; + + pr_debug("Setup crash memory ranges.\n"); + crash_mem_ranges = 0; + /* + * add the first memory chunk (RMA_START through boot_memory_size) as + * a separate memory chunk. The reason is, at the time crash firmware + * will move the content of this memory chunk to different location + * specified during fadump registration. We need to create a separate + * program header for this chunk with the correct offset. + */ + fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + + for_each_memblock(memory, reg) { + start = (unsigned long long)reg->base; + end = start + (unsigned long long)reg->size; + if (start == RMA_START && end >= fw_dump.boot_memory_size) + start = fw_dump.boot_memory_size; + + /* add this range excluding the reserved dump area. */ + fadump_exclude_reserved_area(start, end); + } +} + +/* + * If the given physical address falls within the boot memory region then + * return the relocated address that points to the dump region reserved + * for saving initial boot memory contents. + */ +static inline unsigned long fadump_relocate(unsigned long paddr) +{ + if (paddr > RMA_START && paddr < fw_dump.boot_memory_size) + return fdm.rmr_region.destination_address + paddr; + else + return paddr; +} + +static int fadump_create_elfcore_headers(char *bufp) +{ + struct elfhdr *elf; + struct elf_phdr *phdr; + int i; + + fadump_init_elfcore_header(bufp); + elf = (struct elfhdr *)bufp; + bufp += sizeof(struct elfhdr); + + /* + * setup ELF PT_NOTE, place holder for cpu notes info. The notes info + * will be populated during second kernel boot after crash. Hence + * this PT_NOTE will always be the first elf note. + * + * NOTE: Any new ELF note addition should be placed after this note. + */ + phdr = (struct elf_phdr *)bufp; + bufp += sizeof(struct elf_phdr); + phdr->p_type = PT_NOTE; + phdr->p_flags = 0; + phdr->p_vaddr = 0; + phdr->p_align = 0; + + phdr->p_offset = 0; + phdr->p_paddr = 0; + phdr->p_filesz = 0; + phdr->p_memsz = 0; + + (elf->e_phnum)++; + + /* setup ELF PT_NOTE for vmcoreinfo */ + phdr = (struct elf_phdr *)bufp; + bufp += sizeof(struct elf_phdr); + phdr->p_type = PT_NOTE; + phdr->p_flags = 0; + phdr->p_vaddr = 0; + phdr->p_align = 0; + + phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note()); + phdr->p_offset = phdr->p_paddr; + phdr->p_memsz = vmcoreinfo_max_size; + phdr->p_filesz = vmcoreinfo_max_size; + + /* Increment number of program headers. */ + (elf->e_phnum)++; + + /* setup PT_LOAD sections. */ + + for (i = 0; i < crash_mem_ranges; i++) { + unsigned long long mbase, msize; + mbase = crash_memory_ranges[i].base; + msize = crash_memory_ranges[i].size; + + if (!msize) + continue; + + phdr = (struct elf_phdr *)bufp; + bufp += sizeof(struct elf_phdr); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = mbase; + + if (mbase == RMA_START) { + /* + * The entire RMA region will be moved by firmware + * to the specified destination_address. Hence set + * the correct offset. + */ + phdr->p_offset = fdm.rmr_region.destination_address; + } + + phdr->p_paddr = mbase; + phdr->p_vaddr = (unsigned long)__va(mbase); + phdr->p_filesz = msize; + phdr->p_memsz = msize; + phdr->p_align = 0; + + /* Increment number of program headers. */ + (elf->e_phnum)++; + } + return 0; +} + +static unsigned long init_fadump_header(unsigned long addr) +{ + struct fadump_crash_info_header *fdh; + + if (!addr) + return 0; + + fw_dump.fadumphdr_addr = addr; + fdh = __va(addr); + addr += sizeof(struct fadump_crash_info_header); + + memset(fdh, 0, sizeof(struct fadump_crash_info_header)); + fdh->magic_number = FADUMP_CRASH_INFO_MAGIC; + fdh->elfcorehdr_addr = addr; + /* We will set the crashing cpu id in crash_fadump() during crash. */ + fdh->crashing_cpu = CPU_UNKNOWN; + + return addr; +} + +static void register_fadump(void) +{ + unsigned long addr; + void *vaddr; + + /* + * If no memory is reserved then we can not register for firmware- + * assisted dump. + */ + if (!fw_dump.reserve_dump_area_size) + return; + + fadump_setup_crash_memory_ranges(); + + addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len; + /* Initialize fadump crash info header. */ + addr = init_fadump_header(addr); + vaddr = __va(addr); + + pr_debug("Creating ELF core headers at %#016lx\n", addr); + fadump_create_elfcore_headers(vaddr); + + /* register the future kernel dump with firmware. */ + register_fw_dump(&fdm); +} + +static int fadump_unregister_dump(struct fadump_mem_struct *fdm) +{ + int rc = 0; + unsigned int wait_time; + + pr_debug("Un-register firmware-assisted dump\n"); + + /* TODO: Add upper time limit for the delay */ + do { + rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, + FADUMP_UNREGISTER, fdm, + sizeof(struct fadump_mem_struct)); + + wait_time = rtas_busy_delay_time(rc); + if (wait_time) + mdelay(wait_time); + } while (wait_time); + + if (rc) { + printk(KERN_ERR "Failed to un-register firmware-assisted dump." + " unexpected error(%d).\n", rc); + return rc; + } + fw_dump.dump_registered = 0; + return 0; +} + +static int fadump_invalidate_dump(struct fadump_mem_struct *fdm) +{ + int rc = 0; + unsigned int wait_time; + + pr_debug("Invalidating firmware-assisted dump registration\n"); + + /* TODO: Add upper time limit for the delay */ + do { + rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, + FADUMP_INVALIDATE, fdm, + sizeof(struct fadump_mem_struct)); + + wait_time = rtas_busy_delay_time(rc); + if (wait_time) + mdelay(wait_time); + } while (wait_time); + + if (rc) { + printk(KERN_ERR "Failed to invalidate firmware-assisted dump " + "rgistration. unexpected error(%d).\n", rc); + return rc; + } + fw_dump.dump_active = 0; + fdm_active = NULL; + return 0; +} + +void fadump_cleanup(void) +{ + /* Invalidate the registration only if dump is active. */ + if (fw_dump.dump_active) { + init_fadump_mem_struct(&fdm, + fdm_active->cpu_state_data.destination_address); + fadump_invalidate_dump(&fdm); + } +} + +/* + * Release the memory that was reserved in early boot to preserve the memory + * contents. The released memory will be available for general use. + */ +static void fadump_release_memory(unsigned long begin, unsigned long end) +{ + unsigned long addr; + unsigned long ra_start, ra_end; + + ra_start = fw_dump.reserve_dump_area_start; + ra_end = ra_start + fw_dump.reserve_dump_area_size; + + for (addr = begin; addr < end; addr += PAGE_SIZE) { + /* + * exclude the dump reserve area. Will reuse it for next + * fadump registration. + */ + if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start)) + continue; + + ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); + init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); + free_page((unsigned long)__va(addr)); + totalram_pages++; + } +} + +static void fadump_invalidate_release_mem(void) +{ + unsigned long reserved_area_start, reserved_area_end; + unsigned long destination_address; + + mutex_lock(&fadump_mutex); + if (!fw_dump.dump_active) { + mutex_unlock(&fadump_mutex); + return; + } + + destination_address = fdm_active->cpu_state_data.destination_address; + fadump_cleanup(); + mutex_unlock(&fadump_mutex); + + /* + * Save the current reserved memory bounds we will require them + * later for releasing the memory for general use. + */ + reserved_area_start = fw_dump.reserve_dump_area_start; + reserved_area_end = reserved_area_start + + fw_dump.reserve_dump_area_size; + /* + * Setup reserve_dump_area_start and its size so that we can + * reuse this reserved memory for Re-registration. + */ + fw_dump.reserve_dump_area_start = destination_address; + fw_dump.reserve_dump_area_size = get_fadump_area_size(); + + fadump_release_memory(reserved_area_start, reserved_area_end); + if (fw_dump.cpu_notes_buf) { + fadump_cpu_notes_buf_free( + (unsigned long)__va(fw_dump.cpu_notes_buf), + fw_dump.cpu_notes_buf_size); + fw_dump.cpu_notes_buf = 0; + fw_dump.cpu_notes_buf_size = 0; + } + /* Initialize the kernel dump memory structure for FAD registration. */ + init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); +} + +static ssize_t fadump_release_memory_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + if (!fw_dump.dump_active) + return -EPERM; + + if (buf[0] == '1') { + /* + * Take away the '/proc/vmcore'. We are releasing the dump + * memory, hence it will not be valid anymore. + */ + vmcore_cleanup(); + fadump_invalidate_release_mem(); + + } else + return -EINVAL; + return count; +} + +static ssize_t fadump_enabled_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", fw_dump.fadump_enabled); +} + +static ssize_t fadump_register_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", fw_dump.dump_registered); +} + +static ssize_t fadump_register_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int ret = 0; + + if (!fw_dump.fadump_enabled || fdm_active) + return -EPERM; + + mutex_lock(&fadump_mutex); + + switch (buf[0]) { + case '0': + if (fw_dump.dump_registered == 0) { + ret = -EINVAL; + goto unlock_out; + } + /* Un-register Firmware-assisted dump */ + fadump_unregister_dump(&fdm); + break; + case '1': + if (fw_dump.dump_registered == 1) { + ret = -EINVAL; + goto unlock_out; + } + /* Register Firmware-assisted dump */ + register_fadump(); + break; + default: + ret = -EINVAL; + break; + } + +unlock_out: + mutex_unlock(&fadump_mutex); + return ret < 0 ? ret : count; +} + +static int fadump_region_show(struct seq_file *m, void *private) +{ + const struct fadump_mem_struct *fdm_ptr; + + if (!fw_dump.fadump_enabled) + return 0; + + mutex_lock(&fadump_mutex); + if (fdm_active) + fdm_ptr = fdm_active; + else { + mutex_unlock(&fadump_mutex); + fdm_ptr = &fdm; + } + + seq_printf(m, + "CPU : [%#016llx-%#016llx] %#llx bytes, " + "Dumped: %#llx\n", + fdm_ptr->cpu_state_data.destination_address, + fdm_ptr->cpu_state_data.destination_address + + fdm_ptr->cpu_state_data.source_len - 1, + fdm_ptr->cpu_state_data.source_len, + fdm_ptr->cpu_state_data.bytes_dumped); + seq_printf(m, + "HPTE: [%#016llx-%#016llx] %#llx bytes, " + "Dumped: %#llx\n", + fdm_ptr->hpte_region.destination_address, + fdm_ptr->hpte_region.destination_address + + fdm_ptr->hpte_region.source_len - 1, + fdm_ptr->hpte_region.source_len, + fdm_ptr->hpte_region.bytes_dumped); + seq_printf(m, + "DUMP: [%#016llx-%#016llx] %#llx bytes, " + "Dumped: %#llx\n", + fdm_ptr->rmr_region.destination_address, + fdm_ptr->rmr_region.destination_address + + fdm_ptr->rmr_region.source_len - 1, + fdm_ptr->rmr_region.source_len, + fdm_ptr->rmr_region.bytes_dumped); + + if (!fdm_active || + (fw_dump.reserve_dump_area_start == + fdm_ptr->cpu_state_data.destination_address)) + goto out; + + /* Dump is active. Show reserved memory region. */ + seq_printf(m, + " : [%#016llx-%#016llx] %#llx bytes, " + "Dumped: %#llx\n", + (unsigned long long)fw_dump.reserve_dump_area_start, + fdm_ptr->cpu_state_data.destination_address - 1, + fdm_ptr->cpu_state_data.destination_address - + fw_dump.reserve_dump_area_start, + fdm_ptr->cpu_state_data.destination_address - + fw_dump.reserve_dump_area_start); +out: + if (fdm_active) + mutex_unlock(&fadump_mutex); + return 0; +} + +static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem, + 0200, NULL, + fadump_release_memory_store); +static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled, + 0444, fadump_enabled_show, + NULL); +static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered, + 0644, fadump_register_show, + fadump_register_store); + +static int fadump_region_open(struct inode *inode, struct file *file) +{ + return single_open(file, fadump_region_show, inode->i_private); +} + +static const struct file_operations fadump_region_fops = { + .open = fadump_region_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void fadump_init_files(void) +{ + struct dentry *debugfs_file; + int rc = 0; + + rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr); + if (rc) + printk(KERN_ERR "fadump: unable to create sysfs file" + " fadump_enabled (%d)\n", rc); + + rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr); + if (rc) + printk(KERN_ERR "fadump: unable to create sysfs file" + " fadump_registered (%d)\n", rc); + + debugfs_file = debugfs_create_file("fadump_region", 0444, + powerpc_debugfs_root, NULL, + &fadump_region_fops); + if (!debugfs_file) + printk(KERN_ERR "fadump: unable to create debugfs file" + " fadump_region\n"); + + if (fw_dump.dump_active) { + rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr); + if (rc) + printk(KERN_ERR "fadump: unable to create sysfs file" + " fadump_release_mem (%d)\n", rc); + } + return; +} + +/* + * Prepare for firmware-assisted dump. + */ +int __init setup_fadump(void) +{ + if (!fw_dump.fadump_enabled) + return 0; + + if (!fw_dump.fadump_supported) { + printk(KERN_ERR "Firmware-assisted dump is not supported on" + " this hardware\n"); + return 0; + } + + fadump_show_config(); + /* + * If dump data is available then see if it is valid and prepare for + * saving it to the disk. + */ + if (fw_dump.dump_active) { + /* + * if dump process fails then invalidate the registration + * and release memory before proceeding for re-registration. + */ + if (process_fadump(fdm_active) < 0) + fadump_invalidate_release_mem(); + } + /* Initialize the kernel dump memory structure for FAD registration. */ + else if (fw_dump.reserve_dump_area_size) + init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); + fadump_init_files(); + + return 1; +} +subsys_initcall(setup_fadump); diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 0654dba2c1f1..dc0488b6f6e1 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -395,7 +395,7 @@ DataAccess: bl hash_page 1: lwz r5,_DSISR(r11) /* get DSISR value */ mfspr r4,SPRN_DAR - EXC_XFER_EE_LITE(0x300, handle_page_fault) + EXC_XFER_LITE(0x300, handle_page_fault) /* Instruction access exception. */ @@ -410,7 +410,7 @@ InstructionAccess: bl hash_page 1: mr r4,r12 mr r5,r9 - EXC_XFER_EE_LITE(0x400, handle_page_fault) + EXC_XFER_LITE(0x400, handle_page_fault) /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 872a6af83bad..4989661b710b 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -394,7 +394,7 @@ label: NORMAL_EXCEPTION_PROLOG mr r4,r12 /* Pass SRR0 as arg2 */ li r5,0 /* Pass zero as arg3 */ - EXC_XFER_EE_LITE(0x400, handle_page_fault) + EXC_XFER_LITE(0x400, handle_page_fault) /* 0x0500 - External Interrupt Exception */ EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) @@ -747,7 +747,7 @@ DataAccess: mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ stw r5,_ESR(r11) mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ - EXC_XFER_EE_LITE(0x300, handle_page_fault) + EXC_XFER_LITE(0x300, handle_page_fault) /* Other PowerPC processors, namely those derived from the 6xx-series * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 06c7251c1bf7..58bddee8e1e8 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -32,13 +32,13 @@ #include <asm/cputable.h> #include <asm/setup.h> #include <asm/hvcall.h> -#include <asm/iseries/lpar_map.h> #include <asm/thread_info.h> #include <asm/firmware.h> #include <asm/page_64.h> #include <asm/irqflags.h> #include <asm/kvm_book3s_asm.h> #include <asm/ptrace.h> +#include <asm/hw_irq.h> /* The physical memory is laid out such that the secondary processor * spin code sits at 0x0000...0x00ff. On server, the vectors follow @@ -57,10 +57,6 @@ * entry in r9 for debugging purposes * 2. Secondary processors enter at 0x60 with PIR in gpr3 * - * For iSeries: - * 1. The MMU is on (as it always is for iSeries) - * 2. The kernel is entered at system_reset_iSeries - * * For Book3E processors: * 1. The MMU is on running in AS0 in a state defined in ePAPR * 2. The kernel is entered at __start @@ -93,15 +89,6 @@ __secondary_hold_spinloop: __secondary_hold_acknowledge: .llong 0x0 -#ifdef CONFIG_PPC_ISERIES - /* - * At offset 0x20, there is a pointer to iSeries LPAR data. - * This is required by the hypervisor - */ - . = 0x20 - .llong hvReleaseData-KERNELBASE -#endif /* CONFIG_PPC_ISERIES */ - #ifdef CONFIG_RELOCATABLE /* This flag is set to 1 by a loader if the kernel should run * at the loaded address instead of the linked address. This @@ -564,7 +551,8 @@ _GLOBAL(pmac_secondary_start) */ li r0,0 stb r0,PACASOFTIRQEN(r13) - stb r0,PACAHARDIRQEN(r13) + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) @@ -582,7 +570,7 @@ _GLOBAL(pmac_secondary_start) * 1. Processor number * 2. Segment table pointer (virtual address) * On entry the following are set: - * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries + * r1 = stack pointer (real addr of temp stack) * r24 = cpu# (in Linux terms) * r13 = paca virtual address * SPRG_PACA = paca virtual address @@ -595,7 +583,7 @@ __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM - /* Initialize the kernel stack. Just a repeat for iSeries. */ + /* Initialize the kernel stack */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ ldx r14,r3,r28 @@ -615,20 +603,16 @@ __secondary_start: li r7,0 mtlr r7 + /* Mark interrupts soft and hard disabled (they might be enabled + * in the PACA when doing hotplug) + */ + stb r7,PACASOFTIRQEN(r13) + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) + /* enable MMU and jump to start_secondary */ LOAD_REG_ADDR(r3, .start_secondary_prolog) LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - ori r4,r4,MSR_EE - li r8,1 - stb r8,PACAHARDIRQEN(r13) -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif -BEGIN_FW_FTR_SECTION - stb r7,PACAHARDIRQEN(r13) -END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) - stb r7,PACASOFTIRQEN(r13) mtspr SPRN_SRR0,r3 mtspr SPRN_SRR1,r4 @@ -771,22 +755,18 @@ _INIT_GLOBAL(start_here_common) /* Load the TOC (virtual address) */ ld r2,PACATOC(r13) + /* Do more system initializations in virtual mode */ bl .setup_system - /* Load up the kernel context */ -5: - li r5,0 - stb r5,PACASOFTIRQEN(r13) /* Soft Disabled */ -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - mfmsr r5 - ori r5,r5,MSR_EE /* Hard Enabled on iSeries*/ - mtmsrd r5 - li r5,1 -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif - stb r5,PACAHARDIRQEN(r13) /* Hard Disabled on others */ + /* Mark interrupts soft and hard disabled (they might be enabled + * in the PACA when doing hotplug) + */ + li r0,0 + stb r0,PACASOFTIRQEN(r13) + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) + /* Generic kernel entry */ bl .start_kernel /* Not reached */ diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index b68cb173ba2c..b2a5860accfb 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -220,7 +220,7 @@ DataAccess: mfspr r4,SPRN_DAR li r10,0x00f0 mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */ - EXC_XFER_EE_LITE(0x300, handle_page_fault) + EXC_XFER_LITE(0x300, handle_page_fault) /* Instruction access exception. * This is "never generated" by the MPC8xx. We jump to it for other @@ -231,7 +231,7 @@ InstructionAccess: EXCEPTION_PROLOG mr r4,r12 mr r5,r9 - EXC_XFER_EE_LITE(0x400, handle_page_fault) + EXC_XFER_LITE(0x400, handle_page_fault) /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index fc921bf62e15..0e4175388f47 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -359,7 +359,7 @@ label: mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ stw r5,_ESR(r11); \ mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ - EXC_XFER_EE_LITE(0x0300, handle_page_fault) + EXC_XFER_LITE(0x0300, handle_page_fault) #define INSTRUCTION_STORAGE_EXCEPTION \ START_EXCEPTION(InstructionStorage) \ @@ -368,7 +368,7 @@ label: stw r5,_ESR(r11); \ mr r4,r12; /* Pass SRR0 as arg2 */ \ li r5,0; /* Pass zero as arg3 */ \ - EXC_XFER_EE_LITE(0x0400, handle_page_fault) + EXC_XFER_LITE(0x0400, handle_page_fault) #define ALIGNMENT_EXCEPTION \ START_EXCEPTION(Alignment) \ diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index d5d78c4ceef6..28e62598d0e8 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -319,7 +319,7 @@ interrupt_base: mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ andis. r10,r5,(ESR_ILK|ESR_DLK)@h bne 1f - EXC_XFER_EE_LITE(0x0300, handle_page_fault) + EXC_XFER_LITE(0x0300, handle_page_fault) 1: addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x0300, CacheLockingException) diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index d39ae606ff8d..79bb282e6501 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -713,7 +713,7 @@ static struct dev_pm_ops ibmebus_bus_dev_pm_ops = { struct bus_type ibmebus_bus_type = { .name = "ibmebus", - .uevent = of_device_uevent, + .uevent = of_device_uevent_modalias, .bus_attrs = ibmebus_bus_attrs, .match = ibmebus_bus_bus_match, .probe = ibmebus_bus_device_probe, diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index c97fc60c790c..e8e821146f38 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -84,7 +84,11 @@ void cpu_idle(void) start_critical_timings(); - local_irq_enable(); + /* Some power_save functions return with + * interrupts enabled, some don't. + */ + if (irqs_disabled()) + local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); } else { diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S index 16c002d6bdf1..ff007b59448d 100644 --- a/arch/powerpc/kernel/idle_book3e.S +++ b/arch/powerpc/kernel/idle_book3e.S @@ -29,43 +29,30 @@ _GLOBAL(book3e_idle) wrteei 0 /* Now check if an interrupt came in while we were soft disabled - * since we may otherwise lose it (doorbells etc...). We know - * that since PACAHARDIRQEN will have been cleared in that case. + * since we may otherwise lose it (doorbells etc...). */ - lbz r3,PACAHARDIRQEN(r13) + lbz r3,PACAIRQHAPPENED(r13) cmpwi cr0,r3,0 - beqlr + bnelr - /* Now we are going to mark ourselves as soft and hard enables in + /* Now we are going to mark ourselves as soft and hard enabled in * order to be able to take interrupts while asleep. We inform lockdep * of that. We don't actually turn interrupts on just yet tho. */ #ifdef CONFIG_TRACE_IRQFLAGS stdu r1,-128(r1) bl .trace_hardirqs_on + addi r1,r1,128 #endif li r0,1 stb r0,PACASOFTIRQEN(r13) - stb r0,PACAHARDIRQEN(r13) /* Interrupts will make use return to LR, so get something we want * in there */ bl 1f - /* Hard disable interrupts again */ - wrteei 0 - - /* Mark them off again in the PACA as well */ - li r0,0 - stb r0,PACASOFTIRQEN(r13) - stb r0,PACAHARDIRQEN(r13) - - /* Tell lockdep about it */ -#ifdef CONFIG_TRACE_IRQFLAGS - bl .trace_hardirqs_off - addi r1,r1,128 -#endif + /* And return (interrupts are on) */ ld r0,16(r1) mtlr r0 blr diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index ba3195478600..2c71b0fc9f91 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -14,6 +14,7 @@ #include <asm/thread_info.h> #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> +#include <asm/irqflags.h> #undef DEBUG @@ -29,14 +30,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) cmpwi 0,r4,0 beqlr - /* Go to NAP now */ + /* Hard disable interrupts */ mfmsr r7 rldicl r0,r7,48,1 rotldi r0,r0,16 - mtmsrd r0,1 /* hard-disable interrupts */ + mtmsrd r0,1 + + /* Check if something happened while soft-disabled */ + lbz r0,PACAIRQHAPPENED(r13) + cmpwi cr0,r0,0 + bnelr + + /* Soft-enable interrupts */ +#ifdef CONFIG_TRACE_IRQFLAGS + mflr r0 + std r0,16(r1) + stdu r1,-128(r1) + bl .trace_hardirqs_on + addi r1,r1,128 + ld r0,16(r1) + mtlr r0 + mfmsr r7 +#endif /* CONFIG_TRACE_IRQFLAGS */ + li r0,1 stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ - stb r0,PACAHARDIRQEN(r13) BEGIN_FTR_SECTION DSSALL sync diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index fcdff198da4b..0cdc9a392839 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -1,5 +1,5 @@ /* - * This file contains the power_save function for 970-family CPUs. + * This file contains the power_save function for Power7 CPUs. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,6 +15,7 @@ #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> #include <asm/ppc-opcode.h> +#include <asm/hw_irq.h> #undef DEBUG @@ -51,9 +52,25 @@ _GLOBAL(power7_idle) rldicl r9,r9,48,1 rotldi r9,r9,16 mtmsrd r9,1 /* hard-disable interrupts */ + + /* Check if something happened while soft-disabled */ + lbz r0,PACAIRQHAPPENED(r13) + cmpwi cr0,r0,0 + beq 1f + addi r1,r1,INT_FRAME_SIZE + ld r0,16(r1) + mtlr r0 + blr + +1: /* We mark irqs hard disabled as this is the state we'll + * be in when returning and we need to tell arch_local_irq_restore() + * about it + */ + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) + + /* We haven't lost state ... yet */ li r0,0 - stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ - stb r0,PACAHARDIRQEN(r13) stb r0,PACA_NAPSTATELOST(r13) /* Continue saving state */ diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 0cfcf98aafca..359f078571c7 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -39,6 +39,7 @@ #include <asm/pci-bridge.h> #include <asm/machdep.h> #include <asm/kdump.h> +#include <asm/fadump.h> #define DBG(...) @@ -445,7 +446,12 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, static void iommu_table_clear(struct iommu_table *tbl) { - if (!is_kdump_kernel()) { + /* + * In case of firmware assisted dump system goes through clean + * reboot process at the time of system crash. Hence it's safe to + * clear the TCE entries if firmware assisted dump is active. + */ + if (!is_kdump_kernel() || is_fadump_active()) { /* Clear the table in case firmware left allocations in it */ ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); return; diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 01e2877e8e04..a3d128e94cff 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -93,20 +93,16 @@ extern int tau_interrupts(int); #ifdef CONFIG_PPC64 -#ifndef CONFIG_SPARSE_IRQ -EXPORT_SYMBOL(irq_desc); -#endif - int distribute_irqs = 1; -static inline notrace unsigned long get_hard_enabled(void) +static inline notrace unsigned long get_irq_happened(void) { - unsigned long enabled; + unsigned long happened; __asm__ __volatile__("lbz %0,%1(13)" - : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled))); + : "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened))); - return enabled; + return happened; } static inline notrace void set_soft_enabled(unsigned long enable) @@ -115,88 +111,162 @@ static inline notrace void set_soft_enabled(unsigned long enable) : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); } -static inline notrace void decrementer_check_overflow(void) +static inline notrace int decrementer_check_overflow(void) { - u64 now = get_tb_or_rtc(); - u64 *next_tb; - - preempt_disable(); - next_tb = &__get_cpu_var(decrementers_next_tb); - + u64 now = get_tb_or_rtc(); + u64 *next_tb = &__get_cpu_var(decrementers_next_tb); + if (now >= *next_tb) set_dec(1); - preempt_enable(); + return now >= *next_tb; } -notrace void arch_local_irq_restore(unsigned long en) +/* This is called whenever we are re-enabling interrupts + * and returns either 0 (nothing to do) or 500/900 if there's + * either an EE or a DEC to generate. + * + * This is called in two contexts: From arch_local_irq_restore() + * before soft-enabling interrupts, and from the exception exit + * path when returning from an interrupt from a soft-disabled to + * a soft enabled context. In both case we have interrupts hard + * disabled. + * + * We take care of only clearing the bits we handled in the + * PACA irq_happened field since we can only re-emit one at a + * time and we don't want to "lose" one. + */ +notrace unsigned int __check_irq_replay(void) { /* - * get_paca()->soft_enabled = en; - * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1? - * That was allowed before, and in such a case we do need to take care - * that gcc will set soft_enabled directly via r13, not choose to use - * an intermediate register, lest we're preempted to a different cpu. + * We use local_paca rather than get_paca() to avoid all + * the debug_smp_processor_id() business in this low level + * function */ - set_soft_enabled(en); - if (!en) - return; + unsigned char happened = local_paca->irq_happened; + + /* Clear bit 0 which we wouldn't clear otherwise */ + local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; -#ifdef CONFIG_PPC_STD_MMU_64 - if (firmware_has_feature(FW_FEATURE_ISERIES)) { - /* - * Do we need to disable preemption here? Not really: in the - * unlikely event that we're preempted to a different cpu in - * between getting r13, loading its lppaca_ptr, and loading - * its any_int, we might call iseries_handle_interrupts without - * an interrupt pending on the new cpu, but that's no disaster, - * is it? And the business of preempting us off the old cpu - * would itself involve a local_irq_restore which handles the - * interrupt to that cpu. - * - * But use "local_paca->lppaca_ptr" instead of "get_lppaca()" - * to avoid any preemption checking added into get_paca(). - */ - if (local_paca->lppaca_ptr->int_dword.any_int) - iseries_handle_interrupts(); + /* + * Force the delivery of pending soft-disabled interrupts on PS3. + * Any HV call will have this side effect. + */ + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + u64 tmp, tmp2; + lv1_get_version_info(&tmp, &tmp2); } -#endif /* CONFIG_PPC_STD_MMU_64 */ /* - * if (get_paca()->hard_enabled) return; - * But again we need to take care that gcc gets hard_enabled directly - * via r13, not choose to use an intermediate register, lest we're - * preempted to a different cpu in between the two instructions. + * We may have missed a decrementer interrupt. We check the + * decrementer itself rather than the paca irq_happened field + * in case we also had a rollover while hard disabled + */ + local_paca->irq_happened &= ~PACA_IRQ_DEC; + if (decrementer_check_overflow()) + return 0x900; + + /* Finally check if an external interrupt happened */ + local_paca->irq_happened &= ~PACA_IRQ_EE; + if (happened & PACA_IRQ_EE) + return 0x500; + +#ifdef CONFIG_PPC_BOOK3E + /* Finally check if an EPR external interrupt happened + * this bit is typically set if we need to handle another + * "edge" interrupt from within the MPIC "EPR" handler + */ + local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE; + if (happened & PACA_IRQ_EE_EDGE) + return 0x500; + + local_paca->irq_happened &= ~PACA_IRQ_DBELL; + if (happened & PACA_IRQ_DBELL) + return 0x280; +#endif /* CONFIG_PPC_BOOK3E */ + + /* There should be nothing left ! */ + BUG_ON(local_paca->irq_happened != 0); + + return 0; +} + +notrace void arch_local_irq_restore(unsigned long en) +{ + unsigned char irq_happened; + unsigned int replay; + + /* Write the new soft-enabled value */ + set_soft_enabled(en); + if (!en) + return; + /* + * From this point onward, we can take interrupts, preempt, + * etc... unless we got hard-disabled. We check if an event + * happened. If none happened, we know we can just return. + * + * We may have preempted before the check below, in which case + * we are checking the "new" CPU instead of the old one. This + * is only a problem if an event happened on the "old" CPU. + * + * External interrupt events on non-iseries will have caused + * interrupts to be hard-disabled, so there is no problem, we + * cannot have preempted. */ - if (get_hard_enabled()) + irq_happened = get_irq_happened(); + if (!irq_happened) return; /* - * Need to hard-enable interrupts here. Since currently disabled, - * no need to take further asm precautions against preemption; but - * use local_paca instead of get_paca() to avoid preemption checking. + * We need to hard disable to get a trusted value from + * __check_irq_replay(). We also need to soft-disable + * again to avoid warnings in there due to the use of + * per-cpu variables. + * + * We know that if the value in irq_happened is exactly 0x01 + * then we are already hard disabled (there are other less + * common cases that we'll ignore for now), so we skip the + * (expensive) mtmsrd. */ - local_paca->hard_enabled = en; + if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) + __hard_irq_disable(); + set_soft_enabled(0); /* - * Trigger the decrementer if we have a pending event. Some processors - * only trigger on edge transitions of the sign bit. We might also - * have disabled interrupts long enough that the decrementer wrapped - * to positive. + * Check if anything needs to be re-emitted. We haven't + * soft-enabled yet to avoid warnings in decrementer_check_overflow + * accessing per-cpu variables */ - decrementer_check_overflow(); + replay = __check_irq_replay(); + + /* We can soft-enable now */ + set_soft_enabled(1); /* - * Force the delivery of pending soft-disabled interrupts on PS3. - * Any HV call will have this side effect. + * And replay if we have to. This will return with interrupts + * hard-enabled. */ - if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { - u64 tmp, tmp2; - lv1_get_version_info(&tmp, &tmp2); + if (replay) { + __replay_interrupt(replay); + return; } + /* Finally, let's ensure we are hard enabled */ __hard_irq_enable(); } EXPORT_SYMBOL(arch_local_irq_restore); + +/* + * This is specifically called by assembly code to re-enable interrupts + * if they are currently disabled. This is typically called before + * schedule() or do_signal() when returning to userspace. We do it + * in C to avoid the burden of dealing with lockdep etc... + */ +void restore_interrupts(void) +{ + if (irqs_disabled()) + local_irq_enable(); +} + #endif /* CONFIG_PPC64 */ int arch_show_interrupts(struct seq_file *p, int prec) @@ -364,8 +434,17 @@ void do_IRQ(struct pt_regs *regs) check_stack_overflow(); + /* + * Query the platform PIC for the interrupt & ack it. + * + * This will typically lower the interrupt line to the CPU + */ irq = ppc_md.get_irq(); + /* We can hard enable interrupts now */ + may_hard_irq_enable(); + + /* And finally process it */ if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) handle_one_irq(irq); else if (irq != NO_IRQ_IGNORE) @@ -374,15 +453,6 @@ void do_IRQ(struct pt_regs *regs) irq_exit(); set_irq_regs(old_regs); -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES) && - get_lppaca()->int_dword.fields.decr_int) { - get_lppaca()->int_dword.fields.decr_int = 0; - /* Signal a fake decrementer interrupt */ - timer_interrupt(regs); - } -#endif - trace_irq_exit(regs); } @@ -490,409 +560,19 @@ void do_softirq(void) local_irq_restore(flags); } - -/* - * IRQ controller and virtual interrupts - */ - -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { - irq_hw_number_t hwirq; - struct irq_host *host; -}; - -static LIST_HEAD(irq_hosts); -static DEFINE_RAW_SPINLOCK(irq_big_lock); -static DEFINE_MUTEX(revmap_trees_mutex); -static struct irq_map_entry irq_map[NR_IRQS]; -static unsigned int irq_virq_count = NR_IRQS; -static struct irq_host *irq_default_host; - irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { - return irq_map[d->irq].hwirq; + return d->hwirq; } EXPORT_SYMBOL_GPL(irqd_to_hwirq); irq_hw_number_t virq_to_hw(unsigned int virq) { - return irq_map[virq].hwirq; + struct irq_data *irq_data = irq_get_irq_data(virq); + return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; } EXPORT_SYMBOL_GPL(virq_to_hw); -bool virq_is_host(unsigned int virq, struct irq_host *host) -{ - return irq_map[virq].host == host; -} -EXPORT_SYMBOL_GPL(virq_is_host); - -static int default_irq_host_match(struct irq_host *h, struct device_node *np) -{ - return h->of_node != NULL && h->of_node == np; -} - -struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq) -{ - struct irq_host *host; - unsigned int size = sizeof(struct irq_host); - unsigned int i; - unsigned int *rmap; - unsigned long flags; - - /* Allocate structure and revmap table if using linear mapping */ - if (revmap_type == IRQ_HOST_MAP_LINEAR) - size += revmap_arg * sizeof(unsigned int); - host = kzalloc(size, GFP_KERNEL); - if (host == NULL) - return NULL; - - /* Fill structure */ - host->revmap_type = revmap_type; - host->inval_irq = inval_irq; - host->ops = ops; - host->of_node = of_node_get(of_node); - - if (host->ops->match == NULL) - host->ops->match = default_irq_host_match; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* If it's a legacy controller, check for duplicates and - * mark it as allocated (we use irq 0 host pointer for that - */ - if (revmap_type == IRQ_HOST_MAP_LEGACY) { - if (irq_map[0].host != NULL) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - of_node_put(host->of_node); - kfree(host); - return NULL; - } - irq_map[0].host = host; - } - - list_add(&host->link, &irq_hosts); - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - - /* Additional setups per revmap type */ - switch(revmap_type) { - case IRQ_HOST_MAP_LEGACY: - /* 0 is always the invalid number for legacy */ - host->inval_irq = 0; - /* setup us as the host for all legacy interrupts */ - for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { - irq_map[i].hwirq = i; - smp_wmb(); - irq_map[i].host = host; - smp_wmb(); - - /* Legacy flags are left to default at this point, - * one can then use irq_create_mapping() to - * explicitly change them - */ - ops->map(host, i, i); - - /* Clear norequest flags */ - irq_clear_status_flags(i, IRQ_NOREQUEST); - } - break; - case IRQ_HOST_MAP_LINEAR: - rmap = (unsigned int *)(host + 1); - for (i = 0; i < revmap_arg; i++) - rmap[i] = NO_IRQ; - host->revmap_data.linear.size = revmap_arg; - smp_wmb(); - host->revmap_data.linear.revmap = rmap; - break; - case IRQ_HOST_MAP_TREE: - INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); - break; - default: - break; - } - - pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); - - return host; -} - -struct irq_host *irq_find_host(struct device_node *node) -{ - struct irq_host *h, *found = NULL; - unsigned long flags; - - /* We might want to match the legacy controller last since - * it might potentially be set to match all interrupts in - * the absence of a device node. This isn't a problem so far - * yet though... - */ - raw_spin_lock_irqsave(&irq_big_lock, flags); - list_for_each_entry(h, &irq_hosts, link) - if (h->ops->match(h, node)) { - found = h; - break; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_host *host) -{ - pr_debug("irq: Default host set to @0x%p\n", host); - - irq_default_host = host; -} - -void irq_set_virq_count(unsigned int count) -{ - pr_debug("irq: Trying to set virq count to %d\n", count); - - BUG_ON(count < NUM_ISA_INTERRUPTS); - if (count < NR_IRQS) - irq_virq_count = count; -} - -static int irq_setup_virq(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - int res; - - res = irq_alloc_desc_at(virq, 0); - if (res != virq) { - pr_debug("irq: -> allocating desc failed\n"); - goto error; - } - - /* map it */ - smp_wmb(); - irq_map[virq].hwirq = hwirq; - smp_mb(); - - if (host->ops->map(host, virq, hwirq)) { - pr_debug("irq: -> mapping failed, freeing\n"); - goto errdesc; - } - - irq_clear_status_flags(virq, IRQ_NOREQUEST); - - return 0; - -errdesc: - irq_free_descs(virq, 1); -error: - irq_free_virt(virq, 1); - return -1; -} - -unsigned int irq_create_direct_mapping(struct irq_host *host) -{ - unsigned int virq; - - if (host == NULL) - host = irq_default_host; - - BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); - - virq = irq_alloc_virt(host, 1, 0); - if (virq == NO_IRQ) { - pr_debug("irq: create_direct virq allocation failed\n"); - return NO_IRQ; - } - - pr_debug("irq: create_direct obtained virq %d\n", virq); - - if (irq_setup_virq(host, virq, virq)) - return NO_IRQ; - - return virq; -} - -unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int virq, hint; - - pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) { - printk(KERN_WARNING "irq_create_mapping called for" - " NULL host, hwirq=%lx\n", hwirq); - WARN_ON(1); - return NO_IRQ; - } - pr_debug("irq: -> using host @%p\n", host); - - /* Check if mapping already exists */ - virq = irq_find_mapping(host, hwirq); - if (virq != NO_IRQ) { - pr_debug("irq: -> existing mapping on virq %d\n", virq); - return virq; - } - - /* Get a virtual interrupt number */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) { - /* Handle legacy */ - virq = (unsigned int)hwirq; - if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) - return NO_IRQ; - return virq; - } else { - /* Allocate a virtual interrupt number */ - hint = hwirq % irq_virq_count; - virq = irq_alloc_virt(host, 1, hint); - if (virq == NO_IRQ) { - pr_debug("irq: -> virq allocation failed\n"); - return NO_IRQ; - } - } - - if (irq_setup_virq(host, virq, hwirq)) - return NO_IRQ; - - pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", - hwirq, host->of_node ? host->of_node->full_name : "null", virq); - - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - unsigned int virq; - - if (controller == NULL) - host = irq_default_host; - else - host = irq_find_host(controller); - if (host == NULL) { - printk(KERN_WARNING "irq: no irq host found for %s !\n", - controller->full_name); - return NO_IRQ; - } - - /* If host has no translation, then we assume interrupt line */ - if (host->ops->xlate == NULL) - hwirq = intspec[0]; - else { - if (host->ops->xlate(host, controller, intspec, intsize, - &hwirq, &type)) - return NO_IRQ; - } - - /* Create mapping */ - virq = irq_create_mapping(host, hwirq); - if (virq == NO_IRQ) - return virq; - - /* Set type if specified and different than the current one */ - if (type != IRQ_TYPE_NONE && - type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - -void irq_dispose_mapping(unsigned int virq) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - - if (virq == NO_IRQ) - return; - - host = irq_map[virq].host; - if (WARN_ON(host == NULL)) - return; - - /* Never unmap legacy interrupts */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) - return; - - irq_set_status_flags(virq, IRQ_NOREQUEST); - - /* remove chip and handler */ - irq_set_chip_and_handler(virq, NULL, NULL); - - /* Make sure it's completed */ - synchronize_irq(virq); - - /* Tell the PIC about it */ - if (host->ops->unmap) - host->ops->unmap(host, virq); - smp_mb(); - - /* Clear reverse map */ - hwirq = irq_map[virq].hwirq; - switch(host->revmap_type) { - case IRQ_HOST_MAP_LINEAR: - if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; - break; - case IRQ_HOST_MAP_TREE: - mutex_lock(&revmap_trees_mutex); - radix_tree_delete(&host->revmap_data.tree, hwirq); - mutex_unlock(&revmap_trees_mutex); - break; - } - - /* Destroy map */ - smp_mb(); - irq_map[virq].hwirq = host->inval_irq; - - irq_free_descs(virq, 1); - /* Free it */ - irq_free_virt(virq, 1); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int i; - unsigned int hint = hwirq % irq_virq_count; - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) - return NO_IRQ; - - /* legacy -> bail early */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) - return hwirq; - - /* Slow path does a linear search of the map */ - if (hint < NUM_ISA_INTERRUPTS) - hint = NUM_ISA_INTERRUPTS; - i = hint; - do { - if (irq_map[i].host == host && - irq_map[i].hwirq == hwirq) - return i; - i++; - if (i >= irq_virq_count) - i = NUM_ISA_INTERRUPTS; - } while(i != hint); - return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); - #ifdef CONFIG_SMP int irq_choose_cpu(const struct cpumask *mask) { @@ -929,232 +609,11 @@ int irq_choose_cpu(const struct cpumask *mask) } #endif -unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq) -{ - struct irq_map_entry *ptr; - unsigned int virq; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) - return irq_find_mapping(host, hwirq); - - /* - * The ptr returned references the static global irq_map. - * but freeing an irq can delete nodes along the path to - * do the lookup via call_rcu. - */ - rcu_read_lock(); - ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); - rcu_read_unlock(); - - /* - * If found in radix tree, then fine. - * Else fallback to linear lookup - this should not happen in practice - * as it means that we failed to insert the node in the radix tree. - */ - if (ptr) - virq = ptr - irq_map; - else - virq = irq_find_mapping(host, hwirq); - - return virq; -} - -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) - return; - - if (virq != NO_IRQ) { - mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, - &irq_map[virq]); - mutex_unlock(&revmap_trees_mutex); - } -} - -unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int *revmap; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) - return irq_find_mapping(host, hwirq); - - /* Check revmap bounds */ - if (unlikely(hwirq >= host->revmap_data.linear.size)) - return irq_find_mapping(host, hwirq); - - /* Check if revmap was allocated */ - revmap = host->revmap_data.linear.revmap; - if (unlikely(revmap == NULL)) - return irq_find_mapping(host, hwirq); - - /* Fill up revmap with slow path if no mapping found */ - if (unlikely(revmap[hwirq] == NO_IRQ)) - revmap[hwirq] = irq_find_mapping(host, hwirq); - - return revmap[hwirq]; -} - -unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint) -{ - unsigned long flags; - unsigned int i, j, found = NO_IRQ; - - if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS)) - return NO_IRQ; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* Use hint for 1 interrupt if any */ - if (count == 1 && hint >= NUM_ISA_INTERRUPTS && - hint < irq_virq_count && irq_map[hint].host == NULL) { - found = hint; - goto hint_found; - } - - /* Look for count consecutive numbers in the allocatable - * (non-legacy) space - */ - for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) { - if (irq_map[i].host != NULL) - j = 0; - else - j++; - - if (j == count) { - found = i - count + 1; - break; - } - } - if (found == NO_IRQ) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return NO_IRQ; - } - hint_found: - for (i = found; i < (found + count); i++) { - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = host; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} - -void irq_free_virt(unsigned int virq, unsigned int count) -{ - unsigned long flags; - unsigned int i; - - WARN_ON (virq < NUM_ISA_INTERRUPTS); - WARN_ON (count == 0 || (virq + count) > irq_virq_count); - - if (virq < NUM_ISA_INTERRUPTS) { - if (virq + count < NUM_ISA_INTERRUPTS) - return; - count =- NUM_ISA_INTERRUPTS - virq; - virq = NUM_ISA_INTERRUPTS; - } - - if (count > irq_virq_count || virq > irq_virq_count - count) { - if (virq > irq_virq_count) - return; - count = irq_virq_count - virq; - } - - raw_spin_lock_irqsave(&irq_big_lock, flags); - for (i = virq; i < (virq + count); i++) { - struct irq_host *host; - - host = irq_map[i].host; - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = NULL; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); -} - int arch_early_irq_init(void) { return 0; } -#ifdef CONFIG_VIRQ_DEBUG -static int virq_debug_show(struct seq_file *m, void *private) -{ - unsigned long flags; - struct irq_desc *desc; - const char *p; - static const char none[] = "none"; - void *data; - int i; - - seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", - "chip name", "chip data", "host name"); - - for (i = 1; i < nr_irqs; i++) { - desc = irq_to_desc(i); - if (!desc) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - if (desc->action && desc->action->handler) { - struct irq_chip *chip; - - seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", irq_map[i].hwirq); - - chip = irq_desc_get_chip(desc); - if (chip && chip->name) - p = chip->name; - else - p = none; - seq_printf(m, "%-15s ", p); - - data = irq_desc_get_chip_data(desc); - seq_printf(m, "0x%16p ", data); - - if (irq_map[i].host && irq_map[i].host->of_node) - p = irq_map[i].host->of_node->full_name; - else - p = none; - seq_printf(m, "%s\n", p); - } - - raw_spin_unlock_irqrestore(&desc->lock, flags); - } - - return 0; -} - -static int virq_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, virq_debug_show, inode->i_private); -} - -static const struct file_operations virq_debug_fops = { - .open = virq_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init irq_debugfs_init(void) -{ - if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, - NULL, &virq_debug_fops) == NULL) - return -ENOMEM; - - return 0; -} -__initcall(irq_debugfs_init); -#endif /* CONFIG_VIRQ_DEBUG */ - #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c index 479752901ec6..d45ec58703ce 100644 --- a/arch/powerpc/kernel/isa-bridge.c +++ b/arch/powerpc/kernel/isa-bridge.c @@ -29,7 +29,6 @@ #include <asm/pci-bridge.h> #include <asm/machdep.h> #include <asm/ppc-pci.h> -#include <asm/firmware.h> unsigned long isa_io_base; /* NULL if no ISA bus */ EXPORT_SYMBOL(isa_io_base); @@ -261,8 +260,6 @@ static struct notifier_block isa_bridge_notifier = { */ static int __init isa_bridge_init(void) { - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; bus_register_notifier(&pci_bus_type, &isa_bridge_notifier); return 0; } diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 578f35f18723..ac12bd80ad95 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -26,7 +26,6 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <asm/uaccess.h> -#include <asm/iseries/hv_lp_config.h> #include <asm/lppaca.h> #include <asm/hvcall.h> #include <asm/firmware.h> @@ -55,80 +54,14 @@ static unsigned long get_purr(void) int cpu; for_each_possible_cpu(cpu) { - if (firmware_has_feature(FW_FEATURE_ISERIES)) - sum_purr += lppaca_of(cpu).emulated_time_base; - else { - struct cpu_usage *cu; + struct cpu_usage *cu; - cu = &per_cpu(cpu_usage_array, cpu); - sum_purr += cu->current_tb; - } + cu = &per_cpu(cpu_usage_array, cpu); + sum_purr += cu->current_tb; } return sum_purr; } -#ifdef CONFIG_PPC_ISERIES - -/* - * Methods used to fetch LPAR data when running on an iSeries platform. - */ -static int iseries_lparcfg_data(struct seq_file *m, void *v) -{ - unsigned long pool_id; - int shared, entitled_capacity, max_entitled_capacity; - int processors, max_processors; - unsigned long purr = get_purr(); - - shared = (int)(local_paca->lppaca_ptr->shared_proc); - - seq_printf(m, "system_active_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); - - seq_printf(m, "system_potential_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); - - processors = (int)HvLpConfig_getPhysicalProcessors(); - seq_printf(m, "partition_active_processors=%d\n", processors); - - max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); - seq_printf(m, "partition_potential_processors=%d\n", max_processors); - - if (shared) { - entitled_capacity = HvLpConfig_getSharedProcUnits(); - max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); - } else { - entitled_capacity = processors * 100; - max_entitled_capacity = max_processors * 100; - } - seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); - - seq_printf(m, "partition_max_entitled_capacity=%d\n", - max_entitled_capacity); - - if (shared) { - pool_id = HvLpConfig_getSharedPoolIndex(); - seq_printf(m, "pool=%d\n", (int)pool_id); - seq_printf(m, "pool_capacity=%d\n", - (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * - 100)); - seq_printf(m, "purr=%ld\n", purr); - } - - seq_printf(m, "shared_processor_mode=%d\n", shared); - - return 0; -} - -#else /* CONFIG_PPC_ISERIES */ - -static int iseries_lparcfg_data(struct seq_file *m, void *v) -{ - return 0; -} - -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_PSERIES /* * Methods used to fetch LPAR data when running on a pSeries platform. */ @@ -648,8 +581,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, u8 new_weight, *new_weight_ptr = &new_weight; ssize_t retval; - if (!firmware_has_feature(FW_FEATURE_SPLPAR) || - firmware_has_feature(FW_FEATURE_ISERIES)) + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return -EINVAL; if (count > kbuf_sz) @@ -709,21 +641,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, return retval; } -#else /* CONFIG_PPC_PSERIES */ - -static int pseries_lparcfg_data(struct seq_file *m, void *v) -{ - return 0; -} - -static ssize_t lparcfg_write(struct file *file, const char __user * buf, - size_t count, loff_t * off) -{ - return -EINVAL; -} - -#endif /* CONFIG_PPC_PSERIES */ - static int lparcfg_data(struct seq_file *m, void *v) { struct device_node *rootdn; @@ -738,19 +655,11 @@ static int lparcfg_data(struct seq_file *m, void *v) rootdn = of_find_node_by_path("/"); if (rootdn) { tmp = of_get_property(rootdn, "model", NULL); - if (tmp) { + if (tmp) model = tmp; - /* Skip "IBM," - see platforms/iseries/dt.c */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - model += 4; - } tmp = of_get_property(rootdn, "system-id", NULL); - if (tmp) { + if (tmp) system_id = tmp; - /* Skip "IBM," - see platforms/iseries/dt.c */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - system_id += 4; - } lp_index_ptr = of_get_property(rootdn, "ibm,partition-no", NULL); if (lp_index_ptr) @@ -761,8 +670,6 @@ static int lparcfg_data(struct seq_file *m, void *v) seq_printf(m, "system_type=%s\n", model); seq_printf(m, "partition_id=%d\n", (int)lp_index); - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return iseries_lparcfg_data(m, v); return pseries_lparcfg_data(m, v); } @@ -786,8 +693,7 @@ static int __init lparcfg_init(void) umode_t mode = S_IRUSR | S_IRGRP | S_IROTH; /* Allow writing if we have FW_FEATURE_SPLPAR */ - if (firmware_has_feature(FW_FEATURE_SPLPAR) && - !firmware_has_feature(FW_FEATURE_ISERIES)) + if (firmware_has_feature(FW_FEATURE_SPLPAR)) mode |= S_IWUSR; ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops); diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index b69463ec2010..ba16874fe294 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -5,7 +5,6 @@ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras. * - * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * * setjmp/longjmp code by Paul Mackerras. diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index e1612dfb4a93..2049f2d00ffe 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -21,12 +21,13 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/atomic.h> #include <asm/errno.h> #include <asm/topology.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#include <linux/atomic.h> +#include <asm/eeh.h> #ifdef CONFIG_PPC_OF_PLATFORM_PCI @@ -66,6 +67,9 @@ static int __devinit of_pci_phb_probe(struct platform_device *dev) /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); + /* Create EEH devices for the PHB */ + eeh_dev_phb_init_dynamic(phb); + /* Register devices with EEH */ #ifdef CONFIG_EEH if (dev->dev.of_node->child) diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 41456ff55e14..0bb1f98613ba 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -11,13 +11,10 @@ #include <linux/export.h> #include <linux/memblock.h> -#include <asm/firmware.h> #include <asm/lppaca.h> #include <asm/paca.h> #include <asm/sections.h> #include <asm/pgtable.h> -#include <asm/iseries/lpar_map.h> -#include <asm/iseries/hv_types.h> #include <asm/kexec.h> /* This symbol is provided by the linker - let it fill in the paca @@ -30,8 +27,8 @@ extern unsigned long __toc_start; * The structure which the hypervisor knows about - this structure * should not cross a page boundary. The vpa_init/register_vpa call * is now known to fail if the lppaca structure crosses a page - * boundary. The lppaca is also used on legacy iSeries and POWER5 - * pSeries boxes. The lppaca is 640 bytes long, and cannot readily + * boundary. The lppaca is also used on POWER5 pSeries boxes. + * The lppaca is 640 bytes long, and cannot readily * change since the hypervisor knows its layout, so a 1kB alignment * will suffice to ensure that it doesn't cross a page boundary. */ @@ -183,12 +180,9 @@ void __init allocate_pacas(void) /* * We can't take SLB misses on the paca, and we want to access them * in real mode, so allocate them within the RMA and also within - * the first segment. On iSeries they must be within the area mapped - * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. + * the first segment. */ limit = min(0x10000000ULL, ppc64_rma_size); - if (firmware_has_feature(FW_FEATURE_ISERIES)) - limit = min(limit, HvPagesToMap * HVPAGESIZE); paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index cce98d76e905..d0373bcb7c9d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -38,7 +38,6 @@ #include <asm/byteorder.h> #include <asm/machdep.h> #include <asm/ppc-pci.h> -#include <asm/firmware.h> #include <asm/eeh.h> static DEFINE_SPINLOCK(hose_spinlock); @@ -219,20 +218,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev) struct of_irq oirq; unsigned int virq; - /* The current device-tree that iSeries generates from the HV - * PCI informations doesn't contain proper interrupt routing, - * and all the fallback would do is print out crap, so we - * don't attempt to resolve the interrupts here at all, some - * iSeries specific fixup does it. - * - * In the long run, we will hopefully fix the generated device-tree - * instead. - */ -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return -1; -#endif - pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev)); #ifdef DEBUG diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d817ab018486..e40707032ac3 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -647,6 +647,9 @@ void show_regs(struct pt_regs * regs) printk("MSR: "REG" ", regs->msr); printbits(regs->msr, msr_bits); printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); +#ifdef CONFIG_PPC64 + printk("SOFTE: %ld\n", regs->softe); +#endif trap = TRAP(regs); if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR)) printk("CFAR: "REG"\n", regs->orig_gpr3); @@ -1220,34 +1223,32 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); #ifdef CONFIG_PPC64 -void ppc64_runlatch_on(void) +/* Called with hard IRQs off */ +void __ppc64_runlatch_on(void) { + struct thread_info *ti = current_thread_info(); unsigned long ctrl; - if (cpu_has_feature(CPU_FTR_CTRL) && !test_thread_flag(TIF_RUNLATCH)) { - HMT_medium(); - - ctrl = mfspr(SPRN_CTRLF); - ctrl |= CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); + ctrl = mfspr(SPRN_CTRLF); + ctrl |= CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); - set_thread_flag(TIF_RUNLATCH); - } + ti->local_flags |= TLF_RUNLATCH; } +/* Called with hard IRQs off */ void __ppc64_runlatch_off(void) { + struct thread_info *ti = current_thread_info(); unsigned long ctrl; - HMT_medium(); - - clear_thread_flag(TIF_RUNLATCH); + ti->local_flags &= ~TLF_RUNLATCH; ctrl = mfspr(SPRN_CTRLF); ctrl &= ~CTRL_RUNLATCH; mtspr(SPRN_CTRLT, ctrl); } -#endif +#endif /* CONFIG_PPC64 */ #if THREAD_SHIFT < PAGE_SHIFT diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index abe405dab34d..89e850af3dd6 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -52,9 +52,9 @@ #include <asm/machdep.h> #include <asm/pSeries_reconfig.h> #include <asm/pci-bridge.h> -#include <asm/phyp_dump.h> #include <asm/kexec.h> #include <asm/opal.h> +#include <asm/fadump.h> #include <mm/mmu_decl.h> @@ -615,86 +615,6 @@ static void __init early_reserve_mem(void) } } -#ifdef CONFIG_PHYP_DUMP -/** - * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg - * - * Function to find the largest size we need to reserve - * during early boot process. - * - * It either looks for boot param and returns that OR - * returns larger of 256 or 5% rounded down to multiples of 256MB. - * - */ -static inline unsigned long phyp_dump_calculate_reserve_size(void) -{ - unsigned long tmp; - - if (phyp_dump_info->reserve_bootvar) - return phyp_dump_info->reserve_bootvar; - - /* divide by 20 to get 5% of value */ - tmp = memblock_end_of_DRAM(); - do_div(tmp, 20); - - /* round it down in multiples of 256 */ - tmp = tmp & ~0x0FFFFFFFUL; - - return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END); -} - -/** - * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory - * - * This routine may reserve memory regions in the kernel only - * if the system is supported and a dump was taken in last - * boot instance or if the hardware is supported and the - * scratch area needs to be setup. In other instances it returns - * without reserving anything. The memory in case of dump being - * active is freed when the dump is collected (by userland tools). - */ -static void __init phyp_dump_reserve_mem(void) -{ - unsigned long base, size; - unsigned long variable_reserve_size; - - if (!phyp_dump_info->phyp_dump_configured) { - printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); - return; - } - - if (!phyp_dump_info->phyp_dump_at_boot) { - printk(KERN_INFO "Phyp-dump disabled at boot time\n"); - return; - } - - variable_reserve_size = phyp_dump_calculate_reserve_size(); - - if (phyp_dump_info->phyp_dump_is_active) { - /* Reserve *everything* above RMR.Area freed by userland tools*/ - base = variable_reserve_size; - size = memblock_end_of_DRAM() - base; - - /* XXX crashed_ram_end is wrong, since it may be beyond - * the memory_limit, it will need to be adjusted. */ - memblock_reserve(base, size); - - phyp_dump_info->init_reserve_start = base; - phyp_dump_info->init_reserve_size = size; - } else { - size = phyp_dump_info->cpu_state_size + - phyp_dump_info->hpte_region_size + - variable_reserve_size; - base = memblock_end_of_DRAM() - size; - memblock_reserve(base, size); - phyp_dump_info->init_reserve_start = base; - phyp_dump_info->init_reserve_size = size; - } -} -#else -static inline void __init phyp_dump_reserve_mem(void) {} -#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ - void __init early_init_devtree(void *params) { phys_addr_t limit; @@ -714,9 +634,9 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_opal, NULL); #endif -#ifdef CONFIG_PHYP_DUMP - /* scan tree to see if dump occurred during last boot */ - of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); +#ifdef CONFIG_FA_DUMP + /* scan tree to see if dump is active during last boot */ + of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL); #endif /* Pre-initialize the cmd_line with the content of boot_commmand_line, @@ -750,9 +670,15 @@ void __init early_init_devtree(void *params) if (PHYSICAL_START > MEMORY_START) memblock_reserve(MEMORY_START, 0x8000); reserve_kdump_trampoline(); - reserve_crashkernel(); +#ifdef CONFIG_FA_DUMP + /* + * If we fail to reserve memory for firmware-assisted dump then + * fallback to kexec based kdump. + */ + if (fadump_reserve_mem() == 0) +#endif + reserve_crashkernel(); early_reserve_mem(); - phyp_dump_reserve_mem(); /* * Ensure that total memory size is page-aligned, because otherwise diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index eca626ea3f23..e2d599048142 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -48,14 +48,6 @@ #include <linux/linux_logo.h> /* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This value does need to be big enough to - * ensure that we don't lose things like the interrupt-map property - * on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) - -/* * Eventually bump that one up */ #define DEVTREE_CHUNK_SIZE 0x100000 @@ -2273,13 +2265,6 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, /* sanity checks */ if (l == PROM_ERROR) continue; - if (l > MAX_PROPERTY_LENGTH) { - prom_printf("WARNING: ignoring large property "); - /* It seems OF doesn't null-terminate the path :-( */ - prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", RELOC(pname), l); - continue; - } /* push property head */ dt_push_token(OF_DT_PROP, mem_start, mem_end); diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 6cd8f0196b6d..517bd86bc3f0 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -275,6 +275,9 @@ void __init find_and_init_phbs(void) of_node_put(root); pci_devs_phb_init(); + /* Create EEH devices for all PHBs */ + eeh_dev_phb_init(); + /* * pci_probe_only and pci_assign_all_buses can be set via properties * in chosen. diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 77bb77da05c1..b0ebdeab9494 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -61,6 +61,7 @@ #include <asm/xmon.h> #include <asm/cputhreads.h> #include <mm/mmu_decl.h> +#include <asm/fadump.h> #include "setup.h" @@ -109,6 +110,14 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs); /* also used by kexec */ void machine_shutdown(void) { +#ifdef CONFIG_FA_DUMP + /* + * if fadump is active, cleanup the fadump registration before we + * shutdown. + */ + fadump_cleanup(); +#endif + if (ppc_md.machine_shutdown) ppc_md.machine_shutdown(); } @@ -639,6 +648,11 @@ EXPORT_SYMBOL(check_legacy_ioport); static int ppc_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { + /* + * If firmware-assisted dump has been registered then trigger + * firmware-assisted dump and let firmware handle everything else. + */ + crash_fadump(NULL, ptr); ppc_md.panic(ptr); /* May not return */ return NOTIFY_DONE; } diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index ac6e437b1021..7006b7f4267a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -57,10 +57,7 @@ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, void restore_sigmask(sigset_t *set) { sigdelsetmask(set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = *set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(set); } static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, @@ -169,13 +166,7 @@ static int do_signal(struct pt_regs *regs) regs->trap = 0; if (ret) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka.sa.sa_mask); - if (!(ka.sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(&ka, signr); /* * A signal was successfully delivered; the saved sigmask is in diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 836a5a19eb2c..e061ef5dd449 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -242,12 +242,13 @@ static inline int restore_general_regs(struct pt_regs *regs, */ long sys_sigsuspend(old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); + sigset_t blocked; + current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + + mask &= _BLOCKABLE; + siginitset(&blocked, mask); + set_current_blocked(&blocked); current->state = TASK_INTERRUPTIBLE; schedule(); diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 883e74c0d1b3..0c683d376b1c 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -12,7 +12,6 @@ #include <asm/current.h> #include <asm/processor.h> #include <asm/cputable.h> -#include <asm/firmware.h> #include <asm/hvcall.h> #include <asm/prom.h> #include <asm/machdep.h> @@ -341,8 +340,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu) int i, nattrs; #ifdef CONFIG_PPC64 - if (!firmware_has_feature(FW_FEATURE_ISERIES) && - cpu_has_feature(CPU_FTR_SMT)) + if (cpu_has_feature(CPU_FTR_SMT)) device_create_file(s, &dev_attr_smt_snooze_delay); #endif @@ -414,8 +412,7 @@ static void unregister_cpu_online(unsigned int cpu) BUG_ON(!c->hotpluggable); #ifdef CONFIG_PPC64 - if (!firmware_has_feature(FW_FEATURE_ISERIES) && - cpu_has_feature(CPU_FTR_SMT)) + if (cpu_has_feature(CPU_FTR_SMT)) device_remove_file(s, &dev_attr_smt_snooze_delay); #endif diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 567dd7c3ac2a..2c42cd72d0f5 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -17,8 +17,7 @@ * * TODO (not necessarily in this file): * - improve precision and reproducibility of timebase frequency - * measurement at boot time. (for iSeries, we calibrate the timebase - * against the Titan chip's clock.) + * measurement at boot time. * - for astronomical applications: add a new function to get * non ambiguous timestamps even around leap seconds. This needs * a new timestamp format and a good name. @@ -70,10 +69,6 @@ #include <asm/vdso_datapage.h> #include <asm/firmware.h> #include <asm/cputime.h> -#ifdef CONFIG_PPC_ISERIES -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/hv_call_xm.h> -#endif /* powerpc clocksource/clockevent code */ @@ -117,14 +112,6 @@ static struct clock_event_device decrementer_clockevent = { DEFINE_PER_CPU(u64, decrementers_next_tb); static DEFINE_PER_CPU(struct clock_event_device, decrementers); -#ifdef CONFIG_PPC_ISERIES -static unsigned long __initdata iSeries_recal_titan; -static signed long __initdata iSeries_recal_tb; - -/* Forward declaration is only needed for iSereis compiles */ -static void __init clocksource_init(void); -#endif - #define XSEC_PER_SEC (1024*1024) #ifdef CONFIG_PPC64 @@ -259,7 +246,6 @@ void accumulate_stolen_time(void) u64 sst, ust; u8 save_soft_enabled = local_paca->soft_enabled; - u8 save_hard_enabled = local_paca->hard_enabled; /* We are called early in the exception entry, before * soft/hard_enabled are sync'ed to the expected state @@ -268,7 +254,6 @@ void accumulate_stolen_time(void) * complain */ local_paca->soft_enabled = 0; - local_paca->hard_enabled = 0; sst = scan_dispatch_log(local_paca->starttime_user); ust = scan_dispatch_log(local_paca->starttime); @@ -277,7 +262,6 @@ void accumulate_stolen_time(void) local_paca->stolen_time += ust + sst; local_paca->soft_enabled = save_soft_enabled; - local_paca->hard_enabled = save_hard_enabled; } static inline u64 calculate_stolen_time(u64 stop_tb) @@ -426,74 +410,6 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); #endif -#ifdef CONFIG_PPC_ISERIES - -/* - * This function recalibrates the timebase based on the 49-bit time-of-day - * value in the Titan chip. The Titan is much more accurate than the value - * returned by the service processor for the timebase frequency. - */ - -static int __init iSeries_tb_recal(void) -{ - unsigned long titan, tb; - - /* Make sure we only run on iSeries */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return -ENODEV; - - tb = get_tb(); - titan = HvCallXm_loadTod(); - if ( iSeries_recal_titan ) { - unsigned long tb_ticks = tb - iSeries_recal_tb; - unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12; - unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec; - unsigned long new_tb_ticks_per_jiffy = - DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ); - long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy; - char sign = '+'; - /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */ - new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ; - - if ( tick_diff < 0 ) { - tick_diff = -tick_diff; - sign = '-'; - } - if ( tick_diff ) { - if ( tick_diff < tb_ticks_per_jiffy/25 ) { - printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n", - new_tb_ticks_per_jiffy, sign, tick_diff ); - tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; - tb_ticks_per_sec = new_tb_ticks_per_sec; - calc_cputime_factors(); - vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; - setup_cputime_one_jiffy(); - } - else { - printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" - " new tb_ticks_per_jiffy = %lu\n" - " old tb_ticks_per_jiffy = %lu\n", - new_tb_ticks_per_jiffy, tb_ticks_per_jiffy ); - } - } - } - iSeries_recal_titan = titan; - iSeries_recal_tb = tb; - - /* Called here as now we know accurate values for the timebase */ - clocksource_init(); - return 0; -} -late_initcall(iSeries_tb_recal); - -/* Called from platform early init */ -void __init iSeries_time_init_early(void) -{ - iSeries_recal_tb = get_tb(); - iSeries_recal_titan = HvCallXm_loadTod(); -} -#endif /* CONFIG_PPC_ISERIES */ - #ifdef CONFIG_IRQ_WORK /* @@ -550,16 +466,6 @@ void arch_irq_work_raise(void) #endif /* CONFIG_IRQ_WORK */ /* - * For iSeries shared processors, we have to let the hypervisor - * set the hardware decrementer. We set a virtual decrementer - * in the lppaca and call the hypervisor if the virtual - * decrementer is less than the current value in the hardware - * decrementer. (almost always the new decrementer value will - * be greater than the current hardware decementer so the hypervisor - * call will not be needed) - */ - -/* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. */ @@ -580,6 +486,11 @@ void timer_interrupt(struct pt_regs * regs) if (!cpu_online(smp_processor_id())) return; + /* Conditionally hard-enable interrupts now that the DEC has been + * bumped to its maximum value + */ + may_hard_irq_enable(); + trace_timer_interrupt_entry(regs); __get_cpu_var(irq_stat).timer_irqs++; @@ -597,20 +508,10 @@ void timer_interrupt(struct pt_regs * regs) irq_work_run(); } -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) - get_lppaca()->int_dword.fields.decr_int = 0; -#endif - *next_tb = ~(u64)0; if (evt->event_handler) evt->event_handler(evt); -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) - process_hvlpevents(); -#endif - #ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { @@ -982,9 +883,8 @@ void __init time_init(void) */ start_cpu_decrementer(); - /* Register the clocksource, if we're not running on iSeries */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - clocksource_init(); + /* Register the clocksource */ + clocksource_init(); init_decrementer_clockevent(); } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c091527efd89..a750409ccc4e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -57,6 +57,7 @@ #include <asm/kexec.h> #include <asm/ppc-opcode.h> #include <asm/rio.h> +#include <asm/fadump.h> #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int (*__debugger)(struct pt_regs *regs) __read_mostly; @@ -145,6 +146,8 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, arch_spin_unlock(&die_lock); raw_local_irq_restore(flags); + crash_fadump(regs, "die oops"); + /* * A system reset (0x100) is a request to dump, so we always send * it through the crashdump code. @@ -244,6 +247,9 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) addr, regs->nip, regs->link, code); } + if (!arch_irq_disabled_regs(regs)) + local_irq_enable(); + memset(&info, 0, sizeof(info)); info.si_signo = signr; info.si_code = code; diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 8b086299ba25..bca3fc427b45 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -34,11 +34,6 @@ #include <asm/abs_addr.h> #include <asm/page.h> #include <asm/hvcall.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/iommu.h> static struct bus_type vio_bus_type; @@ -1042,7 +1037,6 @@ static void vio_cmo_sysfs_init(void) vio_bus_type.bus_attrs = vio_cmo_bus_attrs; } #else /* CONFIG_PPC_SMLPAR */ -/* Dummy functions for iSeries platform */ int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } @@ -1060,9 +1054,6 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) struct iommu_table *tbl; unsigned long offset, size; - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return vio_build_iommu_table_iseries(dev); - dma_window = of_get_property(dev->dev.of_node, "ibm,my-dma-window", NULL); if (!dma_window) @@ -1195,8 +1186,7 @@ static void __devinit vio_dev_release(struct device *dev) { struct iommu_table *tbl = get_iommu_table_base(dev); - /* iSeries uses a common table for all vio devices */ - if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl) + if (tbl) iommu_free_table(tbl, dev->of_node ? dev->of_node->full_name : dev_name(dev)); of_node_put(dev->of_node); @@ -1244,12 +1234,6 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) viodev->name = of_node->name; viodev->type = of_node->type; viodev->unit_address = *unit_address; - if (firmware_has_feature(FW_FEATURE_ISERIES)) { - unit_address = of_get_property(of_node, - "linux,unit_address", NULL); - if (unit_address != NULL) - viodev->unit_address = *unit_address; - } viodev->dev.of_node = of_node_get(of_node); if (firmware_has_feature(FW_FEATURE_CMO)) diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 710a54005dfb..65d1c08cf09e 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -109,11 +109,6 @@ SECTIONS __ptov_table_begin = .; *(.ptov_fixup); __ptov_table_end = .; -#ifdef CONFIG_PPC_ISERIES - __dt_strings_start = .; - *(.dt_strings); - __dt_strings_end = .; -#endif } .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 336983da9e72..a7267167a550 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -46,7 +46,6 @@ #include <asm/page.h> #include <asm/hvcall.h> #include <linux/gfp.h> -#include <linux/sched.h> #include <linux/vmalloc.h> #include <linux/highmem.h> diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index e2cfb9e1e20e..220fcdf26978 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -227,14 +227,14 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) hpage_offset /= 4; get_page(hpage); - page = kmap_atomic(hpage, KM_USER0); + page = kmap_atomic(hpage); /* patch dcbz into reserved instruction, so we trap */ for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) if ((page[i] & 0xff0007ff) == INS_DCBZ) page[i] &= 0xfffffff7; - kunmap_atomic(page, KM_USER0); + kunmap_atomic(page); put_page(hpage); } diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c index a6ebba56fdd4..bb7cfecf2788 100644 --- a/arch/powerpc/lib/locks.c +++ b/arch/powerpc/lib/locks.c @@ -19,11 +19,9 @@ #include <linux/smp.h> /* waiting for a spinlock... */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +#if defined(CONFIG_PPC_SPLPAR) #include <asm/hvcall.h> -#include <asm/iseries/hv_call.h> #include <asm/smp.h> -#include <asm/firmware.h> void __spin_yield(arch_spinlock_t *lock) { @@ -40,14 +38,8 @@ void __spin_yield(arch_spinlock_t *lock) rmb(); if (lock->slock != lock_value) return; /* something has changed */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, - ((u64)holder_cpu << 32) | yield_count); -#ifdef CONFIG_PPC_SPLPAR - else - plpar_hcall_norets(H_CONFER, - get_hard_smp_processor_id(holder_cpu), yield_count); -#endif + plpar_hcall_norets(H_CONFER, + get_hard_smp_processor_id(holder_cpu), yield_count); } /* @@ -71,14 +63,8 @@ void __rw_yield(arch_rwlock_t *rw) rmb(); if (rw->lock != lock_value) return; /* something has changed */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, - ((u64)holder_cpu << 32) | yield_count); -#ifdef CONFIG_PPC_SPLPAR - else - plpar_hcall_norets(H_CONFER, - get_hard_smp_processor_id(holder_cpu), yield_count); -#endif + plpar_hcall_norets(H_CONFER, + get_hard_smp_processor_id(holder_cpu), yield_count); } #endif diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c index 329be36c0a8d..6747eece84af 100644 --- a/arch/powerpc/mm/dma-noncoherent.c +++ b/arch/powerpc/mm/dma-noncoherent.c @@ -365,12 +365,11 @@ static inline void __dma_sync_page_highmem(struct page *page, local_irq_save(flags); do { - start = (unsigned long)kmap_atomic(page + seg_nr, - KM_PPC_SYNC_PAGE) + seg_offset; + start = (unsigned long)kmap_atomic(page + seg_nr) + seg_offset; /* Sync this buffer segment */ __dma_sync((void *)start, seg_size, direction); - kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); + kunmap_atomic((void *)start); seg_nr++; /* Calculate next buffer segment size */ diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 2f0d1b032a89..19f2f9498b27 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -105,6 +105,82 @@ static int store_updates_sp(struct pt_regs *regs) } return 0; } +/* + * do_page_fault error handling helpers + */ + +#define MM_FAULT_RETURN 0 +#define MM_FAULT_CONTINUE -1 +#define MM_FAULT_ERR(sig) (sig) + +static int out_of_memory(struct pt_regs *regs) +{ + /* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ + up_read(¤t->mm->mmap_sem); + if (!user_mode(regs)) + return MM_FAULT_ERR(SIGKILL); + pagefault_out_of_memory(); + return MM_FAULT_RETURN; +} + +static int do_sigbus(struct pt_regs *regs, unsigned long address) +{ + siginfo_t info; + + up_read(¤t->mm->mmap_sem); + + if (user_mode(regs)) { + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, current); + return MM_FAULT_RETURN; + } + return MM_FAULT_ERR(SIGBUS); +} + +static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) +{ + /* + * Pagefault was interrupted by SIGKILL. We have no reason to + * continue the pagefault. + */ + if (fatal_signal_pending(current)) { + /* + * If we have retry set, the mmap semaphore will have + * alrady been released in __lock_page_or_retry(). Else + * we release it now. + */ + if (!(fault & VM_FAULT_RETRY)) + up_read(¤t->mm->mmap_sem); + /* Coming from kernel, we need to deal with uaccess fixups */ + if (user_mode(regs)) + return MM_FAULT_RETURN; + return MM_FAULT_ERR(SIGKILL); + } + + /* No fault: be happy */ + if (!(fault & VM_FAULT_ERROR)) + return MM_FAULT_CONTINUE; + + /* Out of memory */ + if (fault & VM_FAULT_OOM) + return out_of_memory(regs); + + /* Bus error. x86 handles HWPOISON here, we'll add this if/when + * we support the feature in HW + */ + if (fault & VM_FAULT_SIGBUS) + return do_sigbus(regs, addr); + + /* We don't understand the fault code, this is fatal */ + BUG(); + return MM_FAULT_CONTINUE; +} /* * For 600- and 800-family processors, the error_code parameter is DSISR @@ -124,11 +200,12 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; - siginfo_t info; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; int code = SEGV_MAPERR; - int is_write = 0, ret; + int is_write = 0; int trap = TRAP(regs); int is_exec = trap == 0x400; + int fault; #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) /* @@ -145,6 +222,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, is_write = error_code & ESR_DST; #endif /* CONFIG_4xx || CONFIG_BOOKE */ + if (is_write) + flags |= FAULT_FLAG_WRITE; + #ifdef CONFIG_PPC_ICSWX /* * we need to do this early because this "data storage @@ -152,13 +232,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, * look at it */ if (error_code & ICSWX_DSI_UCT) { - int ret; - - ret = acop_handle_fault(regs, address, error_code); - if (ret) - return ret; + int rc = acop_handle_fault(regs, address, error_code); + if (rc) + return rc; } -#endif +#endif /* CONFIG_PPC_ICSWX */ if (notify_page_fault(regs)) return 0; @@ -179,6 +257,10 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, } #endif + /* We restore the interrupt state now */ + if (!arch_irq_disabled_regs(regs)) + local_irq_enable(); + if (in_atomic() || mm == NULL) { if (!user_mode(regs)) return SIGSEGV; @@ -212,7 +294,15 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, if (!user_mode(regs) && !search_exception_tables(regs->nip)) goto bad_area_nosemaphore; +retry: down_read(&mm->mmap_sem); + } else { + /* + * The above down_read_trylock() might have succeeded in + * which case we'll have missed the might_sleep() from + * down_read(): + */ + might_sleep(); } vma = find_vma(mm, address); @@ -327,30 +417,43 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - ret = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); - if (unlikely(ret & VM_FAULT_ERROR)) { - if (ret & VM_FAULT_OOM) - goto out_of_memory; - else if (ret & VM_FAULT_SIGBUS) - goto do_sigbus; - BUG(); + fault = handle_mm_fault(mm, vma, address, flags); + if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { + int rc = mm_fault_error(regs, address, fault); + if (rc >= MM_FAULT_RETURN) + return rc; } - if (ret & VM_FAULT_MAJOR) { - current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, - regs, address); + + /* + * Major/minor page fault accounting is only done on the + * initial attempt. If we go through a retry, it is extremely + * likely that the page will be found in page cache at that point. + */ + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + current->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + regs, address); #ifdef CONFIG_PPC_SMLPAR - if (firmware_has_feature(FW_FEATURE_CMO)) { - preempt_disable(); - get_lppaca()->page_ins += (1 << PAGE_FACTOR); - preempt_enable(); + if (firmware_has_feature(FW_FEATURE_CMO)) { + preempt_disable(); + get_lppaca()->page_ins += (1 << PAGE_FACTOR); + preempt_enable(); + } +#endif /* CONFIG_PPC_SMLPAR */ + } else { + current->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + regs, address); + } + if (fault & VM_FAULT_RETRY) { + /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk + * of starvation. */ + flags &= ~FAULT_FLAG_ALLOW_RETRY; + goto retry; } -#endif - } else { - current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, - regs, address); } + up_read(&mm->mmap_sem); return 0; @@ -371,28 +474,6 @@ bad_area_nosemaphore: return SIGSEGV; -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -out_of_memory: - up_read(&mm->mmap_sem); - if (!user_mode(regs)) - return SIGKILL; - pagefault_out_of_memory(); - return 0; - -do_sigbus: - up_read(&mm->mmap_sem); - if (user_mode(regs)) { - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)address; - force_sig_info(SIGBUS, &info, current); - return 0; - } - return SIGBUS; } /* diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 66a6fd38e9cd..07ba45b0f07c 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -149,12 +149,19 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys, unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, phys_addr_t phys) { - unsigned int camsize = __ilog2(ram) & ~1U; - unsigned int align = __ffs(virt | phys) & ~1U; - unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; - - /* Convert (4^max) kB to (2^max) bytes */ - max_cam = max_cam * 2 + 10; + unsigned int camsize = __ilog2(ram); + unsigned int align = __ffs(virt | phys); + unsigned long max_cam; + + if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { + /* Convert (4^max) kB to (2^max) bytes */ + max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10; + camsize &= ~1U; + align &= ~1U; + } else { + /* Convert (2^max) kB to (2^max) bytes */ + max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10; + } if (camsize > align) camsize = align; diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 2d282186cb45..3e8c37a4e395 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -55,6 +55,8 @@ #include <asm/spu.h> #include <asm/udbg.h> #include <asm/code-patching.h> +#include <asm/fadump.h> +#include <asm/firmware.h> #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -625,6 +627,16 @@ static void __init htab_initialize(void) /* Using a hypervisor which owns the htab */ htab_address = NULL; _SDR1 = 0; +#ifdef CONFIG_FA_DUMP + /* + * If firmware assisted dump is active firmware preserves + * the contents of htab along with entire partition memory. + * Clear the htab if firmware assisted dump is active so + * that we dont end up using old mappings. + */ + if (is_fadump_active() && ppc_md.hpte_clear_all) + ppc_md.hpte_clear_all(); +#endif } else { /* Find storage for the HPT. Must be contiguous in * the absolute address space. On cell we want it to be @@ -745,12 +757,9 @@ void __init early_init_mmu(void) */ htab_initialize(); - /* Initialize stab / SLB management except on iSeries - */ + /* Initialize stab / SLB management */ if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); - else if (!firmware_has_feature(FW_FEATURE_ISERIES)) - stab_initialize(get_paca()->stab_real); } #ifdef CONFIG_SMP @@ -761,8 +770,7 @@ void __cpuinit early_init_mmu_secondary(void) mtspr(SPRN_SDR1, _SDR1); /* Initialize STAB/SLB. We use a virtual address as it works - * in real mode on pSeries and we want a virtual address on - * iSeries anyway + * in real mode on pSeries. */ if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index a8b3cc7d90fe..57c7465e656e 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -910,9 +910,9 @@ void flush_dcache_icache_hugepage(struct page *page) if (!PageHighMem(page)) { __flush_dcache_icache(page_address(page+i)); } else { - start = kmap_atomic(page+i, KM_PPC_SYNC_ICACHE); + start = kmap_atomic(page+i); __flush_dcache_icache(start); - kunmap_atomic(start, KM_PPC_SYNC_ICACHE); + kunmap_atomic(start); } } } diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c index 5d9a59eaad93..8cdbd8634a58 100644 --- a/arch/powerpc/mm/icswx.c +++ b/arch/powerpc/mm/icswx.c @@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(drop_cop); static int acop_use_cop(int ct) { - /* todo */ + /* There is no alternate policy, yet */ return -1; } @@ -227,11 +227,30 @@ int acop_handle_fault(struct pt_regs *regs, unsigned long address, ct = (ccw >> 16) & 0x3f; } + /* + * We could be here because another thread has enabled acop + * but the ACOP register has yet to be updated. + * + * This should have been taken care of by the IPI to sync all + * the threads (see smp_call_function(sync_cop, mm, 1)), but + * that could take forever if there are a significant amount + * of threads. + * + * Given the number of threads on some of these systems, + * perhaps this is the best way to sync ACOP rather than whack + * every thread with an IPI. + */ + if ((acop_copro_type_bit(ct) & current->active_mm->context.acop) != 0) { + sync_cop(current->active_mm); + return 0; + } + + /* check for alternate policy */ if (!acop_use_cop(ct)) return 0; /* at this point the CT is unknown to the system */ - pr_warn("%s[%d]: Coprocessor %d is unavailable", + pr_warn("%s[%d]: Coprocessor %d is unavailable\n", current->comm, current->pid, ct); /* get inst if we don't already have it */ diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h index 42176bd0884c..6dedc08e62c8 100644 --- a/arch/powerpc/mm/icswx.h +++ b/arch/powerpc/mm/icswx.h @@ -59,4 +59,10 @@ extern void free_cop_pid(int free_pid); extern int acop_handle_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code); + +static inline u64 acop_copro_type_bit(unsigned int type) +{ + return 1ULL << (63 - type); +} + #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */ diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index d974b79a3068..baaafde7d135 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -458,9 +458,9 @@ void flush_dcache_icache_page(struct page *page) #endif #ifdef CONFIG_BOOKE { - void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); + void *start = kmap_atomic(page); __flush_dcache_icache(start); - kunmap_atomic(start, KM_PPC_SYNC_ICACHE); + kunmap_atomic(start); } #elif defined(CONFIG_8xx) || defined(CONFIG_PPC64) /* On 8xx there is no need to kmap since highmem is not supported */ diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 51f87956f8f8..0907f92ce309 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -207,7 +207,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags, */ if (mem_init_done && (p < virt_to_phys(high_memory)) && !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) { - printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n", + printk("__ioremap(): phys addr 0x%llx is RAM lr %pf\n", (unsigned long long)p, __builtin_return_address(0)); return NULL; } diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index e22276cb67a4..a538c80db2df 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -21,7 +21,6 @@ #include <asm/cputable.h> #include <asm/cacheflush.h> #include <asm/smp.h> -#include <asm/firmware.h> #include <linux/compiler.h> #include <asm/udbg.h> #include <asm/code-patching.h> @@ -307,11 +306,6 @@ void slb_initialize(void) get_paca()->stab_rr = SLB_NUM_BOLTED; - /* On iSeries the bolted entries have already been set up by - * the hypervisor from the lparMap data in head.S */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return; - lflags = SLB_VSID_KERNEL | linear_llp; vflags = SLB_VSID_KERNEL | vmalloc_llp; diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index ef653dc95b65..b9ee79ce2200 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -217,21 +217,6 @@ slb_finish_load: * free slot first but that took too long. Unfortunately we * dont have any LRU information to help us choose a slot. */ -#ifdef CONFIG_PPC_ISERIES -BEGIN_FW_FTR_SECTION - /* - * On iSeries, the "bolted" stack segment can be cast out on - * shared processor switch so we need to check for a miss on - * it and restore it to the right slot. - */ - ld r9,PACAKSAVE(r13) - clrrdi r9,r9,28 - clrrdi r3,r3,28 - li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ - cmpld r9,r3 - beq 3f -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif /* CONFIG_PPC_ISERIES */ 7: ld r10,PACASTABRR(r13) addi r10,r10,1 @@ -282,7 +267,6 @@ _GLOBAL(slb_compare_rr_to_size) /* * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. - * We assume legacy iSeries will never have 1T segments. * * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9 */ diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 41e31642a86a..9106ebb118f5 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -21,8 +21,6 @@ #include <asm/cputable.h> #include <asm/prom.h> #include <asm/abs_addr.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call.h> struct stab_entry { unsigned long esid_data; @@ -285,12 +283,5 @@ void stab_initialize(unsigned long stab) /* Set ASR */ stabreal = get_paca()->stab_real | 0x1ul; -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) { - HvCall1(HvCallBaseSetASR, stabreal); - return; - } -#endif /* CONFIG_PPC_ISERIES */ - mtspr(SPRN_ASR, stabreal); } diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index d65e68f3cb25..6f01624f317f 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -195,9 +195,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) if (!cur_cpu_spec->oprofile_cpu_type) return -ENODEV; - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return -ENODEV; - switch (cur_cpu_spec->oprofile_type) { #ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_OPROFILE_CELL diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile new file mode 100644 index 000000000000..af3fac23768c --- /dev/null +++ b/arch/powerpc/perf/Makefile @@ -0,0 +1,14 @@ +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + +obj-$(CONFIG_PERF_EVENTS) += callchain.o + +obj-$(CONFIG_PPC_PERF_CTRS) += core-book3s.o +obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ + power5+-pmu.o power6-pmu.o power7-pmu.o +obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o + +obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o +obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o + +obj-$(CONFIG_PPC64) += $(obj64-y) +obj-$(CONFIG_PPC32) += $(obj32-y) diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/perf/callchain.c index 564c1d8bdb5c..e8a18d1cc7c9 100644 --- a/arch/powerpc/kernel/perf_callchain.c +++ b/arch/powerpc/perf/callchain.c @@ -20,7 +20,7 @@ #include <asm/ucontext.h> #include <asm/vdso.h> #ifdef CONFIG_PPC64 -#include "ppc32.h" +#include "../kernel/ppc32.h" #endif diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/perf/core-book3s.c index c2e27ede07ec..c2e27ede07ec 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/perf/core-book3s.c diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/perf/core-fsl-emb.c index 0a6d2a9d569c..0a6d2a9d569c 100644 --- a/arch/powerpc/kernel/perf_event_fsl_emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c index cb2e2949c8d1..cb2e2949c8d1 100644 --- a/arch/powerpc/kernel/e500-pmu.c +++ b/arch/powerpc/perf/e500-pmu.c diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/perf/mpc7450-pmu.c index fe21b515ca44..fe21b515ca44 100644 --- a/arch/powerpc/kernel/mpc7450-pmu.c +++ b/arch/powerpc/perf/mpc7450-pmu.c diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/perf/power4-pmu.c index b4f1dda4d089..b4f1dda4d089 100644 --- a/arch/powerpc/kernel/power4-pmu.c +++ b/arch/powerpc/perf/power4-pmu.c diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/perf/power5+-pmu.c index a8757baa28f3..a8757baa28f3 100644 --- a/arch/powerpc/kernel/power5+-pmu.c +++ b/arch/powerpc/perf/power5+-pmu.c diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/perf/power5-pmu.c index e7f06eb7a861..e7f06eb7a861 100644 --- a/arch/powerpc/kernel/power5-pmu.c +++ b/arch/powerpc/perf/power5-pmu.c diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/perf/power6-pmu.c index 0bbc901e7efc..31128e086fed 100644 --- a/arch/powerpc/kernel/power6-pmu.c +++ b/arch/powerpc/perf/power6-pmu.c @@ -131,7 +131,7 @@ static u32 marked_bus_events[16] = { 0x00000022, /* BFP set 2: byte 0 bits 1, 5 */ 0, 0 }; - + /* * Returns 1 if event counts things relating to marked instructions * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not. diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 1251e4d7e262..1251e4d7e262 100644 --- a/arch/powerpc/kernel/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/perf/ppc970-pmu.c index 8c2190206964..111eb25bb0b6 100644 --- a/arch/powerpc/kernel/ppc970-pmu.c +++ b/arch/powerpc/perf/ppc970-pmu.c @@ -252,7 +252,7 @@ static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[]) alt[1] = event ^ 0x1000; return 2; } - + return 1; } diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index fcf6bf2ceee9..2e4e64abfab4 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -23,6 +23,7 @@ config BLUESTONE default n select PPC44x_SIMPLE select APM821xx + select PPC4xx_PCI_EXPRESS select IBM_EMAC_RGMII help This option enables support for the APM APM821xx Evaluation board. diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c index 3f6229b5dee0..583e67fee37e 100644 --- a/arch/powerpc/platforms/44x/currituck.c +++ b/arch/powerpc/platforms/44x/currituck.c @@ -83,7 +83,7 @@ static void __init ppc47x_init_irq(void) * device-tree, just pass 0 to all arguments */ struct mpic *mpic = - mpic_alloc(np, 0, 0, 0, 0, " MPIC "); + mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); ppc_md.get_irq = mpic_get_irq; diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index 5b8cdbb82f80..a28a8629727e 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -71,8 +71,7 @@ static void __init iss4xx_init_irq(void) /* The MPIC driver will get everything it needs from the * device-tree, just pass 0 to all arguments */ - struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0, - " MPIC "); + struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); ppc_md.get_irq = mpic_get_irq; diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 8d2202763415..3ffb915446e3 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c @@ -52,7 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe); static char *board[] __initdata = { "amcc,arches", "amcc,bamboo", - "amcc,bluestone", + "apm,bluestone", "amcc,glacier", "ibm,ebony", "amcc,eiger", diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 9f09319352c0..ca3a062ed1b9 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -21,7 +21,7 @@ #include <asm/prom.h> static struct device_node *cpld_pic_node; -static struct irq_host *cpld_pic_host; +static struct irq_domain *cpld_pic_host; /* * Bits to ignore in the misc_status register @@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) } static int -cpld_pic_host_match(struct irq_host *h, struct device_node *node) +cpld_pic_host_match(struct irq_domain *h, struct device_node *node) { return cpld_pic_node == node; } static int -cpld_pic_host_map(struct irq_host *h, unsigned int virq, +cpld_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_status_flags(virq, IRQ_LEVEL); @@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct -irq_host_ops cpld_pic_host_ops = { +static const struct irq_domain_ops cpld_pic_host_ops = { .match = cpld_pic_host_match, .map = cpld_pic_host_map, }; @@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void) cpld_pic_node = of_node_get(np); - cpld_pic_host = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); + cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL); if (!cpld_pic_host) { printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n"); goto end; diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 96f85e5e0cd3..17d91b7da315 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = { struct media5200_irq { void __iomem *regs; spinlock_t lock; - struct irq_host *irqhost; + struct irq_domain *irqhost; }; struct media5200_irq media5200_irq; @@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc) raw_spin_unlock(&desc->lock); } -static int media5200_irq_map(struct irq_host *h, unsigned int virq, +static int media5200_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw); @@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq, return 0; } -static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, +static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops media5200_irq_ops = { +static const struct irq_domain_ops media5200_irq_ops = { .map = media5200_irq_map, .xlate = media5200_irq_xlate, }; @@ -173,15 +173,12 @@ static void __init media5200_init_irq(void) spin_lock_init(&media5200_irq.lock); - media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR, - MEDIA5200_NUM_IRQS, - &media5200_irq_ops, -1); + media5200_irq.irqhost = irq_domain_add_linear(fpga_np, + MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq); if (!media5200_irq.irqhost) goto out; pr_debug("%s: allocated irqhost\n", __func__); - media5200_irq.irqhost->host_data = &media5200_irq; - irq_set_handler_data(cascade_virq, &media5200_irq); irq_set_chained_handler(cascade_virq, media5200_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index 846b789fb195..c0aa04068d69 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void) /* list of the supported boards */ static const char *board[] __initdata = { + "anonymous,a4m072", "anon,charon", "intercontrol,digsy-mtc", "manroland,mucmc52", diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 369fd5457a3f..d7e94f49532a 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -98,13 +98,11 @@ struct mpc52xx_gpio_wkup __iomem *wkup_gpio; * of the localplus bus to the of_platform * bus. */ -void __init -mpc52xx_declare_of_platform_devices(void) +void __init mpc52xx_declare_of_platform_devices(void) { - /* Find every child of the SOC node and add it to of_platform */ - if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) - printk(KERN_ERR __FILE__ ": " - "Error while probing of_platform bus\n"); + /* Find all the 'platform' devices and register them. */ + if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL)) + pr_err(__FILE__ ": Error while populating devices from DT\n"); } /* diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index f94f06e52762..028470b95886 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -81,7 +81,7 @@ MODULE_LICENSE("GPL"); * @regs: virtual address of GPT registers * @lock: spinlock to coordinate between different functions. * @gc: gpio_chip instance structure; used when GPIO is enabled - * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported + * @irqhost: Pointer to irq_domain instance; used when IRQ mode is supported * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates * if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates * if the timer is actively used as wdt which blocks gpt functions @@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv { struct device *dev; struct mpc52xx_gpt __iomem *regs; spinlock_t lock; - struct irq_host *irqhost; + struct irq_domain *irqhost; u32 ipb_freq; u8 wdt_mode; @@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc) } } -static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_gpt_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct mpc52xx_gpt_priv *gpt = h->host_data; @@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, return 0; } -static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops mpc52xx_gpt_irq_ops = { +static const struct irq_domain_ops mpc52xx_gpt_irq_ops = { .map = mpc52xx_gpt_irq_map, .xlate = mpc52xx_gpt_irq_xlate, }; @@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) if (!cascade_virq) return; - gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, - &mpc52xx_gpt_irq_ops, -1); + gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt); if (!gpt->irqhost) { - dev_err(gpt->dev, "irq_alloc_host() failed\n"); + dev_err(gpt->dev, "irq_domain_add_linear() failed\n"); return; } - gpt->irqhost->host_data = gpt; irq_set_handler_data(cascade_virq, gpt); irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1a9a49570579..8520b58a5e9a 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = { static struct mpc52xx_intr __iomem *intr; static struct mpc52xx_sdma __iomem *sdma; -static struct irq_host *mpc52xx_irqhost = NULL; +static struct irq_domain *mpc52xx_irqhost = NULL; static unsigned char mpc52xx_map_senses[4] = { IRQ_TYPE_LEVEL_HIGH, @@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2) /** * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property */ -static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, /** * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure */ -static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t irq) { int l1irq; @@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops mpc52xx_irqhost_ops = { +static const struct irq_domain_ops mpc52xx_irqhost_ops = { .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; @@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void) * As last step, add an irq host to translate the real * hw irq information provided by the ofw to linux virq */ - mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, + mpc52xx_irqhost = irq_domain_add_linear(picnode, MPC52xx_IRQ_HIGHTESTHWIRQ, - &mpc52xx_irqhost_ops, -1); + &mpc52xx_irqhost_ops, NULL); if (!mpc52xx_irqhost) panic(__FILE__ ": Cannot allocate the IRQ host\n"); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 8ccf9ed62fe2..328d221fd1c0 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock); struct pq2ads_pci_pic { struct device_node *node; - struct irq_host *host; + struct irq_domain *host; struct { u32 stat; @@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc) } } -static int pci_pic_host_map(struct irq_host *h, unsigned int virq, +static int pci_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_status_flags(virq, IRQ_LEVEL); @@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops pci_pic_host_ops = { +static const struct irq_domain_ops pci_pic_host_ops = { .map = pci_pic_host_map, }; int __init pq2ads_pci_init_irq(void) { struct pq2ads_pci_pic *priv; - struct irq_host *host; + struct irq_domain *host; struct device_node *np; int ret = -ENODEV; int irq; @@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void) out_be32(&priv->regs->mask, ~0); mb(); - host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, - &pci_pic_host_ops, NUM_IRQS); + host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv); if (!host) { ret = -ENOMEM; goto out_unmap_regs; } - host->host_data = priv; - priv->host = host; - host->host_data = priv; irq_set_handler_data(irq, priv); irq_set_chained_handler(irq, pq2ads_pci_irq_demux); diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index d7946be298b6..f000d81c4e31 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -6,6 +6,7 @@ menuconfig FSL_SOC_BOOKE select MPIC select PPC_PCI_CHOICE select FSL_PCI if PCI + select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 default y @@ -13,6 +14,15 @@ if FSL_SOC_BOOKE if PPC32 +config FSL_85XX_CACHE_SRAM + bool + select PPC_LIB_RHEAP + help + When selected, this option enables cache-sram support + for memory allocation on P1/P2 QorIQ platforms. + cache-sram-size and cache-sram-offset kernel boot + parameters should be passed when this option is enabled. + config MPC8540_ADS bool "Freescale MPC8540 ADS" select DEFAULT_UIMAGE @@ -30,6 +40,7 @@ config MPC85xx_CDS bool "Freescale MPC85xx CDS" select DEFAULT_UIMAGE select PPC_I8259 + select HAS_RAPIDIO help This option enables support for the MPC85xx CDS board @@ -80,7 +91,6 @@ config P1010_RDB config P1022_DS bool "Freescale P1022 DS" select DEFAULT_UIMAGE - select PHYS_64BIT # The DTS has 36-bit addresses select SWIOTLB help This option enables support for the Freescale P1022DS reference board. @@ -171,6 +181,21 @@ config SBC8560 help This option enables support for the Wind River SBC8560 board +config GE_IMP3A + bool "GE Intelligent Platforms IMP3A" + select DEFAULT_UIMAGE + select SWIOTLB + select MMIO_NVRAM + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + select GE_FPGA + help + This option enables support for the GE Intelligent Platforms IMP3A + board. + + This board is a 3U CompactPCI Single Board Computer with a Freescale + P2020 processor. + config P2041_RDB bool "Freescale P2041 RDB" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 9cb2d4320dcc..2125d4ca068a 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_SBC8548) += sbc8548.o obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o obj-$(CONFIG_KSI8560) += ksi8560.o obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o +obj-$(CONFIG_GE_IMP3A) += ge_imp3a.o diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index 07e3e6c47371..df69e99e511c 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/arch/powerpc/platforms/85xx/corenet_ds.c @@ -36,8 +36,8 @@ void __init corenet_ds_pic_init(void) { struct mpic *mpic; - unsigned int flags = MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; + unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU | + MPIC_NO_RESET; if (ppc_md.get_irq == mpic_get_coreint_irq) flags |= MPIC_ENABLE_COREINT; diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c new file mode 100644 index 000000000000..d50056f424f6 --- /dev/null +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -0,0 +1,246 @@ +/* + * GE IMP3A Board Setup + * + * Author Martyn Welch <martyn.welch@ge.com> + * + * Copyright 2010 GE Intelligent Platforms Embedded Systems, Inc. + * + * 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. + * + * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup) + * Copyright 2007 Freescale Semiconductor Inc. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/of_platform.h> +#include <linux/memblock.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <mm/mmu_decl.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/mpic.h> +#include <asm/swiotlb.h> +#include <asm/nvram.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" +#include <sysdev/ge/ge_pic.h> + +void __iomem *imp3a_regs; + +void __init ge_imp3a_pic_init(void) +{ + struct mpic *mpic; + struct device_node *np; + struct device_node *cascade_node = NULL; + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { + mpic = mpic_alloc(NULL, 0, + MPIC_NO_RESET | + MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + } else { + mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + } + + BUG_ON(mpic == NULL); + mpic_init(mpic); + /* + * There is a simple interrupt handler in the main FPGA, this needs + * to be cascaded into the MPIC + */ + for_each_node_by_type(np, "interrupt-controller") + if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) { + cascade_node = np; + break; + } + + if (cascade_node == NULL) { + printk(KERN_WARNING "IMP3A: No FPGA PIC\n"); + return; + } + + gef_pic_init(cascade_node); + of_node_put(cascade_node); +} + +#ifdef CONFIG_PCI +static int primary_phb_addr; +#endif /* CONFIG_PCI */ + +/* + * Setup the architecture + */ +static void __init ge_imp3a_setup_arch(void) +{ + struct device_node *regs; +#ifdef CONFIG_PCI + struct device_node *np; + struct pci_controller *hose; +#endif + dma_addr_t max = 0xffffffff; + + if (ppc_md.progress) + ppc_md.progress("ge_imp3a_setup_arch()", 0); + +#ifdef CONFIG_PCI + for_each_node_by_type(np, "pci") { + if (of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie") || + of_device_is_compatible(np, "fsl,p2020-pcie")) { + struct resource rsrc; + of_address_to_resource(np, 0, &rsrc); + if ((rsrc.start & 0xfffff) == primary_phb_addr) + fsl_add_bridge(np, 1); + else + fsl_add_bridge(np, 0); + + hose = pci_find_hose_for_OF_device(np); + max = min(max, hose->dma_window_base_cur + + hose->dma_window_size); + } + } +#endif + + mpc85xx_smp_init(); + +#ifdef CONFIG_SWIOTLB + if (memblock_end_of_DRAM() > max) { + ppc_swiotlb_enable = 1; + set_pci_dma_ops(&swiotlb_dma_ops); + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + } +#endif + + /* Remap basic board registers */ + regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs"); + if (regs) { + imp3a_regs = of_iomap(regs, 0); + if (imp3a_regs == NULL) + printk(KERN_WARNING "Unable to map board registers\n"); + of_node_put(regs); + } + +#if defined(CONFIG_MMIO_NVRAM) + mmio_nvram_init(); +#endif + + printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n"); +} + +/* Return the PCB revision */ +static unsigned int ge_imp3a_get_pcb_rev(void) +{ + unsigned int reg; + + reg = ioread16(imp3a_regs); + return (reg >> 8) & 0xff; +} + +/* Return the board (software) revision */ +static unsigned int ge_imp3a_get_board_rev(void) +{ + unsigned int reg; + + reg = ioread16(imp3a_regs + 0x2); + return reg & 0xff; +} + +/* Return the FPGA revision */ +static unsigned int ge_imp3a_get_fpga_rev(void) +{ + unsigned int reg; + + reg = ioread16(imp3a_regs + 0x2); + return (reg >> 8) & 0xff; +} + +/* Return compactPCI Geographical Address */ +static unsigned int ge_imp3a_get_cpci_geo_addr(void) +{ + unsigned int reg; + + reg = ioread16(imp3a_regs + 0x6); + return (reg & 0x0f00) >> 8; +} + +/* Return compactPCI System Controller Status */ +static unsigned int ge_imp3a_get_cpci_is_syscon(void) +{ + unsigned int reg; + + reg = ioread16(imp3a_regs + 0x6); + return reg & (1 << 12); +} + +static void ge_imp3a_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); + + seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(), + ('A' + ge_imp3a_get_board_rev() - 1)); + + seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev()); + + seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr()); + + seq_printf(m, "cPCI syscon\t: %s\n", + ge_imp3a_get_cpci_is_syscon() ? "yes" : "no"); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init ge_imp3a_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "ge,IMP3A")) { +#ifdef CONFIG_PCI + primary_phb_addr = 0x9000; +#endif + return 1; + } + + return 0; +} + +machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices); + +machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier); + +define_machine(ge_imp3a) { + .name = "GE_IMP3A", + .probe = ge_imp3a_probe, + .setup_arch = ge_imp3a_setup_arch, + .init_IRQ = ge_imp3a_pic_init, + .show_cpuinfo = ge_imp3a_show_cpuinfo, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index 20f75d7819c6..60120e55da41 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -57,8 +57,7 @@ static void machine_restart(char *cmd) static void __init ksi8560_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index cf266826682e..f58872688d8f 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -36,9 +36,7 @@ void __init mpc8536_ds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 3bebb5173bfc..d19f675cb369 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -50,8 +50,7 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, static void __init mpc85xx_ads_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 40f03da616a9..ab5f0bf19454 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -3,7 +3,7 @@ * * Maintained by Kumar Gala (see MAINTAINERS for contact information) * - * Copyright 2005 Freescale Semiconductor Inc. + * Copyright 2005, 2011-2012 Freescale Semiconductor Inc. * * 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 @@ -48,17 +48,24 @@ #include "mpc85xx.h" -/* CADMUS info */ -/* xxx - galak, move into device tree */ -#define CADMUS_BASE (0xf8004000) -#define CADMUS_SIZE (256) -#define CM_VER (0) -#define CM_CSR (1) -#define CM_RST (2) - +/* + * The CDS board contains an FPGA/CPLD called "Cadmus", which collects + * various logic and performs system control functions. + * Here is the FPGA/CPLD register map. + */ +struct cadmus_reg { + u8 cm_ver; /* Board version */ + u8 cm_csr; /* General control/status */ + u8 cm_rst; /* Reset control */ + u8 cm_hsclk; /* High speed clock */ + u8 cm_hsxclk; /* High speed clock extended */ + u8 cm_led; /* LED data */ + u8 cm_pci; /* PCI control/status */ + u8 cm_dma; /* DMA control */ + u8 res[248]; /* Total 256 bytes */ +}; -static int cds_pci_slot = 2; -static volatile u8 *cadmus; +static struct cadmus_reg *cadmus; #ifdef CONFIG_PCI @@ -158,6 +165,33 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge); DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge); DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); +#define PCI_DEVICE_ID_IDT_TSI310 0x01a7 + +/* + * Fix Tsi310 PCI-X bridge resource. + * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space. + * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed. + */ +void mpc85xx_cds_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + struct resource *res = bus->resource[0]; + + if (dev != NULL && + dev->vendor == PCI_VENDOR_ID_IBM && + dev->device == PCI_DEVICE_ID_IDT_TSI310) { + if (res) { + res->start = 0; + res->end = 0x1fff; + res->flags = IORESOURCE_IO; + pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n"); + pr_info("mpc85xx_cds: %pR\n", res); + } + } + + fsl_pcibios_fixup_bus(bus); +} + #ifdef CONFIG_PPC_I8259 static void mpc85xx_8259_cascade_handler(unsigned int irq, struct irq_desc *desc) @@ -188,8 +222,7 @@ static struct irqaction mpc85xxcds_8259_irqaction = { static void __init mpc85xx_cds_pic_init(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); @@ -249,20 +282,30 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); */ static void __init mpc85xx_cds_setup_arch(void) { -#ifdef CONFIG_PCI struct device_node *np; -#endif + int cds_pci_slot; if (ppc_md.progress) ppc_md.progress("mpc85xx_cds_setup_arch()", 0); - cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); - cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; + np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga"); + if (!np) { + pr_err("Could not find FPGA node.\n"); + return; + } + + cadmus = of_iomap(np, 0); + of_node_put(np); + if (!cadmus) { + pr_err("Fail to map FPGA area.\n"); + return; + } if (ppc_md.progress) { char buf[40]; + cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1; snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", - cadmus[CM_VER], cds_pci_slot); + in_8(&cadmus->cm_ver), cds_pci_slot); ppc_md.progress(buf, 0); } @@ -292,7 +335,8 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) svid = mfspr(SPRN_SVR); seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]); + seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", + in_8(&cadmus->cm_ver)); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); @@ -323,7 +367,7 @@ define_machine(mpc85xx_cds) { .get_irq = mpic_get_irq, #ifdef CONFIG_PCI .restart = mpc85xx_cds_restart, - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, #else .restart = fsl_rstcr_restart, #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index eefbb91e1d61..6e23e3e34bd9 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -72,13 +72,13 @@ void __init mpc85xx_ds_pic_init(void) if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_NO_RESET | + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 1d15a0cd2c82..f33662b46b8d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,6 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved. + * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. + * All rights reserved. * * Author: Andy Fleming <afleming@freescale.com> * @@ -51,6 +52,7 @@ #include <asm/qe_ic.h> #include <asm/mpic.h> #include <asm/swiotlb.h> +#include <asm/fsl_guts.h> #include "smp.h" #include "mpc85xx.h" @@ -268,34 +270,27 @@ static void __init mpc85xx_mds_qe_init(void) mpc85xx_mds_reset_ucc_phys(); if (machine_is(p1021_mds)) { -#define MPC85xx_PMUXCR_OFFSET 0x60 -#define MPC85xx_PMUXCR_QE0 0x00008000 -#define MPC85xx_PMUXCR_QE3 0x00001000 -#define MPC85xx_PMUXCR_QE9 0x00000040 -#define MPC85xx_PMUXCR_QE12 0x00000008 - static __be32 __iomem *pmuxcr; - np = of_find_node_by_name(NULL, "global-utilities"); + struct ccsr_guts_85xx __iomem *guts; + np = of_find_node_by_name(NULL, "global-utilities"); if (np) { - pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET; - - if (!pmuxcr) - printk(KERN_EMERG "Error: Alternate function" - " signal multiplex control register not" - " mapped!\n"); - else + guts = of_iomap(np, 0); + if (!guts) + pr_err("mpc85xx-rdb: could not map global utilities register\n"); + else{ /* P1021 has pins muxed for QE and other functions. To * enable QE UEC mode, we need to set bit QE0 for UCC1 * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 * and QE12 for QE MII management signals in PMUXCR * register. */ - setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 | - MPC85xx_PMUXCR_QE3 | - MPC85xx_PMUXCR_QE9 | - MPC85xx_PMUXCR_QE12); - + setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | + MPC85xx_PMUXCR_QE(3) | + MPC85xx_PMUXCR_QE(9) | + MPC85xx_PMUXCR_QE(12)); + iounmap(guts); + } of_node_put(np); } @@ -434,9 +429,8 @@ machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier); static void __init mpc85xx_mds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index ccf520e890be..db214cd4c822 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -1,7 +1,7 @@ /* * MPC85xx RDB Board Setup * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009,2012 Freescale Semiconductor Inc. * * 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 @@ -26,6 +26,9 @@ #include <asm/prom.h> #include <asm/udbg.h> #include <asm/mpic.h> +#include <asm/qe.h> +#include <asm/qe_ic.h> +#include <asm/fsl_guts.h> #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> @@ -47,21 +50,36 @@ void __init mpc85xx_rdb_pic_init(void) struct mpic *mpic; unsigned long root = of_get_flat_dt_root(); +#ifdef CONFIG_QUICC_ENGINE + struct device_node *np; +#endif + if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) { - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET | + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } BUG_ON(mpic == NULL); mpic_init(mpic); + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); + if (np) { + qe_ic_init(np, 0, qe_ic_cascade_low_mpic, + qe_ic_cascade_high_mpic); + of_node_put(np); + + } else + pr_err("%s: Could not find qe-ic node\n", __func__); +#endif + } /* @@ -69,7 +87,7 @@ void __init mpc85xx_rdb_pic_init(void) */ static void __init mpc85xx_rdb_setup_arch(void) { -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE) struct device_node *np; #endif @@ -85,11 +103,73 @@ static void __init mpc85xx_rdb_setup_arch(void) #endif mpc85xx_smp_init(); + +#ifdef CONFIG_QUICC_ENGINE + np = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!np) { + pr_err("%s: Could not find Quicc Engine node\n", __func__); + goto qe_fail; + } + + qe_reset(); + of_node_put(np); + + np = of_find_node_by_name(NULL, "par_io"); + if (np) { + struct device_node *ucc; + + par_io_init(np); + of_node_put(np); + + for_each_node_by_name(ucc, "ucc") + par_io_of_config(ucc); + + } +#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) + if (machine_is(p1025_rdb)) { + + struct ccsr_guts_85xx __iomem *guts; + + np = of_find_node_by_name(NULL, "global-utilities"); + if (np) { + guts = of_iomap(np, 0); + if (!guts) { + + pr_err("mpc85xx-rdb: could not map global utilities register\n"); + + } else { + /* P1025 has pins muxed for QE and other functions. To + * enable QE UEC mode, we need to set bit QE0 for UCC1 + * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 + * and QE12 for QE MII management singals in PMUXCR + * register. + */ + setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | + MPC85xx_PMUXCR_QE(3) | + MPC85xx_PMUXCR_QE(9) | + MPC85xx_PMUXCR_QE(12)); + iounmap(guts); + } + of_node_put(np); + } + + } +#endif + +qe_fail: +#endif /* CONFIG_QUICC_ENGINE */ + printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); } machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); +machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices); machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened @@ -112,6 +192,52 @@ static int __init p1020_rdb_probe(void) return 0; } +static int __init p1020_rdb_pc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,P1020RDB-PC"); +} + +static int __init p1021_rdb_pc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,P1021RDB-PC")) + return 1; + return 0; +} + +static int __init p2020_rdb_pc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC")) + return 1; + return 0; +} + +static int __init p1025_rdb_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,P1025RDB"); +} + +static int __init p1020_mbg_pc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,P1020MBG-PC"); +} + +static int __init p1020_utm_pc_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC"); +} + define_machine(p2020_rdb) { .name = "P2020 RDB", .probe = p2020_rdb_probe, @@ -139,3 +265,87 @@ define_machine(p1020_rdb) { .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; + +define_machine(p1021_rdb_pc) { + .name = "P1021 RDB-PC", + .probe = p1021_rdb_pc_probe, + .setup_arch = mpc85xx_rdb_setup_arch, + .init_IRQ = mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; + +define_machine(p2020_rdb_pc) { + .name = "P2020RDB-PC", + .probe = p2020_rdb_pc_probe, + .setup_arch = mpc85xx_rdb_setup_arch, + .init_IRQ = mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; + +define_machine(p1025_rdb) { + .name = "P1025 RDB", + .probe = p1025_rdb_probe, + .setup_arch = mpc85xx_rdb_setup_arch, + .init_IRQ = mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; + +define_machine(p1020_mbg_pc) { + .name = "P1020 MBG-PC", + .probe = p1020_mbg_pc_probe, + .setup_arch = mpc85xx_rdb_setup_arch, + .init_IRQ = mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; + +define_machine(p1020_utm_pc) { + .name = "P1020 UTM-PC", + .probe = p1020_utm_pc_probe, + .setup_arch = mpc85xx_rdb_setup_arch, + .init_IRQ = mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; + +define_machine(p1020_rdb_pc) { + .name = "P1020RDB-PC", + .probe = p1020_rdb_pc_probe, + .setup_arch = mpc85xx_rdb_setup_arch, + .init_IRQ = mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 538bc3f57e9d..d8bd6563d9ca 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -32,9 +32,8 @@ void __init p1010_rdb_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index b0984ada3f83..0fe88e39945e 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -33,6 +33,10 @@ #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) +#define PMUXCR_ELBCDIU_MASK 0xc0000000 +#define PMUXCR_ELBCDIU_NOR16 0x80000000 +#define PMUXCR_ELBCDIU_DIU 0x40000000 + /* * Board-specific initialization of the DIU. This code should probably be * executed when the DIU is opened, rather than in arch code, but the DIU @@ -50,11 +54,22 @@ #define CLKDVDR_PXCLK_MASK 0x00FF0000 /* Some ngPIXIS register definitions */ +#define PX_CTL 3 +#define PX_BRDCFG0 8 +#define PX_BRDCFG1 9 + +#define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 +#define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 +#define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 +#define PX_BRDCFG0_ELBC_DIU 0x02 + #define PX_BRDCFG1_DVIEN 0x80 #define PX_BRDCFG1_DFPEN 0x40 #define PX_BRDCFG1_BACKLIGHT 0x20 #define PX_BRDCFG1_DDCEN 0x10 +#define PX_CTL_ALTACC 0x80 + /* * DIU Area Descriptor * @@ -133,44 +148,117 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, */ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) { - struct device_node *np; - void __iomem *pixis; - u8 __iomem *brdcfg1; - - np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); - if (!np) - /* older device trees used "fsl,p1022ds-pixis" */ - np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis"); - if (!np) { - pr_err("p1022ds: missing ngPIXIS node\n"); + struct device_node *guts_node; + struct device_node *indirect_node = NULL; + struct ccsr_guts_85xx __iomem *guts; + u8 __iomem *lbc_lcs0_ba = NULL; + u8 __iomem *lbc_lcs1_ba = NULL; + u8 b; + + /* Map the global utilities registers. */ + guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); + if (!guts_node) { + pr_err("p1022ds: missing global utilties device node\n"); return; } - pixis = of_iomap(np, 0); - if (!pixis) { - pr_err("p1022ds: could not map ngPIXIS registers\n"); - return; + guts = of_iomap(guts_node, 0); + if (!guts) { + pr_err("p1022ds: could not map global utilties device\n"); + goto exit; } - brdcfg1 = pixis + 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */ + + indirect_node = of_find_compatible_node(NULL, NULL, + "fsl,p1022ds-indirect-pixis"); + if (!indirect_node) { + pr_err("p1022ds: missing pixis indirect mode node\n"); + goto exit; + } + + lbc_lcs0_ba = of_iomap(indirect_node, 0); + if (!lbc_lcs0_ba) { + pr_err("p1022ds: could not map localbus chip select 0\n"); + goto exit; + } + + lbc_lcs1_ba = of_iomap(indirect_node, 1); + if (!lbc_lcs1_ba) { + pr_err("p1022ds: could not map localbus chip select 1\n"); + goto exit; + } + + /* Make sure we're in indirect mode first. */ + if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != + PMUXCR_ELBCDIU_DIU) { + struct device_node *pixis_node; + void __iomem *pixis; + + pixis_node = + of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); + if (!pixis_node) { + pr_err("p1022ds: missing pixis node\n"); + goto exit; + } + + pixis = of_iomap(pixis_node, 0); + of_node_put(pixis_node); + if (!pixis) { + pr_err("p1022ds: could not map pixis registers\n"); + goto exit; + } + + /* Enable indirect PIXIS mode. */ + setbits8(pixis + PX_CTL, PX_CTL_ALTACC); + iounmap(pixis); + + /* Switch the board mux to the DIU */ + out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ + b = in_8(lbc_lcs1_ba); + b |= PX_BRDCFG0_ELBC_DIU; + out_8(lbc_lcs1_ba, b); + + /* Set the chip mux to DIU mode. */ + clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, + PMUXCR_ELBCDIU_DIU); + in_be32(&guts->pmuxcr); + } + switch (port) { case FSL_DIU_PORT_DVI: - printk(KERN_INFO "%s:%u\n", __func__, __LINE__); /* Enable the DVI port, disable the DFP and the backlight */ - clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, - PX_BRDCFG1_DVIEN); + out_8(lbc_lcs0_ba, PX_BRDCFG1); + b = in_8(lbc_lcs1_ba); + b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); + b |= PX_BRDCFG1_DVIEN; + out_8(lbc_lcs1_ba, b); break; case FSL_DIU_PORT_LVDS: - printk(KERN_INFO "%s:%u\n", __func__, __LINE__); + /* + * LVDS also needs backlight enabled, otherwise the display + * will be blank. + */ /* Enable the DFP port, disable the DVI and the backlight */ - clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, - PX_BRDCFG1_DFPEN); + out_8(lbc_lcs0_ba, PX_BRDCFG1); + b = in_8(lbc_lcs1_ba); + b &= ~PX_BRDCFG1_DVIEN; + b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; + out_8(lbc_lcs1_ba, b); break; default: pr_err("p1022ds: unsupported monitor port %i\n", port); } - iounmap(pixis); +exit: + if (lbc_lcs1_ba) + iounmap(lbc_lcs1_ba); + if (lbc_lcs0_ba) + iounmap(lbc_lcs0_ba); + if (guts) + iounmap(guts); + + of_node_put(indirect_node); + of_node_put(guts_node); } /** @@ -242,15 +330,56 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) void __init p1022_ds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); } +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + +/* + * Disables a node in the device tree. + * + * This function is called before kmalloc() is available, so the 'new' object + * should be allocated in the global area. The easiest way is to do that is + * to allocate one static local variable for each call to this function. + */ +static void __init disable_one_node(struct device_node *np, struct property *new) +{ + struct property *old; + + old = of_find_property(np, new->name, NULL); + if (old) + prom_update_property(np, new, old); + else + prom_add_property(np, new); +} + +/* TRUE if there is a "video=fslfb" command-line parameter. */ +static bool fslfb; + +/* + * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to + * true if we find it. + * + * We need to use early_param() instead of __setup() because the normal + * __setup() gets called to late. However, early_param() gets called very + * early, before the device tree is unflattened, so all we can do now is set a + * global variable. Later on, p1022_ds_setup_arch() will use that variable + * to determine if we need to update the device tree. + */ +static int __init early_video_setup(char *options) +{ + fslfb = (strncmp(options, "fslfb:", 6) == 0); + + return 0; +} +early_param("video", early_video_setup); + +#endif + /* * Setup the architecture */ @@ -288,6 +417,34 @@ static void __init p1022_ds_setup_arch(void) diu_ops.set_monitor_port = p1022ds_set_monitor_port; diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; + + /* + * Disable the NOR flash node if there is video=fslfb... command-line + * parameter. When the DIU is active, NOR flash is unavailable, so we + * have to disable the node before the MTD driver loads. + */ + if (fslfb) { + struct device_node *np = + of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); + + if (np) { + np = of_find_compatible_node(np, NULL, "cfi-flash"); + if (np) { + static struct property nor_status = { + .name = "status", + .value = "disabled", + .length = sizeof("disabled"), + }; + + pr_info("p1022ds: disabling %s node", + np->full_name); + disable_one_node(np, &nor_status); + of_node_put(np); + } + } + + } + #endif mpc85xx_smp_init(); diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index d951e7027bb6..6b07398e4369 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c @@ -93,9 +93,8 @@ machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices); static void __init mpc85xx_rds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index 184a50784617..1677b8a22677 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -54,8 +54,7 @@ static int sbc_rev; static void __init sbc8548_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index 940752e93051..3c3bbcc27566 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c @@ -41,8 +41,7 @@ static void __init sbc8560_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index 18f635906b27..b71919217756 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -48,8 +48,7 @@ static void __init socrates_pic_init(void) { struct device_node *np; - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 12cb9bb2cc68..3bbbf7489487 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = { static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock); static void __iomem *socrates_fpga_pic_iobase; -static struct irq_host *socrates_fpga_pic_irq_host; +static struct irq_domain *socrates_fpga_pic_irq_host; static unsigned int socrates_fpga_irqs[3]; static inline uint32_t socrates_fpga_pic_read(int reg) @@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = { .irq_set_type = socrates_fpga_pic_set_type, }; -static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, +static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { /* All interrupts are LEVEL sensitive */ @@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int socrates_fpga_pic_host_xlate(struct irq_host *h, +static int socrates_fpga_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h, return 0; } -static struct irq_host_ops socrates_fpga_pic_host_ops = { +static const struct irq_domain_ops socrates_fpga_pic_host_ops = { .map = socrates_fpga_pic_host_map, .xlate = socrates_fpga_pic_host_xlate, }; @@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic) unsigned long flags; int i; - /* Setup an irq_host structure */ - socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR, - SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, - SOCRATES_FPGA_NUM_IRQS); + /* Setup an irq_domain structure */ + socrates_fpga_pic_irq_host = irq_domain_add_linear(pic, + SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL); if (socrates_fpga_pic_irq_host == NULL) { pr_err("FPGA PIC: Unable to allocate host\n"); return; diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index e9e5234b4e76..27ca3a7b04ab 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -48,8 +48,7 @@ static void __init stx_gp3_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index bf7c89fb75bb..d7504cefe016 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -47,7 +47,7 @@ static void __init tqm85xx_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 3a69f8b77de6..503c21596c63 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -43,9 +43,7 @@ void __init xes_mpc85xx_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 8d6599d54ea6..7a6279e38213 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -39,6 +39,7 @@ config GEF_PPC9A select MMIO_NVRAM select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB + select GE_FPGA help This option enables support for the GE PPC9A. @@ -48,6 +49,7 @@ config GEF_SBC310 select MMIO_NVRAM select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB + select GE_FPGA help This option enables support for the GE SBC310. @@ -57,6 +59,7 @@ config GEF_SBC610 select MMIO_NVRAM select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB + select GE_FPGA select HAS_RAPIDIO help This option enables support for the GE SBC610. diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 4b0d7b1aa005..ede815d6489d 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o obj-$(CONFIG_SBC8641D) += sbc8641d.o obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o -gef-gpio-$(CONFIG_GPIOLIB) += gef_gpio.o -obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o $(gef-gpio-y) -obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o gef_pic.o $(gef-gpio-y) -obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o gef_pic.o $(gef-gpio-y) +obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o +obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o +obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c deleted file mode 100644 index 2a703365e664..000000000000 --- a/arch/powerpc/platforms/86xx/gef_gpio.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Driver for GE FPGA based GPIO - * - * Author: Martyn Welch <martyn.welch@ge.com> - * - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -/* TODO - * - * Configuration of output modes (totem-pole/open-drain) - * Interrupt configuration - interrupts are always generated the FPGA relies on - * the I/O interrupt controllers mask to stop them propergating - */ - -#include <linux/kernel.h> -#include <linux/compiler.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_platform.h> -#include <linux/of_gpio.h> -#include <linux/gpio.h> -#include <linux/slab.h> -#include <linux/module.h> - -#define GEF_GPIO_DIRECT 0x00 -#define GEF_GPIO_IN 0x04 -#define GEF_GPIO_OUT 0x08 -#define GEF_GPIO_TRIG 0x0C -#define GEF_GPIO_POLAR_A 0x10 -#define GEF_GPIO_POLAR_B 0x14 -#define GEF_GPIO_INT_STAT 0x18 -#define GEF_GPIO_OVERRUN 0x1C -#define GEF_GPIO_MODE 0x20 - -static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) -{ - unsigned int data; - - data = ioread32be(reg); - /* value: 0=low; 1=high */ - if (value & 0x1) - data = data | (0x1 << offset); - else - data = data & ~(0x1 << offset); - - iowrite32be(data, reg); -} - - -static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | (0x1 << offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) -{ - unsigned int data; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - /* Set direction before switching to input */ - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); - - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~(0x1 << offset); - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - - return 0; -} - -static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - unsigned int data; - int state = 0; - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - data = ioread32be(mmchip->regs + GEF_GPIO_IN); - state = (int)((data >> offset) & 0x1); - - return state; -} - -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); -} - -static int __init gef_gpio_init(void) -{ - struct device_node *np; - int retval; - struct of_mm_gpio_chip *gef_gpio_chip; - - for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 19; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 6; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - return 0; -}; -arch_initcall(gef_gpio_init); - -MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); -MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); -MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 60ce07e39100..ed58b6cfd60c 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -37,9 +37,9 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 3ecee25bf3ed..710db69bd523 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -37,9 +37,9 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 5090d608d9ee..4a13d2f4ac20 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -37,9 +37,9 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 52bbfa031531..22cc3571ae19 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c @@ -37,9 +37,8 @@ void __init mpc86xx_init_irq(void) int cascade_irq; #endif - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " MPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index ee56a9ea6a79..1fb0b3cddeb3 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -26,6 +26,7 @@ config MPC86XADS config MPC885ADS bool "MPC885ADS" select CPM1 + select OF_DYNAMIC help Freescale Semiconductor MPC885 Application Development System (ADS). Also known as DUET. diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 0cfb46d54b8c..a35ca44ade66 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -2,7 +2,6 @@ menu "Platform support" source "arch/powerpc/platforms/powernv/Kconfig" source "arch/powerpc/platforms/pseries/Kconfig" -source "arch/powerpc/platforms/iseries/Kconfig" source "arch/powerpc/platforms/chrp/Kconfig" source "arch/powerpc/platforms/512x/Kconfig" source "arch/powerpc/platforms/52xx/Kconfig" @@ -87,6 +86,14 @@ config MPIC_WEIRD bool default n +config MPIC_MSGR + bool "MPIC message register support" + depends on MPIC + default n + help + Enables support for the MPIC message registers. These + registers are used for inter-processor communication. + config PPC_I8259 bool default n @@ -138,7 +145,7 @@ config MPIC_BROKEN_REGREAD of the register contents in software. config IBMVIO - depends on PPC_PSERIES || PPC_ISERIES + depends on PPC_PSERIES bool default y diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 2635a22bade2..879b4a448498 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_FSL_SOC_BOOKE) += 85xx/ obj-$(CONFIG_PPC_86xx) += 86xx/ obj-$(CONFIG_PPC_POWERNV) += powernv/ obj-$(CONFIG_PPC_PSERIES) += pseries/ -obj-$(CONFIG_PPC_ISERIES) += iseries/ obj-$(CONFIG_PPC_MAPLE) += maple/ obj-$(CONFIG_PPC_PASEMI) += pasemi/ obj-$(CONFIG_PPC_CELL) += cell/ diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 40a6e34793b4..db360fc4cf0e 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -67,7 +67,7 @@ struct axon_msic { - struct irq_host *irq_host; + struct irq_domain *irq_domain; __le32 *fifo_virt; dma_addr_t fifo_phys; dcr_host_t dcr_host; @@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) static struct axon_msic *find_msi_translator(struct pci_dev *dev) { - struct irq_host *irq_host; + struct irq_domain *irq_domain; struct device_node *dn, *tmp; const phandle *ph; struct axon_msic *msic = NULL; @@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) goto out_error; } - irq_host = irq_find_host(dn); - if (!irq_host) { - dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n", + irq_domain = irq_find_host(dn); + if (!irq_domain) { + dev_dbg(&dev->dev, "axon_msi: no irq_domain found for node %s\n", dn->full_name); goto out_error; } - msic = irq_host->host_data; + msic = irq_domain->host_data; out_error: of_node_put(dn); @@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) BUILD_BUG_ON(NR_IRQS > 65536); list_for_each_entry(entry, &dev->msi_list, list) { - virq = irq_create_direct_mapping(msic->irq_host); + virq = irq_create_direct_mapping(msic->irq_domain); if (virq == NO_IRQ) { dev_warn(&dev->dev, "axon_msi: virq allocation failed!\n"); @@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = { .name = "AXON-MSI", }; -static int msic_host_map(struct irq_host *h, unsigned int virq, +static int msic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_data(virq, h->host_data); @@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops msic_host_ops = { +static const struct irq_domain_ops msic_host_ops = { .map = msic_host_map, }; @@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device) u32 tmp; pr_devel("axon_msi: disabling %s\n", - msic->irq_host->of_node->full_name); + msic->irq_domain->of_node->full_name); tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; msic_dcr_write(msic, MSIC_CTRL_REG, tmp); @@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device) } memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES); - msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP, - NR_IRQS, &msic_host_ops, 0); - if (!msic->irq_host) { - printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", + msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic); + if (!msic->irq_domain) { + printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n", dn->full_name); goto out_free_fifo; } - msic->irq_host->host_data = msic; - irq_set_handler_data(virq, msic); irq_set_chained_handler(virq, axon_msi_cascade); pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq); diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 55015e1f6939..e5c3a2c6090d 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock); static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64]; -static struct irq_host *beatic_host; +static struct irq_domain *beatic_host; /* * In this implementation, "virq" == "IRQ plug number", @@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = { * * Note that the number (virq) is already assigned at upper layer. */ -static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) +static void beatic_pic_host_unmap(struct irq_domain *h, unsigned int virq) { beat_destruct_irq_plug(virq); } @@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) * * Note that the number (virq) is already assigned at upper layer. */ -static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, +static int beatic_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { int64_t err; @@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, * Called from irq_create_of_mapping() only. * Note: We have only 1 entry to translate. */ -static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int beatic_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) +static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np) { /* Match all */ return 1; } -static struct irq_host_ops beatic_pic_host_ops = { +static const struct irq_domain_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, @@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void) ppc_md.get_irq = beatic_get_irq; /* Allocate an irq host */ - beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &beatic_pic_host_ops, - 0); + beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL); BUG_ON(beatic_host == NULL); irq_set_default_host(beatic_host); } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 96a433dd2d64..2d42f3bb66d6 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -56,7 +56,7 @@ struct iic { static DEFINE_PER_CPU(struct iic, cpu_iic); #define IIC_NODE_COUNT 2 -static struct irq_host *iic_host; +static struct irq_domain *iic_host; /* Convert between "pending" bits and hw irq number */ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) @@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg) out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4); } -struct irq_host *iic_get_irq_host(int node) +struct irq_domain *iic_get_irq_host(int node) { return iic_host; } @@ -222,13 +222,13 @@ void iic_request_IPIs(void) #endif /* CONFIG_SMP */ -static int iic_host_match(struct irq_host *h, struct device_node *node) +static int iic_host_match(struct irq_domain *h, struct device_node *node) { return of_device_is_compatible(node, "IBM,CBEA-Internal-Interrupt-Controller"); } -static int iic_host_map(struct irq_host *h, unsigned int virq, +static int iic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { switch (hw & IIC_IRQ_TYPE_MASK) { @@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int iic_host_xlate(struct irq_host *h, struct device_node *ct, +static int iic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops iic_host_ops = { +static const struct irq_domain_ops iic_host_ops = { .match = iic_host_match, .map = iic_host_map, .xlate = iic_host_xlate, @@ -378,8 +378,8 @@ static int __init setup_iic(void) void __init iic_init_IRQ(void) { /* Setup an irq host data structure */ - iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, - &iic_host_ops, IIC_IRQ_INVALID); + iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops, + NULL); BUG_ON(iic_host == NULL); irq_set_default_host(iic_host); diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 62002a7edfed..fa3e294fd343 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -197,7 +197,8 @@ static void __init mpic_init_IRQ(void) /* The MPIC driver will get everything it needs from the * device-tree, just pass 0 to all arguments */ - mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC "); + mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET, + 0, 0, " MPIC "); if (mpic == NULL) continue; mpic_init(mpic); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 442c28c00f88..d8b7cc8a66ca 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -62,7 +62,7 @@ enum { #define SPIDER_IRQ_INVALID 63 struct spider_pic { - struct irq_host *host; + struct irq_domain *host; void __iomem *regs; unsigned int node_id; }; @@ -168,7 +168,7 @@ static struct irq_chip spider_pic = { .irq_set_type = spider_set_irq_type, }; -static int spider_host_map(struct irq_host *h, unsigned int virq, +static int spider_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_data(virq, h->host_data); @@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int spider_host_xlate(struct irq_host *h, struct device_node *ct, +static int spider_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops spider_host_ops = { +static const struct irq_domain_ops spider_host_ops = { .map = spider_host_map, .xlate = spider_host_xlate, }; @@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip, panic("spider_pic: can't map registers !"); /* Allocate a host */ - pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR, - SPIDER_SRC_COUNT, &spider_host_ops, - SPIDER_IRQ_INVALID); + pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT, + &spider_host_ops, pic); if (pic->host == NULL) panic("spider_pic: can't allocate irq host !"); - pic->host->host_data = pic; /* Go through all sources and disable them */ for (i = 0; i < SPIDER_SRC_COUNT; i++) { diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d4a094ca96f3..1d75c92ea8fb 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -646,6 +646,7 @@ long spufs_create(struct path *path, struct dentry *dentry, out: mutex_unlock(&path->dentry->d_inode->i_mutex); + dput(dentry); return ret; } @@ -757,9 +758,9 @@ spufs_create_root(struct super_block *sb, void *data) goto out_iput; ret = -ENOMEM; - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) - goto out_iput; + goto out; return 0; out_iput: @@ -828,19 +829,19 @@ static int __init spufs_init(void) ret = spu_sched_init(); if (ret) goto out_cache; - ret = register_filesystem(&spufs_type); + ret = register_spu_syscalls(&spufs_calls); if (ret) goto out_sched; - ret = register_spu_syscalls(&spufs_calls); + ret = register_filesystem(&spufs_type); if (ret) - goto out_fs; + goto out_syscalls; spufs_init_isolated_loader(); return 0; -out_fs: - unregister_filesystem(&spufs_type); +out_syscalls: + unregister_spu_syscalls(&spufs_calls); out_sched: spu_sched_exit(); out_cache: diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 8591bb62d7fc..5665dcc382c7 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -70,8 +70,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, ret = PTR_ERR(dentry); if (!IS_ERR(dentry)) { ret = spufs_create(&path, dentry, flags, mode, neighbor); - mutex_unlock(&path.dentry->d_inode->i_mutex); - dput(dentry); path_put(&path); } diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index f1f17bb2c33c..c665d7de6c99 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -435,7 +435,8 @@ static void __init chrp_find_openpic(void) if (len > 1) isu_size = iranges[3]; - chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC "); + chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET, + isu_size, 0, " MPIC "); if (chrp_mpic == NULL) { printk(KERN_ERR "Failed to allocate MPIC structure\n"); goto bail; diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index f61a2dd96b99..53d6eee01963 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = { * */ -static struct irq_host *flipper_irq_host; +static struct irq_domain *flipper_irq_host; -static int flipper_pic_map(struct irq_host *h, unsigned int virq, +static int flipper_pic_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { irq_set_chip_data(virq, h->host_data); @@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static int flipper_pic_match(struct irq_host *h, struct device_node *np) +static int flipper_pic_match(struct irq_domain *h, struct device_node *np) { return 1; } -static struct irq_host_ops flipper_irq_host_ops = { +static const struct irq_domain_ops flipper_irq_domain_ops = { .map = flipper_pic_map, .match = flipper_pic_match, }; @@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base) out_be32(io_base + FLIPPER_ICR, 0xffffffff); } -struct irq_host * __init flipper_pic_init(struct device_node *np) +struct irq_domain * __init flipper_pic_init(struct device_node *np) { struct device_node *pi; - struct irq_host *irq_host = NULL; + struct irq_domain *irq_domain = NULL; struct resource res; void __iomem *io_base; int retval; @@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np) __flipper_quiesce(io_base); - irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, - &flipper_irq_host_ops, -1); - if (!irq_host) { - pr_err("failed to allocate irq_host\n"); + irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS, + &flipper_irq_domain_ops, io_base); + if (!irq_domain) { + pr_err("failed to allocate irq_domain\n"); return NULL; } - irq_host->host_data = io_base; - out: - return irq_host; + return irq_domain; } unsigned int flipper_pic_get_irq(void) diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index e4919170c6bc..3006b5117ec6 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = { * */ -static struct irq_host *hlwd_irq_host; +static struct irq_domain *hlwd_irq_host; -static int hlwd_pic_map(struct irq_host *h, unsigned int virq, +static int hlwd_pic_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { irq_set_chip_data(virq, h->host_data); @@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops hlwd_irq_host_ops = { +static const struct irq_domain_ops hlwd_irq_domain_ops = { .map = hlwd_pic_map, }; -static unsigned int __hlwd_pic_get_irq(struct irq_host *h) +static unsigned int __hlwd_pic_get_irq(struct irq_domain *h) { void __iomem *io_base = h->host_data; int irq; @@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); - struct irq_host *irq_host = irq_get_handler_data(cascade_virq); + struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq); unsigned int virq; raw_spin_lock(&desc->lock); chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */ raw_spin_unlock(&desc->lock); - virq = __hlwd_pic_get_irq(irq_host); + virq = __hlwd_pic_get_irq(irq_domain); if (virq != NO_IRQ) generic_handle_irq(virq); else @@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base) out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff); } -struct irq_host *hlwd_pic_init(struct device_node *np) +struct irq_domain *hlwd_pic_init(struct device_node *np) { - struct irq_host *irq_host; + struct irq_domain *irq_domain; struct resource res; void __iomem *io_base; int retval; @@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np) __hlwd_quiesce(io_base); - irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS, - &hlwd_irq_host_ops, -1); - if (!irq_host) { - pr_err("failed to allocate irq_host\n"); + irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS, + &hlwd_irq_domain_ops, io_base); + if (!irq_domain) { + pr_err("failed to allocate irq_domain\n"); return NULL; } - irq_host->host_data = io_base; - return irq_host; + return irq_domain; } unsigned int hlwd_pic_get_irq(void) @@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void) void hlwd_pic_probe(void) { - struct irq_host *host; + struct irq_domain *host; struct device_node *np; const u32 *interrupts; int cascade_virq; diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 9cfcf20c0560..ab51b21b4bd7 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -154,11 +154,9 @@ static void __init holly_init_IRQ(void) struct device_node *cascade_node = NULL; #endif - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, - NR_IRQS-4, /* num_sources used */ + 24, 0, "Tsi108_PIC"); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index bcfad92c9cec..455e7c087422 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -82,8 +82,7 @@ static void __init linkstation_init_IRQ(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, - 4, 32, " EPIC "); + mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC "); BUG_ON(mpic == NULL); /* PCI IRQs */ diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index f3350d786f5b..74ccce36baed 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -108,11 +108,9 @@ static void __init mpc7448_hpc2_init_IRQ(void) struct device_node *cascade_node = NULL; #endif - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, - NR_IRQS-4, /* num_sources used */ + 24, 0, "Tsi108_PIC"); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index afa638834965..e0ed3c71d69b 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -84,8 +84,7 @@ static void __init storcenter_init_IRQ(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, - 16, 32, " OpenPIC "); + mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC "); BUG_ON(mpic == NULL); /* diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig deleted file mode 100644 index b57cda3a0817..000000000000 --- a/arch/powerpc/platforms/iseries/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config PPC_ISERIES - bool "IBM Legacy iSeries" - depends on PPC64 && PPC_BOOK3S - select PPC_SMP_MUXED_IPI - select PPC_INDIRECT_PIO - select PPC_INDIRECT_MMIO - select PPC_PCI_CHOICE if EXPERT - -menu "iSeries device drivers" - depends on PPC_ISERIES - -config VIODASD - tristate "iSeries Virtual I/O disk support" - depends on BLOCK - select VIOPATH - help - If you are running on an iSeries system and you want to use - virtual disks created and managed by OS/400, say Y. - -config VIOCD - tristate "iSeries Virtual I/O CD support" - depends on BLOCK - select VIOPATH - help - If you are running Linux on an IBM iSeries system and you want to - read a CD drive owned by OS/400, say Y here. - -config VIOTAPE - tristate "iSeries Virtual Tape Support" - select VIOPATH - help - If you are running Linux on an iSeries system and you want Linux - to read and/or write a tape drive owned by OS/400, say Y here. - -endmenu - -config VIOPATH - bool diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile deleted file mode 100644 index a7602b11ed9d..000000000000 --- a/arch/powerpc/platforms/iseries/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -ccflags-y := -mno-minimal-toc - -obj-y += exception.o -obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \ - hvcall.o proc.o htab.o iommu.o misc.o irq.o -obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_VIOPATH) += viopath.o vio.o -obj-$(CONFIG_MODULES) += ksyms.o diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h deleted file mode 100644 index 8d95fe4b554e..000000000000 --- a/arch/powerpc/platforms/iseries/call_hpt.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _PLATFORMS_ISERIES_CALL_HPT_H -#define _PLATFORMS_ISERIES_CALL_HPT_H - -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/mmu.h> - -#define HvCallHptGetHptAddress HvCallHpt + 0 -#define HvCallHptGetHptPages HvCallHpt + 1 -#define HvCallHptSetPp HvCallHpt + 5 -#define HvCallHptSetSwBits HvCallHpt + 6 -#define HvCallHptUpdate HvCallHpt + 7 -#define HvCallHptInvalidateNoSyncICache HvCallHpt + 8 -#define HvCallHptGet HvCallHpt + 11 -#define HvCallHptFindNextValid HvCallHpt + 12 -#define HvCallHptFindValid HvCallHpt + 13 -#define HvCallHptAddValidate HvCallHpt + 16 -#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18 - - -static inline u64 HvCallHpt_getHptAddress(void) -{ - return HvCall0(HvCallHptGetHptAddress); -} - -static inline u64 HvCallHpt_getHptPages(void) -{ - return HvCall0(HvCallHptGetHptPages); -} - -static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) -{ - HvCall2(HvCallHptSetPp, hpteIndex, value); -} - -static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) -{ - HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); -} - -static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) -{ - HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); -} - -static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, - u8 bitsoff) -{ - u64 compressedStatus; - - compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, - hpteIndex, bitson, bitsoff, 1); - HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); - return compressedStatus; -} - -static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn) -{ - return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); -} - -static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex, - u8 bitson, u8 bitsoff) -{ - return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, - bitson, bitsoff); -} - -static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex) -{ - HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); -} - -static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, - struct hash_pte *hpte) -{ - HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); -} - -#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */ diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h deleted file mode 100644 index dbdf69850ed9..000000000000 --- a/arch/powerpc/platforms/iseries/call_pci.h +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Provides the Hypervisor PCI calls for iSeries Linux Parition. - * Copyright (C) 2001 <Wayne G Holm> <IBM 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., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - * - * Change Activity: - * Created, Jan 9, 2001 - */ - -#ifndef _PLATFORMS_ISERIES_CALL_PCI_H -#define _PLATFORMS_ISERIES_CALL_PCI_H - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -/* - * DSA == Direct Select Address - * this struct must be 64 bits in total - */ -struct HvCallPci_DsaAddr { - u16 busNumber; /* PHB index? */ - u8 subBusNumber; /* PCI bus number? */ - u8 deviceId; /* device and function? */ - u8 barNumber; - u8 reserved[3]; -}; - -union HvDsaMap { - u64 DsaAddr; - struct HvCallPci_DsaAddr Dsa; -}; - -struct HvCallPci_LoadReturn { - u64 rc; - u64 value; -}; - -enum HvCallPci_DeviceType { - HvCallPci_NodeDevice = 1, - HvCallPci_SpDevice = 2, - HvCallPci_IopDevice = 3, - HvCallPci_BridgeDevice = 4, - HvCallPci_MultiFunctionDevice = 5, - HvCallPci_IoaDevice = 6 -}; - - -struct HvCallPci_DeviceInfo { - u32 deviceType; /* See DeviceType enum for values */ -}; - -struct HvCallPci_BusUnitInfo { - u32 sizeReturned; /* length of data returned */ - u32 deviceType; /* see DeviceType enum for values */ -}; - -struct HvCallPci_BridgeInfo { - struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */ - u8 subBusNumber; /* Bus number of secondary bus */ - u8 maxAgents; /* Max idsels on secondary bus */ - u8 maxSubBusNumber; /* Max Sub Bus */ - u8 logicalSlotNumber; /* Logical Slot Number for IOA */ -}; - - -/* - * Maximum BusUnitInfo buffer size. Provided for clients so - * they can allocate a buffer big enough for any type of bus - * unit. Increase as needed. - */ -enum {HvCallPci_MaxBusUnitInfoSize = 128}; - -struct HvCallPci_BarParms { - u64 vaddr; - u64 raddr; - u64 size; - u64 protectStart; - u64 protectEnd; - u64 relocationOffset; - u64 pciAddress; - u64 reserved[3]; -}; - -enum HvCallPci_VpdType { - HvCallPci_BusVpd = 1, - HvCallPci_BusAdapterVpd = 2 -}; - -#define HvCallPciConfigLoad8 HvCallPci + 0 -#define HvCallPciConfigLoad16 HvCallPci + 1 -#define HvCallPciConfigLoad32 HvCallPci + 2 -#define HvCallPciConfigStore8 HvCallPci + 3 -#define HvCallPciConfigStore16 HvCallPci + 4 -#define HvCallPciConfigStore32 HvCallPci + 5 -#define HvCallPciEoi HvCallPci + 16 -#define HvCallPciGetBarParms HvCallPci + 18 -#define HvCallPciMaskFisr HvCallPci + 20 -#define HvCallPciUnmaskFisr HvCallPci + 21 -#define HvCallPciSetSlotReset HvCallPci + 25 -#define HvCallPciGetDeviceInfo HvCallPci + 27 -#define HvCallPciGetCardVpd HvCallPci + 28 -#define HvCallPciBarLoad8 HvCallPci + 40 -#define HvCallPciBarLoad16 HvCallPci + 41 -#define HvCallPciBarLoad32 HvCallPci + 42 -#define HvCallPciBarLoad64 HvCallPci + 43 -#define HvCallPciBarStore8 HvCallPci + 44 -#define HvCallPciBarStore16 HvCallPci + 45 -#define HvCallPciBarStore32 HvCallPci + 46 -#define HvCallPciBarStore64 HvCallPci + 47 -#define HvCallPciMaskInterrupts HvCallPci + 48 -#define HvCallPciUnmaskInterrupts HvCallPci + 49 -#define HvCallPciGetBusUnitInfo HvCallPci + 50 - -static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u16 *value) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0); - - *value = retVal.value; - - return retVal.rc; -} - -static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u32 *value) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0); - - *value = retVal.value; - - return retVal.rc; -} - -static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, - u8 deviceId, u32 offset, u8 value) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumber; - dsa.subBusNumber = subBusNumber; - dsa.deviceId = deviceId; - - return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); -} - -static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm) -{ - struct HvCallPci_DsaAddr dsa; - struct HvCallPci_LoadReturn retVal; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa); - - return retVal.rc; -} - -static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - dsa.barNumber = barNumberParm; - - return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms); -} - -static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u64 fisrMask) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask); -} - -static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u64 fisrMask) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); -} - -static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, - u8 deviceNumberParm, u64 parms, u32 sizeofParms) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceNumberParm << 4; - - return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms); -} - -static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u64 interruptMask) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask); -} - -static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u64 interruptMask) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask); -} - -static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, - u8 deviceIdParm, u64 parms, u32 sizeofParms) -{ - struct HvCallPci_DsaAddr dsa; - - *((u64*)&dsa) = 0; - - dsa.busNumber = busNumberParm; - dsa.subBusNumber = subBusParm; - dsa.deviceId = deviceIdParm; - - return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, - sizeofParms); -} - -static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, - u16 sizeParm) -{ - u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, - sizeParm, HvCallPci_BusVpd); - if (xRc == -1) - return -1; - else - return xRc & 0xFFFF; -} - -#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/call_sm.h b/arch/powerpc/platforms/iseries/call_sm.h deleted file mode 100644 index c7e251619f48..000000000000 --- a/arch/powerpc/platforms/iseries/call_sm.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ISERIES_CALL_SM_H -#define _ISERIES_CALL_SM_H - -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -#define HvCallSmGet64BitsOfAccessMap HvCallSm + 11 - -static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, - u64 indexIntoBitMap) -{ - return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap); -} - -#endif /* _ISERIES_CALL_SM_H */ diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c deleted file mode 100644 index f0491cc28900..000000000000 --- a/arch/powerpc/platforms/iseries/dt.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation - * Copyright (C) 2000-2004, IBM Corporation - * - * Description: - * This file contains all the routines to build a flattened device - * tree for a legacy iSeries machine. - * - * 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. - */ - -#undef DEBUG - -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/pci_regs.h> -#include <linux/pci_ids.h> -#include <linux/threads.h> -#include <linux/bitops.h> -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/if_ether.h> /* ETH_ALEN */ - -#include <asm/machdep.h> -#include <asm/prom.h> -#include <asm/lppaca.h> -#include <asm/cputable.h> -#include <asm/abs_addr.h> -#include <asm/system.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/udbg.h> - -#include "processor_vpd.h" -#include "call_hpt.h" -#include "call_pci.h" -#include "pci.h" -#include "it_exp_vpd_panel.h" -#include "naca.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * These are created by the linker script at the start and end - * of the section containing all the strings marked with the DS macro. - */ -extern char __dt_strings_start[]; -extern char __dt_strings_end[]; - -#define DS(s) ({ \ - static const char __s[] __attribute__((section(".dt_strings"))) = s; \ - __s; \ -}) - -struct iseries_flat_dt { - struct boot_param_header header; - u64 reserve_map[2]; -}; - -static void * __initdata dt_data; - -/* - * Putting these strings here keeps them out of the .dt_strings section - * that we capture for the strings blob of the flattened device tree. - */ -static char __initdata device_type_cpu[] = "cpu"; -static char __initdata device_type_memory[] = "memory"; -static char __initdata device_type_serial[] = "serial"; -static char __initdata device_type_network[] = "network"; -static char __initdata device_type_pci[] = "pci"; -static char __initdata device_type_vdevice[] = "vdevice"; -static char __initdata device_type_vscsi[] = "vscsi"; - - -/* EBCDIC to ASCII conversion routines */ - -static unsigned char __init e2a(unsigned char x) -{ - switch (x) { - case 0x81 ... 0x89: - return x - 0x81 + 'a'; - case 0x91 ... 0x99: - return x - 0x91 + 'j'; - case 0xA2 ... 0xA9: - return x - 0xA2 + 's'; - case 0xC1 ... 0xC9: - return x - 0xC1 + 'A'; - case 0xD1 ... 0xD9: - return x - 0xD1 + 'J'; - case 0xE2 ... 0xE9: - return x - 0xE2 + 'S'; - case 0xF0 ... 0xF9: - return x - 0xF0 + '0'; - } - return ' '; -} - -static unsigned char * __init strne2a(unsigned char *dest, - const unsigned char *src, size_t n) -{ - int i; - - n = strnlen(src, n); - - for (i = 0; i < n; i++) - dest[i] = e2a(src[i]); - - return dest; -} - -static struct iseries_flat_dt * __init dt_init(void) -{ - struct iseries_flat_dt *dt; - unsigned long str_len; - - str_len = __dt_strings_end - __dt_strings_start; - dt = (struct iseries_flat_dt *)ALIGN(klimit, 8); - dt->header.off_mem_rsvmap = - offsetof(struct iseries_flat_dt, reserve_map); - dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8); - dt->header.off_dt_struct = dt->header.off_dt_strings - + ALIGN(str_len, 8); - dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct); - dt->header.dt_strings_size = str_len; - - /* There is no notion of hardware cpu id on iSeries */ - dt->header.boot_cpuid_phys = smp_processor_id(); - - memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start, - str_len); - - dt->header.magic = OF_DT_HEADER; - dt->header.version = 0x10; - dt->header.last_comp_version = 0x10; - - dt->reserve_map[0] = 0; - dt->reserve_map[1] = 0; - - return dt; -} - -static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value) -{ - *((u32 *)dt_data) = value; - dt_data += sizeof(u32); -} - -#ifdef notyet -static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value) -{ - *((u64 *)dt_data) = value; - dt_data += sizeof(u64); -} -#endif - -static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data, - int len) -{ - memcpy(dt_data, data, len); - dt_data += ALIGN(len, 4); -} - -static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name) -{ - dt_push_u32(dt, OF_DT_BEGIN_NODE); - dt_push_bytes(dt, name, strlen(name) + 1); -} - -#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) - -static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name, - const void *data, int len) -{ - unsigned long offset; - - dt_push_u32(dt, OF_DT_PROP); - - /* Length of the data */ - dt_push_u32(dt, len); - - offset = name - __dt_strings_start; - - /* The offset of the properties name in the string blob. */ - dt_push_u32(dt, (u32)offset); - - /* The actual data. */ - dt_push_bytes(dt, data, len); -} -#define dt_prop(dt, name, data, len) __dt_prop((dt), DS(name), (data), (len)) - -#define dt_prop_str(dt, name, data) \ - dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */ - -static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name, - u32 data) -{ - __dt_prop(dt, name, &data, sizeof(u32)); -} -#define dt_prop_u32(dt, name, data) __dt_prop_u32((dt), DS(name), (data)) - -static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt, - const char *name, u64 data) -{ - __dt_prop(dt, name, &data, sizeof(u64)); -} -#define dt_prop_u64(dt, name, data) __dt_prop_u64((dt), DS(name), (data)) - -#define dt_prop_u64_list(dt, name, data, n) \ - dt_prop((dt), name, (data), sizeof(u64) * (n)) - -#define dt_prop_u32_list(dt, name, data, n) \ - dt_prop((dt), name, (data), sizeof(u32) * (n)) - -#define dt_prop_empty(dt, name) dt_prop((dt), name, NULL, 0) - -static void __init dt_cpus(struct iseries_flat_dt *dt) -{ - unsigned char buf[32]; - unsigned char *p; - unsigned int i, index; - struct IoHriProcessorVpd *d; - u32 pft_size[2]; - - /* yuck */ - snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name); - p = strchr(buf, ' '); - if (!p) p = buf + strlen(buf); - - dt_start_node(dt, "cpus"); - dt_prop_u32(dt, "#address-cells", 1); - dt_prop_u32(dt, "#size-cells", 0); - - pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */ - pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); - - for (i = 0; i < NR_LPPACAS; i++) { - if (lppaca[i].dyn_proc_status >= 2) - continue; - - snprintf(p, 32 - (p - buf), "@%d", i); - dt_start_node(dt, buf); - - dt_prop_str(dt, "device_type", device_type_cpu); - - index = lppaca[i].dyn_hv_phys_proc_index; - d = &xIoHriProcessorVpd[index]; - - dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); - dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize); - - dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024); - dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize); - - /* magic conversions to Hz copied from old code */ - dt_prop_u32(dt, "clock-frequency", - ((1UL << 34) * 1000000) / d->xProcFreq); - dt_prop_u32(dt, "timebase-frequency", - ((1UL << 32) * 1000000) / d->xTimeBaseFreq); - - dt_prop_u32(dt, "reg", i); - - dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2); - - dt_end_node(dt); - } - - dt_end_node(dt); -} - -static void __init dt_model(struct iseries_flat_dt *dt) -{ - char buf[16] = "IBM,"; - - /* N.B. lparcfg.c knows about the "IBM," prefixes ... */ - /* "IBM," + mfgId[2:3] + systemSerial[1:5] */ - strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2); - strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5); - buf[11] = '\0'; - dt_prop_str(dt, "system-id", buf); - - /* "IBM," + machineType[0:4] */ - strne2a(buf + 4, xItExtVpdPanel.machineType, 4); - buf[8] = '\0'; - dt_prop_str(dt, "model", buf); - - dt_prop_str(dt, "compatible", "IBM,iSeries"); - dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex()); -} - -static void __init dt_initrd(struct iseries_flat_dt *dt) -{ -#ifdef CONFIG_BLK_DEV_INITRD - if (naca.xRamDisk) { - dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk); - dt_prop_u64(dt, "linux,initrd-end", - (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE); - } -#endif -} - -static void __init dt_do_vdevice(struct iseries_flat_dt *dt, - const char *name, u32 reg, int unit, - const char *type, const char *compat, int end) -{ - char buf[32]; - - snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0)); - dt_start_node(dt, buf); - dt_prop_str(dt, "device_type", type); - if (compat) - dt_prop_str(dt, "compatible", compat); - dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0)); - if (unit >= 0) - dt_prop_u32(dt, "linux,unit_address", unit); - if (end) - dt_end_node(dt); -} - -static void __init dt_vdevices(struct iseries_flat_dt *dt) -{ - u32 reg = 0; - HvLpIndexMap vlan_map; - int i; - - dt_start_node(dt, "vdevice"); - dt_prop_str(dt, "device_type", device_type_vdevice); - dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice"); - dt_prop_u32(dt, "#address-cells", 1); - dt_prop_u32(dt, "#size-cells", 0); - - dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, - "IBM,iSeries-vty", 1); - reg++; - - dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi, - "IBM,v-scsi", 1); - reg++; - - vlan_map = HvLpConfig_getVirtualLanIndexMap(); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { - unsigned char mac_addr[ETH_ALEN]; - - if ((vlan_map & (0x8000 >> i)) == 0) - continue; - dt_do_vdevice(dt, "l-lan", reg, i, device_type_network, - "IBM,iSeries-l-lan", 0); - mac_addr[0] = 0x02; - mac_addr[1] = 0x01; - mac_addr[2] = 0xff; - mac_addr[3] = i; - mac_addr[4] = 0xff; - mac_addr[5] = HvLpConfig_getLpIndex_outline(); - dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN); - dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN); - dt_prop_u32(dt, "max-frame-size", 9000); - dt_prop_u32(dt, "address-bits", 48); - - dt_end_node(dt); - } - - dt_end_node(dt); -} - -struct pci_class_name { - u16 code; - const char *name; - const char *type; -}; - -static struct pci_class_name __initdata pci_class_name[] = { - { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network }, -}; - -static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code) -{ - struct pci_class_name *cp; - - for (cp = pci_class_name; - cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++) - if (cp->code == class_code) - return cp; - return NULL; -} - -/* - * This assumes that the node slot is always on the primary bus! - */ -static void __init scan_bridge_slot(struct iseries_flat_dt *dt, - HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info) -{ - HvSubBusNumber sub_bus = bridge_info->subBusNumber; - u16 vendor_id; - u16 device_id; - u32 class_id; - int err; - char buf[32]; - u32 reg[5]; - int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus); - int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus); - HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function); - u8 devfn; - struct pci_class_name *cp; - - /* - * Connect all functions of any device found. - */ - for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) { - for (function = 0; function < 8; function++) { - HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel, - function); - err = HvCallXm_connectBusUnit(bus, sub_bus, - agent_id, 0); - if (err) { - if (err != 0x302) - DBG("connectBusUnit(%x, %x, %x) %x\n", - bus, sub_bus, agent_id, err); - continue; - } - - err = HvCallPci_configLoad16(bus, sub_bus, agent_id, - PCI_VENDOR_ID, &vendor_id); - if (err) { - DBG("ReadVendor(%x, %x, %x) %x\n", - bus, sub_bus, agent_id, err); - continue; - } - err = HvCallPci_configLoad16(bus, sub_bus, agent_id, - PCI_DEVICE_ID, &device_id); - if (err) { - DBG("ReadDevice(%x, %x, %x) %x\n", - bus, sub_bus, agent_id, err); - continue; - } - err = HvCallPci_configLoad32(bus, sub_bus, agent_id, - PCI_CLASS_REVISION , &class_id); - if (err) { - DBG("ReadClass(%x, %x, %x) %x\n", - bus, sub_bus, agent_id, err); - continue; - } - - devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel), - function); - cp = dt_find_pci_class_name(class_id >> 16); - if (cp && cp->name) - strncpy(buf, cp->name, sizeof(buf) - 1); - else - snprintf(buf, sizeof(buf), "pci%x,%x", - vendor_id, device_id); - buf[sizeof(buf) - 1] = '\0'; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "@%x", PCI_SLOT(devfn)); - buf[sizeof(buf) - 1] = '\0'; - if (function != 0) - snprintf(buf + strlen(buf), - sizeof(buf) - strlen(buf), - ",%x", function); - dt_start_node(dt, buf); - reg[0] = (bus << 16) | (devfn << 8); - reg[1] = 0; - reg[2] = 0; - reg[3] = 0; - reg[4] = 0; - dt_prop_u32_list(dt, "reg", reg, 5); - if (cp && (cp->type || cp->name)) - dt_prop_str(dt, "device_type", - cp->type ? cp->type : cp->name); - dt_prop_u32(dt, "vendor-id", vendor_id); - dt_prop_u32(dt, "device-id", device_id); - dt_prop_u32(dt, "class-code", class_id >> 8); - dt_prop_u32(dt, "revision-id", class_id & 0xff); - dt_prop_u32(dt, "linux,subbus", sub_bus); - dt_prop_u32(dt, "linux,agent-id", agent_id); - dt_prop_u32(dt, "linux,logical-slot-number", - bridge_info->logicalSlotNumber); - dt_end_node(dt); - - } - } -} - -static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus, - HvSubBusNumber sub_bus, int id_sel) -{ - struct HvCallPci_BridgeInfo bridge_info; - HvAgentId agent_id; - int function; - int ret; - - /* Note: hvSubBus and irq is always be 0 at this level! */ - for (function = 0; function < 8; ++function) { - agent_id = ISERIES_PCI_AGENTID(id_sel, function); - ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0); - if (ret != 0) { - if (ret != 0xb) - DBG("connectBusUnit(%x, %x, %x) %x\n", - bus, sub_bus, agent_id, ret); - continue; - } - DBG("found device at bus %d idsel %d func %d (AgentId %x)\n", - bus, id_sel, function, agent_id); - ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id, - iseries_hv_addr(&bridge_info), - sizeof(struct HvCallPci_BridgeInfo)); - if (ret != 0) - continue; - DBG("bridge info: type %x subbus %x " - "maxAgents %x maxsubbus %x logslot %x\n", - bridge_info.busUnitInfo.deviceType, - bridge_info.subBusNumber, - bridge_info.maxAgents, - bridge_info.maxSubBusNumber, - bridge_info.logicalSlotNumber); - if (bridge_info.busUnitInfo.deviceType == - HvCallPci_BridgeDevice) - scan_bridge_slot(dt, bus, &bridge_info); - else - DBG("PCI: Invalid Bridge Configuration(0x%02X)", - bridge_info.busUnitInfo.deviceType); - } -} - -static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus) -{ - struct HvCallPci_DeviceInfo dev_info; - const HvSubBusNumber sub_bus = 0; /* EADs is always 0. */ - int err; - int id_sel; - const int max_agents = 8; - - /* - * Probe for EADs Bridges - */ - for (id_sel = 1; id_sel < max_agents; ++id_sel) { - err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel, - iseries_hv_addr(&dev_info), - sizeof(struct HvCallPci_DeviceInfo)); - if (err) { - if (err != 0x302) - DBG("getDeviceInfo(%x, %x, %x) %x\n", - bus, sub_bus, id_sel, err); - continue; - } - if (dev_info.deviceType != HvCallPci_NodeDevice) { - DBG("PCI: Invalid System Configuration" - "(0x%02X) for bus 0x%02x id 0x%02x.\n", - dev_info.deviceType, bus, id_sel); - continue; - } - scan_bridge(dt, bus, sub_bus, id_sel); - } -} - -static void __init dt_pci_devices(struct iseries_flat_dt *dt) -{ - HvBusNumber bus; - char buf[32]; - u32 buses[2]; - int phb_num = 0; - - /* Check all possible buses. */ - for (bus = 0; bus < 256; bus++) { - int err = HvCallXm_testBus(bus); - - if (err) { - /* - * Check for Unexpected Return code, a clue that - * something has gone wrong. - */ - if (err != 0x0301) - DBG("Unexpected Return on Probe(0x%02X) " - "0x%04X\n", bus, err); - continue; - } - DBG("bus %d appears to exist\n", bus); - snprintf(buf, 32, "pci@%d", phb_num); - dt_start_node(dt, buf); - dt_prop_str(dt, "device_type", device_type_pci); - dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB"); - dt_prop_u32(dt, "#address-cells", 3); - dt_prop_u32(dt, "#size-cells", 2); - buses[0] = buses[1] = bus; - dt_prop_u32_list(dt, "bus-range", buses, 2); - scan_phb(dt, bus); - dt_end_node(dt); - phb_num++; - } -} - -static void dt_finish(struct iseries_flat_dt *dt) -{ - dt_push_u32(dt, OF_DT_END); - dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt; - klimit = ALIGN((unsigned long)dt_data, 8); -} - -void * __init build_flat_dt(unsigned long phys_mem_size) -{ - struct iseries_flat_dt *iseries_dt; - u64 tmp[2]; - - iseries_dt = dt_init(); - - dt_start_node(iseries_dt, ""); - - dt_prop_u32(iseries_dt, "#address-cells", 2); - dt_prop_u32(iseries_dt, "#size-cells", 2); - dt_model(iseries_dt); - - /* /memory */ - dt_start_node(iseries_dt, "memory@0"); - dt_prop_str(iseries_dt, "device_type", device_type_memory); - tmp[0] = 0; - tmp[1] = phys_mem_size; - dt_prop_u64_list(iseries_dt, "reg", tmp, 2); - dt_end_node(iseries_dt); - - /* /chosen */ - dt_start_node(iseries_dt, "chosen"); - dt_prop_str(iseries_dt, "bootargs", cmd_line); - dt_initrd(iseries_dt); - dt_end_node(iseries_dt); - - dt_cpus(iseries_dt); - - dt_vdevices(iseries_dt); - dt_pci_devices(iseries_dt); - - dt_end_node(iseries_dt); - - dt_finish(iseries_dt); - - return iseries_dt; -} diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S deleted file mode 100644 index f519ee17ff7d..000000000000 --- a/arch/powerpc/platforms/iseries/exception.S +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Low level routines for legacy iSeries support. - * - * Extracted from head_64.S - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * - * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com - * - * This file contains the low-level support and setup for the - * PowerPC-64 platform, including trap and interrupt dispatch. - * - * 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. - */ - -#include <asm/reg.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/thread_info.h> -#include <asm/ptrace.h> -#include <asm/cputable.h> -#include <asm/mmu.h> - -#include "exception.h" - - .text - - .globl system_reset_iSeries -system_reset_iSeries: - bl .relative_toc - mfspr r13,SPRN_SPRG3 /* Get alpaca address */ - LOAD_REG_ADDR(r23, alpaca) - li r0,ALPACA_SIZE - sub r23,r13,r23 - divdu r24,r23,r0 /* r24 has cpu number */ - cmpwi 0,r24,0 /* Are we processor 0? */ - bne 1f - LOAD_REG_ADDR(r13, boot_paca) - mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */ - mfmsr r23 - ori r23,r23,MSR_RI - mtmsrd r23 /* RI on */ - b .__start_initialization_iSeries /* Start up the first processor */ -1: mfspr r4,SPRN_CTRLF - li r5,CTRL_RUNLATCH /* Turn off the run light */ - 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 yield() later, and we will not access the paca anyway */ -#ifdef CONFIG_SMP -iSeries_secondary_wait_paca: - HMT_LOW - LOAD_REG_ADDR(r23, __secondary_hold_spinloop) - ld r23,0(r23) - - cmpdi 0,r23,0 - bne 2f /* go on when the master is ready */ - - /* Keep poking the Hypervisor until we're released */ - /* 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 iSeries_secondary_wait_paca - -2: - HMT_MEDIUM - sync - - LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */ - lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */ - cmpld 0,r24,r3 /* is our cpu number allocated? */ - bge iSeries_secondary_yield /* no, yield forever */ - - /* Load our paca now that it's been allocated */ - LOAD_REG_ADDR(r13, paca) - ld r13,0(r13) - mulli r0,r24,PACA_SIZE - add r13,r13,r0 - mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */ - mfmsr r23 - ori r23,r23,MSR_RI - mtmsrd r23 /* RI on */ - -iSeries_secondary_smp_loop: - lbz r23,PACAPROCSTART(r13) /* Test if this processor - * should start */ - cmpwi 0,r23,0 - bne 3f /* go on when we are told */ - - HMT_LOW - /* 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 */ - mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ - b iSeries_secondary_smp_loop /* wait for signal to start */ - -3: - HMT_MEDIUM - sync - LOAD_REG_ADDR(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 - - b __secondary_start /* Loop until told to go */ -#endif /* CONFIG_SMP */ - -iSeries_secondary_yield: - /* Yield the processor. This is required for non-SMP kernels - which are running on multi-threaded machines. */ - HMT_LOW - lis r3,0x8000 - rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ - addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ - li r4,0 /* "yield timed" */ - li r5,-1 /* "yield forever" */ - li r0,-1 /* r0=-1 indicates a Hypervisor call */ - sc /* Invoke the hypervisor via a system call */ - mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ - b iSeries_secondary_yield /* If SMP not configured, secondaries - * loop forever */ - -/*** ISeries-LPAR interrupt handlers ***/ - - STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC) - - .globl data_access_iSeries -data_access_iSeries: - mtspr SPRN_SPRG_SCRATCH0,r13 -BEGIN_FTR_SECTION - mfspr r13,SPRN_SPRG_PACA - std r9,PACA_EXSLB+EX_R9(r13) - std r10,PACA_EXSLB+EX_R10(r13) - mfspr r10,SPRN_DAR - mfspr r9,SPRN_DSISR - srdi r10,r10,60 - rlwimi r10,r9,16,0x20 - mfcr r9 - cmpwi r10,0x2c - beq .do_stab_bolted_iSeries - ld r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXGEN+EX_R11(r13) - ld r11,PACA_EXSLB+EX_R9(r13) - std r12,PACA_EXGEN+EX_R12(r13) - mfspr r12,SPRN_SPRG_SCRATCH0 - std r10,PACA_EXGEN+EX_R10(r13) - std r11,PACA_EXGEN+EX_R9(r13) - std r12,PACA_EXGEN+EX_R13(r13) - EXCEPTION_PROLOG_ISERIES_1 -FTR_SECTION_ELSE - EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0) - EXCEPTION_PROLOG_ISERIES_1 -ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) - b data_access_common - -.do_stab_bolted_iSeries: - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 - std r10,PACA_EXSLB+EX_R13(r13) - EXCEPTION_PROLOG_ISERIES_1 - b .do_stab_bolted - - .globl data_access_slb_iSeries -data_access_slb_iSeries: - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ - std r3,PACA_EXSLB+EX_R3(r13) - mfspr r3,SPRN_DAR - std r9,PACA_EXSLB+EX_R9(r13) - mfcr r9 -#ifdef __DISABLED__ - cmpdi r3,0 - bge slb_miss_user_iseries -#endif - std r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 - std r10,PACA_EXSLB+EX_R13(r13) - ld r12,PACALPPACAPTR(r13) - ld r12,LPPACASRR1(r12) - b .slb_miss_realmode - - STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN) - - .globl instruction_access_slb_iSeries -instruction_access_slb_iSeries: - mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ - mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ - std r3,PACA_EXSLB+EX_R3(r13) - ld r3,PACALPPACAPTR(r13) - ld r3,LPPACASRR0(r3) /* get SRR0 value */ - std r9,PACA_EXSLB+EX_R9(r13) - mfcr r9 -#ifdef __DISABLED__ - cmpdi r3,0 - bge slb_miss_user_iseries -#endif - std r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - mfspr r10,SPRN_SPRG_SCRATCH0 - std r10,PACA_EXSLB+EX_R13(r13) - ld r12,PACALPPACAPTR(r13) - ld r12,LPPACASRR1(r12) - b .slb_miss_realmode - -#ifdef __DISABLED__ -slb_miss_user_iseries: - std r10,PACA_EXGEN+EX_R10(r13) - std r11,PACA_EXGEN+EX_R11(r13) - std r12,PACA_EXGEN+EX_R12(r13) - mfspr r10,SPRG_SCRATCH0 - ld r11,PACA_EXSLB+EX_R9(r13) - ld r12,PACA_EXSLB+EX_R3(r13) - std r10,PACA_EXGEN+EX_R13(r13) - std r11,PACA_EXGEN+EX_R9(r13) - std r12,PACA_EXGEN+EX_R3(r13) - EXCEPTION_PROLOG_ISERIES_1 - b slb_miss_user_common -#endif - - MASKABLE_EXCEPTION_ISERIES(hardware_interrupt) - STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN) - STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN) - STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN) - MASKABLE_EXCEPTION_ISERIES(decrementer) - STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN) - STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN) - - .globl system_call_iSeries -system_call_iSeries: - mr r9,r13 - mfspr r13,SPRN_SPRG_PACA - EXCEPTION_PROLOG_ISERIES_1 - b system_call_common - - STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN) - STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN) - STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN) - -decrementer_iSeries_masked: - /* We may not have a valid TOC pointer in here. */ - li r11,1 - ld r12,PACALPPACAPTR(r13) - stb r11,LPPACADECRINT(r12) - li r12,-1 - clrldi r12,r12,33 /* set DEC to 0x7fffffff */ - mtspr SPRN_DEC,r12 - /* fall through */ - -hardware_interrupt_iSeries_masked: - mtcrf 0x80,r9 /* Restore regs */ - ld r12,PACALPPACAPTR(r13) - ld r11,LPPACASRR0(r12) - ld r12,LPPACASRR1(r12) - mtspr SPRN_SRR0,r11 - mtspr SPRN_SRR1,r12 - ld r9,PACA_EXGEN+EX_R9(r13) - ld r10,PACA_EXGEN+EX_R10(r13) - ld r11,PACA_EXGEN+EX_R11(r13) - ld r12,PACA_EXGEN+EX_R12(r13) - ld r13,PACA_EXGEN+EX_R13(r13) - rfid - b . /* prevent speculative execution */ - -_INIT_STATIC(__start_initialization_iSeries) - /* Clear out the BSS */ - LOAD_REG_ADDR(r11,__bss_stop) - LOAD_REG_ADDR(r8,__bss_start) - sub r11,r11,r8 /* bss size */ - addi r11,r11,7 /* round up to an even double word */ - rldicl. r11,r11,61,3 /* shift right by 3 */ - beq 4f - addi r8,r8,-8 - li r0,0 - mtctr r11 /* zero this many doublewords */ -3: stdu r0,8(r8) - bdnz 3b -4: - LOAD_REG_ADDR(r1,init_thread_union) - addi r1,r1,THREAD_SIZE - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - - bl .iSeries_early_setup - bl .early_setup - - /* relocation is on at this point */ - - b .start_here_common diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h deleted file mode 100644 index 50271b550a99..000000000000 --- a/arch/powerpc/platforms/iseries/exception.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H -#define _ASM_POWERPC_ISERIES_EXCEPTION_H -/* - * Extracted from head_64.S - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * - * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com - * - * This file contains the low-level support and setup for the - * PowerPC-64 platform, including trap and interrupt dispatch. - * - * 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. - */ -#include <asm/exception-64s.h> - -#define EXCEPTION_PROLOG_ISERIES_1 \ - mfmsr r10; \ - ld r12,PACALPPACAPTR(r13); \ - ld r11,LPPACASRR0(r12); \ - ld r12,LPPACASRR1(r12); \ - ori r10,r10,MSR_RI; \ - mtmsrd r10,1 - -#define STD_EXCEPTION_ISERIES(label, area) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(area, NOTEST, 0); \ - EXCEPTION_PROLOG_ISERIES_1; \ - b label##_common - -#define MASKABLE_EXCEPTION_ISERIES(label) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ - EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0); \ - lbz r10,PACASOFTIRQEN(r13); \ - cmpwi 0,r10,0; \ - beq- label##_iSeries_masked; \ - EXCEPTION_PROLOG_ISERIES_1; \ - b label##_common; \ - -#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */ diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c deleted file mode 100644 index 3ae66ab9d5e7..000000000000 --- a/arch/powerpc/platforms/iseries/htab.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * iSeries hashtable management. - * Derived from pSeries_htab.c - * - * SMP scalability work: - * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM - * - * 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. - */ -#include <asm/machdep.h> -#include <asm/pgtable.h> -#include <asm/mmu.h> -#include <asm/mmu_context.h> -#include <asm/abs_addr.h> -#include <linux/spinlock.h> - -#include "call_hpt.h" - -static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp; - -/* - * Very primitive algorithm for picking up a lock - */ -static inline void iSeries_hlock(unsigned long slot) -{ - if (slot & 0x8) - slot = ~slot; - spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]); -} - -static inline void iSeries_hunlock(unsigned long slot) -{ - if (slot & 0x8) - slot = ~slot; - spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); -} - -static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, - unsigned long pa, unsigned long rflags, - unsigned long vflags, int psize, int ssize) -{ - long slot; - struct hash_pte lhpte; - int secondary = 0; - - BUG_ON(psize != MMU_PAGE_4K); - - /* - * The hypervisor tries both primary and secondary. - * If we are being called to insert in the secondary, - * it means we have already tried both primary and secondary, - * so we return failure immediately. - */ - if (vflags & HPTE_V_SECONDARY) - return -1; - - iSeries_hlock(hpte_group); - - slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT); - if (unlikely(lhpte.v & HPTE_V_VALID)) { - if (vflags & HPTE_V_BOLTED) { - HvCallHpt_setSwBits(slot, 0x10, 0); - HvCallHpt_setPp(slot, PP_RWXX); - iSeries_hunlock(hpte_group); - if (slot < 0) - return 0x8 | (slot & 7); - else - return slot & 7; - } - BUG(); - } - - if (slot == -1) { /* No available entry found in either group */ - iSeries_hunlock(hpte_group); - return -1; - } - - if (slot < 0) { /* MSB set means secondary group */ - vflags |= HPTE_V_SECONDARY; - secondary = 1; - slot &= 0x7fffffffffffffff; - } - - - lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) | - vflags | HPTE_V_VALID; - lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; - - /* Now fill in the actual HPTE */ - HvCallHpt_addValidate(slot, secondary, &lhpte); - - iSeries_hunlock(hpte_group); - - return (secondary << 3) | (slot & 7); -} - -static unsigned long iSeries_hpte_getword0(unsigned long slot) -{ - struct hash_pte hpte; - - HvCallHpt_get(&hpte, slot); - return hpte.v; -} - -static long iSeries_hpte_remove(unsigned long hpte_group) -{ - unsigned long slot_offset; - int i; - unsigned long hpte_v; - - /* Pick a random slot to start at */ - slot_offset = mftb() & 0x7; - - iSeries_hlock(hpte_group); - - for (i = 0; i < HPTES_PER_GROUP; i++) { - hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset); - - if (! (hpte_v & HPTE_V_BOLTED)) { - HvCallHpt_invalidateSetSwBitsGet(hpte_group + - slot_offset, 0, 0); - iSeries_hunlock(hpte_group); - return i; - } - - slot_offset++; - slot_offset &= 0x7; - } - - iSeries_hunlock(hpte_group); - - return -1; -} - -/* - * The HyperVisor expects the "flags" argument in this form: - * bits 0..59 : reserved - * bit 60 : N - * bits 61..63 : PP2,PP1,PP0 - */ -static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int ssize, int local) -{ - struct hash_pte hpte; - unsigned long want_v; - - iSeries_hlock(slot); - - HvCallHpt_get(&hpte, slot); - want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M); - - if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { - /* - * Hypervisor expects bits as NPPP, which is - * different from how they are mapped in our PP. - */ - HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); - iSeries_hunlock(slot); - return 0; - } - iSeries_hunlock(slot); - - return -1; -} - -/* - * Functions used to find the PTE for a particular virtual address. - * Only used during boot when bolting pages. - * - * Input : vpn : virtual page number - * Output: PTE index within the page table of the entry - * -1 on failure - */ -static long iSeries_hpte_find(unsigned long vpn) -{ - struct hash_pte hpte; - long slot; - - /* - * The HvCallHpt_findValid interface is as follows: - * 0xffffffffffffffff : No entry found. - * 0x00000000xxxxxxxx : Entry found in primary group, slot x - * 0x80000000xxxxxxxx : Entry found in secondary group, slot x - */ - slot = HvCallHpt_findValid(&hpte, vpn); - if (hpte.v & HPTE_V_VALID) { - if (slot < 0) { - slot &= 0x7fffffffffffffff; - slot = -slot; - } - } else - slot = -1; - return slot; -} - -/* - * Update the page protection bits. Intended to be used to create - * guard pages for kernel data structures on pages which are bolted - * in the HPT. Assumes pages being operated on will not be stolen. - * Does not work on large pages. - * - * No need to lock here because we should be the only user. - */ -static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, - int psize, int ssize) -{ - unsigned long vsid,va,vpn; - long slot; - - BUG_ON(psize != MMU_PAGE_4K); - - vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); - va = (vsid << 28) | (ea & 0x0fffffff); - vpn = va >> HW_PAGE_SHIFT; - slot = iSeries_hpte_find(vpn); - if (slot == -1) - panic("updateboltedpp: Could not find page to bolt\n"); - HvCallHpt_setPp(slot, newpp); -} - -static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, - int psize, int ssize, int local) -{ - unsigned long hpte_v; - unsigned long avpn = va >> 23; - unsigned long flags; - - local_irq_save(flags); - - iSeries_hlock(slot); - - hpte_v = iSeries_hpte_getword0(slot); - - if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID)) - HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); - - iSeries_hunlock(slot); - - local_irq_restore(flags); -} - -void __init hpte_init_iSeries(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++) - spin_lock_init(&iSeries_hlocks[i]); - - ppc_md.hpte_invalidate = iSeries_hpte_invalidate; - ppc_md.hpte_updatepp = iSeries_hpte_updatepp; - ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; - ppc_md.hpte_insert = iSeries_hpte_insert; - ppc_md.hpte_remove = iSeries_hpte_remove; -} diff --git a/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S deleted file mode 100644 index 07ae6ad5f49f..000000000000 --- a/arch/powerpc/platforms/iseries/hvcall.S +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file contains the code to perform calls to the - * iSeries LPAR hypervisor - * - * 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. - */ - -#include <asm/ppc_asm.h> -#include <asm/processor.h> -#include <asm/ptrace.h> /* XXX for STACK_FRAME_OVERHEAD */ - - .text - -/* - * Hypervisor call - * - * Invoke the iSeries hypervisor via the System Call instruction - * Parameters are passed to this routine in registers r3 - r10 - * - * r3 contains the HV function to be called - * r4-r10 contain the operands to the hypervisor function - * - */ - -_GLOBAL(HvCall) -_GLOBAL(HvCall0) -_GLOBAL(HvCall1) -_GLOBAL(HvCall2) -_GLOBAL(HvCall3) -_GLOBAL(HvCall4) -_GLOBAL(HvCall5) -_GLOBAL(HvCall6) -_GLOBAL(HvCall7) - - - mfcr r0 - std r0,-8(r1) - stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) - - /* r0 = 0xffffffffffffffff indicates a hypervisor call */ - - li r0,-1 - - /* Invoke the hypervisor */ - - sc - - ld r1,0(r1) - ld r0,-8(r1) - mtcrf 0xff,r0 - - /* return to caller, return value in r3 */ - - blr - -_GLOBAL(HvCall0Ret16) -_GLOBAL(HvCall1Ret16) -_GLOBAL(HvCall2Ret16) -_GLOBAL(HvCall3Ret16) -_GLOBAL(HvCall4Ret16) -_GLOBAL(HvCall5Ret16) -_GLOBAL(HvCall6Ret16) -_GLOBAL(HvCall7Ret16) - - mfcr r0 - std r0,-8(r1) - std r31,-16(r1) - stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1) - - mr r31,r4 - li r0,-1 - mr r4,r5 - mr r5,r6 - mr r6,r7 - mr r7,r8 - mr r8,r9 - mr r9,r10 - - sc - - std r3,0(r31) - std r4,8(r31) - - mr r3,r5 - - ld r1,0(r1) - ld r0,-8(r1) - mtcrf 0xff,r0 - ld r31,-16(r1) - - blr diff --git a/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c deleted file mode 100644 index f476d71194fa..000000000000 --- a/arch/powerpc/platforms/iseries/hvlog.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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. - */ - -#include <asm/page.h> -#include <asm/abs_addr.h> -#include <asm/iseries/hv_call.h> -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - - -void HvCall_writeLogBuffer(const void *buffer, u64 len) -{ - struct HvLpBufferList hv_buf; - u64 left_this_page; - u64 cur = virt_to_abs(buffer); - - while (len) { - hv_buf.addr = cur; - left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur; - if (left_this_page > len) - left_this_page = len; - hv_buf.len = left_this_page; - len -= left_this_page; - HvCall2(HvCallBaseWriteLogBuffer, - virt_to_abs(&hv_buf), - left_this_page); - cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE; - } -} diff --git a/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c deleted file mode 100644 index f62a0c5fa670..000000000000 --- a/arch/powerpc/platforms/iseries/hvlpconfig.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2001 Kyle A. Lucke, IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/export.h> -#include <asm/iseries/hv_lp_config.h> -#include "it_lp_naca.h" - -HvLpIndex HvLpConfig_getLpIndex_outline(void) -{ - return HvLpConfig_getLpIndex(); -} -EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline); - -HvLpIndex HvLpConfig_getLpIndex(void) -{ - return itLpNaca.xLpIndex; -} -EXPORT_SYMBOL(HvLpConfig_getLpIndex); - -HvLpIndex HvLpConfig_getPrimaryLpIndex(void) -{ - return itLpNaca.xPrimaryLpIndex; -} -EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex); diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c deleted file mode 100644 index 2f3d9110248c..000000000000 --- a/arch/powerpc/platforms/iseries/iommu.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup: - * - * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation - * Copyright (C) 2006 Olof Johansson <olof@lixom.net> - * - * Dynamic DMA mapping support, iSeries-specific parts. - * - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/types.h> -#include <linux/dma-mapping.h> -#include <linux/list.h> -#include <linux/pci.h> -#include <linux/export.h> -#include <linux/slab.h> - -#include <asm/iommu.h> -#include <asm/vio.h> -#include <asm/tce.h> -#include <asm/machdep.h> -#include <asm/abs_addr.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/iommu.h> - -static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction, - struct dma_attrs *attrs) -{ - u64 rc; - u64 tce, rpn; - - while (npages--) { - rpn = virt_to_abs(uaddr) >> TCE_SHIFT; - tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; - - if (tbl->it_type == TCE_VB) { - /* Virtual Bus */ - tce |= TCE_VALID|TCE_ALLIO; - if (direction != DMA_TO_DEVICE) - tce |= TCE_VB_WRITE; - } else { - /* PCI Bus */ - tce |= TCE_PCI_READ; /* Read allowed */ - if (direction != DMA_TO_DEVICE) - tce |= TCE_PCI_WRITE; - } - - rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce); - if (rc) - panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", - rc); - index++; - uaddr += TCE_PAGE_SIZE; - } - return 0; -} - -static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) -{ - u64 rc; - - while (npages--) { - rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0); - if (rc) - panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", - rc); - index++; - } -} - -/* - * Structure passed to HvCallXm_getTceTableParms - */ -struct iommu_table_cb { - unsigned long itc_busno; /* Bus number for this tce table */ - unsigned long itc_start; /* Will be NULL for secondary */ - unsigned long itc_totalsize; /* Size (in pages) of whole table */ - unsigned long itc_offset; /* Index into real tce table of the - start of our section */ - unsigned long itc_size; /* Size (in pages) of our section */ - unsigned long itc_index; /* Index of this tce table */ - unsigned short itc_maxtables; /* Max num of tables for partition */ - unsigned char itc_virtbus; /* Flag to indicate virtual bus */ - unsigned char itc_slotno; /* IOA Tce Slot Index */ - unsigned char itc_rsvd[4]; -}; - -/* - * Call Hv with the architected data structure to get TCE table info. - * info. Put the returned data into the Linux representation of the - * TCE table data. - * The Hardware Tce table comes in three flavors. - * 1. TCE table shared between Buses. - * 2. TCE table per Bus. - * 3. TCE Table per IOA. - */ -void iommu_table_getparms_iSeries(unsigned long busno, - unsigned char slotno, - unsigned char virtbus, - struct iommu_table* tbl) -{ - struct iommu_table_cb *parms; - - parms = kzalloc(sizeof(*parms), GFP_KERNEL); - if (parms == NULL) - panic("PCI_DMA: TCE Table Allocation failed."); - - parms->itc_busno = busno; - parms->itc_slotno = slotno; - parms->itc_virtbus = virtbus; - - HvCallXm_getTceTableParms(iseries_hv_addr(parms)); - - if (parms->itc_size == 0) - panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); - - /* itc_size is in pages worth of table, it_size is in # of entries */ - tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE; - tbl->it_busno = parms->itc_busno; - tbl->it_offset = parms->itc_offset; - tbl->it_index = parms->itc_index; - tbl->it_blocksize = 1; - tbl->it_type = virtbus ? TCE_VB : TCE_PCI; - - kfree(parms); -} - - -#ifdef CONFIG_PCI -/* - * This function compares the known tables to find an iommu_table - * that has already been built for hardware TCEs. - */ -static struct iommu_table *iommu_table_find(struct iommu_table * tbl) -{ - struct device_node *node; - - for (node = NULL; (node = of_find_all_nodes(node)); ) { - struct pci_dn *pdn = PCI_DN(node); - struct iommu_table *it; - - if (pdn == NULL) - continue; - it = pdn->iommu_table; - if ((it != NULL) && - (it->it_type == TCE_PCI) && - (it->it_offset == tbl->it_offset) && - (it->it_index == tbl->it_index) && - (it->it_size == tbl->it_size)) { - of_node_put(node); - return it; - } - } - return NULL; -} - - -static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) -{ - struct iommu_table *tbl; - struct device_node *dn = pci_device_to_OF_node(pdev); - struct pci_dn *pdn = PCI_DN(dn); - const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL); - - BUG_ON(lsn == NULL); - - tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); - - /* Look for existing tce table */ - pdn->iommu_table = iommu_table_find(tbl); - if (pdn->iommu_table == NULL) - pdn->iommu_table = iommu_init_table(tbl, -1); - else - kfree(tbl); - set_iommu_table_base(&pdev->dev, pdn->iommu_table); -} -#else -#define pci_dma_dev_setup_iseries NULL -#endif - -static struct iommu_table veth_iommu_table; -static struct iommu_table vio_iommu_table; - -void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) -{ - return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle, - DMA_BIT_MASK(32), flag, -1); -} -EXPORT_SYMBOL_GPL(iseries_hv_alloc); - -void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) -{ - iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); -} -EXPORT_SYMBOL_GPL(iseries_hv_free); - -dma_addr_t iseries_hv_map(void *vaddr, size_t size, - enum dma_data_direction direction) -{ - return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr), - (unsigned long)vaddr % PAGE_SIZE, size, - DMA_BIT_MASK(32), direction, NULL); -} - -void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL); -} - -void __init iommu_vio_init(void) -{ - iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); - veth_iommu_table.it_size /= 2; - vio_iommu_table = veth_iommu_table; - vio_iommu_table.it_offset += veth_iommu_table.it_size; - - if (!iommu_init_table(&veth_iommu_table, -1)) - printk("Virtual Bus VETH TCE table failed.\n"); - if (!iommu_init_table(&vio_iommu_table, -1)) - printk("Virtual Bus VIO TCE table failed.\n"); -} - -struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev) -{ - if (strcmp(dev->type, "network") == 0) - return &veth_iommu_table; - return &vio_iommu_table; -} - -void iommu_init_early_iSeries(void) -{ - ppc_md.tce_build = tce_build_iSeries; - ppc_md.tce_free = tce_free_iSeries; - - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries; - set_pci_dma_ops(&dma_iommu_ops); -} diff --git a/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h deleted file mode 100644 index 83e4ca42fc57..000000000000 --- a/arch/powerpc/platforms/iseries/ipl_parms.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ISERIES_IPL_PARMS_H -#define _ISERIES_IPL_PARMS_H - -/* - * This struct maps the IPL Parameters DMA'd from the SP. - * - * Warning: - * This data must map in exactly 64 bytes and match the architecture for - * the IPL parms - */ - -#include <asm/types.h> - -struct ItIplParmsReal { - u8 xFormat; // Defines format of IplParms x00-x00 - u8 xRsvd01:6; // Reserved x01-x01 - u8 xAlternateSearch:1; // Alternate search indicator ... - u8 xUaSupplied:1; // UA Supplied on programmed IPL... - u8 xLsUaFormat; // Format byte for UA x02-x02 - u8 xRsvd02; // Reserved x03-x03 - u32 xLsUa; // LS UA x04-x07 - u32 xUnusedLsLid; // First OS LID to load x08-x0B - u16 xLsBusNumber; // LS Bus Number x0C-x0D - u8 xLsCardAdr; // LS Card Address x0E-x0E - u8 xLsBoardAdr; // LS Board Address x0F-x0F - u32 xRsvd03; // Reserved x10-x13 - u8 xSpcnPresent:1; // SPCN present x14-x14 - u8 xCpmPresent:1; // CPM present ... - u8 xRsvd04:6; // Reserved ... - u8 xRsvd05:4; // Reserved x15-x15 - u8 xKeyLock:4; // Keylock setting ... - u8 xRsvd06:6; // Reserved x16-x16 - u8 xIplMode:2; // Ipl mode (A|B|C|D) ... - u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17 - u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x19 - u16 xPowerOnResetIpl:1; // Indicate POR condition ... - u16 xMainStorePreserved:1; // Main Storage is preserved ... - u16 xRsvd07:13; // Reserved ... - u16 xIplSource:16; // Ipl source x1A-x1B - u8 xIplReason:8; // Reason for this IPL x1C-x1C - u8 xRsvd08; // Reserved x1D-x1D - u16 xRsvd09; // Reserved x1E-x1F - u16 xSysBoxType; // System Box Type x20-x21 - u16 xSysProcType; // System Processor Type x22-x23 - u32 xRsvd10; // Reserved x24-x27 - u64 xRsvd11; // Reserved x28-x2F - u64 xRsvd12; // Reserved x30-x37 - u64 xRsvd13; // Reserved x38-x3F -}; - -#endif /* _ISERIES_IPL_PARMS_H */ diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c deleted file mode 100644 index b2103453eb01..000000000000 --- a/arch/powerpc/platforms/iseries/irq.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * This module supports the iSeries PCI bus interrupt handling - * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp> - * Copyright (C) 2004-2005 IBM 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., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - * - * Change Activity: - * Created, December 13, 2000 by Wayne Holm - * End Change Activity - */ -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/bootmem.h> -#include <linux/irq.h> -#include <linux/spinlock.h> - -#include <asm/paca.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> - -#include "irq.h" -#include "pci.h" -#include "call_pci.h" - -#ifdef CONFIG_PCI - -enum pci_event_type { - pe_bus_created = 0, /* PHB has been created */ - pe_bus_error = 1, /* PHB has failed */ - pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */ - pe_node_failed = 4, /* Multi-adapter bridge has failed */ - pe_node_recovered = 5, /* Multi-adapter bridge has recovered */ - pe_bus_recovered = 12, /* PHB has been recovered */ - pe_unquiese_bus = 18, /* Secondary bus unqiescing */ - pe_bridge_error = 21, /* Bridge Error */ - pe_slot_interrupt = 22 /* Slot interrupt */ -}; - -struct pci_event { - struct HvLpEvent event; - union { - u64 __align; /* Align on an 8-byte boundary */ - struct { - u32 fisr; - HvBusNumber bus_number; - HvSubBusNumber sub_bus_number; - HvAgentId dev_id; - } slot; - struct { - HvBusNumber bus_number; - HvSubBusNumber sub_bus_number; - } bus; - struct { - HvBusNumber bus_number; - HvSubBusNumber sub_bus_number; - HvAgentId dev_id; - } node; - } data; -}; - -static DEFINE_SPINLOCK(pending_irqs_lock); -static int num_pending_irqs; -static int pending_irqs[NR_IRQS]; - -static void int_received(struct pci_event *event) -{ - int irq; - - switch (event->event.xSubtype) { - case pe_slot_interrupt: - irq = event->event.xCorrelationToken; - if (irq < NR_IRQS) { - spin_lock(&pending_irqs_lock); - pending_irqs[irq]++; - num_pending_irqs++; - spin_unlock(&pending_irqs_lock); - } else { - printk(KERN_WARNING "int_received: bad irq number %d\n", - irq); - HvCallPci_eoi(event->data.slot.bus_number, - event->data.slot.sub_bus_number, - event->data.slot.dev_id); - } - break; - /* Ignore error recovery events for now */ - case pe_bus_created: - printk(KERN_INFO "int_received: system bus %d created\n", - event->data.bus.bus_number); - break; - case pe_bus_error: - case pe_bus_failed: - printk(KERN_INFO "int_received: system bus %d failed\n", - event->data.bus.bus_number); - break; - case pe_bus_recovered: - case pe_unquiese_bus: - printk(KERN_INFO "int_received: system bus %d recovered\n", - event->data.bus.bus_number); - break; - case pe_node_failed: - case pe_bridge_error: - printk(KERN_INFO - "int_received: multi-adapter bridge %d/%d/%d failed\n", - event->data.node.bus_number, - event->data.node.sub_bus_number, - event->data.node.dev_id); - break; - case pe_node_recovered: - printk(KERN_INFO - "int_received: multi-adapter bridge %d/%d/%d recovered\n", - event->data.node.bus_number, - event->data.node.sub_bus_number, - event->data.node.dev_id); - break; - default: - printk(KERN_ERR - "int_received: unrecognized event subtype 0x%x\n", - event->event.xSubtype); - break; - } -} - -static void pci_event_handler(struct HvLpEvent *event) -{ - if (event && (event->xType == HvLpEvent_Type_PciIo)) { - if (hvlpevent_is_int(event)) - int_received((struct pci_event *)event); - else - printk(KERN_ERR - "pci_event_handler: unexpected ack received\n"); - } else if (event) - printk(KERN_ERR - "pci_event_handler: Unrecognized PCI event type 0x%x\n", - (int)event->xType); - else - printk(KERN_ERR "pci_event_handler: NULL event received\n"); -} - -#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) -#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) -#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) -#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) - -/* - * This will be called by device drivers (via enable_IRQ) - * to enable INTA in the bridge interrupt status register. - */ -static void iseries_enable_IRQ(struct irq_data *d) -{ - u32 bus, dev_id, function, mask; - const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - - /* The IRQ has already been locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Unmask secondary INTA */ - mask = 0x80000000; - HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask); -} - -/* This is called by iseries_activate_IRQs */ -static unsigned int iseries_startup_IRQ(struct irq_data *d) -{ - u32 bus, dev_id, function, mask; - const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Link the IRQ number to the bridge */ - HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq); - - /* Unmask bridge interrupts in the FISR */ - mask = 0x01010000 << function; - HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); - iseries_enable_IRQ(d); - return 0; -} - -/* - * This is called out of iSeries_fixup to activate interrupt - * generation for usable slots - */ -void __init iSeries_activate_IRQs() -{ - int irq; - unsigned long flags; - - for_each_irq (irq) { - struct irq_desc *desc = irq_to_desc(irq); - struct irq_chip *chip; - - if (!desc) - continue; - - chip = irq_desc_get_chip(desc); - if (chip && chip->irq_startup) { - raw_spin_lock_irqsave(&desc->lock, flags); - chip->irq_startup(&desc->irq_data); - raw_spin_unlock_irqrestore(&desc->lock, flags); - } - } -} - -/* this is not called anywhere currently */ -static void iseries_shutdown_IRQ(struct irq_data *d) -{ - u32 bus, dev_id, function, mask; - const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - - /* irq should be locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Invalidate the IRQ number in the bridge */ - HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0); - - /* Mask bridge interrupts in the FISR */ - mask = 0x01010000 << function; - HvCallPci_maskFisr(bus, sub_bus, dev_id, mask); -} - -/* - * This will be called by device drivers (via disable_IRQ) - * to disable INTA in the bridge interrupt status register. - */ -static void iseries_disable_IRQ(struct irq_data *d) -{ - u32 bus, dev_id, function, mask; - const u32 sub_bus = 0; - unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - - /* The IRQ has already been locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Mask secondary INTA */ - mask = 0x80000000; - HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); -} - -static void iseries_end_IRQ(struct irq_data *d) -{ - unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - - HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), - (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); -} - -static struct irq_chip iseries_pic = { - .name = "iSeries", - .irq_startup = iseries_startup_IRQ, - .irq_shutdown = iseries_shutdown_IRQ, - .irq_unmask = iseries_enable_IRQ, - .irq_mask = iseries_disable_IRQ, - .irq_eoi = iseries_end_IRQ -}; - -/* - * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot - * It calculates the irq value for the slot. - * Note that sub_bus is always 0 (at the moment at least). - */ -int __init iSeries_allocate_IRQ(HvBusNumber bus, - HvSubBusNumber sub_bus, u32 bsubbus) -{ - unsigned int realirq; - u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); - u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); - - realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) - + function; - - return irq_create_mapping(NULL, realirq); -} - -#endif /* CONFIG_PCI */ - -/* - * Get the next pending IRQ. - */ -unsigned int iSeries_get_irq(void) -{ - int irq = NO_IRQ_IGNORE; - -#ifdef CONFIG_SMP - if (get_lppaca()->int_dword.fields.ipi_cnt) { - get_lppaca()->int_dword.fields.ipi_cnt = 0; - smp_ipi_demux(); - } -#endif /* CONFIG_SMP */ - if (hvlpevent_is_pending()) - process_hvlpevents(); - -#ifdef CONFIG_PCI - if (num_pending_irqs) { - spin_lock(&pending_irqs_lock); - for (irq = 0; irq < NR_IRQS; irq++) { - if (pending_irqs[irq]) { - pending_irqs[irq]--; - num_pending_irqs--; - break; - } - } - spin_unlock(&pending_irqs_lock); - if (irq >= NR_IRQS) - irq = NO_IRQ_IGNORE; - } -#endif - - return irq; -} - -#ifdef CONFIG_PCI - -static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) -{ - irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); - - return 0; -} - -static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) -{ - /* Match all */ - return 1; -} - -static struct irq_host_ops iseries_irq_host_ops = { - .map = iseries_irq_host_map, - .match = iseries_irq_host_match, -}; - -/* - * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c - * It must be called before the bus walk. - */ -void __init iSeries_init_IRQ(void) -{ - /* Register PCI event handler and open an event path */ - struct irq_host *host; - int ret; - - /* - * The Hypervisor only allows us up to 256 interrupt - * sources (the irq number is passed in a u8). - */ - irq_set_virq_count(256); - - /* Create irq host. No need for a revmap since HV will give us - * back our virtual irq number - */ - host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &iseries_irq_host_ops, 0); - BUG_ON(host == NULL); - irq_set_default_host(host); - - ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, - &pci_event_handler); - if (ret == 0) { - ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); - if (ret != 0) - printk(KERN_ERR "iseries_init_IRQ: open event path " - "failed with rc 0x%x\n", ret); - } else - printk(KERN_ERR "iseries_init_IRQ: register handler " - "failed with rc 0x%x\n", ret); -} - -#endif /* CONFIG_PCI */ diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h deleted file mode 100644 index a1c236074034..000000000000 --- a/arch/powerpc/platforms/iseries/irq.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _ISERIES_IRQ_H -#define _ISERIES_IRQ_H - -#ifdef CONFIG_PCI -extern void iSeries_init_IRQ(void); -extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32); -extern void iSeries_activate_IRQs(void); -#else -#define iSeries_init_IRQ NULL -#endif -extern unsigned int iSeries_get_irq(void); - -#endif /* _ISERIES_IRQ_H */ diff --git a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h deleted file mode 100644 index 6de9097b7f57..000000000000 --- a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2002 Dave Boutcher IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H -#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H - -/* - * This struct maps the panel information - * - * Warning: - * This data must match the architecture for the panel information - */ - -#include <asm/types.h> - -struct ItExtVpdPanel { - /* Definition of the Extended Vpd On Panel Data Area */ - char systemSerial[8]; - char mfgID[4]; - char reserved1[24]; - char machineType[4]; - char systemID[6]; - char somUniqueCnt[4]; - char serialNumberCount; - char reserved2[7]; - u16 bbu3; - u16 bbu2; - u16 bbu1; - char xLocationLabel[8]; - u8 xRsvd1[6]; - u16 xFrameId; - u8 xRsvd2[48]; -}; - -extern struct ItExtVpdPanel xItExtVpdPanel; - -#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */ diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h deleted file mode 100644 index cf6dcf6ef07b..000000000000 --- a/arch/powerpc/platforms/iseries/it_lp_naca.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H -#define _PLATFORMS_ISERIES_IT_LP_NACA_H - -#include <linux/types.h> - -/* - * This control block contains the data that is shared between the - * hypervisor (PLIC) and the OS. - */ - -struct ItLpNaca { -// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data - u32 xDesc; // Eye catcher x00-x03 - u16 xSize; // Size of this class x04-x05 - u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07 - u8 xMaxIntHdlrEntries; // Number of entries in array x08-x08 - u8 xPrimaryLpIndex; // LP Index of Primary x09-x09 - u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A - u8 xLpIndex; // LP Index x0B-x0B - u16 xMaxLpQueues; // Number of allocated queues x0C-x0D - u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F - u8 xPirEnvironMode; // Piranha or hardware x10-x10 - u8 xPirConsoleMode; // Piranha console indicator x11-x11 - u8 xPirDasdMode; // Piranha dasd indicator x12-x12 - u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x17 - u8 flags; // flags, see below x18-x1F - u8 xSpVpdFormat; // VPD areas are in CSP format ... - u8 xIntProcRatio; // Ratio of int procs to procs ... - u8 xRsvd1_2[5]; // Reserved ... - u16 xRsvd1_3; // Reserved x20-x21 - u16 xPlicVrmIndex; // VRM index of PLIC x22-x23 - u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x25 - u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27 - u64 xLoadAreaAddr; // ER address of load area x28-x2F - u32 xLoadAreaChunks; // Chunks for the load area x30-x33 - u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37 - // doing an ASR switch on PASE - // system call. - u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f - u8 xRsvd1_4[64]; // x40-x7F - -// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data - u8 xRsvd2_0[128]; // Reserved x00-x7F - -// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators -// NB: Padding required to keep xInterruptHdlr at x300 which is required -// for v4r4 PLIC. - u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F - u8 xRsvd3_0[384]; // Reserved 180-2FF - -// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt -// handlers - u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF -}; - -extern struct ItLpNaca itLpNaca; - -#define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */ -#define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */ -#define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */ -#define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */ - -#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */ diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c deleted file mode 100644 index 997e234fb8b7..000000000000 --- a/arch/powerpc/platforms/iseries/ksyms.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) 2001-2005 PPC 64 Team, IBM Corp - * - * 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. - */ -#include <linux/export.h> - -#include <asm/hw_irq.h> -#include <asm/iseries/hv_call_sc.h> - -EXPORT_SYMBOL(HvCall0); -EXPORT_SYMBOL(HvCall1); -EXPORT_SYMBOL(HvCall2); -EXPORT_SYMBOL(HvCall3); -EXPORT_SYMBOL(HvCall4); -EXPORT_SYMBOL(HvCall5); -EXPORT_SYMBOL(HvCall6); -EXPORT_SYMBOL(HvCall7); diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c deleted file mode 100644 index 00e0ec813a1c..000000000000 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2001 Mike Corrigan, IBM Corp - * - * 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. - */ -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/bitops.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/abs_addr.h> -#include <asm/lppaca.h> -#include <asm/paca.h> -#include <asm/iseries/lpar_map.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/alpaca.h> - -#include "naca.h" -#include "vpd_areas.h" -#include "spcomm_area.h" -#include "ipl_parms.h" -#include "processor_vpd.h" -#include "release_data.h" -#include "it_exp_vpd_panel.h" -#include "it_lp_naca.h" - -/* The HvReleaseData is the root of the information shared between - * the hypervisor and Linux. - */ -const struct HvReleaseData hvReleaseData = { - .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ - .xSize = sizeof(struct HvReleaseData), - .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), - .xSlicNacaAddr = &naca, /* 64-bit Naca address */ - .xMsNucDataOffset = LPARMAP_PHYS, - .xFlags = HVREL_TAGSINACTIVE /* tags inactive */ - /* 64 bit */ - /* shared processors */ - /* HMT allowed */ - | 6, /* TEMP: This allows non-GA driver */ - .xVrmIndex = 4, /* We are v5r2m0 */ - .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */ - .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */ - .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */ - 0xa7, 0x40, 0xf2, 0x4b, - 0xf4, 0x4b, 0xf6, 0xf4 }, -}; - -/* - * The NACA. The first dword of the naca is required by the iSeries - * hypervisor to point to itVpdAreas. The hypervisor finds the NACA - * through the pointer in hvReleaseData. - */ -struct naca_struct naca = { - .xItVpdAreas = &itVpdAreas, - .xRamDisk = 0, - .xRamDiskSize = 0, -}; - -struct ItLpRegSave { - u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003 - u16 xSize; // Size of this class 004-005 - u8 xInUse; // Area is live 006-007 - u8 xRsvd1[9]; // Reserved 007-00F - - u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F - u32 xCTRL; // Control Register 170-173 - u32 xDEC; // Decrementer 174-177 - u32 xFPSCR; // FP Status and Control Reg 178-17B - u32 xPVR; // Processor Version Number 17C-17F - - u64 xMMCR0; // Monitor Mode Control Reg 0 180-187 - u32 xPMC1; // Perf Monitor Counter 1 188-18B - u32 xPMC2; // Perf Monitor Counter 2 18C-18F - u32 xPMC3; // Perf Monitor Counter 3 190-193 - u32 xPMC4; // Perf Monitor Counter 4 194-197 - u32 xPIR; // Processor ID Reg 198-19B - - u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F - u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3 - u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7 - u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB - u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF - u32 xPMC8; // Perf Monitor Counter 8 1B0-1B3 - u32 xTSC; // Thread Switch Control 1B4-1B7 - u32 xTST; // Thread Switch Timeout 1B8-1BB - u32 xRsvd; // Reserved 1BC-1BF - - u64 xACCR; // Address Compare Control Reg 1C0-1C7 - u64 xIMR; // Instruction Match Register 1C8-1CF - u64 xSDR1; // Storage Description Reg 1 1D0-1D7 - u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF - u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7 - u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF - u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7 - u64 xTB; // Time Base Register 1F8-1FF - - u64 xFPR[32]; // Floating Point Registers 200-2FF - - u64 xMSR; // Machine State Register 300-307 - u64 xNIA; // Next Instruction Address 308-30F - - u64 xDABR; // Data Address Breakpoint Reg 310-317 - u64 xIABR; // Inst Address Breakpoint Reg 318-31F - - u64 xHID0; // HW Implementation Dependent0 320-327 - - u64 xHID4; // HW Implementation Dependent4 328-32F - u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337 - u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F - u64 xSDAR; // Sample Data Address Register 340-347 - u64 xSIAR; // Sample Inst Address Register 348-34F - - u8 xRsvd3[176]; // Reserved 350-3FF -}; - -extern void system_reset_iSeries(void); -extern void machine_check_iSeries(void); -extern void data_access_iSeries(void); -extern void instruction_access_iSeries(void); -extern void hardware_interrupt_iSeries(void); -extern void alignment_iSeries(void); -extern void program_check_iSeries(void); -extern void fp_unavailable_iSeries(void); -extern void decrementer_iSeries(void); -extern void trap_0a_iSeries(void); -extern void trap_0b_iSeries(void); -extern void system_call_iSeries(void); -extern void single_step_iSeries(void); -extern void trap_0e_iSeries(void); -extern void performance_monitor_iSeries(void); -extern void data_access_slb_iSeries(void); -extern void instruction_access_slb_iSeries(void); - -struct ItLpNaca itLpNaca = { - .xDesc = 0xd397d581, /* "LpNa" ebcdic */ - .xSize = 0x0400, /* size of ItLpNaca */ - .xIntHdlrOffset = 0x0300, /* offset to int array */ - .xMaxIntHdlrEntries = 19, /* # ents */ - .xPrimaryLpIndex = 0, /* Part # of primary */ - .xServiceLpIndex = 0, /* Part # of serv */ - .xLpIndex = 0, /* Part # of me */ - .xMaxLpQueues = 0, /* # of LP queues */ - .xLpQueueOffset = 0x100, /* offset of start of LP queues */ - .xPirEnvironMode = 0, /* Piranha stuff */ - .xPirConsoleMode = 0, - .xPirDasdMode = 0, - .flags = 0, - .xSpVpdFormat = 0, - .xIntProcRatio = 0, - .xPlicVrmIndex = 0, /* VRM index of PLIC */ - .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */ - .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */ - .xLoadAreaAddr = 0, /* 64-bit addr of load area */ - .xLoadAreaChunks = 0, /* chunks for load area */ - .xPaseSysCallCRMask = 0, /* PASE mask */ - .xSlicSegmentTablePtr = 0, /* seg table */ - .xOldLpQueue = { 0 }, /* Old LP Queue */ - .xInterruptHdlr = { - (u64)system_reset_iSeries, /* 0x100 System Reset */ - (u64)machine_check_iSeries, /* 0x200 Machine Check */ - (u64)data_access_iSeries, /* 0x300 Data Access */ - (u64)instruction_access_iSeries, /* 0x400 Instruction Access */ - (u64)hardware_interrupt_iSeries, /* 0x500 External */ - (u64)alignment_iSeries, /* 0x600 Alignment */ - (u64)program_check_iSeries, /* 0x700 Program Check */ - (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */ - (u64)decrementer_iSeries, /* 0x900 Decrementer */ - (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */ - (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */ - (u64)system_call_iSeries, /* 0xc00 System Call */ - (u64)single_step_iSeries, /* 0xd00 Single Step */ - (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */ - (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */ - 0, /* int 0x1000 */ - 0, /* int 0x1010 */ - 0, /* int 0x1020 CPU ctls */ - (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */ - (u64)data_access_slb_iSeries, /* 0x380 D-SLB */ - (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */ - } -}; - -/* May be filled in by the hypervisor so cannot end up in the BSS */ -static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); - -/* May be filled in by the hypervisor so cannot end up in the BSS */ -struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); - -#define maxPhysicalProcessors 32 - -struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = { - { - .xInstCacheOperandSize = 32, - .xDataCacheOperandSize = 32, - .xProcFreq = 50000000, - .xTimeBaseFreq = 50000000, - .xPVR = 0x3600 - } -}; - -/* Space for Main Store Vpd 27,200 bytes */ -/* May be filled in by the hypervisor so cannot end up in the BSS */ -u64 xMsVpd[3400] __attribute__((__section__(".data"))); - -/* Space for Recovery Log Buffer */ -/* May be filled in by the hypervisor so cannot end up in the BSS */ -static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); - -static const struct SpCommArea xSpCommArea = { - .xDesc = 0xE2D7C3C2, - .xFormat = 1, -}; - -static const struct ItLpRegSave iseries_reg_save[] = { - [0 ... (NR_CPUS-1)] = { - .xDesc = 0xd397d9e2, /* "LpRS" */ - .xSize = sizeof(struct ItLpRegSave), - }, -}; - -#define ALPACA_INIT(number) \ -{ \ - .lppaca_ptr = &lppaca[number], \ - .reg_save_ptr = &iseries_reg_save[number], \ -} - -const struct alpaca alpaca[] = { - ALPACA_INIT( 0), -#if NR_CPUS > 1 - ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3), -#if NR_CPUS > 4 - ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7), -#if NR_CPUS > 8 - ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11), - ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15), - ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19), - ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23), - ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27), - ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31), -#if NR_CPUS > 32 - ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35), - ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39), - ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43), - ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47), - ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51), - ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55), - ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59), - ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63), -#endif -#endif -#endif -#endif -}; - -/* The LparMap data is now located at offset 0x6000 in head.S - * It was put there so that the HvReleaseData could address it - * with a 32-bit offset as required by the iSeries hypervisor - * - * The Naca has a pointer to the ItVpdAreas. The hypervisor finds - * the Naca via the HvReleaseData area. The HvReleaseData has the - * offset into the Naca of the pointer to the ItVpdAreas. - */ -const struct ItVpdAreas itVpdAreas = { - .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */ - .xSlicSize = sizeof(struct ItVpdAreas), - .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */ - .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */ - .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */ - .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */ - .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks), - .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs), - .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens), - .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens), - .xSlicMaxSlotLabels = 0, /* max slot labels */ - .xSlicMaxLpQueues = 1, /* max LP queues */ - .xPlicDmaLens = { 0 }, /* DMA lengths */ - .xPlicDmaToks = { 0 }, /* DMA tokens */ - .xSlicVpdLens = { /* VPD lengths */ - 0,0,0, /* 0 - 2 */ - sizeof(xItExtVpdPanel), /* 3 Extended VPD */ - sizeof(struct alpaca), /* 4 length of (fake) Paca */ - 0, /* 5 */ - sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ - 26992, /* 7 length of MS VPD */ - 0, /* 8 */ - sizeof(struct ItLpNaca),/* 9 length of LP Naca */ - 0, /* 10 */ - 256, /* 11 length of Recovery Log Buf */ - sizeof(struct SpCommArea), /* 12 length of SP Comm Area */ - 0,0,0, /* 13 - 15 */ - sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */ - 0,0,0,0,0,0, /* 17 - 22 */ - sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */ - 0,0 /* 24 - 25 */ - }, - .xSlicVpdAdrs = { /* VPD addresses */ - 0,0,0, /* 0 - 2 */ - &xItExtVpdPanel, /* 3 Extended VPD */ - &alpaca[0], /* 4 first (fake) Paca */ - 0, /* 5 */ - &xItIplParmsReal, /* 6 IPL parms */ - &xMsVpd, /* 7 MS Vpd */ - 0, /* 8 */ - &itLpNaca, /* 9 LpNaca */ - 0, /* 10 */ - &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */ - &xSpCommArea, /* 12 SP Comm Area */ - 0,0,0, /* 13 - 15 */ - &xIoHriProcessorVpd, /* 16 Proc Vpd */ - 0,0,0,0,0,0, /* 17 - 22 */ - &hvlpevent_queue, /* 23 Lp Queue */ - 0,0 - } -}; diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c deleted file mode 100644 index 202e22798d30..000000000000 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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. - */ - -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/proc_fs.h> -#include <linux/export.h> - -#include <asm/system.h> -#include <asm/paca.h> -#include <asm/firmware.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_event.h> -#include "it_lp_naca.h" - -/* - * The LpQueue is used to pass event data from the hypervisor to - * the partition. This is where I/O interrupt events are communicated. - * - * It is written to by the hypervisor so cannot end up in the BSS. - */ -struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); - -DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); - -static char *event_types[HvLpEvent_Type_NumTypes] = { - "Hypervisor", - "Machine Facilities", - "Session Manager", - "SPD I/O", - "Virtual Bus", - "PCI I/O", - "RIO I/O", - "Virtual Lan", - "Virtual I/O" -}; - -/* Array of LpEvent handler functions */ -static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; -static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; - -static struct HvLpEvent * get_next_hvlpevent(void) -{ - struct HvLpEvent * event; - event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; - - if (hvlpevent_is_valid(event)) { - /* rmb() needed only for weakly consistent machines (regatta) */ - rmb(); - /* Set pointer to next potential event */ - hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 + - IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) * - IT_LP_EVENT_ALIGN; - - /* Wrap to beginning if no room at end */ - if (hvlpevent_queue.hq_current_event > - hvlpevent_queue.hq_last_event) { - hvlpevent_queue.hq_current_event = - hvlpevent_queue.hq_event_stack; - } - } else { - event = NULL; - } - - return event; -} - -static unsigned long spread_lpevents = NR_CPUS; - -int hvlpevent_is_pending(void) -{ - struct HvLpEvent *next_event; - - if (smp_processor_id() >= spread_lpevents) - return 0; - - next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; - - return hvlpevent_is_valid(next_event) || - hvlpevent_queue.hq_overflow_pending; -} - -static void hvlpevent_clear_valid(struct HvLpEvent * event) -{ - /* Tell the Hypervisor that we're done with this event. - * Also clear bits within this event that might look like valid bits. - * ie. on 64-byte boundaries. - */ - struct HvLpEvent *tmp; - unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) / - IT_LP_EVENT_ALIGN) - 1; - - switch (extra) { - case 3: - tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN); - hvlpevent_invalidate(tmp); - case 2: - tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN); - hvlpevent_invalidate(tmp); - case 1: - tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN); - hvlpevent_invalidate(tmp); - } - - mb(); - - hvlpevent_invalidate(event); -} - -void process_hvlpevents(void) -{ - struct HvLpEvent * event; - - restart: - /* If we have recursed, just return */ - if (!spin_trylock(&hvlpevent_queue.hq_lock)) - return; - - for (;;) { - event = get_next_hvlpevent(); - if (event) { - /* Call appropriate handler here, passing - * a pointer to the LpEvent. The handler - * must make a copy of the LpEvent if it - * needs it in a bottom half. (perhaps for - * an ACK) - * - * Handlers are responsible for ACK processing - * - * The Hypervisor guarantees that LpEvents will - * only be delivered with types that we have - * registered for, so no type check is necessary - * here! - */ - if (event->xType < HvLpEvent_Type_NumTypes) - __get_cpu_var(hvlpevent_counts)[event->xType]++; - if (event->xType < HvLpEvent_Type_NumTypes && - lpEventHandler[event->xType]) - lpEventHandler[event->xType](event); - else { - u8 type = event->xType; - - /* - * Don't printk in the spinlock as printk - * may require ack events form the HV to send - * any characters there. - */ - hvlpevent_clear_valid(event); - spin_unlock(&hvlpevent_queue.hq_lock); - printk(KERN_INFO - "Unexpected Lp Event type=%d\n", type); - goto restart; - } - - hvlpevent_clear_valid(event); - } else if (hvlpevent_queue.hq_overflow_pending) - /* - * No more valid events. If overflow events are - * pending process them - */ - HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index); - else - break; - } - - spin_unlock(&hvlpevent_queue.hq_lock); -} - -static int set_spread_lpevents(char *str) -{ - unsigned long val = simple_strtoul(str, NULL, 0); - - /* - * The parameter is the number of processors to share in processing - * lp events. - */ - if (( val > 0) && (val <= NR_CPUS)) { - spread_lpevents = val; - printk("lpevent processing spread over %ld processors\n", val); - } else { - printk("invalid spread_lpevents %ld\n", val); - } - - return 1; -} -__setup("spread_lpevents=", set_spread_lpevents); - -void __init setup_hvlpevent_queue(void) -{ - void *eventStack; - - spin_lock_init(&hvlpevent_queue.hq_lock); - - /* Allocate a page for the Event Stack. */ - eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE); - memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE); - - /* Invoke the hypervisor to initialize the event stack */ - HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE); - - hvlpevent_queue.hq_event_stack = eventStack; - hvlpevent_queue.hq_current_event = eventStack; - hvlpevent_queue.hq_last_event = (char *)eventStack + - (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE); - hvlpevent_queue.hq_index = 0; -} - -/* Register a handler for an LpEvent type */ -int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler) -{ - if (eventType < HvLpEvent_Type_NumTypes) { - lpEventHandler[eventType] = handler; - return 0; - } - return 1; -} -EXPORT_SYMBOL(HvLpEvent_registerHandler); - -int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType) -{ - might_sleep(); - - if (eventType < HvLpEvent_Type_NumTypes) { - if (!lpEventHandlerPaths[eventType]) { - lpEventHandler[eventType] = NULL; - /* - * We now sleep until all other CPUs have scheduled. - * This ensures that the deletion is seen by all - * other CPUs, and that the deleted handler isn't - * still running on another CPU when we return. - */ - synchronize_sched(); - return 0; - } - } - return 1; -} -EXPORT_SYMBOL(HvLpEvent_unregisterHandler); - -/* - * lpIndex is the partition index of the target partition. - * needed only for VirtualIo, VirtualLan and SessionMgr. Zero - * indicates to use our partition index - for the other types. - */ -int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex) -{ - if ((eventType < HvLpEvent_Type_NumTypes) && - lpEventHandler[eventType]) { - if (lpIndex == 0) - lpIndex = itLpNaca.xLpIndex; - HvCallEvent_openLpEventPath(lpIndex, eventType); - ++lpEventHandlerPaths[eventType]; - return 0; - } - return 1; -} - -int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex) -{ - if ((eventType < HvLpEvent_Type_NumTypes) && - lpEventHandler[eventType] && - lpEventHandlerPaths[eventType]) { - if (lpIndex == 0) - lpIndex = itLpNaca.xLpIndex; - HvCallEvent_closeLpEventPath(lpIndex, eventType); - --lpEventHandlerPaths[eventType]; - return 0; - } - return 1; -} - -static int proc_lpevents_show(struct seq_file *m, void *v) -{ - int cpu, i; - unsigned long sum; - static unsigned long cpu_totals[NR_CPUS]; - - /* FIXME: do we care that there's no locking here? */ - sum = 0; - for_each_online_cpu(cpu) { - cpu_totals[cpu] = 0; - for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { - cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; - } - sum += cpu_totals[cpu]; - } - - seq_printf(m, "LpEventQueue 0\n"); - seq_printf(m, " events processed:\t%lu\n", sum); - - for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { - sum = 0; - for_each_online_cpu(cpu) { - sum += per_cpu(hvlpevent_counts, cpu)[i]; - } - - seq_printf(m, " %-20s %10lu\n", event_types[i], sum); - } - - seq_printf(m, "\n events processed by processor:\n"); - - for_each_online_cpu(cpu) { - seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]); - } - - return 0; -} - -static int proc_lpevents_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_lpevents_show, NULL); -} - -static const struct file_operations proc_lpevents_operations = { - .open = proc_lpevents_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_lpevents_init(void) -{ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; - - proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL, - &proc_lpevents_operations); - return 0; -} -__initcall(proc_lpevents_init); - diff --git a/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h deleted file mode 100644 index 1a7a3f50e40b..000000000000 --- a/arch/powerpc/platforms/iseries/main_store.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ISERIES_MAIN_STORE_H -#define _ISERIES_MAIN_STORE_H - -/* Main Store Vpd for Condor,iStar,sStar */ -struct IoHriMainStoreSegment4 { - u8 msArea0Exists:1; - u8 msArea1Exists:1; - u8 msArea2Exists:1; - u8 msArea3Exists:1; - u8 reserved1:4; - u8 reserved2; - - u8 msArea0Functional:1; - u8 msArea1Functional:1; - u8 msArea2Functional:1; - u8 msArea3Functional:1; - u8 reserved3:4; - u8 reserved4; - - u32 totalMainStore; - - u64 msArea0Ptr; - u64 msArea1Ptr; - u64 msArea2Ptr; - u64 msArea3Ptr; - - u32 cardProductionLevel; - - u32 msAdrHole; - - u8 msArea0HasRiserVpd:1; - u8 msArea1HasRiserVpd:1; - u8 msArea2HasRiserVpd:1; - u8 msArea3HasRiserVpd:1; - u8 reserved5:4; - u8 reserved6; - u16 reserved7; - - u8 reserved8[28]; - - u64 nonInterleavedBlocksStartAdr; - u64 nonInterleavedBlocksEndAdr; -}; - -/* Main Store VPD for Power4 */ -struct __attribute((packed)) IoHriMainStoreChipInfo1 { - u32 chipMfgID; - char chipECLevel[4]; -}; - -struct IoHriMainStoreVpdIdData { - char typeNumber[4]; - char modelNumber[4]; - char partNumber[12]; - char serialNumber[12]; -}; - -struct __attribute((packed)) IoHriMainStoreVpdFruData { - char fruLabel[8]; - u8 numberOfSlots; - u8 pluggingType; - u16 slotMapIndex; -}; - -struct __attribute((packed)) IoHriMainStoreAdrRangeBlock { - void *blockStart; - void *blockEnd; - u32 blockProcChipId; -}; - -#define MaxAreaAdrRangeBlocks 4 - -struct __attribute((packed)) IoHriMainStoreArea4 { - u32 msVpdFormat; - u8 containedVpdType; - u8 reserved1; - u16 reserved2; - - u64 msExists; - u64 msFunctional; - - u32 memorySize; - u32 procNodeId; - - u32 numAdrRangeBlocks; - struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks]; - - struct IoHriMainStoreChipInfo1 chipInfo0; - struct IoHriMainStoreChipInfo1 chipInfo1; - struct IoHriMainStoreChipInfo1 chipInfo2; - struct IoHriMainStoreChipInfo1 chipInfo3; - struct IoHriMainStoreChipInfo1 chipInfo4; - struct IoHriMainStoreChipInfo1 chipInfo5; - struct IoHriMainStoreChipInfo1 chipInfo6; - struct IoHriMainStoreChipInfo1 chipInfo7; - - void *msRamAreaArray; - u32 msRamAreaArrayNumEntries; - u32 msRamAreaArrayEntrySize; - - u32 numaDimmExists; - u32 numaDimmFunctional; - void *numaDimmArray; - u32 numaDimmArrayNumEntries; - u32 numaDimmArrayEntrySize; - - struct IoHriMainStoreVpdIdData idData; - - u64 powerData; - u64 cardAssemblyPartNum; - u64 chipSerialNum; - - u64 reserved3; - char reserved4[16]; - - struct IoHriMainStoreVpdFruData fruData; - - u8 vpdPortNum; - u8 reserved5; - u8 frameId; - u8 rackUnit; - char asciiKeywordVpd[256]; - u32 reserved6; -}; - - -struct IoHriMainStoreSegment5 { - u16 reserved1; - u8 reserved2; - u8 msVpdFormat; - - u32 totalMainStore; - u64 maxConfiguredMsAdr; - - struct IoHriMainStoreArea4 *msAreaArray; - u32 msAreaArrayNumEntries; - u32 msAreaArrayEntrySize; - - u32 msAreaExists; - u32 msAreaFunctional; - - u64 reserved3; -}; - -extern u64 xMsVpd[]; - -#endif /* _ISERIES_MAIN_STORE_H */ diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c deleted file mode 100644 index 254c1fc3d8dd..000000000000 --- a/arch/powerpc/platforms/iseries/mf.c +++ /dev/null @@ -1,1275 +0,0 @@ -/* - * Copyright (C) 2001 Troy D. Armstrong IBM Corporation - * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation - * - * This modules exists as an interface between a Linux secondary partition - * running on an iSeries and the primary partition's Virtual Service - * Processor (VSP) object. The VSP has final authority over powering on/off - * all partitions in the iSeries. It also provides miscellaneous low-level - * machine facility type operations. - * - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/export.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/bcd.h> -#include <linux/rtc.h> -#include <linux/slab.h> - -#include <asm/time.h> -#include <asm/uaccess.h> -#include <asm/paca.h> -#include <asm/abs_addr.h> -#include <asm/firmware.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/it_lp_queue.h> - -#include "setup.h" - -static int mf_initialized; - -/* - * This is the structure layout for the Machine Facilities LPAR event - * flows. - */ -struct vsp_cmd_data { - u64 token; - u16 cmd; - HvLpIndex lp_index; - u8 result_code; - u32 reserved; - union { - u64 state; /* GetStateOut */ - u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */ - u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */ - u64 page[4]; /* GetSrcHistoryIn */ - u64 flag; /* GetAutoIplWhenPrimaryIplsOut, - SetAutoIplWhenPrimaryIplsIn, - WhiteButtonPowerOffIn, - Function08FastPowerOffIn, - IsSpcnRackPowerIncompleteOut */ - struct { - u64 token; - u64 address_type; - u64 side; - u32 length; - u32 offset; - } kern; /* SetKernelImageIn, GetKernelImageIn, - SetKernelCmdLineIn, GetKernelCmdLineIn */ - u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */ - u8 reserved[80]; - } sub_data; -}; - -struct vsp_rsp_data { - struct completion com; - struct vsp_cmd_data *response; -}; - -struct alloc_data { - u16 size; - u16 type; - u32 count; - u16 reserved1; - u8 reserved2; - HvLpIndex target_lp; -}; - -struct ce_msg_data; - -typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp); - -struct ce_msg_comp_data { - ce_msg_comp_hdlr handler; - void *token; -}; - -struct ce_msg_data { - u8 ce_msg[12]; - char reserved[4]; - struct ce_msg_comp_data *completion; -}; - -struct io_mf_lp_event { - struct HvLpEvent hp_lp_event; - u16 subtype_result_code; - u16 reserved1; - u32 reserved2; - union { - struct alloc_data alloc; - struct ce_msg_data ce_msg; - struct vsp_cmd_data vsp_cmd; - } data; -}; - -#define subtype_data(a, b, c, d) \ - (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -/* - * All outgoing event traffic is kept on a FIFO queue. The first - * pointer points to the one that is outstanding, and all new - * requests get stuck on the end. Also, we keep a certain number of - * preallocated pending events so that we can operate very early in - * the boot up sequence (before kmalloc is ready). - */ -struct pending_event { - struct pending_event *next; - struct io_mf_lp_event event; - MFCompleteHandler hdlr; - char dma_data[72]; - unsigned dma_data_length; - unsigned remote_address; -}; -static spinlock_t pending_event_spinlock; -static struct pending_event *pending_event_head; -static struct pending_event *pending_event_tail; -static struct pending_event *pending_event_avail; -#define PENDING_EVENT_PREALLOC_LEN 16 -static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN]; - -/* - * Put a pending event onto the available queue, so it can get reused. - * Attention! You must have the pending_event_spinlock before calling! - */ -static void free_pending_event(struct pending_event *ev) -{ - if (ev != NULL) { - ev->next = pending_event_avail; - pending_event_avail = ev; - } -} - -/* - * Enqueue the outbound event onto the stack. If the queue was - * empty to begin with, we must also issue it via the Hypervisor - * interface. There is a section of code below that will touch - * the first stack pointer without the protection of the pending_event_spinlock. - * This is OK, because we know that nobody else will be modifying - * the first pointer when we do this. - */ -static int signal_event(struct pending_event *ev) -{ - int rc = 0; - unsigned long flags; - int go = 1; - struct pending_event *ev1; - HvLpEvent_Rc hv_rc; - - /* enqueue the event */ - if (ev != NULL) { - ev->next = NULL; - spin_lock_irqsave(&pending_event_spinlock, flags); - if (pending_event_head == NULL) - pending_event_head = ev; - else { - go = 0; - pending_event_tail->next = ev; - } - pending_event_tail = ev; - spin_unlock_irqrestore(&pending_event_spinlock, flags); - } - - /* send the event */ - while (go) { - go = 0; - - /* any DMA data to send beforehand? */ - if (pending_event_head->dma_data_length > 0) - HvCallEvent_dmaToSp(pending_event_head->dma_data, - pending_event_head->remote_address, - pending_event_head->dma_data_length, - HvLpDma_Direction_LocalToRemote); - - hv_rc = HvCallEvent_signalLpEvent( - &pending_event_head->event.hp_lp_event); - if (hv_rc != HvLpEvent_Rc_Good) { - printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() " - "failed with %d\n", (int)hv_rc); - - spin_lock_irqsave(&pending_event_spinlock, flags); - ev1 = pending_event_head; - pending_event_head = pending_event_head->next; - if (pending_event_head != NULL) - go = 1; - spin_unlock_irqrestore(&pending_event_spinlock, flags); - - if (ev1 == ev) - rc = -EIO; - else if (ev1->hdlr != NULL) - (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO); - - spin_lock_irqsave(&pending_event_spinlock, flags); - free_pending_event(ev1); - spin_unlock_irqrestore(&pending_event_spinlock, flags); - } - } - - return rc; -} - -/* - * Allocate a new pending_event structure, and initialize it. - */ -static struct pending_event *new_pending_event(void) -{ - struct pending_event *ev = NULL; - HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex(); - unsigned long flags; - struct HvLpEvent *hev; - - spin_lock_irqsave(&pending_event_spinlock, flags); - if (pending_event_avail != NULL) { - ev = pending_event_avail; - pending_event_avail = pending_event_avail->next; - } - spin_unlock_irqrestore(&pending_event_spinlock, flags); - if (ev == NULL) { - ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC); - if (ev == NULL) { - printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", - sizeof(struct pending_event)); - return NULL; - } - } - memset(ev, 0, sizeof(struct pending_event)); - hev = &ev->event.hp_lp_event; - hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT; - hev->xType = HvLpEvent_Type_MachineFac; - hev->xSourceLp = HvLpConfig_getLpIndex(); - hev->xTargetLp = primary_lp; - hev->xSizeMinus1 = sizeof(ev->event) - 1; - hev->xRc = HvLpEvent_Rc_Good; - hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp, - HvLpEvent_Type_MachineFac); - hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp, - HvLpEvent_Type_MachineFac); - - return ev; -} - -static int __maybe_unused -signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) -{ - struct pending_event *ev = new_pending_event(); - int rc; - struct vsp_rsp_data response; - - if (ev == NULL) - return -ENOMEM; - - init_completion(&response.com); - response.response = vsp_cmd; - ev->event.hp_lp_event.xSubtype = 6; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'V', 'I'); - ev->event.data.vsp_cmd.token = (u64)&response; - ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd; - ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); - ev->event.data.vsp_cmd.result_code = 0xFF; - ev->event.data.vsp_cmd.reserved = 0; - memcpy(&(ev->event.data.vsp_cmd.sub_data), - &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data)); - mb(); - - rc = signal_event(ev); - if (rc == 0) - wait_for_completion(&response.com); - return rc; -} - - -/* - * Send a 12-byte CE message to the primary partition VSP object - */ -static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion) -{ - struct pending_event *ev = new_pending_event(); - - if (ev == NULL) - return -ENOMEM; - - ev->event.hp_lp_event.xSubtype = 0; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'C', 'E'); - memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); - ev->event.data.ce_msg.completion = completion; - return signal_event(ev); -} - -/* - * Send a 12-byte CE message (with no data) to the primary partition VSP object - */ -static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion) -{ - u8 ce_msg[12]; - - memset(ce_msg, 0, sizeof(ce_msg)); - ce_msg[3] = ce_op; - return signal_ce_msg(ce_msg, completion); -} - -/* - * Send a 12-byte CE message and DMA data to the primary partition VSP object - */ -static int dma_and_signal_ce_msg(char *ce_msg, - struct ce_msg_comp_data *completion, void *dma_data, - unsigned dma_data_length, unsigned remote_address) -{ - struct pending_event *ev = new_pending_event(); - - if (ev == NULL) - return -ENOMEM; - - ev->event.hp_lp_event.xSubtype = 0; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'C', 'E'); - memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); - ev->event.data.ce_msg.completion = completion; - memcpy(ev->dma_data, dma_data, dma_data_length); - ev->dma_data_length = dma_data_length; - ev->remote_address = remote_address; - return signal_event(ev); -} - -/* - * Initiate a nice (hopefully) shutdown of Linux. We simply are - * going to try and send the init process a SIGINT signal. If - * this fails (why?), we'll simply force it off in a not-so-nice - * manner. - */ -static int shutdown(void) -{ - int rc = kill_cad_pid(SIGINT, 1); - - if (rc) { - printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " - "hard shutdown commencing\n", rc); - mf_power_off(); - } else - printk(KERN_INFO "mf.c: init has been successfully notified " - "to proceed with shutdown\n"); - return rc; -} - -/* - * The primary partition VSP object is sending us a new - * event flow. Handle it... - */ -static void handle_int(struct io_mf_lp_event *event) -{ - struct ce_msg_data *ce_msg_data; - struct ce_msg_data *pce_msg_data; - unsigned long flags; - struct pending_event *pev; - - /* ack the interrupt */ - event->hp_lp_event.xRc = HvLpEvent_Rc_Good; - HvCallEvent_ackLpEvent(&event->hp_lp_event); - - /* process interrupt */ - switch (event->hp_lp_event.xSubtype) { - case 0: /* CE message */ - ce_msg_data = &event->data.ce_msg; - switch (ce_msg_data->ce_msg[3]) { - case 0x5B: /* power control notification */ - if ((ce_msg_data->ce_msg[5] & 0x20) != 0) { - printk(KERN_INFO "mf.c: Commencing partition shutdown\n"); - if (shutdown() == 0) - signal_ce_msg_simple(0xDB, NULL); - } - break; - case 0xC0: /* get time */ - spin_lock_irqsave(&pending_event_spinlock, flags); - pev = pending_event_head; - if (pev != NULL) - pending_event_head = pending_event_head->next; - spin_unlock_irqrestore(&pending_event_spinlock, flags); - if (pev == NULL) - break; - pce_msg_data = &pev->event.data.ce_msg; - if (pce_msg_data->ce_msg[3] != 0x40) - break; - if (pce_msg_data->completion != NULL) { - ce_msg_comp_hdlr handler = - pce_msg_data->completion->handler; - void *token = pce_msg_data->completion->token; - - if (handler != NULL) - (*handler)(token, ce_msg_data); - } - spin_lock_irqsave(&pending_event_spinlock, flags); - free_pending_event(pev); - spin_unlock_irqrestore(&pending_event_spinlock, flags); - /* send next waiting event */ - if (pending_event_head != NULL) - signal_event(NULL); - break; - } - break; - case 1: /* IT sys shutdown */ - printk(KERN_INFO "mf.c: Commencing system shutdown\n"); - shutdown(); - break; - } -} - -/* - * The primary partition VSP object is acknowledging the receipt - * of a flow we sent to them. If there are other flows queued - * up, we must send another one now... - */ -static void handle_ack(struct io_mf_lp_event *event) -{ - unsigned long flags; - struct pending_event *two = NULL; - unsigned long free_it = 0; - struct ce_msg_data *ce_msg_data; - struct ce_msg_data *pce_msg_data; - struct vsp_rsp_data *rsp; - - /* handle current event */ - if (pending_event_head == NULL) { - printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); - return; - } - - switch (event->hp_lp_event.xSubtype) { - case 0: /* CE msg */ - ce_msg_data = &event->data.ce_msg; - if (ce_msg_data->ce_msg[3] != 0x40) { - free_it = 1; - break; - } - if (ce_msg_data->ce_msg[2] == 0) - break; - free_it = 1; - pce_msg_data = &pending_event_head->event.data.ce_msg; - if (pce_msg_data->completion != NULL) { - ce_msg_comp_hdlr handler = - pce_msg_data->completion->handler; - void *token = pce_msg_data->completion->token; - - if (handler != NULL) - (*handler)(token, ce_msg_data); - } - break; - case 4: /* allocate */ - case 5: /* deallocate */ - if (pending_event_head->hdlr != NULL) - (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); - free_it = 1; - break; - case 6: - free_it = 1; - rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; - if (rsp == NULL) { - printk(KERN_ERR "mf.c: no rsp\n"); - break; - } - if (rsp->response != NULL) - memcpy(rsp->response, &event->data.vsp_cmd, - sizeof(event->data.vsp_cmd)); - complete(&rsp->com); - break; - } - - /* remove from queue */ - spin_lock_irqsave(&pending_event_spinlock, flags); - if ((pending_event_head != NULL) && (free_it == 1)) { - struct pending_event *oldHead = pending_event_head; - - pending_event_head = pending_event_head->next; - two = pending_event_head; - free_pending_event(oldHead); - } - spin_unlock_irqrestore(&pending_event_spinlock, flags); - - /* send next waiting event */ - if (two != NULL) - signal_event(NULL); -} - -/* - * This is the generic event handler we are registering with - * the Hypervisor. Ensure the flows are for us, and then - * parse it enough to know if it is an interrupt or an - * acknowledge. - */ -static void hv_handler(struct HvLpEvent *event) -{ - if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { - if (hvlpevent_is_ack(event)) - handle_ack((struct io_mf_lp_event *)event); - else - handle_int((struct io_mf_lp_event *)event); - } else - printk(KERN_ERR "mf.c: alien event received\n"); -} - -/* - * Global kernel interface to allocate and seed events into the - * Hypervisor. - */ -void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, - unsigned size, unsigned count, MFCompleteHandler hdlr, - void *user_token) -{ - struct pending_event *ev = new_pending_event(); - int rc; - - if (ev == NULL) { - rc = -ENOMEM; - } else { - ev->event.hp_lp_event.xSubtype = 4; - ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'M', 'A'); - ev->event.data.alloc.target_lp = target_lp; - ev->event.data.alloc.type = type; - ev->event.data.alloc.size = size; - ev->event.data.alloc.count = count; - ev->hdlr = hdlr; - rc = signal_event(ev); - } - if ((rc != 0) && (hdlr != NULL)) - (*hdlr)(user_token, rc); -} -EXPORT_SYMBOL(mf_allocate_lp_events); - -/* - * Global kernel interface to unseed and deallocate events already in - * Hypervisor. - */ -void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, - unsigned count, MFCompleteHandler hdlr, void *user_token) -{ - struct pending_event *ev = new_pending_event(); - int rc; - - if (ev == NULL) - rc = -ENOMEM; - else { - ev->event.hp_lp_event.xSubtype = 5; - ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'M', 'D'); - ev->event.data.alloc.target_lp = target_lp; - ev->event.data.alloc.type = type; - ev->event.data.alloc.count = count; - ev->hdlr = hdlr; - rc = signal_event(ev); - } - if ((rc != 0) && (hdlr != NULL)) - (*hdlr)(user_token, rc); -} -EXPORT_SYMBOL(mf_deallocate_lp_events); - -/* - * Global kernel interface to tell the VSP object in the primary - * partition to power this partition off. - */ -void mf_power_off(void) -{ - printk(KERN_INFO "mf.c: Down it goes...\n"); - signal_ce_msg_simple(0x4d, NULL); - for (;;) - ; -} - -/* - * Global kernel interface to tell the VSP object in the primary - * partition to reboot this partition. - */ -void mf_reboot(char *cmd) -{ - printk(KERN_INFO "mf.c: Preparing to bounce...\n"); - signal_ce_msg_simple(0x4e, NULL); - for (;;) - ; -} - -/* - * Display a single word SRC onto the VSP control panel. - */ -void mf_display_src(u32 word) -{ - u8 ce[12]; - - memset(ce, 0, sizeof(ce)); - ce[3] = 0x4a; - ce[7] = 0x01; - ce[8] = word >> 24; - ce[9] = word >> 16; - ce[10] = word >> 8; - ce[11] = word; - signal_ce_msg(ce, NULL); -} - -/* - * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. - */ -static __init void mf_display_progress_src(u16 value) -{ - u8 ce[12]; - u8 src[72]; - - memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); - memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00PROGxxxx ", - 72); - src[6] = value >> 8; - src[7] = value & 255; - src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; - src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; - src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; - src[47] = "0123456789ABCDEF"[value & 15]; - dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024); -} - -/* - * Clear the VSP control panel. Used to "erase" an SRC that was - * previously displayed. - */ -static void mf_clear_src(void) -{ - signal_ce_msg_simple(0x4b, NULL); -} - -void __init mf_display_progress(u16 value) -{ - if (!mf_initialized) - return; - - if (0xFFFF == value) - mf_clear_src(); - else - mf_display_progress_src(value); -} - -/* - * Initialization code here. - */ -void __init mf_init(void) -{ - int i; - - spin_lock_init(&pending_event_spinlock); - - for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++) - free_pending_event(&pending_event_prealloc[i]); - - HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); - - /* virtual continue ack */ - signal_ce_msg_simple(0x57, NULL); - - mf_initialized = 1; - mb(); - - printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " - "initialized\n"); -} - -struct rtc_time_data { - struct completion com; - struct ce_msg_data ce_msg; - int rc; -}; - -static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) -{ - struct rtc_time_data *rtc = token; - - memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); - rtc->rc = 0; - complete(&rtc->com); -} - -static int mf_set_rtc(struct rtc_time *tm) -{ - char ce_time[12]; - u8 day, mon, hour, min, sec, y1, y2; - unsigned year; - - year = 1900 + tm->tm_year; - y1 = year / 100; - y2 = year % 100; - - sec = tm->tm_sec; - min = tm->tm_min; - hour = tm->tm_hour; - day = tm->tm_mday; - mon = tm->tm_mon + 1; - - sec = bin2bcd(sec); - min = bin2bcd(min); - hour = bin2bcd(hour); - mon = bin2bcd(mon); - day = bin2bcd(day); - y1 = bin2bcd(y1); - y2 = bin2bcd(y2); - - memset(ce_time, 0, sizeof(ce_time)); - ce_time[3] = 0x41; - ce_time[4] = y1; - ce_time[5] = y2; - ce_time[6] = sec; - ce_time[7] = min; - ce_time[8] = hour; - ce_time[10] = day; - ce_time[11] = mon; - - return signal_ce_msg(ce_time, NULL); -} - -static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) -{ - tm->tm_wday = 0; - tm->tm_yday = 0; - tm->tm_isdst = 0; - if (rc) { - tm->tm_sec = 0; - tm->tm_min = 0; - tm->tm_hour = 0; - tm->tm_mday = 15; - tm->tm_mon = 5; - tm->tm_year = 52; - return rc; - } - - if ((ce_msg[2] == 0xa9) || - (ce_msg[2] == 0xaf)) { - /* TOD clock is not set */ - tm->tm_sec = 1; - tm->tm_min = 1; - tm->tm_hour = 1; - tm->tm_mday = 10; - tm->tm_mon = 8; - tm->tm_year = 71; - mf_set_rtc(tm); - } - { - u8 year = ce_msg[5]; - u8 sec = ce_msg[6]; - u8 min = ce_msg[7]; - u8 hour = ce_msg[8]; - u8 day = ce_msg[10]; - u8 mon = ce_msg[11]; - - sec = bcd2bin(sec); - min = bcd2bin(min); - hour = bcd2bin(hour); - day = bcd2bin(day); - mon = bcd2bin(mon); - year = bcd2bin(year); - - if (year <= 69) - year += 100; - - tm->tm_sec = sec; - tm->tm_min = min; - tm->tm_hour = hour; - tm->tm_mday = day; - tm->tm_mon = mon; - tm->tm_year = year; - } - - return 0; -} - -static int mf_get_rtc(struct rtc_time *tm) -{ - struct ce_msg_comp_data ce_complete; - struct rtc_time_data rtc_data; - int rc; - - memset(&ce_complete, 0, sizeof(ce_complete)); - memset(&rtc_data, 0, sizeof(rtc_data)); - init_completion(&rtc_data.com); - ce_complete.handler = &get_rtc_time_complete; - ce_complete.token = &rtc_data; - rc = signal_ce_msg_simple(0x40, &ce_complete); - if (rc) - return rc; - wait_for_completion(&rtc_data.com); - return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); -} - -struct boot_rtc_time_data { - int busy; - struct ce_msg_data ce_msg; - int rc; -}; - -static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) -{ - struct boot_rtc_time_data *rtc = token; - - memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); - rtc->rc = 0; - rtc->busy = 0; -} - -static int mf_get_boot_rtc(struct rtc_time *tm) -{ - struct ce_msg_comp_data ce_complete; - struct boot_rtc_time_data rtc_data; - int rc; - - memset(&ce_complete, 0, sizeof(ce_complete)); - memset(&rtc_data, 0, sizeof(rtc_data)); - rtc_data.busy = 1; - ce_complete.handler = &get_boot_rtc_time_complete; - ce_complete.token = &rtc_data; - rc = signal_ce_msg_simple(0x40, &ce_complete); - if (rc) - return rc; - /* We need to poll here as we are not yet taking interrupts */ - while (rtc_data.busy) { - if (hvlpevent_is_pending()) - process_hvlpevents(); - } - return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); -} - -#ifdef CONFIG_PROC_FS -static int mf_cmdline_proc_show(struct seq_file *m, void *v) -{ - char *page, *p; - struct vsp_cmd_data vsp_cmd; - int rc; - dma_addr_t dma_addr; - - /* The HV appears to return no more than 256 bytes of command line */ - page = kmalloc(256, GFP_KERNEL); - if (!page) - return -ENOMEM; - - dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE); - if (dma_addr == DMA_ERROR_CODE) { - kfree(page); - return -ENOMEM; - } - memset(page, 0, 256); - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 33; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = (u64)m->private; - vsp_cmd.sub_data.kern.length = 256; - mb(); - rc = signal_vsp_instruction(&vsp_cmd); - iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE); - if (rc) { - kfree(page); - return rc; - } - if (vsp_cmd.result_code != 0) { - kfree(page); - return -ENOMEM; - } - p = page; - while (p - page < 256) { - if (*p == '\0' || *p == '\n') { - *p = '\n'; - break; - } - p++; - - } - seq_write(m, page, p - page); - kfree(page); - return 0; -} - -static int mf_cmdline_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mf_cmdline_proc_show, PDE(inode)->data); -} - -#if 0 -static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) -{ - struct vsp_cmd_data vsp_cmd; - int rc; - int len = *size; - dma_addr_t dma_addr; - - dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); - memset(buffer, 0, len); - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 32; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = side; - vsp_cmd.sub_data.kern.offset = offset; - vsp_cmd.sub_data.kern.length = len; - mb(); - rc = signal_vsp_instruction(&vsp_cmd); - if (rc == 0) { - if (vsp_cmd.result_code == 0) - *size = vsp_cmd.sub_data.length_out; - else - rc = -ENOMEM; - } - - iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); - - return rc; -} - -static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int sizeToGet = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) { - if (sizeToGet != 0) { - *start = page + off; - return sizeToGet; - } - *eof = 1; - return 0; - } - *eof = 1; - return 0; -} -#endif - -static int mf_side_proc_show(struct seq_file *m, void *v) -{ - char mf_current_side = ' '; - struct vsp_cmd_data vsp_cmd; - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 2; - vsp_cmd.sub_data.ipl_type = 0; - mb(); - - if (signal_vsp_instruction(&vsp_cmd) == 0) { - if (vsp_cmd.result_code == 0) { - switch (vsp_cmd.sub_data.ipl_type) { - case 0: mf_current_side = 'A'; - break; - case 1: mf_current_side = 'B'; - break; - case 2: mf_current_side = 'C'; - break; - default: mf_current_side = 'D'; - break; - } - } - } - - seq_printf(m, "%c\n", mf_current_side); - return 0; -} - -static int mf_side_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mf_side_proc_show, NULL); -} - -static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - char side; - u64 newSide; - struct vsp_cmd_data vsp_cmd; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (count == 0) - return 0; - - if (get_user(side, buffer)) - return -EFAULT; - - switch (side) { - case 'A': newSide = 0; - break; - case 'B': newSide = 1; - break; - case 'C': newSide = 2; - break; - case 'D': newSide = 3; - break; - default: - printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); - return -EINVAL; - } - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.sub_data.ipl_type = newSide; - vsp_cmd.cmd = 10; - - (void)signal_vsp_instruction(&vsp_cmd); - - return count; -} - -static const struct file_operations mf_side_proc_fops = { - .owner = THIS_MODULE, - .open = mf_side_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = mf_side_proc_write, -}; - -static int mf_src_proc_show(struct seq_file *m, void *v) -{ - return 0; -} - -static int mf_src_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, mf_src_proc_show, NULL); -} - -static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - char stkbuf[10]; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if ((count < 4) && (count != 1)) { - printk(KERN_ERR "mf_proc: invalid src\n"); - return -EINVAL; - } - - if (count > (sizeof(stkbuf) - 1)) - count = sizeof(stkbuf) - 1; - if (copy_from_user(stkbuf, buffer, count)) - return -EFAULT; - - if ((count == 1) && (*stkbuf == '\0')) - mf_clear_src(); - else - mf_display_src(*(u32 *)stkbuf); - - return count; -} - -static const struct file_operations mf_src_proc_fops = { - .owner = THIS_MODULE, - .open = mf_src_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = mf_src_proc_write, -}; - -static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) -{ - void *data = PDE(file->f_path.dentry->d_inode)->data; - struct vsp_cmd_data vsp_cmd; - dma_addr_t dma_addr; - char *page; - int ret = -EACCES; - - if (!capable(CAP_SYS_ADMIN)) - goto out; - - dma_addr = 0; - page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); - ret = -ENOMEM; - if (page == NULL) - goto out; - - ret = -EFAULT; - if (copy_from_user(page, buffer, count)) - goto out_free; - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 31; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = (u64)data; - vsp_cmd.sub_data.kern.length = count; - mb(); - (void)signal_vsp_instruction(&vsp_cmd); - ret = count; - -out_free: - iseries_hv_free(count, page, dma_addr); -out: - return ret; -} - -static const struct file_operations mf_cmdline_proc_fops = { - .owner = THIS_MODULE, - .open = mf_cmdline_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = mf_cmdline_proc_write, -}; - -static ssize_t proc_mf_change_vmlinux(struct file *file, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); - ssize_t rc; - dma_addr_t dma_addr; - char *page; - struct vsp_cmd_data vsp_cmd; - - rc = -EACCES; - if (!capable(CAP_SYS_ADMIN)) - goto out; - - dma_addr = 0; - page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); - rc = -ENOMEM; - if (page == NULL) { - printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); - goto out; - } - rc = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out_free; - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 30; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = (u64)dp->data; - vsp_cmd.sub_data.kern.offset = *ppos; - vsp_cmd.sub_data.kern.length = count; - mb(); - rc = signal_vsp_instruction(&vsp_cmd); - if (rc) - goto out_free; - rc = -ENOMEM; - if (vsp_cmd.result_code != 0) - goto out_free; - - *ppos += count; - rc = count; -out_free: - iseries_hv_free(count, page, dma_addr); -out: - return rc; -} - -static const struct file_operations proc_vmlinux_operations = { - .write = proc_mf_change_vmlinux, - .llseek = default_llseek, -}; - -static int __init mf_proc_init(void) -{ - struct proc_dir_entry *mf_proc_root; - struct proc_dir_entry *ent; - struct proc_dir_entry *mf; - char name[2]; - int i; - - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; - - mf_proc_root = proc_mkdir("iSeries/mf", NULL); - if (!mf_proc_root) - return 1; - - name[1] = '\0'; - for (i = 0; i < 4; i++) { - name[0] = 'A' + i; - mf = proc_mkdir(name, mf_proc_root); - if (!mf) - return 1; - - ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf, - &mf_cmdline_proc_fops, (void *)(long)i); - if (!ent) - return 1; - - if (i == 3) /* no vmlinux entry for 'D' */ - continue; - - ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf, - &proc_vmlinux_operations, - (void *)(long)i); - if (!ent) - return 1; - } - - ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, - &mf_side_proc_fops); - if (!ent) - return 1; - - ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, - &mf_src_proc_fops); - if (!ent) - return 1; - - return 0; -} - -__initcall(mf_proc_init); - -#endif /* CONFIG_PROC_FS */ - -/* - * Get the RTC from the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -void iSeries_get_rtc_time(struct rtc_time *rtc_tm) -{ - mf_get_rtc(rtc_tm); - rtc_tm->tm_mon--; -} - -/* - * Set the RTC in the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -int iSeries_set_rtc_time(struct rtc_time *tm) -{ - mf_set_rtc(tm); - return 0; -} - -unsigned long iSeries_get_boot_time(void) -{ - struct rtc_time tm; - - mf_get_boot_rtc(&tm); - return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); -} diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S deleted file mode 100644 index 2c6ff0fdac98..000000000000 --- a/arch/powerpc/platforms/iseries/misc.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file contains miscellaneous low-level functions. - * Copyright (C) 1995-2005 IBM Corp - * - * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras. - * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) - * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) - * - * 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. - */ - -#include <asm/processor.h> -#include <asm/asm-offsets.h> -#include <asm/ppc_asm.h> - - .text - -/* Handle pending interrupts in interrupt context */ -_GLOBAL(iseries_handle_interrupts) - li r0,0x5555 - sc - blr diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h deleted file mode 100644 index f01708e12862..000000000000 --- a/arch/powerpc/platforms/iseries/naca.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_NACA_H -#define _PLATFORMS_ISERIES_NACA_H - -/* - * c 2001 PPC 64 Team, IBM Corp - * - * 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. - */ - -#include <asm/types.h> - -struct naca_struct { - /* Kernel only data - undefined for user space */ - const void *xItVpdAreas; /* VPD Data 0x00 */ - void *xRamDisk; /* iSeries ramdisk 0x08 */ - u64 xRamDiskSize; /* In pages 0x10 */ -}; - -extern struct naca_struct naca; - -#endif /* _PLATFORMS_ISERIES_NACA_H */ diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c deleted file mode 100644 index c75412884625..000000000000 --- a/arch/powerpc/platforms/iseries/pci.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * Copyright (C) 2001 Allan Trautman, IBM Corporation - * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp - * - * iSeries specific routines for PCI. - * - * Based on code from pci.c and iSeries_pci.c 32bit - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#undef DEBUG - -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/of.h> -#include <linux/ratelimit.h> - -#include <asm/types.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/abs_addr.h> -#include <asm/firmware.h> - -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/iommu.h> - -#include <asm/ppc-pci.h> - -#include "irq.h" -#include "pci.h" -#include "call_pci.h" - -#define PCI_RETRY_MAX 3 -static int limit_pci_retries = 1; /* Set Retry Error on. */ - -/* - * Table defines - * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. - */ -#define IOMM_TABLE_MAX_ENTRIES 1024 -#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL -#define BASE_IO_MEMORY 0xE000000000000000UL -#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL - -static unsigned long max_io_memory = BASE_IO_MEMORY; -static long current_iomm_table_entry; - -/* - * Lookup Tables. - */ -static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; -static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES]; - -static DEFINE_SPINLOCK(iomm_table_lock); - -/* - * Generate a Direct Select Address for the Hypervisor - */ -static inline u64 iseries_ds_addr(struct device_node *node) -{ - struct pci_dn *pdn = PCI_DN(node); - const u32 *sbp = of_get_property(node, "linux,subbus", NULL); - - return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40) - + ((u64)0x10 << 32); -} - -/* - * Size of Bus VPD data - */ -#define BUS_VPDSIZE 1024 - -/* - * Bus Vpd Tags - */ -#define VPD_END_OF_AREA 0x79 -#define VPD_ID_STRING 0x82 -#define VPD_VENDOR_AREA 0x84 - -/* - * Mfg Area Tags - */ -#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */ -#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */ -#define VPD_SLOT_MAP 0x534D /* "SM" */ - -/* - * Structures of the areas - */ -struct mfg_vpd_area { - u16 tag; - u8 length; - u8 data1; - u8 data2; -}; -#define MFG_ENTRY_SIZE 3 - -struct slot_map { - u8 agent; - u8 secondary_agent; - u8 phb; - char card_location[3]; - char parms[8]; - char reserved[2]; -}; -#define SLOT_ENTRY_SIZE 16 - -/* - * Parse the Slot Area - */ -static void __init iseries_parse_slot_area(struct slot_map *map, int len, - HvAgentId agent, u8 *phb, char card[4]) -{ - /* - * Parse Slot label until we find the one requested - */ - while (len > 0) { - if (map->agent == agent) { - /* - * If Phb wasn't found, grab the entry first one found. - */ - if (*phb == 0xff) - *phb = map->phb; - /* Found it, extract the data. */ - if (map->phb == *phb) { - memcpy(card, &map->card_location, 3); - card[3] = 0; - break; - } - } - /* Point to the next Slot */ - map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE); - len -= SLOT_ENTRY_SIZE; - } -} - -/* - * Parse the Mfg Area - */ -static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len, - HvAgentId agent, u8 *phb, u8 *frame, char card[4]) -{ - u16 slot_map_fmt = 0; - - /* Parse Mfg Data */ - while (len > 0) { - int mfg_tag_len = area->length; - /* Frame ID (FI 4649020310 ) */ - if (area->tag == VPD_FRU_FRAME_ID) - *frame = area->data1; - /* Slot Map Format (MF 4D46020004 ) */ - else if (area->tag == VPD_SLOT_MAP_FORMAT) - slot_map_fmt = (area->data1 * 256) - + area->data2; - /* Slot Map (SM 534D90 */ - else if (area->tag == VPD_SLOT_MAP) { - struct slot_map *slot_map; - - if (slot_map_fmt == 0x1004) - slot_map = (struct slot_map *)((char *)area - + MFG_ENTRY_SIZE + 1); - else - slot_map = (struct slot_map *)((char *)area - + MFG_ENTRY_SIZE); - iseries_parse_slot_area(slot_map, mfg_tag_len, - agent, phb, card); - } - /* - * Point to the next Mfg Area - * Use defined size, sizeof give wrong answer - */ - area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len - + MFG_ENTRY_SIZE); - len -= (mfg_tag_len + MFG_ENTRY_SIZE); - } -} - -/* - * Look for "BUS".. Data is not Null terminated. - * PHBID of 0xFF indicates PHB was not found in VPD Data. - */ -static u8 __init iseries_parse_phbid(u8 *area, int len) -{ - while (len > 0) { - if ((*area == 'B') && (*(area + 1) == 'U') - && (*(area + 2) == 'S')) { - area += 3; - while (*area == ' ') - area++; - return *area & 0x0F; - } - area++; - len--; - } - return 0xff; -} - -/* - * Parse out the VPD Areas - */ -static void __init iseries_parse_vpd(u8 *data, int data_len, - HvAgentId agent, u8 *frame, char card[4]) -{ - u8 phb = 0xff; - - while (data_len > 0) { - int len; - u8 tag = *data; - - if (tag == VPD_END_OF_AREA) - break; - len = *(data + 1) + (*(data + 2) * 256); - data += 3; - data_len -= 3; - if (tag == VPD_ID_STRING) - phb = iseries_parse_phbid(data, len); - else if (tag == VPD_VENDOR_AREA) - iseries_parse_mfg_area((struct mfg_vpd_area *)data, len, - agent, &phb, frame, card); - /* Point to next Area. */ - data += len; - data_len -= len; - } -} - -static int __init iseries_get_location_code(u16 bus, HvAgentId agent, - u8 *frame, char card[4]) -{ - int status = 0; - int bus_vpd_len = 0; - u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL); - - if (bus_vpd == NULL) { - printk("PCI: Bus VPD Buffer allocation failure.\n"); - return 0; - } - bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd), - BUS_VPDSIZE); - if (bus_vpd_len == 0) { - printk("PCI: Bus VPD Buffer zero length.\n"); - goto out_free; - } - /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */ - /* Make sure this is what I think it is */ - if (*bus_vpd != VPD_ID_STRING) { - printk("PCI: Bus VPD Buffer missing starting tag.\n"); - goto out_free; - } - iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card); - status = 1; -out_free: - kfree(bus_vpd); - return status; -} - -/* - * Prints the device information. - * - Pass in pci_dev* pointer to the device. - * - Pass in the device count - * - * Format: - * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet - * controller - */ -static void __init iseries_device_information(struct pci_dev *pdev, - u16 bus, HvSubBusNumber subbus) -{ - u8 frame = 0; - char card[4]; - HvAgentId agent; - - agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), - ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); - - if (iseries_get_location_code(bus, agent, &frame, card)) { - printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, " - "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor, - frame, card, (int)(pdev->class >> 8)); - } -} - -/* - * iomm_table_allocate_entry - * - * Adds pci_dev entry in address translation table - * - * - Allocates the number of entries required in table base on BAR - * size. - * - Allocates starting at BASE_IO_MEMORY and increases. - * - The size is round up to be a multiple of entry size. - * - CurrentIndex is incremented to keep track of the last entry. - * - Builds the resource entry for allocated BARs. - */ -static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) -{ - struct resource *bar_res = &dev->resource[bar_num]; - long bar_size = pci_resource_len(dev, bar_num); - struct device_node *dn = pci_device_to_OF_node(dev); - - /* - * No space to allocate, quick exit, skip Allocation. - */ - if (bar_size == 0) - return; - /* - * Set Resource values. - */ - spin_lock(&iomm_table_lock); - bar_res->start = BASE_IO_MEMORY + - IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; - bar_res->end = bar_res->start + bar_size - 1; - /* - * Allocate the number of table entries needed for BAR. - */ - while (bar_size > 0 ) { - iomm_table[current_iomm_table_entry] = dn; - ds_addr_table[current_iomm_table_entry] = - iseries_ds_addr(dn) | (bar_num << 24); - bar_size -= IOMM_TABLE_ENTRY_SIZE; - ++current_iomm_table_entry; - } - max_io_memory = BASE_IO_MEMORY + - IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; - spin_unlock(&iomm_table_lock); -} - -/* - * allocate_device_bars - * - * - Allocates ALL pci_dev BAR's and updates the resources with the - * BAR value. BARS with zero length will have the resources - * The HvCallPci_getBarParms is used to get the size of the BAR - * space. It calls iomm_table_allocate_entry to allocate - * each entry. - * - Loops through The Bar resources(0 - 5) including the ROM - * is resource(6). - */ -static void __init allocate_device_bars(struct pci_dev *dev) -{ - int bar_num; - - for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) - iomm_table_allocate_entry(dev, bar_num); -} - -/* - * Log error information to system console. - * Filter out the device not there errors. - * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx - * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx - * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx - */ -static void pci_log_error(char *error, int bus, int subbus, - int agent, int hv_res) -{ - if (hv_res == 0x0302) - return; - printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", - error, bus, subbus, agent, hv_res); -} - -/* - * Look down the chain to find the matching Device Device - */ -static struct device_node *find_device_node(int bus, int devfn) -{ - struct device_node *node; - - for (node = NULL; (node = of_find_all_nodes(node)); ) { - struct pci_dn *pdn = PCI_DN(node); - - if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn)) - return node; - } - return NULL; -} - -/* - * iSeries_pcibios_fixup_resources - * - * Fixes up all resources for devices - */ -void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev) -{ - const u32 *agent; - const u32 *sub_bus; - unsigned char bus = pdev->bus->number; - struct device_node *node; - int i; - - node = pci_device_to_OF_node(pdev); - pr_debug("PCI: iSeries %s, pdev %p, node %p\n", - pci_name(pdev), pdev, node); - if (!node) { - printk("PCI: %s disabled, device tree entry not found !\n", - pci_name(pdev)); - for (i = 0; i <= PCI_ROM_RESOURCE; i++) - pdev->resource[i].flags = 0; - return; - } - sub_bus = of_get_property(node, "linux,subbus", NULL); - agent = of_get_property(node, "linux,agent-id", NULL); - if (agent && sub_bus) { - u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); - int err; - - err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq); - if (err) - pci_log_error("Connect Bus Unit", - bus, *sub_bus, *agent, err); - else { - err = HvCallPci_configStore8(bus, *sub_bus, - *agent, PCI_INTERRUPT_LINE, irq); - if (err) - pci_log_error("PciCfgStore Irq Failed!", - bus, *sub_bus, *agent, err); - else - pdev->irq = irq; - } - } - - allocate_device_bars(pdev); - if (likely(sub_bus)) - iseries_device_information(pdev, bus, *sub_bus); - else - printk(KERN_ERR "PCI: Device node %s has missing or invalid " - "linux,subbus property\n", node->full_name); -} - -/* - * iSeries_pci_final_fixup(void) - */ -void __init iSeries_pci_final_fixup(void) -{ - /* Fix up at the device node and pci_dev relationship */ - mf_display_src(0xC9000100); - iSeries_activate_IRQs(); - mf_display_src(0xC9000200); -} - -/* - * Config space read and write functions. - * For now at least, we look for the device node for the bus and devfn - * that we are asked to access. It may be possible to translate the devfn - * to a subbus and deviceid more directly. - */ -static u64 hv_cfg_read_func[4] = { - HvCallPciConfigLoad8, HvCallPciConfigLoad16, - HvCallPciConfigLoad32, HvCallPciConfigLoad32 -}; - -static u64 hv_cfg_write_func[4] = { - HvCallPciConfigStore8, HvCallPciConfigStore16, - HvCallPciConfigStore32, HvCallPciConfigStore32 -}; - -/* - * Read PCI config space - */ -static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int size, u32 *val) -{ - struct device_node *node = find_device_node(bus->number, devfn); - u64 fn; - struct HvCallPci_LoadReturn ret; - - if (node == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset > 255) { - *val = ~0; - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - fn = hv_cfg_read_func[(size - 1) & 3]; - HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0); - - if (ret.rc != 0) { - *val = ~0; - return PCIBIOS_DEVICE_NOT_FOUND; /* or something */ - } - - *val = ret.value; - return 0; -} - -/* - * Write PCI config space - */ - -static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int size, u32 val) -{ - struct device_node *node = find_device_node(bus->number, devfn); - u64 fn; - u64 ret; - - if (node == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset > 255) - return PCIBIOS_BAD_REGISTER_NUMBER; - - fn = hv_cfg_write_func[(size - 1) & 3]; - ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0); - - if (ret != 0) - return PCIBIOS_DEVICE_NOT_FOUND; - - return 0; -} - -static struct pci_ops iSeries_pci_ops = { - .read = iSeries_pci_read_config, - .write = iSeries_pci_write_config -}; - -/* - * Check Return Code - * -> On Failure, print and log information. - * Increment Retry Count, if exceeds max, panic partition. - * - * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 - * PCI: Device 23.90 ReadL Retry( 1) - * PCI: Device 23.90 ReadL Retry Successful(1) - */ -static int check_return_code(char *type, struct device_node *dn, - int *retry, u64 ret) -{ - if (ret != 0) { - struct pci_dn *pdn = PCI_DN(dn); - - (*retry)++; - printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", - type, pdn->busno, pdn->devfn, - *retry, (int)ret); - /* - * Bump the retry and check for retry count exceeded. - * If, Exceeded, panic the system. - */ - if (((*retry) > PCI_RETRY_MAX) && - (limit_pci_retries > 0)) { - mf_display_src(0xB6000103); - panic_timeout = 0; - panic("PCI: Hardware I/O Error, SRC B6000103, " - "Automatic Reboot Disabled.\n"); - } - return -1; /* Retry Try */ - } - return 0; -} - -/* - * Translate the I/O Address into a device node, bar, and bar offset. - * Note: Make sure the passed variable end up on the stack to avoid - * the exposure of being device global. - */ -static inline struct device_node *xlate_iomm_address( - const volatile void __iomem *addr, - u64 *dsaptr, u64 *bar_offset, const char *func) -{ - unsigned long orig_addr; - unsigned long base_addr; - unsigned long ind; - struct device_node *dn; - - orig_addr = (unsigned long __force)addr; - if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) { - static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10); - - if (__ratelimit(&ratelimit)) - printk(KERN_ERR - "iSeries_%s: invalid access at IO address %p\n", - func, addr); - return NULL; - } - base_addr = orig_addr - BASE_IO_MEMORY; - ind = base_addr / IOMM_TABLE_ENTRY_SIZE; - dn = iomm_table[ind]; - - if (dn != NULL) { - *dsaptr = ds_addr_table[ind]; - *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE; - } else - panic("PCI: Invalid PCI IO address detected!\n"); - return dn; -} - -/* - * Read MM I/O Instructions for the iSeries - * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal - * else, data is returned in Big Endian format. - */ -static u8 iseries_readb(const volatile void __iomem *addr) -{ - u64 bar_offset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct device_node *dn = - xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte"); - - if (dn == NULL) - return 0xff; - do { - HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0); - } while (check_return_code("RDB", dn, &retry, ret.rc) != 0); - - return ret.value; -} - -static u16 iseries_readw_be(const volatile void __iomem *addr) -{ - u64 bar_offset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct device_node *dn = - xlate_iomm_address(addr, &dsa, &bar_offset, "read_word"); - - if (dn == NULL) - return 0xffff; - do { - HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, - bar_offset, 0); - } while (check_return_code("RDW", dn, &retry, ret.rc) != 0); - - return ret.value; -} - -static u32 iseries_readl_be(const volatile void __iomem *addr) -{ - u64 bar_offset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct device_node *dn = - xlate_iomm_address(addr, &dsa, &bar_offset, "read_long"); - - if (dn == NULL) - return 0xffffffff; - do { - HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, - bar_offset, 0); - } while (check_return_code("RDL", dn, &retry, ret.rc) != 0); - - return ret.value; -} - -/* - * Write MM I/O Instructions for the iSeries - * - */ -static void iseries_writeb(u8 data, volatile void __iomem *addr) -{ - u64 bar_offset; - u64 dsa; - int retry = 0; - u64 rc; - struct device_node *dn = - xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte"); - - if (dn == NULL) - return; - do { - rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0); - } while (check_return_code("WWB", dn, &retry, rc) != 0); -} - -static void iseries_writew_be(u16 data, volatile void __iomem *addr) -{ - u64 bar_offset; - u64 dsa; - int retry = 0; - u64 rc; - struct device_node *dn = - xlate_iomm_address(addr, &dsa, &bar_offset, "write_word"); - - if (dn == NULL) - return; - do { - rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0); - } while (check_return_code("WWW", dn, &retry, rc) != 0); -} - -static void iseries_writel_be(u32 data, volatile void __iomem *addr) -{ - u64 bar_offset; - u64 dsa; - int retry = 0; - u64 rc; - struct device_node *dn = - xlate_iomm_address(addr, &dsa, &bar_offset, "write_long"); - - if (dn == NULL) - return; - do { - rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0); - } while (check_return_code("WWL", dn, &retry, rc) != 0); -} - -static u16 iseries_readw(const volatile void __iomem *addr) -{ - return le16_to_cpu(iseries_readw_be(addr)); -} - -static u32 iseries_readl(const volatile void __iomem *addr) -{ - return le32_to_cpu(iseries_readl_be(addr)); -} - -static void iseries_writew(u16 data, volatile void __iomem *addr) -{ - iseries_writew_be(cpu_to_le16(data), addr); -} - -static void iseries_writel(u32 data, volatile void __iomem *addr) -{ - iseries_writel(cpu_to_le32(data), addr); -} - -static void iseries_readsb(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - u8 *dst = buf; - while(count-- > 0) - *(dst++) = iseries_readb(addr); -} - -static void iseries_readsw(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - u16 *dst = buf; - while(count-- > 0) - *(dst++) = iseries_readw_be(addr); -} - -static void iseries_readsl(const volatile void __iomem *addr, void *buf, - unsigned long count) -{ - u32 *dst = buf; - while(count-- > 0) - *(dst++) = iseries_readl_be(addr); -} - -static void iseries_writesb(volatile void __iomem *addr, const void *buf, - unsigned long count) -{ - const u8 *src = buf; - while(count-- > 0) - iseries_writeb(*(src++), addr); -} - -static void iseries_writesw(volatile void __iomem *addr, const void *buf, - unsigned long count) -{ - const u16 *src = buf; - while(count-- > 0) - iseries_writew_be(*(src++), addr); -} - -static void iseries_writesl(volatile void __iomem *addr, const void *buf, - unsigned long count) -{ - const u32 *src = buf; - while(count-- > 0) - iseries_writel_be(*(src++), addr); -} - -static void iseries_memset_io(volatile void __iomem *addr, int c, - unsigned long n) -{ - volatile char __iomem *d = addr; - - while (n-- > 0) - iseries_writeb(c, d++); -} - -static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, - unsigned long n) -{ - char *d = dest; - const volatile char __iomem *s = src; - - while (n-- > 0) - *d++ = iseries_readb(s++); -} - -static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, - unsigned long n) -{ - const char *s = src; - volatile char __iomem *d = dest; - - while (n-- > 0) - iseries_writeb(*s++, d++); -} - -/* We only set MMIO ops. The default PIO ops will be default - * to the MMIO ops + pci_io_base which is 0 on iSeries as - * expected so both should work. - * - * Note that we don't implement the readq/writeq versions as - * I don't know of an HV call for doing so. Thus, the default - * operation will be used instead, which will fault a the value - * return by iSeries for MMIO addresses always hits a non mapped - * area. This is as good as the BUG() we used to have there. - */ -static struct ppc_pci_io __initdata iseries_pci_io = { - .readb = iseries_readb, - .readw = iseries_readw, - .readl = iseries_readl, - .readw_be = iseries_readw_be, - .readl_be = iseries_readl_be, - .writeb = iseries_writeb, - .writew = iseries_writew, - .writel = iseries_writel, - .writew_be = iseries_writew_be, - .writel_be = iseries_writel_be, - .readsb = iseries_readsb, - .readsw = iseries_readsw, - .readsl = iseries_readsl, - .writesb = iseries_writesb, - .writesw = iseries_writesw, - .writesl = iseries_writesl, - .memset_io = iseries_memset_io, - .memcpy_fromio = iseries_memcpy_fromio, - .memcpy_toio = iseries_memcpy_toio, -}; - -/* - * iSeries_pcibios_init - * - * Description: - * This function checks for all possible system PCI host bridges that connect - * PCI buses. The system hypervisor is queried as to the guest partition - * ownership status. A pci_controller is built for any bus which is partially - * owned or fully owned by this guest partition. - */ -void __init iSeries_pcibios_init(void) -{ - struct pci_controller *phb; - struct device_node *root = of_find_node_by_path("/"); - struct device_node *node = NULL; - - /* Install IO hooks */ - ppc_pci_io = iseries_pci_io; - - pci_probe_only = 1; - - /* iSeries has no IO space in the common sense, it needs to set - * the IO base to 0 - */ - pci_io_base = 0; - - if (root == NULL) { - printk(KERN_CRIT "iSeries_pcibios_init: can't find root " - "of device tree\n"); - return; - } - while ((node = of_get_next_child(root, node)) != NULL) { - HvBusNumber bus; - const u32 *busp; - - if ((node->type == NULL) || (strcmp(node->type, "pci") != 0)) - continue; - - busp = of_get_property(node, "bus-range", NULL); - if (busp == NULL) - continue; - bus = *busp; - printk("bus %d appears to exist\n", bus); - phb = pcibios_alloc_controller(node); - if (phb == NULL) - continue; - /* All legacy iSeries PHBs are in domain zero */ - phb->global_number = 0; - - phb->first_busno = bus; - phb->last_busno = bus; - phb->ops = &iSeries_pci_ops; - phb->io_base_virt = (void __iomem *)_IO_BASE; - phb->io_resource.flags = IORESOURCE_IO; - phb->io_resource.start = BASE_IO_MEMORY; - phb->io_resource.end = END_IO_MEMORY; - phb->io_resource.name = "iSeries PCI IO"; - phb->mem_resources[0].flags = IORESOURCE_MEM; - phb->mem_resources[0].start = BASE_IO_MEMORY; - phb->mem_resources[0].end = END_IO_MEMORY; - phb->mem_resources[0].name = "Series PCI MEM"; - } - - of_node_put(root); - - pci_devs_phb_init(); -} - diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h deleted file mode 100644 index d9cf974c2718..000000000000 --- a/arch/powerpc/platforms/iseries/pci.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_PCI_H -#define _PLATFORMS_ISERIES_PCI_H - -/* - * Created by Allan Trautman on Tue Feb 20, 2001. - * - * Define some useful macros for the iSeries pci routines. - * Copyright (C) 2001 Allan H Trautman, IBM 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., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - * - * Change Activity: - * Created Feb 20, 2001 - * Added device reset, March 22, 2001 - * Ported to ppc64, May 25, 2001 - * End Change Activity - */ - -/* - * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. - * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h - */ - -#define ISERIES_PCI_AGENTID(idsel, func) \ - (((idsel & 0x0F) << 4) | (func & 0x07)) -#define ISERIES_ENCODE_DEVICE(agentid) \ - ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07)) - -#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) -#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) - -struct pci_dev; - -#ifdef CONFIG_PCI -extern void iSeries_pcibios_init(void); -extern void iSeries_pci_final_fixup(void); -extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev); -#else -static inline void iSeries_pcibios_init(void) { } -static inline void iSeries_pci_final_fixup(void) { } -static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {} -#endif - -#endif /* _PLATFORMS_ISERIES_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c deleted file mode 100644 index 06763682db47..000000000000 --- a/arch/powerpc/platforms/iseries/proc.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2001 Kyle A. Lucke IBM Corporation - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/param.h> /* for HZ */ -#include <asm/paca.h> -#include <asm/processor.h> -#include <asm/time.h> -#include <asm/lppaca.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call_xm.h> - -#include "processor_vpd.h" -#include "main_store.h" - -static int __init iseries_proc_create(void) -{ - struct proc_dir_entry *e; - - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; - - e = proc_mkdir("iSeries", 0); - if (!e) - return 1; - - return 0; -} -core_initcall(iseries_proc_create); - -static unsigned long startTitan = 0; -static unsigned long startTb = 0; - -static int proc_titantod_show(struct seq_file *m, void *v) -{ - unsigned long tb0, titan_tod; - - tb0 = get_tb(); - titan_tod = HvCallXm_loadTod(); - - seq_printf(m, "Titan\n" ); - seq_printf(m, " time base = %016lx\n", tb0); - seq_printf(m, " titan tod = %016lx\n", titan_tod); - seq_printf(m, " xProcFreq = %016x\n", - xIoHriProcessorVpd[0].xProcFreq); - seq_printf(m, " xTimeBaseFreq = %016x\n", - xIoHriProcessorVpd[0].xTimeBaseFreq); - seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy); - seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec); - - if (!startTitan) { - startTitan = titan_tod; - startTb = tb0; - } else { - unsigned long titan_usec = (titan_tod - startTitan) >> 12; - unsigned long tb_ticks = (tb0 - startTb); - unsigned long titan_jiffies = titan_usec / (1000000/HZ); - unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); - unsigned long titan_jiff_rem_usec = - titan_usec - titan_jiff_usec; - unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; - unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; - unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; - unsigned long tb_jiff_rem_usec = - tb_jiff_rem_ticks / tb_ticks_per_usec; - unsigned long new_tb_ticks_per_jiffy = - (tb_ticks * (1000000/HZ))/titan_usec; - - seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec); - seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks); - seq_printf(m, " titan jiffies = %lu.%04lu\n", titan_jiffies, - titan_jiff_rem_usec); - seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies, - tb_jiff_rem_usec); - seq_printf(m, " new tb_ticks_per_jiffy = %lu\n", - new_tb_ticks_per_jiffy); - } - - return 0; -} - -static int proc_titantod_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_titantod_show, NULL); -} - -static const struct file_operations proc_titantod_operations = { - .open = proc_titantod_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init iseries_proc_init(void) -{ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; - - proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL, - &proc_titantod_operations); - return 0; -} -__initcall(iseries_proc_init); diff --git a/arch/powerpc/platforms/iseries/processor_vpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h deleted file mode 100644 index 7ac5d0d0dbfa..000000000000 --- a/arch/powerpc/platforms/iseries/processor_vpd.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ISERIES_PROCESSOR_VPD_H -#define _ISERIES_PROCESSOR_VPD_H - -#include <asm/types.h> - -/* - * This struct maps Processor Vpd that is DMAd to SLIC by CSP - */ -struct IoHriProcessorVpd { - u8 xFormat; // VPD format indicator x00-x00 - u8 xProcStatus:8; // Processor State x01-x01 - u8 xSecondaryThreadCount; // Secondary thread cnt x02-x02 - u8 xSrcType:1; // Src Type x03-x03 - u8 xSrcSoft:1; // Src stay soft ... - u8 xSrcParable:1; // Src parable ... - u8 xRsvd1:5; // Reserved ... - u16 xHvPhysicalProcIndex; // Hypervisor physical proc index04-x05 - u16 xRsvd2; // Reserved x06-x07 - u32 xHwNodeId; // Hardware node id x08-x0B - u32 xHwProcId; // Hardware processor id x0C-x0F - - u32 xTypeNum; // Card Type/CCIN number x10-x13 - u32 xModelNum; // Model/Feature number x14-x17 - u64 xSerialNum; // Serial number x18-x1F - char xPartNum[12]; // Book Part or FPU number x20-x2B - char xMfgID[4]; // Manufacturing ID x2C-x2F - - u32 xProcFreq; // Processor Frequency x30-x33 - u32 xTimeBaseFreq; // Time Base Frequency x34-x37 - - u32 xChipEcLevel; // Chip EC Levels x38-x3B - u32 xProcIdReg; // PIR SPR value x3C-x3F - u32 xPVR; // PVR value x40-x43 - u8 xRsvd3[12]; // Reserved x44-x4F - - u32 xInstCacheSize; // Instruction cache size in KB x50-x53 - u32 xInstBlockSize; // Instruction cache block size x54-x57 - u32 xDataCacheOperandSize; // Data cache operand size x58-x5B - u32 xInstCacheOperandSize; // Inst cache operand size x5C-x5F - - u32 xDataL1CacheSizeKB; // L1 data cache size in KB x60-x63 - u32 xDataL1CacheLineSize; // L1 data cache block size x64-x67 - u64 xRsvd4; // Reserved x68-x6F - - u32 xDataL2CacheSizeKB; // L2 data cache size in KB x70-x73 - u32 xDataL2CacheLineSize; // L2 data cache block size x74-x77 - u64 xRsvd5; // Reserved x78-x7F - - u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x83 - u32 xDataL3CacheLineSize; // L3 data cache block size x84-x87 - u64 xRsvd6; // Reserved x88-x8F - - u64 xFruLabel; // Card Location Label x90-x97 - u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x98 - u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x99 - u16 xSlotMapIndex; // Index in slot map table x9A-x9B - u8 xSmartCardPortNo; // Smart card port number x9C-x9C - u8 xRsvd7; // Reserved x9D-x9D - u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F - - u8 xRsvd8[24]; // Reserved xA0-xB7 - - char xProcSrc[72]; // CSP format SRC xB8-xFF -}; - -extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; - -#endif /* _ISERIES_PROCESSOR_VPD_H */ diff --git a/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h deleted file mode 100644 index 6ad7d843e8fc..000000000000 --- a/arch/powerpc/platforms/iseries/release_data.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ISERIES_RELEASE_DATA_H -#define _ISERIES_RELEASE_DATA_H - -/* - * This control block contains the critical information about the - * release so that it can be changed in the future (ie, the virtual - * address of the OS's NACA). - */ -#include <asm/types.h> -#include "naca.h" - -/* - * When we IPL a secondary partition, we will check if if the - * secondary xMinPlicVrmIndex > the primary xVrmIndex. - * If it is then this tells PLIC that this secondary is not - * supported running on this "old" of a level of PLIC. - * - * Likewise, we will compare the primary xMinSlicVrmIndex to - * the secondary xVrmIndex. - * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we - * know that this PLIC does not support running an OS "that old". - */ - -#define HVREL_TAGSINACTIVE 0x8000 -#define HVREL_32BIT 0x4000 -#define HVREL_NOSHAREDPROCS 0x2000 -#define HVREL_NOHMT 0x1000 - -struct HvReleaseData { - u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */ - u16 xSize; /* Size of this control block x04-x05 */ - u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */ - struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */ - u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */ - u32 xRsvd1; /* Reserved x14-x17 */ - u16 xFlags; - u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */ - u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */ - u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */ - char xVrmName[12]; /* Displayable name x20-x2B */ - char xRsvd3[20]; /* Reserved x2C-x3F */ -}; - -extern const struct HvReleaseData hvReleaseData; - -#endif /* _ISERIES_RELEASE_DATA_H */ diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c deleted file mode 100644 index a5fbf4cb6329..000000000000 --- a/arch/powerpc/platforms/iseries/setup.c +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and - * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek - * <dan@net4x.com>. - * - * 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. - */ - -#undef DEBUG - -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/export.h> -#include <linux/seq_file.h> -#include <linux/kdev_t.h> -#include <linux/kexec.h> -#include <linux/major.h> -#include <linux/root_dev.h> -#include <linux/kernel.h> -#include <linux/hrtimer.h> -#include <linux/tick.h> - -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/mmu_context.h> -#include <asm/cputable.h> -#include <asm/sections.h> -#include <asm/iommu.h> -#include <asm/firmware.h> -#include <asm/system.h> -#include <asm/time.h> -#include <asm/paca.h> -#include <asm/cache.h> -#include <asm/abs_addr.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/lpar_map.h> -#include <asm/udbg.h> -#include <asm/irq.h> - -#include "naca.h" -#include "setup.h" -#include "irq.h" -#include "vpd_areas.h" -#include "processor_vpd.h" -#include "it_lp_naca.h" -#include "main_store.h" -#include "call_sm.h" -#include "call_hpt.h" -#include "pci.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* Function Prototypes */ -static unsigned long build_iSeries_Memory_Map(void); -static void iseries_shared_idle(void); -static void iseries_dedicated_idle(void); - - -struct MemoryBlock { - unsigned long absStart; - unsigned long absEnd; - unsigned long logicalStart; - unsigned long logicalEnd; -}; - -/* - * Process the main store vpd to determine where the holes in memory are - * and return the number of physical blocks and fill in the array of - * block data. - */ -static unsigned long iSeries_process_Condor_mainstore_vpd( - struct MemoryBlock *mb_array, unsigned long max_entries) -{ - unsigned long holeFirstChunk, holeSizeChunks; - unsigned long numMemoryBlocks = 1; - struct IoHriMainStoreSegment4 *msVpd = - (struct IoHriMainStoreSegment4 *)xMsVpd; - unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr; - unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr; - unsigned long holeSize = holeEnd - holeStart; - - printk("Mainstore_VPD: Condor\n"); - /* - * Determine if absolute memory has any - * holes so that we can interpret the - * access map we get back from the hypervisor - * correctly. - */ - mb_array[0].logicalStart = 0; - mb_array[0].logicalEnd = 0x100000000UL; - mb_array[0].absStart = 0; - mb_array[0].absEnd = 0x100000000UL; - - if (holeSize) { - numMemoryBlocks = 2; - holeStart = holeStart & 0x000fffffffffffffUL; - holeStart = addr_to_chunk(holeStart); - holeFirstChunk = holeStart; - holeSize = addr_to_chunk(holeSize); - holeSizeChunks = holeSize; - printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n", - holeFirstChunk, holeSizeChunks ); - mb_array[0].logicalEnd = holeFirstChunk; - mb_array[0].absEnd = holeFirstChunk; - mb_array[1].logicalStart = holeFirstChunk; - mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks; - mb_array[1].absStart = holeFirstChunk + holeSizeChunks; - mb_array[1].absEnd = 0x100000000UL; - } - return numMemoryBlocks; -} - -#define MaxSegmentAreas 32 -#define MaxSegmentAdrRangeBlocks 128 -#define MaxAreaRangeBlocks 4 - -static unsigned long iSeries_process_Regatta_mainstore_vpd( - struct MemoryBlock *mb_array, unsigned long max_entries) -{ - struct IoHriMainStoreSegment5 *msVpdP = - (struct IoHriMainStoreSegment5 *)xMsVpd; - unsigned long numSegmentBlocks = 0; - u32 existsBits = msVpdP->msAreaExists; - unsigned long area_num; - - printk("Mainstore_VPD: Regatta\n"); - - for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) { - unsigned long numAreaBlocks; - struct IoHriMainStoreArea4 *currentArea; - - if (existsBits & 0x80000000) { - unsigned long block_num; - - currentArea = &msVpdP->msAreaArray[area_num]; - numAreaBlocks = currentArea->numAdrRangeBlocks; - printk("ms_vpd: processing area %2ld blocks=%ld", - area_num, numAreaBlocks); - for (block_num = 0; block_num < numAreaBlocks; - ++block_num ) { - /* Process an address range block */ - struct MemoryBlock tempBlock; - unsigned long i; - - tempBlock.absStart = - (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart; - tempBlock.absEnd = - (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd; - tempBlock.logicalStart = 0; - tempBlock.logicalEnd = 0; - printk("\n block %ld absStart=%016lx absEnd=%016lx", - block_num, tempBlock.absStart, - tempBlock.absEnd); - - for (i = 0; i < numSegmentBlocks; ++i) { - if (mb_array[i].absStart == - tempBlock.absStart) - break; - } - if (i == numSegmentBlocks) { - if (numSegmentBlocks == max_entries) - panic("iSeries_process_mainstore_vpd: too many memory blocks"); - mb_array[numSegmentBlocks] = tempBlock; - ++numSegmentBlocks; - } else - printk(" (duplicate)"); - } - printk("\n"); - } - existsBits <<= 1; - } - /* Now sort the blocks found into ascending sequence */ - if (numSegmentBlocks > 1) { - unsigned long m, n; - - for (m = 0; m < numSegmentBlocks - 1; ++m) { - for (n = numSegmentBlocks - 1; m < n; --n) { - if (mb_array[n].absStart < - mb_array[n-1].absStart) { - struct MemoryBlock tempBlock; - - tempBlock = mb_array[n]; - mb_array[n] = mb_array[n-1]; - mb_array[n-1] = tempBlock; - } - } - } - } - /* - * Assign "logical" addresses to each block. These - * addresses correspond to the hypervisor "bitmap" space. - * Convert all addresses into units of 256K chunks. - */ - { - unsigned long i, nextBitmapAddress; - - printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks); - nextBitmapAddress = 0; - for (i = 0; i < numSegmentBlocks; ++i) { - unsigned long length = mb_array[i].absEnd - - mb_array[i].absStart; - - mb_array[i].logicalStart = nextBitmapAddress; - mb_array[i].logicalEnd = nextBitmapAddress + length; - nextBitmapAddress += length; - printk(" Bitmap range: %016lx - %016lx\n" - " Absolute range: %016lx - %016lx\n", - mb_array[i].logicalStart, - mb_array[i].logicalEnd, - mb_array[i].absStart, mb_array[i].absEnd); - mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & - 0x000fffffffffffffUL); - mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & - 0x000fffffffffffffUL); - mb_array[i].logicalStart = - addr_to_chunk(mb_array[i].logicalStart); - mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); - } - } - - return numSegmentBlocks; -} - -static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, - unsigned long max_entries) -{ - unsigned long i; - unsigned long mem_blocks = 0; - - if (mmu_has_feature(MMU_FTR_SLB)) - mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, - max_entries); - else - mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array, - max_entries); - - printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks); - for (i = 0; i < mem_blocks; ++i) { - printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n" - " abs chunks %016lx - %016lx\n", - i, mb_array[i].logicalStart, mb_array[i].logicalEnd, - mb_array[i].absStart, mb_array[i].absEnd); - } - return mem_blocks; -} - -static void __init iSeries_get_cmdline(void) -{ - char *p, *q; - - /* copy the command line parameter from the primary VSP */ - HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, - HvLpDma_Direction_RemoteToLocal); - - p = cmd_line; - q = cmd_line + 255; - while(p < q) { - if (!*p || *p == '\n') - break; - ++p; - } - *p = 0; -} - -static void __init iSeries_init_early(void) -{ - DBG(" -> iSeries_init_early()\n"); - - /* Snapshot the timebase, for use in later recalibration */ - iSeries_time_init_early(); - - /* - * Initialize the DMA/TCE management - */ - iommu_init_early_iSeries(); - - /* Initialize machine-dependency vectors */ -#ifdef CONFIG_SMP - smp_init_iSeries(); -#endif - - /* Associate Lp Event Queue 0 with processor 0 */ - HvCallEvent_setLpEventQueueInterruptProc(0, 0); - - mf_init(); - - DBG(" <- iSeries_init_early()\n"); -} - -struct mschunks_map mschunks_map = { - /* XXX We don't use these, but Piranha might need them. */ - .chunk_size = MSCHUNKS_CHUNK_SIZE, - .chunk_shift = MSCHUNKS_CHUNK_SHIFT, - .chunk_mask = MSCHUNKS_OFFSET_MASK, -}; -EXPORT_SYMBOL(mschunks_map); - -static void mschunks_alloc(unsigned long num_chunks) -{ - klimit = _ALIGN(klimit, sizeof(u32)); - mschunks_map.mapping = (u32 *)klimit; - klimit += num_chunks * sizeof(u32); - mschunks_map.num_chunks = num_chunks; -} - -/* - * The iSeries may have very large memories ( > 128 GB ) and a partition - * may get memory in "chunks" that may be anywhere in the 2**52 real - * address space. The chunks are 256K in size. To map this to the - * memory model Linux expects, the AS/400 specific code builds a - * translation table to translate what Linux thinks are "physical" - * addresses to the actual real addresses. This allows us to make - * it appear to Linux that we have contiguous memory starting at - * physical address zero while in fact this could be far from the truth. - * To avoid confusion, I'll let the words physical and/or real address - * apply to the Linux addresses while I'll use "absolute address" to - * refer to the actual hardware real address. - * - * build_iSeries_Memory_Map gets information from the Hypervisor and - * looks at the Main Store VPD to determine the absolute addresses - * of the memory that has been assigned to our partition and builds - * a table used to translate Linux's physical addresses to these - * absolute addresses. Absolute addresses are needed when - * communicating with the hypervisor (e.g. to build HPT entries) - * - * Returns the physical memory size - */ - -static unsigned long __init build_iSeries_Memory_Map(void) -{ - u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; - u32 nextPhysChunk; - u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; - u32 totalChunks,moreChunks; - u32 currChunk, thisChunk, absChunk; - u32 currDword; - u32 chunkBit; - u64 map; - struct MemoryBlock mb[32]; - unsigned long numMemoryBlocks, curBlock; - - /* Chunk size on iSeries is 256K bytes */ - totalChunks = (u32)HvLpConfig_getMsChunks(); - mschunks_alloc(totalChunks); - - /* - * Get absolute address of our load area - * and map it to physical address 0 - * This guarantees that the loadarea ends up at physical 0 - * otherwise, it might not be returned by PLIC as the first - * chunks - */ - - loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr); - loadAreaSize = itLpNaca.xLoadAreaChunks; - - /* - * Only add the pages already mapped here. - * Otherwise we might add the hpt pages - * The rest of the pages of the load area - * aren't in the HPT yet and can still - * be assigned an arbitrary physical address - */ - if ((loadAreaSize * 64) > HvPagesToMap) - loadAreaSize = HvPagesToMap / 64; - - loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; - - /* - * TODO Do we need to do something if the HPT is in the 64MB load area? - * This would be required if the itLpNaca.xLoadAreaChunks includes - * the HPT size - */ - - printk("Mapping load area - physical addr = 0000000000000000\n" - " absolute addr = %016lx\n", - chunk_to_addr(loadAreaFirstChunk)); - printk("Load area size %dK\n", loadAreaSize * 256); - - for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) - mschunks_map.mapping[nextPhysChunk] = - loadAreaFirstChunk + nextPhysChunk; - - /* - * Get absolute address of our HPT and remember it so - * we won't map it to any physical address - */ - hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); - hptSizePages = (u32)HvCallHpt_getHptPages(); - hptSizeChunks = hptSizePages >> - (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT); - hptLastChunk = hptFirstChunk + hptSizeChunks - 1; - - printk("HPT absolute addr = %016lx, size = %dK\n", - chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); - - /* - * Determine if absolute memory has any - * holes so that we can interpret the - * access map we get back from the hypervisor - * correctly. - */ - numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32); - - /* - * Process the main store access map from the hypervisor - * to build up our physical -> absolute translation table - */ - curBlock = 0; - currChunk = 0; - currDword = 0; - moreChunks = totalChunks; - - while (moreChunks) { - map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex, - currDword); - thisChunk = currChunk; - while (map) { - chunkBit = map >> 63; - map <<= 1; - if (chunkBit) { - --moreChunks; - while (thisChunk >= mb[curBlock].logicalEnd) { - ++curBlock; - if (curBlock >= numMemoryBlocks) - panic("out of memory blocks"); - } - if (thisChunk < mb[curBlock].logicalStart) - panic("memory block error"); - - absChunk = mb[curBlock].absStart + - (thisChunk - mb[curBlock].logicalStart); - if (((absChunk < hptFirstChunk) || - (absChunk > hptLastChunk)) && - ((absChunk < loadAreaFirstChunk) || - (absChunk > loadAreaLastChunk))) { - mschunks_map.mapping[nextPhysChunk] = - absChunk; - ++nextPhysChunk; - } - } - ++thisChunk; - } - ++currDword; - currChunk += 64; - } - - /* - * main store size (in chunks) is - * totalChunks - hptSizeChunks - * which should be equal to - * nextPhysChunk - */ - return chunk_to_addr(nextPhysChunk); -} - -/* - * Document me. - */ -static void __init iSeries_setup_arch(void) -{ - if (get_lppaca()->shared_proc) { - ppc_md.idle_loop = iseries_shared_idle; - printk(KERN_DEBUG "Using shared processor idle loop\n"); - } else { - ppc_md.idle_loop = iseries_dedicated_idle; - printk(KERN_DEBUG "Using dedicated idle loop\n"); - } - - /* Setup the Lp Event Queue */ - setup_hvlpevent_queue(); - - printk("Max logical processors = %d\n", - itVpdAreas.xSlicMaxLogicalProcs); - printk("Max physical processors = %d\n", - itVpdAreas.xSlicMaxPhysicalProcs); - - iSeries_pcibios_init(); -} - -static void iSeries_show_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); -} - -static void __init iSeries_progress(char * st, unsigned short code) -{ - printk("Progress: [%04x] - %s\n", (unsigned)code, st); - mf_display_progress(code); -} - -static void __init iSeries_fixup_klimit(void) -{ - /* - * Change klimit to take into account any ram disk - * that may be included - */ - if (naca.xRamDisk) - klimit = KERNELBASE + (u64)naca.xRamDisk + - (naca.xRamDiskSize * HW_PAGE_SIZE); -} - -static int __init iSeries_src_init(void) -{ - /* clear the progress line */ - if (firmware_has_feature(FW_FEATURE_ISERIES)) - ppc_md.progress(" ", 0xffff); - return 0; -} - -late_initcall(iSeries_src_init); - -static inline void process_iSeries_events(void) -{ - asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); -} - -static void yield_shared_processor(void) -{ - unsigned long tb; - - HvCall_setEnabledInterrupts(HvCall_MaskIPI | - HvCall_MaskLpEvent | - HvCall_MaskLpProd | - HvCall_MaskTimeout); - - tb = get_tb(); - /* Compute future tb value when yield should expire */ - HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); - - /* - * The decrementer stops during the yield. Force a fake decrementer - * here and let the timer_interrupt code sort out the actual time. - */ - get_lppaca()->int_dword.fields.decr_int = 1; - ppc64_runlatch_on(); - process_iSeries_events(); -} - -static void iseries_shared_idle(void) -{ - while (1) { - tick_nohz_idle_enter(); - rcu_idle_enter(); - while (!need_resched() && !hvlpevent_is_pending()) { - local_irq_disable(); - ppc64_runlatch_off(); - - /* Recheck with irqs off */ - if (!need_resched() && !hvlpevent_is_pending()) - yield_shared_processor(); - - HMT_medium(); - local_irq_enable(); - } - - ppc64_runlatch_on(); - rcu_idle_exit(); - tick_nohz_idle_exit(); - - if (hvlpevent_is_pending()) - process_iSeries_events(); - - schedule_preempt_disabled(); - } -} - -static void iseries_dedicated_idle(void) -{ - set_thread_flag(TIF_POLLING_NRFLAG); - - while (1) { - tick_nohz_idle_enter(); - rcu_idle_enter(); - if (!need_resched()) { - while (!need_resched()) { - ppc64_runlatch_off(); - HMT_low(); - - if (hvlpevent_is_pending()) { - HMT_medium(); - ppc64_runlatch_on(); - process_iSeries_events(); - } - } - - HMT_medium(); - } - - ppc64_runlatch_on(); - rcu_idle_exit(); - tick_nohz_idle_exit(); - schedule_preempt_disabled(); - } -} - -static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size, - unsigned long flags, void *caller) -{ - return (void __iomem *)address; -} - -static void iseries_iounmap(volatile void __iomem *token) -{ -} - -static int __init iseries_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) - return 0; - - hpte_init_iSeries(); - /* iSeries does not support 16M pages */ - cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; - - return 1; -} - -#ifdef CONFIG_KEXEC -static int iseries_kexec_prepare(struct kimage *image) -{ - return -ENOSYS; -} -#endif - -define_machine(iseries) { - .name = "iSeries", - .setup_arch = iSeries_setup_arch, - .show_cpuinfo = iSeries_show_cpuinfo, - .init_IRQ = iSeries_init_IRQ, - .get_irq = iSeries_get_irq, - .init_early = iSeries_init_early, - .pcibios_fixup = iSeries_pci_final_fixup, - .pcibios_fixup_resources= iSeries_pcibios_fixup_resources, - .restart = mf_reboot, - .power_off = mf_power_off, - .halt = mf_power_off, - .get_boot_time = iSeries_get_boot_time, - .set_rtc_time = iSeries_set_rtc_time, - .get_rtc_time = iSeries_get_rtc_time, - .calibrate_decr = generic_calibrate_decr, - .progress = iSeries_progress, - .probe = iseries_probe, - .ioremap = iseries_ioremap, - .iounmap = iseries_iounmap, -#ifdef CONFIG_KEXEC - .machine_kexec_prepare = iseries_kexec_prepare, -#endif - /* XXX Implement enable_pmcs for iSeries */ -}; - -void * __init iSeries_early_setup(void) -{ - unsigned long phys_mem_size; - - /* Identify CPU type. This is done again by the common code later - * on but calling this function multiple times is fine. - */ - identify_cpu(0, mfspr(SPRN_PVR)); - initialise_paca(&boot_paca, 0); - - powerpc_firmware_features |= FW_FEATURE_ISERIES; - powerpc_firmware_features |= FW_FEATURE_LPAR; - -#ifdef CONFIG_SMP - /* On iSeries we know we can never have more than 64 cpus */ - nr_cpu_ids = max(nr_cpu_ids, 64); -#endif - - iSeries_fixup_klimit(); - - /* - * Initialize the table which translate Linux physical addresses to - * AS/400 absolute addresses - */ - phys_mem_size = build_iSeries_Memory_Map(); - - iSeries_get_cmdline(); - - return (void *) __pa(build_flat_dt(phys_mem_size)); -} - -static void hvputc(char c) -{ - if (c == '\n') - hvputc('\r'); - - HvCall_writeLogBuffer(&c, 1); -} - -void __init udbg_init_iseries(void) -{ - udbg_putc = hvputc; -} diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h deleted file mode 100644 index 729754bbb018..000000000000 --- a/arch/powerpc/platforms/iseries/setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and - * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek - * <dan@netx4.com>. - * - * 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. - */ - -#ifndef __ISERIES_SETUP_H__ -#define __ISERIES_SETUP_H__ - -extern void *iSeries_early_setup(void); -extern unsigned long iSeries_get_boot_time(void); -extern int iSeries_set_rtc_time(struct rtc_time *tm); -extern void iSeries_get_rtc_time(struct rtc_time *tm); - -extern void *build_flat_dt(unsigned long phys_mem_size); - -#endif /* __ISERIES_SETUP_H__ */ diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c deleted file mode 100644 index 02df49fb59f0..000000000000 --- a/arch/powerpc/platforms/iseries/smp.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SMP support for iSeries machines. - * - * Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * - * Plus various changes from other IBM teams... - * - * 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. - */ - -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> -#include <linux/err.h> -#include <linux/device.h> -#include <linux/cpu.h> - -#include <asm/ptrace.h> -#include <linux/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/paca.h> -#include <asm/iseries/hv_call.h> -#include <asm/time.h> -#include <asm/machdep.h> -#include <asm/cputable.h> -#include <asm/system.h> - -static void smp_iSeries_cause_ipi(int cpu, unsigned long data) -{ - HvCall_sendIPI(&(paca[cpu])); -} - -static int smp_iSeries_probe(void) -{ - return cpumask_weight(cpu_possible_mask); -} - -static int smp_iSeries_kick_cpu(int nr) -{ - BUG_ON((nr < 0) || (nr >= NR_CPUS)); - - /* Verify that our partition has a processor nr */ - if (lppaca_of(nr).dyn_proc_status >= 2) - return -ENOENT; - - /* The processor is currently spinning, waiting - * for the cpu_start field to become non-zero - * After we set cpu_start, the processor will - * continue on to secondary_start in iSeries_head.S - */ - paca[nr].cpu_start = 1; - - return 0; -} - -static void __devinit smp_iSeries_setup_cpu(int nr) -{ -} - -static struct smp_ops_t iSeries_smp_ops = { - .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */ - .cause_ipi = smp_iSeries_cause_ipi, - .probe = smp_iSeries_probe, - .kick_cpu = smp_iSeries_kick_cpu, - .setup_cpu = smp_iSeries_setup_cpu, -}; - -/* This is called very early. */ -void __init smp_init_iSeries(void) -{ - smp_ops = &iSeries_smp_ops; -} diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h deleted file mode 100644 index 598b7c14573a..000000000000 --- a/arch/powerpc/platforms/iseries/spcomm_area.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ISERIES_SPCOMM_AREA_H -#define _ISERIES_SPCOMM_AREA_H - - -struct SpCommArea { - u32 xDesc; // Descriptor (only in new formats) 000-003 - u8 xFormat; // Format (only in new formats) 004-004 - u8 xRsvd1[11]; // Reserved 005-00F - u64 xRawTbAtIplStart; // Raw HW TB value when IPL is started 010-017 - u64 xRawTodAtIplStart; // Raw HW TOD value when IPL is started 018-01F - u64 xBcdTimeAtIplStart; // BCD time when IPL is started 020-027 - u64 xBcdTimeAtOsStart; // BCD time when OS passed control 028-02F - u8 xRsvd2[80]; // Reserved 030-07F -}; - -#endif /* _ISERIES_SPCOMM_AREA_H */ diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c deleted file mode 100644 index 04be62d368a6..000000000000 --- a/arch/powerpc/platforms/iseries/vio.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Legacy iSeries specific vio initialisation - * that needs to be built in (not a module). - * - * © Copyright 2007 IBM Corporation - * Author: Stephen Rothwell - * Some parts collected from various other files - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/of.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/completion.h> -#include <linux/proc_fs.h> -#include <linux/export.h> - -#include <asm/firmware.h> -#include <asm/vio.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/iommu.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> - -#define FIRST_VTY 0 -#define NUM_VTYS 1 -#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) -#define NUM_VSCSIS 1 -#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) -#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS -#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) -#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS -#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) -#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS -#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) -#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES - -struct vio_waitevent { - struct completion com; - int rc; - u16 sub_result; -}; - -struct vio_resource { - char rsrcname[10]; - char type[4]; - char model[3]; -}; - -static struct property *new_property(const char *name, int length, - const void *value) -{ - struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, - GFP_KERNEL); - - if (!np) - return NULL; - np->name = (char *)(np + 1); - np->value = np->name + strlen(name) + 1; - strcpy(np->name, name); - memcpy(np->value, value, length); - np->length = length; - return np; -} - -static void free_property(struct property *np) -{ - kfree(np); -} - -static struct device_node *new_node(const char *path, - struct device_node *parent) -{ - struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); - - if (!np) - return NULL; - np->full_name = kstrdup(path, GFP_KERNEL); - if (!np->full_name) { - kfree(np); - return NULL; - } - of_node_set_flag(np, OF_DYNAMIC); - kref_init(&np->kref); - np->parent = of_node_get(parent); - return np; -} - -static void free_node(struct device_node *np) -{ - struct property *next; - struct property *prop; - - next = np->properties; - while (next) { - prop = next; - next = prop->next; - free_property(prop); - } - of_node_put(np->parent); - kfree(np->full_name); - kfree(np); -} - -static int add_string_property(struct device_node *np, const char *name, - const char *value) -{ - struct property *nprop = new_property(name, strlen(value) + 1, value); - - if (!nprop) - return 0; - prom_add_property(np, nprop); - return 1; -} - -static int add_raw_property(struct device_node *np, const char *name, - int length, const void *value) -{ - struct property *nprop = new_property(name, length, value); - - if (!nprop) - return 0; - prom_add_property(np, nprop); - return 1; -} - -static struct device_node *do_device_node(struct device_node *parent, - const char *name, u32 reg, u32 unit, const char *type, - const char *compat, struct vio_resource *res) -{ - struct device_node *np; - char path[32]; - - snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); - np = new_node(path, parent); - if (!np) - return NULL; - if (!add_string_property(np, "name", name) || - !add_string_property(np, "device_type", type) || - !add_string_property(np, "compatible", compat) || - !add_raw_property(np, "reg", sizeof(reg), ®) || - !add_raw_property(np, "linux,unit_address", - sizeof(unit), &unit)) { - goto node_free; - } - if (res) { - if (!add_raw_property(np, "linux,vio_rsrcname", - sizeof(res->rsrcname), res->rsrcname) || - !add_raw_property(np, "linux,vio_type", - sizeof(res->type), res->type) || - !add_raw_property(np, "linux,vio_model", - sizeof(res->model), res->model)) - goto node_free; - } - np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - of_attach_node(np); -#ifdef CONFIG_PROC_DEVICETREE - if (parent->pde) { - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); - if (ent) - proc_device_tree_add_node(np, ent); - } -#endif - return np; - - node_free: - free_node(np); - return NULL; -} - -/* - * This is here so that we can dynamically add viodasd - * devices without exposing all the above infrastructure. - */ -struct vio_dev *vio_create_viodasd(u32 unit) -{ - struct device_node *vio_root; - struct device_node *np; - struct vio_dev *vdev = NULL; - - vio_root = of_find_node_by_path("/vdevice"); - if (!vio_root) - return NULL; - np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, - "block", "IBM,iSeries-viodasd", NULL); - of_node_put(vio_root); - if (np) { - vdev = vio_register_device_node(np); - if (!vdev) - free_node(np); - } - return vdev; -} -EXPORT_SYMBOL_GPL(vio_create_viodasd); - -static void __init handle_block_event(struct HvLpEvent *event) -{ - struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; - struct vio_waitevent *pwe; - - if (event == NULL) - /* Notification that a partition went away! */ - return; - /* First, we should NEVER get an int here...only acks */ - if (hvlpevent_is_int(event)) { - printk(KERN_WARNING "handle_viod_request: " - "Yikes! got an int in viodasd event handler!\n"); - if (hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - return; - } - - switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { - case vioblockopen: - /* - * Handle a response to an open request. We get all the - * disk information in the response, so update it. The - * correlation token contains a pointer to a waitevent - * structure that has a completion in it. update the - * return code in the waitevent structure and post the - * completion to wake up the guy who sent the request - */ - pwe = (struct vio_waitevent *)event->xCorrelationToken; - pwe->rc = event->xRc; - pwe->sub_result = bevent->sub_result; - complete(&pwe->com); - break; - case vioblockclose: - break; - default: - printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); - if (hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - } -} - -static void __init probe_disk(struct device_node *vio_root, u32 unit) -{ - HvLpEvent_Rc hvrc; - struct vio_waitevent we; - u16 flags = 0; - -retry: - init_completion(&we.com); - - /* Send the open event to OS/400 */ - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_blockio | vioblockopen, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)(unsigned long)&we, VIOVERSION << 16, - ((u64)unit << 48) | ((u64)flags<< 32), - 0, 0, 0); - if (hvrc != 0) { - printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", - (int)hvrc); - return; - } - - wait_for_completion(&we.com); - - if (we.rc != 0) { - if (flags != 0) - return; - /* try again with read only flag set */ - flags = vioblockflags_ro; - goto retry; - } - - /* Send the close event to OS/400. We DON'T expect a response */ - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_blockio | vioblockclose, - HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - 0, VIOVERSION << 16, - ((u64)unit << 48) | ((u64)flags << 32), - 0, 0, 0); - if (hvrc != 0) { - printk(KERN_WARNING "probe_disk: " - "bad rc sending event to OS/400 %d\n", (int)hvrc); - return; - } - - do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, - "block", "IBM,iSeries-viodasd", NULL); -} - -static void __init get_viodasd_info(struct device_node *vio_root) -{ - int rc; - u32 unit; - - rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); - if (rc) { - printk(KERN_WARNING "get_viodasd_info: " - "error opening path to host partition %d\n", - viopath_hostLp); - return; - } - - /* Initialize our request handler */ - vio_setHandler(viomajorsubtype_blockio, handle_block_event); - - for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) - probe_disk(vio_root, unit); - - vio_clearHandler(viomajorsubtype_blockio); - viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); -} - -static void __init handle_cd_event(struct HvLpEvent *event) -{ - struct viocdlpevent *bevent; - struct vio_waitevent *pwe; - - if (!event) - /* Notification that a partition went away! */ - return; - - /* First, we should NEVER get an int here...only acks */ - if (hvlpevent_is_int(event)) { - printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); - if (hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - return; - } - - bevent = (struct viocdlpevent *)event; - - switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { - case viocdgetinfo: - pwe = (struct vio_waitevent *)event->xCorrelationToken; - pwe->rc = event->xRc; - pwe->sub_result = bevent->sub_result; - complete(&pwe->com); - break; - - default: - printk(KERN_WARNING "handle_cd_event: " - "message with unexpected subtype %0x04X!\n", - event->xSubtype & VIOMINOR_SUBTYPE_MASK); - if (hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - } -} - -static void __init get_viocd_info(struct device_node *vio_root) -{ - HvLpEvent_Rc hvrc; - u32 unit; - struct vio_waitevent we; - struct vio_resource *unitinfo; - dma_addr_t unitinfo_dmaaddr; - int ret; - - ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); - if (ret) { - printk(KERN_WARNING - "get_viocd_info: error opening path to host partition %d\n", - viopath_hostLp); - return; - } - - /* Initialize our request handler */ - vio_setHandler(viomajorsubtype_cdio, handle_cd_event); - - unitinfo = iseries_hv_alloc( - sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, - &unitinfo_dmaaddr, GFP_ATOMIC); - if (!unitinfo) { - printk(KERN_WARNING - "get_viocd_info: error allocating unitinfo\n"); - goto clear_handler; - } - - memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); - - init_completion(&we.com); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_cdio | viocdgetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, - sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(KERN_WARNING - "get_viocd_info: cdrom error sending event. rc %d\n", - (int)hvrc); - goto hv_free; - } - - wait_for_completion(&we.com); - - if (we.rc) { - printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", - we.rc, we.sub_result); - goto hv_free; - } - - for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && - unitinfo[unit].rsrcname[0]; unit++) { - if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, - "block", "IBM,iSeries-viocd", &unitinfo[unit])) - break; - } - - hv_free: - iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, - unitinfo, unitinfo_dmaaddr); - clear_handler: - vio_clearHandler(viomajorsubtype_cdio); - viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); -} - -/* Handle interrupt events for tape */ -static void __init handle_tape_event(struct HvLpEvent *event) -{ - struct vio_waitevent *we; - struct viotapelpevent *tevent = (struct viotapelpevent *)event; - - if (event == NULL) - /* Notification that a partition went away! */ - return; - - we = (struct vio_waitevent *)event->xCorrelationToken; - switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { - case viotapegetinfo: - we->rc = tevent->sub_type_result; - complete(&we->com); - break; - default: - printk(KERN_WARNING "handle_tape_event: weird ack\n"); - } -} - -static void __init get_viotape_info(struct device_node *vio_root) -{ - HvLpEvent_Rc hvrc; - u32 unit; - struct vio_resource *unitinfo; - dma_addr_t unitinfo_dmaaddr; - size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; - struct vio_waitevent we; - int ret; - - init_completion(&we.com); - - ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); - if (ret) { - printk(KERN_WARNING "get_viotape_info: " - "error on viopath_open to hostlp %d\n", ret); - return; - } - - vio_setHandler(viomajorsubtype_tape, handle_tape_event); - - unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); - if (!unitinfo) - goto clear_handler; - - memset(unitinfo, 0, len); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_tape | viotapegetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)(unsigned long)&we, VIOVERSION << 16, - unitinfo_dmaaddr, len, 0, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", - (int)hvrc); - goto hv_free; - } - - wait_for_completion(&we.com); - - for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && - unitinfo[unit].rsrcname[0]; unit++) { - if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, - unit, "byte", "IBM,iSeries-viotape", - &unitinfo[unit])) - break; - } - - hv_free: - iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); - clear_handler: - vio_clearHandler(viomajorsubtype_tape); - viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); -} - -static int __init iseries_vio_init(void) -{ - struct device_node *vio_root; - int ret = -ENODEV; - - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - goto out; - - iommu_vio_init(); - - vio_root = of_find_node_by_path("/vdevice"); - if (!vio_root) - goto out; - - if (viopath_hostLp == HvLpIndexInvalid) { - vio_set_hostlp(); - /* If we don't have a host, bail out */ - if (viopath_hostLp == HvLpIndexInvalid) - goto put_node; - } - - get_viodasd_info(vio_root); - get_viocd_info(vio_root); - get_viotape_info(vio_root); - - ret = 0; - - put_node: - of_node_put(vio_root); - out: - return ret; -} -arch_initcall(iseries_vio_init); diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c deleted file mode 100644 index 40dad0840eb3..000000000000 --- a/arch/powerpc/platforms/iseries/viopath.c +++ /dev/null @@ -1,677 +0,0 @@ -/* -*- linux-c -*- - * - * iSeries Virtual I/O Message Path code - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * - * (C) Copyright 2000-2005 IBM Corporation - * - * This code is used by the iSeries virtual disk, cd, - * tape, and console to communicate with OS/400 in another - * partition. - * - * 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) anyu 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#include <linux/export.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/vmalloc.h> -#include <linux/string.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/wait.h> -#include <linux/seq_file.h> -#include <linux/interrupt.h> -#include <linux/completion.h> - -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/prom.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/vio.h> - -/* Status of the path to each other partition in the system. - * This is overkill, since we will only ever establish connections - * to our hosting partition and the primary partition on the system. - * But this allows for other support in the future. - */ -static struct viopathStatus { - int isOpen; /* Did we open the path? */ - int isActive; /* Do we have a mon msg outstanding */ - int users[VIO_MAX_SUBTYPES]; - HvLpInstanceId mSourceInst; - HvLpInstanceId mTargetInst; - int numberAllocated; -} viopathStatus[HVMAXARCHITECTEDLPS]; - -static DEFINE_SPINLOCK(statuslock); - -/* - * For each kind of event we allocate a buffer that is - * guaranteed not to cross a page boundary - */ -static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] - __attribute__((__aligned__(4096))); -static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; -static int event_buffer_initialised; - -static void handleMonitorEvent(struct HvLpEvent *event); - -/* - * We use this structure to handle asynchronous responses. The caller - * blocks on the semaphore and the handler posts the semaphore. However, - * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ... - */ -struct alloc_parms { - struct completion done; - int number; - atomic_t wait_atomic; - int used_wait_atomic; -}; - -/* Put a sequence number in each mon msg. The value is not - * important. Start at something other than 0 just for - * readability. wrapping this is ok. - */ -static u8 viomonseq = 22; - -/* Our hosting logical partition. We get this at startup - * time, and different modules access this variable directly. - */ -HvLpIndex viopath_hostLp = HvLpIndexInvalid; -EXPORT_SYMBOL(viopath_hostLp); -HvLpIndex viopath_ourLp = HvLpIndexInvalid; -EXPORT_SYMBOL(viopath_ourLp); - -/* For each kind of incoming event we set a pointer to a - * routine to call. - */ -static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES]; - -#define VIOPATH_KERN_WARN KERN_WARNING "viopath: " -#define VIOPATH_KERN_INFO KERN_INFO "viopath: " - -static int proc_viopath_show(struct seq_file *m, void *v) -{ - char *buf; - u16 vlanMap; - dma_addr_t handle; - HvLpEvent_Rc hvrc; - DECLARE_COMPLETION_ONSTACK(done); - struct device_node *node; - const char *sysid; - - buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL); - if (!buf) - return 0; - - handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_config | vioconfigget, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)(unsigned long)&done, VIOVERSION << 16, - ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0); - - if (hvrc != HvLpEvent_Rc_Good) - printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); - - wait_for_completion(&done); - - vlanMap = HvLpConfig_getVirtualLanIndexMap(); - - buf[HW_PAGE_SIZE-1] = '\0'; - seq_printf(m, "%s", buf); - - iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); - kfree(buf); - - seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); - - node = of_find_node_by_path("/"); - sysid = NULL; - if (node != NULL) - sysid = of_get_property(node, "system-id", NULL); - - if (sysid == NULL) - seq_printf(m, "SRLNBR=<UNKNOWN>\n"); - else - /* Skip "IBM," on front of serial number, see dt.c */ - seq_printf(m, "SRLNBR=%s\n", sysid + 4); - - of_node_put(node); - - return 0; -} - -static int proc_viopath_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_viopath_show, NULL); -} - -static const struct file_operations proc_viopath_operations = { - .open = proc_viopath_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init vio_proc_init(void) -{ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; - - proc_create("iSeries/config", 0, NULL, &proc_viopath_operations); - return 0; -} -__initcall(vio_proc_init); - -/* See if a given LP is active. Allow for invalid lps to be passed in - * and just return invalid - */ -int viopath_isactive(HvLpIndex lp) -{ - if (lp == HvLpIndexInvalid) - return 0; - if (lp < HVMAXARCHITECTEDLPS) - return viopathStatus[lp].isActive; - else - return 0; -} -EXPORT_SYMBOL(viopath_isactive); - -/* - * We cache the source and target instance ids for each - * partition. - */ -HvLpInstanceId viopath_sourceinst(HvLpIndex lp) -{ - return viopathStatus[lp].mSourceInst; -} -EXPORT_SYMBOL(viopath_sourceinst); - -HvLpInstanceId viopath_targetinst(HvLpIndex lp) -{ - return viopathStatus[lp].mTargetInst; -} -EXPORT_SYMBOL(viopath_targetinst); - -/* - * Send a monitor message. This is a message with the acknowledge - * bit on that the other side will NOT explicitly acknowledge. When - * the other side goes down, the hypervisor will acknowledge any - * outstanding messages....so we will know when the other side dies. - */ -static void sendMonMsg(HvLpIndex remoteLp) -{ - HvLpEvent_Rc hvrc; - - viopathStatus[remoteLp].mSourceInst = - HvCallEvent_getSourceLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - viopathStatus[remoteLp].mTargetInst = - HvCallEvent_getTargetLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - - /* - * Deliberately ignore the return code here. if we call this - * more than once, we don't care. - */ - vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); - - hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, - viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck, - HvLpEvent_AckType_DeferredAck, - viopathStatus[remoteLp].mSourceInst, - viopathStatus[remoteLp].mTargetInst, - viomonseq++, 0, 0, 0, 0, 0); - - if (hvrc == HvLpEvent_Rc_Good) - viopathStatus[remoteLp].isActive = 1; - else { - printk(VIOPATH_KERN_WARN "could not connect to partition %d\n", - remoteLp); - viopathStatus[remoteLp].isActive = 0; - } -} - -static void handleMonitorEvent(struct HvLpEvent *event) -{ - HvLpIndex remoteLp; - int i; - - /* - * This handler is _also_ called as part of the loop - * at the end of this routine, so it must be able to - * ignore NULL events... - */ - if (!event) - return; - - /* - * First see if this is just a normal monitor message from the - * other partition - */ - if (hvlpevent_is_int(event)) { - remoteLp = event->xSourceLp; - if (!viopathStatus[remoteLp].isActive) - sendMonMsg(remoteLp); - return; - } - - /* - * This path is for an acknowledgement; the other partition - * died - */ - remoteLp = event->xTargetLp; - if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) || - (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) { - printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n"); - return; - } - - printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp); - - viopathStatus[remoteLp].isActive = 0; - - /* - * For each active handler, pass them a NULL - * message to indicate that the other partition - * died - */ - for (i = 0; i < VIO_MAX_SUBTYPES; i++) { - if (vio_handler[i] != NULL) - (*vio_handler[i])(NULL); - } -} - -int vio_setHandler(int subtype, vio_event_handler_t *beh) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - if (vio_handler[subtype] != NULL) - return -EBUSY; - vio_handler[subtype] = beh; - return 0; -} -EXPORT_SYMBOL(vio_setHandler); - -int vio_clearHandler(int subtype) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - if (vio_handler[subtype] == NULL) - return -EAGAIN; - vio_handler[subtype] = NULL; - return 0; -} -EXPORT_SYMBOL(vio_clearHandler); - -static void handleConfig(struct HvLpEvent *event) -{ - if (!event) - return; - if (hvlpevent_is_int(event)) { - printk(VIOPATH_KERN_WARN - "unexpected config request from partition %d", - event->xSourceLp); - - if (hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - return; - } - - complete((struct completion *)event->xCorrelationToken); -} - -/* - * Initialization of the hosting partition - */ -void vio_set_hostlp(void) -{ - /* - * If this has already been set then we DON'T want to either change - * it or re-register the proc file system - */ - if (viopath_hostLp != HvLpIndexInvalid) - return; - - /* - * Figure out our hosting partition. This isn't allowed to change - * while we're active - */ - viopath_ourLp = HvLpConfig_getLpIndex(); - viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); - - if (viopath_hostLp != HvLpIndexInvalid) - vio_setHandler(viomajorsubtype_config, handleConfig); -} -EXPORT_SYMBOL(vio_set_hostlp); - -static void vio_handleEvent(struct HvLpEvent *event) -{ - HvLpIndex remoteLp; - int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) - >> VIOMAJOR_SUBTYPE_SHIFT; - - if (hvlpevent_is_int(event)) { - remoteLp = event->xSourceLp; - /* - * The isActive is checked because if the hosting partition - * went down and came back up it would not be active but it - * would have different source and target instances, in which - * case we'd want to reset them. This case really protects - * against an unauthorized active partition sending interrupts - * or acks to this linux partition. - */ - if (viopathStatus[remoteLp].isActive - && (event->xSourceInstanceId != - viopathStatus[remoteLp].mTargetInst)) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "int msg rcvd, source inst (%d) doesn't match (%d)\n", - viopathStatus[remoteLp].mTargetInst, - event->xSourceInstanceId); - return; - } - - if (viopathStatus[remoteLp].isActive - && (event->xTargetInstanceId != - viopathStatus[remoteLp].mSourceInst)) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "int msg rcvd, target inst (%d) doesn't match (%d)\n", - viopathStatus[remoteLp].mSourceInst, - event->xTargetInstanceId); - return; - } - } else { - remoteLp = event->xTargetLp; - if (event->xSourceInstanceId != - viopathStatus[remoteLp].mSourceInst) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "ack msg rcvd, source inst (%d) doesn't match (%d)\n", - viopathStatus[remoteLp].mSourceInst, - event->xSourceInstanceId); - return; - } - - if (event->xTargetInstanceId != - viopathStatus[remoteLp].mTargetInst) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n", - viopathStatus[remoteLp].mTargetInst, - event->xTargetInstanceId); - return; - } - } - - if (vio_handler[subtype] == NULL) { - printk(VIOPATH_KERN_WARN - "unexpected virtual io event subtype %d from partition %d\n", - event->xSubtype, remoteLp); - /* No handler. Ack if necessary */ - if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - return; - } - - /* This innocuous little line is where all the real work happens */ - (*vio_handler[subtype])(event); -} - -static void viopath_donealloc(void *parm, int number) -{ - struct alloc_parms *parmsp = parm; - - parmsp->number = number; - if (parmsp->used_wait_atomic) - atomic_set(&parmsp->wait_atomic, 0); - else - complete(&parmsp->done); -} - -static int allocateEvents(HvLpIndex remoteLp, int numEvents) -{ - struct alloc_parms parms; - - if (system_state != SYSTEM_RUNNING) { - parms.used_wait_atomic = 1; - atomic_set(&parms.wait_atomic, 1); - } else { - parms.used_wait_atomic = 0; - init_completion(&parms.done); - } - mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */ - numEvents, &viopath_donealloc, &parms); - if (system_state != SYSTEM_RUNNING) { - while (atomic_read(&parms.wait_atomic)) - mb(); - } else - wait_for_completion(&parms.done); - return parms.number; -} - -int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) -{ - int i; - unsigned long flags; - int tempNumAllocated; - - if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) - return -EINVAL; - - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - - spin_lock_irqsave(&statuslock, flags); - - if (!event_buffer_initialised) { - for (i = 0; i < VIO_MAX_SUBTYPES; i++) - atomic_set(&event_buffer_available[i], 1); - event_buffer_initialised = 1; - } - - viopathStatus[remoteLp].users[subtype]++; - - if (!viopathStatus[remoteLp].isOpen) { - viopathStatus[remoteLp].isOpen = 1; - HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo); - - /* - * Don't hold the spinlock during an operation that - * can sleep. - */ - spin_unlock_irqrestore(&statuslock, flags); - tempNumAllocated = allocateEvents(remoteLp, 1); - spin_lock_irqsave(&statuslock, flags); - - viopathStatus[remoteLp].numberAllocated += tempNumAllocated; - - if (viopathStatus[remoteLp].numberAllocated == 0) { - HvCallEvent_closeLpEventPath(remoteLp, - HvLpEvent_Type_VirtualIo); - - spin_unlock_irqrestore(&statuslock, flags); - return -ENOMEM; - } - - viopathStatus[remoteLp].mSourceInst = - HvCallEvent_getSourceLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - viopathStatus[remoteLp].mTargetInst = - HvCallEvent_getTargetLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, - &vio_handleEvent); - sendMonMsg(remoteLp); - printk(VIOPATH_KERN_INFO "opening connection to partition %d, " - "setting sinst %d, tinst %d\n", - remoteLp, viopathStatus[remoteLp].mSourceInst, - viopathStatus[remoteLp].mTargetInst); - } - - spin_unlock_irqrestore(&statuslock, flags); - tempNumAllocated = allocateEvents(remoteLp, numReq); - spin_lock_irqsave(&statuslock, flags); - viopathStatus[remoteLp].numberAllocated += tempNumAllocated; - spin_unlock_irqrestore(&statuslock, flags); - - return 0; -} -EXPORT_SYMBOL(viopath_open); - -int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) -{ - unsigned long flags; - int i; - int numOpen; - struct alloc_parms parms; - - if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) - return -EINVAL; - - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - - spin_lock_irqsave(&statuslock, flags); - /* - * If the viopath_close somehow gets called before a - * viopath_open it could decrement to -1 which is a non - * recoverable state so we'll prevent this from - * happening. - */ - if (viopathStatus[remoteLp].users[subtype] > 0) - viopathStatus[remoteLp].users[subtype]--; - - spin_unlock_irqrestore(&statuslock, flags); - - parms.used_wait_atomic = 0; - init_completion(&parms.done); - mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, - numReq, &viopath_donealloc, &parms); - wait_for_completion(&parms.done); - - spin_lock_irqsave(&statuslock, flags); - for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++) - numOpen += viopathStatus[remoteLp].users[i]; - - if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { - printk(VIOPATH_KERN_INFO "closing connection to partition %d\n", - remoteLp); - - HvCallEvent_closeLpEventPath(remoteLp, - HvLpEvent_Type_VirtualIo); - viopathStatus[remoteLp].isOpen = 0; - viopathStatus[remoteLp].isActive = 0; - - for (i = 0; i < VIO_MAX_SUBTYPES; i++) - atomic_set(&event_buffer_available[i], 0); - event_buffer_initialised = 0; - } - spin_unlock_irqrestore(&statuslock, flags); - return 0; -} -EXPORT_SYMBOL(viopath_close); - -void *vio_get_event_buffer(int subtype) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return NULL; - - if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0) - return &event_buffer[subtype * 256]; - else - return NULL; -} -EXPORT_SYMBOL(vio_get_event_buffer); - -void vio_free_event_buffer(int subtype, void *buffer) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) { - printk(VIOPATH_KERN_WARN - "unexpected subtype %d freeing event buffer\n", subtype); - return; - } - - if (atomic_read(&event_buffer_available[subtype]) != 0) { - printk(VIOPATH_KERN_WARN - "freeing unallocated event buffer, subtype %d\n", - subtype); - return; - } - - if (buffer != &event_buffer[subtype * 256]) { - printk(VIOPATH_KERN_WARN - "freeing invalid event buffer, subtype %d\n", subtype); - } - - atomic_set(&event_buffer_available[subtype], 1); -} -EXPORT_SYMBOL(vio_free_event_buffer); - -static const struct vio_error_entry vio_no_error = - { 0, 0, "Non-VIO Error" }; -static const struct vio_error_entry vio_unknown_error = - { 0, EIO, "Unknown Error" }; - -static const struct vio_error_entry vio_default_errors[] = { - {0x0001, EIO, "No Connection"}, - {0x0002, EIO, "No Receiver"}, - {0x0003, EIO, "No Buffer Available"}, - {0x0004, EBADRQC, "Invalid Message Type"}, - {0x0000, 0, NULL}, -}; - -const struct vio_error_entry *vio_lookup_rc( - const struct vio_error_entry *local_table, u16 rc) -{ - const struct vio_error_entry *cur; - - if (!rc) - return &vio_no_error; - if (local_table) - for (cur = local_table; cur->rc; ++cur) - if (cur->rc == rc) - return cur; - for (cur = vio_default_errors; cur->rc; ++cur) - if (cur->rc == rc) - return cur; - return &vio_unknown_error; -} -EXPORT_SYMBOL(vio_lookup_rc); diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h deleted file mode 100644 index feb001f3a5fe..000000000000 --- a/arch/powerpc/platforms/iseries/vpd_areas.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan IBM 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _ISERIES_VPD_AREAS_H -#define _ISERIES_VPD_AREAS_H - -/* - * This file defines the address and length of all of the VPD area passed to - * the OS from PLIC (most of which start from the SP). - */ - -#include <asm/types.h> - -/* VPD Entry index is carved in stone - cannot be changed (easily). */ -#define ItVpdCecVpd 0 -#define ItVpdDynamicSpace 1 -#define ItVpdExtVpd 2 -#define ItVpdExtVpdOnPanel 3 -#define ItVpdFirstPaca 4 -#define ItVpdIoVpd 5 -#define ItVpdIplParms 6 -#define ItVpdMsVpd 7 -#define ItVpdPanelVpd 8 -#define ItVpdLpNaca 9 -#define ItVpdBackplaneAndMaybeClockCardVpd 10 -#define ItVpdRecoveryLogBuffer 11 -#define ItVpdSpCommArea 12 -#define ItVpdSpLogBuffer 13 -#define ItVpdSpLogBufferSave 14 -#define ItVpdSpCardVpd 15 -#define ItVpdFirstProcVpd 16 -#define ItVpdApModelVpd 17 -#define ItVpdClockCardVpd 18 -#define ItVpdBusExtCardVpd 19 -#define ItVpdProcCapacityVpd 20 -#define ItVpdInteractiveCapacityVpd 21 -#define ItVpdFirstSlotLabel 22 -#define ItVpdFirstLpQueue 23 -#define ItVpdFirstL3CacheVpd 24 -#define ItVpdFirstProcFruVpd 25 - -#define ItVpdMaxEntries 26 - -#define ItDmaMaxEntries 10 - -#define ItVpdAreasMaxSlotLabels 192 - - -struct ItVpdAreas { - u32 xSlicDesc; // Descriptor 000-003 - u16 xSlicSize; // Size of this control block 004-005 - u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-007 - u16 xRsvd1:15; // Reserved bits ... - u16 xSlicVpdEntries; // Number of VPD entries 008-009 - u16 xSlicDmaEntries; // Number of DMA entries 00A-00B - u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D - u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F - u16 xSlicDmaToksOffset; // Offset into this of array 010-011 - u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013 - u16 xSlicDmaLensOffset; // Offset into this of array 014-015 - u16 xSlicVpdLensOffset; // Offset into this of array 016-017 - u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-019 - u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B - u8 xRsvd2[4]; // Reserved 01C-01F - u64 xRsvd3[12]; // Reserved 020-07F - u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7 - u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF - u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F - const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF -}; - -extern const struct ItVpdAreas itVpdAreas; - -#endif /* _ISERIES_VPD_AREAS_H */ diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 0bcbfe7b2c55..3b7545a51aa9 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -262,7 +262,7 @@ static void __init maple_init_IRQ(void) flags |= MPIC_BIG_ENDIAN; /* XXX Maple specific bits */ - flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET; + flags |= MPIC_U3_HT_IRQS; /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ flags |= MPIC_BIG_ENDIAN; diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 98b7a7c13176..e777ad471a48 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -224,7 +224,7 @@ static __init void pas_init_IRQ(void) openpic_addr = of_read_number(opprop, naddr); printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); - mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS; + mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET; nmiprop = of_get_property(mpic_node, "nmi-source", NULL); if (nmiprop) diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 54d227127c9f..da18b26dcc6f 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -279,7 +279,7 @@ static u32 core99_check(u8* datas) static int sm_erase_bank(int bank) { - int stat, i; + int stat; unsigned long timeout; u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -301,11 +301,10 @@ static int sm_erase_bank(int bank) out_8(base, SM_FLASH_CMD_CLEAR_STATUS); out_8(base, SM_FLASH_CMD_RESET); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); - return -ENXIO; - } + if (memchr_inv(base, 0xff, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); + return -ENXIO; + } return 0; } @@ -336,17 +335,16 @@ static int sm_write_bank(int bank, u8* datas) } out_8(base, SM_FLASH_CMD_CLEAR_STATUS); out_8(base, SM_FLASH_CMD_RESET); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); - return -ENXIO; - } + if (memcmp(base, datas, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); + return -ENXIO; + } return 0; } static int amd_erase_bank(int bank) { - int i, stat = 0; + int stat = 0; unsigned long timeout; u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -382,12 +380,11 @@ static int amd_erase_bank(int bank) /* Reset */ out_8(base, 0xf0); udelay(1); - - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk(KERN_ERR "nvram: AMD flash erase failed !\n"); - return -ENXIO; - } + + if (memchr_inv(base, 0xff, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: AMD flash erase failed !\n"); + return -ENXIO; + } return 0; } @@ -429,11 +426,10 @@ static int amd_write_bank(int bank, u8* datas) out_8(base, 0xf0); udelay(1); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk(KERN_ERR "nvram: AMD flash write failed !\n"); - return -ENXIO; - } + if (memcmp(base, datas, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: AMD flash write failed !\n"); + return -ENXIO; + } return 0; } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 7761aabfc293..66ad93de1d55 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock); static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; static int pmac_irq_cascade = -1; -static struct irq_host *pmac_pic_host; +static struct irq_domain *pmac_pic_host; static void __pmac_retrigger(unsigned int irq_nr) { @@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = { .name = "cascade", }; -static int pmac_pic_host_match(struct irq_host *h, struct device_node *node) +static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node) { /* We match all, we don't always have a node anyway */ return 1; } -static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, +static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { if (hw >= max_irqs) @@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, - unsigned int *out_flags) - -{ - *out_flags = IRQ_TYPE_NONE; - *out_hwirq = *intspec; - return 0; -} - -static struct irq_host_ops pmac_pic_host_ops = { +static const struct irq_domain_ops pmac_pic_host_ops = { .match = pmac_pic_host_match, .map = pmac_pic_host_map, - .xlate = pmac_pic_host_xlate, + .xlate = irq_domain_xlate_onecell, }; static void __init pmac_pic_probe_oldstyle(void) @@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void) /* * Allocate an irq host */ - pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs, - &pmac_pic_host_ops, - max_irqs); + pmac_pic_host = irq_domain_add_linear(master, max_irqs, + &pmac_pic_host_ops, NULL); BUG_ON(pmac_pic_host == NULL); irq_set_default_host(pmac_pic_host); @@ -469,7 +457,6 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); - flags |= MPIC_WANTS_RESET; if (of_get_property(np, "big-endian", NULL)) flags |= MPIC_BIG_ENDIAN; diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 44d769258ebf..a81e5a88fbdf 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start; static int psurge_type = PSURGE_NONE; /* irq for secondary cpus to report */ -static struct irq_host *psurge_host; +static struct irq_domain *psurge_host; int psurge_secondary_virq; /* @@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data) psurge_set_ipi(cpu); } -static int psurge_host_map(struct irq_host *h, unsigned int virq, +static int psurge_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq); @@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq, return 0; } -struct irq_host_ops psurge_host_ops = { +static const struct irq_domain_ops psurge_host_ops = { .map = psurge_host_map, }; @@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void) { int rc = -ENOMEM; - psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &psurge_host_ops, 0); + psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL); if (psurge_host) psurge_secondary_virq = irq_create_direct_mapping(psurge_host); diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index f92b9ef7340e..214478d781ae 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -31,6 +31,7 @@ #include <asm/iommu.h> #include <asm/tce.h> #include <asm/abs_addr.h> +#include <asm/firmware.h> #include "powernv.h" #include "pci.h" diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 467bd4ac6824..db1ad1c8f68f 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -31,7 +31,6 @@ #include <asm/xics.h> #include <asm/rtas.h> #include <asm/opal.h> -#include <asm/xics.h> #include "powernv.h" diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 617efa12a3a5..2a4ff86cc21f 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, static void dump_bmp(struct ps3_private* pd) {}; #endif /* defined(DEBUG) */ -static int ps3_host_map(struct irq_host *h, unsigned int virq, +static int ps3_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, @@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int ps3_host_match(struct irq_host *h, struct device_node *np) +static int ps3_host_match(struct irq_domain *h, struct device_node *np) { /* Match all */ return 1; } -static struct irq_host_ops ps3_host_ops = { +static const struct irq_domain_ops ps3_host_ops = { .map = ps3_host_map, .match = ps3_host_match, }; @@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void) { int result; unsigned cpu; - struct irq_host *host; + struct irq_domain *host; - host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, - PS3_INVALID_OUTLET); + host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL); irq_set_default_host(host); irq_set_virq_count(PS3_PLUG_MAX + 1); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 31f22c1f657d..aadbe4f6d537 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -3,6 +3,7 @@ config PPC_PSERIES bool "IBM pSeries & new (POWER5-based) iSeries" select HAVE_PCSPKR_PLATFORM select MPIC + select OF_DYNAMIC select PCI_MSI select PPC_XICS select PPC_ICP_NATIVE @@ -72,7 +73,7 @@ config IO_EVENT_IRQ config LPARCFG bool "LPAR Configuration Data" - depends on PPC_PSERIES || PPC_ISERIES + depends on PPC_PSERIES help Provide system capacity information via human readable <key word>=<value> pairs through a /proc/ppc64/lparcfg interface. diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 236db46b4078..c222189f5bb2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -6,7 +6,8 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ firmware.o power.o dlpar.o mobility.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o +obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \ + eeh_event.o eeh_sysfs.o eeh_pseries.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_PSERIES_MSI) += msi.o @@ -18,7 +19,6 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o -obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index c0b40af4ce4f..8011088392d3 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1,8 +1,8 @@ /* - * eeh.c * Copyright IBM Corporation 2001, 2005, 2006 * Copyright Dave Engebretsen & Todd Inglett 2001 * Copyright Linas Vepstas 2005, 2006 + * Copyright 2001-2012 IBM 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 @@ -22,7 +22,7 @@ */ #include <linux/delay.h> -#include <linux/sched.h> /* for init_mm */ +#include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> #include <linux/pci.h> @@ -86,16 +86,8 @@ /* Time to wait for a PCI slot to report status, in milliseconds */ #define PCI_BUS_RESET_WAIT_MSEC (60*1000) -/* RTAS tokens */ -static int ibm_set_eeh_option; -static int ibm_set_slot_reset; -static int ibm_read_slot_reset_state; -static int ibm_read_slot_reset_state2; -static int ibm_slot_error_detail; -static int ibm_get_config_addr_info; -static int ibm_get_config_addr_info2; -static int ibm_configure_bridge; -static int ibm_configure_pe; +/* Platform dependent EEH operations */ +struct eeh_ops *eeh_ops = NULL; int eeh_subsystem_enabled; EXPORT_SYMBOL(eeh_subsystem_enabled); @@ -103,14 +95,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled); /* Lock to avoid races due to multiple reports of an error */ static DEFINE_RAW_SPINLOCK(confirm_error_lock); -/* Buffer for reporting slot-error-detail rtas calls. Its here - * in BSS, and not dynamically alloced, so that it ends up in - * RMO where RTAS can access it. - */ -static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; -static DEFINE_SPINLOCK(slot_errbuf_lock); -static int eeh_error_buf_size; - /* Buffer for reporting pci register dumps. Its here in BSS, and * not dynamically alloced, so that it ends up in RMO where RTAS * can access it. @@ -118,74 +102,50 @@ static int eeh_error_buf_size; #define EEH_PCI_REGS_LOG_LEN 4096 static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; -/* System monitoring statistics */ -static unsigned long no_device; -static unsigned long no_dn; -static unsigned long no_cfg_addr; -static unsigned long ignored_check; -static unsigned long total_mmio_ffs; -static unsigned long false_positives; -static unsigned long slot_resets; - -#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) - -/* --------------------------------------------------------------- */ -/* Below lies the EEH event infrastructure */ +/* + * The struct is used to maintain the EEH global statistic + * information. Besides, the EEH global statistics will be + * exported to user space through procfs + */ +struct eeh_stats { + u64 no_device; /* PCI device not found */ + u64 no_dn; /* OF node not found */ + u64 no_cfg_addr; /* Config address not found */ + u64 ignored_check; /* EEH check skipped */ + u64 total_mmio_ffs; /* Total EEH checks */ + u64 false_positives; /* Unnecessary EEH checks */ + u64 slot_resets; /* PE reset */ +}; -static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, - char *driver_log, size_t loglen) -{ - int config_addr; - unsigned long flags; - int rc; +static struct eeh_stats eeh_stats; - /* Log the error with the rtas logger */ - spin_lock_irqsave(&slot_errbuf_lock, flags); - memset(slot_errbuf, 0, eeh_error_buf_size); - - /* Use PE configuration address, if present */ - config_addr = pdn->eeh_config_addr; - if (pdn->eeh_pe_config_addr) - config_addr = pdn->eeh_pe_config_addr; - - rc = rtas_call(ibm_slot_error_detail, - 8, 1, NULL, config_addr, - BUID_HI(pdn->phb->buid), - BUID_LO(pdn->phb->buid), - virt_to_phys(driver_log), loglen, - virt_to_phys(slot_errbuf), - eeh_error_buf_size, - severity); - - if (rc == 0) - log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); - spin_unlock_irqrestore(&slot_errbuf_lock, flags); -} +#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) /** - * gather_pci_data - copy assorted PCI config space registers to buff - * @pdn: device to report data for + * eeh_gather_pci_data - Copy assorted PCI config space registers to buff + * @edev: device to report data for * @buf: point to buffer in which to log * @len: amount of room in buffer * * This routine captures assorted PCI configuration space data, * and puts them into a buffer for RTAS error logging. */ -static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) +static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) { - struct pci_dev *dev = pdn->pcidev; + struct device_node *dn = eeh_dev_to_of_node(edev); + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); u32 cfg; int cap, i; int n = 0; - n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name); - printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name); + n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); + printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); - rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg); + eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg); n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); - rtas_read_config(pdn, PCI_COMMAND, 4, &cfg); + eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg); n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); @@ -196,11 +156,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) /* Gather bridge-specific registers */ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); + eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg); n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); - rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); + eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg); n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); } @@ -208,11 +168,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) /* Dump out the PCI-X command and status regs */ cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (cap) { - rtas_read_config(pdn, cap, 4, &cfg); + eeh_ops->read_config(dn, cap, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); - rtas_read_config(pdn, cap+4, 4, &cfg); + eeh_ops->read_config(dn, cap+4, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); } @@ -225,7 +185,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) "EEH: PCI-E capabilities and status follow:\n"); for (i=0; i<=8; i++) { - rtas_read_config(pdn, cap+4*i, 4, &cfg); + eeh_ops->read_config(dn, cap+4*i, 4, &cfg); n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); } @@ -237,7 +197,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) "EEH: PCI-E AER capability register set follows:\n"); for (i=0; i<14; i++) { - rtas_read_config(pdn, cap+4*i, 4, &cfg); + eeh_ops->read_config(dn, cap+4*i, 4, &cfg); n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); } @@ -246,111 +206,46 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) /* Gather status on devices under the bridge */ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - struct device_node *dn; + struct device_node *child; - for_each_child_of_node(pdn->node, dn) { - pdn = PCI_DN(dn); - if (pdn) - n += gather_pci_data(pdn, buf+n, len-n); + for_each_child_of_node(dn, child) { + if (of_node_to_eeh_dev(child)) + n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n); } } return n; } -void eeh_slot_error_detail(struct pci_dn *pdn, int severity) -{ - size_t loglen = 0; - pci_regs_buf[0] = 0; - - rtas_pci_enable(pdn, EEH_THAW_MMIO); - rtas_configure_bridge(pdn); - eeh_restore_bars(pdn); - loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); - - rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); -} - /** - * read_slot_reset_state - Read the reset state of a device node's slot - * @dn: device node to read - * @rets: array to return results in - */ -static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) -{ - int token, outputs; - int config_addr; - - if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { - token = ibm_read_slot_reset_state2; - outputs = 4; - } else { - token = ibm_read_slot_reset_state; - rets[2] = 0; /* fake PE Unavailable info */ - outputs = 3; - } - - /* Use PE configuration address, if present */ - config_addr = pdn->eeh_config_addr; - if (pdn->eeh_pe_config_addr) - config_addr = pdn->eeh_pe_config_addr; - - return rtas_call(token, 3, outputs, rets, config_addr, - BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); -} - -/** - * eeh_wait_for_slot_status - returns error status of slot - * @pdn pci device node - * @max_wait_msecs maximum number to millisecs to wait - * - * Return negative value if a permanent error, else return - * Partition Endpoint (PE) status value. + * eeh_slot_error_detail - Generate combined log including driver log and error log + * @edev: device to report error log for + * @severity: temporary or permanent error log * - * If @max_wait_msecs is positive, then this routine will - * sleep until a valid status can be obtained, or until - * the max allowed wait time is exceeded, in which case - * a -2 is returned. + * This routine should be called to generate the combined log, which + * is comprised of driver log and error log. The driver log is figured + * out from the config space of the corresponding PCI device, while + * the error log is fetched through platform dependent function call. */ -int -eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) +void eeh_slot_error_detail(struct eeh_dev *edev, int severity) { - int rc; - int rets[3]; - int mwait; - - while (1) { - rc = read_slot_reset_state(pdn, rets); - if (rc) return rc; - if (rets[1] == 0) return -1; /* EEH is not supported */ - - if (rets[0] != 5) return rets[0]; /* return actual status */ - - if (rets[2] == 0) return -1; /* permanently unavailable */ + size_t loglen = 0; + pci_regs_buf[0] = 0; - if (max_wait_msecs <= 0) break; + eeh_pci_enable(edev, EEH_OPT_THAW_MMIO); + eeh_ops->configure_bridge(eeh_dev_to_of_node(edev)); + eeh_restore_bars(edev); + loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); - mwait = rets[2]; - if (mwait <= 0) { - printk (KERN_WARNING - "EEH: Firmware returned bad wait value=%d\n", mwait); - mwait = 1000; - } else if (mwait > 300*1000) { - printk (KERN_WARNING - "EEH: Firmware is taking too long, time=%d\n", mwait); - mwait = 300*1000; - } - max_wait_msecs -= mwait; - msleep (mwait); - } - - printk(KERN_WARNING "EEH: Timed out waiting for slot status\n"); - return -2; + eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen); } /** - * eeh_token_to_phys - convert EEH address token to phys address - * @token i/o token, should be address in the form 0xA.... + * eeh_token_to_phys - Convert EEH address token to phys address + * @token: I/O token, should be address in the form 0xA.... + * + * This routine should be called to convert virtual I/O address + * to physical one. */ static inline unsigned long eeh_token_to_phys(unsigned long token) { @@ -365,36 +260,43 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) return pa | (token & (PAGE_SIZE-1)); } -/** - * Return the "partitionable endpoint" (pe) under which this device lies +/** + * eeh_find_device_pe - Retrieve the PE for the given device + * @dn: device node + * + * Return the PE under which this device lies */ -struct device_node * find_device_pe(struct device_node *dn) +struct device_node *eeh_find_device_pe(struct device_node *dn) { - while ((dn->parent) && PCI_DN(dn->parent) && - (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { + while (dn->parent && of_node_to_eeh_dev(dn->parent) && + (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { dn = dn->parent; } return dn; } -/** Mark all devices that are children of this device as failed. - * Mark the device driver too, so that it can see the failure - * immediately; this is critical, since some drivers poll - * status registers in interrupts ... If a driver is polling, - * and the slot is frozen, then the driver can deadlock in - * an interrupt context, which is bad. +/** + * __eeh_mark_slot - Mark all child devices as failed + * @parent: parent device + * @mode_flag: failure flag + * + * Mark all devices that are children of this device as failed. + * Mark the device driver too, so that it can see the failure + * immediately; this is critical, since some drivers poll + * status registers in interrupts ... If a driver is polling, + * and the slot is frozen, then the driver can deadlock in + * an interrupt context, which is bad. */ - static void __eeh_mark_slot(struct device_node *parent, int mode_flag) { struct device_node *dn; for_each_child_of_node(parent, dn) { - if (PCI_DN(dn)) { + if (of_node_to_eeh_dev(dn)) { /* Mark the pci device driver too */ - struct pci_dev *dev = PCI_DN(dn)->pcidev; + struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; - PCI_DN(dn)->eeh_mode |= mode_flag; + of_node_to_eeh_dev(dn)->mode |= mode_flag; if (dev && dev->driver) dev->error_state = pci_channel_io_frozen; @@ -404,92 +306,81 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag) } } -void eeh_mark_slot (struct device_node *dn, int mode_flag) +/** + * eeh_mark_slot - Mark the indicated device and its children as failed + * @dn: parent device + * @mode_flag: failure flag + * + * Mark the indicated device and its child devices as failed. + * The device drivers are marked as failed as well. + */ +void eeh_mark_slot(struct device_node *dn, int mode_flag) { struct pci_dev *dev; - dn = find_device_pe (dn); + dn = eeh_find_device_pe(dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent; - PCI_DN(dn)->eeh_mode |= mode_flag; + of_node_to_eeh_dev(dn)->mode |= mode_flag; /* Mark the pci device too */ - dev = PCI_DN(dn)->pcidev; + dev = of_node_to_eeh_dev(dn)->pdev; if (dev) dev->error_state = pci_channel_io_frozen; __eeh_mark_slot(dn, mode_flag); } +/** + * __eeh_clear_slot - Clear failure flag for the child devices + * @parent: parent device + * @mode_flag: flag to be cleared + * + * Clear failure flag for the child devices. + */ static void __eeh_clear_slot(struct device_node *parent, int mode_flag) { struct device_node *dn; for_each_child_of_node(parent, dn) { - if (PCI_DN(dn)) { - PCI_DN(dn)->eeh_mode &= ~mode_flag; - PCI_DN(dn)->eeh_check_count = 0; + if (of_node_to_eeh_dev(dn)) { + of_node_to_eeh_dev(dn)->mode &= ~mode_flag; + of_node_to_eeh_dev(dn)->check_count = 0; __eeh_clear_slot(dn, mode_flag); } } } -void eeh_clear_slot (struct device_node *dn, int mode_flag) +/** + * eeh_clear_slot - Clear failure flag for the indicated device and its children + * @dn: parent device + * @mode_flag: flag to be cleared + * + * Clear failure flag for the indicated device and its children. + */ +void eeh_clear_slot(struct device_node *dn, int mode_flag) { unsigned long flags; raw_spin_lock_irqsave(&confirm_error_lock, flags); - dn = find_device_pe (dn); + dn = eeh_find_device_pe(dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent; - PCI_DN(dn)->eeh_mode &= ~mode_flag; - PCI_DN(dn)->eeh_check_count = 0; + of_node_to_eeh_dev(dn)->mode &= ~mode_flag; + of_node_to_eeh_dev(dn)->check_count = 0; __eeh_clear_slot(dn, mode_flag); raw_spin_unlock_irqrestore(&confirm_error_lock, flags); } -void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) -{ - struct device_node *dn; - - for_each_child_of_node(parent, dn) { - if (PCI_DN(dn)) { - - struct pci_dev *dev = PCI_DN(dn)->pcidev; - - if (dev && dev->driver) - *freset |= dev->needs_freset; - - __eeh_set_pe_freset(dn, freset); - } - } -} - -void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) -{ - struct pci_dev *dev; - dn = find_device_pe(dn); - - /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) - dn = dn->parent; - - dev = PCI_DN(dn)->pcidev; - if (dev) - *freset |= dev->needs_freset; - - __eeh_set_pe_freset(dn, freset); -} - /** - * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze - * @dn device node - * @dev pci device, if known + * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze + * @dn: device node + * @dev: pci device, if known * * Check for an EEH failure for the given device node. Call this * routine if the result of a read was all 0xff's and you want to @@ -504,35 +395,34 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) { int ret; - int rets[3]; unsigned long flags; - struct pci_dn *pdn; + struct eeh_dev *edev; int rc = 0; const char *location; - total_mmio_ffs++; + eeh_stats.total_mmio_ffs++; if (!eeh_subsystem_enabled) return 0; if (!dn) { - no_dn++; + eeh_stats.no_dn++; return 0; } - dn = find_device_pe(dn); - pdn = PCI_DN(dn); + dn = eeh_find_device_pe(dn); + edev = of_node_to_eeh_dev(dn); /* Access to IO BARs might get this far and still not want checking. */ - if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || - pdn->eeh_mode & EEH_MODE_NOCHECK) { - ignored_check++; + if (!(edev->mode & EEH_MODE_SUPPORTED) || + edev->mode & EEH_MODE_NOCHECK) { + eeh_stats.ignored_check++; pr_debug("EEH: Ignored check (%x) for %s %s\n", - pdn->eeh_mode, eeh_pci_name(dev), dn->full_name); + edev->mode, eeh_pci_name(dev), dn->full_name); return 0; } - if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) { - no_cfg_addr++; + if (!edev->config_addr && !edev->pe_config_addr) { + eeh_stats.no_cfg_addr++; return 0; } @@ -544,15 +434,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) */ raw_spin_lock_irqsave(&confirm_error_lock, flags); rc = 1; - if (pdn->eeh_mode & EEH_MODE_ISOLATED) { - pdn->eeh_check_count ++; - if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) { + if (edev->mode & EEH_MODE_ISOLATED) { + edev->check_count++; + if (edev->check_count % EEH_MAX_FAILS == 0) { location = of_get_property(dn, "ibm,loc-code", NULL); - printk (KERN_ERR "EEH: %d reads ignored for recovering device at " + printk(KERN_ERR "EEH: %d reads ignored for recovering device at " "location=%s driver=%s pci addr=%s\n", - pdn->eeh_check_count, location, + edev->check_count, location, eeh_driver_name(dev), eeh_pci_name(dev)); - printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n", + printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", eeh_driver_name(dev)); dump_stack(); } @@ -566,58 +456,39 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) * function zero of a multi-function device. * In any case they must share a common PHB. */ - ret = read_slot_reset_state(pdn, rets); - - /* If the call to firmware failed, punt */ - if (ret != 0) { - printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", - ret, dn->full_name); - false_positives++; - pdn->eeh_false_positives ++; - rc = 0; - goto dn_unlock; - } + ret = eeh_ops->get_state(dn, NULL); /* Note that config-io to empty slots may fail; - * they are empty when they don't have children. */ - if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) { - false_positives++; - pdn->eeh_false_positives ++; - rc = 0; - goto dn_unlock; - } - - /* If EEH is not supported on this device, punt. */ - if (rets[1] != 1) { - printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", - ret, dn->full_name); - false_positives++; - pdn->eeh_false_positives ++; - rc = 0; - goto dn_unlock; - } - - /* If not the kind of error we know about, punt. */ - if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { - false_positives++; - pdn->eeh_false_positives ++; + * they are empty when they don't have children. + * We will punt with the following conditions: Failure to get + * PE's state, EEH not support and Permanently unavailable + * state, PE is in good state. + */ + if ((ret < 0) || + (ret == EEH_STATE_NOT_SUPPORT) || + (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == + (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { + eeh_stats.false_positives++; + edev->false_positives ++; rc = 0; goto dn_unlock; } - slot_resets++; + eeh_stats.slot_resets++; /* Avoid repeated reports of this failure, including problems * with other functions on this device, and functions under - * bridges. */ - eeh_mark_slot (dn, EEH_MODE_ISOLATED); + * bridges. + */ + eeh_mark_slot(dn, EEH_MODE_ISOLATED); raw_spin_unlock_irqrestore(&confirm_error_lock, flags); - eeh_send_failure_event (dn, dev); + eeh_send_failure_event(edev); /* Most EEH events are due to device driver bugs. Having * a stack trace will help the device-driver authors figure - * out what happened. So print that out. */ + * out what happened. So print that out. + */ dump_stack(); return 1; @@ -629,9 +500,9 @@ dn_unlock: EXPORT_SYMBOL_GPL(eeh_dn_check_failure); /** - * eeh_check_failure - check if all 1's data is due to EEH slot freeze - * @token i/o token, should be address in the form 0xA.... - * @val value, should be all 1's (XXX why do we need this arg??) + * eeh_check_failure - Check if all 1's data is due to EEH slot freeze + * @token: I/O token, should be address in the form 0xA.... + * @val: value, should be all 1's (XXX why do we need this arg??) * * Check for an EEH failure at the given token address. Call this * routine if the result of a read was all 0xff's and you want to @@ -648,14 +519,14 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon /* Finding the phys addr + pci device; this is pretty quick. */ addr = eeh_token_to_phys((unsigned long __force) token); - dev = pci_get_device_by_addr(addr); + dev = pci_addr_cache_get_device(addr); if (!dev) { - no_device++; + eeh_stats.no_device++; return val; } dn = pci_device_to_OF_node(dev); - eeh_dn_check_failure (dn, dev); + eeh_dn_check_failure(dn, dev); pci_dev_put(dev); return val; @@ -663,115 +534,54 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon EXPORT_SYMBOL(eeh_check_failure); -/* ------------------------------------------------------------- */ -/* The code below deals with error recovery */ /** - * rtas_pci_enable - enable MMIO or DMA transfers for this slot - * @pdn pci device node + * eeh_pci_enable - Enable MMIO or DMA transfers for this slot + * @edev: pci device node + * + * This routine should be called to reenable frozen MMIO or DMA + * so that it would work correctly again. It's useful while doing + * recovery or log collection on the indicated device. */ - -int -rtas_pci_enable(struct pci_dn *pdn, int function) +int eeh_pci_enable(struct eeh_dev *edev, int function) { - int config_addr; int rc; + struct device_node *dn = eeh_dev_to_of_node(edev); - /* Use PE configuration address, if present */ - config_addr = pdn->eeh_config_addr; - if (pdn->eeh_pe_config_addr) - config_addr = pdn->eeh_pe_config_addr; - - rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, - config_addr, - BUID_HI(pdn->phb->buid), - BUID_LO(pdn->phb->buid), - function); - + rc = eeh_ops->set_option(dn, function); if (rc) printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", - function, rc, pdn->node->full_name); + function, rc, dn->full_name); - rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); - if ((rc == 4) && (function == EEH_THAW_MMIO)) + rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); + if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && + (function == EEH_OPT_THAW_MMIO)) return 0; return rc; } /** - * rtas_pci_slot_reset - raises/lowers the pci #RST line - * @pdn pci device node - * @state: 1/0 to raise/lower the #RST - * - * Clear the EEH-frozen condition on a slot. This routine - * asserts the PCI #RST line if the 'state' argument is '1', - * and drops the #RST line if 'state is '0'. This routine is - * safe to call in an interrupt context. - * - */ - -static void -rtas_pci_slot_reset(struct pci_dn *pdn, int state) -{ - int config_addr; - int rc; - - BUG_ON (pdn==NULL); - - if (!pdn->phb) { - printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", - pdn->node->full_name); - return; - } - - /* Use PE configuration address, if present */ - config_addr = pdn->eeh_config_addr; - if (pdn->eeh_pe_config_addr) - config_addr = pdn->eeh_pe_config_addr; - - rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, - config_addr, - BUID_HI(pdn->phb->buid), - BUID_LO(pdn->phb->buid), - state); - - /* Fundamental-reset not supported on this PE, try hot-reset */ - if (rc == -8 && state == 3) { - rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, - config_addr, - BUID_HI(pdn->phb->buid), - BUID_LO(pdn->phb->buid), 1); - if (rc) - printk(KERN_WARNING - "EEH: Unable to reset the failed slot," - " #RST=%d dn=%s\n", - rc, pdn->node->full_name); - } -} - -/** * pcibios_set_pcie_slot_reset - Set PCI-E reset state - * @dev: pci device struct - * @state: reset state to enter + * @dev: pci device struct + * @state: reset state to enter * * Return value: * 0 if success - **/ + */ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) { struct device_node *dn = pci_device_to_OF_node(dev); - struct pci_dn *pdn = PCI_DN(dn); switch (state) { case pcie_deassert_reset: - rtas_pci_slot_reset(pdn, 0); + eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); break; case pcie_hot_reset: - rtas_pci_slot_reset(pdn, 1); + eeh_ops->reset(dn, EEH_RESET_HOT); break; case pcie_warm_reset: - rtas_pci_slot_reset(pdn, 3); + eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); break; default: return -EINVAL; @@ -781,13 +591,66 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat } /** - * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second - * @pdn: pci device node to be reset. + * __eeh_set_pe_freset - Check the required reset for child devices + * @parent: parent device + * @freset: return value + * + * Each device might have its preferred reset type: fundamental or + * hot reset. The routine is used to collect the information from + * the child devices so that they could be reset accordingly. + */ +void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) +{ + struct device_node *dn; + + for_each_child_of_node(parent, dn) { + if (of_node_to_eeh_dev(dn)) { + struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; + + if (dev && dev->driver) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); + } + } +} + +/** + * eeh_set_pe_freset - Check the required reset for the indicated device and its children + * @dn: parent device + * @freset: return value + * + * Each device might have its preferred reset type: fundamental or + * hot reset. The routine is used to collected the information for + * the indicated device and its children so that the bunch of the + * devices could be reset properly. */ +void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) +{ + struct pci_dev *dev; + dn = eeh_find_device_pe(dn); + + /* Back up one, since config addrs might be shared */ + if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) + dn = dn->parent; + + dev = of_node_to_eeh_dev(dn)->pdev; + if (dev) + *freset |= dev->needs_freset; -static void __rtas_set_slot_reset(struct pci_dn *pdn) + __eeh_set_pe_freset(dn, freset); +} + +/** + * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second + * @edev: pci device node to be reset. + * + * Assert the PCI #RST line for 1/4 second. + */ +static void eeh_reset_pe_once(struct eeh_dev *edev) { unsigned int freset = 0; + struct device_node *dn = eeh_dev_to_of_node(edev); /* Determine type of EEH reset required for * Partitionable Endpoint, a hot-reset (1) @@ -795,58 +658,68 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn) * A fundamental reset required by any device under * Partitionable Endpoint trumps hot-reset. */ - eeh_set_pe_freset(pdn->node, &freset); + eeh_set_pe_freset(dn, &freset); if (freset) - rtas_pci_slot_reset(pdn, 3); + eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); else - rtas_pci_slot_reset(pdn, 1); + eeh_ops->reset(dn, EEH_RESET_HOT); /* The PCI bus requires that the reset be held high for at least - * a 100 milliseconds. We wait a bit longer 'just in case'. */ - + * a 100 milliseconds. We wait a bit longer 'just in case'. + */ #define PCI_BUS_RST_HOLD_TIME_MSEC 250 - msleep (PCI_BUS_RST_HOLD_TIME_MSEC); + msleep(PCI_BUS_RST_HOLD_TIME_MSEC); /* We might get hit with another EEH freeze as soon as the * pci slot reset line is dropped. Make sure we don't miss - * these, and clear the flag now. */ - eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); + * these, and clear the flag now. + */ + eeh_clear_slot(dn, EEH_MODE_ISOLATED); - rtas_pci_slot_reset (pdn, 0); + eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); /* After a PCI slot has been reset, the PCI Express spec requires * a 1.5 second idle time for the bus to stabilize, before starting - * up traffic. */ + * up traffic. + */ #define PCI_BUS_SETTLE_TIME_MSEC 1800 - msleep (PCI_BUS_SETTLE_TIME_MSEC); + msleep(PCI_BUS_SETTLE_TIME_MSEC); } -int rtas_set_slot_reset(struct pci_dn *pdn) +/** + * eeh_reset_pe - Reset the indicated PE + * @edev: PCI device associated EEH device + * + * This routine should be called to reset indicated device, including + * PE. A PE might include multiple PCI devices and sometimes PCI bridges + * might be involved as well. + */ +int eeh_reset_pe(struct eeh_dev *edev) { int i, rc; + struct device_node *dn = eeh_dev_to_of_node(edev); /* Take three shots at resetting the bus */ for (i=0; i<3; i++) { - __rtas_set_slot_reset(pdn); + eeh_reset_pe_once(edev); - rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); - if (rc == 0) + rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); + if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) return 0; if (rc < 0) { printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", - pdn->node->full_name); + dn->full_name); return -1; } printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", - i+1, pdn->node->full_name, rc); + i+1, dn->full_name, rc); } return -1; } -/* ------------------------------------------------------- */ /** Save and restore of PCI BARs * * Although firmware will set up BARs during boot, it doesn't @@ -856,181 +729,122 @@ int rtas_set_slot_reset(struct pci_dn *pdn) */ /** - * __restore_bars - Restore the Base Address Registers - * @pdn: pci device node + * eeh_restore_one_device_bars - Restore the Base Address Registers for one device + * @edev: PCI device associated EEH device * * Loads the PCI configuration space base address registers, * the expansion ROM base address, the latency timer, and etc. * from the saved values in the device node. */ -static inline void __restore_bars (struct pci_dn *pdn) +static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) { int i; u32 cmd; + struct device_node *dn = eeh_dev_to_of_node(edev); + + if (!edev->phb) + return; - if (NULL==pdn->phb) return; for (i=4; i<10; i++) { - rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); + eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); } /* 12 == Expansion ROM Address */ - rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); + eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) -#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) +#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) - rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, + eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, SAVED_BYTE(PCI_CACHE_LINE_SIZE)); - rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, + eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, SAVED_BYTE(PCI_LATENCY_TIMER)); /* max latency, min grant, interrupt pin and line */ - rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); + eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); /* Restore PERR & SERR bits, some devices require it, - don't touch the other command bits */ - rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); - if (pdn->config_space[1] & PCI_COMMAND_PARITY) + * don't touch the other command bits + */ + eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); + if (edev->config_space[1] & PCI_COMMAND_PARITY) cmd |= PCI_COMMAND_PARITY; else cmd &= ~PCI_COMMAND_PARITY; - if (pdn->config_space[1] & PCI_COMMAND_SERR) + if (edev->config_space[1] & PCI_COMMAND_SERR) cmd |= PCI_COMMAND_SERR; else cmd &= ~PCI_COMMAND_SERR; - rtas_write_config(pdn, PCI_COMMAND, 4, cmd); + eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); } /** - * eeh_restore_bars - restore the PCI config space info + * eeh_restore_bars - Restore the PCI config space info + * @edev: EEH device * * This routine performs a recursive walk to the children * of this device as well. */ -void eeh_restore_bars(struct pci_dn *pdn) +void eeh_restore_bars(struct eeh_dev *edev) { struct device_node *dn; - if (!pdn) + if (!edev) return; - if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) - __restore_bars (pdn); + if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) + eeh_restore_one_device_bars(edev); - for_each_child_of_node(pdn->node, dn) - eeh_restore_bars (PCI_DN(dn)); + for_each_child_of_node(eeh_dev_to_of_node(edev), dn) + eeh_restore_bars(of_node_to_eeh_dev(dn)); } /** - * eeh_save_bars - save device bars + * eeh_save_bars - Save device bars + * @edev: PCI device associated EEH device * * Save the values of the device bars. Unlike the restore * routine, this routine is *not* recursive. This is because * PCI devices are added individually; but, for the restore, * an entire slot is reset at a time. */ -static void eeh_save_bars(struct pci_dn *pdn) +static void eeh_save_bars(struct eeh_dev *edev) { int i; + struct device_node *dn; - if (!pdn ) + if (!edev) return; + dn = eeh_dev_to_of_node(edev); for (i = 0; i < 16; i++) - rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]); -} - -void -rtas_configure_bridge(struct pci_dn *pdn) -{ - int config_addr; - int rc; - int token; - - /* Use PE configuration address, if present */ - config_addr = pdn->eeh_config_addr; - if (pdn->eeh_pe_config_addr) - config_addr = pdn->eeh_pe_config_addr; - - /* Use new configure-pe function, if supported */ - if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) - token = ibm_configure_pe; - else - token = ibm_configure_bridge; - - rc = rtas_call(token, 3, 1, NULL, - config_addr, - BUID_HI(pdn->phb->buid), - BUID_LO(pdn->phb->buid)); - if (rc) { - printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", - rc, pdn->node->full_name); - } + eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]); } -/* ------------------------------------------------------------- */ -/* The code below deals with enabling EEH for devices during the - * early boot sequence. EEH must be enabled before any PCI probing - * can be done. +/** + * eeh_early_enable - Early enable EEH on the indicated device + * @dn: device node + * @data: BUID + * + * Enable EEH functionality on the specified PCI device. The function + * is expected to be called before real PCI probing is done. However, + * the PHBs have been initialized at this point. */ - -#define EEH_ENABLE 1 - -struct eeh_early_enable_info { - unsigned int buid_hi; - unsigned int buid_lo; -}; - -static int get_pe_addr (int config_addr, - struct eeh_early_enable_info *info) +static void *eeh_early_enable(struct device_node *dn, void *data) { - unsigned int rets[3]; - int ret; - - /* Use latest config-addr token on power6 */ - if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { - /* Make sure we have a PE in hand */ - ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, - config_addr, info->buid_hi, info->buid_lo, 1); - if (ret || (rets[0]==0)) - return 0; - - ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, - config_addr, info->buid_hi, info->buid_lo, 0); - if (ret) - return 0; - return rets[0]; - } - - /* Use older config-addr token on power5 */ - if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, - config_addr, info->buid_hi, info->buid_lo, 0); - if (ret) - return 0; - return rets[0]; - } - return 0; -} - -/* Enable eeh for the given device node. */ -static void *early_enable_eeh(struct device_node *dn, void *data) -{ - unsigned int rets[3]; - struct eeh_early_enable_info *info = data; int ret; const u32 *class_code = of_get_property(dn, "class-code", NULL); const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); const u32 *device_id = of_get_property(dn, "device-id", NULL); const u32 *regs; int enable; - struct pci_dn *pdn = PCI_DN(dn); + struct eeh_dev *edev = of_node_to_eeh_dev(dn); - pdn->class_code = 0; - pdn->eeh_mode = 0; - pdn->eeh_check_count = 0; - pdn->eeh_freeze_count = 0; - pdn->eeh_false_positives = 0; + edev->class_code = 0; + edev->mode = 0; + edev->check_count = 0; + edev->freeze_count = 0; + edev->false_positives = 0; if (!of_device_is_available(dn)) return NULL; @@ -1041,54 +855,56 @@ static void *early_enable_eeh(struct device_node *dn, void *data) /* There is nothing to check on PCI to ISA bridges */ if (dn->type && !strcmp(dn->type, "isa")) { - pdn->eeh_mode |= EEH_MODE_NOCHECK; + edev->mode |= EEH_MODE_NOCHECK; return NULL; } - pdn->class_code = *class_code; + edev->class_code = *class_code; /* Ok... see if this device supports EEH. Some do, some don't, - * and the only way to find out is to check each and every one. */ + * and the only way to find out is to check each and every one. + */ regs = of_get_property(dn, "reg", NULL); if (regs) { /* First register entry is addr (00BBSS00) */ /* Try to enable eeh */ - ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, - regs[0], info->buid_hi, info->buid_lo, - EEH_ENABLE); + ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE); enable = 0; if (ret == 0) { - pdn->eeh_config_addr = regs[0]; + edev->config_addr = regs[0]; /* If the newer, better, ibm,get-config-addr-info is supported, - * then use that instead. */ - pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); + * then use that instead. + */ + edev->pe_config_addr = eeh_ops->get_pe_addr(dn); /* Some older systems (Power4) allow the * ibm,set-eeh-option call to succeed even on nodes * where EEH is not supported. Verify support - * explicitly. */ - ret = read_slot_reset_state(pdn, rets); - if ((ret == 0) && (rets[1] == 1)) + * explicitly. + */ + ret = eeh_ops->get_state(dn, NULL); + if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) enable = 1; } if (enable) { eeh_subsystem_enabled = 1; - pdn->eeh_mode |= EEH_MODE_SUPPORTED; + edev->mode |= EEH_MODE_SUPPORTED; pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", - dn->full_name, pdn->eeh_config_addr, - pdn->eeh_pe_config_addr); + dn->full_name, edev->config_addr, + edev->pe_config_addr); } else { /* This device doesn't support EEH, but it may have an - * EEH parent, in which case we mark it as supported. */ - if (dn->parent && PCI_DN(dn->parent) - && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { + * EEH parent, in which case we mark it as supported. + */ + if (dn->parent && of_node_to_eeh_dev(dn->parent) && + (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { /* Parent supports EEH. */ - pdn->eeh_mode |= EEH_MODE_SUPPORTED; - pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; + edev->mode |= EEH_MODE_SUPPORTED; + edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; return NULL; } } @@ -1097,11 +913,63 @@ static void *early_enable_eeh(struct device_node *dn, void *data) dn->full_name); } - eeh_save_bars(pdn); + eeh_save_bars(edev); return NULL; } -/* +/** + * eeh_ops_register - Register platform dependent EEH operations + * @ops: platform dependent EEH operations + * + * Register the platform dependent EEH operation callback + * functions. The platform should call this function before + * any other EEH operations. + */ +int __init eeh_ops_register(struct eeh_ops *ops) +{ + if (!ops->name) { + pr_warning("%s: Invalid EEH ops name for %p\n", + __func__, ops); + return -EINVAL; + } + + if (eeh_ops && eeh_ops != ops) { + pr_warning("%s: EEH ops of platform %s already existing (%s)\n", + __func__, eeh_ops->name, ops->name); + return -EEXIST; + } + + eeh_ops = ops; + + return 0; +} + +/** + * eeh_ops_unregister - Unreigster platform dependent EEH operations + * @name: name of EEH platform operations + * + * Unregister the platform dependent EEH operation callback + * functions. + */ +int __exit eeh_ops_unregister(const char *name) +{ + if (!name || !strlen(name)) { + pr_warning("%s: Invalid EEH ops name\n", + __func__); + return -EINVAL; + } + + if (eeh_ops && !strcmp(eeh_ops->name, name)) { + eeh_ops = NULL; + return 0; + } + + return -EEXIST; +} + +/** + * eeh_init - EEH initialization + * * Initialize EEH by trying to enable it for all of the adapters in the system. * As a side effect we can determine here if eeh is supported at all. * Note that we leave EEH on so failed config cycles won't cause a machine @@ -1117,50 +985,35 @@ static void *early_enable_eeh(struct device_node *dn, void *data) void __init eeh_init(void) { struct device_node *phb, *np; - struct eeh_early_enable_info info; + int ret; + + /* call platform initialization function */ + if (!eeh_ops) { + pr_warning("%s: Platform EEH operation not found\n", + __func__); + return; + } else if ((ret = eeh_ops->init())) { + pr_warning("%s: Failed to call platform init function (%d)\n", + __func__, ret); + return; + } raw_spin_lock_init(&confirm_error_lock); - spin_lock_init(&slot_errbuf_lock); np = of_find_node_by_path("/rtas"); if (np == NULL) return; - ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); - ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); - ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); - ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); - ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); - ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); - ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); - ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); - ibm_configure_pe = rtas_token("ibm,configure-pe"); - - if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) - return; - - eeh_error_buf_size = rtas_token("rtas-error-log-max"); - if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { - eeh_error_buf_size = 1024; - } - if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { - printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated " - "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX); - eeh_error_buf_size = RTAS_ERROR_LOG_MAX; - } - /* Enable EEH for all adapters. Note that eeh requires buid's */ for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) { unsigned long buid; buid = get_phb_buid(phb); - if (buid == 0 || PCI_DN(phb) == NULL) + if (buid == 0 || !of_node_to_eeh_dev(phb)) continue; - info.buid_lo = BUID_LO(buid); - info.buid_hi = BUID_HI(buid); - traverse_pci_devices(phb, early_enable_eeh, &info); + traverse_pci_devices(phb, eeh_early_enable, NULL); } if (eeh_subsystem_enabled) @@ -1170,7 +1023,7 @@ void __init eeh_init(void) } /** - * eeh_add_device_early - enable EEH for the indicated device_node + * eeh_add_device_early - Enable EEH for the indicated device_node * @dn: device node for which to set up EEH * * This routine must be used to perform EEH initialization for PCI @@ -1184,21 +1037,26 @@ void __init eeh_init(void) static void eeh_add_device_early(struct device_node *dn) { struct pci_controller *phb; - struct eeh_early_enable_info info; - if (!dn || !PCI_DN(dn)) + if (!dn || !of_node_to_eeh_dev(dn)) return; - phb = PCI_DN(dn)->phb; + phb = of_node_to_eeh_dev(dn)->phb; /* USB Bus children of PCI devices will not have BUID's */ if (NULL == phb || 0 == phb->buid) return; - info.buid_hi = BUID_HI(phb->buid); - info.buid_lo = BUID_LO(phb->buid); - early_enable_eeh(dn, &info); + eeh_early_enable(dn, NULL); } +/** + * eeh_add_device_tree_early - Enable EEH for the indicated device + * @dn: device node + * + * This routine must be used to perform EEH initialization for the + * indicated PCI device that was added after system boot (e.g. + * hotplug, dlpar). + */ void eeh_add_device_tree_early(struct device_node *dn) { struct device_node *sib; @@ -1210,7 +1068,7 @@ void eeh_add_device_tree_early(struct device_node *dn) EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); /** - * eeh_add_device_late - perform EEH initialization for the indicated pci device + * eeh_add_device_late - Perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH * * This routine must be used to complete EEH initialization for PCI @@ -1219,7 +1077,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); static void eeh_add_device_late(struct pci_dev *dev) { struct device_node *dn; - struct pci_dn *pdn; + struct eeh_dev *edev; if (!dev || !eeh_subsystem_enabled) return; @@ -1227,20 +1085,29 @@ static void eeh_add_device_late(struct pci_dev *dev) pr_debug("EEH: Adding device %s\n", pci_name(dev)); dn = pci_device_to_OF_node(dev); - pdn = PCI_DN(dn); - if (pdn->pcidev == dev) { + edev = pci_dev_to_eeh_dev(dev); + if (edev->pdev == dev) { pr_debug("EEH: Already referenced !\n"); return; } - WARN_ON(pdn->pcidev); + WARN_ON(edev->pdev); - pci_dev_get (dev); - pdn->pcidev = dev; + pci_dev_get(dev); + edev->pdev = dev; + dev->dev.archdata.edev = edev; pci_addr_cache_insert_device(dev); eeh_sysfs_add_device(dev); } +/** + * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus + * @bus: PCI bus + * + * This routine must be used to perform EEH initialization for PCI + * devices which are attached to the indicated PCI bus. The PCI bus + * is added after system boot through hotplug or dlpar. + */ void eeh_add_device_tree_late(struct pci_bus *bus) { struct pci_dev *dev; @@ -1257,7 +1124,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus) EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); /** - * eeh_remove_device - undo EEH setup for the indicated pci device + * eeh_remove_device - Undo EEH setup for the indicated pci device * @dev: pci device to be removed * * This routine should be called when a device is removed from @@ -1268,25 +1135,35 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); */ static void eeh_remove_device(struct pci_dev *dev) { - struct device_node *dn; + struct eeh_dev *edev; + if (!dev || !eeh_subsystem_enabled) return; + edev = pci_dev_to_eeh_dev(dev); /* Unregister the device with the EEH/PCI address search system */ pr_debug("EEH: Removing device %s\n", pci_name(dev)); - dn = pci_device_to_OF_node(dev); - if (PCI_DN(dn)->pcidev == NULL) { + if (!edev || !edev->pdev) { pr_debug("EEH: Not referenced !\n"); return; } - PCI_DN(dn)->pcidev = NULL; - pci_dev_put (dev); + edev->pdev = NULL; + dev->dev.archdata.edev = NULL; + pci_dev_put(dev); pci_addr_cache_remove_device(dev); eeh_sysfs_remove_device(dev); } +/** + * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device + * @dev: PCI device + * + * This routine must be called when a device is removed from the + * running system through hotplug or dlpar. The corresponding + * PCI address cache will be removed. + */ void eeh_remove_bus_device(struct pci_dev *dev) { struct pci_bus *bus = dev->subordinate; @@ -1305,21 +1182,24 @@ static int proc_eeh_show(struct seq_file *m, void *v) { if (0 == eeh_subsystem_enabled) { seq_printf(m, "EEH Subsystem is globally disabled\n"); - seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs); + seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); } else { seq_printf(m, "EEH Subsystem is enabled\n"); seq_printf(m, - "no device=%ld\n" - "no device node=%ld\n" - "no config address=%ld\n" - "check not wanted=%ld\n" - "eeh_total_mmio_ffs=%ld\n" - "eeh_false_positives=%ld\n" - "eeh_slot_resets=%ld\n", - no_device, no_dn, no_cfg_addr, - ignored_check, total_mmio_ffs, - false_positives, - slot_resets); + "no device=%llu\n" + "no device node=%llu\n" + "no config address=%llu\n" + "check not wanted=%llu\n" + "eeh_total_mmio_ffs=%llu\n" + "eeh_false_positives=%llu\n" + "eeh_slot_resets=%llu\n", + eeh_stats.no_device, + eeh_stats.no_dn, + eeh_stats.no_cfg_addr, + eeh_stats.ignored_check, + eeh_stats.total_mmio_ffs, + eeh_stats.false_positives, + eeh_stats.slot_resets); } return 0; diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index fc5ae767989e..e5ae1c687c66 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -1,5 +1,4 @@ /* - * eeh_cache.c * PCI address cache; allows the lookup of PCI devices based on I/O address * * Copyright IBM Corporation 2004 @@ -47,8 +46,7 @@ * than any hash algo I could think of for this problem, even * with the penalty of slow pointer chases for d-cache misses). */ -struct pci_io_addr_range -{ +struct pci_io_addr_range { struct rb_node rb_node; unsigned long addr_lo; unsigned long addr_hi; @@ -56,13 +54,12 @@ struct pci_io_addr_range unsigned int flags; }; -static struct pci_io_addr_cache -{ +static struct pci_io_addr_cache { struct rb_root rb_root; spinlock_t piar_lock; } pci_io_addr_cache_root; -static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) +static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) { struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; @@ -86,7 +83,7 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) } /** - * pci_get_device_by_addr - Get device, given only address + * pci_addr_cache_get_device - Get device, given only address * @addr: mmio (PIO) phys address or i/o port number * * Given an mmio phys address, or a port number, find a pci device @@ -95,13 +92,13 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) * from zero (that is, they do *not* have pci_io_addr added in). * It is safe to call this function within an interrupt. */ -struct pci_dev *pci_get_device_by_addr(unsigned long addr) +struct pci_dev *pci_addr_cache_get_device(unsigned long addr) { struct pci_dev *dev; unsigned long flags; spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - dev = __pci_get_device_by_addr(addr); + dev = __pci_addr_cache_get_device(addr); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); return dev; } @@ -166,7 +163,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, #ifdef DEBUG printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", - alo, ahi, pci_name (dev)); + alo, ahi, pci_name(dev)); #endif rb_link_node(&piar->rb_node, parent, p); @@ -178,7 +175,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, static void __pci_addr_cache_insert_device(struct pci_dev *dev) { struct device_node *dn; - struct pci_dn *pdn; + struct eeh_dev *edev; int i; dn = pci_device_to_OF_node(dev); @@ -187,13 +184,19 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) return; } + edev = of_node_to_eeh_dev(dn); + if (!edev) { + pr_warning("PCI: no EEH dev found for dn=%s\n", + dn->full_name); + return; + } + /* Skip any devices for which EEH is not enabled. */ - pdn = PCI_DN(dn); - if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || - pdn->eeh_mode & EEH_MODE_NOCHECK) { + if (!(edev->mode & EEH_MODE_SUPPORTED) || + edev->mode & EEH_MODE_NOCHECK) { #ifdef DEBUG - printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", - pci_name(dev), pdn->node->full_name); + pr_info("PCI: skip building address cache for=%s - %s\n", + pci_name(dev), dn->full_name); #endif return; } @@ -284,6 +287,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) void __init pci_addr_cache_build(void) { struct device_node *dn; + struct eeh_dev *edev; struct pci_dev *dev = NULL; spin_lock_init(&pci_io_addr_cache_root.piar_lock); @@ -294,8 +298,14 @@ void __init pci_addr_cache_build(void) dn = pci_device_to_OF_node(dev); if (!dn) continue; + + edev = of_node_to_eeh_dev(dn); + if (!edev) + continue; + pci_dev_get(dev); /* matching put is in eeh_remove_device() */ - PCI_DN(dn)->pcidev = dev; + dev->dev.archdata.edev = edev; + edev->pdev = dev; eeh_sysfs_add_device(dev); } diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c new file mode 100644 index 000000000000..f3aed7dcae95 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_dev.c @@ -0,0 +1,102 @@ +/* + * The file intends to implement dynamic creation of EEH device, which will + * be bound with OF node and PCI device simutaneously. The EEH devices would + * be foundamental information for EEH core components to work proerly. Besides, + * We have to support multiple situations where dynamic creation of EEH device + * is required: + * + * 1) Before PCI emunation starts, we need create EEH devices according to the + * PCI sensitive OF nodes. + * 2) When PCI emunation is done, we need do the binding between PCI device and + * the associated EEH device. + * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device + * will be created while PCI sensitive OF node is detected from DR. + * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If + * PHB is newly inserted, we also need create EEH devices accordingly. + * + * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/export.h> +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> + +#include <asm/pci-bridge.h> +#include <asm/ppc-pci.h> + +/** + * eeh_dev_init - Create EEH device according to OF node + * @dn: device node + * @data: PHB + * + * It will create EEH device according to the given OF node. The function + * might be called by PCI emunation, DR, PHB hotplug. + */ +void * __devinit eeh_dev_init(struct device_node *dn, void *data) +{ + struct pci_controller *phb = data; + struct eeh_dev *edev; + + /* Allocate EEH device */ + edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL); + if (!edev) { + pr_warning("%s: out of memory\n", __func__); + return NULL; + } + + /* Associate EEH device with OF node */ + dn->edev = edev; + edev->dn = dn; + edev->phb = phb; + + return NULL; +} + +/** + * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB + * @phb: PHB + * + * Scan the PHB OF node and its child association, then create the + * EEH devices accordingly + */ +void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) +{ + struct device_node *dn = phb->dn; + + /* EEH device for PHB */ + eeh_dev_init(dn, phb); + + /* EEH devices for children OF nodes */ + traverse_pci_devices(dn, eeh_dev_init, phb); +} + +/** + * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs + * + * Scan all the existing PHBs and create EEH devices for their OF + * nodes and their children OF nodes + */ +void __init eeh_dev_phb_init(void) +{ + struct pci_controller *phb, *tmp; + + list_for_each_entry_safe(phb, tmp, &hose_list, list_node) + eeh_dev_phb_init_dynamic(phb); +} diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1b6cb10589e0..baf92cd9dfab 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -33,8 +33,14 @@ #include <asm/prom.h> #include <asm/rtas.h> - -static inline const char * pcid_name (struct pci_dev *pdev) +/** + * eeh_pcid_name - Retrieve name of PCI device driver + * @pdev: PCI device + * + * This routine is used to retrieve the name of PCI device driver + * if that's valid. + */ +static inline const char *eeh_pcid_name(struct pci_dev *pdev) { if (pdev && pdev->dev.driver) return pdev->dev.driver->name; @@ -64,48 +70,59 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent) #endif /** - * eeh_disable_irq - disable interrupt for the recovering device + * eeh_disable_irq - Disable interrupt for the recovering device + * @dev: PCI device + * + * This routine must be called when reporting temporary or permanent + * error to the particular PCI device to disable interrupt of that + * device. If the device has enabled MSI or MSI-X interrupt, we needn't + * do real work because EEH should freeze DMA transfers for those PCI + * devices encountering EEH errors, which includes MSI or MSI-X. */ static void eeh_disable_irq(struct pci_dev *dev) { - struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); /* Don't disable MSI and MSI-X interrupts. They are * effectively disabled by the DMA Stopped state * when an EEH error occurs. - */ + */ if (dev->msi_enabled || dev->msix_enabled) return; if (!irq_has_action(dev->irq)) return; - PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; + edev->mode |= EEH_MODE_IRQ_DISABLED; disable_irq_nosync(dev->irq); } /** - * eeh_enable_irq - enable interrupt for the recovering device + * eeh_enable_irq - Enable interrupt for the recovering device + * @dev: PCI device + * + * This routine must be called to enable interrupt while failed + * device could be resumed. */ static void eeh_enable_irq(struct pci_dev *dev) { - struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); - if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { - PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; + if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { + edev->mode &= ~EEH_MODE_IRQ_DISABLED; enable_irq(dev->irq); } } -/* ------------------------------------------------------- */ /** - * eeh_report_error - report pci error to each device driver + * eeh_report_error - Report pci error to each device driver + * @dev: PCI device + * @userdata: return value * * Report an EEH error to each device driver, collect up and * merge the device driver responses. Cumulative response * passed back in "userdata". */ - static int eeh_report_error(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -122,7 +139,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) !driver->err_handler->error_detected) return 0; - rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); + rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); /* A driver that needs a reset trumps all others */ if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; @@ -132,13 +149,14 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) } /** - * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled + * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled + * @dev: PCI device + * @userdata: return value * * Tells each device driver that IO ports, MMIO and config space I/O * are now enabled. Collects up and merges the device driver responses. * Cumulative response passed back in "userdata". */ - static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -149,7 +167,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) !driver->err_handler->mmio_enabled) return 0; - rc = driver->err_handler->mmio_enabled (dev); + rc = driver->err_handler->mmio_enabled(dev); /* A driver that needs a reset trumps all others */ if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; @@ -159,9 +177,15 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) } /** - * eeh_report_reset - tell device that slot has been reset + * eeh_report_reset - Tell device that slot has been reset + * @dev: PCI device + * @userdata: return value + * + * This routine must be called while EEH tries to reset particular + * PCI device so that the associated PCI device driver could take + * some actions, usually to save data the driver needs so that the + * driver can work again while the device is recovered. */ - static int eeh_report_reset(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -188,9 +212,14 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) } /** - * eeh_report_resume - tell device to resume normal operations + * eeh_report_resume - Tell device to resume normal operations + * @dev: PCI device + * @userdata: return value + * + * This routine must be called to notify the device driver that it + * could resume so that the device driver can do some initialization + * to make the recovered device work again. */ - static int eeh_report_resume(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; @@ -212,12 +241,13 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata) } /** - * eeh_report_failure - tell device driver that device is dead. + * eeh_report_failure - Tell device driver that device is dead. + * @dev: PCI device + * @userdata: return value * * This informs the device driver that the device is permanently * dead, and that no further recovery attempts will be made on it. */ - static int eeh_report_failure(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; @@ -238,65 +268,46 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata) return 0; } -/* ------------------------------------------------------- */ /** - * handle_eeh_events -- reset a PCI device after hard lockup. - * - * pSeries systems will isolate a PCI slot if the PCI-Host - * bridge detects address or data parity errors, DMA's - * occurring to wild addresses (which usually happen due to - * bugs in device drivers or in PCI adapter firmware). - * Slot isolations also occur if #SERR, #PERR or other misc - * PCI-related errors are detected. + * eeh_reset_device - Perform actual reset of a pci slot + * @edev: PE associated EEH device + * @bus: PCI bus corresponding to the isolcated slot * - * Recovery process consists of unplugging the device driver - * (which generated hotplug events to userspace), then issuing - * a PCI #RST to the device, then reconfiguring the PCI config - * space for all bridges & devices under this slot, and then - * finally restarting the device drivers (which cause a second - * set of hotplug events to go out to userspace). + * This routine must be called to do reset on the indicated PE. + * During the reset, udev might be invoked because those affected + * PCI devices will be removed and then added. */ - -/** - * eeh_reset_device() -- perform actual reset of a pci slot - * @bus: pointer to the pci bus structure corresponding - * to the isolated slot. A non-null value will - * cause all devices under the bus to be removed - * and then re-added. - * @pe_dn: pointer to a "Partionable Endpoint" device node. - * This is the top-level structure on which pci - * bus resets can be performed. - */ - -static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) +static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) { struct device_node *dn; int cnt, rc; /* pcibios will clear the counter; save the value */ - cnt = pe_dn->eeh_freeze_count; + cnt = edev->freeze_count; if (bus) pcibios_remove_pci_devices(bus); /* Reset the pci controller. (Asserts RST#; resets config space). * Reconfigure bridges and devices. Don't try to bring the system - * up if the reset failed for some reason. */ - rc = rtas_set_slot_reset(pe_dn); + * up if the reset failed for some reason. + */ + rc = eeh_reset_pe(edev); if (rc) return rc; - /* Walk over all functions on this device. */ - dn = pe_dn->node; - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + /* Walk over all functions on this device. */ + dn = eeh_dev_to_of_node(edev); + if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent->child; while (dn) { - struct pci_dn *ppe = PCI_DN(dn); + struct eeh_dev *pedev = of_node_to_eeh_dev(dn); + /* On Power4, always true because eeh_pe_config_addr=0 */ - if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { - rtas_configure_bridge(ppe); - eeh_restore_bars(ppe); + if (edev->pe_config_addr == pedev->pe_config_addr) { + eeh_ops->configure_bridge(dn); + eeh_restore_bars(pedev); } dn = dn->sibling; } @@ -308,10 +319,10 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) * potentially weird things happen. */ if (bus) { - ssleep (5); + ssleep(5); pcibios_add_pci_devices(bus); } - pe_dn->eeh_freeze_count = cnt; + edev->freeze_count = cnt; return 0; } @@ -321,23 +332,39 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) */ #define MAX_WAIT_FOR_RECOVERY 150 -struct pci_dn * handle_eeh_events (struct eeh_event *event) +/** + * eeh_handle_event - Reset a PCI device after hard lockup. + * @event: EEH event + * + * While PHB detects address or data parity errors on particular PCI + * slot, the associated PE will be frozen. Besides, DMA's occurring + * to wild addresses (which usually happen due to bugs in device + * drivers or in PCI adapter firmware) can cause EEH error. #SERR, + * #PERR or other misc PCI-related errors also can trigger EEH errors. + * + * Recovery process consists of unplugging the device driver (which + * generated hotplug events to userspace), then issuing a PCI #RST to + * the device, then reconfiguring the PCI config space for all bridges + * & devices under this slot, and then finally restarting the device + * drivers (which cause a second set of hotplug events to go out to + * userspace). + */ +struct eeh_dev *handle_eeh_events(struct eeh_event *event) { struct device_node *frozen_dn; - struct pci_dn *frozen_pdn; + struct eeh_dev *frozen_edev; struct pci_bus *frozen_bus; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; - frozen_dn = find_device_pe(event->dn); + frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev)); if (!frozen_dn) { - - location = of_get_property(event->dn, "ibm,loc-code", NULL); + location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL); location = location ? location : "unknown"; printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " "for location=%s pci addr=%s\n", - location, eeh_pci_name(event->dev)); + location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev))); return NULL; } @@ -350,9 +377,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) * which was always an EADS pci bridge. In the new style, * there might not be any EADS bridges, and even when there are, * the firmware marks them as "EEH incapable". So another - * two-step is needed to find the pci bus.. */ + * two-step is needed to find the pci bus.. + */ if (!frozen_bus) - frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); + frozen_bus = pcibios_find_pci_bus(frozen_dn->parent); if (!frozen_bus) { printk(KERN_ERR "EEH: Cannot find PCI bus " @@ -361,22 +389,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) return NULL; } - frozen_pdn = PCI_DN(frozen_dn); - frozen_pdn->eeh_freeze_count++; + frozen_edev = of_node_to_eeh_dev(frozen_dn); + frozen_edev->freeze_count++; + pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev)); + drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev)); - pci_str = eeh_pci_name(event->dev); - drv_str = pcid_name(event->dev); - - if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) + if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES) goto excess_failures; printk(KERN_WARNING "EEH: This PCI device has failed %d times in the last hour:\n", - frozen_pdn->eeh_freeze_count); + frozen_edev->freeze_count); - if (frozen_pdn->pcidev) { - bus_pci_str = pci_name(frozen_pdn->pcidev); - bus_drv_str = pcid_name(frozen_pdn->pcidev); + if (frozen_edev->pdev) { + bus_pci_str = pci_name(frozen_edev->pdev); + bus_drv_str = eeh_pcid_name(frozen_edev->pdev); printk(KERN_WARNING "EEH: Bus location=%s driver=%s pci addr=%s\n", location, bus_drv_str, bus_pci_str); @@ -395,9 +422,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) pci_walk_bus(frozen_bus, eeh_report_error, &result); /* Get the current PCI slot state. This can take a long time, - * sometimes over 3 seconds for certain systems. */ - rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); - if (rc < 0) { + * sometimes over 3 seconds for certain systems. + */ + rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000); + if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { printk(KERN_WARNING "EEH: Permanent failure\n"); goto hard_fail; } @@ -406,14 +434,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) * don't post the error log until after all dev drivers * have been informed. */ - eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE); + eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP); /* If all device drivers were EEH-unaware, then shut * down all of the device drivers, and hope they * go down willingly, without panicing the system. */ if (result == PCI_ERS_RESULT_NONE) { - rc = eeh_reset_device(frozen_pdn, frozen_bus); + rc = eeh_reset_device(frozen_edev, frozen_bus); if (rc) { printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); goto hard_fail; @@ -422,7 +450,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) /* If all devices reported they can proceed, then re-enable MMIO */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { - rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); + rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO); if (rc < 0) goto hard_fail; @@ -436,7 +464,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) /* If all devices reported they can proceed, then re-enable DMA */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { - rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); + rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA); if (rc < 0) goto hard_fail; @@ -454,7 +482,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) /* If any device called out for a reset, then reset the slot */ if (result == PCI_ERS_RESULT_NEED_RESET) { - rc = eeh_reset_device(frozen_pdn, NULL); + rc = eeh_reset_device(frozen_edev, NULL); if (rc) { printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); goto hard_fail; @@ -473,7 +501,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) /* Tell all device drivers that they can resume operations */ pci_walk_bus(frozen_bus, eeh_report_resume, NULL); - return frozen_pdn; + return frozen_edev; excess_failures: /* @@ -486,7 +514,7 @@ excess_failures: "has failed %d times in the last hour " "and has been permanently disabled.\n" "Please try reseating this device or replacing it.\n", - location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); + location, drv_str, pci_str, frozen_edev->freeze_count); goto perm_error; hard_fail: @@ -497,7 +525,7 @@ hard_fail: location, drv_str, pci_str); perm_error: - eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); + eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM); /* Notify all devices that they're about to go down. */ pci_walk_bus(frozen_bus, eeh_report_failure, NULL); @@ -508,4 +536,3 @@ perm_error: return NULL; } -/* ---------- end of file ---------- */ diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index d2383cfb6dfd..4a4752565856 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -1,6 +1,4 @@ /* - * eeh_event.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 @@ -46,7 +44,7 @@ DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); DEFINE_MUTEX(eeh_event_mutex); /** - * eeh_event_handler - dispatch EEH events. + * eeh_event_handler - Dispatch EEH events. * @dummy - unused * * The detection of a frozen slot can occur inside an interrupt, @@ -58,10 +56,10 @@ DEFINE_MUTEX(eeh_event_mutex); static int eeh_event_handler(void * dummy) { unsigned long flags; - struct eeh_event *event; - struct pci_dn *pdn; + struct eeh_event *event; + struct eeh_dev *edev; - daemonize ("eehd"); + daemonize("eehd"); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -79,31 +77,37 @@ static int eeh_event_handler(void * dummy) /* Serialize processing of EEH events */ mutex_lock(&eeh_event_mutex); - eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); + edev = event->edev; + eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", - eeh_pci_name(event->dev)); + eeh_pci_name(edev->pdev)); + + edev = handle_eeh_events(event); - pdn = handle_eeh_events(event); + eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); + pci_dev_put(edev->pdev); - eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); - pci_dev_put(event->dev); kfree(event); mutex_unlock(&eeh_event_mutex); /* If there are no new errors after an hour, clear the counter. */ - if (pdn && pdn->eeh_freeze_count>0) { - msleep_interruptible (3600*1000); - if (pdn->eeh_freeze_count>0) - pdn->eeh_freeze_count--; + if (edev && edev->freeze_count>0) { + msleep_interruptible(3600*1000); + if (edev->freeze_count>0) + edev->freeze_count--; + } return 0; } /** - * eeh_thread_launcher + * eeh_thread_launcher - Start kernel thread to handle EEH events * @dummy - unused + * + * This routine is called to start the kernel thread for processing + * EEH event. */ static void eeh_thread_launcher(struct work_struct *dummy) { @@ -112,18 +116,18 @@ static void eeh_thread_launcher(struct work_struct *dummy) } /** - * eeh_send_failure_event - generate a PCI error event - * @dev pci device + * eeh_send_failure_event - Generate a PCI error event + * @edev: EEH device * * This routine can be called within an interrupt context; * the actual event will be delivered in a normal context * (from a workqueue). */ -int eeh_send_failure_event (struct device_node *dn, - struct pci_dev *dev) +int eeh_send_failure_event(struct eeh_dev *edev) { unsigned long flags; struct eeh_event *event; + struct device_node *dn = eeh_dev_to_of_node(edev); const char *location; if (!mem_init_done) { @@ -135,15 +139,14 @@ int eeh_send_failure_event (struct device_node *dn, } event = kmalloc(sizeof(*event), GFP_ATOMIC); if (event == NULL) { - printk (KERN_ERR "EEH: out of memory, event not handled\n"); + printk(KERN_ERR "EEH: out of memory, event not handled\n"); return 1; } - if (dev) - pci_dev_get(dev); + if (edev->pdev) + pci_dev_get(edev->pdev); - event->dn = dn; - event->dev = dev; + event->edev = edev; /* We may or may not be called in an interrupt context */ spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -154,5 +157,3 @@ int eeh_send_failure_event (struct device_node *dn, return 0; } - -/********************** END OF FILE ******************************/ diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c new file mode 100644 index 000000000000..8752f79a6af8 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -0,0 +1,565 @@ +/* + * The file intends to implement the platform dependent EEH operations on pseries. + * Actually, the pseries platform is built based on RTAS heavily. That means the + * pseries platform dependent EEH operations will be built on RTAS calls. The functions + * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has + * been done. + * + * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011. + * Copyright IBM Corporation 2001, 2005, 2006 + * Copyright Dave Engebretsen & Todd Inglett 2001 + * Copyright Linas Vepstas 2005, 2006 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/atomic.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/of.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/rbtree.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/spinlock.h> + +#include <asm/eeh.h> +#include <asm/eeh_event.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ppc-pci.h> +#include <asm/rtas.h> + +/* RTAS tokens */ +static int ibm_set_eeh_option; +static int ibm_set_slot_reset; +static int ibm_read_slot_reset_state; +static int ibm_read_slot_reset_state2; +static int ibm_slot_error_detail; +static int ibm_get_config_addr_info; +static int ibm_get_config_addr_info2; +static int ibm_configure_bridge; +static int ibm_configure_pe; + +/* + * Buffer for reporting slot-error-detail rtas calls. Its here + * in BSS, and not dynamically alloced, so that it ends up in + * RMO where RTAS can access it. + */ +static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; +static DEFINE_SPINLOCK(slot_errbuf_lock); +static int eeh_error_buf_size; + +/** + * pseries_eeh_init - EEH platform dependent initialization + * + * EEH platform dependent initialization on pseries. + */ +static int pseries_eeh_init(void) +{ + /* figure out EEH RTAS function call tokens */ + ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); + ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); + ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); + ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); + ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); + ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); + ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); + ibm_configure_pe = rtas_token("ibm,configure-pe"); + ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); + + /* necessary sanity check */ + if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && + ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and " + "<ibm,read-slot-reset-state> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE && + ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,get-config-addr-info2> and " + "<ibm,get-config-addr-info> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE && + ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,configure-pe> and " + "<ibm,configure-bridge> invalid\n", + __func__); + return -EINVAL; + } + + /* Initialize error log lock and size */ + spin_lock_init(&slot_errbuf_lock); + eeh_error_buf_size = rtas_token("rtas-error-log-max"); + if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: unknown EEH error log size\n", + __func__); + eeh_error_buf_size = 1024; + } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { + pr_warning("%s: EEH error log size %d exceeds the maximal %d\n", + __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX); + eeh_error_buf_size = RTAS_ERROR_LOG_MAX; + } + + return 0; +} + +/** + * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable + * @dn: device node + * @option: operation to be issued + * + * The function is used to control the EEH functionality globally. + * Currently, following options are support according to PAPR: + * Enable EEH, Disable EEH, Enable MMIO and Enable DMA + */ +static int pseries_eeh_set_option(struct device_node *dn, int option) +{ + int ret = 0; + struct eeh_dev *edev; + const u32 *reg; + int config_addr; + + edev = of_node_to_eeh_dev(dn); + + /* + * When we're enabling or disabling EEH functioality on + * the particular PE, the PE config address is possibly + * unavailable. Therefore, we have to figure it out from + * the FDT node. + */ + switch (option) { + case EEH_OPT_DISABLE: + case EEH_OPT_ENABLE: + reg = of_get_property(dn, "reg", NULL); + config_addr = reg[0]; + break; + + case EEH_OPT_THAW_MMIO: + case EEH_OPT_THAW_DMA: + config_addr = edev->config_addr; + if (edev->pe_config_addr) + config_addr = edev->pe_config_addr; + break; + + default: + pr_err("%s: Invalid option %d\n", + __func__, option); + return -EINVAL; + } + + ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid), option); + + return ret; +} + +/** + * pseries_eeh_get_pe_addr - Retrieve PE address + * @dn: device node + * + * Retrieve the assocated PE address. Actually, there're 2 RTAS + * function calls dedicated for the purpose. We need implement + * it through the new function and then the old one. Besides, + * you should make sure the config address is figured out from + * FDT node before calling the function. + * + * It's notable that zero'ed return value means invalid PE config + * address. + */ +static int pseries_eeh_get_pe_addr(struct device_node *dn) +{ + struct eeh_dev *edev; + int ret = 0; + int rets[3]; + + edev = of_node_to_eeh_dev(dn); + + if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { + /* + * First of all, we need to make sure there has one PE + * associated with the device. Otherwise, PE address is + * meaningless. + */ + ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, + edev->config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid), 1); + if (ret || (rets[0] == 0)) + return 0; + + /* Retrieve the associated PE config address */ + ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, + edev->config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid), 0); + if (ret) { + pr_warning("%s: Failed to get PE address for %s\n", + __func__, dn->full_name); + return 0; + } + + return rets[0]; + } + + if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, + edev->config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid), 0); + if (ret) { + pr_warning("%s: Failed to get PE address for %s\n", + __func__, dn->full_name); + return 0; + } + + return rets[0]; + } + + return ret; +} + +/** + * pseries_eeh_get_state - Retrieve PE state + * @dn: PE associated device node + * @state: return value + * + * Retrieve the state of the specified PE. On RTAS compliant + * pseries platform, there already has one dedicated RTAS function + * for the purpose. It's notable that the associated PE config address + * might be ready when calling the function. Therefore, endeavour to + * use the PE config address if possible. Further more, there're 2 + * RTAS calls for the purpose, we need to try the new one and back + * to the old one if the new one couldn't work properly. + */ +static int pseries_eeh_get_state(struct device_node *dn, int *state) +{ + struct eeh_dev *edev; + int config_addr; + int ret; + int rets[4]; + int result; + + /* Figure out PE config address if possible */ + edev = of_node_to_eeh_dev(dn); + config_addr = edev->config_addr; + if (edev->pe_config_addr) + config_addr = edev->pe_config_addr; + + if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid)); + } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { + /* Fake PE unavailable info */ + rets[2] = 0; + ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid)); + } else { + return EEH_STATE_NOT_SUPPORT; + } + + if (ret) + return ret; + + /* Parse the result out */ + result = 0; + if (rets[1]) { + switch(rets[0]) { + case 0: + result &= ~EEH_STATE_RESET_ACTIVE; + result |= EEH_STATE_MMIO_ACTIVE; + result |= EEH_STATE_DMA_ACTIVE; + break; + case 1: + result |= EEH_STATE_RESET_ACTIVE; + result |= EEH_STATE_MMIO_ACTIVE; + result |= EEH_STATE_DMA_ACTIVE; + break; + case 2: + result &= ~EEH_STATE_RESET_ACTIVE; + result &= ~EEH_STATE_MMIO_ACTIVE; + result &= ~EEH_STATE_DMA_ACTIVE; + break; + case 4: + result &= ~EEH_STATE_RESET_ACTIVE; + result &= ~EEH_STATE_MMIO_ACTIVE; + result &= ~EEH_STATE_DMA_ACTIVE; + result |= EEH_STATE_MMIO_ENABLED; + break; + case 5: + if (rets[2]) { + if (state) *state = rets[2]; + result = EEH_STATE_UNAVAILABLE; + } else { + result = EEH_STATE_NOT_SUPPORT; + } + default: + result = EEH_STATE_NOT_SUPPORT; + } + } else { + result = EEH_STATE_NOT_SUPPORT; + } + + return result; +} + +/** + * pseries_eeh_reset - Reset the specified PE + * @dn: PE associated device node + * @option: reset option + * + * Reset the specified PE + */ +static int pseries_eeh_reset(struct device_node *dn, int option) +{ + struct eeh_dev *edev; + int config_addr; + int ret; + + /* Figure out PE address */ + edev = of_node_to_eeh_dev(dn); + config_addr = edev->config_addr; + if (edev->pe_config_addr) + config_addr = edev->pe_config_addr; + + /* Reset PE through RTAS call */ + ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid), option); + + /* If fundamental-reset not supported, try hot-reset */ + if (option == EEH_RESET_FUNDAMENTAL && + ret == -8) { + ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid), EEH_RESET_HOT); + } + + return ret; +} + +/** + * pseries_eeh_wait_state - Wait for PE state + * @dn: PE associated device node + * @max_wait: maximal period in microsecond + * + * Wait for the state of associated PE. It might take some time + * to retrieve the PE's state. + */ +static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) +{ + int ret; + int mwait; + + /* + * According to PAPR, the state of PE might be temporarily + * unavailable. Under the circumstance, we have to wait + * for indicated time determined by firmware. The maximal + * wait time is 5 minutes, which is acquired from the original + * EEH implementation. Also, the original implementation + * also defined the minimal wait time as 1 second. + */ +#define EEH_STATE_MIN_WAIT_TIME (1000) +#define EEH_STATE_MAX_WAIT_TIME (300 * 1000) + + while (1) { + ret = pseries_eeh_get_state(dn, &mwait); + + /* + * If the PE's state is temporarily unavailable, + * we have to wait for the specified time. Otherwise, + * the PE's state will be returned immediately. + */ + if (ret != EEH_STATE_UNAVAILABLE) + return ret; + + if (max_wait <= 0) { + pr_warning("%s: Timeout when getting PE's state (%d)\n", + __func__, max_wait); + return EEH_STATE_NOT_SUPPORT; + } + + if (mwait <= 0) { + pr_warning("%s: Firmware returned bad wait value %d\n", + __func__, mwait); + mwait = EEH_STATE_MIN_WAIT_TIME; + } else if (mwait > EEH_STATE_MAX_WAIT_TIME) { + pr_warning("%s: Firmware returned too long wait value %d\n", + __func__, mwait); + mwait = EEH_STATE_MAX_WAIT_TIME; + } + + max_wait -= mwait; + msleep(mwait); + } + + return EEH_STATE_NOT_SUPPORT; +} + +/** + * pseries_eeh_get_log - Retrieve error log + * @dn: device node + * @severity: temporary or permanent error log + * @drv_log: driver log to be combined with retrieved error log + * @len: length of driver log + * + * Retrieve the temporary or permanent error from the PE. + * Actually, the error will be retrieved through the dedicated + * RTAS call. + */ +static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) +{ + struct eeh_dev *edev; + int config_addr; + unsigned long flags; + int ret; + + edev = of_node_to_eeh_dev(dn); + spin_lock_irqsave(&slot_errbuf_lock, flags); + memset(slot_errbuf, 0, eeh_error_buf_size); + + /* Figure out the PE address */ + config_addr = edev->config_addr; + if (edev->pe_config_addr) + config_addr = edev->pe_config_addr; + + ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, + BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), + virt_to_phys(drv_log), len, + virt_to_phys(slot_errbuf), eeh_error_buf_size, + severity); + if (!ret) + log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); + spin_unlock_irqrestore(&slot_errbuf_lock, flags); + + return ret; +} + +/** + * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE + * @dn: PE associated device node + * + * The function will be called to reconfigure the bridges included + * in the specified PE so that the mulfunctional PE would be recovered + * again. + */ +static int pseries_eeh_configure_bridge(struct device_node *dn) +{ + struct eeh_dev *edev; + int config_addr; + int ret; + + /* Figure out the PE address */ + edev = of_node_to_eeh_dev(dn); + config_addr = edev->config_addr; + if (edev->pe_config_addr) + config_addr = edev->pe_config_addr; + + /* Use new configure-pe function, if supported */ + if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_configure_pe, 3, 1, NULL, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid)); + } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, + config_addr, BUID_HI(edev->phb->buid), + BUID_LO(edev->phb->buid)); + } else { + return -EFAULT; + } + + if (ret) + pr_warning("%s: Unable to configure bridge %d for %s\n", + __func__, ret, dn->full_name); + + return ret; +} + +/** + * pseries_eeh_read_config - Read PCI config space + * @dn: device node + * @where: PCI address + * @size: size to read + * @val: return value + * + * Read config space from the speicifed device + */ +static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val) +{ + struct pci_dn *pdn; + + pdn = PCI_DN(dn); + + return rtas_read_config(pdn, where, size, val); +} + +/** + * pseries_eeh_write_config - Write PCI config space + * @dn: device node + * @where: PCI address + * @size: size to write + * @val: value to be written + * + * Write config space to the specified device + */ +static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val) +{ + struct pci_dn *pdn; + + pdn = PCI_DN(dn); + + return rtas_write_config(pdn, where, size, val); +} + +static struct eeh_ops pseries_eeh_ops = { + .name = "pseries", + .init = pseries_eeh_init, + .set_option = pseries_eeh_set_option, + .get_pe_addr = pseries_eeh_get_pe_addr, + .get_state = pseries_eeh_get_state, + .reset = pseries_eeh_reset, + .wait_state = pseries_eeh_wait_state, + .get_log = pseries_eeh_get_log, + .configure_bridge = pseries_eeh_configure_bridge, + .read_config = pseries_eeh_read_config, + .write_config = pseries_eeh_write_config +}; + +/** + * eeh_pseries_init - Register platform dependent EEH operations + * + * EEH initialization on pseries platform. This function should be + * called before any EEH related functions. + */ +int __init eeh_pseries_init(void) +{ + return eeh_ops_register(&pseries_eeh_ops); +} diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index eb744ee234da..243b3510d70f 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -28,7 +28,7 @@ #include <asm/pci-bridge.h> /** - * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic + * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic * @_name: name of file in sysfs directory * @_memb: name of member in struct pci_dn to access * @_format: printf format for display @@ -41,24 +41,21 @@ static ssize_t eeh_show_##_name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct pci_dev *pdev = to_pci_dev(dev); \ - struct device_node *dn = pci_device_to_OF_node(pdev); \ - struct pci_dn *pdn; \ + struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \ \ - if (!dn || PCI_DN(dn) == NULL) \ - return 0; \ + if (!edev) \ + return 0; \ \ - pdn = PCI_DN(dn); \ - return sprintf(buf, _format "\n", pdn->_memb); \ + return sprintf(buf, _format "\n", edev->_memb); \ } \ static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); - -EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); -EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); -EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); -EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); +EEH_SHOW_ATTR(eeh_mode, mode, "0x%x"); +EEH_SHOW_ATTR(eeh_config_addr, config_addr, "0x%x"); +EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); +EEH_SHOW_ATTR(eeh_check_count, check_count, "%d" ); +EEH_SHOW_ATTR(eeh_freeze_count, freeze_count, "%d" ); +EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d" ); void eeh_sysfs_add_device(struct pci_dev *pdev) { diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 7bc73af6c7b9..5f3ef876ded2 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -41,6 +41,7 @@ #include <asm/udbg.h> #include <asm/smp.h> #include <asm/trace.h> +#include <asm/firmware.h> #include "plpar_wrappers.h" #include "pseries.h" diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 38d24e7e7bb1..109fdb75578d 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -217,7 +217,7 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) if (!dn) return NULL; - dn = find_device_pe(dn); + dn = eeh_find_device_pe(dn); if (!dn) return NULL; diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 55d4ec1bd1ac..fbb21fc3080b 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -147,6 +147,9 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) pci_devs_phb_init_dynamic(phb); + /* Create EEH devices for the PHB */ + eeh_dev_phb_init_dynamic(phb); + if (dn->child) eeh_add_device_tree_early(dn); diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c deleted file mode 100644 index 6e7742da0072..000000000000 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Hypervisor-assisted dump - * - * Linas Vepstas, Manish Ahuja 2008 - * Copyright 2008 IBM Corp. - * - * 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. - * - */ - -#include <linux/gfp.h> -#include <linux/init.h> -#include <linux/kobject.h> -#include <linux/mm.h> -#include <linux/of.h> -#include <linux/pfn.h> -#include <linux/swap.h> -#include <linux/sysfs.h> - -#include <asm/page.h> -#include <asm/phyp_dump.h> -#include <asm/machdep.h> -#include <asm/prom.h> -#include <asm/rtas.h> - -/* Variables, used to communicate data between early boot and late boot */ -static struct phyp_dump phyp_dump_vars; -struct phyp_dump *phyp_dump_info = &phyp_dump_vars; - -static int ibm_configure_kernel_dump; -/* ------------------------------------------------- */ -/* RTAS interfaces to declare the dump regions */ - -struct dump_section { - u32 dump_flags; - u16 source_type; - u16 error_flags; - u64 source_address; - u64 source_length; - u64 length_copied; - u64 destination_address; -}; - -struct phyp_dump_header { - u32 version; - u16 num_of_sections; - u16 status; - - u32 first_offset_section; - u32 dump_disk_section; - u64 block_num_dd; - u64 num_of_blocks_dd; - u32 offset_dd; - u32 maxtime_to_auto; - /* No dump disk path string used */ - - struct dump_section cpu_data; - struct dump_section hpte_data; - struct dump_section kernel_data; -}; - -/* The dump header *must be* in low memory, so .bss it */ -static struct phyp_dump_header phdr; - -#define NUM_DUMP_SECTIONS 3 -#define DUMP_HEADER_VERSION 0x1 -#define DUMP_REQUEST_FLAG 0x1 -#define DUMP_SOURCE_CPU 0x0001 -#define DUMP_SOURCE_HPTE 0x0002 -#define DUMP_SOURCE_RMO 0x0011 -#define DUMP_ERROR_FLAG 0x2000 -#define DUMP_TRIGGERED 0x4000 -#define DUMP_PERFORMED 0x8000 - - -/** - * init_dump_header() - initialize the header declaring a dump - * Returns: length of dump save area. - * - * When the hypervisor saves crashed state, it needs to put - * it somewhere. The dump header tells the hypervisor where - * the data can be saved. - */ -static unsigned long init_dump_header(struct phyp_dump_header *ph) -{ - unsigned long addr_offset = 0; - - /* Set up the dump header */ - ph->version = DUMP_HEADER_VERSION; - ph->num_of_sections = NUM_DUMP_SECTIONS; - ph->status = 0; - - ph->first_offset_section = - (u32)offsetof(struct phyp_dump_header, cpu_data); - ph->dump_disk_section = 0; - ph->block_num_dd = 0; - ph->num_of_blocks_dd = 0; - ph->offset_dd = 0; - - ph->maxtime_to_auto = 0; /* disabled */ - - /* The first two sections are mandatory */ - ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; - ph->cpu_data.source_type = DUMP_SOURCE_CPU; - ph->cpu_data.source_address = 0; - ph->cpu_data.source_length = phyp_dump_info->cpu_state_size; - ph->cpu_data.destination_address = addr_offset; - addr_offset += phyp_dump_info->cpu_state_size; - - ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; - ph->hpte_data.source_type = DUMP_SOURCE_HPTE; - ph->hpte_data.source_address = 0; - ph->hpte_data.source_length = phyp_dump_info->hpte_region_size; - ph->hpte_data.destination_address = addr_offset; - addr_offset += phyp_dump_info->hpte_region_size; - - /* This section describes the low kernel region */ - ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; - ph->kernel_data.source_type = DUMP_SOURCE_RMO; - ph->kernel_data.source_address = PHYP_DUMP_RMR_START; - ph->kernel_data.source_length = PHYP_DUMP_RMR_END; - ph->kernel_data.destination_address = addr_offset; - addr_offset += ph->kernel_data.source_length; - - return addr_offset; -} - -static void print_dump_header(const struct phyp_dump_header *ph) -{ -#ifdef DEBUG - if (ph == NULL) - return; - - printk(KERN_INFO "dump header:\n"); - /* setup some ph->sections required */ - printk(KERN_INFO "version = %d\n", ph->version); - printk(KERN_INFO "Sections = %d\n", ph->num_of_sections); - printk(KERN_INFO "Status = 0x%x\n", ph->status); - - /* No ph->disk, so all should be set to 0 */ - printk(KERN_INFO "Offset to first section 0x%x\n", - ph->first_offset_section); - printk(KERN_INFO "dump disk sections should be zero\n"); - printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section); - printk(KERN_INFO "block num = %lld\n", ph->block_num_dd); - printk(KERN_INFO "number of blocks = %lld\n", ph->num_of_blocks_dd); - printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd); - printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto); - - /*set cpu state and hpte states as well scratch pad area */ - printk(KERN_INFO " CPU AREA\n"); - printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags); - printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type); - printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags); - printk(KERN_INFO "cpu source_address =%llx\n", - ph->cpu_data.source_address); - printk(KERN_INFO "cpu source_length =%llx\n", - ph->cpu_data.source_length); - printk(KERN_INFO "cpu length_copied =%llx\n", - ph->cpu_data.length_copied); - - printk(KERN_INFO " HPTE AREA\n"); - printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags); - printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type); - printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags); - printk(KERN_INFO "HPTE source_address =%llx\n", - ph->hpte_data.source_address); - printk(KERN_INFO "HPTE source_length =%llx\n", - ph->hpte_data.source_length); - printk(KERN_INFO "HPTE length_copied =%llx\n", - ph->hpte_data.length_copied); - - printk(KERN_INFO " SRSD AREA\n"); - printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags); - printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type); - printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags); - printk(KERN_INFO "SRSD source_address =%llx\n", - ph->kernel_data.source_address); - printk(KERN_INFO "SRSD source_length =%llx\n", - ph->kernel_data.source_length); - printk(KERN_INFO "SRSD length_copied =%llx\n", - ph->kernel_data.length_copied); -#endif -} - -static ssize_t show_phyp_dump_active(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - - /* create filesystem entry so kdump is phyp-dump aware */ - return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot); -} - -static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600, - show_phyp_dump_active, - NULL); - -static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) -{ - int rc; - - /* Add addr value if not initialized before */ - if (ph->cpu_data.destination_address == 0) { - ph->cpu_data.destination_address += addr; - ph->hpte_data.destination_address += addr; - ph->kernel_data.destination_address += addr; - } - - /* ToDo Invalidate kdump and free memory range. */ - - do { - rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, - 1, ph, sizeof(struct phyp_dump_header)); - } while (rtas_busy_delay(rc)); - - if (rc) { - printk(KERN_ERR "phyp-dump: unexpected error (%d) on " - "register\n", rc); - print_dump_header(ph); - return; - } - - rc = sysfs_create_file(kernel_kobj, &pdl.attr); - if (rc) - printk(KERN_ERR "phyp-dump: unable to create sysfs" - " file (%d)\n", rc); -} - -static -void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) -{ - int rc; - - /* Add addr value if not initialized before */ - if (ph->cpu_data.destination_address == 0) { - ph->cpu_data.destination_address += addr; - ph->hpte_data.destination_address += addr; - ph->kernel_data.destination_address += addr; - } - - do { - rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, - 2, ph, sizeof(struct phyp_dump_header)); - } while (rtas_busy_delay(rc)); - - if (rc) { - printk(KERN_ERR "phyp-dump: unexpected error (%d) " - "on invalidate\n", rc); - print_dump_header(ph); - } -} - -/* ------------------------------------------------- */ -/** - * release_memory_range -- release memory previously memblock_reserved - * @start_pfn: starting physical frame number - * @nr_pages: number of pages to free. - * - * This routine will release memory that had been previously - * memblock_reserved in early boot. The released memory becomes - * available for genreal use. - */ -static void release_memory_range(unsigned long start_pfn, - unsigned long nr_pages) -{ - struct page *rpage; - unsigned long end_pfn; - long i; - - end_pfn = start_pfn + nr_pages; - - for (i = start_pfn; i <= end_pfn; i++) { - rpage = pfn_to_page(i); - if (PageReserved(rpage)) { - ClearPageReserved(rpage); - init_page_count(rpage); - __free_page(rpage); - totalram_pages++; - } - } -} - -/** - * track_freed_range -- Counts the range being freed. - * Once the counter goes to zero, it re-registers dump for - * future use. - */ -static void -track_freed_range(unsigned long addr, unsigned long length) -{ - static unsigned long scratch_area_size, reserved_area_size; - - if (addr < phyp_dump_info->init_reserve_start) - return; - - if ((addr >= phyp_dump_info->init_reserve_start) && - (addr <= phyp_dump_info->init_reserve_start + - phyp_dump_info->init_reserve_size)) - reserved_area_size += length; - - if ((addr >= phyp_dump_info->reserved_scratch_addr) && - (addr <= phyp_dump_info->reserved_scratch_addr + - phyp_dump_info->reserved_scratch_size)) - scratch_area_size += length; - - if ((reserved_area_size == phyp_dump_info->init_reserve_size) && - (scratch_area_size == phyp_dump_info->reserved_scratch_size)) { - - invalidate_last_dump(&phdr, - phyp_dump_info->reserved_scratch_addr); - register_dump_area(&phdr, - phyp_dump_info->reserved_scratch_addr); - } -} - -/* ------------------------------------------------- */ -/** - * sysfs_release_region -- sysfs interface to release memory range. - * - * Usage: - * "echo <start addr> <length> > /sys/kernel/release_region" - * - * Example: - * "echo 0x40000000 0x10000000 > /sys/kernel/release_region" - * - * will release 256MB starting at 1GB. - */ -static ssize_t store_release_region(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - unsigned long start_addr, length, end_addr; - unsigned long start_pfn, nr_pages; - ssize_t ret; - - ret = sscanf(buf, "%lx %lx", &start_addr, &length); - if (ret != 2) - return -EINVAL; - - track_freed_range(start_addr, length); - - /* Range-check - don't free any reserved memory that - * wasn't reserved for phyp-dump */ - if (start_addr < phyp_dump_info->init_reserve_start) - start_addr = phyp_dump_info->init_reserve_start; - - end_addr = phyp_dump_info->init_reserve_start + - phyp_dump_info->init_reserve_size; - if (start_addr+length > end_addr) - length = end_addr - start_addr; - - /* Release the region of memory assed in by user */ - start_pfn = PFN_DOWN(start_addr); - nr_pages = PFN_DOWN(length); - release_memory_range(start_pfn, nr_pages); - - return count; -} - -static ssize_t show_release_region(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - u64 second_addr_range; - - /* total reserved size - start of scratch area */ - second_addr_range = phyp_dump_info->init_reserve_size - - phyp_dump_info->reserved_scratch_size; - return sprintf(buf, "CPU:0x%llx-0x%llx: HPTE:0x%llx-0x%llx:" - " DUMP:0x%llx-0x%llx, 0x%lx-0x%llx:\n", - phdr.cpu_data.destination_address, - phdr.cpu_data.length_copied, - phdr.hpte_data.destination_address, - phdr.hpte_data.length_copied, - phdr.kernel_data.destination_address, - phdr.kernel_data.length_copied, - phyp_dump_info->init_reserve_start, - second_addr_range); -} - -static struct kobj_attribute rr = __ATTR(release_region, 0600, - show_release_region, - store_release_region); - -static int __init phyp_dump_setup(void) -{ - struct device_node *rtas; - const struct phyp_dump_header *dump_header = NULL; - unsigned long dump_area_start; - unsigned long dump_area_length; - int header_len = 0; - int rc; - - /* If no memory was reserved in early boot, there is nothing to do */ - if (phyp_dump_info->init_reserve_size == 0) - return 0; - - /* Return if phyp dump not supported */ - if (!phyp_dump_info->phyp_dump_configured) - return -ENOSYS; - - /* Is there dump data waiting for us? If there isn't, - * then register a new dump area, and release all of - * the rest of the reserved ram. - * - * The /rtas/ibm,kernel-dump rtas node is present only - * if there is dump data waiting for us. - */ - rtas = of_find_node_by_path("/rtas"); - if (rtas) { - dump_header = of_get_property(rtas, "ibm,kernel-dump", - &header_len); - of_node_put(rtas); - } - - ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump"); - - print_dump_header(dump_header); - dump_area_length = init_dump_header(&phdr); - /* align down */ - dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK; - - if (dump_header == NULL) { - register_dump_area(&phdr, dump_area_start); - return 0; - } - - /* re-register the dump area, if old dump was invalid */ - if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { - invalidate_last_dump(&phdr, dump_area_start); - register_dump_area(&phdr, dump_area_start); - return 0; - } - - if (dump_header) { - phyp_dump_info->reserved_scratch_addr = - dump_header->cpu_data.destination_address; - phyp_dump_info->reserved_scratch_size = - dump_header->cpu_data.source_length + - dump_header->hpte_data.source_length + - dump_header->kernel_data.source_length; - } - - /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ - rc = sysfs_create_file(kernel_kobj, &rr.attr); - if (rc) - printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", - rc); - - /* ToDo: re-register the dump area, for next time. */ - return 0; -} -machine_subsys_initcall(pseries, phyp_dump_setup); - -int __init early_init_dt_scan_phyp_dump(unsigned long node, - const char *uname, int depth, void *data) -{ - const unsigned int *sizes; - - phyp_dump_info->phyp_dump_configured = 0; - phyp_dump_info->phyp_dump_is_active = 0; - - if (depth != 1 || strcmp(uname, "rtas") != 0) - return 0; - - if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL)) - phyp_dump_info->phyp_dump_configured++; - - if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL)) - phyp_dump_info->phyp_dump_is_active++; - - sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", - NULL); - if (!sizes) - return 0; - - if (sizes[0] == 1) - phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]); - - if (sizes[3] == 2) - phyp_dump_info->hpte_region_size = - *((unsigned long *)&sizes[4]); - return 1; -} - -/* Look for phyp_dump= cmdline option */ -static int __init early_phyp_dump_enabled(char *p) -{ - phyp_dump_info->phyp_dump_at_boot = 1; - - if (!p) - return 0; - - if (strncmp(p, "1", 1) == 0) - phyp_dump_info->phyp_dump_at_boot = 1; - else if (strncmp(p, "0", 1) == 0) - phyp_dump_info->phyp_dump_at_boot = 0; - - return 0; -} -early_param("phyp_dump", early_phyp_dump_enabled); - -/* Look for phyp_dump_reserve_size= cmdline option */ -static int __init early_phyp_dump_reserve_size(char *p) -{ - if (p) - phyp_dump_info->reserve_bootvar = memparse(p, &p); - - return 0; -} -early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size); diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 085fd3f45ad2..a12e95af6933 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -96,6 +96,20 @@ out: return index; } +static void check_and_cede_processor(void) +{ + /* + * Interrupts are soft-disabled at this point, + * but not hard disabled. So an interrupt might have + * occurred before entering NAP, and would be potentially + * lost (edge events, decrementer events, etc...) unless + * we first hard disable then check. + */ + hard_irq_disable(); + if (get_paca()->irq_happened == 0) + cede_processor(); +} + static int dedicated_cede_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -108,7 +122,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, ppc64_runlatch_off(); HMT_medium(); - cede_processor(); + check_and_cede_processor(); get_lppaca()->donate_dedicated_cpu = 0; dev->last_residency = @@ -132,7 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, * processor. When returning here, external interrupts * are enabled. */ - cede_processor(); + check_and_cede_processor(); dev->last_residency = (int)idle_loop_epilog(in_purr, kt_before); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f79f1278dfca..8f137af616af 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -190,9 +190,8 @@ static void __init pseries_mpic_init_IRQ(void) BUG_ON(openpic_addr == 0); /* Setup the openpic driver */ - mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0, - 16, 250, /* isu size, irq count */ - " MPIC "); + mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, + MPIC_NO_RESET, 16, 0, " MPIC "); BUG_ON(mpic == NULL); /* Add ISUs */ @@ -261,8 +260,12 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act switch (action) { case PSERIES_RECONFIG_ADD: pci = np->parent->data; - if (pci) + if (pci) { update_dn_pci_info(np, pci->phb); + + /* Create EEH device for the OF node */ + eeh_dev_init(np, pci->phb); + } break; default: err = NOTIFY_DONE; @@ -382,6 +385,7 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); + eeh_pseries_init(); find_and_init_phbs(); pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); eeh_init(); diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig index 57d22a2f4ba9..79d2225b7608 100644 --- a/arch/powerpc/platforms/wsp/Kconfig +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -25,6 +25,7 @@ config PPC_CHROMA bool "PowerEN PCIe Chroma Card" select EPAPR_BOOT select PPC_WSP + select OF_DYNAMIC default y endmenu diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index 19f353dfcd03..cb565bf93650 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -30,7 +30,7 @@ static int opb_index = 0; struct opb_pic { - struct irq_host *host; + struct irq_domain *host; void *regs; int index; spinlock_t lock; @@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = { .irq_set_type = opb_set_irq_type }; -static int opb_host_map(struct irq_host *host, unsigned int virq, +static int opb_host_map(struct irq_domain *host, unsigned int virq, irq_hw_number_t hwirq) { struct opb_pic *opb; @@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq, return 0; } -static int opb_host_xlate(struct irq_host *host, struct device_node *dn, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ - /* Interrupt size must == 2 */ - BUG_ON(intsize != 2); - *out_hwirq = intspec[0]; - *out_type = intspec[1]; - return 0; -} - -static struct irq_host_ops opb_host_ops = { +static const struct irq_domain_ops opb_host_ops = { .map = opb_host_map, - .xlate = opb_host_xlate, + .xlate = irq_domain_xlate_twocell, }; irqreturn_t opb_irq_handler(int irq, void *private) @@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn) goto free_opb; } - /* Allocate an irq host so that Linux knows that despite only + /* Allocate an irq domain so that Linux knows that despite only * having one interrupt to issue, we're the controller for multiple * hardware IRQs, so later we can lookup their virtual IRQs. */ - opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR, - OPB_NR_IRQS, &opb_host_ops, -1); - + opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb); if (!opb->host) { printk(KERN_ERR "opb: Failed to allocate IRQ host!\n"); goto free_regs; @@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn) opb->index = opb_index++; spin_lock_init(&opb->lock); - opb->host->host_data = opb; /* Disable all interrupts by default */ opb_out(opb, OPB_MLSASIER, 0); diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 7b4df37ac381..a84fecf63c4d 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -29,3 +29,7 @@ config SCOM_DEBUGFS bool "Expose SCOM controllers via debugfs" depends on PPC_SCOM default n + +config GE_FPGA + bool + default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5e37b4717864..1bd7ecb24620 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -4,6 +4,8 @@ ccflags-$(CONFIG_PPC64) := -mno-minimal-toc mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) +mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o +obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y) obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o @@ -65,3 +67,5 @@ obj-$(CONFIG_PPC_SCOM) += scom.o subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-$(CONFIG_PPC_XICS) += xics/ + +obj-$(CONFIG_GE_FPGA) += ge/ diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 5d7d59a43c4c..d4fa03f2b6ac 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -54,7 +54,7 @@ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ immap_t __iomem *mpc8xx_immr; static cpic8xx_t __iomem *cpic_reg; -static struct irq_host *cpm_pic_host; +static struct irq_domain *cpm_pic_host; static void cpm_mask_irq(struct irq_data *d) { @@ -98,7 +98,7 @@ int cpm_get_irq(void) return irq_linear_revmap(cpm_pic_host, cpm_vec); } -static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, +static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = { .name = "error", }; -static struct irq_host_ops cpm_pic_host_ops = { +static const struct irq_domain_ops cpm_pic_host_ops = { .map = cpm_pic_host_map, }; @@ -164,8 +164,7 @@ unsigned int cpm_pic_init(void) out_be32(&cpic_reg->cpic_cimr, 0); - cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - 64, &cpm_pic_host_ops, 64); + cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL); if (cpm_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); sirq = NO_IRQ; diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index bcab50e2a9eb..d3be961e2ae7 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -50,7 +50,7 @@ static intctl_cpm2_t __iomem *cpm2_intctl; -static struct irq_host *cpm2_pic_host; +static struct irq_domain *cpm2_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; @@ -214,7 +214,7 @@ unsigned int cpm2_get_irq(void) return irq_linear_revmap(cpm2_pic_host, irq); } -static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, +static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) -{ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops cpm2_pic_host_ops = { +static const struct irq_domain_ops cpm2_pic_host_ops = { .map = cpm2_pic_host_map, - .xlate = cpm2_pic_host_xlate, + .xlate = irq_domain_xlate_onetwocell, }; void cpm2_pic_init(struct device_node *node) @@ -275,8 +263,7 @@ void cpm2_pic_init(struct device_node *node) out_be32(&cpm2_intctl->ic_scprrl, 0x05309770); /* create a legacy host */ - cpm2_pic_host = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - 64, &cpm2_pic_host_ops, 64); + cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL); if (cpm2_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); return; diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index b6731e4a6646..6e0e1005227f 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -182,13 +182,13 @@ unsigned int ehv_pic_get_irq(void) return irq_linear_revmap(global_ehv_pic->irqhost, irq); } -static int ehv_pic_host_match(struct irq_host *h, struct device_node *node) +static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless ehv_pic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int ehv_pic_host_map(struct irq_host *h, unsigned int virq, +static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct ehv_pic *ehv_pic = h->host_data; @@ -217,7 +217,7 @@ static int ehv_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops ehv_pic_host_ops = { +static const struct irq_domain_ops ehv_pic_host_ops = { .match = ehv_pic_host_match, .map = ehv_pic_host_map, .xlate = ehv_pic_host_xlate, @@ -275,9 +275,8 @@ void __init ehv_pic_init(void) return; } - ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0); - + ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS, + &ehv_pic_host_ops, ehv_pic); if (!ehv_pic->irqhost) { of_node_put(np); kfree(ehv_pic); @@ -293,7 +292,6 @@ void __init ehv_pic_init(void) of_node_put(np2); } - ehv_pic->irqhost->host_data = ehv_pic; ehv_pic->hc_irq = ehv_pic_irq_chip; ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity; ehv_pic->coreint_flag = coreint_flag; diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 116415899176..37a69097e022 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -24,6 +24,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/of_platform.h> diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index 5f88797dce73..cedabd0f4bfe 100644 --- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c @@ -21,6 +21,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/of_platform.h> #include <asm/io.h> @@ -200,6 +201,9 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = { { .compatible = "fsl,p1022-l2-cache-controller", }, + { + .compatible = "fsl,mpc8548-l2-cache-controller", + }, {}, }; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index ecb5c1946d22..6e097de00e09 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -60,7 +60,7 @@ static struct irq_chip fsl_msi_chip = { .name = "FSL-MSI", }; -static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, +static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct fsl_msi *msi_data = h->host_data; @@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops fsl_msi_host_ops = { +static const struct irq_domain_ops fsl_msi_host_ops = { .map = fsl_msi_host_map, }; @@ -387,8 +387,8 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) } platform_set_drvdata(dev, msi); - msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, - NR_MSI_IRQS, &fsl_msi_host_ops, 0); + msi->irqhost = irq_domain_add_linear(dev->dev.of_node, + NR_MSI_IRQS, &fsl_msi_host_ops, msi); if (msi->irqhost == NULL) { dev_err(&dev->dev, "No memory for MSI irqhost\n"); @@ -410,6 +410,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) msi->msi_regs = ioremap(res.start, resource_size(&res)); if (!msi->msi_regs) { + err = -ENOMEM; dev_err(&dev->dev, "could not map node %s\n", dev->dev.of_node->full_name); goto error_out; @@ -420,8 +421,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) msi->feature = features->fsl_pic_ip; - msi->irqhost->host_data = msi; - /* * Remember the phandle, so that we can match with any PCI nodes * that have an "fsl,msi" property. diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index f6c646a52541..8225f8653f78 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -26,7 +26,7 @@ #define FSL_PIC_IP_VMPIC 0x00000003 struct fsl_msi { - struct irq_host *irqhost; + struct irq_domain *irqhost; unsigned long cascade_irq; diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index a4c4f4a932d8..5b6f556094dd 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -66,8 +66,8 @@ " li %0,%3\n" \ " b 2b\n" \ ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ + PPC_LONG_ALIGN "\n" \ + PPC_LONG "1b,3b\n" \ ".text" \ : "=r" (err), "=r" (x) \ : "b" (addr), "i" (-EFAULT), "0" (err)) diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c index 15485789e9db..14bd5221f28a 100644 --- a/arch/powerpc/sysdev/fsl_rmu.c +++ b/arch/powerpc/sysdev/fsl_rmu.c @@ -100,14 +100,8 @@ #define DOORBELL_DSR_TE 0x00000080 #define DOORBELL_DSR_QFI 0x00000010 #define DOORBELL_DSR_DIQI 0x00000001 -#define DOORBELL_TID_OFFSET 0x02 -#define DOORBELL_SID_OFFSET 0x04 -#define DOORBELL_INFO_OFFSET 0x06 #define DOORBELL_MESSAGE_SIZE 0x08 -#define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET)) -#define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET)) -#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) struct rio_msg_regs { u32 omr; @@ -193,6 +187,13 @@ struct fsl_rmu { int rxirq; }; +struct rio_dbell_msg { + u16 pad1; + u16 tid; + u16 sid; + u16 info; +}; + /** * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler * @irq: Linux interrupt number @@ -311,8 +312,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) /* XXX Need to check/dispatch until queue empty */ if (dsr & DOORBELL_DSR_DIQI) { - u32 dmsg = - (u32) fsl_dbell->dbell_ring.virt + + struct rio_dbell_msg *dmsg = + fsl_dbell->dbell_ring.virt + (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); struct rio_dbell *dbell; int found = 0; @@ -320,25 +321,25 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) pr_debug ("RIO: processing doorbell," " sid %2.2x tid %2.2x info %4.4x\n", - DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); + dmsg->sid, dmsg->tid, dmsg->info); for (i = 0; i < MAX_PORT_NUM; i++) { if (fsl_dbell->mport[i]) { list_for_each_entry(dbell, &fsl_dbell->mport[i]->dbells, node) { if ((dbell->res->start - <= DBELL_INF(dmsg)) + <= dmsg->info) && (dbell->res->end - >= DBELL_INF(dmsg))) { + >= dmsg->info)) { found = 1; break; } } if (found && dbell->dinb) { dbell->dinb(fsl_dbell->mport[i], - dbell->dev_id, DBELL_SID(dmsg), - DBELL_TID(dmsg), - DBELL_INF(dmsg)); + dbell->dev_id, dmsg->sid, + dmsg->tid, + dmsg->info); break; } } @@ -348,8 +349,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) pr_debug ("RIO: spurious doorbell," " sid %2.2x tid %2.2x info %4.4x\n", - DBELL_SID(dmsg), DBELL_TID(dmsg), - DBELL_INF(dmsg)); + dmsg->sid, dmsg->tid, + dmsg->info); } setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); @@ -657,7 +658,7 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, int ret = 0; pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ - "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len); + "%p len %8.8zx\n", rdev->destid, mbox, buffer, len); if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { ret = -EINVAL; goto out; @@ -972,7 +973,8 @@ out: void *fsl_get_inb_message(struct rio_mport *mport, int mbox) { struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); - u32 phys_buf, virt_buf; + u32 phys_buf; + void *virt_buf; void *buf = NULL; int buf_idx; @@ -982,7 +984,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) goto out2; - virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf + virt_buf = rmu->msg_rx_ring.virt + (phys_buf - rmu->msg_rx_ring.phys); buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; buf = rmu->msg_rx_ring.virt_buffer[buf_idx]; @@ -994,7 +996,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) } /* Copy max message size, caller is expected to allocate that big */ - memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); + memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE); /* Clear the available buffer */ rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile new file mode 100644 index 000000000000..8731ffcb79b9 --- /dev/null +++ b/arch/powerpc/sysdev/ge/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_GE_FPGA) += ge_pic.o diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c index 94594e58594c..2bcb78bb3a15 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/sysdev/ge/ge_pic.c @@ -22,7 +22,7 @@ #include <asm/prom.h> #include <asm/irq.h> -#include "gef_pic.h" +#include "ge_pic.h" #define DEBUG #undef DEBUG @@ -50,7 +50,7 @@ static DEFINE_RAW_SPINLOCK(gef_pic_lock); static void __iomem *gef_pic_irq_reg_base; -static struct irq_host *gef_pic_irq_host; +static struct irq_domain *gef_pic_irq_host; static int gef_pic_cascade_irq; /* @@ -153,7 +153,7 @@ static struct irq_chip gef_pic_chip = { /* When an interrupt is being configured, this call allows some flexibilty * in deciding which irq_chip structure is used */ -static int gef_pic_host_map(struct irq_host *h, unsigned int virq, +static int gef_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { /* All interrupts are LEVEL sensitive */ @@ -163,7 +163,7 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops gef_pic_host_ops = { +static const struct irq_domain_ops gef_pic_host_ops = { .map = gef_pic_host_map, .xlate = gef_pic_host_xlate, }; @@ -211,10 +211,9 @@ void __init gef_pic_init(struct device_node *np) return; } - /* Setup an irq_host structure */ - gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - GEF_PIC_NUM_IRQS, - &gef_pic_host_ops, NO_IRQ); + /* Setup an irq_domain structure */ + gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS, + &gef_pic_host_ops, NULL); if (gef_pic_irq_host == NULL) return; diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h index 6149916da3f4..6149916da3f4 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.h +++ b/arch/powerpc/sysdev/ge/ge_pic.h diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index d18bb27e4df9..997df6a7ab5d 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -25,7 +25,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff }; static DEFINE_RAW_SPINLOCK(i8259_lock); -static struct irq_host *i8259_host; +static struct irq_domain *i8259_host; /* * Acknowledge the IRQ using either the PCI host bridge's interrupt @@ -163,12 +163,12 @@ static struct resource pic_edgectrl_iores = { .flags = IORESOURCE_BUSY, }; -static int i8259_host_match(struct irq_host *h, struct device_node *node) +static int i8259_host_match(struct irq_domain *h, struct device_node *node) { return h->of_node == NULL || h->of_node == node; } -static int i8259_host_map(struct irq_host *h, unsigned int virq, +static int i8259_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("i8259_host_map(%d, 0x%lx)\n", virq, hw); @@ -185,7 +185,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, +static int i8259_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -205,13 +205,13 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops i8259_host_ops = { +static struct irq_domain_ops i8259_host_ops = { .match = i8259_host_match, .map = i8259_host_map, .xlate = i8259_host_xlate, }; -struct irq_host *i8259_get_host(void) +struct irq_domain *i8259_get_host(void) { return i8259_host; } @@ -263,8 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr) raw_spin_unlock_irqrestore(&i8259_lock, flags); /* create a legacy host */ - i8259_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY, - 0, &i8259_host_ops, 0); + i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL); if (i8259_host == NULL) { printk(KERN_ERR "i8259: failed to allocate irq host !\n"); return; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 95da897f05a7..b50f97811c25 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -672,13 +672,13 @@ static struct irq_chip ipic_edge_irq_chip = { .irq_set_type = ipic_set_irq_type, }; -static int ipic_host_match(struct irq_host *h, struct device_node *node) +static int ipic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless ipic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int ipic_host_map(struct irq_host *h, unsigned int virq, +static int ipic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct ipic *ipic = h->host_data; @@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) - -{ - /* interrupt sense values coming from the device tree equal either - * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change) - */ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops ipic_host_ops = { +static struct irq_domain_ops ipic_host_ops = { .match = ipic_host_match, .map = ipic_host_map, - .xlate = ipic_host_xlate, + .xlate = irq_domain_xlate_onetwocell, }; struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) @@ -728,9 +712,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) if (ipic == NULL) return NULL; - ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - NR_IPIC_INTS, - &ipic_host_ops, 0); + ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS, + &ipic_host_ops, ipic); if (ipic->irqhost == NULL) { kfree(ipic); return NULL; @@ -738,8 +721,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) ipic->regs = ioremap(res.start, resource_size(&res)); - ipic->irqhost->host_data = ipic; - /* init hw */ ipic_write(ipic->regs, IPIC_SICNR, 0x0); diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h index 9391c57b0c51..90031d1282e1 100644 --- a/arch/powerpc/sysdev/ipic.h +++ b/arch/powerpc/sysdev/ipic.h @@ -43,7 +43,7 @@ struct ipic { volatile u32 __iomem *regs; /* The remapper for this IPIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; }; struct ipic_info { diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 2ca0a85fcce9..d5f5416be310 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -17,7 +17,7 @@ extern int cpm_get_irq(struct pt_regs *regs); -static struct irq_host *mpc8xx_pic_host; +static struct irq_domain *mpc8xx_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; static sysconf8xx_t __iomem *siu_reg; @@ -110,7 +110,7 @@ unsigned int mpc8xx_get_irq(void) } -static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, +static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -121,7 +121,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, } -static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -142,7 +142,7 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, } -static struct irq_host_ops mpc8xx_pic_host_ops = { +static struct irq_domain_ops mpc8xx_pic_host_ops = { .map = mpc8xx_pic_host_map, .xlate = mpc8xx_pic_host_xlate, }; @@ -171,8 +171,7 @@ int mpc8xx_pic_init(void) goto out; } - mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - 64, &mpc8xx_pic_host_ops, 64); + mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL); if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret = -ENOMEM; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4e9ccb1015de..9ac71ebd2c40 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -873,7 +873,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", mpic, d->irq, src, flow_type); - if (src >= mpic->irq_count) + if (src >= mpic->num_sources) return -EINVAL; if (flow_type == IRQ_TYPE_NONE) @@ -909,7 +909,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", mpic, virq, src, vector); - if (src >= mpic->irq_count) + if (src >= mpic->num_sources) return; vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); @@ -926,7 +926,7 @@ void mpic_set_destination(unsigned int virq, unsigned int cpuid) DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", mpic, virq, src, cpuid); - if (src >= mpic->irq_count) + if (src >= mpic->num_sources) return; mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); @@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = { #endif /* CONFIG_MPIC_U3_HT_IRQS */ -static int mpic_host_match(struct irq_host *h, struct device_node *node) +static int mpic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless mpic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int mpic_host_map(struct irq_host *h, unsigned int virq, +static int mpic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct mpic *mpic = h->host_data; @@ -1006,7 +1006,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, return 0; } - if (hw >= mpic->irq_count) + if (hw >= mpic->num_sources) return -EINVAL; mpic_msi_reserve_hwirq(mpic, hw); @@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc) BUG_ON(!(mpic->flags & MPIC_SECONDARY)); virq = mpic_get_one_irq(mpic); - if (virq != NO_IRQ) + if (virq) generic_handle_irq(virq); chip->irq_eoi(&desc->irq_data); } -static struct irq_host_ops mpic_host_ops = { +static struct irq_domain_ops mpic_host_ops = { .match = mpic_host_match, .map = mpic_host_map, .xlate = mpic_host_xlate, @@ -1149,6 +1149,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, u32 greg_feature; const char *vers; const u32 *psrc; + u32 last_irq; /* Default MPIC search parameters */ static const struct of_device_id __initconst mpic_device_id[] = { @@ -1182,6 +1183,16 @@ struct mpic * __init mpic_alloc(struct device_node *node, } } + /* Read extra device-tree properties into the flags variable */ + if (of_get_property(node, "big-endian", NULL)) + flags |= MPIC_BIG_ENDIAN; + if (of_get_property(node, "pic-no-reset", NULL)) + flags |= MPIC_NO_RESET; + if (of_get_property(node, "single-cpu-affinity", NULL)) + flags |= MPIC_SINGLE_DEST_CPU; + if (of_device_is_compatible(node, "fsl,mpic")) + flags |= MPIC_FSL; + mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); if (mpic == NULL) goto err_of_node_put; @@ -1189,15 +1200,16 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->name = name; mpic->node = node; mpic->paddr = phys_addr; + mpic->flags = flags; mpic->hc_irq = mpic_irq_chip; mpic->hc_irq.name = name; - if (!(flags & MPIC_SECONDARY)) + if (!(mpic->flags & MPIC_SECONDARY)) mpic->hc_irq.irq_set_affinity = mpic_set_affinity; #ifdef CONFIG_MPIC_U3_HT_IRQS mpic->hc_ht_irq = mpic_irq_ht_chip; mpic->hc_ht_irq.name = name; - if (!(flags & MPIC_SECONDARY)) + if (!(mpic->flags & MPIC_SECONDARY)) mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; #endif /* CONFIG_MPIC_U3_HT_IRQS */ @@ -1209,12 +1221,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->hc_tm = mpic_tm_chip; mpic->hc_tm.name = name; - mpic->flags = flags; - mpic->isu_size = isu_size; - mpic->irq_count = irq_count; mpic->num_sources = 0; /* so far */ - if (flags & MPIC_LARGE_VECTORS) + if (mpic->flags & MPIC_LARGE_VECTORS) intvec_top = 2047; else intvec_top = 255; @@ -1233,12 +1242,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->ipi_vecs[3] = intvec_top - 1; mpic->spurious_vec = intvec_top; - /* Check for "big-endian" in device-tree */ - if (of_get_property(mpic->node, "big-endian", NULL) != NULL) - mpic->flags |= MPIC_BIG_ENDIAN; - if (of_device_is_compatible(mpic->node, "fsl,mpic")) - mpic->flags |= MPIC_FSL; - /* Look for protected sources */ psrc = of_get_property(mpic->node, "protected-sources", &psize); if (psrc) { @@ -1254,11 +1257,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, } #ifdef CONFIG_MPIC_WEIRD - mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; + mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)]; #endif /* default register type */ - if (flags & MPIC_BIG_ENDIAN) + if (mpic->flags & MPIC_BIG_ENDIAN) mpic->reg_type = mpic_access_mmio_be; else mpic->reg_type = mpic_access_mmio_le; @@ -1268,10 +1271,10 @@ struct mpic * __init mpic_alloc(struct device_node *node, * only if the kernel includes DCR support. */ #ifdef CONFIG_PPC_DCR - if (flags & MPIC_USES_DCR) + if (mpic->flags & MPIC_USES_DCR) mpic->reg_type = mpic_access_dcr; #else - BUG_ON(flags & MPIC_USES_DCR); + BUG_ON(mpic->flags & MPIC_USES_DCR); #endif /* Map the global registers */ @@ -1283,10 +1286,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* When using a device-node, reset requests are only honored if the MPIC * is allowed to reset. */ - if (of_get_property(mpic->node, "pic-no-reset", NULL)) - mpic->flags |= MPIC_NO_RESET; - - if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { + if (!(mpic->flags & MPIC_NO_RESET)) { printk(KERN_DEBUG "mpic: Resetting\n"); mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) @@ -1297,31 +1297,17 @@ struct mpic * __init mpic_alloc(struct device_node *node, } /* CoreInt */ - if (flags & MPIC_ENABLE_COREINT) + if (mpic->flags & MPIC_ENABLE_COREINT) mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_COREINT); - if (flags & MPIC_ENABLE_MCK) + if (mpic->flags & MPIC_ENABLE_MCK) mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_MCK); /* - * Read feature register. For non-ISU MPICs, num sources as well. On - * ISU MPICs, sources are counted as ISUs are added - */ - greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); - if (isu_size == 0) { - if (flags & MPIC_BROKEN_FRR_NIRQS) - mpic->num_sources = mpic->irq_count; - else - mpic->num_sources = - ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) - >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; - } - - /* * The MPIC driver will crash if there are more cores than we * can initialize, so we may as well catch that problem here. */ @@ -1336,19 +1322,42 @@ struct mpic * __init mpic_alloc(struct device_node *node, 0x1000); } + /* + * Read feature register. For non-ISU MPICs, num sources as well. On + * ISU MPICs, sources are counted as ISUs are added + */ + greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); + + /* + * By default, the last source number comes from the MPIC, but the + * device-tree and board support code can override it on buggy hw. + * If we get passed an isu_size (multi-isu MPIC) then we use that + * as a default instead of the value read from the HW. + */ + last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) + >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT; + if (isu_size) + last_irq = isu_size * MPIC_MAX_ISU - 1; + of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq); + if (irq_count) + last_irq = irq_count - 1; + /* Initialize main ISU if none provided */ - if (mpic->isu_size == 0) { - mpic->isu_size = mpic->num_sources; + if (!isu_size) { + isu_size = last_irq + 1; + mpic->num_sources = isu_size; mpic_map(mpic, mpic->paddr, &mpic->isus[0], - MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); + MPIC_INFO(IRQ_BASE), + MPIC_INFO(IRQ_STRIDE) * isu_size); } + + mpic->isu_size = isu_size; mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); mpic->isu_mask = (1 << mpic->isu_shift) - 1; - mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR, - isu_size ? isu_size : mpic->num_sources, - &mpic_host_ops, - flags & MPIC_LARGE_VECTORS ? 2048 : 256); + mpic->irqhost = irq_domain_add_linear(mpic->node, + last_irq + 1, + &mpic_host_ops, mpic); /* * FIXME: The code leaks the MPIC object and mappings here; this @@ -1357,8 +1366,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, if (mpic->irqhost == NULL) return NULL; - mpic->irqhost->host_data = mpic; - /* Display version */ switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { case 1: @@ -1383,7 +1390,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->next = mpics; mpics = mpic; - if (!(flags & MPIC_SECONDARY)) { + if (!(mpic->flags & MPIC_SECONDARY)) { mpic_primary = mpic; irq_set_default_host(mpic->irqhost); } @@ -1450,10 +1457,6 @@ void __init mpic_init(struct mpic *mpic) (mpic->ipi_vecs[0] + i)); } - /* Initialize interrupt sources */ - if (mpic->irq_count == 0) - mpic->irq_count = mpic->num_sources; - /* Do the HT PIC fixups on U3 broken mpic */ DBG("MPIC flags: %x\n", mpic->flags); if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c new file mode 100644 index 000000000000..6e7fa386e76a --- /dev/null +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -0,0 +1,282 @@ +/* + * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. + * + * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and + * Mingkai Hu from Freescale Semiconductor, Inc. + * + * 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; version 2 of the + * License. + * + */ + +#include <linux/list.h> +#include <linux/of_platform.h> +#include <linux/errno.h> +#include <asm/prom.h> +#include <asm/hw_irq.h> +#include <asm/ppc-pci.h> +#include <asm/mpic_msgr.h> + +#define MPIC_MSGR_REGISTERS_PER_BLOCK 4 +#define MPIC_MSGR_STRIDE 0x10 +#define MPIC_MSGR_MER_OFFSET 0x100 +#define MSGR_INUSE 0 +#define MSGR_FREE 1 + +static struct mpic_msgr **mpic_msgrs; +static unsigned int mpic_msgr_count; + +static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value) +{ + out_be32(msgr->mer, value); +} + +static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr) +{ + return in_be32(msgr->mer); +} + +static inline void _mpic_msgr_disable(struct mpic_msgr *msgr) +{ + u32 mer = _mpic_msgr_mer_read(msgr); + + _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num)); +} + +struct mpic_msgr *mpic_msgr_get(unsigned int reg_num) +{ + unsigned long flags; + struct mpic_msgr *msgr; + + /* Assume busy until proven otherwise. */ + msgr = ERR_PTR(-EBUSY); + + if (reg_num >= mpic_msgr_count) + return ERR_PTR(-ENODEV); + + raw_spin_lock_irqsave(&msgr->lock, flags); + if (mpic_msgrs[reg_num]->in_use == MSGR_FREE) { + msgr = mpic_msgrs[reg_num]; + msgr->in_use = MSGR_INUSE; + } + raw_spin_unlock_irqrestore(&msgr->lock, flags); + + return msgr; +} +EXPORT_SYMBOL_GPL(mpic_msgr_get); + +void mpic_msgr_put(struct mpic_msgr *msgr) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&msgr->lock, flags); + msgr->in_use = MSGR_FREE; + _mpic_msgr_disable(msgr); + raw_spin_unlock_irqrestore(&msgr->lock, flags); +} +EXPORT_SYMBOL_GPL(mpic_msgr_put); + +void mpic_msgr_enable(struct mpic_msgr *msgr) +{ + unsigned long flags; + u32 mer; + + raw_spin_lock_irqsave(&msgr->lock, flags); + mer = _mpic_msgr_mer_read(msgr); + _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num)); + raw_spin_unlock_irqrestore(&msgr->lock, flags); +} +EXPORT_SYMBOL_GPL(mpic_msgr_enable); + +void mpic_msgr_disable(struct mpic_msgr *msgr) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&msgr->lock, flags); + _mpic_msgr_disable(msgr); + raw_spin_unlock_irqrestore(&msgr->lock, flags); +} +EXPORT_SYMBOL_GPL(mpic_msgr_disable); + +/* The following three functions are used to compute the order and number of + * the message register blocks. They are clearly very inefficent. However, + * they are called *only* a few times during device initialization. + */ +static unsigned int mpic_msgr_number_of_blocks(void) +{ + unsigned int count; + struct device_node *aliases; + + count = 0; + aliases = of_find_node_by_name(NULL, "aliases"); + + if (aliases) { + char buf[32]; + + for (;;) { + snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count); + if (!of_find_property(aliases, buf, NULL)) + break; + + count += 1; + } + } + + return count; +} + +static unsigned int mpic_msgr_number_of_registers(void) +{ + return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK; +} + +static int mpic_msgr_block_number(struct device_node *node) +{ + struct device_node *aliases; + unsigned int index, number_of_blocks; + char buf[64]; + + number_of_blocks = mpic_msgr_number_of_blocks(); + aliases = of_find_node_by_name(NULL, "aliases"); + if (!aliases) + return -1; + + for (index = 0; index < number_of_blocks; ++index) { + struct property *prop; + + snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index); + prop = of_find_property(aliases, buf, NULL); + if (node == of_find_node_by_path(prop->value)) + break; + } + + return index == number_of_blocks ? -1 : index; +} + +/* The probe function for a single message register block. + */ +static __devinit int mpic_msgr_probe(struct platform_device *dev) +{ + void __iomem *msgr_block_addr; + int block_number; + struct resource rsrc; + unsigned int i; + unsigned int irq_index; + struct device_node *np = dev->dev.of_node; + unsigned int receive_mask; + const unsigned int *prop; + + if (!np) { + dev_err(&dev->dev, "Device OF-Node is NULL"); + return -EFAULT; + } + + /* Allocate the message register array upon the first device + * registered. + */ + if (!mpic_msgrs) { + mpic_msgr_count = mpic_msgr_number_of_registers(); + dev_info(&dev->dev, "Found %d message registers\n", + mpic_msgr_count); + + mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count, + GFP_KERNEL); + if (!mpic_msgrs) { + dev_err(&dev->dev, + "No memory for message register blocks\n"); + return -ENOMEM; + } + } + dev_info(&dev->dev, "Of-device full name %s\n", np->full_name); + + /* IO map the message register block. */ + of_address_to_resource(np, 0, &rsrc); + msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); + if (!msgr_block_addr) { + dev_err(&dev->dev, "Failed to iomap MPIC message registers"); + return -EFAULT; + } + + /* Ensure the block has a defined order. */ + block_number = mpic_msgr_block_number(np); + if (block_number < 0) { + dev_err(&dev->dev, + "Failed to find message register block alias\n"); + return -ENODEV; + } + dev_info(&dev->dev, "Setting up message register block %d\n", + block_number); + + /* Grab the receive mask which specifies what registers can receive + * interrupts. + */ + prop = of_get_property(np, "mpic-msgr-receive-mask", NULL); + receive_mask = (prop) ? *prop : 0xF; + + /* Build up the appropriate message register data structures. */ + for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) { + struct mpic_msgr *msgr; + unsigned int reg_number; + + msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL); + if (!msgr) { + dev_err(&dev->dev, "No memory for message register\n"); + return -ENOMEM; + } + + reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i; + msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE; + msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET; + msgr->in_use = MSGR_FREE; + msgr->num = i; + raw_spin_lock_init(&msgr->lock); + + if (receive_mask & (1 << i)) { + struct resource irq; + + if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) { + dev_err(&dev->dev, + "Missing interrupt specifier"); + kfree(msgr); + return -EFAULT; + } + msgr->irq = irq.start; + irq_index += 1; + } else { + msgr->irq = NO_IRQ; + } + + mpic_msgrs[reg_number] = msgr; + mpic_msgr_disable(msgr); + dev_info(&dev->dev, "Register %d initialized: irq %d\n", + reg_number, msgr->irq); + + } + + return 0; +} + +static const struct of_device_id mpic_msgr_ids[] = { + { + .compatible = "fsl,mpic-v3.1-msgr", + .data = NULL, + }, + {} +}; + +static struct platform_driver mpic_msgr_driver = { + .driver = { + .name = "mpic-msgr", + .owner = THIS_MODULE, + .of_match_table = mpic_msgr_ids, + }, + .probe = mpic_msgr_probe, +}; + +static __init int mpic_msgr_init(void) +{ + return platform_driver_register(&mpic_msgr_driver); +} +subsys_initcall(mpic_msgr_init); diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 0f67cd79d481..bbf342c88314 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -32,7 +32,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { irq_hw_number_t hwirq; - struct irq_host_ops *ops = mpic->irqhost->ops; + const struct irq_domain_ops *ops = mpic->irqhost->ops; struct device_node *np; int flags, index, i; struct of_irq oirq; @@ -54,7 +54,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) for (i = 100; i < 105; i++) msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); - for (i = 124; i < mpic->irq_count; i++) + for (i = 124; i < mpic->num_sources; i++) msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); @@ -83,7 +83,7 @@ int mpic_msi_init_allocator(struct mpic *mpic) { int rc; - rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count, + rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources, mpic->irqhost->of_node); if (rc) return rc; diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 14d130268e7a..8848e99a83f2 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -70,7 +70,7 @@ static u32 mv64x60_cached_low_mask; static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS; static u32 mv64x60_cached_gpp_mask; -static struct irq_host *mv64x60_irq_host; +static struct irq_domain *mv64x60_irq_host; /* * mv64x60_chip_low functions @@ -208,7 +208,7 @@ static struct irq_chip *mv64x60_chips[] = { [MV64x60_LEVEL1_GPP] = &mv64x60_chip_gpp, }; -static int mv64x60_host_map(struct irq_host *h, unsigned int virq, +static int mv64x60_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { int level1; @@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops mv64x60_host_ops = { +static struct irq_domain_ops mv64x60_host_ops = { .map = mv64x60_host_map, }; @@ -250,9 +250,8 @@ void __init mv64x60_init_irq(void) paddr = of_translate_address(np, reg); mv64x60_irq_reg_base = ioremap(paddr, reg[1]); - mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - MV64x60_NUM_IRQS, - &mv64x60_host_ops, MV64x60_NUM_IRQS); + mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS, + &mv64x60_host_ops, NULL); spin_lock_irqsave(&mv64x60_lock, flags); out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK, diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 4f05f7542346..56e8b3c3c890 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1050,6 +1050,74 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = .check_link = ppc4xx_pciex_check_link_sdr, }; +static int __init apm821xx_pciex_core_init(struct device_node *np) +{ + /* Return the number of pcie port */ + return 1; +} + +static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) +{ + u32 val; + + /* + * Do a software reset on PCIe ports. + * This code is to fix the issue that pci drivers doesn't re-assign + * bus number for PCIE devices after Uboot + * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 + * PT quad port, SAS LSI 1064E) + */ + + mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0); + mdelay(10); + + if (port->endpoint) + val = PTYPE_LEGACY_ENDPOINT << 20; + else + val = PTYPE_ROOT_PORT << 20; + + val |= LNKW_X1 << 12; + + mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); + mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); + mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); + + mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); + mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); + mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); + + mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000); + mdelay(50); + mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000); + + mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, + mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | + (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN)); + + /* Poll for PHY reset */ + val = PESDR0_460EX_RSTSTA - port->sdr_base; + if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) { + printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__); + return -EBUSY; + } else { + mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, + (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) & + ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) | + PESDRx_RCSSET_RSTPYN); + + port->has_ibpre = 1; + return 0; + } +} + +static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = { + .want_sdr = true, + .core_init = apm821xx_pciex_core_init, + .port_init_hw = apm821xx_pciex_init_port_hw, + .setup_utl = ppc460ex_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, +}; + static int __init ppc460sx_pciex_core_init(struct device_node *np) { /* HSS drive amplitude */ @@ -1362,6 +1430,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; if (of_device_is_compatible(np, "ibm,plb-pciex-460sx")) ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; + if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx")) + ppc4xx_pciex_hwops = &apm821xx_pcie_hwops; #endif /* CONFIG_44x */ #ifdef CONFIG_40x if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 73034bd203c4..2fba6ef2f95e 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -245,13 +245,13 @@ static struct irq_chip qe_ic_irq_chip = { .irq_mask_ack = qe_ic_mask_irq, }; -static int qe_ic_host_match(struct irq_host *h, struct device_node *node) +static int qe_ic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless qe_ic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int qe_ic_host_map(struct irq_host *h, unsigned int virq, +static int qe_ic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct qe_ic *qe_ic = h->host_data; @@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 * intspec, unsigned int intsize, - irq_hw_number_t * out_hwirq, - unsigned int *out_flags) -{ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops qe_ic_host_ops = { +static struct irq_domain_ops qe_ic_host_ops = { .match = qe_ic_host_match, .map = qe_ic_host_map, - .xlate = qe_ic_host_xlate, + .xlate = irq_domain_xlate_onetwocell, }; /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ @@ -339,8 +326,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, if (qe_ic == NULL) return; - qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - NR_QE_IC_INTS, &qe_ic_host_ops, 0); + qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, + &qe_ic_host_ops, qe_ic); if (qe_ic->irqhost == NULL) { kfree(qe_ic); return; @@ -348,7 +335,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, qe_ic->regs = ioremap(res.start, resource_size(&res)); - qe_ic->irqhost->host_data = qe_ic; qe_ic->hc_irq = qe_ic_irq_chip; qe_ic->virq_high = irq_of_parse_and_map(node, 0); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h index c1361d005a8a..c327872ed35c 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.h +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h @@ -79,7 +79,7 @@ struct qe_ic { volatile u32 __iomem *regs; /* The remapper for this QEIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; /* The "linux" controller struct */ struct irq_chip hc_irq; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 4d18658116e5..188012c58f7f 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -51,7 +51,7 @@ u32 tsi108_pci_cfg_base; static u32 tsi108_pci_cfg_phys; u32 tsi108_csr_vir_base; -static struct irq_host *pci_irq_host; +static struct irq_domain *pci_irq_host; extern u32 get_vir_csrbase(void); extern u32 tsi108_read_reg(u32 reg_offset); @@ -376,7 +376,7 @@ static struct irq_chip tsi108_pci_irq = { .irq_unmask = tsi108_pci_irq_unmask, }; -static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, +static int pci_irq_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -385,7 +385,7 @@ static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static int pci_irq_host_map(struct irq_host *h, unsigned int virq, +static int pci_irq_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { unsigned int irq; DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); @@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops pci_irq_host_ops = { +static struct irq_domain_ops pci_irq_domain_ops = { .map = pci_irq_host_map, .xlate = pci_irq_host_xlate, }; @@ -419,10 +419,9 @@ void __init tsi108_pci_int_init(struct device_node *node) { DBG("Tsi108_pci_int_init: initializing PCI interrupts\n"); - pci_irq_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY, - 0, &pci_irq_host_ops, 0); + pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL); if (pci_irq_host == NULL) { - printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n"); + printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n"); return; } diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 063c901b1265..92033936a8f7 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -49,7 +49,7 @@ struct uic { raw_spinlock_t lock; /* The remapper for this UIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; }; static void uic_unmask_irq(struct irq_data *d) @@ -174,7 +174,7 @@ static struct irq_chip uic_irq_chip = { .irq_set_type = uic_set_irq_type, }; -static int uic_host_map(struct irq_host *h, unsigned int virq, +static int uic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct uic *uic = h->host_data; @@ -190,21 +190,9 @@ static int uic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int uic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ - /* UIC intspecs must have 2 cells */ - BUG_ON(intsize != 2); - *out_hwirq = intspec[0]; - *out_type = intspec[1]; - return 0; -} - -static struct irq_host_ops uic_host_ops = { +static struct irq_domain_ops uic_host_ops = { .map = uic_host_map, - .xlate = uic_host_xlate, + .xlate = irq_domain_xlate_twocell, }; void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) @@ -270,13 +258,11 @@ static struct uic * __init uic_init_one(struct device_node *node) } uic->dcrbase = *dcrreg; - uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - NR_UIC_INTS, &uic_host_ops, -1); + uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops, + uic); if (! uic->irqhost) return NULL; /* FIXME: panic? */ - uic->irqhost->host_data = uic; - /* Start with all interrupts disabled, level and non-critical */ mtdcr(uic->dcrbase + UIC_ER, 0); mtdcr(uic->dcrbase + UIC_CR, 0); diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index d72eda6a4c05..ea5e204e3450 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -40,7 +40,7 @@ unsigned int xics_interrupt_server_size = 8; DEFINE_PER_CPU(struct xics_cppr, xics_cppr); -struct irq_host *xics_host; +struct irq_domain *xics_host; static LIST_HEAD(ics_list); @@ -212,16 +212,16 @@ void xics_migrate_irqs_away(void) /* We can't set affinity on ISA interrupts */ if (virq < NUM_ISA_INTERRUPTS) continue; - if (!virq_is_host(virq, xics_host)) - continue; - irq = (unsigned int)virq_to_hw(virq); - /* We need to get IPIs still. */ - if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) - continue; desc = irq_to_desc(virq); /* We only need to migrate enabled IRQS */ if (!desc || !desc->action) continue; + if (desc->irq_data.domain != xics_host) + continue; + irq = desc->irq_data.hwirq; + /* We need to get IPIs still. */ + if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) + continue; chip = irq_desc_get_chip(desc); if (!chip || !chip->irq_set_affinity) continue; @@ -301,7 +301,7 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, } #endif /* CONFIG_SMP */ -static int xics_host_match(struct irq_host *h, struct device_node *node) +static int xics_host_match(struct irq_domain *h, struct device_node *node) { struct ics *ics; @@ -323,7 +323,7 @@ static struct irq_chip xics_ipi_chip = { .irq_unmask = xics_ipi_unmask, }; -static int xics_host_map(struct irq_host *h, unsigned int virq, +static int xics_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct ics *ics; @@ -351,7 +351,7 @@ static int xics_host_map(struct irq_host *h, unsigned int virq, return -EINVAL; } -static int xics_host_xlate(struct irq_host *h, struct device_node *ct, +static int xics_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -366,7 +366,7 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops xics_host_ops = { +static struct irq_domain_ops xics_host_ops = { .match = xics_host_match, .map = xics_host_map, .xlate = xics_host_xlate, @@ -374,8 +374,7 @@ static struct irq_host_ops xics_host_ops = { static void __init xics_init_host(void) { - xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, - XICS_IRQ_SPURIOUS); + xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL); BUG_ON(xics_host == NULL); irq_set_default_host(xics_host); } diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 6183799754af..8d73c3c0bee6 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -40,7 +40,7 @@ #define XINTC_IVR 24 /* Interrupt Vector */ #define XINTC_MER 28 /* Master Enable */ -static struct irq_host *master_irqhost; +static struct irq_domain *master_irqhost; #define XILINX_INTC_MAXIRQS (32) @@ -141,7 +141,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = { /** * xilinx_intc_xlate - translate virq# from device tree interrupts property */ -static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, +static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -161,7 +161,7 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static int xilinx_intc_map(struct irq_host *h, unsigned int virq, +static int xilinx_intc_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t irq) { irq_set_chip_data(virq, h->host_data); @@ -177,15 +177,15 @@ static int xilinx_intc_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops xilinx_intc_ops = { +static struct irq_domain_ops xilinx_intc_ops = { .map = xilinx_intc_map, .xlate = xilinx_intc_xlate, }; -struct irq_host * __init +struct irq_domain * __init xilinx_intc_init(struct device_node *np) { - struct irq_host * irq; + struct irq_domain * irq; void * regs; /* Find and map the intc registers */ @@ -200,12 +200,11 @@ xilinx_intc_init(struct device_node *np) out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */ out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ - /* Allocate and initialize an irq_host structure. */ - irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS, - &xilinx_intc_ops, -1); + /* Allocate and initialize an irq_domain structure. */ + irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops, + regs); if (!irq) panic(__FILE__ ": Cannot allocate IRQ host\n"); - irq->host_data = regs; return irq; } diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index cb95eea74d3d..68a9cbbab450 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -39,7 +39,6 @@ #include <asm/irq_regs.h> #include <asm/spu.h> #include <asm/spu_priv1.h> -#include <asm/firmware.h> #include <asm/setjmp.h> #include <asm/reg.h> @@ -1437,7 +1436,8 @@ static void excprint(struct pt_regs *fp) printf(" current = 0x%lx\n", current); #ifdef CONFIG_PPC64 - printf(" paca = 0x%lx\n", get_paca()); + printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n", + local_paca, local_paca->soft_enabled, local_paca->irq_happened); #endif if (current) { printf(" pid = %ld, comm = %s\n", @@ -1634,25 +1634,6 @@ static void super_regs(void) mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) { - struct paca_struct *ptrPaca; - struct lppaca *ptrLpPaca; - - /* Dump out relevant Paca data areas. */ - printf("Paca: \n"); - ptrPaca = get_paca(); - - printf(" Local Processor Control Area (LpPaca): \n"); - ptrLpPaca = ptrPaca->lppaca_ptr; - printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", - ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); - printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", - ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); - printf(" Saved Gpr5=%.16lx \n", - ptrLpPaca->gpr5_dword.saved_gpr5); - } -#endif return; } @@ -2644,7 +2625,7 @@ static void dump_slb(void) static void dump_stab(void) { int i; - unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; + unsigned long *tmp = (unsigned long *)local_paca->stab_addr; printf("Segment table contents of cpu %x\n", smp_processor_id()); @@ -2855,10 +2836,6 @@ static void dump_tlb_book3e(void) static void xmon_init(int enable) { -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return; -#endif if (enable) { __debugger = xmon; __debugger_ipi = xmon_ipi; @@ -2895,10 +2872,6 @@ static struct sysrq_key_op sysrq_xmon_op = { static int __init setup_xmon_sysrq(void) { -#ifdef CONFIG_PPC_ISERIES - if (firmware_has_feature(FW_FEATURE_ISERIES)) - return 0; -#endif register_sysrq_key('x', &sysrq_xmon_op); return 0; } diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 8a2a887478cc..6a2cb560e968 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -293,11 +293,9 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - sb->s_root = root_dentry = d_alloc_root(root_inode); - if (!root_dentry) { - iput(root_inode); + sb->s_root = root_dentry = d_make_root(root_inode); + if (!root_dentry) return -ENOMEM; - } if (MACHINE_IS_VM) rc = hypfs_vm_create_files(sb, root_dentry); else diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index c23c3900c304..24ef186a1c4f 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -170,24 +170,17 @@ struct s390_idle_data { unsigned int sequence; unsigned long long idle_count; unsigned long long idle_enter; + unsigned long long idle_exit; unsigned long long idle_time; int nohz_delay; }; DECLARE_PER_CPU(struct s390_idle_data, s390_idle); -void vtime_start_cpu(__u64 int_clock, __u64 enter_timer); cputime64_t s390_get_idle_time(int cpu); #define arch_idle_time(cpu) s390_get_idle_time(cpu) -static inline void s390_idle_check(struct pt_regs *regs, __u64 int_clock, - __u64 enter_timer) -{ - if (regs->psw.mask & PSW_MASK_WAIT) - vtime_start_cpu(int_clock, enter_timer); -} - static inline int s390_nohz_delay(int cpu) { return __get_cpu_var(s390_idle).nohz_delay != 0; diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h index 9d88db1f55d0..8a8245ed14d2 100644 --- a/arch/s390/include/asm/debug.h +++ b/arch/s390/include/asm/debug.h @@ -131,6 +131,7 @@ void debug_unregister(debug_info_t* id); void debug_set_level(debug_info_t* id, int new_level); +void debug_set_critical(void); void debug_stop_all(void); static inline debug_entry_t* diff --git a/arch/s390/include/asm/hardirq.h b/arch/s390/include/asm/hardirq.h index e4155d3eb2cb..510ba9ef4248 100644 --- a/arch/s390/include/asm/hardirq.h +++ b/arch/s390/include/asm/hardirq.h @@ -18,6 +18,7 @@ #define __ARCH_IRQ_STAT #define __ARCH_HAS_DO_SOFTIRQ +#define __ARCH_IRQ_EXIT_IRQS_DISABLED #define HARDIRQ_BITS 8 diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index 6940abfbe1d9..2bd6cb897b90 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h @@ -169,5 +169,6 @@ enum diag308_rc { extern int diag308(unsigned long subcode, void *addr); extern void diag308_reset(void); extern void store_status(void); +extern void lgr_info_log(void); #endif /* _ASM_S390_IPL_H */ diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index ba6d85f88d50..acee1806f61e 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h @@ -34,7 +34,12 @@ enum interruption_class { NR_IRQS, }; -typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long); +struct ext_code { + unsigned short subcode; + unsigned short code; +}; + +typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long); int register_external_interrupt(u16 code, ext_int_handler_t handler); int unregister_external_interrupt(u16 code, ext_int_handler_t handler); diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 707f2306725b..47853debb3b9 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 1999,2010 + * Copyright IBM Corp. 1999,2012 * Author(s): Hartmut Penner <hp@de.ibm.com>, * Martin Schwidefsky <schwidefsky@de.ibm.com>, * Denis Joseph Barrow, @@ -12,14 +12,6 @@ #include <asm/ptrace.h> #include <asm/cpu.h> -void restart_int_handler(void); -void ext_int_handler(void); -void system_call(void); -void pgm_check_handler(void); -void mcck_int_handler(void); -void io_int_handler(void); -void psw_restart_int_handler(void); - #ifdef CONFIG_32BIT #define LC_ORDER 0 @@ -56,7 +48,7 @@ struct _lowcore { psw_t mcck_new_psw; /* 0x0070 */ psw_t io_new_psw; /* 0x0078 */ __u32 ext_params; /* 0x0080 */ - __u16 cpu_addr; /* 0x0084 */ + __u16 ext_cpu_addr; /* 0x0084 */ __u16 ext_int_code; /* 0x0086 */ __u16 svc_ilc; /* 0x0088 */ __u16 svc_code; /* 0x008a */ @@ -117,32 +109,37 @@ struct _lowcore { __u64 steal_timer; /* 0x0288 */ __u64 last_update_timer; /* 0x0290 */ __u64 last_update_clock; /* 0x0298 */ + __u64 int_clock; /* 0x02a0 */ + __u64 mcck_clock; /* 0x02a8 */ + __u64 clock_comparator; /* 0x02b0 */ /* Current process. */ - __u32 current_task; /* 0x02a0 */ - __u32 thread_info; /* 0x02a4 */ - __u32 kernel_stack; /* 0x02a8 */ + __u32 current_task; /* 0x02b8 */ + __u32 thread_info; /* 0x02bc */ + __u32 kernel_stack; /* 0x02c0 */ + + /* Interrupt, panic and restart stack. */ + __u32 async_stack; /* 0x02c4 */ + __u32 panic_stack; /* 0x02c8 */ + __u32 restart_stack; /* 0x02cc */ - /* Interrupt and panic stack. */ - __u32 async_stack; /* 0x02ac */ - __u32 panic_stack; /* 0x02b0 */ + /* Restart function and parameter. */ + __u32 restart_fn; /* 0x02d0 */ + __u32 restart_data; /* 0x02d4 */ + __u32 restart_source; /* 0x02d8 */ /* Address space pointer. */ - __u32 kernel_asce; /* 0x02b4 */ - __u32 user_asce; /* 0x02b8 */ - __u32 current_pid; /* 0x02bc */ + __u32 kernel_asce; /* 0x02dc */ + __u32 user_asce; /* 0x02e0 */ + __u32 current_pid; /* 0x02e4 */ /* SMP info area */ - __u32 cpu_nr; /* 0x02c0 */ - __u32 softirq_pending; /* 0x02c4 */ - __u32 percpu_offset; /* 0x02c8 */ - __u32 ext_call_fast; /* 0x02cc */ - __u64 int_clock; /* 0x02d0 */ - __u64 mcck_clock; /* 0x02d8 */ - __u64 clock_comparator; /* 0x02e0 */ - __u32 machine_flags; /* 0x02e8 */ - __u32 ftrace_func; /* 0x02ec */ - __u8 pad_0x02f8[0x0300-0x02f0]; /* 0x02f0 */ + __u32 cpu_nr; /* 0x02e8 */ + __u32 softirq_pending; /* 0x02ec */ + __u32 percpu_offset; /* 0x02f0 */ + __u32 machine_flags; /* 0x02f4 */ + __u32 ftrace_func; /* 0x02f8 */ + __u8 pad_0x02fc[0x0300-0x02fc]; /* 0x02fc */ /* Interrupt response block */ __u8 irb[64]; /* 0x0300 */ @@ -157,7 +154,9 @@ struct _lowcore { __u32 ipib; /* 0x0e00 */ __u32 ipib_checksum; /* 0x0e04 */ __u32 vmcore_info; /* 0x0e08 */ - __u8 pad_0x0e0c[0x0f00-0x0e0c]; /* 0x0e0c */ + __u8 pad_0x0e0c[0x0e18-0x0e0c]; /* 0x0e0c */ + __u32 os_info; /* 0x0e18 */ + __u8 pad_0x0e1c[0x0f00-0x0e1c]; /* 0x0e1c */ /* Extended facility list */ __u64 stfle_fac_list[32]; /* 0x0f00 */ @@ -189,7 +188,7 @@ struct _lowcore { __u32 ipl_parmblock_ptr; /* 0x0014 */ __u8 pad_0x0018[0x0080-0x0018]; /* 0x0018 */ __u32 ext_params; /* 0x0080 */ - __u16 cpu_addr; /* 0x0084 */ + __u16 ext_cpu_addr; /* 0x0084 */ __u16 ext_int_code; /* 0x0086 */ __u16 svc_ilc; /* 0x0088 */ __u16 svc_code; /* 0x008a */ @@ -254,34 +253,39 @@ struct _lowcore { __u64 steal_timer; /* 0x02e0 */ __u64 last_update_timer; /* 0x02e8 */ __u64 last_update_clock; /* 0x02f0 */ + __u64 int_clock; /* 0x02f8 */ + __u64 mcck_clock; /* 0x0300 */ + __u64 clock_comparator; /* 0x0308 */ /* Current process. */ - __u64 current_task; /* 0x02f8 */ - __u64 thread_info; /* 0x0300 */ - __u64 kernel_stack; /* 0x0308 */ + __u64 current_task; /* 0x0310 */ + __u64 thread_info; /* 0x0318 */ + __u64 kernel_stack; /* 0x0320 */ + + /* Interrupt, panic and restart stack. */ + __u64 async_stack; /* 0x0328 */ + __u64 panic_stack; /* 0x0330 */ + __u64 restart_stack; /* 0x0338 */ - /* Interrupt and panic stack. */ - __u64 async_stack; /* 0x0310 */ - __u64 panic_stack; /* 0x0318 */ + /* Restart function and parameter. */ + __u64 restart_fn; /* 0x0340 */ + __u64 restart_data; /* 0x0348 */ + __u64 restart_source; /* 0x0350 */ /* Address space pointer. */ - __u64 kernel_asce; /* 0x0320 */ - __u64 user_asce; /* 0x0328 */ - __u64 current_pid; /* 0x0330 */ + __u64 kernel_asce; /* 0x0358 */ + __u64 user_asce; /* 0x0360 */ + __u64 current_pid; /* 0x0368 */ /* SMP info area */ - __u32 cpu_nr; /* 0x0338 */ - __u32 softirq_pending; /* 0x033c */ - __u64 percpu_offset; /* 0x0340 */ - __u64 ext_call_fast; /* 0x0348 */ - __u64 int_clock; /* 0x0350 */ - __u64 mcck_clock; /* 0x0358 */ - __u64 clock_comparator; /* 0x0360 */ - __u64 vdso_per_cpu_data; /* 0x0368 */ - __u64 machine_flags; /* 0x0370 */ - __u64 ftrace_func; /* 0x0378 */ - __u64 gmap; /* 0x0380 */ - __u8 pad_0x0388[0x0400-0x0388]; /* 0x0388 */ + __u32 cpu_nr; /* 0x0370 */ + __u32 softirq_pending; /* 0x0374 */ + __u64 percpu_offset; /* 0x0378 */ + __u64 vdso_per_cpu_data; /* 0x0380 */ + __u64 machine_flags; /* 0x0388 */ + __u64 ftrace_func; /* 0x0390 */ + __u64 gmap; /* 0x0398 */ + __u8 pad_0x03a0[0x0400-0x03a0]; /* 0x03a0 */ /* Interrupt response block. */ __u8 irb[64]; /* 0x0400 */ @@ -298,8 +302,15 @@ struct _lowcore { */ __u64 ipib; /* 0x0e00 */ __u32 ipib_checksum; /* 0x0e08 */ - __u64 vmcore_info; /* 0x0e0c */ - __u8 pad_0x0e14[0x0f00-0x0e14]; /* 0x0e14 */ + /* + * Because the vmcore_info pointer is not 8 byte aligned it never + * should not be accessed directly. For accessing the pointer, first + * copy it to a local pointer variable. + */ + __u8 vmcore_info[8]; /* 0x0e0c */ + __u8 pad_0x0e14[0x0e18-0x0e14]; /* 0x0e14 */ + __u64 os_info; /* 0x0e18 */ + __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ /* Extended facility list */ __u64 stfle_fac_list[32]; /* 0x0f00 */ diff --git a/arch/s390/include/asm/os_info.h b/arch/s390/include/asm/os_info.h new file mode 100644 index 000000000000..d07518af09ea --- /dev/null +++ b/arch/s390/include/asm/os_info.h @@ -0,0 +1,50 @@ +/* + * OS info memory interface + * + * Copyright IBM Corp. 2012 + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ +#ifndef _ASM_S390_OS_INFO_H +#define _ASM_S390_OS_INFO_H + +#define OS_INFO_VERSION_MAJOR 1 +#define OS_INFO_VERSION_MINOR 1 +#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */ + +#define OS_INFO_VMCOREINFO 0 +#define OS_INFO_REIPL_BLOCK 1 +#define OS_INFO_INIT_FN 2 + +struct os_info_entry { + u64 addr; + u64 size; + u32 csum; +} __packed; + +struct os_info { + u64 magic; + u32 csum; + u16 version_major; + u16 version_minor; + u64 crashkernel_addr; + u64 crashkernel_size; + struct os_info_entry entry[3]; + u8 reserved[4004]; +} __packed; + +void os_info_init(void); +void os_info_entry_add(int nr, void *ptr, u64 len); +void os_info_crashkernel_add(unsigned long base, unsigned long size); +u32 os_info_csum(struct os_info *os_info); + +#ifdef CONFIG_CRASH_DUMP +void *os_info_old_entry(int nr, unsigned long *size); +int copy_from_oldmem(void *dest, void *src, size_t count); +#else +static inline void *os_info_old_entry(int nr, unsigned long *size) +{ + return NULL; +} +#endif + +#endif /* _ASM_S390_OS_INFO_H */ diff --git a/arch/s390/include/asm/qeth.h b/arch/s390/include/asm/qeth.h index 90efda0b137d..2c7c898c03e4 100644 --- a/arch/s390/include/asm/qeth.h +++ b/arch/s390/include/asm/qeth.h @@ -20,6 +20,7 @@ #define SIOC_QETH_ARP_FLUSH_CACHE (SIOCDEVPRIVATE + 4) #define SIOC_QETH_ADP_SET_SNMP_CONTROL (SIOCDEVPRIVATE + 5) #define SIOC_QETH_GET_CARD_TYPE (SIOCDEVPRIVATE + 6) +#define SIOC_QETH_QUERY_OAT (SIOCDEVPRIVATE + 7) struct qeth_arp_cache_entry { __u8 macaddr[6]; @@ -107,4 +108,10 @@ struct qeth_arp_query_user_data { char *entries; } __attribute__((packed)); +struct qeth_query_oat_data { + __u32 command; + __u32 buffer_len; + __u32 response_len; + __u64 ptr; +}; #endif /* __ASM_S390_QETH_IOCTL_H__ */ diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h deleted file mode 100644 index 7040b8567cd0..000000000000 --- a/arch/s390/include/asm/sigp.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Routines and structures for signalling other processors. - * - * Copyright IBM Corp. 1999,2010 - * Author(s): Denis Joseph Barrow, - * Martin Schwidefsky <schwidefsky@de.ibm.com>, - * Heiko Carstens <heiko.carstens@de.ibm.com>, - */ - -#ifndef __ASM_SIGP_H -#define __ASM_SIGP_H - -#include <asm/system.h> - -/* Get real cpu address from logical cpu number. */ -extern unsigned short __cpu_logical_map[]; - -static inline int cpu_logical_map(int cpu) -{ -#ifdef CONFIG_SMP - return __cpu_logical_map[cpu]; -#else - return stap(); -#endif -} - -enum { - sigp_sense = 1, - sigp_external_call = 2, - sigp_emergency_signal = 3, - sigp_start = 4, - sigp_stop = 5, - sigp_restart = 6, - sigp_stop_and_store_status = 9, - sigp_initial_cpu_reset = 11, - sigp_cpu_reset = 12, - sigp_set_prefix = 13, - sigp_store_status_at_address = 14, - sigp_store_extended_status_at_address = 15, - sigp_set_architecture = 18, - sigp_conditional_emergency_signal = 19, - sigp_sense_running = 21, -}; - -enum { - sigp_order_code_accepted = 0, - sigp_status_stored = 1, - sigp_busy = 2, - sigp_not_operational = 3, -}; - -/* - * Definitions for external call. - */ -enum { - ec_schedule = 0, - ec_call_function, - ec_call_function_single, - ec_stop_cpu, -}; - -/* - * Signal processor. - */ -static inline int raw_sigp(u16 cpu, int order) -{ - register unsigned long reg1 asm ("1") = 0; - int ccode; - - asm volatile( - " sigp %1,%2,0(%3)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode) - : "d" (reg1), "d" (cpu), - "a" (order) : "cc" , "memory"); - return ccode; -} - -/* - * Signal processor with parameter. - */ -static inline int raw_sigp_p(u32 parameter, u16 cpu, int order) -{ - register unsigned int reg1 asm ("1") = parameter; - int ccode; - - asm volatile( - " sigp %1,%2,0(%3)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode) - : "d" (reg1), "d" (cpu), - "a" (order) : "cc" , "memory"); - return ccode; -} - -/* - * Signal processor with parameter and return status. - */ -static inline int raw_sigp_ps(u32 *status, u32 parm, u16 cpu, int order) -{ - register unsigned int reg1 asm ("1") = parm; - int ccode; - - asm volatile( - " sigp %1,%2,0(%3)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "+d" (reg1) - : "d" (cpu), "a" (order) - : "cc" , "memory"); - *status = reg1; - return ccode; -} - -static inline int sigp(int cpu, int order) -{ - return raw_sigp(cpu_logical_map(cpu), order); -} - -static inline int sigp_p(u32 parameter, int cpu, int order) -{ - return raw_sigp_p(parameter, cpu_logical_map(cpu), order); -} - -static inline int sigp_ps(u32 *status, u32 parm, int cpu, int order) -{ - return raw_sigp_ps(status, parm, cpu_logical_map(cpu), order); -} - -#endif /* __ASM_SIGP_H */ diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index c32e9123b40c..797f78729680 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 1999,2009 + * Copyright IBM Corp. 1999,2012 * Author(s): Denis Joseph Barrow, * Martin Schwidefsky <schwidefsky@de.ibm.com>, * Heiko Carstens <heiko.carstens@de.ibm.com>, @@ -10,71 +10,52 @@ #ifdef CONFIG_SMP #include <asm/system.h> -#include <asm/sigp.h> - -extern void machine_restart_smp(char *); -extern void machine_halt_smp(void); -extern void machine_power_off_smp(void); #define raw_smp_processor_id() (S390_lowcore.cpu_nr) -extern int __cpu_disable (void); -extern void __cpu_die (unsigned int cpu); -extern int __cpu_up (unsigned int cpu); - extern struct mutex smp_cpu_state_mutex; +extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; + +extern int __cpu_up(unsigned int cpu); extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); -extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; - -extern void smp_switch_to_ipl_cpu(void (*func)(void *), void *); -extern void smp_switch_to_cpu(void (*)(void *), void *, unsigned long sp, - int from, int to); -extern void smp_restart_with_online_cpu(void); -extern void smp_restart_cpu(void); +extern void smp_call_online_cpu(void (*func)(void *), void *); +extern void smp_call_ipl_cpu(void (*func)(void *), void *); -/* - * returns 1 if (virtual) cpu is scheduled - * returns 0 otherwise - */ -static inline int smp_vcpu_scheduled(int cpu) -{ - u32 status; - - switch (sigp_ps(&status, 0, cpu, sigp_sense_running)) { - case sigp_status_stored: - /* Check for running status */ - if (status & 0x400) - return 0; - break; - case sigp_not_operational: - return 0; - default: - break; - } - return 1; -} +extern int smp_find_processor_id(u16 address); +extern int smp_store_status(int cpu); +extern int smp_vcpu_scheduled(int cpu); +extern void smp_yield_cpu(int cpu); +extern void smp_yield(void); +extern void smp_stop_cpu(void); #else /* CONFIG_SMP */ -static inline void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) +static inline void smp_call_ipl_cpu(void (*func)(void *), void *data) { func(data); } -static inline void smp_restart_with_online_cpu(void) +static inline void smp_call_online_cpu(void (*func)(void *), void *data) { + func(data); } -#define smp_vcpu_scheduled (1) +static inline int smp_find_processor_id(int address) { return 0; } +static inline int smp_vcpu_scheduled(int cpu) { return 1; } +static inline void smp_yield_cpu(int cpu) { } +static inline void smp_yield(void) { } +static inline void smp_stop_cpu(void) { } #endif /* CONFIG_SMP */ #ifdef CONFIG_HOTPLUG_CPU extern int smp_rescan_cpus(void); extern void __noreturn cpu_die(void); +extern void __cpu_die(unsigned int cpu); +extern int __cpu_disable(void); #else static inline int smp_rescan_cpus(void) { return 0; } static inline void cpu_die(void) { } diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index 67b5c1b14b51..c91b720965c0 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -72,5 +72,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _ASM_SOCKET_H */ diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index d73cc6b60000..2e0bb7f0f9b2 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -7,8 +7,10 @@ #ifndef __ASM_SYSTEM_H #define __ASM_SYSTEM_H +#include <linux/preempt.h> #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/string.h> #include <asm/types.h> #include <asm/ptrace.h> #include <asm/setup.h> @@ -248,6 +250,38 @@ static inline int test_facility(unsigned long nr) return (*ptr & (0x80 >> (nr & 7))) != 0; } +/** + * stfle - Store facility list extended + * @stfle_fac_list: array where facility list can be stored + * @size: size of passed in array in double words + */ +static inline void stfle(u64 *stfle_fac_list, int size) +{ + unsigned long nr; + + preempt_disable(); + S390_lowcore.stfl_fac_list = 0; + asm volatile( + " .insn s,0xb2b10000,0(0)\n" /* stfl */ + "0:\n" + EX_TABLE(0b, 0b) + : "=m" (S390_lowcore.stfl_fac_list)); + nr = 4; /* bytes stored by stfl */ + memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4); + if (S390_lowcore.stfl_fac_list & 0x01000000) { + /* More facility bits available with stfle */ + register unsigned long reg0 asm("0") = size - 1; + + asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */ + : "+d" (reg0) + : "a" (stfle_fac_list) + : "memory", "cc"); + nr = (reg0 + 1) * 8; /* # bytes stored by stfle */ + } + memset((char *) stfle_fac_list + nr, 0, size * 8 - nr); + preempt_enable(); +} + static inline unsigned short stap(void) { unsigned short cpu_address; diff --git a/arch/s390/include/asm/timer.h b/arch/s390/include/asm/timer.h index 814243cafdfe..e63069ba39e3 100644 --- a/arch/s390/include/asm/timer.h +++ b/arch/s390/include/asm/timer.h @@ -33,8 +33,8 @@ struct vtimer_queue { spinlock_t lock; __u64 timer; /* last programmed timer */ __u64 elapsed; /* elapsed time of timer expire values */ - __u64 idle; /* temp var for idle */ - int do_spt; /* =1: reprogram cpu timer in idle */ + __u64 idle_enter; /* cpu timer on idle enter */ + __u64 idle_exit; /* cpu timer on idle exit */ }; extern void init_virt_timer(struct vtimer_list *timer); diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index 533f35751aeb..c4a11cfad3c8 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -40,8 +40,8 @@ struct vdso_per_cpu_data { extern struct vdso_data *vdso_data; #ifdef CONFIG_64BIT -int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore); -void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore); +int vdso_alloc_per_cpu(struct _lowcore *lowcore); +void vdso_free_per_cpu(struct _lowcore *lowcore); #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 7d9ec924e7e7..16b0b433f1f4 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ - sysinfo.o jump_label.o + sysinfo.o jump_label.o lgr.o os_info.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) @@ -34,8 +34,6 @@ extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o) obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCHED_BOOK) += topology.o -obj-$(CONFIG_SMP) += $(if $(CONFIG_64BIT),switch_cpu64.o, \ - switch_cpu.o) obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 6e6a72e66d60..ed8c913db79e 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -8,9 +8,11 @@ #include <linux/kbuild.h> #include <linux/sched.h> +#include <asm/cputime.h> +#include <asm/timer.h> #include <asm/vdso.h> -#include <asm/sigp.h> #include <asm/pgtable.h> +#include <asm/system.h> /* * Make sure that the compiler is new enough. We want a compiler that @@ -70,15 +72,15 @@ int main(void) DEFINE(__CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); BLANK(); - /* constants for SIGP */ - DEFINE(__SIGP_STOP, sigp_stop); - DEFINE(__SIGP_RESTART, sigp_restart); - DEFINE(__SIGP_SENSE, sigp_sense); - DEFINE(__SIGP_INITIAL_CPU_RESET, sigp_initial_cpu_reset); - BLANK(); + /* idle data offsets */ + DEFINE(__IDLE_ENTER, offsetof(struct s390_idle_data, idle_enter)); + DEFINE(__IDLE_EXIT, offsetof(struct s390_idle_data, idle_exit)); + /* vtimer queue offsets */ + DEFINE(__VQ_IDLE_ENTER, offsetof(struct vtimer_queue, idle_enter)); + DEFINE(__VQ_IDLE_EXIT, offsetof(struct vtimer_queue, idle_exit)); /* lowcore offsets */ DEFINE(__LC_EXT_PARAMS, offsetof(struct _lowcore, ext_params)); - DEFINE(__LC_CPU_ADDRESS, offsetof(struct _lowcore, cpu_addr)); + DEFINE(__LC_EXT_CPU_ADDR, offsetof(struct _lowcore, ext_cpu_addr)); DEFINE(__LC_EXT_INT_CODE, offsetof(struct _lowcore, ext_int_code)); DEFINE(__LC_SVC_ILC, offsetof(struct _lowcore, svc_ilc)); DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code)); @@ -95,20 +97,19 @@ int main(void) DEFINE(__LC_IO_INT_WORD, offsetof(struct _lowcore, io_int_word)); DEFINE(__LC_STFL_FAC_LIST, offsetof(struct _lowcore, stfl_fac_list)); DEFINE(__LC_MCCK_CODE, offsetof(struct _lowcore, mcck_interruption_code)); - DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); - BLANK(); - DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw)); DEFINE(__LC_RST_OLD_PSW, offsetof(struct _lowcore, restart_old_psw)); DEFINE(__LC_EXT_OLD_PSW, offsetof(struct _lowcore, external_old_psw)); DEFINE(__LC_SVC_OLD_PSW, offsetof(struct _lowcore, svc_old_psw)); DEFINE(__LC_PGM_OLD_PSW, offsetof(struct _lowcore, program_old_psw)); DEFINE(__LC_MCK_OLD_PSW, offsetof(struct _lowcore, mcck_old_psw)); DEFINE(__LC_IO_OLD_PSW, offsetof(struct _lowcore, io_old_psw)); + DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw)); DEFINE(__LC_EXT_NEW_PSW, offsetof(struct _lowcore, external_new_psw)); DEFINE(__LC_SVC_NEW_PSW, offsetof(struct _lowcore, svc_new_psw)); DEFINE(__LC_PGM_NEW_PSW, offsetof(struct _lowcore, program_new_psw)); DEFINE(__LC_MCK_NEW_PSW, offsetof(struct _lowcore, mcck_new_psw)); DEFINE(__LC_IO_NEW_PSW, offsetof(struct _lowcore, io_new_psw)); + BLANK(); DEFINE(__LC_SAVE_AREA_SYNC, offsetof(struct _lowcore, save_area_sync)); DEFINE(__LC_SAVE_AREA_ASYNC, offsetof(struct _lowcore, save_area_async)); DEFINE(__LC_SAVE_AREA_RESTART, offsetof(struct _lowcore, save_area_restart)); @@ -129,12 +130,16 @@ int main(void) DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack)); DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack)); DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); + DEFINE(__LC_RESTART_STACK, offsetof(struct _lowcore, restart_stack)); + DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn)); DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); + DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); + BLANK(); DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area)); DEFINE(__LC_PSW_SAVE_AREA, offsetof(struct _lowcore, psw_save_area)); diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 6fe78c2f95d9..53a82c8d50e9 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -581,7 +581,6 @@ give_sigsegv: int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t blocked; int ret; /* Set up the stack frame */ @@ -591,10 +590,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, ret = setup_frame32(sig, ka, oldset, regs); if (ret) return ret; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, sig); - set_current_blocked(&blocked); + block_sigmask(ka, sig); return 0; } diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index c383ce440d99..cc1172b26873 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -14,6 +14,7 @@ #include <linux/bootmem.h> #include <linux/elf.h> #include <asm/ipl.h> +#include <asm/os_info.h> #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) @@ -51,7 +52,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, /* * Copy memory from old kernel */ -static int copy_from_oldmem(void *dest, void *src, size_t count) +int copy_from_oldmem(void *dest, void *src, size_t count) { unsigned long copied = 0; int rc; @@ -224,28 +225,44 @@ static void *nt_prpsinfo(void *ptr) } /* - * Initialize vmcoreinfo note (new kernel) + * Get vmcoreinfo using lowcore->vmcore_info (new kernel) */ -static void *nt_vmcoreinfo(void *ptr) +static void *get_vmcoreinfo_old(unsigned long *size) { char nt_name[11], *vmcoreinfo; Elf64_Nhdr note; void *addr; if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) - return ptr; + return NULL; memset(nt_name, 0, sizeof(nt_name)); if (copy_from_oldmem(¬e, addr, sizeof(note))) - return ptr; + return NULL; if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) - return ptr; + return NULL; if (strcmp(nt_name, "VMCOREINFO") != 0) - return ptr; - vmcoreinfo = kzalloc_panic(note.n_descsz + 1); + return NULL; + vmcoreinfo = kzalloc_panic(note.n_descsz); if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) + return NULL; + *size = note.n_descsz; + return vmcoreinfo; +} + +/* + * Initialize vmcoreinfo note (new kernel) + */ +static void *nt_vmcoreinfo(void *ptr) +{ + unsigned long size; + void *vmcoreinfo; + + vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size); + if (!vmcoreinfo) + vmcoreinfo = get_vmcoreinfo_old(&size); + if (!vmcoreinfo) return ptr; - vmcoreinfo[note.n_descsz + 1] = 0; - return nt_init(ptr, 0, vmcoreinfo, note.n_descsz, "VMCOREINFO"); + return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO"); } /* diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 6848828b962e..19e5e9eba546 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -2,8 +2,8 @@ * arch/s390/kernel/debug.c * S/390 debug facility * - * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, - * IBM Corporation + * Copyright IBM Corp. 1999, 2012 + * * Author(s): Michael Holzheu (holzheu@de.ibm.com), * Holger Smolinski (Holger.Smolinski@de.ibm.com) * @@ -167,6 +167,7 @@ static debug_info_t *debug_area_last = NULL; static DEFINE_MUTEX(debug_mutex); static int initialized; +static int debug_critical; static const struct file_operations debug_file_ops = { .owner = THIS_MODULE, @@ -932,6 +933,11 @@ debug_stop_all(void) } +void debug_set_critical(void) +{ + debug_critical = 1; +} + /* * debug_event_common: * - write debug entry with given size @@ -945,7 +951,11 @@ debug_event_common(debug_info_t * id, int level, const void *buf, int len) if (!debug_active || !id->areas) return NULL; - spin_lock_irqsave(&id->lock, flags); + if (debug_critical) { + if (!spin_trylock_irqsave(&id->lock, flags)) + return NULL; + } else + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); memset(DEBUG_DATA(active), 0, id->buf_size); memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); @@ -968,7 +978,11 @@ debug_entry_t if (!debug_active || !id->areas) return NULL; - spin_lock_irqsave(&id->lock, flags); + if (debug_critical) { + if (!spin_trylock_irqsave(&id->lock, flags)) + return NULL; + } else + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); memset(DEBUG_DATA(active), 0, id->buf_size); memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size)); @@ -1013,7 +1027,11 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) return NULL; numargs=debug_count_numargs(string); - spin_lock_irqsave(&id->lock, flags); + if (debug_critical) { + if (!spin_trylock_irqsave(&id->lock, flags)) + return NULL; + } else + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active); va_start(ap,string); @@ -1047,7 +1065,11 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) numargs=debug_count_numargs(string); - spin_lock_irqsave(&id->lock, flags); + if (debug_critical) { + if (!spin_trylock_irqsave(&id->lock, flags)) + return NULL; + } else + spin_lock_irqsave(&id->lock, flags); active = get_active_entry(id); curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active); va_start(ap,string); @@ -1428,10 +1450,10 @@ debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, rc += sprintf(out_buf + rc, "| "); for (i = 0; i < id->buf_size; i++) { unsigned char c = in_buf[i]; - if (!isprint(c)) - rc += sprintf(out_buf + rc, "."); - else + if (isascii(c) && isprint(c)) rc += sprintf(out_buf + rc, "%c", c); + else + rc += sprintf(out_buf + rc, "."); } rc += sprintf(out_buf + rc, "\n"); return rc; diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 52098d6dfaa7..578eb4e6d157 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -29,6 +29,7 @@ #include <asm/sysinfo.h> #include <asm/cpcmd.h> #include <asm/sclp.h> +#include <asm/system.h> #include "entry.h" /* @@ -262,25 +263,8 @@ static noinline __init void setup_lowcore_early(void) static noinline __init void setup_facility_list(void) { - unsigned long nr; - - S390_lowcore.stfl_fac_list = 0; - asm volatile( - " .insn s,0xb2b10000,0(0)\n" /* stfl */ - "0:\n" - EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list)); - memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4); - nr = 4; /* # bytes stored by stfl */ - if (test_facility(7)) { - /* More facility bits available with stfle */ - register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1; - asm volatile(".insn s,0xb2b00000,%0" /* stfle */ - : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0) - : : "cc"); - nr = (reg0 + 1) * 8; /* # bytes stored by stfle */ - } - memset((char *) S390_lowcore.stfle_fac_list + nr, 0, - MAX_FACILITY_BIT/8 - nr); + stfle(S390_lowcore.stfle_fac_list, + ARRAY_SIZE(S390_lowcore.stfle_fac_list)); } static noinline __init void setup_hpage(void) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 3705700ed374..74ee563fe62b 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -2,7 +2,7 @@ * arch/s390/kernel/entry.S * S390 low-level entry points. * - * Copyright (C) IBM Corp. 1999,2006 + * Copyright (C) IBM Corp. 1999,2012 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Hartmut Penner (hp@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), @@ -105,14 +105,14 @@ STACK_SIZE = 1 << STACK_SHIFT .macro ADD64 high,low,timer al \high,\timer - al \low,\timer+4 + al \low,4+\timer brc 12,.+8 ahi \high,1 .endm .macro SUB64 high,low,timer sl \high,\timer - sl \low,\timer+4 + sl \low,4+\timer brc 3,.+8 ahi \high,-1 .endm @@ -471,7 +471,6 @@ io_tif: jnz io_work # there is work to do (signals etc.) io_restore: mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) - ni __LC_RETURN_PSW+1,0xfd # clean wait state bit stpt __LC_EXIT_TIMER lm %r0,%r15,__PT_R0(%r11) lpsw __LC_RETURN_PSW @@ -606,12 +605,32 @@ ext_skip: stm %r8,%r9,__PT_PSW(%r11) TRACE_IRQS_OFF lr %r2,%r11 # pass pointer to pt_regs - l %r3,__LC_CPU_ADDRESS # get cpu address + interruption code + l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code l %r4,__LC_EXT_PARAMS # get external parameters l %r1,BASED(.Ldo_extint) basr %r14,%r1 # call do_extint j io_return +/* + * Load idle PSW. The second "half" of this function is in cleanup_idle. + */ +ENTRY(psw_idle) + st %r4,__SF_EMPTY(%r15) + basr %r1,0 + la %r1,psw_idle_lpsw+4-.(%r1) + st %r1,__SF_EMPTY+4(%r15) + oi __SF_EMPTY+4(%r15),0x80 + la %r1,.Lvtimer_max-psw_idle_lpsw-4(%r1) + stck __IDLE_ENTER(%r2) + ltr %r5,%r5 + stpt __VQ_IDLE_ENTER(%r3) + jz psw_idle_lpsw + spt 0(%r1) +psw_idle_lpsw: + lpsw __SF_EMPTY(%r15) + br %r14 +psw_idle_end: + __critical_end: /* @@ -673,7 +692,6 @@ mcck_skip: TRACE_IRQS_ON mcck_return: mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW - ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f lm %r0,%r15,__PT_R0(%r11) @@ -691,77 +709,30 @@ mcck_panic: 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) j mcck_skip -/* - * Restart interruption handler, kick starter for additional CPUs - */ -#ifdef CONFIG_SMP - __CPUINIT -ENTRY(restart_int_handler) - basr %r1,0 -restart_base: - spt restart_vtime-restart_base(%r1) - stck __LC_LAST_UPDATE_CLOCK - mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) - mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) - l %r15,__LC_GPREGS_SAVE_AREA+60 # load ksp - lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs - lam %a0,%a15,__LC_AREGS_SAVE_AREA - lm %r6,%r15,__SF_GPRS(%r15)# load registers from clone - l %r1,__LC_THREAD_INFO - mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) - mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) - xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER - ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off - basr %r14,0 - l %r14,restart_addr-.(%r14) - basr %r14,%r14 # call start_secondary -restart_addr: - .long start_secondary - .align 8 -restart_vtime: - .long 0x7fffffff,0xffffffff - .previous -#else -/* - * If we do not run with SMP enabled, let the new CPU crash ... - */ -ENTRY(restart_int_handler) - basr %r1,0 -restart_base: - lpsw restart_crash-restart_base(%r1) - .align 8 -restart_crash: - .long 0x000a0000,0x00000000 -restart_go: -#endif - # # PSW restart interrupt handler # -ENTRY(psw_restart_int_handler) +ENTRY(restart_int_handler) st %r15,__LC_SAVE_AREA_RESTART - basr %r15,0 -0: l %r15,.Lrestart_stack-0b(%r15) # load restart stack - l %r15,0(%r15) + l %r15,__LC_RESTART_STACK ahi %r15,-__PT_SIZE # create pt_regs on stack + xc 0(__PT_SIZE,%r15),0(%r15) stm %r0,%r14,__PT_R0(%r15) mvc __PT_R15(4,%r15),__LC_SAVE_AREA_RESTART mvc __PT_PSW(8,%r15),__LC_RST_OLD_PSW # store restart old psw - ahi %r15,-STACK_FRAME_OVERHEAD - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) - basr %r14,0 -1: l %r14,.Ldo_restart-1b(%r14) - basr %r14,%r14 - basr %r14,0 # load disabled wait PSW if -2: lpsw restart_psw_crash-2b(%r14) # do_restart returns - .align 4 -.Ldo_restart: - .long do_restart -.Lrestart_stack: - .long restart_stack - .align 8 -restart_psw_crash: - .long 0x000a0000,0x00000000 + restart_psw_crash + ahi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack + xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) + lm %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu + ltr %r3,%r3 # test source cpu address + jm 1f # negative -> skip source stop +0: sigp %r4,%r3,1 # sigp sense to source cpu + brc 10,0b # wait for status stored +1: basr %r14,%r1 # call function + stap __SF_EMPTY(%r15) # store cpu address + lh %r3,__SF_EMPTY(%r15) +2: sigp %r4,%r3,5 # sigp stop to current cpu + brc 2,2b +3: j 3b .section .kprobes.text, "ax" @@ -795,6 +766,8 @@ cleanup_table: .long io_tif + 0x80000000 .long io_restore + 0x80000000 .long io_done + 0x80000000 + .long psw_idle + 0x80000000 + .long psw_idle_end + 0x80000000 cleanup_critical: cl %r9,BASED(cleanup_table) # system_call @@ -813,6 +786,10 @@ cleanup_critical: jl cleanup_io_tif cl %r9,BASED(cleanup_table+28) # io_done jl cleanup_io_restore + cl %r9,BASED(cleanup_table+32) # psw_idle + jl 0f + cl %r9,BASED(cleanup_table+36) # psw_idle_end + jl cleanup_idle 0: br %r14 cleanup_system_call: @@ -896,7 +873,6 @@ cleanup_io_restore: jhe 0f l %r9,12(%r11) # get saved r11 pointer to pt_regs mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) - ni __LC_RETURN_PSW+1,0xfd # clear wait state bit mvc 0(32,%r11),__PT_R8(%r9) lm %r0,%r7,__PT_R0(%r9) 0: lm %r8,%r9,__LC_RETURN_PSW @@ -904,11 +880,52 @@ cleanup_io_restore: cleanup_io_restore_insn: .long io_done - 4 + 0x80000000 +cleanup_idle: + # copy interrupt clock & cpu timer + mvc __IDLE_EXIT(8,%r2),__LC_INT_CLOCK + mvc __VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER + chi %r11,__LC_SAVE_AREA_ASYNC + je 0f + mvc __IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK + mvc __VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER +0: # check if stck has been executed + cl %r9,BASED(cleanup_idle_insn) + jhe 1f + mvc __IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2) + mvc __VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3) + j 2f +1: # check if the cpu timer has been reprogrammed + ltr %r5,%r5 + jz 2f + spt __VQ_IDLE_ENTER(%r3) +2: # account system time going idle + lm %r9,%r10,__LC_STEAL_TIMER + ADD64 %r9,%r10,__IDLE_ENTER(%r2) + SUB64 %r9,%r10,__LC_LAST_UPDATE_CLOCK + stm %r9,%r10,__LC_STEAL_TIMER + mvc __LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2) + lm %r9,%r10,__LC_SYSTEM_TIMER + ADD64 %r9,%r10,__LC_LAST_UPDATE_TIMER + SUB64 %r9,%r10,__VQ_IDLE_ENTER(%r3) + stm %r9,%r10,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3) + # prepare return psw + n %r8,BASED(cleanup_idle_wait) # clear wait state bit + l %r9,24(%r11) # return from psw_idle + br %r14 +cleanup_idle_insn: + .long psw_idle_lpsw + 0x80000000 +cleanup_idle_wait: + .long 0xfffdffff + /* * Integer constants */ .align 4 -.Lnr_syscalls: .long NR_syscalls +.Lnr_syscalls: + .long NR_syscalls +.Lvtimer_max: + .quad 0x7fffffffffffffff /* * Symbol constants diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index bf538aaf407d..6cdddac93a2e 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -4,11 +4,22 @@ #include <linux/types.h> #include <linux/signal.h> #include <asm/ptrace.h> - +#include <asm/cputime.h> +#include <asm/timer.h> extern void (*pgm_check_table[128])(struct pt_regs *); extern void *restart_stack; +void system_call(void); +void pgm_check_handler(void); +void ext_int_handler(void); +void io_int_handler(void); +void mcck_int_handler(void); +void restart_int_handler(void); +void restart_call_handler(void); +void psw_idle(struct s390_idle_data *, struct vtimer_queue *, + unsigned long, int); + asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); @@ -24,9 +35,9 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs); void do_notify_resume(struct pt_regs *regs); -void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long); +struct ext_code; +void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long); void do_restart(void); -int __cpuinit start_secondary(void *cpuvoid); void __init startup_init(void); void die(struct pt_regs *regs, const char *str); diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 412a7b8783d7..4e1c292fa7e3 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -2,7 +2,7 @@ * arch/s390/kernel/entry64.S * S390 low-level entry points. * - * Copyright (C) IBM Corp. 1999,2010 + * Copyright (C) IBM Corp. 1999,2012 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Hartmut Penner (hp@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), @@ -489,7 +489,6 @@ io_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) - ni __LC_RETURN_PSW+1,0xfd # clear wait state bit stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER lmg %r11,%r15,__PT_R11(%r11) @@ -625,12 +624,30 @@ ext_skip: TRACE_IRQS_OFF lghi %r1,4096 lgr %r2,%r11 # pass pointer to pt_regs - llgf %r3,__LC_CPU_ADDRESS # get cpu address + interruption code + llgf %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code llgf %r4,__LC_EXT_PARAMS # get external parameter lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter brasl %r14,do_extint j io_return +/* + * Load idle PSW. The second "half" of this function is in cleanup_idle. + */ +ENTRY(psw_idle) + stg %r4,__SF_EMPTY(%r15) + larl %r1,psw_idle_lpsw+4 + stg %r1,__SF_EMPTY+8(%r15) + larl %r1,.Lvtimer_max + stck __IDLE_ENTER(%r2) + ltr %r5,%r5 + stpt __VQ_IDLE_ENTER(%r3) + jz psw_idle_lpsw + spt 0(%r1) +psw_idle_lpsw: + lpswe __SF_EMPTY(%r15) + br %r14 +psw_idle_end: + __critical_end: /* @@ -696,7 +713,6 @@ mcck_return: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW - ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f stpt __LC_EXIT_TIMER @@ -713,68 +729,30 @@ mcck_panic: 0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) j mcck_skip -/* - * Restart interruption handler, kick starter for additional CPUs - */ -#ifdef CONFIG_SMP - __CPUINIT -ENTRY(restart_int_handler) - basr %r1,0 -restart_base: - spt restart_vtime-restart_base(%r1) - stck __LC_LAST_UPDATE_CLOCK - mvc __LC_LAST_UPDATE_TIMER(8),restart_vtime-restart_base(%r1) - mvc __LC_EXIT_TIMER(8),restart_vtime-restart_base(%r1) - lghi %r10,__LC_GPREGS_SAVE_AREA - lg %r15,120(%r10) # load ksp - lghi %r10,__LC_CREGS_SAVE_AREA - lctlg %c0,%c15,0(%r10) # get new ctl regs - lghi %r10,__LC_AREGS_SAVE_AREA - lam %a0,%a15,0(%r10) - lmg %r6,%r15,__SF_GPRS(%r15)# load registers from clone - lg %r1,__LC_THREAD_INFO - mvc __LC_USER_TIMER(8),__TI_user_timer(%r1) - mvc __LC_SYSTEM_TIMER(8),__TI_system_timer(%r1) - xc __LC_STEAL_TIMER(8),__LC_STEAL_TIMER - ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off - brasl %r14,start_secondary - .align 8 -restart_vtime: - .long 0x7fffffff,0xffffffff - .previous -#else -/* - * If we do not run with SMP enabled, let the new CPU crash ... - */ -ENTRY(restart_int_handler) - basr %r1,0 -restart_base: - lpswe restart_crash-restart_base(%r1) - .align 8 -restart_crash: - .long 0x000a0000,0x00000000,0x00000000,0x00000000 -restart_go: -#endif - # # PSW restart interrupt handler # -ENTRY(psw_restart_int_handler) +ENTRY(restart_int_handler) stg %r15,__LC_SAVE_AREA_RESTART - larl %r15,restart_stack # load restart stack - lg %r15,0(%r15) + lg %r15,__LC_RESTART_STACK aghi %r15,-__PT_SIZE # create pt_regs on stack + xc 0(__PT_SIZE,%r15),0(%r15) stmg %r0,%r14,__PT_R0(%r15) mvc __PT_R15(8,%r15),__LC_SAVE_AREA_RESTART mvc __PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw - aghi %r15,-STACK_FRAME_OVERHEAD - xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) - brasl %r14,do_restart - larl %r14,restart_psw_crash # load disabled wait PSW if - lpswe 0(%r14) # do_restart returns - .align 8 -restart_psw_crash: - .quad 0x0002000080000000,0x0000000000000000 + restart_psw_crash + aghi %r15,-STACK_FRAME_OVERHEAD # create stack frame on stack + xc 0(STACK_FRAME_OVERHEAD,%r15),0(%r15) + lmg %r1,%r3,__LC_RESTART_FN # load fn, parm & source cpu + ltgr %r3,%r3 # test source cpu address + jm 1f # negative -> skip source stop +0: sigp %r4,%r3,1 # sigp sense to source cpu + brc 10,0b # wait for status stored +1: basr %r14,%r1 # call function + stap __SF_EMPTY(%r15) # store cpu address + llgh %r3,__SF_EMPTY(%r15) +2: sigp %r4,%r3,5 # sigp stop to current cpu + brc 2,2b +3: j 3b .section .kprobes.text, "ax" @@ -808,6 +786,8 @@ cleanup_table: .quad io_tif .quad io_restore .quad io_done + .quad psw_idle + .quad psw_idle_end cleanup_critical: clg %r9,BASED(cleanup_table) # system_call @@ -826,6 +806,10 @@ cleanup_critical: jl cleanup_io_tif clg %r9,BASED(cleanup_table+56) # io_done jl cleanup_io_restore + clg %r9,BASED(cleanup_table+64) # psw_idle + jl 0f + clg %r9,BASED(cleanup_table+72) # psw_idle_end + jl cleanup_idle 0: br %r14 @@ -915,7 +899,6 @@ cleanup_io_restore: je 0f lg %r9,24(%r11) # get saved r11 pointer to pt_regs mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) - ni __LC_RETURN_PSW+1,0xfd # clear wait state bit mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 0: lmg %r8,%r9,__LC_RETURN_PSW @@ -923,6 +906,42 @@ cleanup_io_restore: cleanup_io_restore_insn: .quad io_done - 4 +cleanup_idle: + # copy interrupt clock & cpu timer + mvc __IDLE_EXIT(8,%r2),__LC_INT_CLOCK + mvc __VQ_IDLE_EXIT(8,%r3),__LC_ASYNC_ENTER_TIMER + cghi %r11,__LC_SAVE_AREA_ASYNC + je 0f + mvc __IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK + mvc __VQ_IDLE_EXIT(8,%r3),__LC_MCCK_ENTER_TIMER +0: # check if stck & stpt have been executed + clg %r9,BASED(cleanup_idle_insn) + jhe 1f + mvc __IDLE_ENTER(8,%r2),__IDLE_EXIT(%r2) + mvc __VQ_IDLE_ENTER(8,%r3),__VQ_IDLE_EXIT(%r3) + j 2f +1: # check if the cpu timer has been reprogrammed + ltr %r5,%r5 + jz 2f + spt __VQ_IDLE_ENTER(%r3) +2: # account system time going idle + lg %r9,__LC_STEAL_TIMER + alg %r9,__IDLE_ENTER(%r2) + slg %r9,__LC_LAST_UPDATE_CLOCK + stg %r9,__LC_STEAL_TIMER + mvc __LC_LAST_UPDATE_CLOCK(8),__IDLE_EXIT(%r2) + lg %r9,__LC_SYSTEM_TIMER + alg %r9,__LC_LAST_UPDATE_TIMER + slg %r9,__VQ_IDLE_ENTER(%r3) + stg %r9,__LC_SYSTEM_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__VQ_IDLE_EXIT(%r3) + # prepare return psw + nihh %r8,0xfffd # clear wait state bit + lg %r9,48(%r11) # return from psw_idle + br %r14 +cleanup_idle_insn: + .quad psw_idle_lpsw + /* * Integer constants */ @@ -931,6 +950,8 @@ cleanup_io_restore_insn: .quad __critical_start .Lcritical_length: .quad __critical_end - __critical_start +.Lvtimer_max: + .quad 0x7fffffffffffffff #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index affa8e68124a..8342e65a140d 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -2,7 +2,7 @@ * arch/s390/kernel/ipl.c * ipl/reipl/dump support for Linux on s390. * - * Copyright IBM Corp. 2005,2007 + * Copyright IBM Corp. 2005,2012 * Author(s): Michael Holzheu <holzheu@de.ibm.com> * Heiko Carstens <heiko.carstens@de.ibm.com> * Volker Sameske <sameske@de.ibm.com> @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/gfp.h> #include <linux/crash_dump.h> +#include <linux/debug_locks.h> #include <asm/ipl.h> #include <asm/smp.h> #include <asm/setup.h> @@ -25,8 +26,9 @@ #include <asm/ebcdic.h> #include <asm/reset.h> #include <asm/sclp.h> -#include <asm/sigp.h> #include <asm/checksum.h> +#include <asm/debug.h> +#include <asm/os_info.h> #include "entry.h" #define IPL_PARM_BLOCK_VERSION 0 @@ -571,7 +573,7 @@ static void __ipl_run(void *unused) static void ipl_run(struct shutdown_trigger *trigger) { - smp_switch_to_ipl_cpu(__ipl_run, NULL); + smp_call_ipl_cpu(__ipl_run, NULL); } static int __init ipl_init(void) @@ -950,6 +952,13 @@ static struct attribute_group reipl_nss_attr_group = { .attrs = reipl_nss_attrs, }; +static void set_reipl_block_actual(struct ipl_parameter_block *reipl_block) +{ + reipl_block_actual = reipl_block; + os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual, + reipl_block->hdr.len); +} + /* reipl type */ static int reipl_set_type(enum ipl_type type) @@ -965,7 +974,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_CCW_VM; else reipl_method = REIPL_METHOD_CCW_CIO; - reipl_block_actual = reipl_block_ccw; + set_reipl_block_actual(reipl_block_ccw); break; case IPL_TYPE_FCP: if (diag308_set_works) @@ -974,7 +983,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_FCP_RO_VM; else reipl_method = REIPL_METHOD_FCP_RO_DIAG; - reipl_block_actual = reipl_block_fcp; + set_reipl_block_actual(reipl_block_fcp); break; case IPL_TYPE_FCP_DUMP: reipl_method = REIPL_METHOD_FCP_DUMP; @@ -984,7 +993,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_NSS_DIAG; else reipl_method = REIPL_METHOD_NSS; - reipl_block_actual = reipl_block_nss; + set_reipl_block_actual(reipl_block_nss); break; case IPL_TYPE_UNKNOWN: reipl_method = REIPL_METHOD_DEFAULT; @@ -1101,7 +1110,7 @@ static void __reipl_run(void *unused) static void reipl_run(struct shutdown_trigger *trigger) { - smp_switch_to_ipl_cpu(__reipl_run, NULL); + smp_call_ipl_cpu(__reipl_run, NULL); } static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) @@ -1256,6 +1265,29 @@ static int __init reipl_fcp_init(void) return 0; } +static int __init reipl_type_init(void) +{ + enum ipl_type reipl_type = ipl_info.type; + struct ipl_parameter_block *reipl_block; + unsigned long size; + + reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size); + if (!reipl_block) + goto out; + /* + * If we have an OS info reipl block, this will be used + */ + if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_FCP) { + memcpy(reipl_block_fcp, reipl_block, size); + reipl_type = IPL_TYPE_FCP; + } else if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_CCW) { + memcpy(reipl_block_ccw, reipl_block, size); + reipl_type = IPL_TYPE_CCW; + } +out: + return reipl_set_type(reipl_type); +} + static int __init reipl_init(void) { int rc; @@ -1277,10 +1309,7 @@ static int __init reipl_init(void) rc = reipl_nss_init(); if (rc) return rc; - rc = reipl_set_type(ipl_info.type); - if (rc) - return rc; - return 0; + return reipl_type_init(); } static struct shutdown_action __refdata reipl_action = { @@ -1421,7 +1450,7 @@ static void dump_run(struct shutdown_trigger *trigger) if (dump_method == DUMP_METHOD_NONE) return; smp_send_stop(); - smp_switch_to_ipl_cpu(__dump_run, NULL); + smp_call_ipl_cpu(__dump_run, NULL); } static int __init dump_ccw_init(void) @@ -1499,30 +1528,12 @@ static struct shutdown_action __refdata dump_action = { static void dump_reipl_run(struct shutdown_trigger *trigger) { - preempt_disable(); - /* - * Bypass dynamic address translation (DAT) when storing IPL parameter - * information block address and checksum into the prefix area - * (corresponding to absolute addresses 0-8191). - * When enhanced DAT applies and the STE format control in one, - * the absolute address is formed without prefixing. In this case a - * normal store (stg/st) into the prefix area would no more match to - * absolute addresses 0-8191. - */ -#ifdef CONFIG_64BIT - asm volatile("sturg %0,%1" - :: "a" ((unsigned long) reipl_block_actual), - "a" (&lowcore_ptr[smp_processor_id()]->ipib)); -#else - asm volatile("stura %0,%1" - :: "a" ((unsigned long) reipl_block_actual), - "a" (&lowcore_ptr[smp_processor_id()]->ipib)); -#endif - asm volatile("stura %0,%1" - :: "a" (csum_partial(reipl_block_actual, - reipl_block_actual->hdr.len, 0)), - "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); - preempt_enable(); + u32 csum; + + csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); + copy_to_absolute_zero(&S390_lowcore.ipib_checksum, &csum, sizeof(csum)); + copy_to_absolute_zero(&S390_lowcore.ipib, &reipl_block_actual, + sizeof(reipl_block_actual)); dump_run(trigger); } @@ -1623,9 +1634,7 @@ static void stop_run(struct shutdown_trigger *trigger) if (strcmp(trigger->name, ON_PANIC_STR) == 0 || strcmp(trigger->name, ON_RESTART_STR) == 0) disabled_wait((unsigned long) __builtin_return_address(0)); - while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) - cpu_relax(); - for (;;); + smp_stop_cpu(); } static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, @@ -1713,6 +1722,7 @@ static struct kobj_attribute on_panic_attr = static void do_panic(void) { + lgr_info_log(); on_panic_trigger.action->fn(&on_panic_trigger); stop_run(&on_panic_trigger); } @@ -1738,9 +1748,8 @@ static ssize_t on_restart_store(struct kobject *kobj, static struct kobj_attribute on_restart_attr = __ATTR(on_restart, 0644, on_restart_show, on_restart_store); -void do_restart(void) +static void __do_restart(void *ignore) { - smp_restart_with_online_cpu(); smp_send_stop(); #ifdef CONFIG_CRASH_DUMP crash_kexec(NULL); @@ -1749,6 +1758,14 @@ void do_restart(void) stop_run(&on_restart_trigger); } +void do_restart(void) +{ + tracing_off(); + debug_locks_off(); + lgr_info_log(); + smp_call_online_cpu(__do_restart, NULL); +} + /* on halt */ static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action}; diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index e30b2dfa8ba0..2429ecd68872 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -202,31 +202,27 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler) } EXPORT_SYMBOL(unregister_external_interrupt); -void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code, +void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct pt_regs *old_regs; - unsigned short code; struct ext_int_info *p; int index; - code = (unsigned short) ext_int_code; old_regs = set_irq_regs(regs); - s390_idle_check(regs, S390_lowcore.int_clock, - S390_lowcore.async_enter_timer); irq_enter(); if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) /* Serve timer interrupts first. */ clock_comparator_work(); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; - if (code != 0x1004) + if (ext_code.code != 0x1004) __get_cpu_var(s390_idle).nohz_delay = 1; - index = ext_hash(code); + index = ext_hash(ext_code.code); rcu_read_lock(); list_for_each_entry_rcu(p, &ext_int_hash[index], entry) - if (likely(p->code == code)) - p->handler(ext_int_code, param32, param64); + if (likely(p->code == ext_code.code)) + p->handler(ext_code, param32, param64); rcu_read_unlock(); irq_exit(); set_irq_regs(old_regs); diff --git a/arch/s390/kernel/lgr.c b/arch/s390/kernel/lgr.c new file mode 100644 index 000000000000..8431b92ca3ae --- /dev/null +++ b/arch/s390/kernel/lgr.c @@ -0,0 +1,200 @@ +/* + * Linux Guest Relocation (LGR) detection + * + * Copyright IBM Corp. 2012 + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/slab.h> +#include <asm/sysinfo.h> +#include <asm/ebcdic.h> +#include <asm/system.h> +#include <asm/debug.h> +#include <asm/ipl.h> + +#define LGR_TIMER_INTERVAL_SECS (30 * 60) +#define VM_LEVEL_MAX 2 /* Maximum is 8, but we only record two levels */ + +/* + * LGR info: Contains stfle and stsi data + */ +struct lgr_info { + /* Bit field with facility information: 4 DWORDs are stored */ + u64 stfle_fac_list[4]; + /* Level of system (1 = CEC, 2 = LPAR, 3 = z/VM */ + u32 level; + /* Level 1: CEC info (stsi 1.1.1) */ + char manufacturer[16]; + char type[4]; + char sequence[16]; + char plant[4]; + char model[16]; + /* Level 2: LPAR info (stsi 2.2.2) */ + u16 lpar_number; + char name[8]; + /* Level 3: VM info (stsi 3.2.2) */ + u8 vm_count; + struct { + char name[8]; + char cpi[16]; + } vm[VM_LEVEL_MAX]; +} __packed __aligned(8); + +/* + * LGR globals + */ +static void *lgr_page; +static struct lgr_info lgr_info_last; +static struct lgr_info lgr_info_cur; +static struct debug_info *lgr_dbf; + +/* + * Return number of valid stsi levels + */ +static inline int stsi_0(void) +{ + int rc = stsi(NULL, 0, 0, 0); + + return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); +} + +/* + * Copy buffer and then convert it to ASCII + */ +static void cpascii(char *dst, char *src, int size) +{ + memcpy(dst, src, size); + EBCASC(dst, size); +} + +/* + * Fill LGR info with 1.1.1 stsi data + */ +static void lgr_stsi_1_1_1(struct lgr_info *lgr_info) +{ + struct sysinfo_1_1_1 *si = lgr_page; + + if (stsi(si, 1, 1, 1) == -ENOSYS) + return; + cpascii(lgr_info->manufacturer, si->manufacturer, + sizeof(si->manufacturer)); + cpascii(lgr_info->type, si->type, sizeof(si->type)); + cpascii(lgr_info->model, si->model, sizeof(si->model)); + cpascii(lgr_info->sequence, si->sequence, sizeof(si->sequence)); + cpascii(lgr_info->plant, si->plant, sizeof(si->plant)); +} + +/* + * Fill LGR info with 2.2.2 stsi data + */ +static void lgr_stsi_2_2_2(struct lgr_info *lgr_info) +{ + struct sysinfo_2_2_2 *si = lgr_page; + + if (stsi(si, 2, 2, 2) == -ENOSYS) + return; + cpascii(lgr_info->name, si->name, sizeof(si->name)); + memcpy(&lgr_info->lpar_number, &si->lpar_number, + sizeof(lgr_info->lpar_number)); +} + +/* + * Fill LGR info with 3.2.2 stsi data + */ +static void lgr_stsi_3_2_2(struct lgr_info *lgr_info) +{ + struct sysinfo_3_2_2 *si = lgr_page; + int i; + + if (stsi(si, 3, 2, 2) == -ENOSYS) + return; + for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) { + cpascii(lgr_info->vm[i].name, si->vm[i].name, + sizeof(si->vm[i].name)); + cpascii(lgr_info->vm[i].cpi, si->vm[i].cpi, + sizeof(si->vm[i].cpi)); + } + lgr_info->vm_count = si->count; +} + +/* + * Fill LGR info with current data + */ +static void lgr_info_get(struct lgr_info *lgr_info) +{ + memset(lgr_info, 0, sizeof(*lgr_info)); + stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list)); + lgr_info->level = stsi_0(); + if (lgr_info->level == -ENOSYS) + return; + if (lgr_info->level >= 1) + lgr_stsi_1_1_1(lgr_info); + if (lgr_info->level >= 2) + lgr_stsi_2_2_2(lgr_info); + if (lgr_info->level >= 3) + lgr_stsi_3_2_2(lgr_info); +} + +/* + * Check if LGR info has changed and if yes log new LGR info to s390dbf + */ +void lgr_info_log(void) +{ + static DEFINE_SPINLOCK(lgr_info_lock); + unsigned long flags; + + if (!spin_trylock_irqsave(&lgr_info_lock, flags)) + return; + lgr_info_get(&lgr_info_cur); + if (memcmp(&lgr_info_last, &lgr_info_cur, sizeof(lgr_info_cur)) != 0) { + debug_event(lgr_dbf, 1, &lgr_info_cur, sizeof(lgr_info_cur)); + lgr_info_last = lgr_info_cur; + } + spin_unlock_irqrestore(&lgr_info_lock, flags); +} +EXPORT_SYMBOL_GPL(lgr_info_log); + +static void lgr_timer_set(void); + +/* + * LGR timer callback + */ +static void lgr_timer_fn(unsigned long ignored) +{ + lgr_info_log(); + lgr_timer_set(); +} + +static struct timer_list lgr_timer = + TIMER_DEFERRED_INITIALIZER(lgr_timer_fn, 0, 0); + +/* + * Setup next LGR timer + */ +static void lgr_timer_set(void) +{ + mod_timer(&lgr_timer, jiffies + LGR_TIMER_INTERVAL_SECS * HZ); +} + +/* + * Initialize LGR: Add s390dbf, write initial lgr_info and setup timer + */ +static int __init lgr_init(void) +{ + lgr_page = (void *) __get_free_pages(GFP_KERNEL, 0); + if (!lgr_page) + return -ENOMEM; + lgr_dbf = debug_register("lgr", 1, 1, sizeof(struct lgr_info)); + if (!lgr_dbf) { + free_page((unsigned long) lgr_page); + return -ENOMEM; + } + debug_register_view(lgr_dbf, &debug_hex_ascii_view); + lgr_info_get(&lgr_info_last); + debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last)); + lgr_timer_set(); + return 0; +} +module_init(lgr_init); diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 47b168fb29c4..0f8cdf1268d0 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/reboot.h> #include <linux/ftrace.h> +#include <linux/debug_locks.h> #include <asm/cio.h> #include <asm/setup.h> #include <asm/pgtable.h> @@ -49,50 +50,21 @@ static void add_elf_notes(int cpu) } /* - * Store status of next available physical CPU - */ -static int store_status_next(int start_cpu, int this_cpu) -{ - struct save_area *sa = (void *) 4608 + store_prefix(); - int cpu, rc; - - for (cpu = start_cpu; cpu < 65536; cpu++) { - if (cpu == this_cpu) - continue; - do { - rc = raw_sigp(cpu, sigp_stop_and_store_status); - } while (rc == sigp_busy); - if (rc != sigp_order_code_accepted) - continue; - if (sa->pref_reg) - return cpu; - } - return -1; -} - -/* * Initialize CPU ELF notes */ void setup_regs(void) { unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE; - int cpu, this_cpu, phys_cpu = 0, first = 1; + int cpu, this_cpu; - this_cpu = stap(); - - if (!S390_lowcore.prefixreg_save_area) - first = 0; + this_cpu = smp_find_processor_id(stap()); + add_elf_notes(this_cpu); for_each_online_cpu(cpu) { - if (first) { - add_elf_notes(cpu); - first = 0; + if (cpu == this_cpu) + continue; + if (smp_store_status(cpu)) continue; - } - phys_cpu = store_status_next(phys_cpu, this_cpu); - if (phys_cpu == -1) - break; add_elf_notes(cpu); - phys_cpu++; } /* Copy dump CPU store status info to absolute zero */ memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area)); @@ -238,10 +210,14 @@ static void __machine_kexec(void *data) struct kimage *image = data; pfault_fini(); - if (image->type == KEXEC_TYPE_CRASH) + tracing_off(); + debug_locks_off(); + if (image->type == KEXEC_TYPE_CRASH) { + lgr_info_log(); s390_reset_system(__do_machine_kdump, data); - else + } else { s390_reset_system(__do_machine_kexec, data); + } disabled_wait((unsigned long) __builtin_return_address(0)); } @@ -255,5 +231,5 @@ void machine_kexec(struct kimage *image) return; tracer_disable(); smp_send_stop(); - smp_switch_to_ipl_cpu(__machine_kexec, image); + smp_call_ipl_cpu(__machine_kexec, image); } diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 0fd2e863e114..8c372ca61350 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -254,8 +254,6 @@ void notrace s390_do_machine_check(struct pt_regs *regs) int umode; nmi_enter(); - s390_idle_check(regs, S390_lowcore.mcck_clock, - S390_lowcore.mcck_enter_timer); kstat_cpu(smp_processor_id()).irqs[NMI_NMI]++; mci = (struct mci *) &S390_lowcore.mcck_interruption_code; mcck = &__get_cpu_var(cpu_mcck); diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c new file mode 100644 index 000000000000..bbe522672e06 --- /dev/null +++ b/arch/s390/kernel/os_info.c @@ -0,0 +1,169 @@ +/* + * OS info memory interface + * + * Copyright IBM Corp. 2012 + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#define KMSG_COMPONENT "os_info" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/crash_dump.h> +#include <linux/kernel.h> +#include <asm/checksum.h> +#include <asm/lowcore.h> +#include <asm/system.h> +#include <asm/os_info.h> + +/* + * OS info structure has to be page aligned + */ +static struct os_info os_info __page_aligned_data; + +/* + * Compute checksum over OS info structure + */ +u32 os_info_csum(struct os_info *os_info) +{ + int size = sizeof(*os_info) - offsetof(struct os_info, version_major); + return csum_partial(&os_info->version_major, size, 0); +} + +/* + * Add crashkernel info to OS info and update checksum + */ +void os_info_crashkernel_add(unsigned long base, unsigned long size) +{ + os_info.crashkernel_addr = (u64)(unsigned long)base; + os_info.crashkernel_size = (u64)(unsigned long)size; + os_info.csum = os_info_csum(&os_info); +} + +/* + * Add OS info entry and update checksum + */ +void os_info_entry_add(int nr, void *ptr, u64 size) +{ + os_info.entry[nr].addr = (u64)(unsigned long)ptr; + os_info.entry[nr].size = size; + os_info.entry[nr].csum = csum_partial(ptr, size, 0); + os_info.csum = os_info_csum(&os_info); +} + +/* + * Initialize OS info struture and set lowcore pointer + */ +void __init os_info_init(void) +{ + void *ptr = &os_info; + + os_info.version_major = OS_INFO_VERSION_MAJOR; + os_info.version_minor = OS_INFO_VERSION_MINOR; + os_info.magic = OS_INFO_MAGIC; + os_info.csum = os_info_csum(&os_info); + copy_to_absolute_zero(&S390_lowcore.os_info, &ptr, sizeof(ptr)); +} + +#ifdef CONFIG_CRASH_DUMP + +static struct os_info *os_info_old; + +/* + * Allocate and copy OS info entry from oldmem + */ +static void os_info_old_alloc(int nr, int align) +{ + unsigned long addr, size = 0; + char *buf, *buf_align, *msg; + u32 csum; + + addr = os_info_old->entry[nr].addr; + if (!addr) { + msg = "not available"; + goto fail; + } + size = os_info_old->entry[nr].size; + buf = kmalloc(size + align - 1, GFP_KERNEL); + if (!buf) { + msg = "alloc failed"; + goto fail; + } + buf_align = PTR_ALIGN(buf, align); + if (copy_from_oldmem(buf_align, (void *) addr, size)) { + msg = "copy failed"; + goto fail_free; + } + csum = csum_partial(buf_align, size, 0); + if (csum != os_info_old->entry[nr].csum) { + msg = "checksum failed"; + goto fail_free; + } + os_info_old->entry[nr].addr = (u64)(unsigned long)buf_align; + msg = "copied"; + goto out; +fail_free: + kfree(buf); +fail: + os_info_old->entry[nr].addr = 0; +out: + pr_info("entry %i: %s (addr=0x%lx size=%lu)\n", + nr, msg, addr, size); +} + +/* + * Initialize os info and os info entries from oldmem + */ +static void os_info_old_init(void) +{ + static int os_info_init; + unsigned long addr; + + if (os_info_init) + return; + if (!OLDMEM_BASE) + goto fail; + if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr))) + goto fail; + if (addr == 0 || addr % PAGE_SIZE) + goto fail; + os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL); + if (!os_info_old) + goto fail; + if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old))) + goto fail_free; + if (os_info_old->magic != OS_INFO_MAGIC) + goto fail_free; + if (os_info_old->csum != os_info_csum(os_info_old)) + goto fail_free; + if (os_info_old->version_major > OS_INFO_VERSION_MAJOR) + goto fail_free; + os_info_old_alloc(OS_INFO_VMCOREINFO, 1); + os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1); + os_info_old_alloc(OS_INFO_INIT_FN, PAGE_SIZE); + pr_info("crashkernel: addr=0x%lx size=%lu\n", + (unsigned long) os_info_old->crashkernel_addr, + (unsigned long) os_info_old->crashkernel_size); + os_info_init = 1; + return; +fail_free: + kfree(os_info_old); +fail: + os_info_init = 1; + os_info_old = NULL; +} + +/* + * Return pointer to os infor entry and its size + */ +void *os_info_old_entry(int nr, unsigned long *size) +{ + os_info_old_init(); + + if (!os_info_old) + return NULL; + if (!os_info_old->entry[nr].addr) + return NULL; + *size = (unsigned long) os_info_old->entry[nr].size; + return (void *)(unsigned long)os_info_old->entry[nr].addr; +} +#endif diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7618085b4164..3732e4c09cbe 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -77,13 +77,8 @@ static void default_idle(void) local_irq_enable(); return; } - trace_hardirqs_on(); - /* Don't trace preempt off for idle. */ - stop_critical_timings(); - /* Stop virtual timer and halt the cpu. */ + /* Halt the cpu and keep track of cpu time accounting. */ vtime_stop_cpu(); - /* Reenable preemption tracer. */ - start_critical_timings(); } void cpu_idle(void) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 3b2efc81f34e..38e751278bf7 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -2,7 +2,7 @@ * arch/s390/kernel/setup.c * * S390 version - * Copyright (C) IBM Corp. 1999,2010 + * Copyright (C) IBM Corp. 1999,2012 * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com) * @@ -62,6 +62,8 @@ #include <asm/ebcdic.h> #include <asm/kvm_virtio.h> #include <asm/diag.h> +#include <asm/os_info.h> +#include "entry.h" long psw_kernel_bits = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY | PSW_MASK_EA | PSW_MASK_BA; @@ -351,8 +353,9 @@ static void setup_addressing_mode(void) } } -static void __init -setup_lowcore(void) +void *restart_stack __attribute__((__section__(".data"))); + +static void __init setup_lowcore(void) { struct _lowcore *lc; @@ -363,7 +366,7 @@ setup_lowcore(void) lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); lc->restart_psw.mask = psw_kernel_bits; lc->restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler; + PSW_ADDR_AMODE | (unsigned long) restart_int_handler; lc->external_new_psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK; lc->external_new_psw.addr = @@ -412,6 +415,24 @@ setup_lowcore(void) lc->last_update_timer = S390_lowcore.last_update_timer; lc->last_update_clock = S390_lowcore.last_update_clock; lc->ftrace_func = S390_lowcore.ftrace_func; + + restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); + restart_stack += ASYNC_SIZE; + + /* + * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant + * restart data to the absolute zero lowcore. This is necesary if + * PSW restart is done on an offline CPU that has lowcore zero. + */ + lc->restart_stack = (unsigned long) restart_stack; + lc->restart_fn = (unsigned long) do_restart; + lc->restart_data = 0; + lc->restart_source = -1UL; + memcpy(&S390_lowcore.restart_stack, &lc->restart_stack, + 4*sizeof(unsigned long)); + copy_to_absolute_zero(&S390_lowcore.restart_psw, + &lc->restart_psw, sizeof(psw_t)); + set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; } @@ -572,27 +593,6 @@ static void __init setup_memory_end(void) } } -void *restart_stack __attribute__((__section__(".data"))); - -/* - * Setup new PSW and allocate stack for PSW restart interrupt - */ -static void __init setup_restart_psw(void) -{ - psw_t psw; - - restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); - restart_stack += ASYNC_SIZE; - - /* - * Setup restart PSW for absolute zero lowcore. This is necesary - * if PSW restart is done on an offline CPU that has lowcore zero - */ - psw.mask = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA; - psw.addr = PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler; - copy_to_absolute_zero(&S390_lowcore.restart_psw, &psw, sizeof(psw)); -} - static void __init setup_vmcoreinfo(void) { #ifdef CONFIG_KEXEC @@ -747,7 +747,7 @@ static void __init reserve_crashkernel(void) { #ifdef CONFIG_CRASH_DUMP unsigned long long crash_base, crash_size; - char *msg; + char *msg = NULL; int rc; rc = parse_crashkernel(boot_command_line, memory_end, &crash_size, @@ -779,11 +779,11 @@ static void __init reserve_crashkernel(void) pr_info("Reserving %lluMB of memory at %lluMB " "for crashkernel (System RAM: %luMB)\n", crash_size >> 20, crash_base >> 20, memory_end >> 20); + os_info_crashkernel_add(crash_base, crash_size); #endif } -static void __init -setup_memory(void) +static void __init setup_memory(void) { unsigned long bootmap_size; unsigned long start_pfn, end_pfn; @@ -1014,8 +1014,7 @@ static void __init setup_hwcaps(void) * was printed. */ -void __init -setup_arch(char **cmdline_p) +void __init setup_arch(char **cmdline_p) { /* * print what head.S has found out about the machine @@ -1060,6 +1059,7 @@ setup_arch(char **cmdline_p) parse_early_param(); + os_info_init(); setup_ipl(); setup_memory_end(); setup_addressing_mode(); @@ -1068,7 +1068,6 @@ setup_arch(char **cmdline_p) setup_memory(); setup_resources(); setup_vmcoreinfo(); - setup_restart_psw(); setup_lowcore(); cpu_init(); diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 2d421d90fada..f29f5ef400e5 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -384,7 +384,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t blocked; int ret; /* Set up the stack frame */ @@ -394,10 +393,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, ret = setup_frame(sig, ka, oldset, regs); if (ret) return ret; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, sig); - set_current_blocked(&blocked); + block_sigmask(ka, sig); return 0; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index b0e28c47ab83..a8bf9994b086 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1,23 +1,18 @@ /* - * arch/s390/kernel/smp.c + * SMP related functions * - * Copyright IBM Corp. 1999, 2009 - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * Martin Schwidefsky (schwidefsky@de.ibm.com) - * Heiko Carstens (heiko.carstens@de.ibm.com) + * Copyright IBM Corp. 1999,2012 + * Author(s): Denis Joseph Barrow, + * Martin Schwidefsky <schwidefsky@de.ibm.com>, + * Heiko Carstens <heiko.carstens@de.ibm.com>, * * based on other smp stuff by * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net> * (c) 1998 Ingo Molnar * - * We work with logical cpu numbering everywhere we can. The only - * functions using the real cpu address (got from STAP) are the sigp - * functions. For all other functions we use the identity mapping. - * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is - * used e.g. to find the idle task belonging to a logical cpu. Every array - * in the kernel is sorted by the logical cpu number and not by the physical - * one which is causing all the confusion with __cpu_logical_map and - * cpu_number_map in other architectures. + * The code outside of smp.c uses logical cpu numbers, only smp.c does + * the translation of logical to physical cpu ids. All new code that + * operates on physical cpu numbers needs to go into smp.c. */ #define KMSG_COMPONENT "cpu" @@ -31,198 +26,433 @@ #include <linux/spinlock.h> #include <linux/kernel_stat.h> #include <linux/delay.h> -#include <linux/cache.h> #include <linux/interrupt.h> #include <linux/irqflags.h> #include <linux/cpu.h> -#include <linux/timex.h> -#include <linux/bootmem.h> #include <linux/slab.h> #include <linux/crash_dump.h> #include <asm/asm-offsets.h> #include <asm/ipl.h> #include <asm/setup.h> -#include <asm/sigp.h> -#include <asm/pgalloc.h> #include <asm/irq.h> -#include <asm/cpcmd.h> #include <asm/tlbflush.h> #include <asm/timer.h> #include <asm/lowcore.h> #include <asm/sclp.h> -#include <asm/cputime.h> #include <asm/vdso.h> -#include <asm/cpu.h> +#include <asm/debug.h> +#include <asm/os_info.h> #include "entry.h" -/* logical cpu to cpu address */ -unsigned short __cpu_logical_map[NR_CPUS]; +enum { + sigp_sense = 1, + sigp_external_call = 2, + sigp_emergency_signal = 3, + sigp_start = 4, + sigp_stop = 5, + sigp_restart = 6, + sigp_stop_and_store_status = 9, + sigp_initial_cpu_reset = 11, + sigp_cpu_reset = 12, + sigp_set_prefix = 13, + sigp_store_status_at_address = 14, + sigp_store_extended_status_at_address = 15, + sigp_set_architecture = 18, + sigp_conditional_emergency_signal = 19, + sigp_sense_running = 21, +}; -static struct task_struct *current_set[NR_CPUS]; +enum { + sigp_order_code_accepted = 0, + sigp_status_stored = 1, + sigp_busy = 2, + sigp_not_operational = 3, +}; -static u8 smp_cpu_type; -static int smp_use_sigp_detection; +enum { + ec_schedule = 0, + ec_call_function, + ec_call_function_single, + ec_stop_cpu, +}; -enum s390_cpu_state { +enum { CPU_STATE_STANDBY, CPU_STATE_CONFIGURED, }; +struct pcpu { + struct cpu cpu; + struct task_struct *idle; /* idle process for the cpu */ + struct _lowcore *lowcore; /* lowcore page(s) for the cpu */ + unsigned long async_stack; /* async stack for the cpu */ + unsigned long panic_stack; /* panic stack for the cpu */ + unsigned long ec_mask; /* bit mask for ec_xxx functions */ + int state; /* physical cpu state */ + u32 status; /* last status received via sigp */ + u16 address; /* physical cpu address */ +}; + +static u8 boot_cpu_type; +static u16 boot_cpu_address; +static struct pcpu pcpu_devices[NR_CPUS]; + DEFINE_MUTEX(smp_cpu_state_mutex); -static int smp_cpu_state[NR_CPUS]; -static DEFINE_PER_CPU(struct cpu, cpu_devices); +/* + * Signal processor helper functions. + */ +static inline int __pcpu_sigp(u16 addr, u8 order, u32 parm, u32 *status) +{ + register unsigned int reg1 asm ("1") = parm; + int cc; -static void smp_ext_bitcall(int, int); + asm volatile( + " sigp %1,%2,0(%3)\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc"); + if (status && cc == 1) + *status = reg1; + return cc; +} -static int raw_cpu_stopped(int cpu) +static inline int __pcpu_sigp_relax(u16 addr, u8 order, u32 parm, u32 *status) { - u32 status; + int cc; - switch (raw_sigp_ps(&status, 0, cpu, sigp_sense)) { - case sigp_status_stored: - /* Check for stopped and check stop state */ - if (status & 0x50) - return 1; - break; - default: - break; + while (1) { + cc = __pcpu_sigp(addr, order, parm, status); + if (cc != sigp_busy) + return cc; + cpu_relax(); } - return 0; } -static inline int cpu_stopped(int cpu) +static int pcpu_sigp_retry(struct pcpu *pcpu, u8 order, u32 parm) +{ + int cc, retry; + + for (retry = 0; ; retry++) { + cc = __pcpu_sigp(pcpu->address, order, parm, &pcpu->status); + if (cc != sigp_busy) + break; + if (retry >= 3) + udelay(10); + } + return cc; +} + +static inline int pcpu_stopped(struct pcpu *pcpu) +{ + if (__pcpu_sigp(pcpu->address, sigp_sense, + 0, &pcpu->status) != sigp_status_stored) + return 0; + /* Check for stopped and check stop state */ + return !!(pcpu->status & 0x50); +} + +static inline int pcpu_running(struct pcpu *pcpu) { - return raw_cpu_stopped(cpu_logical_map(cpu)); + if (__pcpu_sigp(pcpu->address, sigp_sense_running, + 0, &pcpu->status) != sigp_status_stored) + return 1; + /* Check for running status */ + return !(pcpu->status & 0x400); } /* - * Ensure that PSW restart is done on an online CPU + * Find struct pcpu by cpu address. */ -void smp_restart_with_online_cpu(void) +static struct pcpu *pcpu_find_address(const struct cpumask *mask, int address) { int cpu; - for_each_online_cpu(cpu) { - if (stap() == __cpu_logical_map[cpu]) { - /* We are online: Enable DAT again and return */ - __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); - return; - } + for_each_cpu(cpu, mask) + if (pcpu_devices[cpu].address == address) + return pcpu_devices + cpu; + return NULL; +} + +static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit) +{ + int order; + + set_bit(ec_bit, &pcpu->ec_mask); + order = pcpu_running(pcpu) ? + sigp_external_call : sigp_emergency_signal; + pcpu_sigp_retry(pcpu, order, 0); +} + +static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) +{ + struct _lowcore *lc; + + if (pcpu != &pcpu_devices[0]) { + pcpu->lowcore = (struct _lowcore *) + __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); + pcpu->async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); + pcpu->panic_stack = __get_free_page(GFP_KERNEL); + if (!pcpu->lowcore || !pcpu->panic_stack || !pcpu->async_stack) + goto out; } - /* We are not online: Do PSW restart on an online CPU */ - while (sigp(cpu, sigp_restart) == sigp_busy) - cpu_relax(); - /* And stop ourself */ - while (raw_sigp(stap(), sigp_stop) == sigp_busy) - cpu_relax(); - for (;;); + lc = pcpu->lowcore; + memcpy(lc, &S390_lowcore, 512); + memset((char *) lc + 512, 0, sizeof(*lc) - 512); + lc->async_stack = pcpu->async_stack + ASYNC_SIZE; + lc->panic_stack = pcpu->panic_stack + PAGE_SIZE; + lc->cpu_nr = cpu; +#ifndef CONFIG_64BIT + if (MACHINE_HAS_IEEE) { + lc->extended_save_area_addr = get_zeroed_page(GFP_KERNEL); + if (!lc->extended_save_area_addr) + goto out; + } +#else + if (vdso_alloc_per_cpu(lc)) + goto out; +#endif + lowcore_ptr[cpu] = lc; + pcpu_sigp_retry(pcpu, sigp_set_prefix, (u32)(unsigned long) lc); + return 0; +out: + if (pcpu != &pcpu_devices[0]) { + free_page(pcpu->panic_stack); + free_pages(pcpu->async_stack, ASYNC_ORDER); + free_pages((unsigned long) pcpu->lowcore, LC_ORDER); + } + return -ENOMEM; } -void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) +static void pcpu_free_lowcore(struct pcpu *pcpu) { - struct _lowcore *lc, *current_lc; - struct stack_frame *sf; - struct pt_regs *regs; - unsigned long sp; - - if (smp_processor_id() == 0) - func(data); - __load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | - PSW_MASK_EA | PSW_MASK_BA); - /* Disable lowcore protection */ - __ctl_clear_bit(0, 28); - current_lc = lowcore_ptr[smp_processor_id()]; - lc = lowcore_ptr[0]; - if (!lc) - lc = current_lc; - lc->restart_psw.mask = - PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA; - lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) smp_restart_cpu; - if (!cpu_online(0)) - smp_switch_to_cpu(func, data, 0, stap(), __cpu_logical_map[0]); - while (sigp(0, sigp_stop_and_store_status) == sigp_busy) - cpu_relax(); - sp = lc->panic_stack; - sp -= sizeof(struct pt_regs); - regs = (struct pt_regs *) sp; - memcpy(®s->gprs, ¤t_lc->gpregs_save_area, sizeof(regs->gprs)); - regs->psw = current_lc->psw_save_area; - sp -= STACK_FRAME_OVERHEAD; - sf = (struct stack_frame *) sp; - sf->back_chain = 0; - smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); + pcpu_sigp_retry(pcpu, sigp_set_prefix, 0); + lowcore_ptr[pcpu - pcpu_devices] = NULL; +#ifndef CONFIG_64BIT + if (MACHINE_HAS_IEEE) { + struct _lowcore *lc = pcpu->lowcore; + + free_page((unsigned long) lc->extended_save_area_addr); + lc->extended_save_area_addr = 0; + } +#else + vdso_free_per_cpu(pcpu->lowcore); +#endif + if (pcpu != &pcpu_devices[0]) { + free_page(pcpu->panic_stack); + free_pages(pcpu->async_stack, ASYNC_ORDER); + free_pages((unsigned long) pcpu->lowcore, LC_ORDER); + } +} + +static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) +{ + struct _lowcore *lc = pcpu->lowcore; + + atomic_inc(&init_mm.context.attach_count); + lc->cpu_nr = cpu; + lc->percpu_offset = __per_cpu_offset[cpu]; + lc->kernel_asce = S390_lowcore.kernel_asce; + lc->machine_flags = S390_lowcore.machine_flags; + lc->ftrace_func = S390_lowcore.ftrace_func; + lc->user_timer = lc->system_timer = lc->steal_timer = 0; + __ctl_store(lc->cregs_save_area, 0, 15); + save_access_regs((unsigned int *) lc->access_regs_save_area); + memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, + MAX_FACILITY_BIT/8); +} + +static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) +{ + struct _lowcore *lc = pcpu->lowcore; + struct thread_info *ti = task_thread_info(tsk); + + lc->kernel_stack = (unsigned long) task_stack_page(tsk) + THREAD_SIZE; + lc->thread_info = (unsigned long) task_thread_info(tsk); + lc->current_task = (unsigned long) tsk; + lc->user_timer = ti->user_timer; + lc->system_timer = ti->system_timer; + lc->steal_timer = 0; +} + +static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data) +{ + struct _lowcore *lc = pcpu->lowcore; + + lc->restart_stack = lc->kernel_stack; + lc->restart_fn = (unsigned long) func; + lc->restart_data = (unsigned long) data; + lc->restart_source = -1UL; + pcpu_sigp_retry(pcpu, sigp_restart, 0); +} + +/* + * Call function via PSW restart on pcpu and stop the current cpu. + */ +static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), + void *data, unsigned long stack) +{ + struct _lowcore *lc = pcpu->lowcore; + unsigned short this_cpu; + + __load_psw_mask(psw_kernel_bits); + this_cpu = stap(); + if (pcpu->address == this_cpu) + func(data); /* should not return */ + /* Stop target cpu (if func returns this stops the current cpu). */ + pcpu_sigp_retry(pcpu, sigp_stop, 0); + /* Restart func on the target cpu and stop the current cpu. */ + lc->restart_stack = stack; + lc->restart_fn = (unsigned long) func; + lc->restart_data = (unsigned long) data; + lc->restart_source = (unsigned long) this_cpu; + asm volatile( + "0: sigp 0,%0,6 # sigp restart to target cpu\n" + " brc 2,0b # busy, try again\n" + "1: sigp 0,%1,5 # sigp stop to current cpu\n" + " brc 2,1b # busy, try again\n" + : : "d" (pcpu->address), "d" (this_cpu) : "0", "1", "cc"); + for (;;) ; +} + +/* + * Call function on an online CPU. + */ +void smp_call_online_cpu(void (*func)(void *), void *data) +{ + struct pcpu *pcpu; + + /* Use the current cpu if it is online. */ + pcpu = pcpu_find_address(cpu_online_mask, stap()); + if (!pcpu) + /* Use the first online cpu. */ + pcpu = pcpu_devices + cpumask_first(cpu_online_mask); + pcpu_delegate(pcpu, func, data, (unsigned long) restart_stack); +} + +/* + * Call function on the ipl CPU. + */ +void smp_call_ipl_cpu(void (*func)(void *), void *data) +{ + pcpu_delegate(&pcpu_devices[0], func, data, + pcpu_devices->panic_stack + PAGE_SIZE); +} + +int smp_find_processor_id(u16 address) +{ + int cpu; + + for_each_present_cpu(cpu) + if (pcpu_devices[cpu].address == address) + return cpu; + return -1; +} + +int smp_vcpu_scheduled(int cpu) +{ + return pcpu_running(pcpu_devices + cpu); +} + +void smp_yield(void) +{ + if (MACHINE_HAS_DIAG44) + asm volatile("diag 0,0,0x44"); } -static void smp_stop_cpu(void) +void smp_yield_cpu(int cpu) { - while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) + if (MACHINE_HAS_DIAG9C) + asm volatile("diag %0,0,0x9c" + : : "d" (pcpu_devices[cpu].address)); + else if (MACHINE_HAS_DIAG44) + asm volatile("diag 0,0,0x44"); +} + +/* + * Send cpus emergency shutdown signal. This gives the cpus the + * opportunity to complete outstanding interrupts. + */ +void smp_emergency_stop(cpumask_t *cpumask) +{ + u64 end; + int cpu; + + end = get_clock() + (1000000UL << 12); + for_each_cpu(cpu, cpumask) { + struct pcpu *pcpu = pcpu_devices + cpu; + set_bit(ec_stop_cpu, &pcpu->ec_mask); + while (__pcpu_sigp(pcpu->address, sigp_emergency_signal, + 0, NULL) == sigp_busy && + get_clock() < end) + cpu_relax(); + } + while (get_clock() < end) { + for_each_cpu(cpu, cpumask) + if (pcpu_stopped(pcpu_devices + cpu)) + cpumask_clear_cpu(cpu, cpumask); + if (cpumask_empty(cpumask)) + break; cpu_relax(); + } } +/* + * Stop all cpus but the current one. + */ void smp_send_stop(void) { cpumask_t cpumask; int cpu; - u64 end; /* Disable all interrupts/machine checks */ __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); trace_hardirqs_off(); + debug_set_critical(); cpumask_copy(&cpumask, cpu_online_mask); cpumask_clear_cpu(smp_processor_id(), &cpumask); - if (oops_in_progress) { - /* - * Give the other cpus the opportunity to complete - * outstanding interrupts before stopping them. - */ - end = get_clock() + (1000000UL << 12); - for_each_cpu(cpu, &cpumask) { - set_bit(ec_stop_cpu, (unsigned long *) - &lowcore_ptr[cpu]->ext_call_fast); - while (sigp(cpu, sigp_emergency_signal) == sigp_busy && - get_clock() < end) - cpu_relax(); - } - while (get_clock() < end) { - for_each_cpu(cpu, &cpumask) - if (cpu_stopped(cpu)) - cpumask_clear_cpu(cpu, &cpumask); - if (cpumask_empty(&cpumask)) - break; - cpu_relax(); - } - } + if (oops_in_progress) + smp_emergency_stop(&cpumask); /* stop all processors */ for_each_cpu(cpu, &cpumask) { - while (sigp(cpu, sigp_stop) == sigp_busy) - cpu_relax(); - while (!cpu_stopped(cpu)) + struct pcpu *pcpu = pcpu_devices + cpu; + pcpu_sigp_retry(pcpu, sigp_stop, 0); + while (!pcpu_stopped(pcpu)) cpu_relax(); } } /* + * Stop the current cpu. + */ +void smp_stop_cpu(void) +{ + pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0); + for (;;) ; +} + +/* * This is the main routine where commands issued by other * cpus are handled. */ - -static void do_ext_call_interrupt(unsigned int ext_int_code, +static void do_ext_call_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { unsigned long bits; + int cpu; - if ((ext_int_code & 0xffff) == 0x1202) - kstat_cpu(smp_processor_id()).irqs[EXTINT_EXC]++; + cpu = smp_processor_id(); + if (ext_code.code == 0x1202) + kstat_cpu(cpu).irqs[EXTINT_EXC]++; else - kstat_cpu(smp_processor_id()).irqs[EXTINT_EMS]++; + kstat_cpu(cpu).irqs[EXTINT_EMS]++; /* * handle bit signal external calls */ - bits = xchg(&S390_lowcore.ext_call_fast, 0); + bits = xchg(&pcpu_devices[cpu].ec_mask, 0); if (test_bit(ec_stop_cpu, &bits)) smp_stop_cpu(); @@ -238,38 +468,17 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, } -/* - * Send an external call sigp to another cpu and return without waiting - * for its completion. - */ -static void smp_ext_bitcall(int cpu, int sig) -{ - int order; - - /* - * Set signaling bit in lowcore of target cpu and kick it - */ - set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); - while (1) { - order = smp_vcpu_scheduled(cpu) ? - sigp_external_call : sigp_emergency_signal; - if (sigp(cpu, order) != sigp_busy) - break; - udelay(10); - } -} - void arch_send_call_function_ipi_mask(const struct cpumask *mask) { int cpu; for_each_cpu(cpu, mask) - smp_ext_bitcall(cpu, ec_call_function); + pcpu_ec_call(pcpu_devices + cpu, ec_call_function); } void arch_send_call_function_single_ipi(int cpu) { - smp_ext_bitcall(cpu, ec_call_function_single); + pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single); } #ifndef CONFIG_64BIT @@ -295,15 +504,16 @@ EXPORT_SYMBOL(smp_ptlb_all); */ void smp_send_reschedule(int cpu) { - smp_ext_bitcall(cpu, ec_schedule); + pcpu_ec_call(pcpu_devices + cpu, ec_schedule); } /* * parameter area for the set/clear control bit callbacks */ struct ec_creg_mask_parms { - unsigned long orvals[16]; - unsigned long andvals[16]; + unsigned long orval; + unsigned long andval; + int cr; }; /* @@ -313,11 +523,9 @@ static void smp_ctl_bit_callback(void *info) { struct ec_creg_mask_parms *pp = info; unsigned long cregs[16]; - int i; __ctl_store(cregs, 0, 15); - for (i = 0; i <= 15; i++) - cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i]; + cregs[pp->cr] = (cregs[pp->cr] & pp->andval) | pp->orval; __ctl_load(cregs, 0, 15); } @@ -326,11 +534,8 @@ static void smp_ctl_bit_callback(void *info) */ void smp_ctl_set_bit(int cr, int bit) { - struct ec_creg_mask_parms parms; + struct ec_creg_mask_parms parms = { 1UL << bit, -1UL, cr }; - memset(&parms.orvals, 0, sizeof(parms.orvals)); - memset(&parms.andvals, 0xff, sizeof(parms.andvals)); - parms.orvals[cr] = 1UL << bit; on_each_cpu(smp_ctl_bit_callback, &parms, 1); } EXPORT_SYMBOL(smp_ctl_set_bit); @@ -340,220 +545,178 @@ EXPORT_SYMBOL(smp_ctl_set_bit); */ void smp_ctl_clear_bit(int cr, int bit) { - struct ec_creg_mask_parms parms; + struct ec_creg_mask_parms parms = { 0, ~(1UL << bit), cr }; - memset(&parms.orvals, 0, sizeof(parms.orvals)); - memset(&parms.andvals, 0xff, sizeof(parms.andvals)); - parms.andvals[cr] = ~(1UL << bit); on_each_cpu(smp_ctl_bit_callback, &parms, 1); } EXPORT_SYMBOL(smp_ctl_clear_bit); #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_CRASH_DUMP) -static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) +struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; +EXPORT_SYMBOL_GPL(zfcpdump_save_areas); + +static void __init smp_get_save_area(int cpu, u16 address) { - if (ipl_info.type != IPL_TYPE_FCP_DUMP && !OLDMEM_BASE) - return; + void *lc = pcpu_devices[0].lowcore; + struct save_area *save_area; + if (is_kdump_kernel()) return; + if (!OLDMEM_BASE && (address == boot_cpu_address || + ipl_info.type != IPL_TYPE_FCP_DUMP)) + return; if (cpu >= NR_CPUS) { - pr_warning("CPU %i exceeds the maximum %i and is excluded from " - "the dump\n", cpu, NR_CPUS - 1); + pr_warning("CPU %i exceeds the maximum %i and is excluded " + "from the dump\n", cpu, NR_CPUS - 1); return; } - zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL); - while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy) - cpu_relax(); - memcpy_real(zfcpdump_save_areas[cpu], - (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, - sizeof(struct save_area)); + save_area = kmalloc(sizeof(struct save_area), GFP_KERNEL); + if (!save_area) + panic("could not allocate memory for save area\n"); + zfcpdump_save_areas[cpu] = save_area; +#ifdef CONFIG_CRASH_DUMP + if (address == boot_cpu_address) { + /* Copy the registers of the boot cpu. */ + copy_oldmem_page(1, (void *) save_area, sizeof(*save_area), + SAVE_AREA_BASE - PAGE_SIZE, 0); + return; + } +#endif + /* Get the registers of a non-boot cpu. */ + __pcpu_sigp_relax(address, sigp_stop_and_store_status, 0, NULL); + memcpy_real(save_area, lc + SAVE_AREA_BASE, sizeof(*save_area)); } -struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; -EXPORT_SYMBOL_GPL(zfcpdump_save_areas); - -#else - -static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { } - -#endif /* CONFIG_ZFCPDUMP */ - -static int cpu_known(int cpu_id) +int smp_store_status(int cpu) { - int cpu; + struct pcpu *pcpu; - for_each_present_cpu(cpu) { - if (__cpu_logical_map[cpu] == cpu_id) - return 1; - } + pcpu = pcpu_devices + cpu; + if (__pcpu_sigp_relax(pcpu->address, sigp_stop_and_store_status, + 0, NULL) != sigp_order_code_accepted) + return -EIO; return 0; } -static int smp_rescan_cpus_sigp(cpumask_t avail) -{ - int cpu_id, logical_cpu; +#else /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */ - logical_cpu = cpumask_first(&avail); - if (logical_cpu >= nr_cpu_ids) - return 0; - for (cpu_id = 0; cpu_id <= MAX_CPU_ADDRESS; cpu_id++) { - if (cpu_known(cpu_id)) - continue; - __cpu_logical_map[logical_cpu] = cpu_id; - cpu_set_polarization(logical_cpu, POLARIZATION_UNKNOWN); - if (!cpu_stopped(logical_cpu)) - continue; - set_cpu_present(logical_cpu, true); - smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; - logical_cpu = cpumask_next(logical_cpu, &avail); - if (logical_cpu >= nr_cpu_ids) - break; - } - return 0; -} +static inline void smp_get_save_area(int cpu, u16 address) { } -static int smp_rescan_cpus_sclp(cpumask_t avail) +#endif /* CONFIG_ZFCPDUMP || CONFIG_CRASH_DUMP */ + +static struct sclp_cpu_info *smp_get_cpu_info(void) { + static int use_sigp_detection; struct sclp_cpu_info *info; - int cpu_id, logical_cpu, cpu; - int rc; - - logical_cpu = cpumask_first(&avail); - if (logical_cpu >= nr_cpu_ids) - return 0; - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - rc = sclp_get_cpu_info(info); - if (rc) - goto out; - for (cpu = 0; cpu < info->combined; cpu++) { - if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type) - continue; - cpu_id = info->cpu[cpu].address; - if (cpu_known(cpu_id)) - continue; - __cpu_logical_map[logical_cpu] = cpu_id; - cpu_set_polarization(logical_cpu, POLARIZATION_UNKNOWN); - set_cpu_present(logical_cpu, true); - if (cpu >= info->configured) - smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; - else - smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; - logical_cpu = cpumask_next(logical_cpu, &avail); - if (logical_cpu >= nr_cpu_ids) - break; + int address; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info && (use_sigp_detection || sclp_get_cpu_info(info))) { + use_sigp_detection = 1; + for (address = 0; address <= MAX_CPU_ADDRESS; address++) { + if (__pcpu_sigp_relax(address, sigp_sense, 0, NULL) == + sigp_not_operational) + continue; + info->cpu[info->configured].address = address; + info->configured++; + } + info->combined = info->configured; } -out: - kfree(info); - return rc; + return info; } -static int __smp_rescan_cpus(void) +static int __devinit smp_add_present_cpu(int cpu); + +static int __devinit __smp_rescan_cpus(struct sclp_cpu_info *info, + int sysfs_add) { + struct pcpu *pcpu; cpumask_t avail; + int cpu, nr, i; + nr = 0; cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask); - if (smp_use_sigp_detection) - return smp_rescan_cpus_sigp(avail); - else - return smp_rescan_cpus_sclp(avail); + cpu = cpumask_first(&avail); + for (i = 0; (i < info->combined) && (cpu < nr_cpu_ids); i++) { + if (info->has_cpu_type && info->cpu[i].type != boot_cpu_type) + continue; + if (pcpu_find_address(cpu_present_mask, info->cpu[i].address)) + continue; + pcpu = pcpu_devices + cpu; + pcpu->address = info->cpu[i].address; + pcpu->state = (cpu >= info->configured) ? + CPU_STATE_STANDBY : CPU_STATE_CONFIGURED; + cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); + set_cpu_present(cpu, true); + if (sysfs_add && smp_add_present_cpu(cpu) != 0) + set_cpu_present(cpu, false); + else + nr++; + cpu = cpumask_next(cpu, &avail); + } + return nr; } static void __init smp_detect_cpus(void) { unsigned int cpu, c_cpus, s_cpus; struct sclp_cpu_info *info; - u16 boot_cpu_addr, cpu_addr; - c_cpus = 1; - s_cpus = 0; - boot_cpu_addr = __cpu_logical_map[0]; - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = smp_get_cpu_info(); if (!info) panic("smp_detect_cpus failed to allocate memory\n"); -#ifdef CONFIG_CRASH_DUMP - if (OLDMEM_BASE && !is_kdump_kernel()) { - struct save_area *save_area; - - save_area = kmalloc(sizeof(*save_area), GFP_KERNEL); - if (!save_area) - panic("could not allocate memory for save area\n"); - copy_oldmem_page(1, (void *) save_area, sizeof(*save_area), - 0x200, 0); - zfcpdump_save_areas[0] = save_area; - } -#endif - /* Use sigp detection algorithm if sclp doesn't work. */ - if (sclp_get_cpu_info(info)) { - smp_use_sigp_detection = 1; - for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) { - if (cpu == boot_cpu_addr) - continue; - if (!raw_cpu_stopped(cpu)) - continue; - smp_get_save_area(c_cpus, cpu); - c_cpus++; - } - goto out; - } - if (info->has_cpu_type) { for (cpu = 0; cpu < info->combined; cpu++) { - if (info->cpu[cpu].address == boot_cpu_addr) { - smp_cpu_type = info->cpu[cpu].type; - break; - } + if (info->cpu[cpu].address != boot_cpu_address) + continue; + /* The boot cpu dictates the cpu type. */ + boot_cpu_type = info->cpu[cpu].type; + break; } } - + c_cpus = s_cpus = 0; for (cpu = 0; cpu < info->combined; cpu++) { - if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type) + if (info->has_cpu_type && info->cpu[cpu].type != boot_cpu_type) continue; - cpu_addr = info->cpu[cpu].address; - if (cpu_addr == boot_cpu_addr) - continue; - if (!raw_cpu_stopped(cpu_addr)) { + if (cpu < info->configured) { + smp_get_save_area(c_cpus, info->cpu[cpu].address); + c_cpus++; + } else s_cpus++; - continue; - } - smp_get_save_area(c_cpus, cpu_addr); - c_cpus++; } -out: - kfree(info); pr_info("%d configured CPUs, %d standby CPUs\n", c_cpus, s_cpus); get_online_cpus(); - __smp_rescan_cpus(); + __smp_rescan_cpus(info, 0); put_online_cpus(); + kfree(info); } /* * Activate a secondary processor. */ -int __cpuinit start_secondary(void *cpuvoid) +static void __cpuinit smp_start_secondary(void *cpuvoid) { + S390_lowcore.last_update_clock = get_clock(); + S390_lowcore.restart_stack = (unsigned long) restart_stack; + S390_lowcore.restart_fn = (unsigned long) do_restart; + S390_lowcore.restart_data = 0; + S390_lowcore.restart_source = -1UL; + restore_access_regs(S390_lowcore.access_regs_save_area); + __ctl_load(S390_lowcore.cregs_save_area, 0, 15); + __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); cpu_init(); preempt_disable(); init_cpu_timer(); init_cpu_vtimer(); pfault_init(); - notify_cpu_starting(smp_processor_id()); ipi_call_lock(); set_cpu_online(smp_processor_id(), true); ipi_call_unlock(); - __ctl_clear_bit(0, 28); /* Disable lowcore protection */ - S390_lowcore.restart_psw.mask = - PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA; - S390_lowcore.restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) psw_restart_int_handler; - __ctl_set_bit(0, 28); /* Enable lowcore protection */ local_irq_enable(); /* cpu_idle will call schedule for us */ cpu_idle(); - return 0; } struct create_idle { @@ -572,82 +735,20 @@ static void __cpuinit smp_fork_idle(struct work_struct *work) complete(&c_idle->done); } -static int __cpuinit smp_alloc_lowcore(int cpu) -{ - unsigned long async_stack, panic_stack; - struct _lowcore *lowcore; - - lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); - if (!lowcore) - return -ENOMEM; - async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); - panic_stack = __get_free_page(GFP_KERNEL); - if (!panic_stack || !async_stack) - goto out; - memcpy(lowcore, &S390_lowcore, 512); - memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512); - lowcore->async_stack = async_stack + ASYNC_SIZE; - lowcore->panic_stack = panic_stack + PAGE_SIZE; - lowcore->restart_psw.mask = - PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA; - lowcore->restart_psw.addr = - PSW_ADDR_AMODE | (unsigned long) restart_int_handler; - if (user_mode != HOME_SPACE_MODE) - lowcore->restart_psw.mask |= PSW_ASC_HOME; -#ifndef CONFIG_64BIT - if (MACHINE_HAS_IEEE) { - unsigned long save_area; - - save_area = get_zeroed_page(GFP_KERNEL); - if (!save_area) - goto out; - lowcore->extended_save_area_addr = (u32) save_area; - } -#else - if (vdso_alloc_per_cpu(cpu, lowcore)) - goto out; -#endif - lowcore_ptr[cpu] = lowcore; - return 0; - -out: - free_page(panic_stack); - free_pages(async_stack, ASYNC_ORDER); - free_pages((unsigned long) lowcore, LC_ORDER); - return -ENOMEM; -} - -static void smp_free_lowcore(int cpu) -{ - struct _lowcore *lowcore; - - lowcore = lowcore_ptr[cpu]; -#ifndef CONFIG_64BIT - if (MACHINE_HAS_IEEE) - free_page((unsigned long) lowcore->extended_save_area_addr); -#else - vdso_free_per_cpu(cpu, lowcore); -#endif - free_page(lowcore->panic_stack - PAGE_SIZE); - free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER); - free_pages((unsigned long) lowcore, LC_ORDER); - lowcore_ptr[cpu] = NULL; -} - /* Upping and downing of CPUs */ int __cpuinit __cpu_up(unsigned int cpu) { - struct _lowcore *cpu_lowcore; struct create_idle c_idle; - struct task_struct *idle; - struct stack_frame *sf; - u32 lowcore; - int ccode; + struct pcpu *pcpu; + int rc; - if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED) + pcpu = pcpu_devices + cpu; + if (pcpu->state != CPU_STATE_CONFIGURED) + return -EIO; + if (pcpu_sigp_retry(pcpu, sigp_initial_cpu_reset, 0) != + sigp_order_code_accepted) return -EIO; - idle = current_set[cpu]; - if (!idle) { + if (!pcpu->idle) { c_idle.done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done); INIT_WORK_ONSTACK(&c_idle.work, smp_fork_idle); c_idle.cpu = cpu; @@ -655,68 +756,28 @@ int __cpuinit __cpu_up(unsigned int cpu) wait_for_completion(&c_idle.done); if (IS_ERR(c_idle.idle)) return PTR_ERR(c_idle.idle); - idle = c_idle.idle; - current_set[cpu] = c_idle.idle; + pcpu->idle = c_idle.idle; } - init_idle(idle, cpu); - if (smp_alloc_lowcore(cpu)) - return -ENOMEM; - do { - ccode = sigp(cpu, sigp_initial_cpu_reset); - if (ccode == sigp_busy) - udelay(10); - if (ccode == sigp_not_operational) - goto err_out; - } while (ccode == sigp_busy); - - lowcore = (u32)(unsigned long)lowcore_ptr[cpu]; - while (sigp_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) - udelay(10); - - cpu_lowcore = lowcore_ptr[cpu]; - cpu_lowcore->kernel_stack = (unsigned long) - task_stack_page(idle) + THREAD_SIZE; - cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle); - sf = (struct stack_frame *) (cpu_lowcore->kernel_stack - - sizeof(struct pt_regs) - - sizeof(struct stack_frame)); - memset(sf, 0, sizeof(struct stack_frame)); - sf->gprs[9] = (unsigned long) sf; - cpu_lowcore->gpregs_save_area[15] = (unsigned long) sf; - __ctl_store(cpu_lowcore->cregs_save_area, 0, 15); - atomic_inc(&init_mm.context.attach_count); - asm volatile( - " stam 0,15,0(%0)" - : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); - cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; - cpu_lowcore->current_task = (unsigned long) idle; - cpu_lowcore->cpu_nr = cpu; - cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; - cpu_lowcore->machine_flags = S390_lowcore.machine_flags; - cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func; - memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list, - MAX_FACILITY_BIT/8); - eieio(); - - while (sigp(cpu, sigp_restart) == sigp_busy) - udelay(10); - + init_idle(pcpu->idle, cpu); + rc = pcpu_alloc_lowcore(pcpu, cpu); + if (rc) + return rc; + pcpu_prepare_secondary(pcpu, cpu); + pcpu_attach_task(pcpu, pcpu->idle); + pcpu_start_fn(pcpu, smp_start_secondary, NULL); while (!cpu_online(cpu)) cpu_relax(); return 0; - -err_out: - smp_free_lowcore(cpu); - return -EIO; } static int __init setup_possible_cpus(char *s) { - int pcpus, cpu; + int max, cpu; - pcpus = simple_strtoul(s, NULL, 0); + if (kstrtoint(s, 0, &max) < 0) + return 0; init_cpu_possible(cpumask_of(0)); - for (cpu = 1; cpu < pcpus && cpu < nr_cpu_ids; cpu++) + for (cpu = 1; cpu < max && cpu < nr_cpu_ids; cpu++) set_cpu_possible(cpu, true); return 0; } @@ -726,113 +787,79 @@ early_param("possible_cpus", setup_possible_cpus); int __cpu_disable(void) { - struct ec_creg_mask_parms cr_parms; - int cpu = smp_processor_id(); - - set_cpu_online(cpu, false); + unsigned long cregs[16]; - /* Disable pfault pseudo page faults on this cpu. */ + set_cpu_online(smp_processor_id(), false); + /* Disable pseudo page faults on this cpu. */ pfault_fini(); - - memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); - memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); - - /* disable all external interrupts */ - cr_parms.orvals[0] = 0; - cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 | - 1 << 10 | 1 << 9 | 1 << 6 | 1 << 5 | - 1 << 4); - /* disable all I/O interrupts */ - cr_parms.orvals[6] = 0; - cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | - 1 << 27 | 1 << 26 | 1 << 25 | 1 << 24); - /* disable most machine checks */ - cr_parms.orvals[14] = 0; - cr_parms.andvals[14] = ~(1 << 28 | 1 << 27 | 1 << 26 | - 1 << 25 | 1 << 24); - - smp_ctl_bit_callback(&cr_parms); - + /* Disable interrupt sources via control register. */ + __ctl_store(cregs, 0, 15); + cregs[0] &= ~0x0000ee70UL; /* disable all external interrupts */ + cregs[6] &= ~0xff000000UL; /* disable all I/O interrupts */ + cregs[14] &= ~0x1f000000UL; /* disable most machine checks */ + __ctl_load(cregs, 0, 15); return 0; } void __cpu_die(unsigned int cpu) { + struct pcpu *pcpu; + /* Wait until target cpu is down */ - while (!cpu_stopped(cpu)) + pcpu = pcpu_devices + cpu; + while (!pcpu_stopped(pcpu)) cpu_relax(); - while (sigp_p(0, cpu, sigp_set_prefix) == sigp_busy) - udelay(10); - smp_free_lowcore(cpu); + pcpu_free_lowcore(pcpu); atomic_dec(&init_mm.context.attach_count); } void __noreturn cpu_die(void) { idle_task_exit(); - while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) - cpu_relax(); - for (;;); + pcpu_sigp_retry(pcpu_devices + smp_processor_id(), sigp_stop, 0); + for (;;) ; } #endif /* CONFIG_HOTPLUG_CPU */ -void __init smp_prepare_cpus(unsigned int max_cpus) +static void smp_call_os_info_init_fn(void) { -#ifndef CONFIG_64BIT - unsigned long save_area = 0; -#endif - unsigned long async_stack, panic_stack; - struct _lowcore *lowcore; + int (*init_fn)(void); + unsigned long size; - smp_detect_cpus(); + init_fn = os_info_old_entry(OS_INFO_INIT_FN, &size); + if (!init_fn) + return; + init_fn(); +} +void __init smp_prepare_cpus(unsigned int max_cpus) +{ /* request the 0x1201 emergency signal external interrupt */ if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1201"); /* request the 0x1202 external call external interrupt */ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1202"); - - /* Reallocate current lowcore, but keep its contents. */ - lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); - panic_stack = __get_free_page(GFP_KERNEL); - async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER); - BUG_ON(!lowcore || !panic_stack || !async_stack); -#ifndef CONFIG_64BIT - if (MACHINE_HAS_IEEE) - save_area = get_zeroed_page(GFP_KERNEL); -#endif - local_irq_disable(); - local_mcck_disable(); - lowcore_ptr[smp_processor_id()] = lowcore; - *lowcore = S390_lowcore; - lowcore->panic_stack = panic_stack + PAGE_SIZE; - lowcore->async_stack = async_stack + ASYNC_SIZE; -#ifndef CONFIG_64BIT - if (MACHINE_HAS_IEEE) - lowcore->extended_save_area_addr = (u32) save_area; -#endif - set_prefix((u32)(unsigned long) lowcore); - local_mcck_enable(); - local_irq_enable(); -#ifdef CONFIG_64BIT - if (vdso_alloc_per_cpu(smp_processor_id(), &S390_lowcore)) - BUG(); -#endif + smp_call_os_info_init_fn(); + smp_detect_cpus(); } void __init smp_prepare_boot_cpu(void) { - BUG_ON(smp_processor_id() != 0); - - current_thread_info()->cpu = 0; - set_cpu_present(0, true); - set_cpu_online(0, true); + struct pcpu *pcpu = pcpu_devices; + + boot_cpu_address = stap(); + pcpu->idle = current; + pcpu->state = CPU_STATE_CONFIGURED; + pcpu->address = boot_cpu_address; + pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix(); + pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE; + pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE; S390_lowcore.percpu_offset = __per_cpu_offset[0]; - current_set[0] = current; - smp_cpu_state[0] = CPU_STATE_CONFIGURED; cpu_set_polarization(0, POLARIZATION_UNKNOWN); + set_cpu_present(0, true); + set_cpu_online(0, true); } void __init smp_cpus_done(unsigned int max_cpus) @@ -842,7 +869,6 @@ void __init smp_cpus_done(unsigned int max_cpus) void __init smp_setup_processor_id(void) { S390_lowcore.cpu_nr = 0; - __cpu_logical_map[0] = stap(); } /* @@ -858,56 +884,57 @@ int setup_profiling_timer(unsigned int multiplier) #ifdef CONFIG_HOTPLUG_CPU static ssize_t cpu_configure_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { ssize_t count; mutex_lock(&smp_cpu_state_mutex); - count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]); + count = sprintf(buf, "%d\n", pcpu_devices[dev->id].state); mutex_unlock(&smp_cpu_state_mutex); return count; } static ssize_t cpu_configure_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - int cpu = dev->id; - int val, rc; + struct pcpu *pcpu; + int cpu, val, rc; char delim; if (sscanf(buf, "%d %c", &val, &delim) != 1) return -EINVAL; if (val != 0 && val != 1) return -EINVAL; - get_online_cpus(); mutex_lock(&smp_cpu_state_mutex); rc = -EBUSY; /* disallow configuration changes of online cpus and cpu 0 */ + cpu = dev->id; if (cpu_online(cpu) || cpu == 0) goto out; + pcpu = pcpu_devices + cpu; rc = 0; switch (val) { case 0: - if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) { - rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); - if (!rc) { - smp_cpu_state[cpu] = CPU_STATE_STANDBY; - cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); - topology_expect_change(); - } - } + if (pcpu->state != CPU_STATE_CONFIGURED) + break; + rc = sclp_cpu_deconfigure(pcpu->address); + if (rc) + break; + pcpu->state = CPU_STATE_STANDBY; + cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); + topology_expect_change(); break; case 1: - if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) { - rc = sclp_cpu_configure(__cpu_logical_map[cpu]); - if (!rc) { - smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; - cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); - topology_expect_change(); - } - } + if (pcpu->state != CPU_STATE_STANDBY) + break; + rc = sclp_cpu_configure(pcpu->address); + if (rc) + break; + pcpu->state = CPU_STATE_CONFIGURED; + cpu_set_polarization(cpu, POLARIZATION_UNKNOWN); + topology_expect_change(); break; default: break; @@ -923,7 +950,7 @@ static DEVICE_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); static ssize_t show_cpu_address(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]); + return sprintf(buf, "%d\n", pcpu_devices[dev->id].address); } static DEVICE_ATTR(address, 0444, show_cpu_address, NULL); @@ -955,22 +982,16 @@ static DEVICE_ATTR(capability, 0444, show_capability, NULL); static ssize_t show_idle_count(struct device *dev, struct device_attribute *attr, char *buf) { - struct s390_idle_data *idle; + struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); unsigned long long idle_count; unsigned int sequence; - idle = &per_cpu(s390_idle, dev->id); -repeat: - sequence = idle->sequence; - smp_rmb(); - if (sequence & 1) - goto repeat; - idle_count = idle->idle_count; - if (idle->idle_enter) - idle_count++; - smp_rmb(); - if (idle->sequence != sequence) - goto repeat; + do { + sequence = ACCESS_ONCE(idle->sequence); + idle_count = ACCESS_ONCE(idle->idle_count); + if (ACCESS_ONCE(idle->idle_enter)) + idle_count++; + } while ((sequence & 1) || (idle->sequence != sequence)); return sprintf(buf, "%llu\n", idle_count); } static DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL); @@ -978,24 +999,18 @@ static DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL); static ssize_t show_idle_time(struct device *dev, struct device_attribute *attr, char *buf) { - struct s390_idle_data *idle; - unsigned long long now, idle_time, idle_enter; + struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); + unsigned long long now, idle_time, idle_enter, idle_exit; unsigned int sequence; - idle = &per_cpu(s390_idle, dev->id); - now = get_clock(); -repeat: - sequence = idle->sequence; - smp_rmb(); - if (sequence & 1) - goto repeat; - idle_time = idle->idle_time; - idle_enter = idle->idle_enter; - if (idle_enter != 0ULL && idle_enter < now) - idle_time += now - idle_enter; - smp_rmb(); - if (idle->sequence != sequence) - goto repeat; + do { + now = get_clock(); + sequence = ACCESS_ONCE(idle->sequence); + idle_time = ACCESS_ONCE(idle->idle_time); + idle_enter = ACCESS_ONCE(idle->idle_enter); + idle_exit = ACCESS_ONCE(idle->idle_exit); + } while ((sequence & 1) || (idle->sequence != sequence)); + idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; return sprintf(buf, "%llu\n", idle_time >> 12); } static DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL); @@ -1015,7 +1030,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned int)(long)hcpu; - struct cpu *c = &per_cpu(cpu_devices, cpu); + struct cpu *c = &pcpu_devices[cpu].cpu; struct device *s = &c->dev; struct s390_idle_data *idle; int err = 0; @@ -1041,7 +1056,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = { static int __devinit smp_add_present_cpu(int cpu) { - struct cpu *c = &per_cpu(cpu_devices, cpu); + struct cpu *c = &pcpu_devices[cpu].cpu; struct device *s = &c->dev; int rc; @@ -1079,29 +1094,21 @@ out: int __ref smp_rescan_cpus(void) { - cpumask_t newcpus; - int cpu; - int rc; + struct sclp_cpu_info *info; + int nr; + info = smp_get_cpu_info(); + if (!info) + return -ENOMEM; get_online_cpus(); mutex_lock(&smp_cpu_state_mutex); - cpumask_copy(&newcpus, cpu_present_mask); - rc = __smp_rescan_cpus(); - if (rc) - goto out; - cpumask_andnot(&newcpus, cpu_present_mask, &newcpus); - for_each_cpu(cpu, &newcpus) { - rc = smp_add_present_cpu(cpu); - if (rc) - set_cpu_present(cpu, false); - } - rc = 0; -out: + nr = __smp_rescan_cpus(info, 1); mutex_unlock(&smp_cpu_state_mutex); put_online_cpus(); - if (!cpumask_empty(&newcpus)) + kfree(info); + if (nr) topology_schedule_update(); - return rc; + return 0; } static ssize_t __ref rescan_store(struct device *dev, diff --git a/arch/s390/kernel/switch_cpu.S b/arch/s390/kernel/switch_cpu.S deleted file mode 100644 index bfe070bc7659..000000000000 --- a/arch/s390/kernel/switch_cpu.S +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 31-bit switch cpu code - * - * Copyright IBM Corp. 2009 - * - */ - -#include <linux/linkage.h> -#include <asm/asm-offsets.h> -#include <asm/ptrace.h> - -# smp_switch_to_cpu switches to destination cpu and executes the passed function -# Parameter: %r2 - function to call -# %r3 - function parameter -# %r4 - stack poiner -# %r5 - current cpu -# %r6 - destination cpu - - .section .text -ENTRY(smp_switch_to_cpu) - stm %r6,%r15,__SF_GPRS(%r15) - lr %r1,%r15 - ahi %r15,-STACK_FRAME_OVERHEAD - st %r1,__SF_BACKCHAIN(%r15) - basr %r13,0 -0: la %r1,.gprregs_addr-0b(%r13) - l %r1,0(%r1) - stm %r0,%r15,0(%r1) -1: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */ - brc 2,1b /* busy, try again */ -2: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */ - brc 2,2b /* busy, try again */ -3: j 3b - -ENTRY(smp_restart_cpu) - basr %r13,0 -0: la %r1,.gprregs_addr-0b(%r13) - l %r1,0(%r1) - lm %r0,%r15,0(%r1) -1: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */ - brc 10,1b /* busy, accepted (status 0), running */ - tmll %r0,0x40 /* Test if calling CPU is stopped */ - jz 1b - ltr %r4,%r4 /* New stack ? */ - jz 1f - lr %r15,%r4 -1: lr %r14,%r2 /* r14: Function to call */ - lr %r2,%r3 /* r2 : Parameter for function*/ - basr %r14,%r14 /* Call function */ - -.gprregs_addr: - .long .gprregs - - .section .data,"aw",@progbits -.gprregs: - .rept 16 - .long 0 - .endr diff --git a/arch/s390/kernel/switch_cpu64.S b/arch/s390/kernel/switch_cpu64.S deleted file mode 100644 index fcc42d799e41..000000000000 --- a/arch/s390/kernel/switch_cpu64.S +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 64-bit switch cpu code - * - * Copyright IBM Corp. 2009 - * - */ - -#include <linux/linkage.h> -#include <asm/asm-offsets.h> -#include <asm/ptrace.h> - -# smp_switch_to_cpu switches to destination cpu and executes the passed function -# Parameter: %r2 - function to call -# %r3 - function parameter -# %r4 - stack poiner -# %r5 - current cpu -# %r6 - destination cpu - - .section .text -ENTRY(smp_switch_to_cpu) - stmg %r6,%r15,__SF_GPRS(%r15) - lgr %r1,%r15 - aghi %r15,-STACK_FRAME_OVERHEAD - stg %r1,__SF_BACKCHAIN(%r15) - larl %r1,.gprregs - stmg %r0,%r15,0(%r1) -1: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */ - brc 2,1b /* busy, try again */ -2: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */ - brc 2,2b /* busy, try again */ -3: j 3b - -ENTRY(smp_restart_cpu) - larl %r1,.gprregs - lmg %r0,%r15,0(%r1) -1: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */ - brc 10,1b /* busy, accepted (status 0), running */ - tmll %r0,0x40 /* Test if calling CPU is stopped */ - jz 1b - ltgr %r4,%r4 /* New stack ? */ - jz 1f - lgr %r15,%r4 -1: lgr %r14,%r2 /* r14: Function to call */ - lgr %r2,%r3 /* r2 : Parameter for function*/ - basr %r14,%r14 /* Call function */ - - .section .data,"aw",@progbits -.gprregs: - .rept 16 - .quad 0 - .endr diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index acb78cdee896..dd70ef046058 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -42,7 +42,7 @@ ENTRY(swsusp_arch_suspend) lghi %r1,0x1000 /* Save CPU address */ - stap __LC_CPU_ADDRESS(%r0) + stap __LC_EXT_CPU_ADDR(%r0) /* Store registers */ mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */ @@ -173,15 +173,15 @@ pgm_check_entry: larl %r1,.Lresume_cpu /* Resume CPU address: r2 */ stap 0(%r1) llgh %r2,0(%r1) - llgh %r1,__LC_CPU_ADDRESS(%r0) /* Suspend CPU address: r1 */ + llgh %r1,__LC_EXT_CPU_ADDR(%r0) /* Suspend CPU address: r1 */ cgr %r1,%r2 je restore_registers /* r1 = r2 -> nothing to do */ larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 3: - sigp %r9,%r1,__SIGP_INITIAL_CPU_RESET - brc 8,4f /* accepted */ - brc 2,3b /* busy, try again */ + sigp %r9,%r1,11 /* sigp initial cpu reset */ + brc 8,4f /* accepted */ + brc 2,3b /* busy, try again */ /* Suspend CPU not available -> panic */ larl %r15,init_thread_union @@ -196,10 +196,10 @@ pgm_check_entry: lpsw 0(%r3) 4: /* Switch to suspend CPU */ - sigp %r9,%r1,__SIGP_RESTART /* start suspend CPU */ + sigp %r9,%r1,6 /* sigp restart to suspend CPU */ brc 2,4b /* busy, try again */ 5: - sigp %r9,%r2,__SIGP_STOP /* stop resume (current) CPU */ + sigp %r9,%r2,5 /* sigp stop to current resume CPU */ brc 2,5b /* busy, try again */ 6: j 6b @@ -207,7 +207,7 @@ restart_suspend: larl %r1,.Lresume_cpu llgh %r2,0(%r1) 7: - sigp %r9,%r2,__SIGP_SENSE /* Wait for resume CPU */ + sigp %r9,%r2,1 /* sigp sense, wait for resume CPU */ brc 8,7b /* accepted, status 0, still running */ brc 2,7b /* busy, try again */ tmll %r9,0x40 /* Test if resume CPU is stopped */ @@ -257,6 +257,9 @@ restore_registers: lghi %r2,0 brasl %r14,arch_set_page_states + /* Log potential guest relocation */ + brasl %r14,lgr_info_log + /* Reinitialize the channel subsystem */ brasl %r14,channel_subsystem_reinit diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 14da278febbf..d4e1cb1dbcd1 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -165,7 +165,7 @@ void init_cpu_timer(void) __ctl_set_bit(0, 4); } -static void clock_comparator_interrupt(unsigned int ext_int_code, +static void clock_comparator_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { @@ -177,7 +177,7 @@ static void clock_comparator_interrupt(unsigned int ext_int_code, static void etr_timing_alert(struct etr_irq_parm *); static void stp_timing_alert(struct stp_irq_parm *); -static void timing_alert_interrupt(unsigned int ext_int_code, +static void timing_alert_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { kstat_cpu(smp_processor_id()).irqs[EXTINT_TLA]++; diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 7370a41948ca..4f8dc942257c 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -79,12 +79,12 @@ static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu, cpu < TOPOLOGY_CPU_BITS; cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1)) { - unsigned int rcpu, lcpu; + unsigned int rcpu; + int lcpu; rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin; - for_each_present_cpu(lcpu) { - if (cpu_logical_map(lcpu) != rcpu) - continue; + lcpu = smp_find_processor_id(rcpu); + if (lcpu >= 0) { cpumask_set_cpu(lcpu, &book->mask); cpu_book_id[lcpu] = book->id; cpumask_set_cpu(lcpu, &core->mask); diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 5ce3750b181f..cd6ebe12c481 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -41,6 +41,7 @@ #include <asm/cpcmd.h> #include <asm/lowcore.h> #include <asm/debug.h> +#include <asm/ipl.h> #include "entry.h" void (*pgm_check_table[128])(struct pt_regs *regs); @@ -144,8 +145,8 @@ void show_stack(struct task_struct *task, unsigned long *sp) for (i = 0; i < kstack_depth_to_print; i++) { if (((addr_t) stack & (THREAD_SIZE-1)) == 0) break; - if (i && ((i * sizeof (long) % 32) == 0)) - printk("\n "); + if ((i * sizeof(long) % 32) == 0) + printk("%s ", i == 0 ? "" : "\n"); printk(LONG, *stack++); } printk("\n"); @@ -239,6 +240,7 @@ void die(struct pt_regs *regs, const char *str) static int die_counter; oops_enter(); + lgr_info_log(); debug_stop_all(); console_verbose(); spin_lock_irq(&die_lock); diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index d73630b4fe1d..e704a9965f90 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -89,18 +89,11 @@ static void vdso_init_data(struct vdso_data *vd) #ifdef CONFIG_64BIT /* - * Setup per cpu vdso data page. - */ -static void vdso_init_per_cpu_data(int cpu, struct vdso_per_cpu_data *vpcd) -{ -} - -/* * Allocate/free per cpu vdso data. */ #define SEGMENT_ORDER 2 -int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) +int vdso_alloc_per_cpu(struct _lowcore *lowcore) { unsigned long segment_table, page_table, page_frame; u32 *psal, *aste; @@ -139,7 +132,6 @@ int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) aste[4] = (u32)(addr_t) psal; lowcore->vdso_per_cpu_data = page_frame; - vdso_init_per_cpu_data(cpu, (struct vdso_per_cpu_data *) page_frame); return 0; out: @@ -149,7 +141,7 @@ out: return -ENOMEM; } -void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore) +void vdso_free_per_cpu(struct _lowcore *lowcore) { unsigned long segment_table, page_table, page_frame; u32 *psal, *aste; @@ -168,19 +160,15 @@ void vdso_free_per_cpu(int cpu, struct _lowcore *lowcore) free_pages(segment_table, SEGMENT_ORDER); } -static void __vdso_init_cr5(void *dummy) +static void vdso_init_cr5(void) { unsigned long cr5; + if (user_mode == HOME_SPACE_MODE || !vdso_enabled) + return; cr5 = offsetof(struct _lowcore, paste); __ctl_load(cr5, 5, 5); } - -static void vdso_init_cr5(void) -{ - if (user_mode != HOME_SPACE_MODE && vdso_enabled) - on_each_cpu(__vdso_init_cr5, NULL, 1); -} #endif /* CONFIG_64BIT */ /* @@ -322,10 +310,8 @@ static int __init vdso_init(void) } vdso64_pagelist[vdso64_pages - 1] = virt_to_page(vdso_data); vdso64_pagelist[vdso64_pages] = NULL; -#ifndef CONFIG_SMP - if (vdso_alloc_per_cpu(0, &S390_lowcore)) + if (vdso_alloc_per_cpu(&S390_lowcore)) BUG(); -#endif vdso_init_cr5(); #endif /* CONFIG_64BIT */ @@ -335,7 +321,7 @@ static int __init vdso_init(void) return 0; } -arch_initcall(vdso_init); +early_initcall(vdso_init); int in_gate_area_no_mm(unsigned long addr) { diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index bb48977f5469..39ebff506946 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -26,6 +26,7 @@ #include <asm/irq_regs.h> #include <asm/cputime.h> #include <asm/irq.h> +#include "entry.h" static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); @@ -123,153 +124,53 @@ void account_system_vtime(struct task_struct *tsk) } EXPORT_SYMBOL_GPL(account_system_vtime); -void __kprobes vtime_start_cpu(__u64 int_clock, __u64 enter_timer) +void __kprobes vtime_stop_cpu(void) { struct s390_idle_data *idle = &__get_cpu_var(s390_idle); struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); - __u64 idle_time, expires; + unsigned long long idle_time; + unsigned long psw_mask; - if (idle->idle_enter == 0ULL) - return; + trace_hardirqs_on(); + /* Don't trace preempt off for idle. */ + stop_critical_timings(); - /* Account time spent with enabled wait psw loaded as idle time. */ - idle_time = int_clock - idle->idle_enter; - account_idle_time(idle_time); - S390_lowcore.steal_timer += - idle->idle_enter - S390_lowcore.last_update_clock; - S390_lowcore.last_update_clock = int_clock; - - /* Account system time spent going idle. */ - S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle; - S390_lowcore.last_update_timer = enter_timer; - - /* Restart vtime CPU timer */ - if (vq->do_spt) { - /* Program old expire value but first save progress. */ - expires = vq->idle - enter_timer; - expires += get_vtimer(); - set_vtimer(expires); - } else { - /* Don't account the CPU timer delta while the cpu was idle. */ - vq->elapsed -= vq->idle - enter_timer; - } + /* Wait for external, I/O or machine check interrupt. */ + psw_mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_DAT | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; + idle->nohz_delay = 0; + /* Call the assembler magic in entry.S */ + psw_idle(idle, vq, psw_mask, !list_empty(&vq->list)); + + /* Reenable preemption tracer. */ + start_critical_timings(); + + /* Account time spent with enabled wait psw loaded as idle time. */ idle->sequence++; smp_wmb(); + idle_time = idle->idle_exit - idle->idle_enter; idle->idle_time += idle_time; - idle->idle_enter = 0ULL; + idle->idle_enter = idle->idle_exit = 0ULL; idle->idle_count++; + account_idle_time(idle_time); smp_wmb(); idle->sequence++; } -void __kprobes vtime_stop_cpu(void) -{ - struct s390_idle_data *idle = &__get_cpu_var(s390_idle); - struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); - psw_t psw; - - /* Wait for external, I/O or machine check interrupt. */ - psw.mask = psw_kernel_bits | PSW_MASK_WAIT | - PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; - - idle->nohz_delay = 0; - - /* Check if the CPU timer needs to be reprogrammed. */ - if (vq->do_spt) { - __u64 vmax = VTIMER_MAX_SLICE; - /* - * The inline assembly is equivalent to - * vq->idle = get_cpu_timer(); - * set_cpu_timer(VTIMER_MAX_SLICE); - * idle->idle_enter = get_clock(); - * __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | - * PSW_MASK_DAT | PSW_MASK_IO | - * PSW_MASK_EXT | PSW_MASK_MCHECK); - * The difference is that the inline assembly makes sure that - * the last three instruction are stpt, stck and lpsw in that - * order. This is done to increase the precision. - */ - asm volatile( -#ifndef CONFIG_64BIT - " basr 1,0\n" - "0: ahi 1,1f-0b\n" - " st 1,4(%2)\n" -#else /* CONFIG_64BIT */ - " larl 1,1f\n" - " stg 1,8(%2)\n" -#endif /* CONFIG_64BIT */ - " stpt 0(%4)\n" - " spt 0(%5)\n" - " stck 0(%3)\n" -#ifndef CONFIG_64BIT - " lpsw 0(%2)\n" -#else /* CONFIG_64BIT */ - " lpswe 0(%2)\n" -#endif /* CONFIG_64BIT */ - "1:" - : "=m" (idle->idle_enter), "=m" (vq->idle) - : "a" (&psw), "a" (&idle->idle_enter), - "a" (&vq->idle), "a" (&vmax), "m" (vmax), "m" (psw) - : "memory", "cc", "1"); - } else { - /* - * The inline assembly is equivalent to - * vq->idle = get_cpu_timer(); - * idle->idle_enter = get_clock(); - * __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | - * PSW_MASK_DAT | PSW_MASK_IO | - * PSW_MASK_EXT | PSW_MASK_MCHECK); - * The difference is that the inline assembly makes sure that - * the last three instruction are stpt, stck and lpsw in that - * order. This is done to increase the precision. - */ - asm volatile( -#ifndef CONFIG_64BIT - " basr 1,0\n" - "0: ahi 1,1f-0b\n" - " st 1,4(%2)\n" -#else /* CONFIG_64BIT */ - " larl 1,1f\n" - " stg 1,8(%2)\n" -#endif /* CONFIG_64BIT */ - " stpt 0(%4)\n" - " stck 0(%3)\n" -#ifndef CONFIG_64BIT - " lpsw 0(%2)\n" -#else /* CONFIG_64BIT */ - " lpswe 0(%2)\n" -#endif /* CONFIG_64BIT */ - "1:" - : "=m" (idle->idle_enter), "=m" (vq->idle) - : "a" (&psw), "a" (&idle->idle_enter), - "a" (&vq->idle), "m" (psw) - : "memory", "cc", "1"); - } -} - cputime64_t s390_get_idle_time(int cpu) { - struct s390_idle_data *idle; - unsigned long long now, idle_time, idle_enter; + struct s390_idle_data *idle = &per_cpu(s390_idle, cpu); + unsigned long long now, idle_enter, idle_exit; unsigned int sequence; - idle = &per_cpu(s390_idle, cpu); - - now = get_clock(); -repeat: - sequence = idle->sequence; - smp_rmb(); - if (sequence & 1) - goto repeat; - idle_time = 0; - idle_enter = idle->idle_enter; - if (idle_enter != 0ULL && idle_enter < now) - idle_time = now - idle_enter; - smp_rmb(); - if (idle->sequence != sequence) - goto repeat; - return idle_time; + do { + now = get_clock(); + sequence = ACCESS_ONCE(idle->sequence); + idle_enter = ACCESS_ONCE(idle->idle_enter); + idle_exit = ACCESS_ONCE(idle->idle_exit); + } while ((sequence & 1) || (idle->sequence != sequence)); + return idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; } /* @@ -319,7 +220,7 @@ static void do_callbacks(struct list_head *cb_list) /* * Handler for the virtual CPU timer. */ -static void do_cpu_timer_interrupt(unsigned int ext_int_code, +static void do_cpu_timer_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct vtimer_queue *vq; @@ -346,7 +247,6 @@ static void do_cpu_timer_interrupt(unsigned int ext_int_code, } spin_unlock(&vq->lock); - vq->do_spt = list_empty(&cb_list); do_callbacks(&cb_list); /* next event is first in list */ @@ -355,8 +255,7 @@ static void do_cpu_timer_interrupt(unsigned int ext_int_code, if (!list_empty(&vq->list)) { event = list_first_entry(&vq->list, struct vtimer_list, entry); next = event->expires; - } else - vq->do_spt = 0; + } spin_unlock(&vq->lock); /* * To improve precision add the time spent by the @@ -570,6 +469,9 @@ void init_cpu_vtimer(void) /* enable cpu timer interrupts */ __ctl_set_bit(0,10); + + /* set initial cpu timer */ + set_vtimer(0x7fffffffffffffffULL); } static int __cpuinit s390_nohz_notify(struct notifier_block *self, diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 278ee009ce65..f0647ce6da21 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -134,7 +134,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, if (rc == -EFAULT) exception = 1; - rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->emerg.code); + rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->emerg.code); if (rc == -EFAULT) exception = 1; @@ -156,7 +156,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, if (rc == -EFAULT) exception = 1; - rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->extcall.code); + rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, inti->extcall.code); if (rc == -EFAULT) exception = 1; @@ -202,7 +202,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, if (rc == -EFAULT) exception = 1; - rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00); + rc = put_guest_u16(vcpu, __LC_EXT_CPU_ADDR, 0x0d00); if (rc == -EFAULT) exception = 1; diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index db92f044024c..9f1f71e85778 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -13,6 +13,7 @@ #include <linux/irqflags.h> #include <linux/interrupt.h> #include <asm/div64.h> +#include <asm/timer.h> void __delay(unsigned long loops) { @@ -28,36 +29,33 @@ void __delay(unsigned long loops) static void __udelay_disabled(unsigned long long usecs) { - unsigned long mask, cr0, cr0_saved; - u64 clock_saved; - u64 end; + unsigned long cr0, cr6, new; + u64 clock_saved, end; - mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_WAIT | - PSW_MASK_EXT | PSW_MASK_MCHECK; end = get_clock() + (usecs << 12); clock_saved = local_tick_disable(); - __ctl_store(cr0_saved, 0, 0); - cr0 = (cr0_saved & 0xffff00e0) | 0x00000800; - __ctl_load(cr0 , 0, 0); + __ctl_store(cr0, 0, 0); + __ctl_store(cr6, 6, 6); + new = (cr0 & 0xffff00e0) | 0x00000800; + __ctl_load(new , 0, 0); + new = 0; + __ctl_load(new, 6, 6); lockdep_off(); do { set_clock_comparator(end); - trace_hardirqs_on(); - __load_psw_mask(mask); + vtime_stop_cpu(); local_irq_disable(); } while (get_clock() < end); lockdep_on(); - __ctl_load(cr0_saved, 0, 0); + __ctl_load(cr0, 0, 0); + __ctl_load(cr6, 6, 6); local_tick_enable(clock_saved); } static void __udelay_enabled(unsigned long long usecs) { - unsigned long mask; - u64 clock_saved; - u64 end; + u64 clock_saved, end; - mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO; end = get_clock() + (usecs << 12); do { clock_saved = 0; @@ -65,8 +63,7 @@ static void __udelay_enabled(unsigned long long usecs) clock_saved = local_tick_disable(); set_clock_comparator(end); } - trace_hardirqs_on(); - __load_psw_mask(mask); + vtime_stop_cpu(); local_irq_disable(); if (clock_saved) local_tick_enable(clock_saved); diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 91754ffb9203..093eb694d9c1 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/init.h> +#include <linux/smp.h> #include <asm/io.h> int spin_retry = 1000; @@ -24,21 +25,6 @@ static int __init spin_retry_setup(char *str) } __setup("spin_retry=", spin_retry_setup); -static inline void _raw_yield(void) -{ - if (MACHINE_HAS_DIAG44) - asm volatile("diag 0,0,0x44"); -} - -static inline void _raw_yield_cpu(int cpu) -{ - if (MACHINE_HAS_DIAG9C) - asm volatile("diag %0,0,0x9c" - : : "d" (cpu_logical_map(cpu))); - else - _raw_yield(); -} - void arch_spin_lock_wait(arch_spinlock_t *lp) { int count = spin_retry; @@ -60,7 +46,7 @@ void arch_spin_lock_wait(arch_spinlock_t *lp) } owner = lp->owner_cpu; if (owner) - _raw_yield_cpu(~owner); + smp_yield_cpu(~owner); if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) return; } @@ -91,7 +77,7 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) } owner = lp->owner_cpu; if (owner) - _raw_yield_cpu(~owner); + smp_yield_cpu(~owner); local_irq_disable(); if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) return; @@ -121,7 +107,7 @@ void arch_spin_relax(arch_spinlock_t *lock) if (cpu != 0) { if (MACHINE_IS_VM || MACHINE_IS_KVM || !smp_vcpu_scheduled(~cpu)) - _raw_yield_cpu(~cpu); + smp_yield_cpu(~cpu); } } EXPORT_SYMBOL(arch_spin_relax); @@ -133,7 +119,7 @@ void _raw_read_lock_wait(arch_rwlock_t *rw) while (1) { if (count-- <= 0) { - _raw_yield(); + smp_yield(); count = spin_retry; } if (!arch_read_can_lock(rw)) @@ -153,7 +139,7 @@ void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) local_irq_restore(flags); while (1) { if (count-- <= 0) { - _raw_yield(); + smp_yield(); count = spin_retry; } if (!arch_read_can_lock(rw)) @@ -188,7 +174,7 @@ void _raw_write_lock_wait(arch_rwlock_t *rw) while (1) { if (count-- <= 0) { - _raw_yield(); + smp_yield(); count = spin_retry; } if (!arch_write_can_lock(rw)) @@ -206,7 +192,7 @@ void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) local_irq_restore(flags); while (1) { if (count-- <= 0) { - _raw_yield(); + smp_yield(); count = spin_retry; } if (!arch_write_can_lock(rw)) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e8fcd928dc78..b17c42df61c9 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -532,7 +532,7 @@ void pfault_fini(void) static DEFINE_SPINLOCK(pfault_lock); static LIST_HEAD(pfault_list); -static void pfault_interrupt(unsigned int ext_int_code, +static void pfault_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct task_struct *tsk; @@ -545,7 +545,7 @@ static void pfault_interrupt(unsigned int ext_int_code, * in the 'cpu address' field associated with the * external interrupt. */ - subcode = ext_int_code >> 16; + subcode = ext_code.subcode; if ((subcode & 0xff00) != __SUBCODE_MASK) return; kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 9daee91e6c3f..12bea05a0fc1 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c @@ -233,8 +233,8 @@ static inline unsigned long *trailer_entry_ptr(unsigned long v) } /* prototypes for external interrupt handler and worker */ -static void hws_ext_handler(unsigned int ext_int_code, - unsigned int param32, unsigned long param64); +static void hws_ext_handler(struct ext_code ext_code, + unsigned int param32, unsigned long param64); static void worker(struct work_struct *work); @@ -673,7 +673,7 @@ int hwsampler_activate(unsigned int cpu) return rc; } -static void hws_ext_handler(unsigned int ext_int_code, +static void hws_ext_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct hws_cpu_buffer *cb; diff --git a/arch/score/Kconfig.debug b/arch/score/Kconfig.debug index a1f346df0a71..d8a9b2d146ee 100644 --- a/arch/score/Kconfig.debug +++ b/arch/score/Kconfig.debug @@ -22,7 +22,7 @@ config RUNTIME_DEBUG help If you say Y here, some debugging macros will do run-time checking. If you say N here, those macros will mostly turn to no-ops. See - include/asm-score/debug.h for debuging macros. + include/asm-score/debug.h for debugging macros. If unsure, say N. endmenu diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index cde7c0085ced..59daae2f29db 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -769,7 +769,9 @@ static struct platform_device camera_devices[] = { /* FSI */ static struct sh_fsi_platform_info fsi_info = { - .portb_flags = SH_FSI_BRS_INV, + .port_b = { + .flags = SH_FSI_BRS_INV, + }, }; static struct resource fsi_resources[] = { diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 2b07fc016950..59f4db829e91 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -278,7 +278,9 @@ static struct platform_device ceu1_device = { /* FSI */ /* change J20, J21, J22 pin to 1-2 connection to use slave mode */ static struct sh_fsi_platform_info fsi_info = { - .porta_flags = SH_FSI_BRS_INV, + .port_a = { + .flags = SH_FSI_BRS_INV, + }, }; static struct resource fsi_resources[] = { diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 92eb98633ab0..112fea12522a 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -244,7 +244,7 @@ static void sh4_flush_cache_page(void *args) if (map_coherent) vaddr = kmap_coherent(page, address); else - vaddr = kmap_atomic(page, KM_USER0); + vaddr = kmap_atomic(page); address = (unsigned long)vaddr; } @@ -259,7 +259,7 @@ static void sh4_flush_cache_page(void *args) if (map_coherent) kunmap_coherent(vaddr); else - kunmap_atomic(vaddr, KM_USER0); + kunmap_atomic(vaddr); } } diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 5a580ea04429..616966a96cba 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -95,7 +95,7 @@ void copy_user_highpage(struct page *to, struct page *from, { void *vfrom, *vto; - vto = kmap_atomic(to, KM_USER1); + vto = kmap_atomic(to); if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && test_bit(PG_dcache_clean, &from->flags)) { @@ -103,16 +103,16 @@ void copy_user_highpage(struct page *to, struct page *from, copy_page(vto, vfrom); kunmap_coherent(vfrom); } else { - vfrom = kmap_atomic(from, KM_USER0); + vfrom = kmap_atomic(from); copy_page(vto, vfrom); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); } if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK) || (vma->vm_flags & VM_EXEC)) __flush_purge_region(vto, PAGE_SIZE); - kunmap_atomic(vto, KM_USER1); + kunmap_atomic(vto); /* Make sure this page is cleared on other CPU's too before using it */ smp_wmb(); } @@ -120,14 +120,14 @@ EXPORT_SYMBOL(copy_user_highpage); void clear_user_highpage(struct page *page, unsigned long vaddr) { - void *kaddr = kmap_atomic(page, KM_USER0); + void *kaddr = kmap_atomic(page); clear_page(kaddr); if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) __flush_purge_region(kaddr, PAGE_SIZE); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } EXPORT_SYMBOL(clear_user_highpage); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 3d7afbb7f4bb..3b6e00dd96e5 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -70,7 +70,7 @@ static inline void kunmap(struct page *page) kunmap_high(page); } -extern void *__kmap_atomic(struct page *page); +extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern struct page *kmap_atomic_to_page(void *vaddr); diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index edd3d3cde460..c28765110706 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -22,6 +22,7 @@ #include <linux/proc_fs.h> #include <linux/mutex.h> #include <linux/atomic.h> +#include <linux/irqdomain.h> #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2 #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 @@ -55,15 +56,6 @@ struct resource; extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); -/* These routines are here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes. We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - extern struct device_node *of_console_device; extern char *of_console_path; extern char *of_console_options; diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 8af1b64168b3..bea1568ae4af 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -60,6 +60,11 @@ #define SO_WIFI_STATUS 0x0025 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 0x0026 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 0x0027 + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 023b8860dc97..c8f5b50db89c 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -776,7 +776,6 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t blocked; int err; if (ka->sa.sa_flags & SA_SIGINFO) @@ -787,11 +786,7 @@ static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka, if (err) return err; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NOMASK)) - sigaddset(&blocked, signr); - set_current_blocked(&blocked); - + block_sigmask(ka, signr); tracehook_signal_handler(signr, info, ka, regs, 0); return 0; diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index d54c6e53aba0..7bb71b6fbd20 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -465,7 +465,6 @@ static inline int handle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t blocked; int err; if (ka->sa.sa_flags & SA_SIGINFO) @@ -476,11 +475,7 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, if (err) return err; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NOMASK)) - sigaddset(&blocked, signr); - set_current_blocked(&blocked); - + block_sigmask(ka, signr); tracehook_signal_handler(signr, info, ka, regs, 0); return 0; diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index f0836cd0e2f2..d8a67e60be80 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -479,18 +479,14 @@ static inline int handle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t blocked; int err; err = setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); if (err) return err; - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NOMASK)) - sigaddset(&blocked, signr); - set_current_blocked(&blocked); + block_sigmask(ka, signr); tracehook_signal_handler(signr, info, ka, regs, 0); return 0; diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 77140a02c86a..055c66cf1bf4 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -30,7 +30,7 @@ #include <asm/tlbflush.h> #include <asm/fixmap.h> -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned long vaddr; long idx, type; @@ -64,7 +64,7 @@ void *__kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/tile/include/asm/highmem.h b/arch/tile/include/asm/highmem.h index b2a6c5de79ab..fc8429a31c85 100644 --- a/arch/tile/include/asm/highmem.h +++ b/arch/tile/include/asm/highmem.h @@ -59,7 +59,7 @@ void *kmap_fix_kpte(struct page *page, int finished); /* This macro is used only in map_new_virtual() to map "page". */ #define kmap_prot page_to_kpgprot(page) -void *__kmap_atomic(struct page *page); +void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 31dbbd9afe47..ef8e5a62b6e3 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c @@ -224,12 +224,12 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { /* PAGE_NONE is a magic value that tells us to check immutability. */ return kmap_atomic_prot(page, PAGE_NONE); } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index a492e59883a3..d2996183e584 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -293,7 +293,7 @@ static void uml_net_user_timer_expire(unsigned long _conn) #endif } -static void setup_etheraddr(char *str, unsigned char *addr, char *name) +static int setup_etheraddr(char *str, unsigned char *addr, char *name) { char *end; int i; @@ -334,12 +334,13 @@ static void setup_etheraddr(char *str, unsigned char *addr, char *name) addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4], addr[5]); } - return; + return 0; random: printk(KERN_INFO "Choosing a random ethernet address for device %s\n", name); random_ether_addr(addr); + return 1; } static DEFINE_SPINLOCK(devices_lock); @@ -391,6 +392,7 @@ static void eth_configure(int n, void *init, char *mac, struct net_device *dev; struct uml_net_private *lp; int err, size; + int random_mac; size = transport->private_size + sizeof(struct uml_net_private); @@ -417,7 +419,7 @@ static void eth_configure(int n, void *init, char *mac, */ snprintf(dev->name, sizeof(dev->name), "eth%d", n); - setup_etheraddr(mac, device->mac, dev->name); + random_mac = setup_etheraddr(mac, device->mac, dev->name); printk(KERN_INFO "Netdevice %d (%pM) : ", n, device->mac); @@ -474,6 +476,9 @@ static void eth_configure(int n, void *init, char *mac, /* don't use eth_mac_addr, it will not work here */ memcpy(dev->dev_addr, device->mac, ETH_ALEN); + if (random_mac) + dev->addr_assign_type |= NET_ADDR_RANDOM; + dev->mtu = transport->user->mtu; dev->netdev_ops = ¨_netdev_ops; dev->ethtool_ops = ¨_net_ethtool_ops; diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h index 30509b9f37fd..53e8b498ebba 100644 --- a/arch/um/include/asm/mmu.h +++ b/arch/um/include/asm/mmu.h @@ -12,7 +12,7 @@ typedef struct mm_context { struct mm_id id; struct uml_arch_mm_context arch; - struct page **stub_pages; + struct page *stub_pages[2]; } mm_context_t; extern void __switch_mm(struct mm_id * mm_idp); diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h index 591b3d8d7614..aa4a743dc4ab 100644 --- a/arch/um/include/asm/mmu_context.h +++ b/arch/um/include/asm/mmu_context.h @@ -9,7 +9,7 @@ #include <linux/sched.h> #include <asm/mmu.h> -extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm); +extern void uml_setup_stubs(struct mm_struct *mm); extern void arch_exit_mmap(struct mm_struct *mm); #define deactivate_mm(tsk,mm) do { } while (0) @@ -23,7 +23,9 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) * when the new ->mm is used for the first time. */ __switch_mm(&new->context.id); - arch_dup_mmap(old, new); + down_write(&new->mmap_sem); + uml_setup_stubs(new); + up_write(&new->mmap_sem); } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -39,6 +41,11 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, } } +static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +{ + uml_setup_stubs(mm); +} + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 1aee587e9c5d..4947b319f53a 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -92,8 +92,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) goto out_free; } - to_mm->stub_pages = NULL; - return 0; out_free: @@ -103,7 +101,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) return ret; } -void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +void uml_setup_stubs(struct mm_struct *mm) { struct page **pages; int err, ret; @@ -120,29 +118,20 @@ void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) if (ret) goto out; - pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL); - if (pages == NULL) { - printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page " - "pointers\n"); - goto out; - } - - pages[0] = virt_to_page(&__syscall_stub_start); - pages[1] = virt_to_page(mm->context.id.stack); - mm->context.stub_pages = pages; + mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); + mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack); /* dup_mmap already holds mmap_sem */ err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START, VM_READ | VM_MAYREAD | VM_EXEC | - VM_MAYEXEC | VM_DONTCOPY, pages); + VM_MAYEXEC | VM_DONTCOPY, + mm->context.stub_pages); if (err) { printk(KERN_ERR "install_special_mapping returned %d\n", err); - goto out_free; + goto out; } return; -out_free: - kfree(pages); out: force_sigsegv(SIGSEGV, current); } @@ -151,8 +140,6 @@ void arch_exit_mmap(struct mm_struct *mm) { pte_t *pte; - if (mm->context.stub_pages != NULL) - kfree(mm->context.stub_pages); pte = virt_to_pte(mm, STUB_CODE); if (pte != NULL) pte_clear(mm, STUB_CODE, pte); diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 9fefd924fb49..cd7df79c6a56 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -69,7 +69,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, return -1; page = pte_page(*pte); - addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + + addr = (unsigned long) kmap_atomic(page) + (addr & ~PAGE_MASK); current->thread.fault_catcher = &buf; @@ -82,7 +82,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, current->thread.fault_catcher = NULL; - kunmap_atomic((void *)addr, KM_UML_USERCOPY); + kunmap_atomic((void *)addr); return n; } diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d523a6c36835..901952355969 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -402,6 +402,7 @@ config X86_INTEL_CE select X86_REBOOTFIXUPS select OF select OF_EARLY_FLATTREE + select IRQ_DOMAIN ---help--- Select for the Intel CE media processor (CE4100) SOC. This option compiles in support for the CE4100 SOC for settop @@ -421,27 +422,6 @@ if X86_WANT_INTEL_MID config X86_INTEL_MID bool -config X86_MRST - bool "Moorestown MID platform" - depends on PCI - depends on PCI_GOANY - depends on X86_IO_APIC - select X86_INTEL_MID - select SFI - select DW_APB_TIMER - select APB_TIMER - select I2C - select SPI - select INTEL_SCU_IPC - select X86_PLATFORM_DEVICES - ---help--- - Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin - Internet Device(MID) platform. Moorestown consists of two chips: - Lincroft (CPU core, graphics, and memory controller) and Langwell IOH. - Unlike standard x86 PCs, Moorestown does not have many legacy devices - nor standard legacy replacement devices/features. e.g. Moorestown does - not contain i8259, i8254, HPET, legacy BIOS, most of the io ports. - config X86_MDFLD bool "Medfield MID platform" depends on PCI @@ -455,6 +435,7 @@ config X86_MDFLD select SPI select INTEL_SCU_IPC select X86_PLATFORM_DEVICES + select MFD_INTEL_MSIC ---help--- Medfield is Intel's Low Power Intel Architecture (LPIA) based Moblin Internet Device(MID) platform. @@ -2080,6 +2061,7 @@ config OLPC select GPIOLIB select OF select OF_PROMTREE + select IRQ_DOMAIN ---help--- Add support for detecting the unique features of the OLPC XO hardware. @@ -2137,6 +2119,12 @@ config ALIX Note: You have to set alix.force=1 for boards with Award BIOS. +config NET5501 + bool "Soekris Engineering net5501 System Support (LEDS, GPIO, etc)" + select GPIOLIB + ---help--- + This option enables system support for the Soekris Engineering net5501. + endif # X86_32 config AMD_NB diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 3c57033e2211..706e12e9984b 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -303,7 +303,6 @@ config X86_GENERIC config X86_INTERNODE_CACHE_SHIFT int default "12" if X86_VSMP - default "7" if NUMA default X86_L1_CACHE_SHIFT config X86_CMPXCHG @@ -441,7 +440,7 @@ config CPU_SUP_INTEL config CPU_SUP_CYRIX_32 default y bool "Support Cyrix processors" if PROCESSOR_SELECT - depends on !64BIT + depends on M386 || M486 || M586 || M586TSC || M586MMX || (EXPERT && !64BIT) ---help--- This enables detection, tunings and quirks for Cyrix processors @@ -495,7 +494,7 @@ config CPU_SUP_TRANSMETA_32 config CPU_SUP_UMC_32 default y bool "Support UMC processors" if PROCESSOR_SELECT - depends on !64BIT + depends on M386 || M486 || (EXPERT && !64BIT) ---help--- This enables detection, tunings and quirks for UMC processors diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index 95365a82b6a0..3e02148bb774 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -37,8 +37,9 @@ setup-y += video-bios.o targets += $(setup-y) hostprogs-y := mkcpustr tools/build -HOST_EXTRACFLAGS += $(LINUXINCLUDE) - +HOSTCFLAGS_mkcpustr.o := -I$(srctree)/arch/$(SRCARCH)/include +HOST_EXTRACFLAGS += -I$(objtree)/include -I$(srctree)/tools/include \ + -include $(srctree)/include/linux/kconfig.h $(obj)/cpu.o: $(obj)/cpustr.h quiet_cmd_cpustr = CPUSTR $@ diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index c7093bd9f2d3..18997e5a1053 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -67,7 +67,7 @@ static inline void outl(u32 v, u16 port) { asm volatile("outl %0,%1" : : "a" (v), "dN" (port)); } -static inline u32 inl(u32 port) +static inline u32 inl(u16 port) { u32 v; asm volatile("inl %1,%0" : "=a" (v) : "dN" (port)); diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index b123b9a8f5b3..fd55a2ff3ad8 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -22,6 +22,7 @@ LDFLAGS := -m elf_$(UTS_MACHINE) LDFLAGS_vmlinux := -T hostprogs-y := mkpiggy +HOST_EXTRACFLAGS += -I$(srctree)/tools/include VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \ diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index fec216f4fbc3..0cdfc0d2315e 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -539,7 +539,7 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, struct initrd *initrd; efi_file_handle_t *h; efi_file_info_t *info; - efi_char16_t filename[256]; + efi_char16_t filename_16[256]; unsigned long info_sz; efi_guid_t info_guid = EFI_FILE_INFO_ID; efi_char16_t *p; @@ -552,14 +552,14 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, str += 7; initrd = &initrds[i]; - p = filename; + p = filename_16; /* Skip any leading slashes */ while (*str == '/' || *str == '\\') str++; while (*str && *str != ' ' && *str != '\n') { - if (p >= filename + sizeof(filename)) + if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) break; *p++ = *str++; @@ -583,7 +583,7 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image, goto free_initrds; } - status = efi_call_phys5(fh->open, fh, &h, filename, + status = efi_call_phys5(fh->open, fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0); if (status != EFI_SUCCESS) goto close_handles; diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index 46a823882437..958a641483dd 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -29,14 +29,7 @@ #include <stdio.h> #include <string.h> #include <inttypes.h> - -static uint32_t getle32(const void *p) -{ - const uint8_t *cp = p; - - return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) + - ((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24); -} +#include <tools/le_byteshift.h> int main(int argc, char *argv[]) { @@ -69,7 +62,7 @@ int main(int argc, char *argv[]) } ilen = ftell(f); - olen = getle32(&olen); + olen = get_unaligned_le32(&olen); fclose(f); /* diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c index 89bbf4e4d05d..d3c0b0277666 100644 --- a/arch/x86/boot/compressed/relocs.c +++ b/arch/x86/boot/compressed/relocs.c @@ -10,6 +10,7 @@ #define USE_BSD #include <endian.h> #include <regex.h> +#include <tools/le_byteshift.h> static void die(char *fmt, ...); @@ -605,10 +606,7 @@ static void emit_relocs(int as_text) fwrite("\0\0\0\0", 4, 1, stdout); /* Now print each relocation */ for (i = 0; i < reloc_count; i++) { - buf[0] = (relocs[i] >> 0) & 0xff; - buf[1] = (relocs[i] >> 8) & 0xff; - buf[2] = (relocs[i] >> 16) & 0xff; - buf[3] = (relocs[i] >> 24) & 0xff; + put_unaligned_le32(relocs[i], buf); fwrite(buf, 4, 1, stdout); } } diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c index 4e9bd6bcafa6..ed549767a231 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c @@ -29,18 +29,18 @@ #include <stdarg.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/sysmacros.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> -#include <asm/boot.h> +#include <tools/le_byteshift.h> typedef unsigned char u8; typedef unsigned short u16; -typedef unsigned long u32; +typedef unsigned int u32; #define DEFAULT_MAJOR_ROOT 0 #define DEFAULT_MINOR_ROOT 0 +#define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT) /* Minimal number of setup sectors */ #define SETUP_SECT_MIN 5 @@ -159,7 +159,7 @@ int main(int argc, char ** argv) die("read-error on `setup'"); if (c < 1024) die("The setup must be at least 1024 bytes"); - if (buf[510] != 0x55 || buf[511] != 0xaa) + if (get_unaligned_le16(&buf[510]) != 0xAA55) die("Boot block hasn't got boot flag (0xAA55)"); fclose(file); @@ -171,8 +171,7 @@ int main(int argc, char ** argv) memset(buf+c, 0, i-c); /* Set the default root device */ - buf[508] = DEFAULT_MINOR_ROOT; - buf[509] = DEFAULT_MAJOR_ROOT; + put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i); @@ -192,44 +191,42 @@ int main(int argc, char ** argv) /* Patch the setup code with the appropriate size parameters */ buf[0x1f1] = setup_sectors-1; - buf[0x1f4] = sys_size; - buf[0x1f5] = sys_size >> 8; - buf[0x1f6] = sys_size >> 16; - buf[0x1f7] = sys_size >> 24; + put_unaligned_le32(sys_size, &buf[0x1f4]); #ifdef CONFIG_EFI_STUB file_sz = sz + i + ((sys_size * 16) - sz); - pe_header = *(unsigned int *)&buf[0x3c]; + pe_header = get_unaligned_le32(&buf[0x3c]); /* Size of code */ - *(unsigned int *)&buf[pe_header + 0x1c] = file_sz; + put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]); /* Size of image */ - *(unsigned int *)&buf[pe_header + 0x50] = file_sz; + put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); #ifdef CONFIG_X86_32 /* Address of entry point */ - *(unsigned int *)&buf[pe_header + 0x28] = i; + put_unaligned_le32(i, &buf[pe_header + 0x28]); /* .text size */ - *(unsigned int *)&buf[pe_header + 0xb0] = file_sz; + put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]); /* .text size of initialised data */ - *(unsigned int *)&buf[pe_header + 0xb8] = file_sz; + put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]); #else /* * Address of entry point. startup_32 is at the beginning and * the 64-bit entry point (startup_64) is always 512 bytes * after. */ - *(unsigned int *)&buf[pe_header + 0x28] = i + 512; + put_unaligned_le32(i + 512, &buf[pe_header + 0x28]); /* .text size */ - *(unsigned int *)&buf[pe_header + 0xc0] = file_sz; + put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]); /* .text size of initialised data */ - *(unsigned int *)&buf[pe_header + 0xc8] = file_sz; + put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]); + #endif /* CONFIG_X86_32 */ #endif /* CONFIG_EFI_STUB */ @@ -250,8 +247,9 @@ int main(int argc, char ** argv) } /* Write the CRC */ - fprintf(stderr, "CRC %lx\n", crc); - if (fwrite(&crc, 1, 4, stdout) != 4) + fprintf(stderr, "CRC %x\n", crc); + put_unaligned_le32(crc, buf); + if (fwrite(buf, 1, 4, stdout) != 4) die("Writing CRC failed"); close(fd); diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 2b0b9631474b..e191ac048b59 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o +obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o @@ -25,6 +26,7 @@ salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o +camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index b3350bd32c60..c799352e24fc 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -1108,12 +1108,12 @@ static int __driver_rfc4106_encrypt(struct aead_request *req) one_entry_in_sg = 1; scatterwalk_start(&src_sg_walk, req->src); scatterwalk_start(&assoc_sg_walk, req->assoc); - src = scatterwalk_map(&src_sg_walk, 0); - assoc = scatterwalk_map(&assoc_sg_walk, 0); + src = scatterwalk_map(&src_sg_walk); + assoc = scatterwalk_map(&assoc_sg_walk); dst = src; if (unlikely(req->src != req->dst)) { scatterwalk_start(&dst_sg_walk, req->dst); - dst = scatterwalk_map(&dst_sg_walk, 0); + dst = scatterwalk_map(&dst_sg_walk); } } else { @@ -1137,11 +1137,11 @@ static int __driver_rfc4106_encrypt(struct aead_request *req) * back to the packet. */ if (one_entry_in_sg) { if (unlikely(req->src != req->dst)) { - scatterwalk_unmap(dst, 0); + scatterwalk_unmap(dst); scatterwalk_done(&dst_sg_walk, 0, 0); } - scatterwalk_unmap(src, 0); - scatterwalk_unmap(assoc, 0); + scatterwalk_unmap(src); + scatterwalk_unmap(assoc); scatterwalk_done(&src_sg_walk, 0, 0); scatterwalk_done(&assoc_sg_walk, 0, 0); } else { @@ -1190,12 +1190,12 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) one_entry_in_sg = 1; scatterwalk_start(&src_sg_walk, req->src); scatterwalk_start(&assoc_sg_walk, req->assoc); - src = scatterwalk_map(&src_sg_walk, 0); - assoc = scatterwalk_map(&assoc_sg_walk, 0); + src = scatterwalk_map(&src_sg_walk); + assoc = scatterwalk_map(&assoc_sg_walk); dst = src; if (unlikely(req->src != req->dst)) { scatterwalk_start(&dst_sg_walk, req->dst); - dst = scatterwalk_map(&dst_sg_walk, 0); + dst = scatterwalk_map(&dst_sg_walk); } } else { @@ -1220,11 +1220,11 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) if (one_entry_in_sg) { if (unlikely(req->src != req->dst)) { - scatterwalk_unmap(dst, 0); + scatterwalk_unmap(dst); scatterwalk_done(&dst_sg_walk, 0, 0); } - scatterwalk_unmap(src, 0); - scatterwalk_unmap(assoc, 0); + scatterwalk_unmap(src); + scatterwalk_unmap(assoc); scatterwalk_done(&src_sg_walk, 0, 0); scatterwalk_done(&assoc_sg_walk, 0, 0); } else { diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c index b05aa163d55a..7967474de8f7 100644 --- a/arch/x86/crypto/blowfish_glue.c +++ b/arch/x86/crypto/blowfish_glue.c @@ -25,6 +25,7 @@ * */ +#include <asm/processor.h> #include <crypto/blowfish.h> #include <linux/crypto.h> #include <linux/init.h> @@ -76,27 +77,6 @@ static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); } -static struct crypto_alg bf_alg = { - .cra_name = "blowfish", - .cra_driver_name = "blowfish-asm", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = BF_MIN_KEY_SIZE, - .cia_max_keysize = BF_MAX_KEY_SIZE, - .cia_setkey = blowfish_setkey, - .cia_encrypt = blowfish_encrypt, - .cia_decrypt = blowfish_decrypt, - } - } -}; - static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, void (*fn)(struct bf_ctx *, u8 *, const u8 *), void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) @@ -160,28 +140,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way); } -static struct crypto_alg blk_ecb_alg = { - .cra_name = "ecb(blowfish)", - .cra_driver_name = "ecb-blowfish-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = BF_MIN_KEY_SIZE, - .max_keysize = BF_MAX_KEY_SIZE, - .setkey = blowfish_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}; - static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -307,29 +265,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_cbc_alg = { - .cra_name = "cbc(blowfish)", - .cra_driver_name = "cbc-blowfish-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = BF_MIN_KEY_SIZE, - .max_keysize = BF_MAX_KEY_SIZE, - .ivsize = BF_BLOCK_SIZE, - .setkey = blowfish_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}; - static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk) { u8 *ctrblk = walk->iv; @@ -423,7 +358,67 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { +static struct crypto_alg bf_algs[4] = { { + .cra_name = "blowfish", + .cra_driver_name = "blowfish-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_algs[0].cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = BF_MIN_KEY_SIZE, + .cia_max_keysize = BF_MAX_KEY_SIZE, + .cia_setkey = blowfish_setkey, + .cia_encrypt = blowfish_encrypt, + .cia_decrypt = blowfish_decrypt, + } + } +}, { + .cra_name = "ecb(blowfish)", + .cra_driver_name = "ecb-blowfish-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = BF_MIN_KEY_SIZE, + .max_keysize = BF_MAX_KEY_SIZE, + .setkey = blowfish_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "cbc(blowfish)", + .cra_driver_name = "cbc-blowfish-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = BF_MIN_KEY_SIZE, + .max_keysize = BF_MAX_KEY_SIZE, + .ivsize = BF_BLOCK_SIZE, + .setkey = blowfish_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { .cra_name = "ctr(blowfish)", .cra_driver_name = "ctr-blowfish-asm", .cra_priority = 300, @@ -433,7 +428,7 @@ static struct crypto_alg blk_ctr_alg = { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), + .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, @@ -444,43 +439,45 @@ static struct crypto_alg blk_ctr_alg = { .decrypt = ctr_crypt, }, }, -}; +} }; + +static bool is_blacklisted_cpu(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return false; + + if (boot_cpu_data.x86 == 0x0f) { + /* + * On Pentium 4, blowfish-x86_64 is slower than generic C + * implementation because use of 64bit rotates (which are really + * slow on P4). Therefore blacklist P4s. + */ + return true; + } + + return false; +} + +static int force; +module_param(force, int, 0); +MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); static int __init init(void) { - int err; + if (!force && is_blacklisted_cpu()) { + printk(KERN_INFO + "blowfish-x86_64: performance on this CPU " + "would be suboptimal: disabling " + "blowfish-x86_64.\n"); + return -ENODEV; + } - err = crypto_register_alg(&bf_alg); - if (err) - goto bf_err; - err = crypto_register_alg(&blk_ecb_alg); - if (err) - goto ecb_err; - err = crypto_register_alg(&blk_cbc_alg); - if (err) - goto cbc_err; - err = crypto_register_alg(&blk_ctr_alg); - if (err) - goto ctr_err; - - return 0; - -ctr_err: - crypto_unregister_alg(&blk_cbc_alg); -cbc_err: - crypto_unregister_alg(&blk_ecb_alg); -ecb_err: - crypto_unregister_alg(&bf_alg); -bf_err: - return err; + return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs)); } static void __exit fini(void) { - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); - crypto_unregister_alg(&bf_alg); + crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs)); } module_init(init); diff --git a/arch/x86/crypto/camellia-x86_64-asm_64.S b/arch/x86/crypto/camellia-x86_64-asm_64.S new file mode 100644 index 000000000000..0b3374335fdc --- /dev/null +++ b/arch/x86/crypto/camellia-x86_64-asm_64.S @@ -0,0 +1,520 @@ +/* + * Camellia Cipher Algorithm (x86_64) + * + * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +.file "camellia-x86_64-asm_64.S" +.text + +.extern camellia_sp10011110; +.extern camellia_sp22000222; +.extern camellia_sp03303033; +.extern camellia_sp00444404; +.extern camellia_sp02220222; +.extern camellia_sp30333033; +.extern camellia_sp44044404; +.extern camellia_sp11101110; + +#define sp10011110 camellia_sp10011110 +#define sp22000222 camellia_sp22000222 +#define sp03303033 camellia_sp03303033 +#define sp00444404 camellia_sp00444404 +#define sp02220222 camellia_sp02220222 +#define sp30333033 camellia_sp30333033 +#define sp44044404 camellia_sp44044404 +#define sp11101110 camellia_sp11101110 + +#define CAMELLIA_TABLE_BYTE_LEN 272 + +/* struct camellia_ctx: */ +#define key_table 0 +#define key_length CAMELLIA_TABLE_BYTE_LEN + +/* register macros */ +#define CTX %rdi +#define RIO %rsi +#define RIOd %esi + +#define RAB0 %rax +#define RCD0 %rcx +#define RAB1 %rbx +#define RCD1 %rdx + +#define RAB0d %eax +#define RCD0d %ecx +#define RAB1d %ebx +#define RCD1d %edx + +#define RAB0bl %al +#define RCD0bl %cl +#define RAB1bl %bl +#define RCD1bl %dl + +#define RAB0bh %ah +#define RCD0bh %ch +#define RAB1bh %bh +#define RCD1bh %dh + +#define RT0 %rsi +#define RT1 %rbp +#define RT2 %r8 + +#define RT0d %esi +#define RT1d %ebp +#define RT2d %r8d + +#define RT2bl %r8b + +#define RXOR %r9 +#define RRBP %r10 +#define RDST %r11 + +#define RXORd %r9d +#define RXORbl %r9b + +#define xor2ror16(T0, T1, tmp1, tmp2, ab, dst) \ + movzbl ab ## bl, tmp2 ## d; \ + movzbl ab ## bh, tmp1 ## d; \ + rorq $16, ab; \ + xorq T0(, tmp2, 8), dst; \ + xorq T1(, tmp1, 8), dst; + +/********************************************************************** + 1-way camellia + **********************************************************************/ +#define roundsm(ab, subkey, cd) \ + movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ + \ + xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ + xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ + \ + xorq RT2, cd ## 0; + +#define fls(l, r, kl, kr) \ + movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ + andl l ## 0d, RT0d; \ + roll $1, RT0d; \ + shlq $32, RT0; \ + xorq RT0, l ## 0; \ + movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ + orq r ## 0, RT1; \ + shrq $32, RT1; \ + xorq RT1, r ## 0; \ + \ + movq (key_table + ((kl) * 2) * 4)(CTX), RT2; \ + orq l ## 0, RT2; \ + shrq $32, RT2; \ + xorq RT2, l ## 0; \ + movl (key_table + ((kr) * 2) * 4)(CTX), RT0d; \ + andl r ## 0d, RT0d; \ + roll $1, RT0d; \ + shlq $32, RT0; \ + xorq RT0, r ## 0; + +#define enc_rounds(i) \ + roundsm(RAB, i + 2, RCD); \ + roundsm(RCD, i + 3, RAB); \ + roundsm(RAB, i + 4, RCD); \ + roundsm(RCD, i + 5, RAB); \ + roundsm(RAB, i + 6, RCD); \ + roundsm(RCD, i + 7, RAB); + +#define enc_fls(i) \ + fls(RAB, RCD, i + 0, i + 1); + +#define enc_inpack() \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rolq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rorq $32, RCD0; \ + xorq key_table(CTX), RAB0; + +#define enc_outunpack(op, max) \ + xorq key_table(CTX, max, 8), RCD0; \ + rorq $32, RCD0; \ + bswapq RCD0; \ + op ## q RCD0, (RIO); \ + rolq $32, RAB0; \ + bswapq RAB0; \ + op ## q RAB0, 4*2(RIO); + +#define dec_rounds(i) \ + roundsm(RAB, i + 7, RCD); \ + roundsm(RCD, i + 6, RAB); \ + roundsm(RAB, i + 5, RCD); \ + roundsm(RCD, i + 4, RAB); \ + roundsm(RAB, i + 3, RCD); \ + roundsm(RCD, i + 2, RAB); + +#define dec_fls(i) \ + fls(RAB, RCD, i + 1, i + 0); + +#define dec_inpack(max) \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rolq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rorq $32, RCD0; \ + xorq key_table(CTX, max, 8), RAB0; + +#define dec_outunpack() \ + xorq key_table(CTX), RCD0; \ + rorq $32, RCD0; \ + bswapq RCD0; \ + movq RCD0, (RIO); \ + rolq $32, RAB0; \ + bswapq RAB0; \ + movq RAB0, 4*2(RIO); + +.global __camellia_enc_blk; +.type __camellia_enc_blk,@function; + +__camellia_enc_blk: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool xor + */ + movq %rbp, RRBP; + + movq %rcx, RXOR; + movq %rsi, RDST; + movq %rdx, RIO; + + enc_inpack(); + + enc_rounds(0); + enc_fls(8); + enc_rounds(8); + enc_fls(16); + enc_rounds(16); + movl $24, RT1d; /* max */ + + cmpb $16, key_length(CTX); + je __enc_done; + + enc_fls(24); + enc_rounds(24); + movl $32, RT1d; /* max */ + +__enc_done: + testb RXORbl, RXORbl; + movq RDST, RIO; + + jnz __enc_xor; + + enc_outunpack(mov, RT1); + + movq RRBP, %rbp; + ret; + +__enc_xor: + enc_outunpack(xor, RT1); + + movq RRBP, %rbp; + ret; + +.global camellia_dec_blk; +.type camellia_dec_blk,@function; + +camellia_dec_blk: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + cmpl $16, key_length(CTX); + movl $32, RT2d; + movl $24, RXORd; + cmovel RXORd, RT2d; /* max */ + + movq %rbp, RRBP; + movq %rsi, RDST; + movq %rdx, RIO; + + dec_inpack(RT2); + + cmpb $24, RT2bl; + je __dec_rounds16; + + dec_rounds(24); + dec_fls(24); + +__dec_rounds16: + dec_rounds(16); + dec_fls(16); + dec_rounds(8); + dec_fls(8); + dec_rounds(0); + + movq RDST, RIO; + + dec_outunpack(); + + movq RRBP, %rbp; + ret; + +/********************************************************************** + 2-way camellia + **********************************************************************/ +#define roundsm2(ab, subkey, cd) \ + movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ + xorq RT2, cd ## 1; \ + \ + xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ + xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ + \ + xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 1, cd ## 1); \ + xorq RT2, cd ## 0; \ + xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 1, cd ## 1); \ + xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 1, cd ## 1); \ + xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 1, cd ## 1); + +#define fls2(l, r, kl, kr) \ + movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ + andl l ## 0d, RT0d; \ + roll $1, RT0d; \ + shlq $32, RT0; \ + xorq RT0, l ## 0; \ + movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ + orq r ## 0, RT1; \ + shrq $32, RT1; \ + xorq RT1, r ## 0; \ + \ + movl (key_table + ((kl) * 2) * 4)(CTX), RT2d; \ + andl l ## 1d, RT2d; \ + roll $1, RT2d; \ + shlq $32, RT2; \ + xorq RT2, l ## 1; \ + movq (key_table + ((kr) * 2) * 4)(CTX), RT0; \ + orq r ## 1, RT0; \ + shrq $32, RT0; \ + xorq RT0, r ## 1; \ + \ + movq (key_table + ((kl) * 2) * 4)(CTX), RT1; \ + orq l ## 0, RT1; \ + shrq $32, RT1; \ + xorq RT1, l ## 0; \ + movl (key_table + ((kr) * 2) * 4)(CTX), RT2d; \ + andl r ## 0d, RT2d; \ + roll $1, RT2d; \ + shlq $32, RT2; \ + xorq RT2, r ## 0; \ + \ + movq (key_table + ((kl) * 2) * 4)(CTX), RT0; \ + orq l ## 1, RT0; \ + shrq $32, RT0; \ + xorq RT0, l ## 1; \ + movl (key_table + ((kr) * 2) * 4)(CTX), RT1d; \ + andl r ## 1d, RT1d; \ + roll $1, RT1d; \ + shlq $32, RT1; \ + xorq RT1, r ## 1; + +#define enc_rounds2(i) \ + roundsm2(RAB, i + 2, RCD); \ + roundsm2(RCD, i + 3, RAB); \ + roundsm2(RAB, i + 4, RCD); \ + roundsm2(RCD, i + 5, RAB); \ + roundsm2(RAB, i + 6, RCD); \ + roundsm2(RCD, i + 7, RAB); + +#define enc_fls2(i) \ + fls2(RAB, RCD, i + 0, i + 1); + +#define enc_inpack2() \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rorq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rolq $32, RCD0; \ + xorq key_table(CTX), RAB0; \ + \ + movq 8*2(RIO), RAB1; \ + bswapq RAB1; \ + rorq $32, RAB1; \ + movq 12*2(RIO), RCD1; \ + bswapq RCD1; \ + rolq $32, RCD1; \ + xorq key_table(CTX), RAB1; + +#define enc_outunpack2(op, max) \ + xorq key_table(CTX, max, 8), RCD0; \ + rolq $32, RCD0; \ + bswapq RCD0; \ + op ## q RCD0, (RIO); \ + rorq $32, RAB0; \ + bswapq RAB0; \ + op ## q RAB0, 4*2(RIO); \ + \ + xorq key_table(CTX, max, 8), RCD1; \ + rolq $32, RCD1; \ + bswapq RCD1; \ + op ## q RCD1, 8*2(RIO); \ + rorq $32, RAB1; \ + bswapq RAB1; \ + op ## q RAB1, 12*2(RIO); + +#define dec_rounds2(i) \ + roundsm2(RAB, i + 7, RCD); \ + roundsm2(RCD, i + 6, RAB); \ + roundsm2(RAB, i + 5, RCD); \ + roundsm2(RCD, i + 4, RAB); \ + roundsm2(RAB, i + 3, RCD); \ + roundsm2(RCD, i + 2, RAB); + +#define dec_fls2(i) \ + fls2(RAB, RCD, i + 1, i + 0); + +#define dec_inpack2(max) \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rorq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rolq $32, RCD0; \ + xorq key_table(CTX, max, 8), RAB0; \ + \ + movq 8*2(RIO), RAB1; \ + bswapq RAB1; \ + rorq $32, RAB1; \ + movq 12*2(RIO), RCD1; \ + bswapq RCD1; \ + rolq $32, RCD1; \ + xorq key_table(CTX, max, 8), RAB1; + +#define dec_outunpack2() \ + xorq key_table(CTX), RCD0; \ + rolq $32, RCD0; \ + bswapq RCD0; \ + movq RCD0, (RIO); \ + rorq $32, RAB0; \ + bswapq RAB0; \ + movq RAB0, 4*2(RIO); \ + \ + xorq key_table(CTX), RCD1; \ + rolq $32, RCD1; \ + bswapq RCD1; \ + movq RCD1, 8*2(RIO); \ + rorq $32, RAB1; \ + bswapq RAB1; \ + movq RAB1, 12*2(RIO); + +.global __camellia_enc_blk_2way; +.type __camellia_enc_blk_2way,@function; + +__camellia_enc_blk_2way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool xor + */ + pushq %rbx; + + movq %rbp, RRBP; + movq %rcx, RXOR; + movq %rsi, RDST; + movq %rdx, RIO; + + enc_inpack2(); + + enc_rounds2(0); + enc_fls2(8); + enc_rounds2(8); + enc_fls2(16); + enc_rounds2(16); + movl $24, RT2d; /* max */ + + cmpb $16, key_length(CTX); + je __enc2_done; + + enc_fls2(24); + enc_rounds2(24); + movl $32, RT2d; /* max */ + +__enc2_done: + test RXORbl, RXORbl; + movq RDST, RIO; + jnz __enc2_xor; + + enc_outunpack2(mov, RT2); + + movq RRBP, %rbp; + popq %rbx; + ret; + +__enc2_xor: + enc_outunpack2(xor, RT2); + + movq RRBP, %rbp; + popq %rbx; + ret; + +.global camellia_dec_blk_2way; +.type camellia_dec_blk_2way,@function; + +camellia_dec_blk_2way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + cmpl $16, key_length(CTX); + movl $32, RT2d; + movl $24, RXORd; + cmovel RXORd, RT2d; /* max */ + + movq %rbx, RXOR; + movq %rbp, RRBP; + movq %rsi, RDST; + movq %rdx, RIO; + + dec_inpack2(RT2); + + cmpb $24, RT2bl; + je __dec2_rounds16; + + dec_rounds2(24); + dec_fls2(24); + +__dec2_rounds16: + dec_rounds2(16); + dec_fls2(16); + dec_rounds2(8); + dec_fls2(8); + dec_rounds2(0); + + movq RDST, RIO; + + dec_outunpack2(); + + movq RRBP, %rbp; + movq RXOR, %rbx; + ret; diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c new file mode 100644 index 000000000000..1ca36a93fd2f --- /dev/null +++ b/arch/x86/crypto/camellia_glue.c @@ -0,0 +1,1952 @@ +/* + * Glue Code for assembler optimized version of Camellia + * + * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * Camellia parts based on code by: + * Copyright (C) 2006 NTT (Nippon Telegraph and Telephone Corporation) + * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: + * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> + * CTR part based on code (crypto/ctr.c) by: + * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +#include <asm/processor.h> +#include <asm/unaligned.h> +#include <linux/crypto.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <crypto/algapi.h> +#include <crypto/b128ops.h> +#include <crypto/lrw.h> +#include <crypto/xts.h> + +#define CAMELLIA_MIN_KEY_SIZE 16 +#define CAMELLIA_MAX_KEY_SIZE 32 +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 + +struct camellia_ctx { + u64 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; + u32 key_length; +}; + +/* regular block cipher functions */ +asmlinkage void __camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void camellia_dec_blk(struct camellia_ctx *ctx, u8 *dst, + const u8 *src); + +/* 2-way parallel cipher functions */ +asmlinkage void __camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void camellia_dec_blk_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src); + +static inline void camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk(ctx, dst, src, false); +} + +static inline void camellia_enc_blk_xor(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk(ctx, dst, src, true); +} + +static inline void camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk_2way(ctx, dst, src, false); +} + +static inline void camellia_enc_blk_xor_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk_2way(ctx, dst, src, true); +} + +static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + camellia_enc_blk(crypto_tfm_ctx(tfm), dst, src); +} + +static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + camellia_dec_blk(crypto_tfm_ctx(tfm), dst, src); +} + +/* camellia sboxes */ +const u64 camellia_sp10011110[256] = { + 0x7000007070707000, 0x8200008282828200, 0x2c00002c2c2c2c00, + 0xec0000ecececec00, 0xb30000b3b3b3b300, 0x2700002727272700, + 0xc00000c0c0c0c000, 0xe50000e5e5e5e500, 0xe40000e4e4e4e400, + 0x8500008585858500, 0x5700005757575700, 0x3500003535353500, + 0xea0000eaeaeaea00, 0x0c00000c0c0c0c00, 0xae0000aeaeaeae00, + 0x4100004141414100, 0x2300002323232300, 0xef0000efefefef00, + 0x6b00006b6b6b6b00, 0x9300009393939300, 0x4500004545454500, + 0x1900001919191900, 0xa50000a5a5a5a500, 0x2100002121212100, + 0xed0000edededed00, 0x0e00000e0e0e0e00, 0x4f00004f4f4f4f00, + 0x4e00004e4e4e4e00, 0x1d00001d1d1d1d00, 0x6500006565656500, + 0x9200009292929200, 0xbd0000bdbdbdbd00, 0x8600008686868600, + 0xb80000b8b8b8b800, 0xaf0000afafafaf00, 0x8f00008f8f8f8f00, + 0x7c00007c7c7c7c00, 0xeb0000ebebebeb00, 0x1f00001f1f1f1f00, + 0xce0000cececece00, 0x3e00003e3e3e3e00, 0x3000003030303000, + 0xdc0000dcdcdcdc00, 0x5f00005f5f5f5f00, 0x5e00005e5e5e5e00, + 0xc50000c5c5c5c500, 0x0b00000b0b0b0b00, 0x1a00001a1a1a1a00, + 0xa60000a6a6a6a600, 0xe10000e1e1e1e100, 0x3900003939393900, + 0xca0000cacacaca00, 0xd50000d5d5d5d500, 0x4700004747474700, + 0x5d00005d5d5d5d00, 0x3d00003d3d3d3d00, 0xd90000d9d9d9d900, + 0x0100000101010100, 0x5a00005a5a5a5a00, 0xd60000d6d6d6d600, + 0x5100005151515100, 0x5600005656565600, 0x6c00006c6c6c6c00, + 0x4d00004d4d4d4d00, 0x8b00008b8b8b8b00, 0x0d00000d0d0d0d00, + 0x9a00009a9a9a9a00, 0x6600006666666600, 0xfb0000fbfbfbfb00, + 0xcc0000cccccccc00, 0xb00000b0b0b0b000, 0x2d00002d2d2d2d00, + 0x7400007474747400, 0x1200001212121200, 0x2b00002b2b2b2b00, + 0x2000002020202000, 0xf00000f0f0f0f000, 0xb10000b1b1b1b100, + 0x8400008484848400, 0x9900009999999900, 0xdf0000dfdfdfdf00, + 0x4c00004c4c4c4c00, 0xcb0000cbcbcbcb00, 0xc20000c2c2c2c200, + 0x3400003434343400, 0x7e00007e7e7e7e00, 0x7600007676767600, + 0x0500000505050500, 0x6d00006d6d6d6d00, 0xb70000b7b7b7b700, + 0xa90000a9a9a9a900, 0x3100003131313100, 0xd10000d1d1d1d100, + 0x1700001717171700, 0x0400000404040400, 0xd70000d7d7d7d700, + 0x1400001414141400, 0x5800005858585800, 0x3a00003a3a3a3a00, + 0x6100006161616100, 0xde0000dededede00, 0x1b00001b1b1b1b00, + 0x1100001111111100, 0x1c00001c1c1c1c00, 0x3200003232323200, + 0x0f00000f0f0f0f00, 0x9c00009c9c9c9c00, 0x1600001616161600, + 0x5300005353535300, 0x1800001818181800, 0xf20000f2f2f2f200, + 0x2200002222222200, 0xfe0000fefefefe00, 0x4400004444444400, + 0xcf0000cfcfcfcf00, 0xb20000b2b2b2b200, 0xc30000c3c3c3c300, + 0xb50000b5b5b5b500, 0x7a00007a7a7a7a00, 0x9100009191919100, + 0x2400002424242400, 0x0800000808080800, 0xe80000e8e8e8e800, + 0xa80000a8a8a8a800, 0x6000006060606000, 0xfc0000fcfcfcfc00, + 0x6900006969696900, 0x5000005050505000, 0xaa0000aaaaaaaa00, + 0xd00000d0d0d0d000, 0xa00000a0a0a0a000, 0x7d00007d7d7d7d00, + 0xa10000a1a1a1a100, 0x8900008989898900, 0x6200006262626200, + 0x9700009797979700, 0x5400005454545400, 0x5b00005b5b5b5b00, + 0x1e00001e1e1e1e00, 0x9500009595959500, 0xe00000e0e0e0e000, + 0xff0000ffffffff00, 0x6400006464646400, 0xd20000d2d2d2d200, + 0x1000001010101000, 0xc40000c4c4c4c400, 0x0000000000000000, + 0x4800004848484800, 0xa30000a3a3a3a300, 0xf70000f7f7f7f700, + 0x7500007575757500, 0xdb0000dbdbdbdb00, 0x8a00008a8a8a8a00, + 0x0300000303030300, 0xe60000e6e6e6e600, 0xda0000dadadada00, + 0x0900000909090900, 0x3f00003f3f3f3f00, 0xdd0000dddddddd00, + 0x9400009494949400, 0x8700008787878700, 0x5c00005c5c5c5c00, + 0x8300008383838300, 0x0200000202020200, 0xcd0000cdcdcdcd00, + 0x4a00004a4a4a4a00, 0x9000009090909000, 0x3300003333333300, + 0x7300007373737300, 0x6700006767676700, 0xf60000f6f6f6f600, + 0xf30000f3f3f3f300, 0x9d00009d9d9d9d00, 0x7f00007f7f7f7f00, + 0xbf0000bfbfbfbf00, 0xe20000e2e2e2e200, 0x5200005252525200, + 0x9b00009b9b9b9b00, 0xd80000d8d8d8d800, 0x2600002626262600, + 0xc80000c8c8c8c800, 0x3700003737373700, 0xc60000c6c6c6c600, + 0x3b00003b3b3b3b00, 0x8100008181818100, 0x9600009696969600, + 0x6f00006f6f6f6f00, 0x4b00004b4b4b4b00, 0x1300001313131300, + 0xbe0000bebebebe00, 0x6300006363636300, 0x2e00002e2e2e2e00, + 0xe90000e9e9e9e900, 0x7900007979797900, 0xa70000a7a7a7a700, + 0x8c00008c8c8c8c00, 0x9f00009f9f9f9f00, 0x6e00006e6e6e6e00, + 0xbc0000bcbcbcbc00, 0x8e00008e8e8e8e00, 0x2900002929292900, + 0xf50000f5f5f5f500, 0xf90000f9f9f9f900, 0xb60000b6b6b6b600, + 0x2f00002f2f2f2f00, 0xfd0000fdfdfdfd00, 0xb40000b4b4b4b400, + 0x5900005959595900, 0x7800007878787800, 0x9800009898989800, + 0x0600000606060600, 0x6a00006a6a6a6a00, 0xe70000e7e7e7e700, + 0x4600004646464600, 0x7100007171717100, 0xba0000babababa00, + 0xd40000d4d4d4d400, 0x2500002525252500, 0xab0000abababab00, + 0x4200004242424200, 0x8800008888888800, 0xa20000a2a2a2a200, + 0x8d00008d8d8d8d00, 0xfa0000fafafafa00, 0x7200007272727200, + 0x0700000707070700, 0xb90000b9b9b9b900, 0x5500005555555500, + 0xf80000f8f8f8f800, 0xee0000eeeeeeee00, 0xac0000acacacac00, + 0x0a00000a0a0a0a00, 0x3600003636363600, 0x4900004949494900, + 0x2a00002a2a2a2a00, 0x6800006868686800, 0x3c00003c3c3c3c00, + 0x3800003838383800, 0xf10000f1f1f1f100, 0xa40000a4a4a4a400, + 0x4000004040404000, 0x2800002828282800, 0xd30000d3d3d3d300, + 0x7b00007b7b7b7b00, 0xbb0000bbbbbbbb00, 0xc90000c9c9c9c900, + 0x4300004343434300, 0xc10000c1c1c1c100, 0x1500001515151500, + 0xe30000e3e3e3e300, 0xad0000adadadad00, 0xf40000f4f4f4f400, + 0x7700007777777700, 0xc70000c7c7c7c700, 0x8000008080808000, + 0x9e00009e9e9e9e00, +}; + +const u64 camellia_sp22000222[256] = { + 0xe0e0000000e0e0e0, 0x0505000000050505, 0x5858000000585858, + 0xd9d9000000d9d9d9, 0x6767000000676767, 0x4e4e0000004e4e4e, + 0x8181000000818181, 0xcbcb000000cbcbcb, 0xc9c9000000c9c9c9, + 0x0b0b0000000b0b0b, 0xaeae000000aeaeae, 0x6a6a0000006a6a6a, + 0xd5d5000000d5d5d5, 0x1818000000181818, 0x5d5d0000005d5d5d, + 0x8282000000828282, 0x4646000000464646, 0xdfdf000000dfdfdf, + 0xd6d6000000d6d6d6, 0x2727000000272727, 0x8a8a0000008a8a8a, + 0x3232000000323232, 0x4b4b0000004b4b4b, 0x4242000000424242, + 0xdbdb000000dbdbdb, 0x1c1c0000001c1c1c, 0x9e9e0000009e9e9e, + 0x9c9c0000009c9c9c, 0x3a3a0000003a3a3a, 0xcaca000000cacaca, + 0x2525000000252525, 0x7b7b0000007b7b7b, 0x0d0d0000000d0d0d, + 0x7171000000717171, 0x5f5f0000005f5f5f, 0x1f1f0000001f1f1f, + 0xf8f8000000f8f8f8, 0xd7d7000000d7d7d7, 0x3e3e0000003e3e3e, + 0x9d9d0000009d9d9d, 0x7c7c0000007c7c7c, 0x6060000000606060, + 0xb9b9000000b9b9b9, 0xbebe000000bebebe, 0xbcbc000000bcbcbc, + 0x8b8b0000008b8b8b, 0x1616000000161616, 0x3434000000343434, + 0x4d4d0000004d4d4d, 0xc3c3000000c3c3c3, 0x7272000000727272, + 0x9595000000959595, 0xabab000000ababab, 0x8e8e0000008e8e8e, + 0xbaba000000bababa, 0x7a7a0000007a7a7a, 0xb3b3000000b3b3b3, + 0x0202000000020202, 0xb4b4000000b4b4b4, 0xadad000000adadad, + 0xa2a2000000a2a2a2, 0xacac000000acacac, 0xd8d8000000d8d8d8, + 0x9a9a0000009a9a9a, 0x1717000000171717, 0x1a1a0000001a1a1a, + 0x3535000000353535, 0xcccc000000cccccc, 0xf7f7000000f7f7f7, + 0x9999000000999999, 0x6161000000616161, 0x5a5a0000005a5a5a, + 0xe8e8000000e8e8e8, 0x2424000000242424, 0x5656000000565656, + 0x4040000000404040, 0xe1e1000000e1e1e1, 0x6363000000636363, + 0x0909000000090909, 0x3333000000333333, 0xbfbf000000bfbfbf, + 0x9898000000989898, 0x9797000000979797, 0x8585000000858585, + 0x6868000000686868, 0xfcfc000000fcfcfc, 0xecec000000ececec, + 0x0a0a0000000a0a0a, 0xdada000000dadada, 0x6f6f0000006f6f6f, + 0x5353000000535353, 0x6262000000626262, 0xa3a3000000a3a3a3, + 0x2e2e0000002e2e2e, 0x0808000000080808, 0xafaf000000afafaf, + 0x2828000000282828, 0xb0b0000000b0b0b0, 0x7474000000747474, + 0xc2c2000000c2c2c2, 0xbdbd000000bdbdbd, 0x3636000000363636, + 0x2222000000222222, 0x3838000000383838, 0x6464000000646464, + 0x1e1e0000001e1e1e, 0x3939000000393939, 0x2c2c0000002c2c2c, + 0xa6a6000000a6a6a6, 0x3030000000303030, 0xe5e5000000e5e5e5, + 0x4444000000444444, 0xfdfd000000fdfdfd, 0x8888000000888888, + 0x9f9f0000009f9f9f, 0x6565000000656565, 0x8787000000878787, + 0x6b6b0000006b6b6b, 0xf4f4000000f4f4f4, 0x2323000000232323, + 0x4848000000484848, 0x1010000000101010, 0xd1d1000000d1d1d1, + 0x5151000000515151, 0xc0c0000000c0c0c0, 0xf9f9000000f9f9f9, + 0xd2d2000000d2d2d2, 0xa0a0000000a0a0a0, 0x5555000000555555, + 0xa1a1000000a1a1a1, 0x4141000000414141, 0xfafa000000fafafa, + 0x4343000000434343, 0x1313000000131313, 0xc4c4000000c4c4c4, + 0x2f2f0000002f2f2f, 0xa8a8000000a8a8a8, 0xb6b6000000b6b6b6, + 0x3c3c0000003c3c3c, 0x2b2b0000002b2b2b, 0xc1c1000000c1c1c1, + 0xffff000000ffffff, 0xc8c8000000c8c8c8, 0xa5a5000000a5a5a5, + 0x2020000000202020, 0x8989000000898989, 0x0000000000000000, + 0x9090000000909090, 0x4747000000474747, 0xefef000000efefef, + 0xeaea000000eaeaea, 0xb7b7000000b7b7b7, 0x1515000000151515, + 0x0606000000060606, 0xcdcd000000cdcdcd, 0xb5b5000000b5b5b5, + 0x1212000000121212, 0x7e7e0000007e7e7e, 0xbbbb000000bbbbbb, + 0x2929000000292929, 0x0f0f0000000f0f0f, 0xb8b8000000b8b8b8, + 0x0707000000070707, 0x0404000000040404, 0x9b9b0000009b9b9b, + 0x9494000000949494, 0x2121000000212121, 0x6666000000666666, + 0xe6e6000000e6e6e6, 0xcece000000cecece, 0xeded000000ededed, + 0xe7e7000000e7e7e7, 0x3b3b0000003b3b3b, 0xfefe000000fefefe, + 0x7f7f0000007f7f7f, 0xc5c5000000c5c5c5, 0xa4a4000000a4a4a4, + 0x3737000000373737, 0xb1b1000000b1b1b1, 0x4c4c0000004c4c4c, + 0x9191000000919191, 0x6e6e0000006e6e6e, 0x8d8d0000008d8d8d, + 0x7676000000767676, 0x0303000000030303, 0x2d2d0000002d2d2d, + 0xdede000000dedede, 0x9696000000969696, 0x2626000000262626, + 0x7d7d0000007d7d7d, 0xc6c6000000c6c6c6, 0x5c5c0000005c5c5c, + 0xd3d3000000d3d3d3, 0xf2f2000000f2f2f2, 0x4f4f0000004f4f4f, + 0x1919000000191919, 0x3f3f0000003f3f3f, 0xdcdc000000dcdcdc, + 0x7979000000797979, 0x1d1d0000001d1d1d, 0x5252000000525252, + 0xebeb000000ebebeb, 0xf3f3000000f3f3f3, 0x6d6d0000006d6d6d, + 0x5e5e0000005e5e5e, 0xfbfb000000fbfbfb, 0x6969000000696969, + 0xb2b2000000b2b2b2, 0xf0f0000000f0f0f0, 0x3131000000313131, + 0x0c0c0000000c0c0c, 0xd4d4000000d4d4d4, 0xcfcf000000cfcfcf, + 0x8c8c0000008c8c8c, 0xe2e2000000e2e2e2, 0x7575000000757575, + 0xa9a9000000a9a9a9, 0x4a4a0000004a4a4a, 0x5757000000575757, + 0x8484000000848484, 0x1111000000111111, 0x4545000000454545, + 0x1b1b0000001b1b1b, 0xf5f5000000f5f5f5, 0xe4e4000000e4e4e4, + 0x0e0e0000000e0e0e, 0x7373000000737373, 0xaaaa000000aaaaaa, + 0xf1f1000000f1f1f1, 0xdddd000000dddddd, 0x5959000000595959, + 0x1414000000141414, 0x6c6c0000006c6c6c, 0x9292000000929292, + 0x5454000000545454, 0xd0d0000000d0d0d0, 0x7878000000787878, + 0x7070000000707070, 0xe3e3000000e3e3e3, 0x4949000000494949, + 0x8080000000808080, 0x5050000000505050, 0xa7a7000000a7a7a7, + 0xf6f6000000f6f6f6, 0x7777000000777777, 0x9393000000939393, + 0x8686000000868686, 0x8383000000838383, 0x2a2a0000002a2a2a, + 0xc7c7000000c7c7c7, 0x5b5b0000005b5b5b, 0xe9e9000000e9e9e9, + 0xeeee000000eeeeee, 0x8f8f0000008f8f8f, 0x0101000000010101, + 0x3d3d0000003d3d3d, +}; + +const u64 camellia_sp03303033[256] = { + 0x0038380038003838, 0x0041410041004141, 0x0016160016001616, + 0x0076760076007676, 0x00d9d900d900d9d9, 0x0093930093009393, + 0x0060600060006060, 0x00f2f200f200f2f2, 0x0072720072007272, + 0x00c2c200c200c2c2, 0x00abab00ab00abab, 0x009a9a009a009a9a, + 0x0075750075007575, 0x0006060006000606, 0x0057570057005757, + 0x00a0a000a000a0a0, 0x0091910091009191, 0x00f7f700f700f7f7, + 0x00b5b500b500b5b5, 0x00c9c900c900c9c9, 0x00a2a200a200a2a2, + 0x008c8c008c008c8c, 0x00d2d200d200d2d2, 0x0090900090009090, + 0x00f6f600f600f6f6, 0x0007070007000707, 0x00a7a700a700a7a7, + 0x0027270027002727, 0x008e8e008e008e8e, 0x00b2b200b200b2b2, + 0x0049490049004949, 0x00dede00de00dede, 0x0043430043004343, + 0x005c5c005c005c5c, 0x00d7d700d700d7d7, 0x00c7c700c700c7c7, + 0x003e3e003e003e3e, 0x00f5f500f500f5f5, 0x008f8f008f008f8f, + 0x0067670067006767, 0x001f1f001f001f1f, 0x0018180018001818, + 0x006e6e006e006e6e, 0x00afaf00af00afaf, 0x002f2f002f002f2f, + 0x00e2e200e200e2e2, 0x0085850085008585, 0x000d0d000d000d0d, + 0x0053530053005353, 0x00f0f000f000f0f0, 0x009c9c009c009c9c, + 0x0065650065006565, 0x00eaea00ea00eaea, 0x00a3a300a300a3a3, + 0x00aeae00ae00aeae, 0x009e9e009e009e9e, 0x00ecec00ec00ecec, + 0x0080800080008080, 0x002d2d002d002d2d, 0x006b6b006b006b6b, + 0x00a8a800a800a8a8, 0x002b2b002b002b2b, 0x0036360036003636, + 0x00a6a600a600a6a6, 0x00c5c500c500c5c5, 0x0086860086008686, + 0x004d4d004d004d4d, 0x0033330033003333, 0x00fdfd00fd00fdfd, + 0x0066660066006666, 0x0058580058005858, 0x0096960096009696, + 0x003a3a003a003a3a, 0x0009090009000909, 0x0095950095009595, + 0x0010100010001010, 0x0078780078007878, 0x00d8d800d800d8d8, + 0x0042420042004242, 0x00cccc00cc00cccc, 0x00efef00ef00efef, + 0x0026260026002626, 0x00e5e500e500e5e5, 0x0061610061006161, + 0x001a1a001a001a1a, 0x003f3f003f003f3f, 0x003b3b003b003b3b, + 0x0082820082008282, 0x00b6b600b600b6b6, 0x00dbdb00db00dbdb, + 0x00d4d400d400d4d4, 0x0098980098009898, 0x00e8e800e800e8e8, + 0x008b8b008b008b8b, 0x0002020002000202, 0x00ebeb00eb00ebeb, + 0x000a0a000a000a0a, 0x002c2c002c002c2c, 0x001d1d001d001d1d, + 0x00b0b000b000b0b0, 0x006f6f006f006f6f, 0x008d8d008d008d8d, + 0x0088880088008888, 0x000e0e000e000e0e, 0x0019190019001919, + 0x0087870087008787, 0x004e4e004e004e4e, 0x000b0b000b000b0b, + 0x00a9a900a900a9a9, 0x000c0c000c000c0c, 0x0079790079007979, + 0x0011110011001111, 0x007f7f007f007f7f, 0x0022220022002222, + 0x00e7e700e700e7e7, 0x0059590059005959, 0x00e1e100e100e1e1, + 0x00dada00da00dada, 0x003d3d003d003d3d, 0x00c8c800c800c8c8, + 0x0012120012001212, 0x0004040004000404, 0x0074740074007474, + 0x0054540054005454, 0x0030300030003030, 0x007e7e007e007e7e, + 0x00b4b400b400b4b4, 0x0028280028002828, 0x0055550055005555, + 0x0068680068006868, 0x0050500050005050, 0x00bebe00be00bebe, + 0x00d0d000d000d0d0, 0x00c4c400c400c4c4, 0x0031310031003131, + 0x00cbcb00cb00cbcb, 0x002a2a002a002a2a, 0x00adad00ad00adad, + 0x000f0f000f000f0f, 0x00caca00ca00caca, 0x0070700070007070, + 0x00ffff00ff00ffff, 0x0032320032003232, 0x0069690069006969, + 0x0008080008000808, 0x0062620062006262, 0x0000000000000000, + 0x0024240024002424, 0x00d1d100d100d1d1, 0x00fbfb00fb00fbfb, + 0x00baba00ba00baba, 0x00eded00ed00eded, 0x0045450045004545, + 0x0081810081008181, 0x0073730073007373, 0x006d6d006d006d6d, + 0x0084840084008484, 0x009f9f009f009f9f, 0x00eeee00ee00eeee, + 0x004a4a004a004a4a, 0x00c3c300c300c3c3, 0x002e2e002e002e2e, + 0x00c1c100c100c1c1, 0x0001010001000101, 0x00e6e600e600e6e6, + 0x0025250025002525, 0x0048480048004848, 0x0099990099009999, + 0x00b9b900b900b9b9, 0x00b3b300b300b3b3, 0x007b7b007b007b7b, + 0x00f9f900f900f9f9, 0x00cece00ce00cece, 0x00bfbf00bf00bfbf, + 0x00dfdf00df00dfdf, 0x0071710071007171, 0x0029290029002929, + 0x00cdcd00cd00cdcd, 0x006c6c006c006c6c, 0x0013130013001313, + 0x0064640064006464, 0x009b9b009b009b9b, 0x0063630063006363, + 0x009d9d009d009d9d, 0x00c0c000c000c0c0, 0x004b4b004b004b4b, + 0x00b7b700b700b7b7, 0x00a5a500a500a5a5, 0x0089890089008989, + 0x005f5f005f005f5f, 0x00b1b100b100b1b1, 0x0017170017001717, + 0x00f4f400f400f4f4, 0x00bcbc00bc00bcbc, 0x00d3d300d300d3d3, + 0x0046460046004646, 0x00cfcf00cf00cfcf, 0x0037370037003737, + 0x005e5e005e005e5e, 0x0047470047004747, 0x0094940094009494, + 0x00fafa00fa00fafa, 0x00fcfc00fc00fcfc, 0x005b5b005b005b5b, + 0x0097970097009797, 0x00fefe00fe00fefe, 0x005a5a005a005a5a, + 0x00acac00ac00acac, 0x003c3c003c003c3c, 0x004c4c004c004c4c, + 0x0003030003000303, 0x0035350035003535, 0x00f3f300f300f3f3, + 0x0023230023002323, 0x00b8b800b800b8b8, 0x005d5d005d005d5d, + 0x006a6a006a006a6a, 0x0092920092009292, 0x00d5d500d500d5d5, + 0x0021210021002121, 0x0044440044004444, 0x0051510051005151, + 0x00c6c600c600c6c6, 0x007d7d007d007d7d, 0x0039390039003939, + 0x0083830083008383, 0x00dcdc00dc00dcdc, 0x00aaaa00aa00aaaa, + 0x007c7c007c007c7c, 0x0077770077007777, 0x0056560056005656, + 0x0005050005000505, 0x001b1b001b001b1b, 0x00a4a400a400a4a4, + 0x0015150015001515, 0x0034340034003434, 0x001e1e001e001e1e, + 0x001c1c001c001c1c, 0x00f8f800f800f8f8, 0x0052520052005252, + 0x0020200020002020, 0x0014140014001414, 0x00e9e900e900e9e9, + 0x00bdbd00bd00bdbd, 0x00dddd00dd00dddd, 0x00e4e400e400e4e4, + 0x00a1a100a100a1a1, 0x00e0e000e000e0e0, 0x008a8a008a008a8a, + 0x00f1f100f100f1f1, 0x00d6d600d600d6d6, 0x007a7a007a007a7a, + 0x00bbbb00bb00bbbb, 0x00e3e300e300e3e3, 0x0040400040004040, + 0x004f4f004f004f4f, +}; + +const u64 camellia_sp00444404[256] = { + 0x0000707070700070, 0x00002c2c2c2c002c, 0x0000b3b3b3b300b3, + 0x0000c0c0c0c000c0, 0x0000e4e4e4e400e4, 0x0000575757570057, + 0x0000eaeaeaea00ea, 0x0000aeaeaeae00ae, 0x0000232323230023, + 0x00006b6b6b6b006b, 0x0000454545450045, 0x0000a5a5a5a500a5, + 0x0000edededed00ed, 0x00004f4f4f4f004f, 0x00001d1d1d1d001d, + 0x0000929292920092, 0x0000868686860086, 0x0000afafafaf00af, + 0x00007c7c7c7c007c, 0x00001f1f1f1f001f, 0x00003e3e3e3e003e, + 0x0000dcdcdcdc00dc, 0x00005e5e5e5e005e, 0x00000b0b0b0b000b, + 0x0000a6a6a6a600a6, 0x0000393939390039, 0x0000d5d5d5d500d5, + 0x00005d5d5d5d005d, 0x0000d9d9d9d900d9, 0x00005a5a5a5a005a, + 0x0000515151510051, 0x00006c6c6c6c006c, 0x00008b8b8b8b008b, + 0x00009a9a9a9a009a, 0x0000fbfbfbfb00fb, 0x0000b0b0b0b000b0, + 0x0000747474740074, 0x00002b2b2b2b002b, 0x0000f0f0f0f000f0, + 0x0000848484840084, 0x0000dfdfdfdf00df, 0x0000cbcbcbcb00cb, + 0x0000343434340034, 0x0000767676760076, 0x00006d6d6d6d006d, + 0x0000a9a9a9a900a9, 0x0000d1d1d1d100d1, 0x0000040404040004, + 0x0000141414140014, 0x00003a3a3a3a003a, 0x0000dededede00de, + 0x0000111111110011, 0x0000323232320032, 0x00009c9c9c9c009c, + 0x0000535353530053, 0x0000f2f2f2f200f2, 0x0000fefefefe00fe, + 0x0000cfcfcfcf00cf, 0x0000c3c3c3c300c3, 0x00007a7a7a7a007a, + 0x0000242424240024, 0x0000e8e8e8e800e8, 0x0000606060600060, + 0x0000696969690069, 0x0000aaaaaaaa00aa, 0x0000a0a0a0a000a0, + 0x0000a1a1a1a100a1, 0x0000626262620062, 0x0000545454540054, + 0x00001e1e1e1e001e, 0x0000e0e0e0e000e0, 0x0000646464640064, + 0x0000101010100010, 0x0000000000000000, 0x0000a3a3a3a300a3, + 0x0000757575750075, 0x00008a8a8a8a008a, 0x0000e6e6e6e600e6, + 0x0000090909090009, 0x0000dddddddd00dd, 0x0000878787870087, + 0x0000838383830083, 0x0000cdcdcdcd00cd, 0x0000909090900090, + 0x0000737373730073, 0x0000f6f6f6f600f6, 0x00009d9d9d9d009d, + 0x0000bfbfbfbf00bf, 0x0000525252520052, 0x0000d8d8d8d800d8, + 0x0000c8c8c8c800c8, 0x0000c6c6c6c600c6, 0x0000818181810081, + 0x00006f6f6f6f006f, 0x0000131313130013, 0x0000636363630063, + 0x0000e9e9e9e900e9, 0x0000a7a7a7a700a7, 0x00009f9f9f9f009f, + 0x0000bcbcbcbc00bc, 0x0000292929290029, 0x0000f9f9f9f900f9, + 0x00002f2f2f2f002f, 0x0000b4b4b4b400b4, 0x0000787878780078, + 0x0000060606060006, 0x0000e7e7e7e700e7, 0x0000717171710071, + 0x0000d4d4d4d400d4, 0x0000abababab00ab, 0x0000888888880088, + 0x00008d8d8d8d008d, 0x0000727272720072, 0x0000b9b9b9b900b9, + 0x0000f8f8f8f800f8, 0x0000acacacac00ac, 0x0000363636360036, + 0x00002a2a2a2a002a, 0x00003c3c3c3c003c, 0x0000f1f1f1f100f1, + 0x0000404040400040, 0x0000d3d3d3d300d3, 0x0000bbbbbbbb00bb, + 0x0000434343430043, 0x0000151515150015, 0x0000adadadad00ad, + 0x0000777777770077, 0x0000808080800080, 0x0000828282820082, + 0x0000ecececec00ec, 0x0000272727270027, 0x0000e5e5e5e500e5, + 0x0000858585850085, 0x0000353535350035, 0x00000c0c0c0c000c, + 0x0000414141410041, 0x0000efefefef00ef, 0x0000939393930093, + 0x0000191919190019, 0x0000212121210021, 0x00000e0e0e0e000e, + 0x00004e4e4e4e004e, 0x0000656565650065, 0x0000bdbdbdbd00bd, + 0x0000b8b8b8b800b8, 0x00008f8f8f8f008f, 0x0000ebebebeb00eb, + 0x0000cececece00ce, 0x0000303030300030, 0x00005f5f5f5f005f, + 0x0000c5c5c5c500c5, 0x00001a1a1a1a001a, 0x0000e1e1e1e100e1, + 0x0000cacacaca00ca, 0x0000474747470047, 0x00003d3d3d3d003d, + 0x0000010101010001, 0x0000d6d6d6d600d6, 0x0000565656560056, + 0x00004d4d4d4d004d, 0x00000d0d0d0d000d, 0x0000666666660066, + 0x0000cccccccc00cc, 0x00002d2d2d2d002d, 0x0000121212120012, + 0x0000202020200020, 0x0000b1b1b1b100b1, 0x0000999999990099, + 0x00004c4c4c4c004c, 0x0000c2c2c2c200c2, 0x00007e7e7e7e007e, + 0x0000050505050005, 0x0000b7b7b7b700b7, 0x0000313131310031, + 0x0000171717170017, 0x0000d7d7d7d700d7, 0x0000585858580058, + 0x0000616161610061, 0x00001b1b1b1b001b, 0x00001c1c1c1c001c, + 0x00000f0f0f0f000f, 0x0000161616160016, 0x0000181818180018, + 0x0000222222220022, 0x0000444444440044, 0x0000b2b2b2b200b2, + 0x0000b5b5b5b500b5, 0x0000919191910091, 0x0000080808080008, + 0x0000a8a8a8a800a8, 0x0000fcfcfcfc00fc, 0x0000505050500050, + 0x0000d0d0d0d000d0, 0x00007d7d7d7d007d, 0x0000898989890089, + 0x0000979797970097, 0x00005b5b5b5b005b, 0x0000959595950095, + 0x0000ffffffff00ff, 0x0000d2d2d2d200d2, 0x0000c4c4c4c400c4, + 0x0000484848480048, 0x0000f7f7f7f700f7, 0x0000dbdbdbdb00db, + 0x0000030303030003, 0x0000dadadada00da, 0x00003f3f3f3f003f, + 0x0000949494940094, 0x00005c5c5c5c005c, 0x0000020202020002, + 0x00004a4a4a4a004a, 0x0000333333330033, 0x0000676767670067, + 0x0000f3f3f3f300f3, 0x00007f7f7f7f007f, 0x0000e2e2e2e200e2, + 0x00009b9b9b9b009b, 0x0000262626260026, 0x0000373737370037, + 0x00003b3b3b3b003b, 0x0000969696960096, 0x00004b4b4b4b004b, + 0x0000bebebebe00be, 0x00002e2e2e2e002e, 0x0000797979790079, + 0x00008c8c8c8c008c, 0x00006e6e6e6e006e, 0x00008e8e8e8e008e, + 0x0000f5f5f5f500f5, 0x0000b6b6b6b600b6, 0x0000fdfdfdfd00fd, + 0x0000595959590059, 0x0000989898980098, 0x00006a6a6a6a006a, + 0x0000464646460046, 0x0000babababa00ba, 0x0000252525250025, + 0x0000424242420042, 0x0000a2a2a2a200a2, 0x0000fafafafa00fa, + 0x0000070707070007, 0x0000555555550055, 0x0000eeeeeeee00ee, + 0x00000a0a0a0a000a, 0x0000494949490049, 0x0000686868680068, + 0x0000383838380038, 0x0000a4a4a4a400a4, 0x0000282828280028, + 0x00007b7b7b7b007b, 0x0000c9c9c9c900c9, 0x0000c1c1c1c100c1, + 0x0000e3e3e3e300e3, 0x0000f4f4f4f400f4, 0x0000c7c7c7c700c7, + 0x00009e9e9e9e009e, +}; + +const u64 camellia_sp02220222[256] = { + 0x00e0e0e000e0e0e0, 0x0005050500050505, 0x0058585800585858, + 0x00d9d9d900d9d9d9, 0x0067676700676767, 0x004e4e4e004e4e4e, + 0x0081818100818181, 0x00cbcbcb00cbcbcb, 0x00c9c9c900c9c9c9, + 0x000b0b0b000b0b0b, 0x00aeaeae00aeaeae, 0x006a6a6a006a6a6a, + 0x00d5d5d500d5d5d5, 0x0018181800181818, 0x005d5d5d005d5d5d, + 0x0082828200828282, 0x0046464600464646, 0x00dfdfdf00dfdfdf, + 0x00d6d6d600d6d6d6, 0x0027272700272727, 0x008a8a8a008a8a8a, + 0x0032323200323232, 0x004b4b4b004b4b4b, 0x0042424200424242, + 0x00dbdbdb00dbdbdb, 0x001c1c1c001c1c1c, 0x009e9e9e009e9e9e, + 0x009c9c9c009c9c9c, 0x003a3a3a003a3a3a, 0x00cacaca00cacaca, + 0x0025252500252525, 0x007b7b7b007b7b7b, 0x000d0d0d000d0d0d, + 0x0071717100717171, 0x005f5f5f005f5f5f, 0x001f1f1f001f1f1f, + 0x00f8f8f800f8f8f8, 0x00d7d7d700d7d7d7, 0x003e3e3e003e3e3e, + 0x009d9d9d009d9d9d, 0x007c7c7c007c7c7c, 0x0060606000606060, + 0x00b9b9b900b9b9b9, 0x00bebebe00bebebe, 0x00bcbcbc00bcbcbc, + 0x008b8b8b008b8b8b, 0x0016161600161616, 0x0034343400343434, + 0x004d4d4d004d4d4d, 0x00c3c3c300c3c3c3, 0x0072727200727272, + 0x0095959500959595, 0x00ababab00ababab, 0x008e8e8e008e8e8e, + 0x00bababa00bababa, 0x007a7a7a007a7a7a, 0x00b3b3b300b3b3b3, + 0x0002020200020202, 0x00b4b4b400b4b4b4, 0x00adadad00adadad, + 0x00a2a2a200a2a2a2, 0x00acacac00acacac, 0x00d8d8d800d8d8d8, + 0x009a9a9a009a9a9a, 0x0017171700171717, 0x001a1a1a001a1a1a, + 0x0035353500353535, 0x00cccccc00cccccc, 0x00f7f7f700f7f7f7, + 0x0099999900999999, 0x0061616100616161, 0x005a5a5a005a5a5a, + 0x00e8e8e800e8e8e8, 0x0024242400242424, 0x0056565600565656, + 0x0040404000404040, 0x00e1e1e100e1e1e1, 0x0063636300636363, + 0x0009090900090909, 0x0033333300333333, 0x00bfbfbf00bfbfbf, + 0x0098989800989898, 0x0097979700979797, 0x0085858500858585, + 0x0068686800686868, 0x00fcfcfc00fcfcfc, 0x00ececec00ececec, + 0x000a0a0a000a0a0a, 0x00dadada00dadada, 0x006f6f6f006f6f6f, + 0x0053535300535353, 0x0062626200626262, 0x00a3a3a300a3a3a3, + 0x002e2e2e002e2e2e, 0x0008080800080808, 0x00afafaf00afafaf, + 0x0028282800282828, 0x00b0b0b000b0b0b0, 0x0074747400747474, + 0x00c2c2c200c2c2c2, 0x00bdbdbd00bdbdbd, 0x0036363600363636, + 0x0022222200222222, 0x0038383800383838, 0x0064646400646464, + 0x001e1e1e001e1e1e, 0x0039393900393939, 0x002c2c2c002c2c2c, + 0x00a6a6a600a6a6a6, 0x0030303000303030, 0x00e5e5e500e5e5e5, + 0x0044444400444444, 0x00fdfdfd00fdfdfd, 0x0088888800888888, + 0x009f9f9f009f9f9f, 0x0065656500656565, 0x0087878700878787, + 0x006b6b6b006b6b6b, 0x00f4f4f400f4f4f4, 0x0023232300232323, + 0x0048484800484848, 0x0010101000101010, 0x00d1d1d100d1d1d1, + 0x0051515100515151, 0x00c0c0c000c0c0c0, 0x00f9f9f900f9f9f9, + 0x00d2d2d200d2d2d2, 0x00a0a0a000a0a0a0, 0x0055555500555555, + 0x00a1a1a100a1a1a1, 0x0041414100414141, 0x00fafafa00fafafa, + 0x0043434300434343, 0x0013131300131313, 0x00c4c4c400c4c4c4, + 0x002f2f2f002f2f2f, 0x00a8a8a800a8a8a8, 0x00b6b6b600b6b6b6, + 0x003c3c3c003c3c3c, 0x002b2b2b002b2b2b, 0x00c1c1c100c1c1c1, + 0x00ffffff00ffffff, 0x00c8c8c800c8c8c8, 0x00a5a5a500a5a5a5, + 0x0020202000202020, 0x0089898900898989, 0x0000000000000000, + 0x0090909000909090, 0x0047474700474747, 0x00efefef00efefef, + 0x00eaeaea00eaeaea, 0x00b7b7b700b7b7b7, 0x0015151500151515, + 0x0006060600060606, 0x00cdcdcd00cdcdcd, 0x00b5b5b500b5b5b5, + 0x0012121200121212, 0x007e7e7e007e7e7e, 0x00bbbbbb00bbbbbb, + 0x0029292900292929, 0x000f0f0f000f0f0f, 0x00b8b8b800b8b8b8, + 0x0007070700070707, 0x0004040400040404, 0x009b9b9b009b9b9b, + 0x0094949400949494, 0x0021212100212121, 0x0066666600666666, + 0x00e6e6e600e6e6e6, 0x00cecece00cecece, 0x00ededed00ededed, + 0x00e7e7e700e7e7e7, 0x003b3b3b003b3b3b, 0x00fefefe00fefefe, + 0x007f7f7f007f7f7f, 0x00c5c5c500c5c5c5, 0x00a4a4a400a4a4a4, + 0x0037373700373737, 0x00b1b1b100b1b1b1, 0x004c4c4c004c4c4c, + 0x0091919100919191, 0x006e6e6e006e6e6e, 0x008d8d8d008d8d8d, + 0x0076767600767676, 0x0003030300030303, 0x002d2d2d002d2d2d, + 0x00dedede00dedede, 0x0096969600969696, 0x0026262600262626, + 0x007d7d7d007d7d7d, 0x00c6c6c600c6c6c6, 0x005c5c5c005c5c5c, + 0x00d3d3d300d3d3d3, 0x00f2f2f200f2f2f2, 0x004f4f4f004f4f4f, + 0x0019191900191919, 0x003f3f3f003f3f3f, 0x00dcdcdc00dcdcdc, + 0x0079797900797979, 0x001d1d1d001d1d1d, 0x0052525200525252, + 0x00ebebeb00ebebeb, 0x00f3f3f300f3f3f3, 0x006d6d6d006d6d6d, + 0x005e5e5e005e5e5e, 0x00fbfbfb00fbfbfb, 0x0069696900696969, + 0x00b2b2b200b2b2b2, 0x00f0f0f000f0f0f0, 0x0031313100313131, + 0x000c0c0c000c0c0c, 0x00d4d4d400d4d4d4, 0x00cfcfcf00cfcfcf, + 0x008c8c8c008c8c8c, 0x00e2e2e200e2e2e2, 0x0075757500757575, + 0x00a9a9a900a9a9a9, 0x004a4a4a004a4a4a, 0x0057575700575757, + 0x0084848400848484, 0x0011111100111111, 0x0045454500454545, + 0x001b1b1b001b1b1b, 0x00f5f5f500f5f5f5, 0x00e4e4e400e4e4e4, + 0x000e0e0e000e0e0e, 0x0073737300737373, 0x00aaaaaa00aaaaaa, + 0x00f1f1f100f1f1f1, 0x00dddddd00dddddd, 0x0059595900595959, + 0x0014141400141414, 0x006c6c6c006c6c6c, 0x0092929200929292, + 0x0054545400545454, 0x00d0d0d000d0d0d0, 0x0078787800787878, + 0x0070707000707070, 0x00e3e3e300e3e3e3, 0x0049494900494949, + 0x0080808000808080, 0x0050505000505050, 0x00a7a7a700a7a7a7, + 0x00f6f6f600f6f6f6, 0x0077777700777777, 0x0093939300939393, + 0x0086868600868686, 0x0083838300838383, 0x002a2a2a002a2a2a, + 0x00c7c7c700c7c7c7, 0x005b5b5b005b5b5b, 0x00e9e9e900e9e9e9, + 0x00eeeeee00eeeeee, 0x008f8f8f008f8f8f, 0x0001010100010101, + 0x003d3d3d003d3d3d, +}; + +const u64 camellia_sp30333033[256] = { + 0x3800383838003838, 0x4100414141004141, 0x1600161616001616, + 0x7600767676007676, 0xd900d9d9d900d9d9, 0x9300939393009393, + 0x6000606060006060, 0xf200f2f2f200f2f2, 0x7200727272007272, + 0xc200c2c2c200c2c2, 0xab00ababab00abab, 0x9a009a9a9a009a9a, + 0x7500757575007575, 0x0600060606000606, 0x5700575757005757, + 0xa000a0a0a000a0a0, 0x9100919191009191, 0xf700f7f7f700f7f7, + 0xb500b5b5b500b5b5, 0xc900c9c9c900c9c9, 0xa200a2a2a200a2a2, + 0x8c008c8c8c008c8c, 0xd200d2d2d200d2d2, 0x9000909090009090, + 0xf600f6f6f600f6f6, 0x0700070707000707, 0xa700a7a7a700a7a7, + 0x2700272727002727, 0x8e008e8e8e008e8e, 0xb200b2b2b200b2b2, + 0x4900494949004949, 0xde00dedede00dede, 0x4300434343004343, + 0x5c005c5c5c005c5c, 0xd700d7d7d700d7d7, 0xc700c7c7c700c7c7, + 0x3e003e3e3e003e3e, 0xf500f5f5f500f5f5, 0x8f008f8f8f008f8f, + 0x6700676767006767, 0x1f001f1f1f001f1f, 0x1800181818001818, + 0x6e006e6e6e006e6e, 0xaf00afafaf00afaf, 0x2f002f2f2f002f2f, + 0xe200e2e2e200e2e2, 0x8500858585008585, 0x0d000d0d0d000d0d, + 0x5300535353005353, 0xf000f0f0f000f0f0, 0x9c009c9c9c009c9c, + 0x6500656565006565, 0xea00eaeaea00eaea, 0xa300a3a3a300a3a3, + 0xae00aeaeae00aeae, 0x9e009e9e9e009e9e, 0xec00ececec00ecec, + 0x8000808080008080, 0x2d002d2d2d002d2d, 0x6b006b6b6b006b6b, + 0xa800a8a8a800a8a8, 0x2b002b2b2b002b2b, 0x3600363636003636, + 0xa600a6a6a600a6a6, 0xc500c5c5c500c5c5, 0x8600868686008686, + 0x4d004d4d4d004d4d, 0x3300333333003333, 0xfd00fdfdfd00fdfd, + 0x6600666666006666, 0x5800585858005858, 0x9600969696009696, + 0x3a003a3a3a003a3a, 0x0900090909000909, 0x9500959595009595, + 0x1000101010001010, 0x7800787878007878, 0xd800d8d8d800d8d8, + 0x4200424242004242, 0xcc00cccccc00cccc, 0xef00efefef00efef, + 0x2600262626002626, 0xe500e5e5e500e5e5, 0x6100616161006161, + 0x1a001a1a1a001a1a, 0x3f003f3f3f003f3f, 0x3b003b3b3b003b3b, + 0x8200828282008282, 0xb600b6b6b600b6b6, 0xdb00dbdbdb00dbdb, + 0xd400d4d4d400d4d4, 0x9800989898009898, 0xe800e8e8e800e8e8, + 0x8b008b8b8b008b8b, 0x0200020202000202, 0xeb00ebebeb00ebeb, + 0x0a000a0a0a000a0a, 0x2c002c2c2c002c2c, 0x1d001d1d1d001d1d, + 0xb000b0b0b000b0b0, 0x6f006f6f6f006f6f, 0x8d008d8d8d008d8d, + 0x8800888888008888, 0x0e000e0e0e000e0e, 0x1900191919001919, + 0x8700878787008787, 0x4e004e4e4e004e4e, 0x0b000b0b0b000b0b, + 0xa900a9a9a900a9a9, 0x0c000c0c0c000c0c, 0x7900797979007979, + 0x1100111111001111, 0x7f007f7f7f007f7f, 0x2200222222002222, + 0xe700e7e7e700e7e7, 0x5900595959005959, 0xe100e1e1e100e1e1, + 0xda00dadada00dada, 0x3d003d3d3d003d3d, 0xc800c8c8c800c8c8, + 0x1200121212001212, 0x0400040404000404, 0x7400747474007474, + 0x5400545454005454, 0x3000303030003030, 0x7e007e7e7e007e7e, + 0xb400b4b4b400b4b4, 0x2800282828002828, 0x5500555555005555, + 0x6800686868006868, 0x5000505050005050, 0xbe00bebebe00bebe, + 0xd000d0d0d000d0d0, 0xc400c4c4c400c4c4, 0x3100313131003131, + 0xcb00cbcbcb00cbcb, 0x2a002a2a2a002a2a, 0xad00adadad00adad, + 0x0f000f0f0f000f0f, 0xca00cacaca00caca, 0x7000707070007070, + 0xff00ffffff00ffff, 0x3200323232003232, 0x6900696969006969, + 0x0800080808000808, 0x6200626262006262, 0x0000000000000000, + 0x2400242424002424, 0xd100d1d1d100d1d1, 0xfb00fbfbfb00fbfb, + 0xba00bababa00baba, 0xed00ededed00eded, 0x4500454545004545, + 0x8100818181008181, 0x7300737373007373, 0x6d006d6d6d006d6d, + 0x8400848484008484, 0x9f009f9f9f009f9f, 0xee00eeeeee00eeee, + 0x4a004a4a4a004a4a, 0xc300c3c3c300c3c3, 0x2e002e2e2e002e2e, + 0xc100c1c1c100c1c1, 0x0100010101000101, 0xe600e6e6e600e6e6, + 0x2500252525002525, 0x4800484848004848, 0x9900999999009999, + 0xb900b9b9b900b9b9, 0xb300b3b3b300b3b3, 0x7b007b7b7b007b7b, + 0xf900f9f9f900f9f9, 0xce00cecece00cece, 0xbf00bfbfbf00bfbf, + 0xdf00dfdfdf00dfdf, 0x7100717171007171, 0x2900292929002929, + 0xcd00cdcdcd00cdcd, 0x6c006c6c6c006c6c, 0x1300131313001313, + 0x6400646464006464, 0x9b009b9b9b009b9b, 0x6300636363006363, + 0x9d009d9d9d009d9d, 0xc000c0c0c000c0c0, 0x4b004b4b4b004b4b, + 0xb700b7b7b700b7b7, 0xa500a5a5a500a5a5, 0x8900898989008989, + 0x5f005f5f5f005f5f, 0xb100b1b1b100b1b1, 0x1700171717001717, + 0xf400f4f4f400f4f4, 0xbc00bcbcbc00bcbc, 0xd300d3d3d300d3d3, + 0x4600464646004646, 0xcf00cfcfcf00cfcf, 0x3700373737003737, + 0x5e005e5e5e005e5e, 0x4700474747004747, 0x9400949494009494, + 0xfa00fafafa00fafa, 0xfc00fcfcfc00fcfc, 0x5b005b5b5b005b5b, + 0x9700979797009797, 0xfe00fefefe00fefe, 0x5a005a5a5a005a5a, + 0xac00acacac00acac, 0x3c003c3c3c003c3c, 0x4c004c4c4c004c4c, + 0x0300030303000303, 0x3500353535003535, 0xf300f3f3f300f3f3, + 0x2300232323002323, 0xb800b8b8b800b8b8, 0x5d005d5d5d005d5d, + 0x6a006a6a6a006a6a, 0x9200929292009292, 0xd500d5d5d500d5d5, + 0x2100212121002121, 0x4400444444004444, 0x5100515151005151, + 0xc600c6c6c600c6c6, 0x7d007d7d7d007d7d, 0x3900393939003939, + 0x8300838383008383, 0xdc00dcdcdc00dcdc, 0xaa00aaaaaa00aaaa, + 0x7c007c7c7c007c7c, 0x7700777777007777, 0x5600565656005656, + 0x0500050505000505, 0x1b001b1b1b001b1b, 0xa400a4a4a400a4a4, + 0x1500151515001515, 0x3400343434003434, 0x1e001e1e1e001e1e, + 0x1c001c1c1c001c1c, 0xf800f8f8f800f8f8, 0x5200525252005252, + 0x2000202020002020, 0x1400141414001414, 0xe900e9e9e900e9e9, + 0xbd00bdbdbd00bdbd, 0xdd00dddddd00dddd, 0xe400e4e4e400e4e4, + 0xa100a1a1a100a1a1, 0xe000e0e0e000e0e0, 0x8a008a8a8a008a8a, + 0xf100f1f1f100f1f1, 0xd600d6d6d600d6d6, 0x7a007a7a7a007a7a, + 0xbb00bbbbbb00bbbb, 0xe300e3e3e300e3e3, 0x4000404040004040, + 0x4f004f4f4f004f4f, +}; + +const u64 camellia_sp44044404[256] = { + 0x7070007070700070, 0x2c2c002c2c2c002c, 0xb3b300b3b3b300b3, + 0xc0c000c0c0c000c0, 0xe4e400e4e4e400e4, 0x5757005757570057, + 0xeaea00eaeaea00ea, 0xaeae00aeaeae00ae, 0x2323002323230023, + 0x6b6b006b6b6b006b, 0x4545004545450045, 0xa5a500a5a5a500a5, + 0xeded00ededed00ed, 0x4f4f004f4f4f004f, 0x1d1d001d1d1d001d, + 0x9292009292920092, 0x8686008686860086, 0xafaf00afafaf00af, + 0x7c7c007c7c7c007c, 0x1f1f001f1f1f001f, 0x3e3e003e3e3e003e, + 0xdcdc00dcdcdc00dc, 0x5e5e005e5e5e005e, 0x0b0b000b0b0b000b, + 0xa6a600a6a6a600a6, 0x3939003939390039, 0xd5d500d5d5d500d5, + 0x5d5d005d5d5d005d, 0xd9d900d9d9d900d9, 0x5a5a005a5a5a005a, + 0x5151005151510051, 0x6c6c006c6c6c006c, 0x8b8b008b8b8b008b, + 0x9a9a009a9a9a009a, 0xfbfb00fbfbfb00fb, 0xb0b000b0b0b000b0, + 0x7474007474740074, 0x2b2b002b2b2b002b, 0xf0f000f0f0f000f0, + 0x8484008484840084, 0xdfdf00dfdfdf00df, 0xcbcb00cbcbcb00cb, + 0x3434003434340034, 0x7676007676760076, 0x6d6d006d6d6d006d, + 0xa9a900a9a9a900a9, 0xd1d100d1d1d100d1, 0x0404000404040004, + 0x1414001414140014, 0x3a3a003a3a3a003a, 0xdede00dedede00de, + 0x1111001111110011, 0x3232003232320032, 0x9c9c009c9c9c009c, + 0x5353005353530053, 0xf2f200f2f2f200f2, 0xfefe00fefefe00fe, + 0xcfcf00cfcfcf00cf, 0xc3c300c3c3c300c3, 0x7a7a007a7a7a007a, + 0x2424002424240024, 0xe8e800e8e8e800e8, 0x6060006060600060, + 0x6969006969690069, 0xaaaa00aaaaaa00aa, 0xa0a000a0a0a000a0, + 0xa1a100a1a1a100a1, 0x6262006262620062, 0x5454005454540054, + 0x1e1e001e1e1e001e, 0xe0e000e0e0e000e0, 0x6464006464640064, + 0x1010001010100010, 0x0000000000000000, 0xa3a300a3a3a300a3, + 0x7575007575750075, 0x8a8a008a8a8a008a, 0xe6e600e6e6e600e6, + 0x0909000909090009, 0xdddd00dddddd00dd, 0x8787008787870087, + 0x8383008383830083, 0xcdcd00cdcdcd00cd, 0x9090009090900090, + 0x7373007373730073, 0xf6f600f6f6f600f6, 0x9d9d009d9d9d009d, + 0xbfbf00bfbfbf00bf, 0x5252005252520052, 0xd8d800d8d8d800d8, + 0xc8c800c8c8c800c8, 0xc6c600c6c6c600c6, 0x8181008181810081, + 0x6f6f006f6f6f006f, 0x1313001313130013, 0x6363006363630063, + 0xe9e900e9e9e900e9, 0xa7a700a7a7a700a7, 0x9f9f009f9f9f009f, + 0xbcbc00bcbcbc00bc, 0x2929002929290029, 0xf9f900f9f9f900f9, + 0x2f2f002f2f2f002f, 0xb4b400b4b4b400b4, 0x7878007878780078, + 0x0606000606060006, 0xe7e700e7e7e700e7, 0x7171007171710071, + 0xd4d400d4d4d400d4, 0xabab00ababab00ab, 0x8888008888880088, + 0x8d8d008d8d8d008d, 0x7272007272720072, 0xb9b900b9b9b900b9, + 0xf8f800f8f8f800f8, 0xacac00acacac00ac, 0x3636003636360036, + 0x2a2a002a2a2a002a, 0x3c3c003c3c3c003c, 0xf1f100f1f1f100f1, + 0x4040004040400040, 0xd3d300d3d3d300d3, 0xbbbb00bbbbbb00bb, + 0x4343004343430043, 0x1515001515150015, 0xadad00adadad00ad, + 0x7777007777770077, 0x8080008080800080, 0x8282008282820082, + 0xecec00ececec00ec, 0x2727002727270027, 0xe5e500e5e5e500e5, + 0x8585008585850085, 0x3535003535350035, 0x0c0c000c0c0c000c, + 0x4141004141410041, 0xefef00efefef00ef, 0x9393009393930093, + 0x1919001919190019, 0x2121002121210021, 0x0e0e000e0e0e000e, + 0x4e4e004e4e4e004e, 0x6565006565650065, 0xbdbd00bdbdbd00bd, + 0xb8b800b8b8b800b8, 0x8f8f008f8f8f008f, 0xebeb00ebebeb00eb, + 0xcece00cecece00ce, 0x3030003030300030, 0x5f5f005f5f5f005f, + 0xc5c500c5c5c500c5, 0x1a1a001a1a1a001a, 0xe1e100e1e1e100e1, + 0xcaca00cacaca00ca, 0x4747004747470047, 0x3d3d003d3d3d003d, + 0x0101000101010001, 0xd6d600d6d6d600d6, 0x5656005656560056, + 0x4d4d004d4d4d004d, 0x0d0d000d0d0d000d, 0x6666006666660066, + 0xcccc00cccccc00cc, 0x2d2d002d2d2d002d, 0x1212001212120012, + 0x2020002020200020, 0xb1b100b1b1b100b1, 0x9999009999990099, + 0x4c4c004c4c4c004c, 0xc2c200c2c2c200c2, 0x7e7e007e7e7e007e, + 0x0505000505050005, 0xb7b700b7b7b700b7, 0x3131003131310031, + 0x1717001717170017, 0xd7d700d7d7d700d7, 0x5858005858580058, + 0x6161006161610061, 0x1b1b001b1b1b001b, 0x1c1c001c1c1c001c, + 0x0f0f000f0f0f000f, 0x1616001616160016, 0x1818001818180018, + 0x2222002222220022, 0x4444004444440044, 0xb2b200b2b2b200b2, + 0xb5b500b5b5b500b5, 0x9191009191910091, 0x0808000808080008, + 0xa8a800a8a8a800a8, 0xfcfc00fcfcfc00fc, 0x5050005050500050, + 0xd0d000d0d0d000d0, 0x7d7d007d7d7d007d, 0x8989008989890089, + 0x9797009797970097, 0x5b5b005b5b5b005b, 0x9595009595950095, + 0xffff00ffffff00ff, 0xd2d200d2d2d200d2, 0xc4c400c4c4c400c4, + 0x4848004848480048, 0xf7f700f7f7f700f7, 0xdbdb00dbdbdb00db, + 0x0303000303030003, 0xdada00dadada00da, 0x3f3f003f3f3f003f, + 0x9494009494940094, 0x5c5c005c5c5c005c, 0x0202000202020002, + 0x4a4a004a4a4a004a, 0x3333003333330033, 0x6767006767670067, + 0xf3f300f3f3f300f3, 0x7f7f007f7f7f007f, 0xe2e200e2e2e200e2, + 0x9b9b009b9b9b009b, 0x2626002626260026, 0x3737003737370037, + 0x3b3b003b3b3b003b, 0x9696009696960096, 0x4b4b004b4b4b004b, + 0xbebe00bebebe00be, 0x2e2e002e2e2e002e, 0x7979007979790079, + 0x8c8c008c8c8c008c, 0x6e6e006e6e6e006e, 0x8e8e008e8e8e008e, + 0xf5f500f5f5f500f5, 0xb6b600b6b6b600b6, 0xfdfd00fdfdfd00fd, + 0x5959005959590059, 0x9898009898980098, 0x6a6a006a6a6a006a, + 0x4646004646460046, 0xbaba00bababa00ba, 0x2525002525250025, + 0x4242004242420042, 0xa2a200a2a2a200a2, 0xfafa00fafafa00fa, + 0x0707000707070007, 0x5555005555550055, 0xeeee00eeeeee00ee, + 0x0a0a000a0a0a000a, 0x4949004949490049, 0x6868006868680068, + 0x3838003838380038, 0xa4a400a4a4a400a4, 0x2828002828280028, + 0x7b7b007b7b7b007b, 0xc9c900c9c9c900c9, 0xc1c100c1c1c100c1, + 0xe3e300e3e3e300e3, 0xf4f400f4f4f400f4, 0xc7c700c7c7c700c7, + 0x9e9e009e9e9e009e, +}; + +const u64 camellia_sp11101110[256] = { + 0x7070700070707000, 0x8282820082828200, 0x2c2c2c002c2c2c00, + 0xececec00ececec00, 0xb3b3b300b3b3b300, 0x2727270027272700, + 0xc0c0c000c0c0c000, 0xe5e5e500e5e5e500, 0xe4e4e400e4e4e400, + 0x8585850085858500, 0x5757570057575700, 0x3535350035353500, + 0xeaeaea00eaeaea00, 0x0c0c0c000c0c0c00, 0xaeaeae00aeaeae00, + 0x4141410041414100, 0x2323230023232300, 0xefefef00efefef00, + 0x6b6b6b006b6b6b00, 0x9393930093939300, 0x4545450045454500, + 0x1919190019191900, 0xa5a5a500a5a5a500, 0x2121210021212100, + 0xededed00ededed00, 0x0e0e0e000e0e0e00, 0x4f4f4f004f4f4f00, + 0x4e4e4e004e4e4e00, 0x1d1d1d001d1d1d00, 0x6565650065656500, + 0x9292920092929200, 0xbdbdbd00bdbdbd00, 0x8686860086868600, + 0xb8b8b800b8b8b800, 0xafafaf00afafaf00, 0x8f8f8f008f8f8f00, + 0x7c7c7c007c7c7c00, 0xebebeb00ebebeb00, 0x1f1f1f001f1f1f00, + 0xcecece00cecece00, 0x3e3e3e003e3e3e00, 0x3030300030303000, + 0xdcdcdc00dcdcdc00, 0x5f5f5f005f5f5f00, 0x5e5e5e005e5e5e00, + 0xc5c5c500c5c5c500, 0x0b0b0b000b0b0b00, 0x1a1a1a001a1a1a00, + 0xa6a6a600a6a6a600, 0xe1e1e100e1e1e100, 0x3939390039393900, + 0xcacaca00cacaca00, 0xd5d5d500d5d5d500, 0x4747470047474700, + 0x5d5d5d005d5d5d00, 0x3d3d3d003d3d3d00, 0xd9d9d900d9d9d900, + 0x0101010001010100, 0x5a5a5a005a5a5a00, 0xd6d6d600d6d6d600, + 0x5151510051515100, 0x5656560056565600, 0x6c6c6c006c6c6c00, + 0x4d4d4d004d4d4d00, 0x8b8b8b008b8b8b00, 0x0d0d0d000d0d0d00, + 0x9a9a9a009a9a9a00, 0x6666660066666600, 0xfbfbfb00fbfbfb00, + 0xcccccc00cccccc00, 0xb0b0b000b0b0b000, 0x2d2d2d002d2d2d00, + 0x7474740074747400, 0x1212120012121200, 0x2b2b2b002b2b2b00, + 0x2020200020202000, 0xf0f0f000f0f0f000, 0xb1b1b100b1b1b100, + 0x8484840084848400, 0x9999990099999900, 0xdfdfdf00dfdfdf00, + 0x4c4c4c004c4c4c00, 0xcbcbcb00cbcbcb00, 0xc2c2c200c2c2c200, + 0x3434340034343400, 0x7e7e7e007e7e7e00, 0x7676760076767600, + 0x0505050005050500, 0x6d6d6d006d6d6d00, 0xb7b7b700b7b7b700, + 0xa9a9a900a9a9a900, 0x3131310031313100, 0xd1d1d100d1d1d100, + 0x1717170017171700, 0x0404040004040400, 0xd7d7d700d7d7d700, + 0x1414140014141400, 0x5858580058585800, 0x3a3a3a003a3a3a00, + 0x6161610061616100, 0xdedede00dedede00, 0x1b1b1b001b1b1b00, + 0x1111110011111100, 0x1c1c1c001c1c1c00, 0x3232320032323200, + 0x0f0f0f000f0f0f00, 0x9c9c9c009c9c9c00, 0x1616160016161600, + 0x5353530053535300, 0x1818180018181800, 0xf2f2f200f2f2f200, + 0x2222220022222200, 0xfefefe00fefefe00, 0x4444440044444400, + 0xcfcfcf00cfcfcf00, 0xb2b2b200b2b2b200, 0xc3c3c300c3c3c300, + 0xb5b5b500b5b5b500, 0x7a7a7a007a7a7a00, 0x9191910091919100, + 0x2424240024242400, 0x0808080008080800, 0xe8e8e800e8e8e800, + 0xa8a8a800a8a8a800, 0x6060600060606000, 0xfcfcfc00fcfcfc00, + 0x6969690069696900, 0x5050500050505000, 0xaaaaaa00aaaaaa00, + 0xd0d0d000d0d0d000, 0xa0a0a000a0a0a000, 0x7d7d7d007d7d7d00, + 0xa1a1a100a1a1a100, 0x8989890089898900, 0x6262620062626200, + 0x9797970097979700, 0x5454540054545400, 0x5b5b5b005b5b5b00, + 0x1e1e1e001e1e1e00, 0x9595950095959500, 0xe0e0e000e0e0e000, + 0xffffff00ffffff00, 0x6464640064646400, 0xd2d2d200d2d2d200, + 0x1010100010101000, 0xc4c4c400c4c4c400, 0x0000000000000000, + 0x4848480048484800, 0xa3a3a300a3a3a300, 0xf7f7f700f7f7f700, + 0x7575750075757500, 0xdbdbdb00dbdbdb00, 0x8a8a8a008a8a8a00, + 0x0303030003030300, 0xe6e6e600e6e6e600, 0xdadada00dadada00, + 0x0909090009090900, 0x3f3f3f003f3f3f00, 0xdddddd00dddddd00, + 0x9494940094949400, 0x8787870087878700, 0x5c5c5c005c5c5c00, + 0x8383830083838300, 0x0202020002020200, 0xcdcdcd00cdcdcd00, + 0x4a4a4a004a4a4a00, 0x9090900090909000, 0x3333330033333300, + 0x7373730073737300, 0x6767670067676700, 0xf6f6f600f6f6f600, + 0xf3f3f300f3f3f300, 0x9d9d9d009d9d9d00, 0x7f7f7f007f7f7f00, + 0xbfbfbf00bfbfbf00, 0xe2e2e200e2e2e200, 0x5252520052525200, + 0x9b9b9b009b9b9b00, 0xd8d8d800d8d8d800, 0x2626260026262600, + 0xc8c8c800c8c8c800, 0x3737370037373700, 0xc6c6c600c6c6c600, + 0x3b3b3b003b3b3b00, 0x8181810081818100, 0x9696960096969600, + 0x6f6f6f006f6f6f00, 0x4b4b4b004b4b4b00, 0x1313130013131300, + 0xbebebe00bebebe00, 0x6363630063636300, 0x2e2e2e002e2e2e00, + 0xe9e9e900e9e9e900, 0x7979790079797900, 0xa7a7a700a7a7a700, + 0x8c8c8c008c8c8c00, 0x9f9f9f009f9f9f00, 0x6e6e6e006e6e6e00, + 0xbcbcbc00bcbcbc00, 0x8e8e8e008e8e8e00, 0x2929290029292900, + 0xf5f5f500f5f5f500, 0xf9f9f900f9f9f900, 0xb6b6b600b6b6b600, + 0x2f2f2f002f2f2f00, 0xfdfdfd00fdfdfd00, 0xb4b4b400b4b4b400, + 0x5959590059595900, 0x7878780078787800, 0x9898980098989800, + 0x0606060006060600, 0x6a6a6a006a6a6a00, 0xe7e7e700e7e7e700, + 0x4646460046464600, 0x7171710071717100, 0xbababa00bababa00, + 0xd4d4d400d4d4d400, 0x2525250025252500, 0xababab00ababab00, + 0x4242420042424200, 0x8888880088888800, 0xa2a2a200a2a2a200, + 0x8d8d8d008d8d8d00, 0xfafafa00fafafa00, 0x7272720072727200, + 0x0707070007070700, 0xb9b9b900b9b9b900, 0x5555550055555500, + 0xf8f8f800f8f8f800, 0xeeeeee00eeeeee00, 0xacacac00acacac00, + 0x0a0a0a000a0a0a00, 0x3636360036363600, 0x4949490049494900, + 0x2a2a2a002a2a2a00, 0x6868680068686800, 0x3c3c3c003c3c3c00, + 0x3838380038383800, 0xf1f1f100f1f1f100, 0xa4a4a400a4a4a400, + 0x4040400040404000, 0x2828280028282800, 0xd3d3d300d3d3d300, + 0x7b7b7b007b7b7b00, 0xbbbbbb00bbbbbb00, 0xc9c9c900c9c9c900, + 0x4343430043434300, 0xc1c1c100c1c1c100, 0x1515150015151500, + 0xe3e3e300e3e3e300, 0xadadad00adadad00, 0xf4f4f400f4f4f400, + 0x7777770077777700, 0xc7c7c700c7c7c700, 0x8080800080808000, + 0x9e9e9e009e9e9e00, +}; + +/* key constants */ +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +/* macros */ +#define ROLDQ(l, r, bits) ({ \ + u64 t = l; \ + l = (l << bits) | (r >> (64 - bits)); \ + r = (r << bits) | (t >> (64 - bits)); \ +}) + +#define CAMELLIA_F(x, kl, kr, y) ({ \ + u64 ii = x ^ (((u64)kl << 32) | kr); \ + y = camellia_sp11101110[(uint8_t)ii]; \ + y ^= camellia_sp44044404[(uint8_t)(ii >> 8)]; \ + ii >>= 16; \ + y ^= camellia_sp30333033[(uint8_t)ii]; \ + y ^= camellia_sp02220222[(uint8_t)(ii >> 8)]; \ + ii >>= 16; \ + y ^= camellia_sp00444404[(uint8_t)ii]; \ + y ^= camellia_sp03303033[(uint8_t)(ii >> 8)]; \ + ii >>= 16; \ + y ^= camellia_sp22000222[(uint8_t)ii]; \ + y ^= camellia_sp10011110[(uint8_t)(ii >> 8)]; \ + y = ror64(y, 32); \ +}) + +#define SET_SUBKEY_LR(INDEX, sRL) (subkey[(INDEX)] = ror64((sRL), 32)) + +static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max) +{ + u64 kw4, tt; + u32 dw, tl, tr; + + /* absorb kw2 to other subkeys */ + /* round 2 */ + subRL[3] ^= subRL[1]; + /* round 4 */ + subRL[5] ^= subRL[1]; + /* round 6 */ + subRL[7] ^= subRL[1]; + + subRL[1] ^= (subRL[1] & ~subRL[9]) << 32; + /* modified for FLinv(kl2) */ + dw = (subRL[1] & subRL[9]) >> 32, + subRL[1] ^= rol32(dw, 1); + + /* round 8 */ + subRL[11] ^= subRL[1]; + /* round 10 */ + subRL[13] ^= subRL[1]; + /* round 12 */ + subRL[15] ^= subRL[1]; + + subRL[1] ^= (subRL[1] & ~subRL[17]) << 32; + /* modified for FLinv(kl4) */ + dw = (subRL[1] & subRL[17]) >> 32, + subRL[1] ^= rol32(dw, 1); + + /* round 14 */ + subRL[19] ^= subRL[1]; + /* round 16 */ + subRL[21] ^= subRL[1]; + /* round 18 */ + subRL[23] ^= subRL[1]; + + if (max == 24) { + /* kw3 */ + subRL[24] ^= subRL[1]; + + /* absorb kw4 to other subkeys */ + kw4 = subRL[25]; + } else { + subRL[1] ^= (subRL[1] & ~subRL[25]) << 32; + /* modified for FLinv(kl6) */ + dw = (subRL[1] & subRL[25]) >> 32, + subRL[1] ^= rol32(dw, 1); + + /* round 20 */ + subRL[27] ^= subRL[1]; + /* round 22 */ + subRL[29] ^= subRL[1]; + /* round 24 */ + subRL[31] ^= subRL[1]; + /* kw3 */ + subRL[32] ^= subRL[1]; + + /* absorb kw4 to other subkeys */ + kw4 = subRL[33]; + /* round 23 */ + subRL[30] ^= kw4; + /* round 21 */ + subRL[28] ^= kw4; + /* round 19 */ + subRL[26] ^= kw4; + + kw4 ^= (kw4 & ~subRL[24]) << 32; + /* modified for FL(kl5) */ + dw = (kw4 & subRL[24]) >> 32, + kw4 ^= rol32(dw, 1); + } + + /* round 17 */ + subRL[22] ^= kw4; + /* round 15 */ + subRL[20] ^= kw4; + /* round 13 */ + subRL[18] ^= kw4; + + kw4 ^= (kw4 & ~subRL[16]) << 32; + /* modified for FL(kl3) */ + dw = (kw4 & subRL[16]) >> 32, + kw4 ^= rol32(dw, 1); + + /* round 11 */ + subRL[14] ^= kw4; + /* round 9 */ + subRL[12] ^= kw4; + /* round 7 */ + subRL[10] ^= kw4; + + kw4 ^= (kw4 & ~subRL[8]) << 32; + /* modified for FL(kl1) */ + dw = (kw4 & subRL[8]) >> 32, + kw4 ^= rol32(dw, 1); + + /* round 5 */ + subRL[6] ^= kw4; + /* round 3 */ + subRL[4] ^= kw4; + /* round 1 */ + subRL[2] ^= kw4; + /* kw1 */ + subRL[0] ^= kw4; + + /* key XOR is end of F-function */ + SET_SUBKEY_LR(0, subRL[0] ^ subRL[2]); /* kw1 */ + SET_SUBKEY_LR(2, subRL[3]); /* round 1 */ + SET_SUBKEY_LR(3, subRL[2] ^ subRL[4]); /* round 2 */ + SET_SUBKEY_LR(4, subRL[3] ^ subRL[5]); /* round 3 */ + SET_SUBKEY_LR(5, subRL[4] ^ subRL[6]); /* round 4 */ + SET_SUBKEY_LR(6, subRL[5] ^ subRL[7]); /* round 5 */ + + tl = (subRL[10] >> 32) ^ (subRL[10] & ~subRL[8]); + dw = tl & (subRL[8] >> 32), /* FL(kl1) */ + tr = subRL[10] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(7, subRL[6] ^ tt); /* round 6 */ + SET_SUBKEY_LR(8, subRL[8]); /* FL(kl1) */ + SET_SUBKEY_LR(9, subRL[9]); /* FLinv(kl2) */ + + tl = (subRL[7] >> 32) ^ (subRL[7] & ~subRL[9]); + dw = tl & (subRL[9] >> 32), /* FLinv(kl2) */ + tr = subRL[7] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(10, subRL[11] ^ tt); /* round 7 */ + SET_SUBKEY_LR(11, subRL[10] ^ subRL[12]); /* round 8 */ + SET_SUBKEY_LR(12, subRL[11] ^ subRL[13]); /* round 9 */ + SET_SUBKEY_LR(13, subRL[12] ^ subRL[14]); /* round 10 */ + SET_SUBKEY_LR(14, subRL[13] ^ subRL[15]); /* round 11 */ + + tl = (subRL[18] >> 32) ^ (subRL[18] & ~subRL[16]); + dw = tl & (subRL[16] >> 32), /* FL(kl3) */ + tr = subRL[18] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(15, subRL[14] ^ tt); /* round 12 */ + SET_SUBKEY_LR(16, subRL[16]); /* FL(kl3) */ + SET_SUBKEY_LR(17, subRL[17]); /* FLinv(kl4) */ + + tl = (subRL[15] >> 32) ^ (subRL[15] & ~subRL[17]); + dw = tl & (subRL[17] >> 32), /* FLinv(kl4) */ + tr = subRL[15] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(18, subRL[19] ^ tt); /* round 13 */ + SET_SUBKEY_LR(19, subRL[18] ^ subRL[20]); /* round 14 */ + SET_SUBKEY_LR(20, subRL[19] ^ subRL[21]); /* round 15 */ + SET_SUBKEY_LR(21, subRL[20] ^ subRL[22]); /* round 16 */ + SET_SUBKEY_LR(22, subRL[21] ^ subRL[23]); /* round 17 */ + + if (max == 24) { + SET_SUBKEY_LR(23, subRL[22]); /* round 18 */ + SET_SUBKEY_LR(24, subRL[24] ^ subRL[23]); /* kw3 */ + } else { + tl = (subRL[26] >> 32) ^ (subRL[26] & ~subRL[24]); + dw = tl & (subRL[24] >> 32), /* FL(kl5) */ + tr = subRL[26] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(23, subRL[22] ^ tt); /* round 18 */ + SET_SUBKEY_LR(24, subRL[24]); /* FL(kl5) */ + SET_SUBKEY_LR(25, subRL[25]); /* FLinv(kl6) */ + + tl = (subRL[23] >> 32) ^ (subRL[23] & ~subRL[25]); + dw = tl & (subRL[25] >> 32), /* FLinv(kl6) */ + tr = subRL[23] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(26, subRL[27] ^ tt); /* round 19 */ + SET_SUBKEY_LR(27, subRL[26] ^ subRL[28]); /* round 20 */ + SET_SUBKEY_LR(28, subRL[27] ^ subRL[29]); /* round 21 */ + SET_SUBKEY_LR(29, subRL[28] ^ subRL[30]); /* round 22 */ + SET_SUBKEY_LR(30, subRL[29] ^ subRL[31]); /* round 23 */ + SET_SUBKEY_LR(31, subRL[30]); /* round 24 */ + SET_SUBKEY_LR(32, subRL[32] ^ subRL[31]); /* kw3 */ + } +} + +static void camellia_setup128(const unsigned char *key, u64 *subkey) +{ + u64 kl, kr, ww; + u64 subRL[26]; + + /** + * k == kl || kr (|| is concatenation) + */ + kl = get_unaligned_be64(key); + kr = get_unaligned_be64(key + 8); + + /* generate KL dependent subkeys */ + /* kw1 */ + subRL[0] = kl; + /* kw2 */ + subRL[1] = kr; + + /* rotation left shift 15bit */ + ROLDQ(kl, kr, 15); + + /* k3 */ + subRL[4] = kl; + /* k4 */ + subRL[5] = kr; + + /* rotation left shift 15+30bit */ + ROLDQ(kl, kr, 30); + + /* k7 */ + subRL[10] = kl; + /* k8 */ + subRL[11] = kr; + + /* rotation left shift 15+30+15bit */ + ROLDQ(kl, kr, 15); + + /* k10 */ + subRL[13] = kr; + /* rotation left shift 15+30+15+17 bit */ + ROLDQ(kl, kr, 17); + + /* kl3 */ + subRL[16] = kl; + /* kl4 */ + subRL[17] = kr; + + /* rotation left shift 15+30+15+17+17 bit */ + ROLDQ(kl, kr, 17); + + /* k13 */ + subRL[18] = kl; + /* k14 */ + subRL[19] = kr; + + /* rotation left shift 15+30+15+17+17+17 bit */ + ROLDQ(kl, kr, 17); + + /* k17 */ + subRL[22] = kl; + /* k18 */ + subRL[23] = kr; + + /* generate KA */ + kl = subRL[0]; + kr = subRL[1]; + CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww); + kr ^= ww; + CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl); + + /* current status == (kll, klr, w0, w1) */ + CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr); + kr ^= ww; + CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww); + kl ^= ww; + + /* generate KA dependent subkeys */ + /* k1, k2 */ + subRL[2] = kl; + subRL[3] = kr; + ROLDQ(kl, kr, 15); + /* k5,k6 */ + subRL[6] = kl; + subRL[7] = kr; + ROLDQ(kl, kr, 15); + /* kl1, kl2 */ + subRL[8] = kl; + subRL[9] = kr; + ROLDQ(kl, kr, 15); + /* k9 */ + subRL[12] = kl; + ROLDQ(kl, kr, 15); + /* k11, k12 */ + subRL[14] = kl; + subRL[15] = kr; + ROLDQ(kl, kr, 34); + /* k15, k16 */ + subRL[20] = kl; + subRL[21] = kr; + ROLDQ(kl, kr, 17); + /* kw3, kw4 */ + subRL[24] = kl; + subRL[25] = kr; + + camellia_setup_tail(subkey, subRL, 24); +} + +static void camellia_setup256(const unsigned char *key, u64 *subkey) +{ + u64 kl, kr; /* left half of key */ + u64 krl, krr; /* right half of key */ + u64 ww; /* temporary variables */ + u64 subRL[34]; + + /** + * key = (kl || kr || krl || krr) (|| is concatenation) + */ + kl = get_unaligned_be64(key); + kr = get_unaligned_be64(key + 8); + krl = get_unaligned_be64(key + 16); + krr = get_unaligned_be64(key + 24); + + /* generate KL dependent subkeys */ + /* kw1 */ + subRL[0] = kl; + /* kw2 */ + subRL[1] = kr; + ROLDQ(kl, kr, 45); + /* k9 */ + subRL[12] = kl; + /* k10 */ + subRL[13] = kr; + ROLDQ(kl, kr, 15); + /* kl3 */ + subRL[16] = kl; + /* kl4 */ + subRL[17] = kr; + ROLDQ(kl, kr, 17); + /* k17 */ + subRL[22] = kl; + /* k18 */ + subRL[23] = kr; + ROLDQ(kl, kr, 34); + /* k23 */ + subRL[30] = kl; + /* k24 */ + subRL[31] = kr; + + /* generate KR dependent subkeys */ + ROLDQ(krl, krr, 15); + /* k3 */ + subRL[4] = krl; + /* k4 */ + subRL[5] = krr; + ROLDQ(krl, krr, 15); + /* kl1 */ + subRL[8] = krl; + /* kl2 */ + subRL[9] = krr; + ROLDQ(krl, krr, 30); + /* k13 */ + subRL[18] = krl; + /* k14 */ + subRL[19] = krr; + ROLDQ(krl, krr, 34); + /* k19 */ + subRL[26] = krl; + /* k20 */ + subRL[27] = krr; + ROLDQ(krl, krr, 34); + + /* generate KA */ + kl = subRL[0] ^ krl; + kr = subRL[1] ^ krr; + + CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww); + kr ^= ww; + CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl); + kl ^= krl; + CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr); + kr ^= ww ^ krr; + CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww); + kl ^= ww; + + /* generate KB */ + krl ^= kl; + krr ^= kr; + CAMELLIA_F(krl, CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, ww); + krr ^= ww; + CAMELLIA_F(krr, CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, ww); + krl ^= ww; + + /* generate KA dependent subkeys */ + ROLDQ(kl, kr, 15); + /* k5 */ + subRL[6] = kl; + /* k6 */ + subRL[7] = kr; + ROLDQ(kl, kr, 30); + /* k11 */ + subRL[14] = kl; + /* k12 */ + subRL[15] = kr; + /* rotation left shift 32bit */ + ROLDQ(kl, kr, 32); + /* kl5 */ + subRL[24] = kl; + /* kl6 */ + subRL[25] = kr; + /* rotation left shift 17 from k11,k12 -> k21,k22 */ + ROLDQ(kl, kr, 17); + /* k21 */ + subRL[28] = kl; + /* k22 */ + subRL[29] = kr; + + /* generate KB dependent subkeys */ + /* k1 */ + subRL[2] = krl; + /* k2 */ + subRL[3] = krr; + ROLDQ(krl, krr, 30); + /* k7 */ + subRL[10] = krl; + /* k8 */ + subRL[11] = krr; + ROLDQ(krl, krr, 30); + /* k15 */ + subRL[20] = krl; + /* k16 */ + subRL[21] = krr; + ROLDQ(krl, krr, 51); + /* kw3 */ + subRL[32] = krl; + /* kw4 */ + subRL[33] = krr; + + camellia_setup_tail(subkey, subRL, 32); +} + +static void camellia_setup192(const unsigned char *key, u64 *subkey) +{ + unsigned char kk[32]; + u64 krl, krr; + + memcpy(kk, key, 24); + memcpy((unsigned char *)&krl, key+16, 8); + krr = ~krl; + memcpy(kk+24, (unsigned char *)&krr, 8); + camellia_setup256(kk, subkey); +} + +static int __camellia_setkey(struct camellia_ctx *cctx, + const unsigned char *key, + unsigned int key_len, u32 *flags) +{ + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + cctx->key_length = key_len; + + switch (key_len) { + case 16: + camellia_setup128(key, cctx->key_table); + break; + case 24: + camellia_setup192(key, cctx->key_table); + break; + case 32: + camellia_setup256(key, cctx->key_table); + break; + } + + return 0; +} + +static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len, + &tfm->crt_flags); +} + +static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, + void (*fn)(struct camellia_ctx *, u8 *, const u8 *), + void (*fn_2way)(struct camellia_ctx *, u8 *, const u8 *)) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes; + int err; + + err = blkcipher_walk_virt(desc, walk); + + while ((nbytes = walk->nbytes)) { + u8 *wsrc = walk->src.virt.addr; + u8 *wdst = walk->dst.virt.addr; + + /* Process two block batch */ + if (nbytes >= bsize * 2) { + do { + fn_2way(ctx, wdst, wsrc); + + wsrc += bsize * 2; + wdst += bsize * 2; + nbytes -= bsize * 2; + } while (nbytes >= bsize * 2); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + fn(ctx, wdst, wsrc); + + wsrc += bsize; + wdst += bsize; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + err = blkcipher_walk_done(desc, walk, nbytes); + } + + return err; +} + +static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_crypt(desc, &walk, camellia_enc_blk, camellia_enc_blk_2way); +} + +static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_crypt(desc, &walk, camellia_dec_blk, camellia_dec_blk_2way); +} + +static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u128 *src = (u128 *)walk->src.virt.addr; + u128 *dst = (u128 *)walk->dst.virt.addr; + u128 *iv = (u128 *)walk->iv; + + do { + u128_xor(dst, src, iv); + camellia_enc_blk(ctx, (u8 *)dst, (u8 *)dst); + iv = dst; + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + + u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); + return nbytes; +} + +static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes = __cbc_encrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u128 *src = (u128 *)walk->src.virt.addr; + u128 *dst = (u128 *)walk->dst.virt.addr; + u128 ivs[2 - 1]; + u128 last_iv; + + /* Start of the last block. */ + src += nbytes / bsize - 1; + dst += nbytes / bsize - 1; + + last_iv = *src; + + /* Process two block batch */ + if (nbytes >= bsize * 2) { + do { + nbytes -= bsize * (2 - 1); + src -= 2 - 1; + dst -= 2 - 1; + + ivs[0] = src[0]; + + camellia_dec_blk_2way(ctx, (u8 *)dst, (u8 *)src); + + u128_xor(dst + 1, dst + 1, ivs + 0); + + nbytes -= bsize; + if (nbytes < bsize) + goto done; + + u128_xor(dst, dst, src - 1); + src -= 1; + dst -= 1; + } while (nbytes >= bsize * 2); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + for (;;) { + camellia_dec_blk(ctx, (u8 *)dst, (u8 *)src); + + nbytes -= bsize; + if (nbytes < bsize) + break; + + u128_xor(dst, dst, src - 1); + src -= 1; + dst -= 1; + } + +done: + u128_xor(dst, dst, (u128 *)walk->iv); + *(u128 *)walk->iv = last_iv; + + return nbytes; +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes = __cbc_decrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static inline void u128_to_be128(be128 *dst, const u128 *src) +{ + dst->a = cpu_to_be64(src->a); + dst->b = cpu_to_be64(src->b); +} + +static inline void be128_to_u128(u128 *dst, const be128 *src) +{ + dst->a = be64_to_cpu(src->a); + dst->b = be64_to_cpu(src->b); +} + +static inline void u128_inc(u128 *i) +{ + i->b++; + if (!i->b) + i->a++; +} + +static void ctr_crypt_final(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + u8 keystream[CAMELLIA_BLOCK_SIZE]; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + u128 ctrblk; + + memcpy(keystream, src, nbytes); + camellia_enc_blk_xor(ctx, keystream, walk->iv); + memcpy(dst, keystream, nbytes); + + be128_to_u128(&ctrblk, (be128 *)walk->iv); + u128_inc(&ctrblk); + u128_to_be128((be128 *)walk->iv, &ctrblk); +} + +static unsigned int __ctr_crypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u128 *src = (u128 *)walk->src.virt.addr; + u128 *dst = (u128 *)walk->dst.virt.addr; + u128 ctrblk; + be128 ctrblocks[2]; + + be128_to_u128(&ctrblk, (be128 *)walk->iv); + + /* Process two block batch */ + if (nbytes >= bsize * 2) { + do { + if (dst != src) { + dst[0] = src[0]; + dst[1] = src[1]; + } + + /* create ctrblks for parallel encrypt */ + u128_to_be128(&ctrblocks[0], &ctrblk); + u128_inc(&ctrblk); + u128_to_be128(&ctrblocks[1], &ctrblk); + u128_inc(&ctrblk); + + camellia_enc_blk_xor_2way(ctx, (u8 *)dst, + (u8 *)ctrblocks); + + src += 2; + dst += 2; + nbytes -= bsize * 2; + } while (nbytes >= bsize * 2); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + if (dst != src) + *dst = *src; + + u128_to_be128(&ctrblocks[0], &ctrblk); + u128_inc(&ctrblk); + + camellia_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + u128_to_be128((be128 *)walk->iv, &ctrblk); + return nbytes; +} + +static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, CAMELLIA_BLOCK_SIZE); + + while ((nbytes = walk.nbytes) >= CAMELLIA_BLOCK_SIZE) { + nbytes = __ctr_crypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + if (walk.nbytes) { + ctr_crypt_final(desc, &walk); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + +static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAMELLIA_BLOCK_SIZE; + struct camellia_ctx *ctx = priv; + int i; + + while (nbytes >= 2 * bsize) { + camellia_enc_blk_2way(ctx, srcdst, srcdst); + srcdst += bsize * 2; + nbytes -= bsize * 2; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + camellia_enc_blk(ctx, srcdst, srcdst); +} + +static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAMELLIA_BLOCK_SIZE; + struct camellia_ctx *ctx = priv; + int i; + + while (nbytes >= 2 * bsize) { + camellia_dec_blk_2way(ctx, srcdst, srcdst); + srcdst += bsize * 2; + nbytes -= bsize * 2; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + camellia_dec_blk(ctx, srcdst, srcdst); +} + +struct camellia_lrw_ctx { + struct lrw_table_ctx lrw_table; + struct camellia_ctx camellia_ctx; +}; + +static int lrw_camellia_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + err = __camellia_setkey(&ctx->camellia_ctx, key, + keylen - CAMELLIA_BLOCK_SIZE, + &tfm->crt_flags); + if (err) + return err; + + return lrw_init_table(&ctx->lrw_table, + key + keylen - CAMELLIA_BLOCK_SIZE); +} + +static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &ctx->camellia_ctx, + .crypt_fn = encrypt_callback, + }; + + return lrw_crypt(desc, dst, src, nbytes, &req); +} + +static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &ctx->camellia_ctx, + .crypt_fn = decrypt_callback, + }; + + return lrw_crypt(desc, dst, src, nbytes, &req); +} + +static void lrw_exit_tfm(struct crypto_tfm *tfm) +{ + struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + + lrw_free_table(&ctx->lrw_table); +} + +struct camellia_xts_ctx { + struct camellia_ctx tweak_ctx; + struct camellia_ctx crypt_ctx; +}; + +static int xts_camellia_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct camellia_xts_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + int err; + + /* key consists of keys of equal size concatenated, therefore + * the length must be even + */ + if (keylen % 2) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* first half of xts-key is for crypt */ + err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return __camellia_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2, + flags); +} + +static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk), + .crypt_ctx = &ctx->crypt_ctx, + .crypt_fn = encrypt_callback, + }; + + return xts_crypt(desc, dst, src, nbytes, &req); +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk), + .crypt_ctx = &ctx->crypt_ctx, + .crypt_fn = decrypt_callback, + }; + + return xts_crypt(desc, dst, src, nbytes, &req); +} + +static struct crypto_alg camellia_algs[6] = { { + .cra_name = "camellia", + .cra_driver_name = "camellia-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[0].cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, + .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, + .cia_setkey = camellia_setkey, + .cia_encrypt = camellia_encrypt, + .cia_decrypt = camellia_decrypt + } + } +}, { + .cra_name = "ecb(camellia)", + .cra_driver_name = "ecb-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .setkey = camellia_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "cbc(camellia)", + .cra_driver_name = "cbc-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = camellia_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "ctr(camellia)", + .cra_driver_name = "ctr-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[3].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = camellia_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "lrw(camellia)", + .cra_driver_name = "lrw-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[4].cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE + + CAMELLIA_BLOCK_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE + + CAMELLIA_BLOCK_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = lrw_camellia_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "xts(camellia)", + .cra_driver_name = "xts-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[5].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2, + .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = xts_camellia_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +} }; + +static bool is_blacklisted_cpu(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return false; + + if (boot_cpu_data.x86 == 0x0f) { + /* + * On Pentium 4, camellia-asm is slower than original assembler + * implementation because excessive uses of 64bit rotate and + * left-shifts (which are really slow on P4) needed to store and + * handle 128bit block in two 64bit registers. + */ + return true; + } + + return false; +} + +static int force; +module_param(force, int, 0); +MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); + +int __init init(void) +{ + if (!force && is_blacklisted_cpu()) { + printk(KERN_INFO + "camellia-x86_64: performance on this CPU " + "would be suboptimal: disabling " + "camellia-x86_64.\n"); + return -ENODEV; + } + + return crypto_register_algs(camellia_algs, ARRAY_SIZE(camellia_algs)); +} + +void __exit fini(void) +{ + crypto_unregister_algs(camellia_algs, ARRAY_SIZE(camellia_algs)); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Camellia Cipher Algorithm, asm optimized"); +MODULE_ALIAS("camellia"); +MODULE_ALIAS("camellia-asm"); diff --git a/arch/x86/crypto/serpent-sse2-i586-asm_32.S b/arch/x86/crypto/serpent-sse2-i586-asm_32.S index 4e37677ca851..c00053d42f99 100644 --- a/arch/x86/crypto/serpent-sse2-i586-asm_32.S +++ b/arch/x86/crypto/serpent-sse2-i586-asm_32.S @@ -463,23 +463,20 @@ pand x0, x4; \ pxor x2, x4; -#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ - movdqa x2, t3; \ - movdqa x0, t1; \ - unpcklps x3, t3; \ +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ movdqa x0, t2; \ - unpcklps x1, t1; \ - unpckhps x1, t2; \ - movdqa t3, x1; \ - unpckhps x3, x2; \ - movdqa t1, x0; \ - movhlps t1, x1; \ - movdqa t2, t1; \ - movlhps t3, x0; \ - movlhps x2, t1; \ - movhlps t2, x2; \ - movdqa x2, x3; \ - movdqa t1, x2; + punpckldq x1, x0; \ + punpckhdq x1, t2; \ + movdqa x2, t1; \ + punpckhdq x3, x2; \ + punpckldq x3, t1; \ + movdqa x0, x1; \ + punpcklqdq t1, x0; \ + punpckhqdq t1, x1; \ + movdqa t2, x3; \ + punpcklqdq x2, t2; \ + punpckhqdq x2, x3; \ + movdqa t2, x2; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S index 7f24a1540821..3ee1ff04d3e9 100644 --- a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S +++ b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S @@ -585,23 +585,20 @@ get_key(i, 1, RK1); \ SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \ -#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ - movdqa x2, t3; \ - movdqa x0, t1; \ - unpcklps x3, t3; \ +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ movdqa x0, t2; \ - unpcklps x1, t1; \ - unpckhps x1, t2; \ - movdqa t3, x1; \ - unpckhps x3, x2; \ - movdqa t1, x0; \ - movhlps t1, x1; \ - movdqa t2, t1; \ - movlhps t3, x0; \ - movlhps x2, t1; \ - movhlps t2, x2; \ - movdqa x2, x3; \ - movdqa t1, x2; + punpckldq x1, x0; \ + punpckhdq x1, t2; \ + movdqa x2, t1; \ + punpckhdq x3, x2; \ + punpckldq x3, t1; \ + movdqa x0, x1; \ + punpcklqdq t1, x0; \ + punpckhqdq t1, x1; \ + movdqa t2, x3; \ + punpcklqdq x2, t2; \ + punpckhqdq x2, x3; \ + movdqa t2, x2; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index 7955a9b76b91..4b21be85e0a1 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -145,28 +145,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, false); } -static struct crypto_alg blk_ecb_alg = { - .cra_name = "__ecb-serpent-sse2", - .cra_driver_name = "__driver-ecb-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .setkey = serpent_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}; - static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -295,28 +273,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_cbc_alg = { - .cra_name = "__cbc-serpent-sse2", - .cra_driver_name = "__driver-cbc-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .setkey = serpent_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}; - static inline void u128_to_be128(be128 *dst, const u128 *src) { dst->a = cpu_to_be64(src->a); @@ -439,29 +395,6 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { - .cra_name = "__ctr-serpent-sse2", - .cra_driver_name = "__driver-ctr-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = serpent_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}; - struct crypt_priv { struct serpent_ctx *ctx; bool fpu_enabled; @@ -580,32 +513,6 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm) lrw_free_table(&ctx->lrw_table); } -static struct crypto_alg blk_lrw_alg = { - .cra_name = "__lrw-serpent-sse2", - .cra_driver_name = "__driver-lrw-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE + - SERPENT_BLOCK_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE + - SERPENT_BLOCK_SIZE, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = lrw_serpent_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}; - struct serpent_xts_ctx { struct serpent_ctx tweak_ctx; struct serpent_ctx crypt_ctx; @@ -689,29 +596,6 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ret; } -static struct crypto_alg blk_xts_alg = { - .cra_name = "__xts-serpent-sse2", - .cra_driver_name = "__driver-xts-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_xts_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE * 2, - .max_keysize = SERPENT_MAX_KEY_SIZE * 2, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = xts_serpent_setkey, - .encrypt = xts_encrypt, - .decrypt = xts_decrypt, - }, - }, -}; - static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int key_len) { @@ -792,28 +676,133 @@ static void ablk_exit(struct crypto_tfm *tfm) cryptd_free_ablkcipher(ctx->cryptd_tfm); } -static void ablk_init_common(struct crypto_tfm *tfm, - struct cryptd_ablkcipher *cryptd_tfm) +static int ablk_init(struct crypto_tfm *tfm) { struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); + struct cryptd_ablkcipher *cryptd_tfm; + char drv_name[CRYPTO_MAX_ALG_NAME]; + + snprintf(drv_name, sizeof(drv_name), "__driver-%s", + crypto_tfm_alg_driver_name(tfm)); + + cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); ctx->cryptd_tfm = cryptd_tfm; tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + crypto_ablkcipher_reqsize(&cryptd_tfm->base); -} - -static int ablk_ecb_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); return 0; } -static struct crypto_alg ablk_ecb_alg = { +static struct crypto_alg serpent_algs[10] = { { + .cra_name = "__ecb-serpent-sse2", + .cra_driver_name = "__driver-ecb-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .setkey = serpent_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "__cbc-serpent-sse2", + .cra_driver_name = "__driver-cbc-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .setkey = serpent_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "__ctr-serpent-sse2", + .cra_driver_name = "__driver-ctr-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = serpent_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "__lrw-serpent-sse2", + .cra_driver_name = "__driver-lrw-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE + + SERPENT_BLOCK_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE + + SERPENT_BLOCK_SIZE, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = lrw_serpent_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "__xts-serpent-sse2", + .cra_driver_name = "__driver-xts-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE * 2, + .max_keysize = SERPENT_MAX_KEY_SIZE * 2, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = xts_serpent_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}, { .cra_name = "ecb(serpent)", .cra_driver_name = "ecb-serpent-sse2", .cra_priority = 400, @@ -823,8 +812,8 @@ static struct crypto_alg ablk_ecb_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), - .cra_init = ablk_ecb_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -835,20 +824,7 @@ static struct crypto_alg ablk_ecb_alg = { .decrypt = ablk_decrypt, }, }, -}; - -static int ablk_cbc_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_cbc_alg = { +}, { .cra_name = "cbc(serpent)", .cra_driver_name = "cbc-serpent-sse2", .cra_priority = 400, @@ -858,8 +834,8 @@ static struct crypto_alg ablk_cbc_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), - .cra_init = ablk_cbc_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -871,20 +847,7 @@ static struct crypto_alg ablk_cbc_alg = { .decrypt = ablk_decrypt, }, }, -}; - -static int ablk_ctr_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_ctr_alg = { +}, { .cra_name = "ctr(serpent)", .cra_driver_name = "ctr-serpent-sse2", .cra_priority = 400, @@ -894,8 +857,8 @@ static struct crypto_alg ablk_ctr_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), - .cra_init = ablk_ctr_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -908,20 +871,7 @@ static struct crypto_alg ablk_ctr_alg = { .geniv = "chainiv", }, }, -}; - -static int ablk_lrw_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_lrw_alg = { +}, { .cra_name = "lrw(serpent)", .cra_driver_name = "lrw-serpent-sse2", .cra_priority = 400, @@ -931,8 +881,8 @@ static struct crypto_alg ablk_lrw_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), - .cra_init = ablk_lrw_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -946,20 +896,7 @@ static struct crypto_alg ablk_lrw_alg = { .decrypt = ablk_decrypt, }, }, -}; - -static int ablk_xts_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_xts_alg = { +}, { .cra_name = "xts(serpent)", .cra_driver_name = "xts-serpent-sse2", .cra_priority = 400, @@ -969,8 +906,8 @@ static struct crypto_alg ablk_xts_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), - .cra_init = ablk_xts_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -982,84 +919,21 @@ static struct crypto_alg ablk_xts_alg = { .decrypt = ablk_decrypt, }, }, -}; +} }; static int __init serpent_sse2_init(void) { - int err; - if (!cpu_has_xmm2) { printk(KERN_INFO "SSE2 instructions are not detected.\n"); return -ENODEV; } - err = crypto_register_alg(&blk_ecb_alg); - if (err) - goto blk_ecb_err; - err = crypto_register_alg(&blk_cbc_alg); - if (err) - goto blk_cbc_err; - err = crypto_register_alg(&blk_ctr_alg); - if (err) - goto blk_ctr_err; - err = crypto_register_alg(&ablk_ecb_alg); - if (err) - goto ablk_ecb_err; - err = crypto_register_alg(&ablk_cbc_alg); - if (err) - goto ablk_cbc_err; - err = crypto_register_alg(&ablk_ctr_alg); - if (err) - goto ablk_ctr_err; - err = crypto_register_alg(&blk_lrw_alg); - if (err) - goto blk_lrw_err; - err = crypto_register_alg(&ablk_lrw_alg); - if (err) - goto ablk_lrw_err; - err = crypto_register_alg(&blk_xts_alg); - if (err) - goto blk_xts_err; - err = crypto_register_alg(&ablk_xts_alg); - if (err) - goto ablk_xts_err; - return err; - - crypto_unregister_alg(&ablk_xts_alg); -ablk_xts_err: - crypto_unregister_alg(&blk_xts_alg); -blk_xts_err: - crypto_unregister_alg(&ablk_lrw_alg); -ablk_lrw_err: - crypto_unregister_alg(&blk_lrw_alg); -blk_lrw_err: - crypto_unregister_alg(&ablk_ctr_alg); -ablk_ctr_err: - crypto_unregister_alg(&ablk_cbc_alg); -ablk_cbc_err: - crypto_unregister_alg(&ablk_ecb_alg); -ablk_ecb_err: - crypto_unregister_alg(&blk_ctr_alg); -blk_ctr_err: - crypto_unregister_alg(&blk_cbc_alg); -blk_cbc_err: - crypto_unregister_alg(&blk_ecb_alg); -blk_ecb_err: - return err; + return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); } static void __exit serpent_sse2_exit(void) { - crypto_unregister_alg(&ablk_xts_alg); - crypto_unregister_alg(&blk_xts_alg); - crypto_unregister_alg(&ablk_lrw_alg); - crypto_unregister_alg(&blk_lrw_alg); - crypto_unregister_alg(&ablk_ctr_alg); - crypto_unregister_alg(&ablk_cbc_alg); - crypto_unregister_alg(&ablk_ecb_alg); - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); + crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); } module_init(serpent_sse2_init); diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c index dc6b3fb817fc..359ae084275c 100644 --- a/arch/x86/crypto/twofish_glue.c +++ b/arch/x86/crypto/twofish_glue.c @@ -68,7 +68,7 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = TF_BLOCK_SIZE, .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 3, + .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 7fee8c152f93..408fc0c5814e 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -25,6 +25,7 @@ * */ +#include <asm/processor.h> #include <linux/crypto.h> #include <linux/init.h> #include <linux/module.h> @@ -122,28 +123,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, twofish_dec_blk, twofish_dec_blk_3way); } -static struct crypto_alg blk_ecb_alg = { - .cra_name = "ecb(twofish)", - .cra_driver_name = "ecb-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .setkey = twofish_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}; - static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -267,29 +246,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_cbc_alg = { - .cra_name = "cbc(twofish)", - .cra_driver_name = "cbc-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = twofish_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}; - static inline void u128_to_be128(be128 *dst, const u128 *src) { dst->a = cpu_to_be64(src->a); @@ -411,29 +367,6 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { - .cra_name = "ctr(twofish)", - .cra_driver_name = "ctr-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = twofish_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}; - static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) { const unsigned int bsize = TF_BLOCK_SIZE; @@ -524,30 +457,6 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm) lrw_free_table(&ctx->lrw_table); } -static struct crypto_alg blk_lrw_alg = { - .cra_name = "lrw(twofish)", - .cra_driver_name = "lrw-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, - .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = lrw_twofish_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}; - struct twofish_xts_ctx { struct twofish_ctx tweak_ctx; struct twofish_ctx crypt_ctx; @@ -614,7 +523,91 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return xts_crypt(desc, dst, src, nbytes, &req); } -static struct crypto_alg blk_xts_alg = { +static struct crypto_alg tf_algs[5] = { { + .cra_name = "ecb(twofish)", + .cra_driver_name = "ecb-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[0].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .setkey = twofish_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "cbc(twofish)", + .cra_driver_name = "cbc-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = twofish_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "ctr(twofish)", + .cra_driver_name = "ctr-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = twofish_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "lrw(twofish)", + .cra_driver_name = "lrw-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[3].cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, + .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = lrw_twofish_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { .cra_name = "xts(twofish)", .cra_driver_name = "xts-twofish-3way", .cra_priority = 300, @@ -624,7 +617,7 @@ static struct crypto_alg blk_xts_alg = { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), + .cra_list = LIST_HEAD_INIT(tf_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, @@ -635,50 +628,62 @@ static struct crypto_alg blk_xts_alg = { .decrypt = xts_decrypt, }, }, -}; +} }; + +static bool is_blacklisted_cpu(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return false; + + if (boot_cpu_data.x86 == 0x06 && + (boot_cpu_data.x86_model == 0x1c || + boot_cpu_data.x86_model == 0x26 || + boot_cpu_data.x86_model == 0x36)) { + /* + * On Atom, twofish-3way is slower than original assembler + * implementation. Twofish-3way trades off some performance in + * storing blocks in 64bit registers to allow three blocks to + * be processed parallel. Parallel operation then allows gaining + * more performance than was trade off, on out-of-order CPUs. + * However Atom does not benefit from this parallellism and + * should be blacklisted. + */ + return true; + } + + if (boot_cpu_data.x86 == 0x0f) { + /* + * On Pentium 4, twofish-3way is slower than original assembler + * implementation because excessive uses of 64bit rotate and + * left-shifts (which are really slow on P4) needed to store and + * handle 128bit block in two 64bit registers. + */ + return true; + } + + return false; +} + +static int force; +module_param(force, int, 0); +MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); int __init init(void) { - int err; + if (!force && is_blacklisted_cpu()) { + printk(KERN_INFO + "twofish-x86_64-3way: performance on this CPU " + "would be suboptimal: disabling " + "twofish-x86_64-3way.\n"); + return -ENODEV; + } - err = crypto_register_alg(&blk_ecb_alg); - if (err) - goto ecb_err; - err = crypto_register_alg(&blk_cbc_alg); - if (err) - goto cbc_err; - err = crypto_register_alg(&blk_ctr_alg); - if (err) - goto ctr_err; - err = crypto_register_alg(&blk_lrw_alg); - if (err) - goto blk_lrw_err; - err = crypto_register_alg(&blk_xts_alg); - if (err) - goto blk_xts_err; - - return 0; - - crypto_unregister_alg(&blk_xts_alg); -blk_xts_err: - crypto_unregister_alg(&blk_lrw_alg); -blk_lrw_err: - crypto_unregister_alg(&blk_ctr_alg); -ctr_err: - crypto_unregister_alg(&blk_cbc_alg); -cbc_err: - crypto_unregister_alg(&blk_ecb_alg); -ecb_err: - return err; + return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs)); } void __exit fini(void) { - crypto_unregister_alg(&blk_xts_alg); - crypto_unregister_alg(&blk_lrw_alg); - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); + crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs)); } module_init(init); diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 39e49091f648..4c2e59a420b9 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -323,7 +323,6 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs) } install_exec_creds(bprm); - current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == OMAGIC) { unsigned long text_addr, map_size; @@ -519,7 +518,8 @@ out: static int __init init_aout_binfmt(void) { - return register_binfmt(&aout_format); + register_binfmt(&aout_format); + return 0; } static void __exit exit_aout_binfmt(void) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 65577698cab2..5563ba1cf513 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -24,6 +24,7 @@ #include <asm/ucontext.h> #include <asm/uaccess.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/ptrace.h> #include <asm/ia32_unistd.h> #include <asm/user32.h> diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 37ad100a2210..49331bedc158 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -145,6 +145,12 @@ static inline int alternatives_text_reserved(void *start, void *end) */ #define ASM_OUTPUT2(a...) a +/* + * use this macro if you need clobbers but no inputs in + * alternative_{input,io,call}() + */ +#define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr + struct paravirt_patch_site; #ifdef CONFIG_PARAVIRT void apply_paravirt(struct paravirt_patch_site *start, diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 3ab9bdd87e79..a9371c91718c 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -288,6 +288,7 @@ struct apic { int (*probe)(void); int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id); + int (*apic_id_valid)(int apicid); int (*apic_id_registered)(void); u32 irq_delivery_mode; @@ -532,6 +533,11 @@ static inline unsigned int read_apic_id(void) return apic->get_apic_id(reg); } +static inline int default_apic_id_valid(int apicid) +{ + return x2apic_mode || (apicid < 255); +} + extern void default_setup_apic_routing(void); extern struct apic apic_noop; diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h index fa13f0ec2874..198119910da5 100644 --- a/arch/x86/include/asm/atomic64_32.h +++ b/arch/x86/include/asm/atomic64_32.h @@ -14,13 +14,52 @@ typedef struct { #define ATOMIC64_INIT(val) { (val) } +#define __ATOMIC64_DECL(sym) void atomic64_##sym(atomic64_t *, ...) +#ifndef ATOMIC64_EXPORT +#define ATOMIC64_DECL_ONE __ATOMIC64_DECL +#else +#define ATOMIC64_DECL_ONE(sym) __ATOMIC64_DECL(sym); \ + ATOMIC64_EXPORT(atomic64_##sym) +#endif + #ifdef CONFIG_X86_CMPXCHG64 -#define ATOMIC64_ALTERNATIVE_(f, g) "call atomic64_" #g "_cx8" +#define __alternative_atomic64(f, g, out, in...) \ + asm volatile("call %P[func]" \ + : out : [func] "i" (atomic64_##g##_cx8), ## in) + +#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8) #else -#define ATOMIC64_ALTERNATIVE_(f, g) ALTERNATIVE("call atomic64_" #f "_386", "call atomic64_" #g "_cx8", X86_FEATURE_CX8) +#define __alternative_atomic64(f, g, out, in...) \ + alternative_call(atomic64_##f##_386, atomic64_##g##_cx8, \ + X86_FEATURE_CX8, ASM_OUTPUT2(out), ## in) + +#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8); \ + ATOMIC64_DECL_ONE(sym##_386) + +ATOMIC64_DECL_ONE(add_386); +ATOMIC64_DECL_ONE(sub_386); +ATOMIC64_DECL_ONE(inc_386); +ATOMIC64_DECL_ONE(dec_386); #endif -#define ATOMIC64_ALTERNATIVE(f) ATOMIC64_ALTERNATIVE_(f, f) +#define alternative_atomic64(f, out, in...) \ + __alternative_atomic64(f, f, ASM_OUTPUT2(out), ## in) + +ATOMIC64_DECL(read); +ATOMIC64_DECL(set); +ATOMIC64_DECL(xchg); +ATOMIC64_DECL(add_return); +ATOMIC64_DECL(sub_return); +ATOMIC64_DECL(inc_return); +ATOMIC64_DECL(dec_return); +ATOMIC64_DECL(dec_if_positive); +ATOMIC64_DECL(inc_not_zero); +ATOMIC64_DECL(add_unless); + +#undef ATOMIC64_DECL +#undef ATOMIC64_DECL_ONE +#undef __ATOMIC64_DECL +#undef ATOMIC64_EXPORT /** * atomic64_cmpxchg - cmpxchg atomic64 variable @@ -50,11 +89,9 @@ static inline long long atomic64_xchg(atomic64_t *v, long long n) long long o; unsigned high = (unsigned)(n >> 32); unsigned low = (unsigned)n; - asm volatile(ATOMIC64_ALTERNATIVE(xchg) - : "=A" (o), "+b" (low), "+c" (high) - : "S" (v) - : "memory" - ); + alternative_atomic64(xchg, "=&A" (o), + "S" (v), "b" (low), "c" (high) + : "memory"); return o; } @@ -69,11 +106,9 @@ static inline void atomic64_set(atomic64_t *v, long long i) { unsigned high = (unsigned)(i >> 32); unsigned low = (unsigned)i; - asm volatile(ATOMIC64_ALTERNATIVE(set) - : "+b" (low), "+c" (high) - : "S" (v) - : "eax", "edx", "memory" - ); + alternative_atomic64(set, /* no output */, + "S" (v), "b" (low), "c" (high) + : "eax", "edx", "memory"); } /** @@ -85,10 +120,7 @@ static inline void atomic64_set(atomic64_t *v, long long i) static inline long long atomic64_read(const atomic64_t *v) { long long r; - asm volatile(ATOMIC64_ALTERNATIVE(read) - : "=A" (r), "+c" (v) - : : "memory" - ); + alternative_atomic64(read, "=&A" (r), "c" (v) : "memory"); return r; } @@ -101,10 +133,9 @@ static inline long long atomic64_read(const atomic64_t *v) */ static inline long long atomic64_add_return(long long i, atomic64_t *v) { - asm volatile(ATOMIC64_ALTERNATIVE(add_return) - : "+A" (i), "+c" (v) - : : "memory" - ); + alternative_atomic64(add_return, + ASM_OUTPUT2("+A" (i), "+c" (v)), + ASM_NO_INPUT_CLOBBER("memory")); return i; } @@ -113,32 +144,25 @@ static inline long long atomic64_add_return(long long i, atomic64_t *v) */ static inline long long atomic64_sub_return(long long i, atomic64_t *v) { - asm volatile(ATOMIC64_ALTERNATIVE(sub_return) - : "+A" (i), "+c" (v) - : : "memory" - ); + alternative_atomic64(sub_return, + ASM_OUTPUT2("+A" (i), "+c" (v)), + ASM_NO_INPUT_CLOBBER("memory")); return i; } static inline long long atomic64_inc_return(atomic64_t *v) { long long a; - asm volatile(ATOMIC64_ALTERNATIVE(inc_return) - : "=A" (a) - : "S" (v) - : "memory", "ecx" - ); + alternative_atomic64(inc_return, "=&A" (a), + "S" (v) : "memory", "ecx"); return a; } static inline long long atomic64_dec_return(atomic64_t *v) { long long a; - asm volatile(ATOMIC64_ALTERNATIVE(dec_return) - : "=A" (a) - : "S" (v) - : "memory", "ecx" - ); + alternative_atomic64(dec_return, "=&A" (a), + "S" (v) : "memory", "ecx"); return a; } @@ -151,10 +175,9 @@ static inline long long atomic64_dec_return(atomic64_t *v) */ static inline long long atomic64_add(long long i, atomic64_t *v) { - asm volatile(ATOMIC64_ALTERNATIVE_(add, add_return) - : "+A" (i), "+c" (v) - : : "memory" - ); + __alternative_atomic64(add, add_return, + ASM_OUTPUT2("+A" (i), "+c" (v)), + ASM_NO_INPUT_CLOBBER("memory")); return i; } @@ -167,10 +190,9 @@ static inline long long atomic64_add(long long i, atomic64_t *v) */ static inline long long atomic64_sub(long long i, atomic64_t *v) { - asm volatile(ATOMIC64_ALTERNATIVE_(sub, sub_return) - : "+A" (i), "+c" (v) - : : "memory" - ); + __alternative_atomic64(sub, sub_return, + ASM_OUTPUT2("+A" (i), "+c" (v)), + ASM_NO_INPUT_CLOBBER("memory")); return i; } @@ -196,10 +218,8 @@ static inline int atomic64_sub_and_test(long long i, atomic64_t *v) */ static inline void atomic64_inc(atomic64_t *v) { - asm volatile(ATOMIC64_ALTERNATIVE_(inc, inc_return) - : : "S" (v) - : "memory", "eax", "ecx", "edx" - ); + __alternative_atomic64(inc, inc_return, /* no output */, + "S" (v) : "memory", "eax", "ecx", "edx"); } /** @@ -210,10 +230,8 @@ static inline void atomic64_inc(atomic64_t *v) */ static inline void atomic64_dec(atomic64_t *v) { - asm volatile(ATOMIC64_ALTERNATIVE_(dec, dec_return) - : : "S" (v) - : "memory", "eax", "ecx", "edx" - ); + __alternative_atomic64(dec, dec_return, /* no output */, + "S" (v) : "memory", "eax", "ecx", "edx"); } /** @@ -263,15 +281,15 @@ static inline int atomic64_add_negative(long long i, atomic64_t *v) * @u: ...unless v is equal to u. * * Atomically adds @a to @v, so long as it was not @u. - * Returns the old value of @v. + * Returns non-zero if the add was done, zero otherwise. */ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) { unsigned low = (unsigned)u; unsigned high = (unsigned)(u >> 32); - asm volatile(ATOMIC64_ALTERNATIVE(add_unless) "\n\t" - : "+A" (a), "+c" (v), "+S" (low), "+D" (high) - : : "memory"); + alternative_atomic64(add_unless, + ASM_OUTPUT2("+A" (a), "+c" (low), "+D" (high)), + "S" (v) : "memory"); return (int)a; } @@ -279,26 +297,20 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) static inline int atomic64_inc_not_zero(atomic64_t *v) { int r; - asm volatile(ATOMIC64_ALTERNATIVE(inc_not_zero) - : "=a" (r) - : "S" (v) - : "ecx", "edx", "memory" - ); + alternative_atomic64(inc_not_zero, "=&a" (r), + "S" (v) : "ecx", "edx", "memory"); return r; } static inline long long atomic64_dec_if_positive(atomic64_t *v) { long long r; - asm volatile(ATOMIC64_ALTERNATIVE(dec_if_positive) - : "=A" (r) - : "S" (v) - : "ecx", "memory" - ); + alternative_atomic64(dec_if_positive, "=&A" (r), + "S" (v) : "ecx", "memory"); return r; } -#undef ATOMIC64_ALTERNATIVE -#undef ATOMIC64_ALTERNATIVE_ +#undef alternative_atomic64 +#undef __alternative_atomic64 #endif /* _ASM_X86_ATOMIC64_32_H */ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index dcb839eebc76..340ee49961a6 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -200,10 +200,13 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */ #define X86_FEATURE_FSGSBASE (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/ #define X86_FEATURE_BMI1 (9*32+ 3) /* 1st group bit manipulation extensions */ +#define X86_FEATURE_HLE (9*32+ 4) /* Hardware Lock Elision */ #define X86_FEATURE_AVX2 (9*32+ 5) /* AVX2 instructions */ #define X86_FEATURE_SMEP (9*32+ 7) /* Supervisor Mode Execution Protection */ #define X86_FEATURE_BMI2 (9*32+ 8) /* 2nd group bit manipulation extensions */ #define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */ +#define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */ +#define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */ #if defined(__KERNEL__) && !defined(__ASSEMBLY__) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 844f735fd63a..c9dcc181d4d1 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -95,7 +95,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, extern int add_efi_memmap; extern void efi_set_executable(efi_memory_desc_t *md, bool executable); -extern void efi_memblock_x86_reserve_range(void); +extern int efi_memblock_x86_reserve_range(void); extern void efi_call_phys_prelog(void); extern void efi_call_phys_epilog(void); diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h new file mode 100644 index 000000000000..4fa88154e4de --- /dev/null +++ b/arch/x86/include/asm/fpu-internal.h @@ -0,0 +1,520 @@ +/* + * Copyright (C) 1994 Linus Torvalds + * + * Pentium III FXSR, SSE support + * General FPU state handling cleanups + * Gareth Hughes <gareth@valinux.com>, May 2000 + * x86-64 work by Andi Kleen 2002 + */ + +#ifndef _FPU_INTERNAL_H +#define _FPU_INTERNAL_H + +#include <linux/kernel_stat.h> +#include <linux/regset.h> +#include <linux/slab.h> +#include <asm/asm.h> +#include <asm/cpufeature.h> +#include <asm/processor.h> +#include <asm/sigcontext.h> +#include <asm/user.h> +#include <asm/uaccess.h> +#include <asm/xsave.h> + +extern unsigned int sig_xstate_size; +extern void fpu_init(void); + +DECLARE_PER_CPU(struct task_struct *, fpu_owner_task); + +extern user_regset_active_fn fpregs_active, xfpregs_active; +extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, + xstateregs_get; +extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set, + xstateregs_set; + + +/* + * xstateregs_active == fpregs_active. Please refer to the comment + * at the definition of fpregs_active. + */ +#define xstateregs_active fpregs_active + +extern struct _fpx_sw_bytes fx_sw_reserved; +#ifdef CONFIG_IA32_EMULATION +extern unsigned int sig_xstate_ia32_size; +extern struct _fpx_sw_bytes fx_sw_reserved_ia32; +struct _fpstate_ia32; +struct _xstate_ia32; +extern int save_i387_xstate_ia32(void __user *buf); +extern int restore_i387_xstate_ia32(void __user *buf); +#endif + +#ifdef CONFIG_MATH_EMULATION +extern void finit_soft_fpu(struct i387_soft_struct *soft); +#else +static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} +#endif + +#define X87_FSW_ES (1 << 7) /* Exception Summary */ + +static __always_inline __pure bool use_xsaveopt(void) +{ + return static_cpu_has(X86_FEATURE_XSAVEOPT); +} + +static __always_inline __pure bool use_xsave(void) +{ + return static_cpu_has(X86_FEATURE_XSAVE); +} + +static __always_inline __pure bool use_fxsr(void) +{ + return static_cpu_has(X86_FEATURE_FXSR); +} + +extern void __sanitize_i387_state(struct task_struct *); + +static inline void sanitize_i387_state(struct task_struct *tsk) +{ + if (!use_xsaveopt()) + return; + __sanitize_i387_state(tsk); +} + +#ifdef CONFIG_X86_64 +static inline int fxrstor_checking(struct i387_fxsave_struct *fx) +{ + int err; + + /* See comment in fxsave() below. */ +#ifdef CONFIG_AS_FXSAVEQ + asm volatile("1: fxrstorq %[fx]\n\t" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl $-1,%[err]\n" + " jmp 2b\n" + ".previous\n" + _ASM_EXTABLE(1b, 3b) + : [err] "=r" (err) + : [fx] "m" (*fx), "0" (0)); +#else + asm volatile("1: rex64/fxrstor (%[fx])\n\t" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl $-1,%[err]\n" + " jmp 2b\n" + ".previous\n" + _ASM_EXTABLE(1b, 3b) + : [err] "=r" (err) + : [fx] "R" (fx), "m" (*fx), "0" (0)); +#endif + return err; +} + +static inline int fxsave_user(struct i387_fxsave_struct __user *fx) +{ + int err; + + /* + * Clear the bytes not touched by the fxsave and reserved + * for the SW usage. + */ + err = __clear_user(&fx->sw_reserved, + sizeof(struct _fpx_sw_bytes)); + if (unlikely(err)) + return -EFAULT; + + /* See comment in fxsave() below. */ +#ifdef CONFIG_AS_FXSAVEQ + asm volatile("1: fxsaveq %[fx]\n\t" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl $-1,%[err]\n" + " jmp 2b\n" + ".previous\n" + _ASM_EXTABLE(1b, 3b) + : [err] "=r" (err), [fx] "=m" (*fx) + : "0" (0)); +#else + asm volatile("1: rex64/fxsave (%[fx])\n\t" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl $-1,%[err]\n" + " jmp 2b\n" + ".previous\n" + _ASM_EXTABLE(1b, 3b) + : [err] "=r" (err), "=m" (*fx) + : [fx] "R" (fx), "0" (0)); +#endif + if (unlikely(err) && + __clear_user(fx, sizeof(struct i387_fxsave_struct))) + err = -EFAULT; + /* No need to clear here because the caller clears USED_MATH */ + return err; +} + +static inline void fpu_fxsave(struct fpu *fpu) +{ + /* Using "rex64; fxsave %0" is broken because, if the memory operand + uses any extended registers for addressing, a second REX prefix + will be generated (to the assembler, rex64 followed by semicolon + is a separate instruction), and hence the 64-bitness is lost. */ + +#ifdef CONFIG_AS_FXSAVEQ + /* Using "fxsaveq %0" would be the ideal choice, but is only supported + starting with gas 2.16. */ + __asm__ __volatile__("fxsaveq %0" + : "=m" (fpu->state->fxsave)); +#else + /* Using, as a workaround, the properly prefixed form below isn't + accepted by any binutils version so far released, complaining that + the same type of prefix is used twice if an extended register is + needed for addressing (fix submitted to mainline 2005-11-21). + asm volatile("rex64/fxsave %0" + : "=m" (fpu->state->fxsave)); + This, however, we can work around by forcing the compiler to select + an addressing mode that doesn't require extended registers. */ + asm volatile("rex64/fxsave (%[fx])" + : "=m" (fpu->state->fxsave) + : [fx] "R" (&fpu->state->fxsave)); +#endif +} + +#else /* CONFIG_X86_32 */ + +/* perform fxrstor iff the processor has extended states, otherwise frstor */ +static inline int fxrstor_checking(struct i387_fxsave_struct *fx) +{ + /* + * The "nop" is needed to make the instructions the same + * length. + */ + alternative_input( + "nop ; frstor %1", + "fxrstor %1", + X86_FEATURE_FXSR, + "m" (*fx)); + + return 0; +} + +static inline void fpu_fxsave(struct fpu *fpu) +{ + asm volatile("fxsave %[fx]" + : [fx] "=m" (fpu->state->fxsave)); +} + +#endif /* CONFIG_X86_64 */ + +/* + * These must be called with preempt disabled. Returns + * 'true' if the FPU state is still intact. + */ +static inline int fpu_save_init(struct fpu *fpu) +{ + if (use_xsave()) { + fpu_xsave(fpu); + + /* + * xsave header may indicate the init state of the FP. + */ + if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP)) + return 1; + } else if (use_fxsr()) { + fpu_fxsave(fpu); + } else { + asm volatile("fnsave %[fx]; fwait" + : [fx] "=m" (fpu->state->fsave)); + return 0; + } + + /* + * If exceptions are pending, we need to clear them so + * that we don't randomly get exceptions later. + * + * FIXME! Is this perhaps only true for the old-style + * irq13 case? Maybe we could leave the x87 state + * intact otherwise? + */ + if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) { + asm volatile("fnclex"); + return 0; + } + return 1; +} + +static inline int __save_init_fpu(struct task_struct *tsk) +{ + return fpu_save_init(&tsk->thread.fpu); +} + +static inline int fpu_fxrstor_checking(struct fpu *fpu) +{ + return fxrstor_checking(&fpu->state->fxsave); +} + +static inline int fpu_restore_checking(struct fpu *fpu) +{ + if (use_xsave()) + return fpu_xrstor_checking(fpu); + else + return fpu_fxrstor_checking(fpu); +} + +static inline int restore_fpu_checking(struct task_struct *tsk) +{ + /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception + is pending. Clear the x87 state here by setting it to fixed + values. "m" is a random variable that should be in L1 */ + alternative_input( + ASM_NOP8 ASM_NOP2, + "emms\n\t" /* clear stack tags */ + "fildl %P[addr]", /* set F?P to defined value */ + X86_FEATURE_FXSAVE_LEAK, + [addr] "m" (tsk->thread.fpu.has_fpu)); + + return fpu_restore_checking(&tsk->thread.fpu); +} + +/* + * Software FPU state helpers. Careful: these need to + * be preemption protection *and* they need to be + * properly paired with the CR0.TS changes! + */ +static inline int __thread_has_fpu(struct task_struct *tsk) +{ + return tsk->thread.fpu.has_fpu; +} + +/* Must be paired with an 'stts' after! */ +static inline void __thread_clear_has_fpu(struct task_struct *tsk) +{ + tsk->thread.fpu.has_fpu = 0; + percpu_write(fpu_owner_task, NULL); +} + +/* Must be paired with a 'clts' before! */ +static inline void __thread_set_has_fpu(struct task_struct *tsk) +{ + tsk->thread.fpu.has_fpu = 1; + percpu_write(fpu_owner_task, tsk); +} + +/* + * Encapsulate the CR0.TS handling together with the + * software flag. + * + * These generally need preemption protection to work, + * do try to avoid using these on their own. + */ +static inline void __thread_fpu_end(struct task_struct *tsk) +{ + __thread_clear_has_fpu(tsk); + stts(); +} + +static inline void __thread_fpu_begin(struct task_struct *tsk) +{ + clts(); + __thread_set_has_fpu(tsk); +} + +/* + * FPU state switching for scheduling. + * + * This is a two-stage process: + * + * - switch_fpu_prepare() saves the old state and + * sets the new state of the CR0.TS bit. This is + * done within the context of the old process. + * + * - switch_fpu_finish() restores the new state as + * necessary. + */ +typedef struct { int preload; } fpu_switch_t; + +/* + * FIXME! We could do a totally lazy restore, but we need to + * add a per-cpu "this was the task that last touched the FPU + * on this CPU" variable, and the task needs to have a "I last + * touched the FPU on this CPU" and check them. + * + * We don't do that yet, so "fpu_lazy_restore()" always returns + * false, but some day.. + */ +static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu) +{ + return new == percpu_read_stable(fpu_owner_task) && + cpu == new->thread.fpu.last_cpu; +} + +static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu) +{ + fpu_switch_t fpu; + + fpu.preload = tsk_used_math(new) && new->fpu_counter > 5; + if (__thread_has_fpu(old)) { + if (!__save_init_fpu(old)) + cpu = ~0; + old->thread.fpu.last_cpu = cpu; + old->thread.fpu.has_fpu = 0; /* But leave fpu_owner_task! */ + + /* Don't change CR0.TS if we just switch! */ + if (fpu.preload) { + new->fpu_counter++; + __thread_set_has_fpu(new); + prefetch(new->thread.fpu.state); + } else + stts(); + } else { + old->fpu_counter = 0; + old->thread.fpu.last_cpu = ~0; + if (fpu.preload) { + new->fpu_counter++; + if (fpu_lazy_restore(new, cpu)) + fpu.preload = 0; + else + prefetch(new->thread.fpu.state); + __thread_fpu_begin(new); + } + } + return fpu; +} + +/* + * By the time this gets called, we've already cleared CR0.TS and + * given the process the FPU if we are going to preload the FPU + * state - all we need to do is to conditionally restore the register + * state itself. + */ +static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu) +{ + if (fpu.preload) { + if (unlikely(restore_fpu_checking(new))) + __thread_fpu_end(new); + } +} + +/* + * Signal frame handlers... + */ +extern int save_i387_xstate(void __user *buf); +extern int restore_i387_xstate(void __user *buf); + +static inline void __clear_fpu(struct task_struct *tsk) +{ + if (__thread_has_fpu(tsk)) { + /* Ignore delayed exceptions from user space */ + asm volatile("1: fwait\n" + "2:\n" + _ASM_EXTABLE(1b, 2b)); + __thread_fpu_end(tsk); + } +} + +/* + * The actual user_fpu_begin/end() functions + * need to be preemption-safe. + * + * NOTE! user_fpu_end() must be used only after you + * have saved the FP state, and user_fpu_begin() must + * be used only immediately before restoring it. + * These functions do not do any save/restore on + * their own. + */ +static inline void user_fpu_end(void) +{ + preempt_disable(); + __thread_fpu_end(current); + preempt_enable(); +} + +static inline void user_fpu_begin(void) +{ + preempt_disable(); + if (!user_has_fpu()) + __thread_fpu_begin(current); + preempt_enable(); +} + +/* + * These disable preemption on their own and are safe + */ +static inline void save_init_fpu(struct task_struct *tsk) +{ + WARN_ON_ONCE(!__thread_has_fpu(tsk)); + preempt_disable(); + __save_init_fpu(tsk); + __thread_fpu_end(tsk); + preempt_enable(); +} + +static inline void clear_fpu(struct task_struct *tsk) +{ + preempt_disable(); + __clear_fpu(tsk); + preempt_enable(); +} + +/* + * i387 state interaction + */ +static inline unsigned short get_fpu_cwd(struct task_struct *tsk) +{ + if (cpu_has_fxsr) { + return tsk->thread.fpu.state->fxsave.cwd; + } else { + return (unsigned short)tsk->thread.fpu.state->fsave.cwd; + } +} + +static inline unsigned short get_fpu_swd(struct task_struct *tsk) +{ + if (cpu_has_fxsr) { + return tsk->thread.fpu.state->fxsave.swd; + } else { + return (unsigned short)tsk->thread.fpu.state->fsave.swd; + } +} + +static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk) +{ + if (cpu_has_xmm) { + return tsk->thread.fpu.state->fxsave.mxcsr; + } else { + return MXCSR_DEFAULT; + } +} + +static bool fpu_allocated(struct fpu *fpu) +{ + return fpu->state != NULL; +} + +static inline int fpu_alloc(struct fpu *fpu) +{ + if (fpu_allocated(fpu)) + return 0; + fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL); + if (!fpu->state) + return -ENOMEM; + WARN_ON((unsigned long)fpu->state & 15); + return 0; +} + +static inline void fpu_free(struct fpu *fpu) +{ + if (fpu->state) { + kmem_cache_free(task_xstate_cachep, fpu->state); + fpu->state = NULL; + } +} + +static inline void fpu_copy(struct fpu *dst, struct fpu *src) +{ + memcpy(dst->state, src->state, xstate_size); +} + +extern void fpu_finit(struct fpu *fpu); + +#endif diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index 3bd04022fd0c..302a323b3f67 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -61,7 +61,7 @@ void *kmap(struct page *page); void kunmap(struct page *page); void *kmap_atomic_prot(struct page *page, pgprot_t prot); -void *__kmap_atomic(struct page *page); +void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 247904945d3f..7ce0798b1b26 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -13,476 +13,19 @@ #ifndef __ASSEMBLY__ #include <linux/sched.h> -#include <linux/kernel_stat.h> -#include <linux/regset.h> #include <linux/hardirq.h> -#include <linux/slab.h> -#include <asm/asm.h> -#include <asm/cpufeature.h> -#include <asm/processor.h> -#include <asm/sigcontext.h> -#include <asm/user.h> -#include <asm/uaccess.h> -#include <asm/xsave.h> +#include <asm/system.h> + +struct pt_regs; +struct user_i387_struct; -extern unsigned int sig_xstate_size; -extern void fpu_init(void); -extern void mxcsr_feature_mask_init(void); extern int init_fpu(struct task_struct *child); -extern void math_state_restore(void); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); +extern void math_state_restore(void); -DECLARE_PER_CPU(struct task_struct *, fpu_owner_task); - -extern user_regset_active_fn fpregs_active, xfpregs_active; -extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get, - xstateregs_get; -extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set, - xstateregs_set; - -/* - * xstateregs_active == fpregs_active. Please refer to the comment - * at the definition of fpregs_active. - */ -#define xstateregs_active fpregs_active - -extern struct _fpx_sw_bytes fx_sw_reserved; -#ifdef CONFIG_IA32_EMULATION -extern unsigned int sig_xstate_ia32_size; -extern struct _fpx_sw_bytes fx_sw_reserved_ia32; -struct _fpstate_ia32; -struct _xstate_ia32; -extern int save_i387_xstate_ia32(void __user *buf); -extern int restore_i387_xstate_ia32(void __user *buf); -#endif - -#ifdef CONFIG_MATH_EMULATION -extern void finit_soft_fpu(struct i387_soft_struct *soft); -#else -static inline void finit_soft_fpu(struct i387_soft_struct *soft) {} -#endif - -#define X87_FSW_ES (1 << 7) /* Exception Summary */ - -static __always_inline __pure bool use_xsaveopt(void) -{ - return static_cpu_has(X86_FEATURE_XSAVEOPT); -} - -static __always_inline __pure bool use_xsave(void) -{ - return static_cpu_has(X86_FEATURE_XSAVE); -} - -static __always_inline __pure bool use_fxsr(void) -{ - return static_cpu_has(X86_FEATURE_FXSR); -} - -extern void __sanitize_i387_state(struct task_struct *); - -static inline void sanitize_i387_state(struct task_struct *tsk) -{ - if (!use_xsaveopt()) - return; - __sanitize_i387_state(tsk); -} - -#ifdef CONFIG_X86_64 -static inline int fxrstor_checking(struct i387_fxsave_struct *fx) -{ - int err; - - /* See comment in fxsave() below. */ -#ifdef CONFIG_AS_FXSAVEQ - asm volatile("1: fxrstorq %[fx]\n\t" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err) - : [fx] "m" (*fx), "0" (0)); -#else - asm volatile("1: rex64/fxrstor (%[fx])\n\t" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err) - : [fx] "R" (fx), "m" (*fx), "0" (0)); -#endif - return err; -} - -static inline int fxsave_user(struct i387_fxsave_struct __user *fx) -{ - int err; - - /* - * Clear the bytes not touched by the fxsave and reserved - * for the SW usage. - */ - err = __clear_user(&fx->sw_reserved, - sizeof(struct _fpx_sw_bytes)); - if (unlikely(err)) - return -EFAULT; - - /* See comment in fxsave() below. */ -#ifdef CONFIG_AS_FXSAVEQ - asm volatile("1: fxsaveq %[fx]\n\t" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err), [fx] "=m" (*fx) - : "0" (0)); -#else - asm volatile("1: rex64/fxsave (%[fx])\n\t" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl $-1,%[err]\n" - " jmp 2b\n" - ".previous\n" - _ASM_EXTABLE(1b, 3b) - : [err] "=r" (err), "=m" (*fx) - : [fx] "R" (fx), "0" (0)); -#endif - if (unlikely(err) && - __clear_user(fx, sizeof(struct i387_fxsave_struct))) - err = -EFAULT; - /* No need to clear here because the caller clears USED_MATH */ - return err; -} - -static inline void fpu_fxsave(struct fpu *fpu) -{ - /* Using "rex64; fxsave %0" is broken because, if the memory operand - uses any extended registers for addressing, a second REX prefix - will be generated (to the assembler, rex64 followed by semicolon - is a separate instruction), and hence the 64-bitness is lost. */ - -#ifdef CONFIG_AS_FXSAVEQ - /* Using "fxsaveq %0" would be the ideal choice, but is only supported - starting with gas 2.16. */ - __asm__ __volatile__("fxsaveq %0" - : "=m" (fpu->state->fxsave)); -#else - /* Using, as a workaround, the properly prefixed form below isn't - accepted by any binutils version so far released, complaining that - the same type of prefix is used twice if an extended register is - needed for addressing (fix submitted to mainline 2005-11-21). - asm volatile("rex64/fxsave %0" - : "=m" (fpu->state->fxsave)); - This, however, we can work around by forcing the compiler to select - an addressing mode that doesn't require extended registers. */ - asm volatile("rex64/fxsave (%[fx])" - : "=m" (fpu->state->fxsave) - : [fx] "R" (&fpu->state->fxsave)); -#endif -} - -#else /* CONFIG_X86_32 */ - -/* perform fxrstor iff the processor has extended states, otherwise frstor */ -static inline int fxrstor_checking(struct i387_fxsave_struct *fx) -{ - /* - * The "nop" is needed to make the instructions the same - * length. - */ - alternative_input( - "nop ; frstor %1", - "fxrstor %1", - X86_FEATURE_FXSR, - "m" (*fx)); - - return 0; -} - -static inline void fpu_fxsave(struct fpu *fpu) -{ - asm volatile("fxsave %[fx]" - : [fx] "=m" (fpu->state->fxsave)); -} - -#endif /* CONFIG_X86_64 */ - -/* - * These must be called with preempt disabled. Returns - * 'true' if the FPU state is still intact. - */ -static inline int fpu_save_init(struct fpu *fpu) -{ - if (use_xsave()) { - fpu_xsave(fpu); - - /* - * xsave header may indicate the init state of the FP. - */ - if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP)) - return 1; - } else if (use_fxsr()) { - fpu_fxsave(fpu); - } else { - asm volatile("fnsave %[fx]; fwait" - : [fx] "=m" (fpu->state->fsave)); - return 0; - } - - /* - * If exceptions are pending, we need to clear them so - * that we don't randomly get exceptions later. - * - * FIXME! Is this perhaps only true for the old-style - * irq13 case? Maybe we could leave the x87 state - * intact otherwise? - */ - if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) { - asm volatile("fnclex"); - return 0; - } - return 1; -} - -static inline int __save_init_fpu(struct task_struct *tsk) -{ - return fpu_save_init(&tsk->thread.fpu); -} - -static inline int fpu_fxrstor_checking(struct fpu *fpu) -{ - return fxrstor_checking(&fpu->state->fxsave); -} - -static inline int fpu_restore_checking(struct fpu *fpu) -{ - if (use_xsave()) - return fpu_xrstor_checking(fpu); - else - return fpu_fxrstor_checking(fpu); -} - -static inline int restore_fpu_checking(struct task_struct *tsk) -{ - /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception - is pending. Clear the x87 state here by setting it to fixed - values. "m" is a random variable that should be in L1 */ - alternative_input( - ASM_NOP8 ASM_NOP2, - "emms\n\t" /* clear stack tags */ - "fildl %P[addr]", /* set F?P to defined value */ - X86_FEATURE_FXSAVE_LEAK, - [addr] "m" (tsk->thread.fpu.has_fpu)); - - return fpu_restore_checking(&tsk->thread.fpu); -} - -/* - * Software FPU state helpers. Careful: these need to - * be preemption protection *and* they need to be - * properly paired with the CR0.TS changes! - */ -static inline int __thread_has_fpu(struct task_struct *tsk) -{ - return tsk->thread.fpu.has_fpu; -} - -/* Must be paired with an 'stts' after! */ -static inline void __thread_clear_has_fpu(struct task_struct *tsk) -{ - tsk->thread.fpu.has_fpu = 0; - percpu_write(fpu_owner_task, NULL); -} - -/* Must be paired with a 'clts' before! */ -static inline void __thread_set_has_fpu(struct task_struct *tsk) -{ - tsk->thread.fpu.has_fpu = 1; - percpu_write(fpu_owner_task, tsk); -} - -/* - * Encapsulate the CR0.TS handling together with the - * software flag. - * - * These generally need preemption protection to work, - * do try to avoid using these on their own. - */ -static inline void __thread_fpu_end(struct task_struct *tsk) -{ - __thread_clear_has_fpu(tsk); - stts(); -} - -static inline void __thread_fpu_begin(struct task_struct *tsk) -{ - clts(); - __thread_set_has_fpu(tsk); -} - -/* - * FPU state switching for scheduling. - * - * This is a two-stage process: - * - * - switch_fpu_prepare() saves the old state and - * sets the new state of the CR0.TS bit. This is - * done within the context of the old process. - * - * - switch_fpu_finish() restores the new state as - * necessary. - */ -typedef struct { int preload; } fpu_switch_t; - -/* - * FIXME! We could do a totally lazy restore, but we need to - * add a per-cpu "this was the task that last touched the FPU - * on this CPU" variable, and the task needs to have a "I last - * touched the FPU on this CPU" and check them. - * - * We don't do that yet, so "fpu_lazy_restore()" always returns - * false, but some day.. - */ -static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu) -{ - return new == percpu_read_stable(fpu_owner_task) && - cpu == new->thread.fpu.last_cpu; -} - -static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new, int cpu) -{ - fpu_switch_t fpu; - - fpu.preload = tsk_used_math(new) && new->fpu_counter > 5; - if (__thread_has_fpu(old)) { - if (!__save_init_fpu(old)) - cpu = ~0; - old->thread.fpu.last_cpu = cpu; - old->thread.fpu.has_fpu = 0; /* But leave fpu_owner_task! */ - - /* Don't change CR0.TS if we just switch! */ - if (fpu.preload) { - new->fpu_counter++; - __thread_set_has_fpu(new); - prefetch(new->thread.fpu.state); - } else - stts(); - } else { - old->fpu_counter = 0; - old->thread.fpu.last_cpu = ~0; - if (fpu.preload) { - new->fpu_counter++; - if (fpu_lazy_restore(new, cpu)) - fpu.preload = 0; - else - prefetch(new->thread.fpu.state); - __thread_fpu_begin(new); - } - } - return fpu; -} - -/* - * By the time this gets called, we've already cleared CR0.TS and - * given the process the FPU if we are going to preload the FPU - * state - all we need to do is to conditionally restore the register - * state itself. - */ -static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu) -{ - if (fpu.preload) { - if (unlikely(restore_fpu_checking(new))) - __thread_fpu_end(new); - } -} - -/* - * Signal frame handlers... - */ -extern int save_i387_xstate(void __user *buf); -extern int restore_i387_xstate(void __user *buf); - -static inline void __clear_fpu(struct task_struct *tsk) -{ - if (__thread_has_fpu(tsk)) { - /* Ignore delayed exceptions from user space */ - asm volatile("1: fwait\n" - "2:\n" - _ASM_EXTABLE(1b, 2b)); - __thread_fpu_end(tsk); - } -} - -/* - * Were we in an interrupt that interrupted kernel mode? - * - * We can do a kernel_fpu_begin/end() pair *ONLY* if that - * pair does nothing at all: the thread must not have fpu (so - * that we don't try to save the FPU state), and TS must - * be set (so that the clts/stts pair does nothing that is - * visible in the interrupted kernel thread). - */ -static inline bool interrupted_kernel_fpu_idle(void) -{ - return !__thread_has_fpu(current) && - (read_cr0() & X86_CR0_TS); -} - -/* - * Were we in user mode (or vm86 mode) when we were - * interrupted? - * - * Doing kernel_fpu_begin/end() is ok if we are running - * in an interrupt context from user mode - we'll just - * save the FPU state as required. - */ -static inline bool interrupted_user_mode(void) -{ - struct pt_regs *regs = get_irq_regs(); - return regs && user_mode_vm(regs); -} - -/* - * Can we use the FPU in kernel mode with the - * whole "kernel_fpu_begin/end()" sequence? - * - * It's always ok in process context (ie "not interrupt") - * but it is sometimes ok even from an irq. - */ -static inline bool irq_fpu_usable(void) -{ - return !in_interrupt() || - interrupted_user_mode() || - interrupted_kernel_fpu_idle(); -} - -static inline void kernel_fpu_begin(void) -{ - struct task_struct *me = current; - - WARN_ON_ONCE(!irq_fpu_usable()); - preempt_disable(); - if (__thread_has_fpu(me)) { - __save_init_fpu(me); - __thread_clear_has_fpu(me); - /* We do 'stts()' in kernel_fpu_end() */ - } else { - percpu_write(fpu_owner_task, NULL); - clts(); - } -} - -static inline void kernel_fpu_end(void) -{ - stts(); - preempt_enable(); -} +extern bool irq_fpu_usable(void); +extern void kernel_fpu_begin(void); +extern void kernel_fpu_end(void); /* * Some instructions like VIA's padlock instructions generate a spurious @@ -524,126 +67,13 @@ static inline void irq_ts_restore(int TS_state) * we can just assume we have FPU access - typically * to save the FP state - we'll just take a #NM * fault and get the FPU access back. - * - * The actual user_fpu_begin/end() functions - * need to be preemption-safe, though. - * - * NOTE! user_fpu_end() must be used only after you - * have saved the FP state, and user_fpu_begin() must - * be used only immediately before restoring it. - * These functions do not do any save/restore on - * their own. */ static inline int user_has_fpu(void) { - return __thread_has_fpu(current); -} - -static inline void user_fpu_end(void) -{ - preempt_disable(); - __thread_fpu_end(current); - preempt_enable(); -} - -static inline void user_fpu_begin(void) -{ - preempt_disable(); - if (!user_has_fpu()) - __thread_fpu_begin(current); - preempt_enable(); -} - -/* - * These disable preemption on their own and are safe - */ -static inline void save_init_fpu(struct task_struct *tsk) -{ - WARN_ON_ONCE(!__thread_has_fpu(tsk)); - preempt_disable(); - __save_init_fpu(tsk); - __thread_fpu_end(tsk); - preempt_enable(); -} - -static inline void unlazy_fpu(struct task_struct *tsk) -{ - preempt_disable(); - if (__thread_has_fpu(tsk)) { - __save_init_fpu(tsk); - __thread_fpu_end(tsk); - } else - tsk->fpu_counter = 0; - preempt_enable(); -} - -static inline void clear_fpu(struct task_struct *tsk) -{ - preempt_disable(); - __clear_fpu(tsk); - preempt_enable(); -} - -/* - * i387 state interaction - */ -static inline unsigned short get_fpu_cwd(struct task_struct *tsk) -{ - if (cpu_has_fxsr) { - return tsk->thread.fpu.state->fxsave.cwd; - } else { - return (unsigned short)tsk->thread.fpu.state->fsave.cwd; - } -} - -static inline unsigned short get_fpu_swd(struct task_struct *tsk) -{ - if (cpu_has_fxsr) { - return tsk->thread.fpu.state->fxsave.swd; - } else { - return (unsigned short)tsk->thread.fpu.state->fsave.swd; - } -} - -static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk) -{ - if (cpu_has_xmm) { - return tsk->thread.fpu.state->fxsave.mxcsr; - } else { - return MXCSR_DEFAULT; - } -} - -static bool fpu_allocated(struct fpu *fpu) -{ - return fpu->state != NULL; -} - -static inline int fpu_alloc(struct fpu *fpu) -{ - if (fpu_allocated(fpu)) - return 0; - fpu->state = kmem_cache_alloc(task_xstate_cachep, GFP_KERNEL); - if (!fpu->state) - return -ENOMEM; - WARN_ON((unsigned long)fpu->state & 15); - return 0; -} - -static inline void fpu_free(struct fpu *fpu) -{ - if (fpu->state) { - kmem_cache_free(task_xstate_cachep, fpu->state); - fpu->state = NULL; - } -} - -static inline void fpu_copy(struct fpu *dst, struct fpu *src) -{ - memcpy(dst->state, src->state, xstate_size); + return current->thread.fpu.has_fpu; } -extern void fpu_finit(struct fpu *fpu); +extern void unlazy_fpu(struct task_struct *tsk); #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h deleted file mode 100644 index 423bbbddf36d..000000000000 --- a/arch/x86/include/asm/irq_controller.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __IRQ_CONTROLLER__ -#define __IRQ_CONTROLLER__ - -struct irq_domain { - int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize, - u32 *out_hwirq, u32 *out_type); - void *priv; - struct device_node *controller; - struct list_head l; -}; - -#endif diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 6aefb14cbbc5..441520e4174f 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -151,7 +151,7 @@ static inline void enable_p5_mce(void) {} void mce_setup(struct mce *m); void mce_log(struct mce *m); -extern struct device *mce_device[CONFIG_NR_CPUS]; +DECLARE_PER_CPU(struct device *, mce_device); /* * Maximum banks number. diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 0a0a95460434..fc18bf3ce7c8 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h @@ -26,8 +26,8 @@ extern struct sfi_rtc_table_entry sfi_mrtc_array[]; * identified via MSRs. */ enum mrst_cpu_type { - MRST_CPU_CHIP_LINCROFT = 1, - MRST_CPU_CHIP_PENWELL, + /* 1 was Moorestown */ + MRST_CPU_CHIP_PENWELL = 2, }; extern enum mrst_cpu_type __mrst_cpu_chip; diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 58545c97d071..95da14f7ee85 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -162,6 +162,7 @@ extern void early_cpu_init(void); extern void identify_boot_cpu(void); extern void identify_secondary_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); +void print_cpu_msr(struct cpuinfo_x86 *); extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c); extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c); extern unsigned short num_cache_leaves; diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h index 644dd885f05a..60bef663609a 100644 --- a/arch/x86/include/asm/prom.h +++ b/arch/x86/include/asm/prom.h @@ -21,7 +21,6 @@ #include <asm/irq.h> #include <linux/atomic.h> #include <asm/setup.h> -#include <asm/irq_controller.h> #ifdef CONFIG_OF extern int of_ioapic; @@ -43,15 +42,6 @@ extern char cmd_line[COMMAND_LINE_SIZE]; #define pci_address_to_pio pci_address_to_pio unsigned long pci_address_to_pio(phys_addr_t addr); -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - * - * FIXME: We really should implement proper virq handling like power, - * but that's going to be major surgery. - */ -static inline void irq_dispose_mapping(unsigned int virq) { } - #define HAVE_ARCH_DEVTREE_FIXUPS #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h index a82c2bf504b6..76bfa2cf301d 100644 --- a/arch/x86/include/asm/spinlock.h +++ b/arch/x86/include/asm/spinlock.h @@ -88,14 +88,14 @@ static inline int __ticket_spin_is_locked(arch_spinlock_t *lock) { struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets); - return !!(tmp.tail ^ tmp.head); + return tmp.tail != tmp.head; } static inline int __ticket_spin_is_contended(arch_spinlock_t *lock) { struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets); - return ((tmp.tail - tmp.head) & TICKET_MASK) > 1; + return (__ticket_t)(tmp.tail - tmp.head) > 1; } #ifndef CONFIG_PARAVIRT_SPINLOCKS diff --git a/arch/x86/include/asm/spinlock_types.h b/arch/x86/include/asm/spinlock_types.h index 8ebd5df7451e..ad0ad07fc006 100644 --- a/arch/x86/include/asm/spinlock_types.h +++ b/arch/x86/include/asm/spinlock_types.h @@ -16,7 +16,6 @@ typedef u32 __ticketpair_t; #endif #define TICKET_SHIFT (sizeof(__ticket_t) * 8) -#define TICKET_MASK ((__ticket_t)((1 << TICKET_SHIFT) - 1)) typedef struct arch_spinlock { union { diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ce664f33ea8e..406ed77216d0 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -593,7 +593,7 @@ void __init acpi_set_irq_model_ioapic(void) #ifdef CONFIG_ACPI_HOTPLUG_CPU #include <acpi/processor.h> -static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +static void __cpuinitdata acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) { #ifdef CONFIG_ACPI_NUMA int nid; diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 8c3cdded6f2b..359b6899a36c 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -180,6 +180,7 @@ static struct apic apic_flat = { .name = "flat", .probe = flat_probe, .acpi_madt_oem_check = flat_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = flat_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, @@ -337,6 +338,7 @@ static struct apic apic_physflat = { .name = "physical flat", .probe = physflat_probe, .acpi_madt_oem_check = physflat_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = flat_apic_id_registered, .irq_delivery_mode = dest_Fixed, diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index 775b82bc655c..634ae6cdd5c9 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -124,6 +124,7 @@ struct apic apic_noop = { .probe = noop_probe, .acpi_madt_oem_check = NULL, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = noop_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index 09d3d8c1cd99..d9ea5f331ac5 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -56,6 +56,12 @@ static unsigned int read_xapic_id(void) return get_apic_id(apic_read(APIC_ID)); } +static int numachip_apic_id_valid(int apicid) +{ + /* Trust what bootloader passes in MADT */ + return 1; +} + static int numachip_apic_id_registered(void) { return physid_isset(read_xapic_id(), phys_cpu_present_map); @@ -223,10 +229,11 @@ static int __init numachip_system_init(void) } early_initcall(numachip_system_init); -static int numachip_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +static int __cpuinit numachip_acpi_madt_oem_check(char *oem_id, char *oem_table_id) { if (!strncmp(oem_id, "NUMASC", 6)) { numachip_system = 1; + setup_force_cpu_cap(X86_FEATURE_X2APIC); return 1; } @@ -238,6 +245,7 @@ static struct apic apic_numachip __refconst = { .name = "NumaConnect system", .probe = numachip_probe, .acpi_madt_oem_check = numachip_acpi_madt_oem_check, + .apic_id_valid = numachip_apic_id_valid, .apic_id_registered = numachip_apic_id_registered, .irq_delivery_mode = dest_Fixed, diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index 521bead01137..0cdec7065aff 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -198,6 +198,7 @@ static struct apic apic_bigsmp = { .name = "bigsmp", .probe = probe_bigsmp, .acpi_madt_oem_check = NULL, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = bigsmp_apic_id_registered, .irq_delivery_mode = dest_Fixed, diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c index 5d513bc47b6b..e42d1d3b9134 100644 --- a/arch/x86/kernel/apic/es7000_32.c +++ b/arch/x86/kernel/apic/es7000_32.c @@ -625,6 +625,7 @@ static struct apic __refdata apic_es7000_cluster = { .name = "es7000", .probe = probe_es7000, .acpi_madt_oem_check = es7000_acpi_madt_oem_check_cluster, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = es7000_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, @@ -690,6 +691,7 @@ static struct apic __refdata apic_es7000 = { .name = "es7000", .probe = probe_es7000, .acpi_madt_oem_check = es7000_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = es7000_apic_id_registered, .irq_delivery_mode = dest_Fixed, diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index fb072754bc1d..6d10a66fc5a9 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3967,18 +3967,36 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi) static __init int bad_ioapic(unsigned long address) { if (nr_ioapics >= MAX_IO_APICS) { - printk(KERN_WARNING "WARNING: Max # of I/O APICs (%d) exceeded " - "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics); + pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n", + MAX_IO_APICS, nr_ioapics); return 1; } if (!address) { - printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address" - " found in table, skipping!\n"); + pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n"); return 1; } return 0; } +static __init int bad_ioapic_register(int idx) +{ + union IO_APIC_reg_00 reg_00; + union IO_APIC_reg_01 reg_01; + union IO_APIC_reg_02 reg_02; + + reg_00.raw = io_apic_read(idx, 0); + reg_01.raw = io_apic_read(idx, 1); + reg_02.raw = io_apic_read(idx, 2); + + if (reg_00.raw == -1 && reg_01.raw == -1 && reg_02.raw == -1) { + pr_warn("I/O APIC 0x%x registers return all ones, skipping!\n", + mpc_ioapic_addr(idx)); + return 1; + } + + return 0; +} + void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) { int idx = 0; @@ -3995,6 +4013,12 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) ioapics[idx].mp_config.apicaddr = address; set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); + + if (bad_ioapic_register(idx)) { + clear_fixmap(FIX_IO_APIC_BASE_0 + idx); + return; + } + ioapics[idx].mp_config.apicid = io_apic_unique_id(id); ioapics[idx].mp_config.apicver = io_apic_get_version(idx); @@ -4015,10 +4039,10 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) if (gsi_cfg->gsi_end >= gsi_top) gsi_top = gsi_cfg->gsi_end + 1; - printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " - "GSI %d-%d\n", idx, mpc_ioapic_id(idx), - mpc_ioapic_ver(idx), mpc_ioapic_addr(idx), - gsi_cfg->gsi_base, gsi_cfg->gsi_end); + pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n", + idx, mpc_ioapic_id(idx), + mpc_ioapic_ver(idx), mpc_ioapic_addr(idx), + gsi_cfg->gsi_base, gsi_cfg->gsi_end); nr_ioapics++; } diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c index c4a61ca1349a..00d2422ca7c9 100644 --- a/arch/x86/kernel/apic/numaq_32.c +++ b/arch/x86/kernel/apic/numaq_32.c @@ -478,6 +478,7 @@ static struct apic __refdata apic_numaq = { .name = "NUMAQ", .probe = probe_numaq, .acpi_madt_oem_check = NULL, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = numaq_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index 0787bb3412f4..ff2c1b9aac4d 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -92,6 +92,7 @@ static struct apic apic_default = { .name = "default", .probe = probe_default, .acpi_madt_oem_check = NULL, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = default_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c index 19114423c58c..fea000b27f07 100644 --- a/arch/x86/kernel/apic/summit_32.c +++ b/arch/x86/kernel/apic/summit_32.c @@ -496,6 +496,7 @@ static struct apic apic_summit = { .name = "summit", .probe = probe_summit, .acpi_madt_oem_check = summit_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = summit_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index 500795875827..9193713060a9 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -213,6 +213,7 @@ static struct apic apic_x2apic_cluster = { .name = "cluster x2apic", .probe = x2apic_cluster_probe, .acpi_madt_oem_check = x2apic_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = x2apic_apic_id_registered, .irq_delivery_mode = dest_LowestPrio, diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index f5373dfde21e..bcd1db6eaca9 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -119,6 +119,7 @@ static struct apic apic_x2apic_phys = { .name = "physical x2apic", .probe = x2apic_phys_probe, .acpi_madt_oem_check = x2apic_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = x2apic_apic_id_registered, .irq_delivery_mode = dest_Fixed, diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 79b05b88aa19..fc4771425852 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -351,6 +351,7 @@ static struct apic __refdata apic_x2apic_uv_x = { .name = "UV large system", .probe = uv_probe, .acpi_madt_oem_check = uv_acpi_madt_oem_check, + .apic_id_valid = default_apic_id_valid, .apic_id_registered = uv_apic_id_registered, .irq_delivery_mode = dest_Fixed, diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index f76623cbe263..5d56931a15b3 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -1234,8 +1234,7 @@ static int suspend(int vetoable) struct apm_user *as; dpm_suspend_start(PMSG_SUSPEND); - - dpm_suspend_noirq(PMSG_SUSPEND); + dpm_suspend_end(PMSG_SUSPEND); local_irq_disable(); syscore_suspend(); @@ -1259,9 +1258,9 @@ static int suspend(int vetoable) syscore_resume(); local_irq_enable(); - dpm_resume_noirq(PMSG_RESUME); - + dpm_resume_start(PMSG_RESUME); dpm_resume_end(PMSG_RESUME); + queue_event(APM_NORMAL_RESUME, NULL); spin_lock(&user_list_lock); for (as = user_list; as != NULL; as = as->next) { @@ -1277,7 +1276,7 @@ static void standby(void) { int err; - dpm_suspend_noirq(PMSG_SUSPEND); + dpm_suspend_end(PMSG_SUSPEND); local_irq_disable(); syscore_suspend(); @@ -1291,7 +1290,7 @@ static void standby(void) syscore_resume(); local_irq_enable(); - dpm_resume_noirq(PMSG_RESUME); + dpm_resume_start(PMSG_RESUME); } static apm_event_t get_event(void) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c0f7d68d318f..ade9c794ed98 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -28,6 +28,7 @@ #include <asm/apic.h> #include <asm/desc.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/mtrr.h> #include <linux/numa.h> #include <asm/asm.h> @@ -933,7 +934,7 @@ static const struct msr_range msr_range_array[] __cpuinitconst = { { 0xc0011000, 0xc001103b}, }; -static void __cpuinit print_cpu_msr(void) +static void __cpuinit __print_cpu_msr(void) { unsigned index_min, index_max; unsigned index; @@ -997,13 +998,13 @@ void __cpuinit print_cpu_info(struct cpuinfo_x86 *c) else printk(KERN_CONT "\n"); -#ifdef CONFIG_SMP + __print_cpu_msr(); +} + +void __cpuinit print_cpu_msr(struct cpuinfo_x86 *c) +{ if (c->cpu_index < show_msr) - print_cpu_msr(); -#else - if (show_msr) - print_cpu_msr(); -#endif + __print_cpu_msr(); } static __init int setup_disablecpuid(char *arg) @@ -1045,7 +1046,6 @@ DEFINE_PER_CPU(char *, irq_stack_ptr) = DEFINE_PER_CPU(unsigned int, irq_count) = -1; DEFINE_PER_CPU(struct task_struct *, fpu_owner_task); -EXPORT_PER_CPU_SYMBOL(fpu_owner_task); /* * Special IST stacks which the CPU switches to when it calls @@ -1115,7 +1115,6 @@ void debug_stack_reset(void) DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; EXPORT_PER_CPU_SYMBOL(current_task); DEFINE_PER_CPU(struct task_struct *, fpu_owner_task); -EXPORT_PER_CPU_SYMBOL(fpu_owner_task); #ifdef CONFIG_CC_STACKPROTECTOR DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 7395d5f4272d..0c82091b1652 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -54,7 +54,14 @@ static struct severity { #define MASK(x, y) .mask = x, .result = y #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S) #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR) +#define MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV) #define MCACOD 0xffff +/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */ +#define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */ +#define MCACOD_SCRUBMSK 0xfff0 +#define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */ +#define MCACOD_DATA 0x0134 /* Data Load */ +#define MCACOD_INSTR 0x0150 /* Instruction Fetch */ MCESEV( NO, "Invalid", @@ -102,11 +109,24 @@ static struct severity { SER, BITCLR(MCI_STATUS_S) ), - /* AR add known MCACODs here */ MCESEV( PANIC, "Action required with lost events", SER, BITSET(MCI_STATUS_OVER|MCI_UC_SAR) ), + + /* known AR MCACODs: */ +#ifdef CONFIG_MEMORY_FAILURE + MCESEV( + KEEP, "HT thread notices Action required: data load error", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA), + MCGMASK(MCG_STATUS_EIPV, 0) + ), + MCESEV( + AR, "Action required: data load error", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA), + USER + ), +#endif MCESEV( PANIC, "Action required: unknown MCACOD", SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR, MCI_UC_SAR) @@ -115,11 +135,11 @@ static struct severity { /* known AO MCACODs: */ MCESEV( AO, "Action optional: memory scrubbing error", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|0xfff0, MCI_UC_S|0x00c0) + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD_SCRUBMSK, MCI_UC_S|MCACOD_SCRUB) ), MCESEV( AO, "Action optional: last level cache writeback error", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_S|0x017a) + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCACOD, MCI_UC_S|MCACOD_L3WB) ), MCESEV( SOME, "Action optional: unknown MCACOD", diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 5a11ae2e9e91..d086a09c087d 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -191,7 +191,7 @@ static void drain_mcelog_buffer(void) { unsigned int next, i, prev = 0; - next = rcu_dereference_check_mce(mcelog.next); + next = ACCESS_ONCE(mcelog.next); do { struct mce *m; @@ -540,6 +540,27 @@ static void mce_report_event(struct pt_regs *regs) irq_work_queue(&__get_cpu_var(mce_irq_work)); } +/* + * Read ADDR and MISC registers. + */ +static void mce_read_aux(struct mce *m, int i) +{ + if (m->status & MCI_STATUS_MISCV) + m->misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); + if (m->status & MCI_STATUS_ADDRV) { + m->addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); + + /* + * Mask the reported address by the reported granularity. + */ + if (mce_ser && (m->status & MCI_STATUS_MISCV)) { + u8 shift = MCI_MISC_ADDR_LSB(m->misc); + m->addr >>= shift; + m->addr <<= shift; + } + } +} + DEFINE_PER_CPU(unsigned, mce_poll_count); /* @@ -590,10 +611,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) (m.status & (mce_ser ? MCI_STATUS_S : MCI_STATUS_UC))) continue; - if (m.status & MCI_STATUS_MISCV) - m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); - if (m.status & MCI_STATUS_ADDRV) - m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); + mce_read_aux(&m, i); if (!(flags & MCP_TIMESTAMP)) m.tsc = 0; @@ -917,6 +935,49 @@ static void mce_clear_state(unsigned long *toclear) } /* + * Need to save faulting physical address associated with a process + * in the machine check handler some place where we can grab it back + * later in mce_notify_process() + */ +#define MCE_INFO_MAX 16 + +struct mce_info { + atomic_t inuse; + struct task_struct *t; + __u64 paddr; +} mce_info[MCE_INFO_MAX]; + +static void mce_save_info(__u64 addr) +{ + struct mce_info *mi; + + for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) { + if (atomic_cmpxchg(&mi->inuse, 0, 1) == 0) { + mi->t = current; + mi->paddr = addr; + return; + } + } + + mce_panic("Too many concurrent recoverable errors", NULL, NULL); +} + +static struct mce_info *mce_find_info(void) +{ + struct mce_info *mi; + + for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) + if (atomic_read(&mi->inuse) && mi->t == current) + return mi; + return NULL; +} + +static void mce_clear_info(struct mce_info *mi) +{ + atomic_set(&mi->inuse, 0); +} + +/* * The actual machine check handler. This only handles real * exceptions when something got corrupted coming in through int 18. * @@ -969,7 +1030,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) barrier(); /* - * When no restart IP must always kill or panic. + * When no restart IP might need to kill or panic. + * Assume the worst for now, but if we find the + * severity is MCE_AR_SEVERITY we have other options. */ if (!(m.mcgstatus & MCG_STATUS_RIPV)) kill_it = 1; @@ -1023,16 +1086,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) continue; } - /* - * Kill on action required. - */ - if (severity == MCE_AR_SEVERITY) - kill_it = 1; - - if (m.status & MCI_STATUS_MISCV) - m.misc = mce_rdmsrl(MSR_IA32_MCx_MISC(i)); - if (m.status & MCI_STATUS_ADDRV) - m.addr = mce_rdmsrl(MSR_IA32_MCx_ADDR(i)); + mce_read_aux(&m, i); /* * Action optional error. Queue address for later processing. @@ -1052,6 +1106,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) } } + /* mce_clear_state will clear *final, save locally for use later */ + m = *final; + if (!no_way_out) mce_clear_state(toclear); @@ -1063,27 +1120,22 @@ void do_machine_check(struct pt_regs *regs, long error_code) no_way_out = worst >= MCE_PANIC_SEVERITY; /* - * If we have decided that we just CAN'T continue, and the user - * has not set tolerant to an insane level, give up and die. - * - * This is mainly used in the case when the system doesn't - * support MCE broadcasting or it has been disabled. - */ - if (no_way_out && tolerant < 3) - mce_panic("Fatal machine check on current CPU", final, msg); - - /* - * If the error seems to be unrecoverable, something should be - * done. Try to kill as little as possible. If we can kill just - * one task, do that. If the user has set the tolerance very - * high, don't try to do anything at all. + * At insane "tolerant" levels we take no action. Otherwise + * we only die if we have no other choice. For less serious + * issues we try to recover, or limit damage to the current + * process. */ - - if (kill_it && tolerant < 3) - force_sig(SIGBUS, current); - - /* notify userspace ASAP */ - set_thread_flag(TIF_MCE_NOTIFY); + if (tolerant < 3) { + if (no_way_out) + mce_panic("Fatal machine check on current CPU", &m, msg); + if (worst == MCE_AR_SEVERITY) { + /* schedule action before return to userland */ + mce_save_info(m.addr); + set_thread_flag(TIF_MCE_NOTIFY); + } else if (kill_it) { + force_sig(SIGBUS, current); + } + } if (worst > 0) mce_report_event(regs); @@ -1094,34 +1146,57 @@ out: } EXPORT_SYMBOL_GPL(do_machine_check); -/* dummy to break dependency. actual code is in mm/memory-failure.c */ -void __attribute__((weak)) memory_failure(unsigned long pfn, int vector) +#ifndef CONFIG_MEMORY_FAILURE +int memory_failure(unsigned long pfn, int vector, int flags) { - printk(KERN_ERR "Action optional memory failure at %lx ignored\n", pfn); + /* mce_severity() should not hand us an ACTION_REQUIRED error */ + BUG_ON(flags & MF_ACTION_REQUIRED); + printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n" + "Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn); + + return 0; } +#endif /* - * Called after mce notification in process context. This code - * is allowed to sleep. Call the high level VM handler to process - * any corrupted pages. - * Assume that the work queue code only calls this one at a time - * per CPU. - * Note we don't disable preemption, so this code might run on the wrong - * CPU. In this case the event is picked up by the scheduled work queue. - * This is merely a fast path to expedite processing in some common - * cases. + * Called in process context that interrupted by MCE and marked with + * TIF_MCE_NOTIFY, just before returning to erroneous userland. + * This code is allowed to sleep. + * Attempt possible recovery such as calling the high level VM handler to + * process any corrupted pages, and kill/signal current process if required. + * Action required errors are handled here. */ void mce_notify_process(void) { unsigned long pfn; - mce_notify_irq(); - while (mce_ring_get(&pfn)) - memory_failure(pfn, MCE_VECTOR); + struct mce_info *mi = mce_find_info(); + + if (!mi) + mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL); + pfn = mi->paddr >> PAGE_SHIFT; + + clear_thread_flag(TIF_MCE_NOTIFY); + + pr_err("Uncorrected hardware memory error in user-access at %llx", + mi->paddr); + if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0) { + pr_err("Memory error not recovered"); + force_sig(SIGBUS, current); + } + mce_clear_info(mi); } +/* + * Action optional processing happens here (picking up + * from the list of faulting pages that do_machine_check() + * placed into the "ring"). + */ static void mce_process_work(struct work_struct *dummy) { - mce_notify_process(); + unsigned long pfn; + + while (mce_ring_get(&pfn)) + memory_failure(pfn, MCE_VECTOR, 0); } #ifdef CONFIG_X86_MCE_INTEL @@ -1211,8 +1286,6 @@ int mce_notify_irq(void) /* Not more than two messages every minute */ static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); - clear_thread_flag(TIF_MCE_NOTIFY); - if (test_and_clear_bit(0, &mce_need_notify)) { /* wake processes polling /dev/mcelog */ wake_up_interruptible(&mce_chrdev_wait); @@ -1541,6 +1614,12 @@ static int __mce_read_apei(char __user **ubuf, size_t usize) /* Error or no more MCE record */ if (rc <= 0) { mce_apei_read_done = 1; + /* + * When ERST is disabled, mce_chrdev_read() should return + * "no record" instead of "no device." + */ + if (rc == -ENODEV) + return 0; return rc; } rc = -EFAULT; @@ -1859,7 +1938,7 @@ static struct bus_type mce_subsys = { .dev_name = "machinecheck", }; -struct device *mce_device[CONFIG_NR_CPUS]; +DEFINE_PER_CPU(struct device *, mce_device); __cpuinitdata void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); @@ -2038,7 +2117,7 @@ static __cpuinit int mce_device_create(unsigned int cpu) goto error2; } cpumask_set_cpu(cpu, mce_device_initialized); - mce_device[cpu] = dev; + per_cpu(mce_device, cpu) = dev; return 0; error2: @@ -2055,7 +2134,7 @@ error: static __cpuinit void mce_device_remove(unsigned int cpu) { - struct device *dev = mce_device[cpu]; + struct device *dev = per_cpu(mce_device, cpu); int i; if (!cpumask_test_cpu(cpu, mce_device_initialized)) @@ -2069,7 +2148,7 @@ static __cpuinit void mce_device_remove(unsigned int cpu) device_unregister(dev); cpumask_clear_cpu(cpu, mce_device_initialized); - mce_device[cpu] = NULL; + per_cpu(mce_device, cpu) = NULL; } /* Make sure there are no machine checks on offlined CPUs. */ diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index e4eeaaf58a47..99b57179f912 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -523,7 +523,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) { int i, err = 0; struct threshold_bank *b = NULL; - struct device *dev = mce_device[cpu]; + struct device *dev = per_cpu(mce_device, cpu); char name[32]; sprintf(name, "threshold_bank%i", bank); @@ -587,7 +587,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (i == cpu) continue; - dev = mce_device[i]; + dev = per_cpu(mce_device, i); if (dev) err = sysfs_create_link(&dev->kobj,b->kobj, name); if (err) @@ -667,7 +667,8 @@ static void threshold_remove_bank(unsigned int cpu, int bank) #ifdef CONFIG_SMP /* sibling symlink */ if (shared_bank[bank] && b->blocks->cpu != cpu) { - sysfs_remove_link(&mce_device[cpu]->kobj, name); + dev = per_cpu(mce_device, cpu); + sysfs_remove_link(&dev->kobj, name); per_cpu(threshold_banks, cpu)[bank] = NULL; return; @@ -679,7 +680,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) if (i == cpu) continue; - dev = mce_device[i]; + dev = per_cpu(mce_device, i); if (dev) sysfs_remove_link(&dev->kobj, name); per_cpu(threshold_banks, i)[bank] = NULL; diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c index 642f75a68cd5..11891ca7b716 100644 --- a/arch/x86/kernel/crash_dump_32.c +++ b/arch/x86/kernel/crash_dump_32.c @@ -62,16 +62,16 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, if (!userbuf) { memcpy(buf, (vaddr + offset), csize); - kunmap_atomic(vaddr, KM_PTE0); + kunmap_atomic(vaddr); } else { if (!kdump_buf_page) { printk(KERN_WARNING "Kdump: Kdump buffer page not" " allocated\n"); - kunmap_atomic(vaddr, KM_PTE0); + kunmap_atomic(vaddr); return -EFAULT; } copy_page(kdump_buf_page, vaddr); - kunmap_atomic(vaddr, KM_PTE0); + kunmap_atomic(vaddr); if (copy_to_user(buf, (kdump_buf_page + offset), csize)) return -EFAULT; } diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 52821799a702..3ae2ced4a874 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -4,6 +4,7 @@ #include <linux/bootmem.h> #include <linux/export.h> #include <linux/io.h> +#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/list.h> #include <linux/of.h> @@ -17,64 +18,14 @@ #include <linux/initrd.h> #include <asm/hpet.h> -#include <asm/irq_controller.h> #include <asm/apic.h> #include <asm/pci_x86.h> __initdata u64 initial_dtb; char __initdata cmd_line[COMMAND_LINE_SIZE]; -static LIST_HEAD(irq_domains); -static DEFINE_RAW_SPINLOCK(big_irq_lock); int __initdata of_ioapic; -#ifdef CONFIG_X86_IO_APIC -static void add_interrupt_host(struct irq_domain *ih) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&big_irq_lock, flags); - list_add(&ih->l, &irq_domains); - raw_spin_unlock_irqrestore(&big_irq_lock, flags); -} -#endif - -static struct irq_domain *get_ih_from_node(struct device_node *controller) -{ - struct irq_domain *ih, *found = NULL; - unsigned long flags; - - raw_spin_lock_irqsave(&big_irq_lock, flags); - list_for_each_entry(ih, &irq_domains, l) { - if (ih->controller == controller) { - found = ih; - break; - } - } - raw_spin_unlock_irqrestore(&big_irq_lock, flags); - return found; -} - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_domain *ih; - u32 virq, type; - int ret; - - ih = get_ih_from_node(controller); - if (!ih) - return 0; - ret = ih->xlate(ih, intspec, intsize, &virq, &type); - if (ret) - return 0; - if (type == IRQ_TYPE_NONE) - return virq; - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - unsigned long pci_address_to_pio(phys_addr_t address) { /* @@ -354,36 +305,43 @@ static struct of_ioapic_type of_ioapic_type[] = }, }; -static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, - u32 *out_hwirq, u32 *out_type) +static int ioapic_xlate(struct irq_domain *domain, + struct device_node *controller, + const u32 *intspec, u32 intsize, + irq_hw_number_t *out_hwirq, u32 *out_type) { - struct mp_ioapic_gsi *gsi_cfg; struct io_apic_irq_attr attr; struct of_ioapic_type *it; - u32 line, idx, type; + u32 line, idx; + int rc; - if (intsize < 2) + if (WARN_ON(intsize < 2)) return -EINVAL; - line = *intspec; - idx = (u32) id->priv; - gsi_cfg = mp_ioapic_gsi_routing(idx); - *out_hwirq = line + gsi_cfg->gsi_base; - - intspec++; - type = *intspec; + line = intspec[0]; - if (type >= ARRAY_SIZE(of_ioapic_type)) + if (intspec[1] >= ARRAY_SIZE(of_ioapic_type)) return -EINVAL; - it = of_ioapic_type + type; - *out_type = it->out_type; + it = &of_ioapic_type[intspec[1]]; + idx = (u32) domain->host_data; set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); - return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr); + rc = io_apic_setup_irq_pin_once(irq_find_mapping(domain, line), + cpu_to_node(0), &attr); + if (rc) + return rc; + + *out_hwirq = line; + *out_type = it->out_type; + return 0; } +const struct irq_domain_ops ioapic_irq_domain_ops = { + .xlate = ioapic_xlate, +}; + static void __init ioapic_add_ofnode(struct device_node *np) { struct resource r; @@ -399,13 +357,14 @@ static void __init ioapic_add_ofnode(struct device_node *np) for (i = 0; i < nr_ioapics; i++) { if (r.start == mpc_ioapic_addr(i)) { struct irq_domain *id; + struct mp_ioapic_gsi *gsi_cfg; + + gsi_cfg = mp_ioapic_gsi_routing(i); - id = kzalloc(sizeof(*id), GFP_KERNEL); + id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0, + &ioapic_irq_domain_ops, + (void*)i); BUG_ON(!id); - id->controller = np; - id->xlate = ioapic_xlate; - id->priv = (void *)i; - add_interrupt_host(id); return; } } diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index c99f9ed013d5..88ec9129271d 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -87,7 +87,7 @@ void show_registers(struct pt_regs *regs) int i; print_modules(); - __show_regs(regs, 0); + __show_regs(regs, !user_mode_vm(regs)); printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n", TASK_COMM_LEN, current->comm, task_pid_nr(current), diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 1333d9851778..734ebd1d3caa 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -320,7 +320,7 @@ ENDPROC(native_usergs_sysret64) movq %rsp, %rsi leaq -RBP(%rsp),%rdi /* arg1 for handler */ - testl $3, CS(%rdi) + testl $3, CS-RBP(%rsi) je 1f SWAPGS /* @@ -330,11 +330,10 @@ ENDPROC(native_usergs_sysret64) * moving irq_enter into assembly, which would be too much work) */ 1: incl PER_CPU_VAR(irq_count) - jne 2f - mov PER_CPU_VAR(irq_stack_ptr),%rsp + cmovzq PER_CPU_VAR(irq_stack_ptr),%rsp CFI_DEF_CFA_REGISTER rsi -2: /* Store previous stack value */ + /* Store previous stack value */ pushq %rsi CFI_ESCAPE 0x0f /* DW_CFA_def_cfa_expression */, 6, \ 0x77 /* DW_OP_breg7 */, 0, \ @@ -813,7 +812,7 @@ ret_from_intr: /* Restore saved previous stack */ popq %rsi - CFI_DEF_CFA_REGISTER rsi + CFI_DEF_CFA rsi,SS+8-RBP /* reg/off reset after def_cfa_expr */ leaq ARGOFFSET-RBP(%rsi), %rsp CFI_DEF_CFA_REGISTER rsp CFI_ADJUST_CFA_OFFSET RBP-ARGOFFSET @@ -1530,6 +1529,7 @@ ENTRY(nmi) /* Use %rdx as out temp variable throughout */ pushq_cfi %rdx + CFI_REL_OFFSET rdx, 0 /* * If %cs was not the kernel segment, then the NMI triggered in user @@ -1554,6 +1554,7 @@ ENTRY(nmi) */ lea 6*8(%rsp), %rdx test_in_nmi rdx, 4*8(%rsp), nested_nmi, first_nmi + CFI_REMEMBER_STATE nested_nmi: /* @@ -1585,10 +1586,12 @@ nested_nmi: nested_nmi_out: popq_cfi %rdx + CFI_RESTORE rdx /* No need to check faults here */ INTERRUPT_RETURN + CFI_RESTORE_STATE first_nmi: /* * Because nested NMIs will use the pushed location that we @@ -1620,10 +1623,15 @@ first_nmi: * | pt_regs | * +-------------------------+ * - * The saved RIP is used to fix up the copied RIP that a nested - * NMI may zero out. The original stack frame and the temp storage + * The saved stack frame is used to fix up the copied stack frame + * that a nested NMI may change to make the interrupted NMI iret jump + * to the repeat_nmi. The original stack frame and the temp storage * is also used by nested NMIs and can not be trusted on exit. */ + /* Do not pop rdx, nested NMIs will corrupt that part of the stack */ + movq (%rsp), %rdx + CFI_RESTORE rdx + /* Set the NMI executing variable on the stack. */ pushq_cfi $1 @@ -1631,22 +1639,39 @@ first_nmi: .rept 5 pushq_cfi 6*8(%rsp) .endr + CFI_DEF_CFA_OFFSET SS+8-RIP + + /* Everything up to here is safe from nested NMIs */ + + /* + * If there was a nested NMI, the first NMI's iret will return + * here. But NMIs are still enabled and we can take another + * nested NMI. The nested NMI checks the interrupted RIP to see + * if it is between repeat_nmi and end_repeat_nmi, and if so + * it will just return, as we are about to repeat an NMI anyway. + * This makes it safe to copy to the stack frame that a nested + * NMI will update. + */ +repeat_nmi: + /* + * Update the stack variable to say we are still in NMI (the update + * is benign for the non-repeat case, where 1 was pushed just above + * to this very stack slot). + */ + movq $1, 5*8(%rsp) /* Make another copy, this one may be modified by nested NMIs */ .rept 5 pushq_cfi 4*8(%rsp) .endr - - /* Do not pop rdx, nested NMIs will corrupt it */ - movq 11*8(%rsp), %rdx + CFI_DEF_CFA_OFFSET SS+8-RIP +end_repeat_nmi: /* * Everything below this point can be preempted by a nested - * NMI if the first NMI took an exception. Repeated NMIs - * caused by an exception and nested NMI will start here, and - * can still be preempted by another NMI. + * NMI if the first NMI took an exception and reset our iret stack + * so that we repeat another NMI. */ -restart_nmi: pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 @@ -1675,26 +1700,6 @@ nmi_restore: CFI_ENDPROC END(nmi) - /* - * If an NMI hit an iret because of an exception or breakpoint, - * it can lose its NMI context, and a nested NMI may come in. - * In that case, the nested NMI will change the preempted NMI's - * stack to jump to here when it does the final iret. - */ -repeat_nmi: - INTR_FRAME - /* Update the stack variable to say we are still in NMI */ - movq $1, 5*8(%rsp) - - /* copy the saved stack back to copy stack */ - .rept 5 - pushq_cfi 4*8(%rsp) - .endr - - jmp restart_nmi - CFI_ENDPROC -end_repeat_nmi: - ENTRY(ignore_sysret) CFI_STARTPROC mov $-ENOSYS,%eax diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 739d8598f789..7734bcbb5a3a 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -16,6 +16,7 @@ #include <asm/uaccess.h> #include <asm/ptrace.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/user.h> #ifdef CONFIG_X86_64 @@ -32,6 +33,86 @@ # define user32_fxsr_struct user_fxsr_struct #endif +/* + * Were we in an interrupt that interrupted kernel mode? + * + * We can do a kernel_fpu_begin/end() pair *ONLY* if that + * pair does nothing at all: the thread must not have fpu (so + * that we don't try to save the FPU state), and TS must + * be set (so that the clts/stts pair does nothing that is + * visible in the interrupted kernel thread). + */ +static inline bool interrupted_kernel_fpu_idle(void) +{ + return !__thread_has_fpu(current) && + (read_cr0() & X86_CR0_TS); +} + +/* + * Were we in user mode (or vm86 mode) when we were + * interrupted? + * + * Doing kernel_fpu_begin/end() is ok if we are running + * in an interrupt context from user mode - we'll just + * save the FPU state as required. + */ +static inline bool interrupted_user_mode(void) +{ + struct pt_regs *regs = get_irq_regs(); + return regs && user_mode_vm(regs); +} + +/* + * Can we use the FPU in kernel mode with the + * whole "kernel_fpu_begin/end()" sequence? + * + * It's always ok in process context (ie "not interrupt") + * but it is sometimes ok even from an irq. + */ +bool irq_fpu_usable(void) +{ + return !in_interrupt() || + interrupted_user_mode() || + interrupted_kernel_fpu_idle(); +} +EXPORT_SYMBOL(irq_fpu_usable); + +void kernel_fpu_begin(void) +{ + struct task_struct *me = current; + + WARN_ON_ONCE(!irq_fpu_usable()); + preempt_disable(); + if (__thread_has_fpu(me)) { + __save_init_fpu(me); + __thread_clear_has_fpu(me); + /* We do 'stts()' in kernel_fpu_end() */ + } else { + percpu_write(fpu_owner_task, NULL); + clts(); + } +} +EXPORT_SYMBOL(kernel_fpu_begin); + +void kernel_fpu_end(void) +{ + stts(); + preempt_enable(); +} +EXPORT_SYMBOL(kernel_fpu_end); + +void unlazy_fpu(struct task_struct *tsk) +{ + preempt_disable(); + if (__thread_has_fpu(tsk)) { + __save_init_fpu(tsk); + __thread_fpu_end(tsk); + } else + tsk->fpu_counter = 0; + preempt_enable(); +} +EXPORT_SYMBOL(unlazy_fpu); + #ifdef CONFIG_MATH_EMULATION # define HAVE_HWFP (boot_cpu_data.hard_math) #else @@ -44,7 +125,7 @@ EXPORT_SYMBOL_GPL(xstate_size); unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); static struct i387_fxsave_struct fx_scratch __cpuinitdata; -void __cpuinit mxcsr_feature_mask_init(void) +static void __cpuinit mxcsr_feature_mask_init(void) { unsigned long mask = 0; diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c index 0d01a8ea4e11..2c39dcd510fa 100644 --- a/arch/x86/kernel/nmi_selftest.c +++ b/arch/x86/kernel/nmi_selftest.c @@ -12,6 +12,7 @@ #include <linux/smp.h> #include <linux/cpumask.h> #include <linux/delay.h> +#include <linux/init.h> #include <asm/apic.h> #include <asm/nmi.h> @@ -20,35 +21,35 @@ #define FAILURE 1 #define TIMEOUT 2 -static int nmi_fail; +static int __initdata nmi_fail; /* check to see if NMI IPIs work on this machine */ -static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly; +static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __initdata; -static int testcase_total; -static int testcase_successes; -static int expected_testcase_failures; -static int unexpected_testcase_failures; -static int unexpected_testcase_unknowns; +static int __initdata testcase_total; +static int __initdata testcase_successes; +static int __initdata expected_testcase_failures; +static int __initdata unexpected_testcase_failures; +static int __initdata unexpected_testcase_unknowns; -static int nmi_unk_cb(unsigned int val, struct pt_regs *regs) +static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs) { unexpected_testcase_unknowns++; return NMI_HANDLED; } -static void init_nmi_testsuite(void) +static void __init init_nmi_testsuite(void) { /* trap all the unknown NMIs we may generate */ register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk"); } -static void cleanup_nmi_testsuite(void) +static void __init cleanup_nmi_testsuite(void) { unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk"); } -static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs) +static int __init test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs) { int cpu = raw_smp_processor_id(); @@ -58,7 +59,7 @@ static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs) return NMI_DONE; } -static void test_nmi_ipi(struct cpumask *mask) +static void __init test_nmi_ipi(struct cpumask *mask) { unsigned long timeout; @@ -86,7 +87,7 @@ static void test_nmi_ipi(struct cpumask *mask) return; } -static void remote_ipi(void) +static void __init remote_ipi(void) { cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask); cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); @@ -94,19 +95,19 @@ static void remote_ipi(void) test_nmi_ipi(to_cpumask(nmi_ipi_mask)); } -static void local_ipi(void) +static void __init local_ipi(void) { cpumask_clear(to_cpumask(nmi_ipi_mask)); cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); test_nmi_ipi(to_cpumask(nmi_ipi_mask)); } -static void reset_nmi(void) +static void __init reset_nmi(void) { nmi_fail = 0; } -static void dotest(void (*testcase_fn)(void), int expected) +static void __init dotest(void (*testcase_fn)(void), int expected) { testcase_fn(); /* @@ -131,12 +132,12 @@ static void dotest(void (*testcase_fn)(void), int expected) reset_nmi(); } -static inline void print_testname(const char *testname) +static inline void __init print_testname(const char *testname) { printk("%12s:", testname); } -void nmi_selftest(void) +void __init nmi_selftest(void) { init_nmi_testsuite(); diff --git a/arch/x86/kernel/probe_roms.c b/arch/x86/kernel/probe_roms.c index 34e06e84ce31..0bc72e2069e3 100644 --- a/arch/x86/kernel/probe_roms.c +++ b/arch/x86/kernel/probe_roms.c @@ -12,6 +12,7 @@ #include <linux/pci.h> #include <linux/export.h> +#include <asm/probe_roms.h> #include <asm/pci-direct.h> #include <asm/e820.h> #include <asm/mmzone.h> diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 44eefde92109..14baf78d5a1f 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -21,6 +21,7 @@ #include <asm/idle.h> #include <asm/uaccess.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/debugreg.h> struct kmem_cache *task_xstate_cachep; diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 49888fefe794..9d7d4842bfaf 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -45,6 +45,7 @@ #include <asm/ldt.h> #include <asm/processor.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/desc.h> #ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index e34257c70c28..292da13fc5aa 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -43,6 +43,7 @@ #include <asm/system.h> #include <asm/processor.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/mmu_context.h> #include <asm/prctl.h> #include <asm/desc.h> @@ -340,6 +341,7 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip, loadsegment(es, _ds); loadsegment(ds, _ds); load_gs_index(0); + current->thread.usersp = new_sp; regs->ip = new_ip; regs->sp = new_sp; percpu_write(old_rsp, new_sp); diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 50267386b766..78f05e438be5 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -27,6 +27,7 @@ #include <asm/system.h> #include <asm/processor.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/debugreg.h> #include <asm/ldt.h> #include <asm/desc.h> diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d7d5099fe874..88638883176a 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -749,10 +749,16 @@ void __init setup_arch(char **cmdline_p) #endif #ifdef CONFIG_EFI if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, - EFI_LOADER_SIGNATURE, 4)) { + "EL32", 4)) { efi_enabled = 1; - efi_memblock_x86_reserve_range(); + efi_64bit = false; + } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, + "EL64", 4)) { + efi_enabled = 1; + efi_64bit = true; } + if (efi_enabled && efi_memblock_x86_reserve_range()) + efi_enabled = 0; #endif x86_init.oem.arch_setup(); diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 46a01bdc27e2..25edcfc9ba5b 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -24,6 +24,7 @@ #include <asm/processor.h> #include <asm/ucontext.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/vdso.h> #include <asm/mce.h> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 58f78165d308..e578a79a3093 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -727,8 +727,6 @@ do_rest: * the targeted processor. */ - printk(KERN_DEBUG "smpboot cpu %d: start_ip = %lx\n", cpu, start_ip); - atomic_set(&init_deasserted, 0); if (get_uv_system_type() != UV_NON_UNIQUE_APIC) { @@ -778,9 +776,10 @@ do_rest: schedule(); } - if (cpumask_test_cpu(cpu, cpu_callin_mask)) + if (cpumask_test_cpu(cpu, cpu_callin_mask)) { + print_cpu_msr(&cpu_data(cpu)); pr_debug("CPU%d: has booted.\n", cpu); - else { + } else { boot_error = 1; if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) == 0xA5A5A5A5) @@ -834,7 +833,7 @@ int __cpuinit native_cpu_up(unsigned int cpu) if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid || !physid_isset(apicid, phys_cpu_present_map) || - (!x2apic_mode && apicid >= 255)) { + !apic->apic_id_valid(apicid)) { printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu); return -EINVAL; } diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 051489082d59..ef59642ff1bf 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -195,7 +195,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, { struct vm_area_struct *vma; struct mm_struct *mm = current->mm; - unsigned long addr = addr0; + unsigned long addr = addr0, start_addr; /* requested length too big for entire address space */ if (len > TASK_SIZE) @@ -223,25 +223,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, mm->free_area_cache = mm->mmap_base; } +try_again: /* either no address requested or can't fit in requested address hole */ - addr = mm->free_area_cache; - - /* make sure it can fit in the remaining address space */ - if (addr > len) { - unsigned long tmp_addr = align_addr(addr - len, filp, - ALIGN_TOPDOWN); - - vma = find_vma(mm, tmp_addr); - if (!vma || tmp_addr + len <= vma->vm_start) - /* remember the address as a hint for next time */ - return mm->free_area_cache = tmp_addr; - } - - if (mm->mmap_base < len) - goto bottomup; + start_addr = addr = mm->free_area_cache; - addr = mm->mmap_base-len; + if (addr < len) + goto fail; + addr -= len; do { addr = align_addr(addr, filp, ALIGN_TOPDOWN); @@ -263,6 +252,17 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = vma->vm_start-len; } while (len < vma->vm_start); +fail: + /* + * if hint left us with no space for the requested + * mapping then try again: + */ + if (start_addr != mm->mmap_base) { + mm->free_area_cache = mm->mmap_base; + mm->cached_hole_size = 0; + goto try_again; + } + bottomup: /* * A failed mmap() very likely causes application failure, diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 4bbe04d96744..ec61d4c1b93b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -54,6 +54,7 @@ #include <asm/traps.h> #include <asm/desc.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #include <asm/mce.h> #include <asm/mach_traps.h> diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index b466cab5ba15..328cb37bb827 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -172,6 +172,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) spinlock_t *ptl; int i; + down_write(&mm->mmap_sem); pgd = pgd_offset(mm, 0xA0000); if (pgd_none_or_clear_bad(pgd)) goto out; @@ -190,6 +191,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) } pte_unmap_unlock(pte, ptl); out: + up_write(&mm->mmap_sem); flush_tlb(); } diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index 711091114119..e62728e30b01 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -6,6 +6,7 @@ #include <linux/bootmem.h> #include <linux/compat.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> #ifdef CONFIG_IA32_EMULATION #include <asm/sigcontext32.h> #endif diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index cfdc6e0ef002..31bfc6927bc0 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1283,9 +1283,9 @@ void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr) return; - vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); + vapic = kmap_atomic(vcpu->arch.apic->vapic_page); data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)); - kunmap_atomic(vapic, KM_USER0); + kunmap_atomic(vapic); apic_set_tpr(vcpu->arch.apic, data & 0xff); } @@ -1310,9 +1310,9 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) max_isr = 0; data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); - vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); + vapic = kmap_atomic(vcpu->arch.apic->vapic_page); *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data; - kunmap_atomic(vapic, KM_USER0); + kunmap_atomic(vapic); } void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 15610285ebb6..df5a70311be8 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -92,9 +92,9 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, if (unlikely(npages != 1)) return -EFAULT; - table = kmap_atomic(page, KM_USER0); + table = kmap_atomic(page); ret = CMPXCHG(&table[index], orig_pte, new_pte); - kunmap_atomic(table, KM_USER0); + kunmap_atomic(table); kvm_release_page_dirty(page); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 3b4c8d8ad906..246490f643b6 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1457,7 +1457,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) #ifdef CONFIG_X86_64 wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); #endif - if (__thread_has_fpu(current)) + if (user_has_fpu()) clts(); load_gdt(&__get_cpu_var(host_gdt)); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9cbfc0698118..54696b5f8443 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -57,6 +57,7 @@ #include <asm/mtrr.h> #include <asm/mce.h> #include <asm/i387.h> +#include <asm/fpu-internal.h> /* Ugh! */ #include <asm/xcr.h> #include <asm/pvclock.h> #include <asm/div64.h> @@ -1162,12 +1163,12 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) */ vcpu->hv_clock.version += 2; - shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0); + shared_kaddr = kmap_atomic(vcpu->time_page); memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock, sizeof(vcpu->hv_clock)); - kunmap_atomic(shared_kaddr, KM_USER0); + kunmap_atomic(shared_kaddr); mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); return 0; @@ -3848,7 +3849,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, goto emul_write; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); kaddr += offset_in_page(gpa); switch (bytes) { case 1: @@ -3866,7 +3867,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, default: BUG(); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); kvm_release_page_dirty(page); if (!exchanged) diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c index 042f6826bf57..a0b4a350daa7 100644 --- a/arch/x86/lib/atomic64_32.c +++ b/arch/x86/lib/atomic64_32.c @@ -1,59 +1,4 @@ -#include <linux/compiler.h> -#include <linux/module.h> -#include <linux/types.h> +#define ATOMIC64_EXPORT EXPORT_SYMBOL -#include <asm/processor.h> -#include <asm/cmpxchg.h> +#include <linux/export.h> #include <linux/atomic.h> - -long long atomic64_read_cx8(long long, const atomic64_t *v); -EXPORT_SYMBOL(atomic64_read_cx8); -long long atomic64_set_cx8(long long, const atomic64_t *v); -EXPORT_SYMBOL(atomic64_set_cx8); -long long atomic64_xchg_cx8(long long, unsigned high); -EXPORT_SYMBOL(atomic64_xchg_cx8); -long long atomic64_add_return_cx8(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_add_return_cx8); -long long atomic64_sub_return_cx8(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_sub_return_cx8); -long long atomic64_inc_return_cx8(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_inc_return_cx8); -long long atomic64_dec_return_cx8(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_dec_return_cx8); -long long atomic64_dec_if_positive_cx8(atomic64_t *v); -EXPORT_SYMBOL(atomic64_dec_if_positive_cx8); -int atomic64_inc_not_zero_cx8(atomic64_t *v); -EXPORT_SYMBOL(atomic64_inc_not_zero_cx8); -int atomic64_add_unless_cx8(atomic64_t *v, long long a, long long u); -EXPORT_SYMBOL(atomic64_add_unless_cx8); - -#ifndef CONFIG_X86_CMPXCHG64 -long long atomic64_read_386(long long, const atomic64_t *v); -EXPORT_SYMBOL(atomic64_read_386); -long long atomic64_set_386(long long, const atomic64_t *v); -EXPORT_SYMBOL(atomic64_set_386); -long long atomic64_xchg_386(long long, unsigned high); -EXPORT_SYMBOL(atomic64_xchg_386); -long long atomic64_add_return_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_add_return_386); -long long atomic64_sub_return_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_sub_return_386); -long long atomic64_inc_return_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_inc_return_386); -long long atomic64_dec_return_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_dec_return_386); -long long atomic64_add_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_add_386); -long long atomic64_sub_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_sub_386); -long long atomic64_inc_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_inc_386); -long long atomic64_dec_386(long long a, atomic64_t *v); -EXPORT_SYMBOL(atomic64_dec_386); -long long atomic64_dec_if_positive_386(atomic64_t *v); -EXPORT_SYMBOL(atomic64_dec_if_positive_386); -int atomic64_inc_not_zero_386(atomic64_t *v); -EXPORT_SYMBOL(atomic64_inc_not_zero_386); -int atomic64_add_unless_386(atomic64_t *v, long long a, long long u); -EXPORT_SYMBOL(atomic64_add_unless_386); -#endif diff --git a/arch/x86/lib/atomic64_386_32.S b/arch/x86/lib/atomic64_386_32.S index e8e7e0d06f42..00933d5e992f 100644 --- a/arch/x86/lib/atomic64_386_32.S +++ b/arch/x86/lib/atomic64_386_32.S @@ -137,13 +137,13 @@ BEGIN(dec_return) RET_ENDP #undef v -#define v %ecx +#define v %esi BEGIN(add_unless) - addl %eax, %esi + addl %eax, %ecx adcl %edx, %edi addl (v), %eax adcl 4(v), %edx - cmpl %eax, %esi + cmpl %eax, %ecx je 3f 1: movl %eax, (v) diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S index 391a083674b4..f5cc9eb1d51b 100644 --- a/arch/x86/lib/atomic64_cx8_32.S +++ b/arch/x86/lib/atomic64_cx8_32.S @@ -55,8 +55,6 @@ ENDPROC(atomic64_set_cx8) ENTRY(atomic64_xchg_cx8) CFI_STARTPROC - movl %ebx, %eax - movl %ecx, %edx 1: LOCK_PREFIX cmpxchg8b (%esi) @@ -78,7 +76,7 @@ ENTRY(atomic64_\func\()_return_cx8) movl %edx, %edi movl %ecx, %ebp - read64 %ebp + read64 %ecx 1: movl %eax, %ebx movl %edx, %ecx @@ -159,23 +157,22 @@ ENTRY(atomic64_add_unless_cx8) SAVE ebx /* these just push these two parameters on the stack */ SAVE edi - SAVE esi + SAVE ecx - movl %ecx, %ebp - movl %eax, %esi + movl %eax, %ebp movl %edx, %edi - read64 %ebp + read64 %esi 1: cmpl %eax, 0(%esp) je 4f 2: movl %eax, %ebx movl %edx, %ecx - addl %esi, %ebx + addl %ebp, %ebx adcl %edi, %ecx LOCK_PREFIX - cmpxchg8b (%ebp) + cmpxchg8b (%esi) jne 1b movl $1, %eax @@ -199,13 +196,13 @@ ENTRY(atomic64_inc_not_zero_cx8) read64 %esi 1: - testl %eax, %eax - je 4f -2: + movl %eax, %ecx + orl %edx, %ecx + jz 3f movl %eax, %ebx - movl %edx, %ecx + xorl %ecx, %ecx addl $1, %ebx - adcl $0, %ecx + adcl %edx, %ecx LOCK_PREFIX cmpxchg8b (%esi) jne 1b @@ -214,9 +211,5 @@ ENTRY(atomic64_inc_not_zero_cx8) 3: RESTORE ebx ret -4: - testl %edx, %edx - jne 2b - jmp 3b CFI_ENDPROC ENDPROC(atomic64_inc_not_zero_cx8) diff --git a/arch/x86/lib/copy_page_64.S b/arch/x86/lib/copy_page_64.S index 01c805ba5359..6b34d04d096a 100644 --- a/arch/x86/lib/copy_page_64.S +++ b/arch/x86/lib/copy_page_64.S @@ -20,14 +20,12 @@ ENDPROC(copy_page_c) ENTRY(copy_page) CFI_STARTPROC - subq $3*8,%rsp - CFI_ADJUST_CFA_OFFSET 3*8 + subq $2*8,%rsp + CFI_ADJUST_CFA_OFFSET 2*8 movq %rbx,(%rsp) CFI_REL_OFFSET rbx, 0 movq %r12,1*8(%rsp) CFI_REL_OFFSET r12, 1*8 - movq %r13,2*8(%rsp) - CFI_REL_OFFSET r13, 2*8 movl $(4096/64)-5,%ecx .p2align 4 @@ -91,10 +89,8 @@ ENTRY(copy_page) CFI_RESTORE rbx movq 1*8(%rsp),%r12 CFI_RESTORE r12 - movq 2*8(%rsp),%r13 - CFI_RESTORE r13 - addq $3*8,%rsp - CFI_ADJUST_CFA_OFFSET -3*8 + addq $2*8,%rsp + CFI_ADJUST_CFA_OFFSET -2*8 ret .Lcopy_page_end: CFI_ENDPROC diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index efbf2a0ecdea..1c273be7c97e 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -27,9 +27,8 @@ .section .altinstr_replacement, "ax", @progbits .Lmemcpy_c: movq %rdi, %rax - - movl %edx, %ecx - shrl $3, %ecx + movq %rdx, %rcx + shrq $3, %rcx andl $7, %edx rep movsq movl %edx, %ecx @@ -48,8 +47,7 @@ .section .altinstr_replacement, "ax", @progbits .Lmemcpy_c_e: movq %rdi, %rax - - movl %edx, %ecx + movq %rdx, %rcx rep movsb ret .Lmemcpy_e_e: @@ -60,10 +58,7 @@ ENTRY(memcpy) CFI_STARTPROC movq %rdi, %rax - /* - * Use 32bit CMP here to avoid long NOP padding. - */ - cmp $0x20, %edx + cmpq $0x20, %rdx jb .Lhandle_tail /* @@ -72,7 +67,7 @@ ENTRY(memcpy) */ cmp %dil, %sil jl .Lcopy_backward - subl $0x20, %edx + subq $0x20, %rdx .Lcopy_forward_loop: subq $0x20, %rdx @@ -91,7 +86,7 @@ ENTRY(memcpy) movq %r11, 3*8(%rdi) leaq 4*8(%rdi), %rdi jae .Lcopy_forward_loop - addq $0x20, %rdx + addl $0x20, %edx jmp .Lhandle_tail .Lcopy_backward: @@ -123,11 +118,11 @@ ENTRY(memcpy) /* * Calculate copy position to head. */ - addq $0x20, %rdx + addl $0x20, %edx subq %rdx, %rsi subq %rdx, %rdi .Lhandle_tail: - cmpq $16, %rdx + cmpl $16, %edx jb .Lless_16bytes /* @@ -144,7 +139,7 @@ ENTRY(memcpy) retq .p2align 4 .Lless_16bytes: - cmpq $8, %rdx + cmpl $8, %edx jb .Lless_8bytes /* * Move data from 8 bytes to 15 bytes. @@ -156,7 +151,7 @@ ENTRY(memcpy) retq .p2align 4 .Lless_8bytes: - cmpq $4, %rdx + cmpl $4, %edx jb .Lless_3bytes /* @@ -169,18 +164,19 @@ ENTRY(memcpy) retq .p2align 4 .Lless_3bytes: - cmpl $0, %edx - je .Lend + subl $1, %edx + jb .Lend /* * Move data from 1 bytes to 3 bytes. */ -.Lloop_1: - movb (%rsi), %r8b - movb %r8b, (%rdi) - incq %rdi - incq %rsi - decl %edx - jnz .Lloop_1 + movzbl (%rsi), %ecx + jz .Lstore_1byte + movzbq 1(%rsi), %r8 + movzbq (%rsi, %rdx), %r9 + movb %r8b, 1(%rdi) + movb %r9b, (%rdi, %rdx) +.Lstore_1byte: + movb %cl, (%rdi) .Lend: retq diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 79bd454b78a3..2dcb3808cbda 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -19,16 +19,15 @@ .section .altinstr_replacement, "ax", @progbits .Lmemset_c: movq %rdi,%r9 - movl %edx,%r8d - andl $7,%r8d - movl %edx,%ecx - shrl $3,%ecx + movq %rdx,%rcx + andl $7,%edx + shrq $3,%rcx /* expand byte value */ movzbl %sil,%esi movabs $0x0101010101010101,%rax - mulq %rsi /* with rax, clobbers rdx */ + imulq %rsi,%rax rep stosq - movl %r8d,%ecx + movl %edx,%ecx rep stosb movq %r9,%rax ret @@ -50,7 +49,7 @@ .Lmemset_c_e: movq %rdi,%r9 movb %sil,%al - movl %edx,%ecx + movq %rdx,%rcx rep stosb movq %r9,%rax ret @@ -61,12 +60,11 @@ ENTRY(memset) ENTRY(__memset) CFI_STARTPROC movq %rdi,%r10 - movq %rdx,%r11 /* expand byte value */ movzbl %sil,%ecx movabs $0x0101010101010101,%rax - mul %rcx /* with rax, clobbers rdx */ + imulq %rcx,%rax /* align dst */ movl %edi,%r9d @@ -75,13 +73,13 @@ ENTRY(__memset) CFI_REMEMBER_STATE .Lafter_bad_alignment: - movl %r11d,%ecx - shrl $6,%ecx + movq %rdx,%rcx + shrq $6,%rcx jz .Lhandle_tail .p2align 4 .Lloop_64: - decl %ecx + decq %rcx movq %rax,(%rdi) movq %rax,8(%rdi) movq %rax,16(%rdi) @@ -97,7 +95,7 @@ ENTRY(__memset) to predict jump tables. */ .p2align 4 .Lhandle_tail: - movl %r11d,%ecx + movl %edx,%ecx andl $63&(~7),%ecx jz .Lhandle_7 shrl $3,%ecx @@ -109,12 +107,11 @@ ENTRY(__memset) jnz .Lloop_8 .Lhandle_7: - movl %r11d,%ecx - andl $7,%ecx + andl $7,%edx jz .Lende .p2align 4 .Lloop_1: - decl %ecx + decl %edx movb %al,(%rdi) leaq 1(%rdi),%rdi jnz .Lloop_1 @@ -125,13 +122,13 @@ ENTRY(__memset) CFI_RESTORE_STATE .Lbad_alignment: - cmpq $7,%r11 + cmpq $7,%rdx jbe .Lhandle_7 movq %rax,(%rdi) /* unaligned store */ movq $8,%r8 subq %r9,%r8 addq %r8,%rdi - subq %r8,%r11 + subq %r8,%rdx jmp .Lafter_bad_alignment .Lfinal: CFI_ENDPROC diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index e218d5df85ff..d9b094ca7aaa 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -760,9 +760,9 @@ survive: break; } - maddr = kmap_atomic(pg, KM_USER0); + maddr = kmap_atomic(pg); memcpy(maddr + offset, from, len); - kunmap_atomic(maddr, KM_USER0); + kunmap_atomic(maddr); set_page_dirty_lock(pg); put_page(pg); up_read(¤t->mm->mmap_sem); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index f4f29b19fac5..6f31ee56c008 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -51,11 +51,11 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { return kmap_atomic_prot(page, kmap_prot); } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); /* * This is the same as kmap_atomic() but can map memory that doesn't diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 8ecbb4bba4b3..f6679a7fb8ca 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -308,10 +308,11 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, { struct hstate *h = hstate_file(file); struct mm_struct *mm = current->mm; - struct vm_area_struct *vma, *prev_vma; - unsigned long base = mm->mmap_base, addr = addr0; + struct vm_area_struct *vma; + unsigned long base = mm->mmap_base; + unsigned long addr = addr0; unsigned long largest_hole = mm->cached_hole_size; - int first_time = 1; + unsigned long start_addr; /* don't allow allocations above current base */ if (mm->free_area_cache > base) @@ -322,6 +323,8 @@ static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, mm->free_area_cache = base; } try_again: + start_addr = mm->free_area_cache; + /* make sure it can fit in the remaining address space */ if (mm->free_area_cache < len) goto fail; @@ -337,22 +340,14 @@ try_again: if (!vma) return addr; - /* - * new region fits between prev_vma->vm_end and - * vma->vm_start, use it: - */ - prev_vma = vma->vm_prev; - if (addr + len <= vma->vm_start && - (!prev_vma || (addr >= prev_vma->vm_end))) { + if (addr + len <= vma->vm_start) { /* remember the address as a hint for next time */ mm->cached_hole_size = largest_hole; return (mm->free_area_cache = addr); - } else { + } else if (mm->free_area_cache == vma->vm_end) { /* pull free_area_cache down to the first hole */ - if (mm->free_area_cache == vma->vm_end) { - mm->free_area_cache = vma->vm_start; - mm->cached_hole_size = largest_hole; - } + mm->free_area_cache = vma->vm_start; + mm->cached_hole_size = largest_hole; } /* remember the largest hole we saw so far */ @@ -368,10 +363,9 @@ fail: * if hint left us with no space for the requested * mapping then try again: */ - if (first_time) { + if (start_addr != base) { mm->free_area_cache = base; largest_hole = 0; - first_time = 0; goto try_again; } /* diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c index 46db56845f18..53489ff6bf82 100644 --- a/arch/x86/mm/numa_emulation.c +++ b/arch/x86/mm/numa_emulation.c @@ -28,7 +28,7 @@ static int __init emu_find_memblk_by_nid(int nid, const struct numa_meminfo *mi) return -ENOENT; } -static u64 mem_hole_size(u64 start, u64 end) +static u64 __init mem_hole_size(u64 start, u64 end) { unsigned long start_pfn = PFN_UP(start); unsigned long end_pfn = PFN_DOWN(end); @@ -60,7 +60,7 @@ static int __init emu_setup_memblk(struct numa_meminfo *ei, eb->nid = nid; if (emu_nid_to_phys[nid] == NUMA_NO_NODE) - emu_nid_to_phys[nid] = pb->nid; + emu_nid_to_phys[nid] = nid; pb->start += size; if (pb->start >= pb->end) { diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7c1b765ecc59..5671752f8d9c 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -475,8 +475,10 @@ void bpf_jit_compile(struct sk_filter *fp) case BPF_S_LD_W_ABS: func = sk_load_word; common_load: seen |= SEEN_DATAREF; - if ((int)K < 0) + if ((int)K < 0) { + /* Abort the JIT because __load_pointer() is needed. */ goto out; + } t_offset = func - (image + addrs[i]); EMIT1_off32(0xbe, K); /* mov imm32,%esi */ EMIT1_off32(0xe8, t_offset); /* call */ @@ -489,14 +491,8 @@ common_load: seen |= SEEN_DATAREF; goto common_load; case BPF_S_LDX_B_MSH: if ((int)K < 0) { - if (pc_ret0 > 0) { - /* addrs[pc_ret0 - 1] is the start address */ - EMIT_JMP(addrs[pc_ret0 - 1] - addrs[i]); - break; - } - CLEAR_A(); - EMIT_JMP(cleanup_addr - addrs[i]); - break; + /* Abort the JIT because __load_pointer() is needed. */ + goto out; } seen |= SEEN_DATAREF | SEEN_XREG; t_offset = sk_load_byte_msh - (image + addrs[i]); diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 4cf9bd0a1653..92660edaa1e7 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -26,6 +26,8 @@ * Skip non-WB memory and ignore empty memory ranges. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/init.h> #include <linux/efi.h> @@ -47,7 +49,6 @@ #include <asm/x86_init.h> #define EFI_DEBUG 1 -#define PFX "EFI: " int efi_enabled; EXPORT_SYMBOL(efi_enabled); @@ -67,6 +68,9 @@ EXPORT_SYMBOL(efi); struct efi_memory_map memmap; +bool efi_64bit; +static bool efi_native; + static struct efi efi_phys __initdata; static efi_system_table_t efi_systab __initdata; @@ -254,7 +258,7 @@ int efi_set_rtc_mmss(unsigned long nowtime) status = efi.get_time(&eft, &cap); if (status != EFI_SUCCESS) { - printk(KERN_ERR "Oops: efitime: can't read time!\n"); + pr_err("Oops: efitime: can't read time!\n"); return -1; } @@ -268,7 +272,7 @@ int efi_set_rtc_mmss(unsigned long nowtime) status = efi.set_time(&eft); if (status != EFI_SUCCESS) { - printk(KERN_ERR "Oops: efitime: can't write time!\n"); + pr_err("Oops: efitime: can't write time!\n"); return -1; } return 0; @@ -282,7 +286,7 @@ unsigned long efi_get_time(void) status = efi.get_time(&eft, &cap); if (status != EFI_SUCCESS) - printk(KERN_ERR "Oops: efitime: can't read time!\n"); + pr_err("Oops: efitime: can't read time!\n"); return mktime(eft.year, eft.month, eft.day, eft.hour, eft.minute, eft.second); @@ -338,11 +342,16 @@ static void __init do_add_efi_memmap(void) sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); } -void __init efi_memblock_x86_reserve_range(void) +int __init efi_memblock_x86_reserve_range(void) { unsigned long pmap; #ifdef CONFIG_X86_32 + /* Can't handle data above 4GB at this time */ + if (boot_params.efi_info.efi_memmap_hi) { + pr_err("Memory map is above 4GB, disabling EFI.\n"); + return -EINVAL; + } pmap = boot_params.efi_info.efi_memmap; #else pmap = (boot_params.efi_info.efi_memmap | @@ -354,6 +363,8 @@ void __init efi_memblock_x86_reserve_range(void) memmap.desc_version = boot_params.efi_info.efi_memdesc_version; memmap.desc_size = boot_params.efi_info.efi_memdesc_size; memblock_reserve(pmap, memmap.nr_map * memmap.desc_size); + + return 0; } #if EFI_DEBUG @@ -367,7 +378,7 @@ static void __init print_efi_memmap(void) p < memmap.map_end; p += memmap.desc_size, i++) { md = p; - printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, " + pr_info("mem%02u: type=%u, attr=0x%llx, " "range=[0x%016llx-0x%016llx) (%lluMB)\n", i, md->type, md->attribute, md->phys_addr, md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), @@ -400,7 +411,7 @@ void __init efi_reserve_boot_services(void) memblock_is_region_reserved(start, size)) { /* Could not reserve, skip it */ md->num_pages = 0; - memblock_dbg(PFX "Could not reserve boot range " + memblock_dbg("Could not reserve boot range " "[0x%010llx-0x%010llx]\n", start, start+size-1); } else @@ -429,103 +440,172 @@ static void __init efi_free_boot_services(void) } } -void __init efi_init(void) +static int __init efi_systab_init(void *phys) { - efi_config_table_t *config_tables; - efi_runtime_services_t *runtime; - efi_char16_t *c16; - char vendor[100] = "unknown"; - int i = 0; - void *tmp; + if (efi_64bit) { + efi_system_table_64_t *systab64; + u64 tmp = 0; + + systab64 = early_ioremap((unsigned long)phys, + sizeof(*systab64)); + if (systab64 == NULL) { + pr_err("Couldn't map the system table!\n"); + return -ENOMEM; + } + efi_systab.hdr = systab64->hdr; + efi_systab.fw_vendor = systab64->fw_vendor; + tmp |= systab64->fw_vendor; + efi_systab.fw_revision = systab64->fw_revision; + efi_systab.con_in_handle = systab64->con_in_handle; + tmp |= systab64->con_in_handle; + efi_systab.con_in = systab64->con_in; + tmp |= systab64->con_in; + efi_systab.con_out_handle = systab64->con_out_handle; + tmp |= systab64->con_out_handle; + efi_systab.con_out = systab64->con_out; + tmp |= systab64->con_out; + efi_systab.stderr_handle = systab64->stderr_handle; + tmp |= systab64->stderr_handle; + efi_systab.stderr = systab64->stderr; + tmp |= systab64->stderr; + efi_systab.runtime = (void *)(unsigned long)systab64->runtime; + tmp |= systab64->runtime; + efi_systab.boottime = (void *)(unsigned long)systab64->boottime; + tmp |= systab64->boottime; + efi_systab.nr_tables = systab64->nr_tables; + efi_systab.tables = systab64->tables; + tmp |= systab64->tables; + + early_iounmap(systab64, sizeof(*systab64)); #ifdef CONFIG_X86_32 - efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; -#else - efi_phys.systab = (efi_system_table_t *) - (boot_params.efi_info.efi_systab | - ((__u64)boot_params.efi_info.efi_systab_hi<<32)); + if (tmp >> 32) { + pr_err("EFI data located above 4GB, disabling EFI.\n"); + return -EINVAL; + } #endif + } else { + efi_system_table_32_t *systab32; + + systab32 = early_ioremap((unsigned long)phys, + sizeof(*systab32)); + if (systab32 == NULL) { + pr_err("Couldn't map the system table!\n"); + return -ENOMEM; + } + + efi_systab.hdr = systab32->hdr; + efi_systab.fw_vendor = systab32->fw_vendor; + efi_systab.fw_revision = systab32->fw_revision; + efi_systab.con_in_handle = systab32->con_in_handle; + efi_systab.con_in = systab32->con_in; + efi_systab.con_out_handle = systab32->con_out_handle; + efi_systab.con_out = systab32->con_out; + efi_systab.stderr_handle = systab32->stderr_handle; + efi_systab.stderr = systab32->stderr; + efi_systab.runtime = (void *)(unsigned long)systab32->runtime; + efi_systab.boottime = (void *)(unsigned long)systab32->boottime; + efi_systab.nr_tables = systab32->nr_tables; + efi_systab.tables = systab32->tables; + + early_iounmap(systab32, sizeof(*systab32)); + } - efi.systab = early_ioremap((unsigned long)efi_phys.systab, - sizeof(efi_system_table_t)); - if (efi.systab == NULL) - printk(KERN_ERR "Couldn't map the EFI system table!\n"); - memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t)); - early_iounmap(efi.systab, sizeof(efi_system_table_t)); efi.systab = &efi_systab; /* * Verify the EFI Table */ - if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) - printk(KERN_ERR "EFI system table signature incorrect!\n"); + if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { + pr_err("System table signature incorrect!\n"); + return -EINVAL; + } if ((efi.systab->hdr.revision >> 16) == 0) - printk(KERN_ERR "Warning: EFI system table version " + pr_err("Warning: System table version " "%d.%02d, expected 1.00 or greater!\n", efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff); - /* - * Show what we know for posterity - */ - c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2); - if (c16) { - for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i) - vendor[i] = *c16++; - vendor[i] = '\0'; - } else - printk(KERN_ERR PFX "Could not map the firmware vendor!\n"); - early_iounmap(tmp, 2); + return 0; +} - printk(KERN_INFO "EFI v%u.%.02u by %s\n", - efi.systab->hdr.revision >> 16, - efi.systab->hdr.revision & 0xffff, vendor); +static int __init efi_config_init(u64 tables, int nr_tables) +{ + void *config_tables, *tablep; + int i, sz; + + if (efi_64bit) + sz = sizeof(efi_config_table_64_t); + else + sz = sizeof(efi_config_table_32_t); /* * Let's see what config tables the firmware passed to us. */ - config_tables = early_ioremap( - efi.systab->tables, - efi.systab->nr_tables * sizeof(efi_config_table_t)); - if (config_tables == NULL) - printk(KERN_ERR "Could not map EFI Configuration Table!\n"); + config_tables = early_ioremap(tables, nr_tables * sz); + if (config_tables == NULL) { + pr_err("Could not map Configuration table!\n"); + return -ENOMEM; + } - printk(KERN_INFO); + tablep = config_tables; + pr_info(""); for (i = 0; i < efi.systab->nr_tables; i++) { - if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) { - efi.mps = config_tables[i].table; - printk(" MPS=0x%lx ", config_tables[i].table); - } else if (!efi_guidcmp(config_tables[i].guid, - ACPI_20_TABLE_GUID)) { - efi.acpi20 = config_tables[i].table; - printk(" ACPI 2.0=0x%lx ", config_tables[i].table); - } else if (!efi_guidcmp(config_tables[i].guid, - ACPI_TABLE_GUID)) { - efi.acpi = config_tables[i].table; - printk(" ACPI=0x%lx ", config_tables[i].table); - } else if (!efi_guidcmp(config_tables[i].guid, - SMBIOS_TABLE_GUID)) { - efi.smbios = config_tables[i].table; - printk(" SMBIOS=0x%lx ", config_tables[i].table); + efi_guid_t guid; + unsigned long table; + + if (efi_64bit) { + u64 table64; + guid = ((efi_config_table_64_t *)tablep)->guid; + table64 = ((efi_config_table_64_t *)tablep)->table; + table = table64; +#ifdef CONFIG_X86_32 + if (table64 >> 32) { + pr_cont("\n"); + pr_err("Table located above 4GB, disabling EFI.\n"); + early_iounmap(config_tables, + efi.systab->nr_tables * sz); + return -EINVAL; + } +#endif + } else { + guid = ((efi_config_table_32_t *)tablep)->guid; + table = ((efi_config_table_32_t *)tablep)->table; + } + if (!efi_guidcmp(guid, MPS_TABLE_GUID)) { + efi.mps = table; + pr_cont(" MPS=0x%lx ", table); + } else if (!efi_guidcmp(guid, ACPI_20_TABLE_GUID)) { + efi.acpi20 = table; + pr_cont(" ACPI 2.0=0x%lx ", table); + } else if (!efi_guidcmp(guid, ACPI_TABLE_GUID)) { + efi.acpi = table; + pr_cont(" ACPI=0x%lx ", table); + } else if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) { + efi.smbios = table; + pr_cont(" SMBIOS=0x%lx ", table); #ifdef CONFIG_X86_UV - } else if (!efi_guidcmp(config_tables[i].guid, - UV_SYSTEM_TABLE_GUID)) { - efi.uv_systab = config_tables[i].table; - printk(" UVsystab=0x%lx ", config_tables[i].table); + } else if (!efi_guidcmp(guid, UV_SYSTEM_TABLE_GUID)) { + efi.uv_systab = table; + pr_cont(" UVsystab=0x%lx ", table); #endif - } else if (!efi_guidcmp(config_tables[i].guid, - HCDP_TABLE_GUID)) { - efi.hcdp = config_tables[i].table; - printk(" HCDP=0x%lx ", config_tables[i].table); - } else if (!efi_guidcmp(config_tables[i].guid, - UGA_IO_PROTOCOL_GUID)) { - efi.uga = config_tables[i].table; - printk(" UGA=0x%lx ", config_tables[i].table); + } else if (!efi_guidcmp(guid, HCDP_TABLE_GUID)) { + efi.hcdp = table; + pr_cont(" HCDP=0x%lx ", table); + } else if (!efi_guidcmp(guid, UGA_IO_PROTOCOL_GUID)) { + efi.uga = table; + pr_cont(" UGA=0x%lx ", table); } + tablep += sz; } - printk("\n"); - early_iounmap(config_tables, - efi.systab->nr_tables * sizeof(efi_config_table_t)); + pr_cont("\n"); + early_iounmap(config_tables, efi.systab->nr_tables * sz); + return 0; +} + +static int __init efi_runtime_init(void) +{ + efi_runtime_services_t *runtime; /* * Check out the runtime services table. We need to map @@ -535,43 +615,116 @@ void __init efi_init(void) */ runtime = early_ioremap((unsigned long)efi.systab->runtime, sizeof(efi_runtime_services_t)); - if (runtime != NULL) { - /* - * We will only need *early* access to the following - * two EFI runtime services before set_virtual_address_map - * is invoked. - */ - efi_phys.get_time = (efi_get_time_t *)runtime->get_time; - efi_phys.set_virtual_address_map = - (efi_set_virtual_address_map_t *) - runtime->set_virtual_address_map; - /* - * Make efi_get_time can be called before entering - * virtual mode. - */ - efi.get_time = phys_efi_get_time; - } else - printk(KERN_ERR "Could not map the EFI runtime service " - "table!\n"); + if (!runtime) { + pr_err("Could not map the runtime service table!\n"); + return -ENOMEM; + } + /* + * We will only need *early* access to the following + * two EFI runtime services before set_virtual_address_map + * is invoked. + */ + efi_phys.get_time = (efi_get_time_t *)runtime->get_time; + efi_phys.set_virtual_address_map = + (efi_set_virtual_address_map_t *) + runtime->set_virtual_address_map; + /* + * Make efi_get_time can be called before entering + * virtual mode. + */ + efi.get_time = phys_efi_get_time; early_iounmap(runtime, sizeof(efi_runtime_services_t)); + return 0; +} + +static int __init efi_memmap_init(void) +{ /* Map the EFI memory map */ memmap.map = early_ioremap((unsigned long)memmap.phys_map, memmap.nr_map * memmap.desc_size); - if (memmap.map == NULL) - printk(KERN_ERR "Could not map the EFI memory map!\n"); + if (memmap.map == NULL) { + pr_err("Could not map the memory map!\n"); + return -ENOMEM; + } memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size); - if (memmap.desc_size != sizeof(efi_memory_desc_t)) - printk(KERN_WARNING - "Kernel-defined memdesc doesn't match the one from EFI!\n"); - if (add_efi_memmap) do_add_efi_memmap(); + return 0; +} + +void __init efi_init(void) +{ + efi_char16_t *c16; + char vendor[100] = "unknown"; + int i = 0; + void *tmp; + +#ifdef CONFIG_X86_32 + if (boot_params.efi_info.efi_systab_hi || + boot_params.efi_info.efi_memmap_hi) { + pr_info("Table located above 4GB, disabling EFI.\n"); + efi_enabled = 0; + return; + } + efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; + efi_native = !efi_64bit; +#else + efi_phys.systab = (efi_system_table_t *) + (boot_params.efi_info.efi_systab | + ((__u64)boot_params.efi_info.efi_systab_hi<<32)); + efi_native = efi_64bit; +#endif + + if (efi_systab_init(efi_phys.systab)) { + efi_enabled = 0; + return; + } + + /* + * Show what we know for posterity + */ + c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2); + if (c16) { + for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i) + vendor[i] = *c16++; + vendor[i] = '\0'; + } else + pr_err("Could not map the firmware vendor!\n"); + early_iounmap(tmp, 2); + + pr_info("EFI v%u.%.02u by %s\n", + efi.systab->hdr.revision >> 16, + efi.systab->hdr.revision & 0xffff, vendor); + + if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) { + efi_enabled = 0; + return; + } + + /* + * Note: We currently don't support runtime services on an EFI + * that doesn't match the kernel 32/64-bit mode. + */ + + if (!efi_native) + pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); + else if (efi_runtime_init()) { + efi_enabled = 0; + return; + } + + if (efi_memmap_init()) { + efi_enabled = 0; + return; + } #ifdef CONFIG_X86_32 - x86_platform.get_wallclock = efi_get_time; - x86_platform.set_wallclock = efi_set_rtc_mmss; + if (efi_native) { + x86_platform.get_wallclock = efi_get_time; + x86_platform.set_wallclock = efi_set_rtc_mmss; + } #endif #if EFI_DEBUG @@ -629,6 +782,14 @@ void __init efi_enter_virtual_mode(void) efi.systab = NULL; + /* + * We don't do virtual mode, since we don't do runtime services, on + * non-native EFI + */ + + if (!efi_native) + goto out; + /* Merge contiguous regions of the same type and attribute */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { u64 prev_size; @@ -677,7 +838,7 @@ void __init efi_enter_virtual_mode(void) md->virt_addr = (u64) (unsigned long) va; if (!va) { - printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n", + pr_err("ioremap of 0x%llX failed!\n", (unsigned long long)md->phys_addr); continue; } @@ -711,8 +872,8 @@ void __init efi_enter_virtual_mode(void) (efi_memory_desc_t *)__pa(new_memmap)); if (status != EFI_SUCCESS) { - printk(KERN_ALERT "Unable to switch EFI into virtual mode " - "(status=%lx)!\n", status); + pr_alert("Unable to switch EFI into virtual mode " + "(status=%lx)!\n", status); panic("EFI call to SetVirtualAddressMap() failed!"); } @@ -744,6 +905,8 @@ void __init efi_enter_virtual_mode(void) efi.query_capsule_caps = virt_efi_query_capsule_caps; if (__supported_pte_mask & _PAGE_NX) runtime_code_page_mkexec(); + +out: early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); memmap.map = NULL; kfree(new_memmap); diff --git a/arch/x86/platform/geode/Makefile b/arch/x86/platform/geode/Makefile index 07c9cd05021a..246b788847ff 100644 --- a/arch/x86/platform/geode/Makefile +++ b/arch/x86/platform/geode/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_ALIX) += alix.o +obj-$(CONFIG_NET5501) += net5501.o diff --git a/arch/x86/platform/geode/alix.c b/arch/x86/platform/geode/alix.c index dc5f1d32aced..90e23e7679a5 100644 --- a/arch/x86/platform/geode/alix.c +++ b/arch/x86/platform/geode/alix.c @@ -6,6 +6,7 @@ * * Copyright (C) 2008 Constantin Baranov <const@mimas.ru> * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com> + * and Philip Prindeville <philipp@redfish-solutions.com> * * TODO: There are large similarities with leds-net5501.c * by Alessandro Zummo <a.zummo@towertech.it> @@ -24,14 +25,47 @@ #include <linux/leds.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/dmi.h> #include <asm/geode.h> +#define BIOS_SIGNATURE_TINYBIOS 0xf0000 +#define BIOS_SIGNATURE_COREBOOT 0x500 +#define BIOS_REGION_SIZE 0x10000 + static bool force = 0; module_param(force, bool, 0444); /* FIXME: Award bios is not automatically detected as Alix platform */ MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform"); +static struct gpio_keys_button alix_gpio_buttons[] = { + { + .code = KEY_RESTART, + .gpio = 24, + .active_low = 1, + .desc = "Reset button", + .type = EV_KEY, + .wakeup = 0, + .debounce_interval = 100, + .can_disable = 0, + } +}; +static struct gpio_keys_platform_data alix_buttons_data = { + .buttons = alix_gpio_buttons, + .nbuttons = ARRAY_SIZE(alix_gpio_buttons), + .poll_interval = 20, +}; + +static struct platform_device alix_buttons_dev = { + .name = "gpio-keys-polled", + .id = 1, + .dev = { + .platform_data = &alix_buttons_data, + } +}; + static struct gpio_led alix_leds[] = { { .name = "alix:1", @@ -64,17 +98,22 @@ static struct platform_device alix_leds_dev = { .dev.platform_data = &alix_leds_data, }; +static struct __initdata platform_device *alix_devs[] = { + &alix_buttons_dev, + &alix_leds_dev, +}; + static void __init register_alix(void) { /* Setup LED control through leds-gpio driver */ - platform_device_register(&alix_leds_dev); + platform_add_devices(alix_devs, ARRAY_SIZE(alix_devs)); } -static int __init alix_present(unsigned long bios_phys, +static bool __init alix_present(unsigned long bios_phys, const char *alix_sig, size_t alix_sig_len) { - const size_t bios_len = 0x00010000; + const size_t bios_len = BIOS_REGION_SIZE; const char *bios_virt; const char *scan_end; const char *p; @@ -84,7 +123,7 @@ static int __init alix_present(unsigned long bios_phys, printk(KERN_NOTICE "%s: forced to skip BIOS test, " "assume system is ALIX.2/ALIX.3\n", KBUILD_MODNAME); - return 1; + return true; } bios_virt = phys_to_virt(bios_phys); @@ -109,15 +148,33 @@ static int __init alix_present(unsigned long bios_phys, *a = '\0'; tail = p + alix_sig_len; - if ((tail[0] == '2' || tail[0] == '3')) { + if ((tail[0] == '2' || tail[0] == '3' || tail[0] == '6')) { printk(KERN_INFO "%s: system is recognized as \"%s\"\n", KBUILD_MODNAME, name); - return 1; + return true; } } - return 0; + return false; +} + +static bool __init alix_present_dmi(void) +{ + const char *vendor, *product; + + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (!vendor || strcmp(vendor, "PC Engines")) + return false; + + product = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!product || (strcmp(product, "ALIX.2D") && strcmp(product, "ALIX.6"))) + return false; + + printk(KERN_INFO "%s: system is recognized as \"%s %s\"\n", + KBUILD_MODNAME, vendor, product); + + return true; } static int __init alix_init(void) @@ -128,8 +185,9 @@ static int __init alix_init(void) if (!is_geode()) return 0; - if (alix_present(0xf0000, tinybios_sig, sizeof(tinybios_sig) - 1) || - alix_present(0x500, coreboot_sig, sizeof(coreboot_sig) - 1)) + if (alix_present(BIOS_SIGNATURE_TINYBIOS, tinybios_sig, sizeof(tinybios_sig) - 1) || + alix_present(BIOS_SIGNATURE_COREBOOT, coreboot_sig, sizeof(coreboot_sig) - 1) || + alix_present_dmi()) register_alix(); return 0; diff --git a/arch/x86/platform/geode/net5501.c b/arch/x86/platform/geode/net5501.c new file mode 100644 index 000000000000..66d377e334f7 --- /dev/null +++ b/arch/x86/platform/geode/net5501.c @@ -0,0 +1,154 @@ +/* + * System Specific setup for Soekris net5501 + * At the moment this means setup of GPIO control of LEDs and buttons + * on net5501 boards. + * + * + * Copyright (C) 2008-2009 Tower Technologies + * Written by Alessandro Zummo <a.zummo@towertech.it> + * + * Copyright (C) 2008 Constantin Baranov <const@mimas.ru> + * Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com> + * and Philip Prindeville <philipp@redfish-solutions.com> + * + * 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 published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/string.h> +#include <linux/module.h> +#include <linux/leds.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> + +#include <asm/geode.h> + +#define BIOS_REGION_BASE 0xffff0000 +#define BIOS_REGION_SIZE 0x00010000 + +static struct gpio_keys_button net5501_gpio_buttons[] = { + { + .code = KEY_RESTART, + .gpio = 24, + .active_low = 1, + .desc = "Reset button", + .type = EV_KEY, + .wakeup = 0, + .debounce_interval = 100, + .can_disable = 0, + } +}; +static struct gpio_keys_platform_data net5501_buttons_data = { + .buttons = net5501_gpio_buttons, + .nbuttons = ARRAY_SIZE(net5501_gpio_buttons), + .poll_interval = 20, +}; + +static struct platform_device net5501_buttons_dev = { + .name = "gpio-keys-polled", + .id = 1, + .dev = { + .platform_data = &net5501_buttons_data, + } +}; + +static struct gpio_led net5501_leds[] = { + { + .name = "net5501:1", + .gpio = 6, + .default_trigger = "default-on", + .active_low = 1, + }, +}; + +static struct gpio_led_platform_data net5501_leds_data = { + .num_leds = ARRAY_SIZE(net5501_leds), + .leds = net5501_leds, +}; + +static struct platform_device net5501_leds_dev = { + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &net5501_leds_data, +}; + +static struct __initdata platform_device *net5501_devs[] = { + &net5501_buttons_dev, + &net5501_leds_dev, +}; + +static void __init register_net5501(void) +{ + /* Setup LED control through leds-gpio driver */ + platform_add_devices(net5501_devs, ARRAY_SIZE(net5501_devs)); +} + +struct net5501_board { + u16 offset; + u16 len; + char *sig; +}; + +static struct net5501_board __initdata boards[] = { + { 0xb7b, 7, "net5501" }, /* net5501 v1.33/1.33c */ + { 0xb1f, 7, "net5501" }, /* net5501 v1.32i */ +}; + +static bool __init net5501_present(void) +{ + int i; + unsigned char *rombase, *bios; + bool found = false; + + rombase = ioremap(BIOS_REGION_BASE, BIOS_REGION_SIZE - 1); + if (!rombase) { + printk(KERN_ERR "%s: failed to get rombase\n", KBUILD_MODNAME); + return found; + } + + bios = rombase + 0x20; /* null terminated */ + + if (memcmp(bios, "comBIOS", 7)) + goto unmap; + + for (i = 0; i < ARRAY_SIZE(boards); i++) { + unsigned char *model = rombase + boards[i].offset; + + if (!memcmp(model, boards[i].sig, boards[i].len)) { + printk(KERN_INFO "%s: system is recognized as \"%s\"\n", + KBUILD_MODNAME, model); + + found = true; + break; + } + } + +unmap: + iounmap(rombase); + return found; +} + +static int __init net5501_init(void) +{ + if (!is_geode()) + return 0; + + if (!net5501_present()) + return 0; + + register_net5501(); + + return 0; +} + +module_init(net5501_init); + +MODULE_AUTHOR("Philip Prindeville <philipp@redfish-solutions.com>"); +MODULE_DESCRIPTION("Soekris net5501 System Setup"); +MODULE_LICENSE("GPL"); diff --git a/arch/x86/platform/mrst/Makefile b/arch/x86/platform/mrst/Makefile index 7baed5135e0f..af1da7e623f9 100644 --- a/arch/x86/platform/mrst/Makefile +++ b/arch/x86/platform/mrst/Makefile @@ -1,4 +1,3 @@ obj-$(CONFIG_X86_INTEL_MID) += mrst.o obj-$(CONFIG_X86_INTEL_MID) += vrtc.o obj-$(CONFIG_EARLY_PRINTK_INTEL_MID) += early_printk_mrst.o -obj-$(CONFIG_X86_MRST) += pmu.o diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 475e2cd0f3c3..e0a37233c0af 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -28,6 +28,8 @@ #include <linux/module.h> #include <linux/notifier.h> #include <linux/mfd/intel_msic.h> +#include <linux/gpio.h> +#include <linux/i2c/tc35876x.h> #include <asm/setup.h> #include <asm/mpspec_def.h> @@ -78,16 +80,11 @@ int sfi_mrtc_num; static void mrst_power_off(void) { - if (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) - intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 1); } static void mrst_reboot(void) { - if (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) - intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0); - else - intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); + intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); } /* parse all the mtimer info to a static mtimer array */ @@ -200,34 +197,28 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table) static unsigned long __init mrst_calibrate_tsc(void) { - unsigned long flags, fast_calibrate; - if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) { - u32 lo, hi, ratio, fsb; - - rdmsr(MSR_IA32_PERF_STATUS, lo, hi); - pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); - ratio = (hi >> 8) & 0x1f; - pr_debug("ratio is %d\n", ratio); - if (!ratio) { - pr_err("read a zero ratio, should be incorrect!\n"); - pr_err("force tsc ratio to 16 ...\n"); - ratio = 16; - } - rdmsr(MSR_FSB_FREQ, lo, hi); - if ((lo & 0x7) == 0x7) - fsb = PENWELL_FSB_FREQ_83SKU; - else - fsb = PENWELL_FSB_FREQ_100SKU; - fast_calibrate = ratio * fsb; - pr_debug("read penwell tsc %lu khz\n", fast_calibrate); - lapic_timer_frequency = fsb * 1000 / HZ; - /* mark tsc clocksource as reliable */ - set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); - } else { - local_irq_save(flags); - fast_calibrate = apbt_quick_calibrate(); - local_irq_restore(flags); + unsigned long fast_calibrate; + u32 lo, hi, ratio, fsb; + + rdmsr(MSR_IA32_PERF_STATUS, lo, hi); + pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi); + ratio = (hi >> 8) & 0x1f; + pr_debug("ratio is %d\n", ratio); + if (!ratio) { + pr_err("read a zero ratio, should be incorrect!\n"); + pr_err("force tsc ratio to 16 ...\n"); + ratio = 16; } + rdmsr(MSR_FSB_FREQ, lo, hi); + if ((lo & 0x7) == 0x7) + fsb = PENWELL_FSB_FREQ_83SKU; + else + fsb = PENWELL_FSB_FREQ_100SKU; + fast_calibrate = ratio * fsb; + pr_debug("read penwell tsc %lu khz\n", fast_calibrate); + lapic_timer_frequency = fsb * 1000 / HZ; + /* mark tsc clocksource as reliable */ + set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE); if (fast_calibrate) return fast_calibrate; @@ -261,16 +252,11 @@ static void __cpuinit mrst_arch_setup(void) { if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27) __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; - else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26) - __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; else { - pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n", + pr_err("Unknown Intel MID CPU (%d:%d), default to Penwell\n", boot_cpu_data.x86, boot_cpu_data.x86_model); - __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT; + __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL; } - pr_debug("Moorestown CPU %s identified\n", - (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ? - "Lincroft" : "Penwell"); } /* MID systems don't have i8042 controller */ @@ -686,6 +672,24 @@ static void *msic_ocd_platform_data(void *info) return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); } +static void *msic_thermal_platform_data(void *info) +{ + return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL); +} + +/* tc35876x DSI-LVDS bridge chip and panel platform data */ +static void *tc35876x_platform_data(void *data) +{ + static struct tc35876x_platform_data pdata; + + /* gpio pins set to -1 will not be used by the driver */ + pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); + pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); + pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); + + return &pdata; +} + static const struct devs_id __initconst device_ids[] = { {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, @@ -698,6 +702,7 @@ static const struct devs_id __initconst device_ids[] = { {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data}, + {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data}, /* MSIC subdevices */ {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data}, @@ -705,6 +710,7 @@ static const struct devs_id __initconst device_ids[] = { {"msic_audio", SFI_DEV_TYPE_IPC, 1, &msic_audio_platform_data}, {"msic_power_btn", SFI_DEV_TYPE_IPC, 1, &msic_power_btn_platform_data}, {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data}, + {"msic_thermal", SFI_DEV_TYPE_IPC, 1, &msic_thermal_platform_data}, {}, }; diff --git a/arch/x86/platform/mrst/pmu.c b/arch/x86/platform/mrst/pmu.c deleted file mode 100644 index c0ac06da57ac..000000000000 --- a/arch/x86/platform/mrst/pmu.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * mrst/pmu.c - driver for MRST Power Management Unit - * - * Copyright (c) 2011, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/cpuidle.h> -#include <linux/debugfs.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/seq_file.h> -#include <linux/sfi.h> -#include <asm/intel_scu_ipc.h> -#include "pmu.h" - -#define IPCMSG_FW_REVISION 0xF4 - -struct mrst_device { - u16 pci_dev_num; /* DEBUG only */ - u16 lss; - u16 latest_request; - unsigned int pci_state_counts[PCI_D3cold + 1]; /* DEBUG only */ -}; - -/* - * comlete list of MRST PCI devices - */ -static struct mrst_device mrst_devs[] = { -/* 0 */ { 0x0800, LSS_SPI0 }, /* Moorestown SPI Ctrl 0 */ -/* 1 */ { 0x0801, LSS_SPI1 }, /* Moorestown SPI Ctrl 1 */ -/* 2 */ { 0x0802, LSS_I2C0 }, /* Moorestown I2C 0 */ -/* 3 */ { 0x0803, LSS_I2C1 }, /* Moorestown I2C 1 */ -/* 4 */ { 0x0804, LSS_I2C2 }, /* Moorestown I2C 2 */ -/* 5 */ { 0x0805, LSS_KBD }, /* Moorestown Keyboard Ctrl */ -/* 6 */ { 0x0806, LSS_USB_HC }, /* Moorestown USB Ctrl */ -/* 7 */ { 0x0807, LSS_SD_HC0 }, /* Moorestown SD Host Ctrl 0 */ -/* 8 */ { 0x0808, LSS_SD_HC1 }, /* Moorestown SD Host Ctrl 1 */ -/* 9 */ { 0x0809, LSS_NAND }, /* Moorestown NAND Ctrl */ -/* 10 */ { 0x080a, LSS_AUDIO }, /* Moorestown Audio Ctrl */ -/* 11 */ { 0x080b, LSS_IMAGING }, /* Moorestown ISP */ -/* 12 */ { 0x080c, LSS_SECURITY }, /* Moorestown Security Controller */ -/* 13 */ { 0x080d, LSS_DISPLAY }, /* Moorestown External Displays */ -/* 14 */ { 0x080e, 0 }, /* Moorestown SCU IPC */ -/* 15 */ { 0x080f, LSS_GPIO }, /* Moorestown GPIO Controller */ -/* 16 */ { 0x0810, 0 }, /* Moorestown Power Management Unit */ -/* 17 */ { 0x0811, LSS_USB_OTG }, /* Moorestown OTG Ctrl */ -/* 18 */ { 0x0812, LSS_SPI2 }, /* Moorestown SPI Ctrl 2 */ -/* 19 */ { 0x0813, 0 }, /* Moorestown SC DMA */ -/* 20 */ { 0x0814, LSS_AUDIO_LPE }, /* Moorestown LPE DMA */ -/* 21 */ { 0x0815, LSS_AUDIO_SSP }, /* Moorestown SSP0 */ - -/* 22 */ { 0x084F, LSS_SD_HC2 }, /* Moorestown SD Host Ctrl 2 */ - -/* 23 */ { 0x4102, 0 }, /* Lincroft */ -/* 24 */ { 0x4110, 0 }, /* Lincroft */ -}; - -/* n.b. We ignore PCI-id 0x815 in LSS9 b/c Linux has no driver for it */ -static u16 mrst_lss9_pci_ids[] = {0x080a, 0x0814, 0}; -static u16 mrst_lss10_pci_ids[] = {0x0800, 0x0801, 0x0802, 0x0803, - 0x0804, 0x0805, 0x080f, 0}; - -/* handle concurrent SMP invokations of pmu_pci_set_power_state() */ -static spinlock_t mrst_pmu_power_state_lock; - -static unsigned int wake_counters[MRST_NUM_LSS]; /* DEBUG only */ -static unsigned int pmu_irq_stats[INT_INVALID + 1]; /* DEBUG only */ - -static int graphics_is_off; -static int lss_s0i3_enabled; -static bool mrst_pmu_s0i3_enable; - -/* debug counters */ -static u32 pmu_wait_ready_calls; -static u32 pmu_wait_ready_udelays; -static u32 pmu_wait_ready_udelays_max; -static u32 pmu_wait_done_calls; -static u32 pmu_wait_done_udelays; -static u32 pmu_wait_done_udelays_max; -static u32 pmu_set_power_state_entry; -static u32 pmu_set_power_state_send_cmd; - -static struct mrst_device *pci_id_2_mrst_dev(u16 pci_dev_num) -{ - int index = 0; - - if ((pci_dev_num >= 0x0800) && (pci_dev_num <= 0x815)) - index = pci_dev_num - 0x800; - else if (pci_dev_num == 0x084F) - index = 22; - else if (pci_dev_num == 0x4102) - index = 23; - else if (pci_dev_num == 0x4110) - index = 24; - - if (pci_dev_num != mrst_devs[index].pci_dev_num) { - WARN_ONCE(1, FW_BUG "Unknown PCI device 0x%04X\n", pci_dev_num); - return 0; - } - - return &mrst_devs[index]; -} - -/** - * mrst_pmu_validate_cstates - * @dev: cpuidle_device - * - * Certain states are not appropriate for governor to pick in some cases. - * This function will be called as cpuidle_device's prepare callback and - * thus tells governor to ignore such states when selecting the next state - * to enter. - */ - -#define IDLE_STATE4_IS_C6 4 -#define IDLE_STATE5_IS_S0I3 5 - -int mrst_pmu_invalid_cstates(void) -{ - int cpu = smp_processor_id(); - - /* - * Demote to C4 if the PMU is busy. - * Since LSS changes leave the busy bit clear... - * busy means either the PMU is waiting for an ACK-C6 that - * isn't coming due to an MWAIT that returned immediately; - * or we returned from S0i3 successfully, and the PMU - * is not done sending us interrupts. - */ - if (pmu_read_busy_status()) - return 1 << IDLE_STATE4_IS_C6 | 1 << IDLE_STATE5_IS_S0I3; - - /* - * Disallow S0i3 if: PMU is not initialized, or CPU1 is active, - * or if device LSS is insufficient, or the GPU is active, - * or if it has been explicitly disabled. - */ - if (!pmu_reg || !cpumask_equal(cpu_online_mask, cpumask_of(cpu)) || - !lss_s0i3_enabled || !graphics_is_off || !mrst_pmu_s0i3_enable) - return 1 << IDLE_STATE5_IS_S0I3; - else - return 0; -} - -/* - * pmu_update_wake_counters(): read PM_WKS, update wake_counters[] - * DEBUG only. - */ -static void pmu_update_wake_counters(void) -{ - int lss; - u32 wake_status; - - wake_status = pmu_read_wks(); - - for (lss = 0; lss < MRST_NUM_LSS; ++lss) { - if (wake_status & (1 << lss)) - wake_counters[lss]++; - } -} - -int mrst_pmu_s0i3_entry(void) -{ - int status; - - /* Clear any possible error conditions */ - pmu_write_ics(0x300); - - /* set wake control to current D-states */ - pmu_write_wssc(S0I3_SSS_TARGET); - - status = mrst_s0i3_entry(PM_S0I3_COMMAND, &pmu_reg->pm_cmd); - pmu_update_wake_counters(); - return status; -} - -/* poll for maximum of 5ms for busy bit to clear */ -static int pmu_wait_ready(void) -{ - int udelays; - - pmu_wait_ready_calls++; - - for (udelays = 0; udelays < 500; ++udelays) { - if (udelays > pmu_wait_ready_udelays_max) - pmu_wait_ready_udelays_max = udelays; - - if (pmu_read_busy_status() == 0) - return 0; - - udelay(10); - pmu_wait_ready_udelays++; - } - - /* - * if this fires, observe - * /sys/kernel/debug/mrst_pmu_wait_ready_calls - * /sys/kernel/debug/mrst_pmu_wait_ready_udelays - */ - WARN_ONCE(1, "SCU not ready for 5ms"); - return -EBUSY; -} -/* poll for maximum of 50ms us for busy bit to clear */ -static int pmu_wait_done(void) -{ - int udelays; - - pmu_wait_done_calls++; - - for (udelays = 0; udelays < 500; ++udelays) { - if (udelays > pmu_wait_done_udelays_max) - pmu_wait_done_udelays_max = udelays; - - if (pmu_read_busy_status() == 0) - return 0; - - udelay(100); - pmu_wait_done_udelays++; - } - - /* - * if this fires, observe - * /sys/kernel/debug/mrst_pmu_wait_done_calls - * /sys/kernel/debug/mrst_pmu_wait_done_udelays - */ - WARN_ONCE(1, "SCU not done for 50ms"); - return -EBUSY; -} - -u32 mrst_pmu_msi_is_disabled(void) -{ - return pmu_msi_is_disabled(); -} - -void mrst_pmu_enable_msi(void) -{ - pmu_msi_enable(); -} - -/** - * pmu_irq - pmu driver interrupt handler - * Context: interrupt context - */ -static irqreturn_t pmu_irq(int irq, void *dummy) -{ - union pmu_pm_ics pmu_ics; - - pmu_ics.value = pmu_read_ics(); - - if (!pmu_ics.bits.pending) - return IRQ_NONE; - - switch (pmu_ics.bits.cause) { - case INT_SPURIOUS: - case INT_CMD_DONE: - case INT_CMD_ERR: - case INT_WAKE_RX: - case INT_SS_ERROR: - case INT_S0IX_MISS: - case INT_NO_ACKC6: - pmu_irq_stats[pmu_ics.bits.cause]++; - break; - default: - pmu_irq_stats[INT_INVALID]++; - } - - pmu_write_ics(pmu_ics.value); /* Clear pending interrupt */ - - return IRQ_HANDLED; -} - -/* - * Translate PCI power management to MRST LSS D-states - */ -static int pci_2_mrst_state(int lss, pci_power_t pci_state) -{ - switch (pci_state) { - case PCI_D0: - if (SSMSK(D0i1, lss) & D0I1_ACG_SSS_TARGET) - return D0i1; - else - return D0; - case PCI_D1: - return D0i1; - case PCI_D2: - return D0i2; - case PCI_D3hot: - case PCI_D3cold: - return D0i3; - default: - WARN(1, "pci_state %d\n", pci_state); - return 0; - } -} - -static int pmu_issue_command(u32 pm_ssc) -{ - union pmu_pm_set_cfg_cmd_t command; - - if (pmu_read_busy_status()) { - pr_debug("pmu is busy, Operation not permitted\n"); - return -1; - } - - /* - * enable interrupts in PMU so that interrupts are - * propagated when ioc bit for a particular set - * command is set - */ - - pmu_irq_enable(); - - /* Configure the sub systems for pmu2 */ - - pmu_write_ssc(pm_ssc); - - /* - * Send the set config command for pmu its configured - * for mode CM_IMMEDIATE & hence with No Trigger - */ - - command.pmu2_params.d_param.cfg_mode = CM_IMMEDIATE; - command.pmu2_params.d_param.cfg_delay = 0; - command.pmu2_params.d_param.rsvd = 0; - - /* construct the command to send SET_CFG to particular PMU */ - command.pmu2_params.d_param.cmd = SET_CFG_CMD; - command.pmu2_params.d_param.ioc = 0; - command.pmu2_params.d_param.mode_id = 0; - command.pmu2_params.d_param.sys_state = SYS_STATE_S0I0; - - /* write the value of PM_CMD into particular PMU */ - pr_debug("pmu command being written %x\n", - command.pmu_pm_set_cfg_cmd_value); - - pmu_write_cmd(command.pmu_pm_set_cfg_cmd_value); - - return 0; -} - -static u16 pmu_min_lss_pci_req(u16 *ids, u16 pci_state) -{ - u16 existing_request; - int i; - - for (i = 0; ids[i]; ++i) { - struct mrst_device *mrst_dev; - - mrst_dev = pci_id_2_mrst_dev(ids[i]); - if (unlikely(!mrst_dev)) - continue; - - existing_request = mrst_dev->latest_request; - if (existing_request < pci_state) - pci_state = existing_request; - } - return pci_state; -} - -/** - * pmu_pci_set_power_state - Callback function is used by all the PCI devices - * for a platform specific device power on/shutdown. - */ - -int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t pci_state) -{ - u32 old_sss, new_sss; - int status = 0; - struct mrst_device *mrst_dev; - - pmu_set_power_state_entry++; - - BUG_ON(pdev->vendor != PCI_VENDOR_ID_INTEL); - BUG_ON(pci_state < PCI_D0 || pci_state > PCI_D3cold); - - mrst_dev = pci_id_2_mrst_dev(pdev->device); - if (unlikely(!mrst_dev)) - return -ENODEV; - - mrst_dev->pci_state_counts[pci_state]++; /* count invocations */ - - /* PMU driver calls self as part of PCI initialization, ignore */ - if (pdev->device == PCI_DEV_ID_MRST_PMU) - return 0; - - BUG_ON(!pmu_reg); /* SW bug if called before initialized */ - - spin_lock(&mrst_pmu_power_state_lock); - - if (pdev->d3_delay) { - dev_dbg(&pdev->dev, "d3_delay %d, should be 0\n", - pdev->d3_delay); - pdev->d3_delay = 0; - } - /* - * If Lincroft graphics, simply remember state - */ - if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY - && !((pdev->class & PCI_SUB_CLASS_MASK) >> 8)) { - if (pci_state == PCI_D0) - graphics_is_off = 0; - else - graphics_is_off = 1; - goto ret; - } - - if (!mrst_dev->lss) - goto ret; /* device with no LSS */ - - if (mrst_dev->latest_request == pci_state) - goto ret; /* no change */ - - mrst_dev->latest_request = pci_state; /* record latest request */ - - /* - * LSS9 and LSS10 contain multiple PCI devices. - * Use the lowest numbered (highest power) state in the LSS - */ - if (mrst_dev->lss == 9) - pci_state = pmu_min_lss_pci_req(mrst_lss9_pci_ids, pci_state); - else if (mrst_dev->lss == 10) - pci_state = pmu_min_lss_pci_req(mrst_lss10_pci_ids, pci_state); - - status = pmu_wait_ready(); - if (status) - goto ret; - - old_sss = pmu_read_sss(); - new_sss = old_sss & ~SSMSK(3, mrst_dev->lss); - new_sss |= SSMSK(pci_2_mrst_state(mrst_dev->lss, pci_state), - mrst_dev->lss); - - if (new_sss == old_sss) - goto ret; /* nothing to do */ - - pmu_set_power_state_send_cmd++; - - status = pmu_issue_command(new_sss); - - if (unlikely(status != 0)) { - dev_err(&pdev->dev, "Failed to Issue a PM command\n"); - goto ret; - } - - if (pmu_wait_done()) - goto ret; - - lss_s0i3_enabled = - ((pmu_read_sss() & S0I3_SSS_TARGET) == S0I3_SSS_TARGET); -ret: - spin_unlock(&mrst_pmu_power_state_lock); - return status; -} - -#ifdef CONFIG_DEBUG_FS -static char *d0ix_names[] = {"D0", "D0i1", "D0i2", "D0i3"}; - -static inline const char *d0ix_name(int state) -{ - return d0ix_names[(int) state]; -} - -static int debug_mrst_pmu_show(struct seq_file *s, void *unused) -{ - struct pci_dev *pdev = NULL; - u32 cur_pmsss; - int lss; - - seq_printf(s, "0x%08X D0I1_ACG_SSS_TARGET\n", D0I1_ACG_SSS_TARGET); - - cur_pmsss = pmu_read_sss(); - - seq_printf(s, "0x%08X S0I3_SSS_TARGET\n", S0I3_SSS_TARGET); - - seq_printf(s, "0x%08X Current SSS ", cur_pmsss); - seq_printf(s, lss_s0i3_enabled ? "\n" : "[BLOCKS s0i3]\n"); - - if (cpumask_equal(cpu_online_mask, cpumask_of(0))) - seq_printf(s, "cpu0 is only cpu online\n"); - else - seq_printf(s, "cpu0 is NOT only cpu online [BLOCKS S0i3]\n"); - - seq_printf(s, "GFX: %s\n", graphics_is_off ? "" : "[BLOCKS s0i3]"); - - - for_each_pci_dev(pdev) { - int pos; - u16 pmcsr; - struct mrst_device *mrst_dev; - int i; - - mrst_dev = pci_id_2_mrst_dev(pdev->device); - - seq_printf(s, "%s %04x/%04X %-16.16s ", - dev_name(&pdev->dev), - pdev->vendor, pdev->device, - dev_driver_string(&pdev->dev)); - - if (unlikely (!mrst_dev)) { - seq_printf(s, " UNKNOWN\n"); - continue; - } - - if (mrst_dev->lss) - seq_printf(s, "LSS %2d %-4s ", mrst_dev->lss, - d0ix_name(((cur_pmsss >> - (mrst_dev->lss * 2)) & 0x3))); - else - seq_printf(s, " "); - - /* PCI PM config space setting */ - pos = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pos != 0) { - pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr); - seq_printf(s, "PCI-%-4s", - pci_power_name(pmcsr & PCI_PM_CTRL_STATE_MASK)); - } else { - seq_printf(s, " "); - } - - seq_printf(s, " %s ", pci_power_name(mrst_dev->latest_request)); - for (i = 0; i <= PCI_D3cold; ++i) - seq_printf(s, "%d ", mrst_dev->pci_state_counts[i]); - - if (mrst_dev->lss) { - unsigned int lssmask; - - lssmask = SSMSK(D0i3, mrst_dev->lss); - - if ((lssmask & S0I3_SSS_TARGET) && - ((lssmask & cur_pmsss) != - (lssmask & S0I3_SSS_TARGET))) - seq_printf(s , "[BLOCKS s0i3]"); - } - - seq_printf(s, "\n"); - } - seq_printf(s, "Wake Counters:\n"); - for (lss = 0; lss < MRST_NUM_LSS; ++lss) - seq_printf(s, "LSS%d %d\n", lss, wake_counters[lss]); - - seq_printf(s, "Interrupt Counters:\n"); - seq_printf(s, - "INT_SPURIOUS \t%8u\n" "INT_CMD_DONE \t%8u\n" - "INT_CMD_ERR \t%8u\n" "INT_WAKE_RX \t%8u\n" - "INT_SS_ERROR \t%8u\n" "INT_S0IX_MISS\t%8u\n" - "INT_NO_ACKC6 \t%8u\n" "INT_INVALID \t%8u\n", - pmu_irq_stats[INT_SPURIOUS], pmu_irq_stats[INT_CMD_DONE], - pmu_irq_stats[INT_CMD_ERR], pmu_irq_stats[INT_WAKE_RX], - pmu_irq_stats[INT_SS_ERROR], pmu_irq_stats[INT_S0IX_MISS], - pmu_irq_stats[INT_NO_ACKC6], pmu_irq_stats[INT_INVALID]); - - seq_printf(s, "mrst_pmu_wait_ready_calls %8d\n", - pmu_wait_ready_calls); - seq_printf(s, "mrst_pmu_wait_ready_udelays %8d\n", - pmu_wait_ready_udelays); - seq_printf(s, "mrst_pmu_wait_ready_udelays_max %8d\n", - pmu_wait_ready_udelays_max); - seq_printf(s, "mrst_pmu_wait_done_calls %8d\n", - pmu_wait_done_calls); - seq_printf(s, "mrst_pmu_wait_done_udelays %8d\n", - pmu_wait_done_udelays); - seq_printf(s, "mrst_pmu_wait_done_udelays_max %8d\n", - pmu_wait_done_udelays_max); - seq_printf(s, "mrst_pmu_set_power_state_entry %8d\n", - pmu_set_power_state_entry); - seq_printf(s, "mrst_pmu_set_power_state_send_cmd %8d\n", - pmu_set_power_state_send_cmd); - seq_printf(s, "SCU busy: %d\n", pmu_read_busy_status()); - - return 0; -} - -static int debug_mrst_pmu_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_mrst_pmu_show, NULL); -} - -static const struct file_operations devices_state_operations = { - .open = debug_mrst_pmu_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* DEBUG_FS */ - -/* - * Validate SCU PCI shim PCI vendor capability byte - * against LSS hard-coded in mrst_devs[] above. - * DEBUG only. - */ -static void pmu_scu_firmware_debug(void) -{ - struct pci_dev *pdev = NULL; - - for_each_pci_dev(pdev) { - struct mrst_device *mrst_dev; - u8 pci_config_lss; - int pos; - - mrst_dev = pci_id_2_mrst_dev(pdev->device); - if (unlikely(!mrst_dev)) { - printk(KERN_ERR FW_BUG "pmu: Unknown " - "PCI device 0x%04X\n", pdev->device); - continue; - } - - if (mrst_dev->lss == 0) - continue; /* no LSS in our table */ - - pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); - if (!pos != 0) { - printk(KERN_ERR FW_BUG "pmu: 0x%04X " - "missing PCI Vendor Capability\n", - pdev->device); - continue; - } - pci_read_config_byte(pdev, pos + 4, &pci_config_lss); - if (!(pci_config_lss & PCI_VENDOR_CAP_LOG_SS_MASK)) { - printk(KERN_ERR FW_BUG "pmu: 0x%04X " - "invalid PCI Vendor Capability 0x%x " - " expected LSS 0x%X\n", - pdev->device, pci_config_lss, mrst_dev->lss); - continue; - } - pci_config_lss &= PCI_VENDOR_CAP_LOG_ID_MASK; - - if (mrst_dev->lss == pci_config_lss) - continue; - - printk(KERN_ERR FW_BUG "pmu: 0x%04X LSS = %d, expected %d\n", - pdev->device, pci_config_lss, mrst_dev->lss); - } -} - -/** - * pmu_probe - */ -static int __devinit pmu_probe(struct pci_dev *pdev, - const struct pci_device_id *pci_id) -{ - int ret; - struct mrst_pmu_reg *pmu; - - /* Init the device */ - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "Unable to Enable PCI device\n"); - return ret; - } - - ret = pci_request_regions(pdev, MRST_PMU_DRV_NAME); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n"); - goto out_err1; - } - - /* Map the memory of PMU reg base */ - pmu = pci_iomap(pdev, 0, 0); - if (!pmu) { - dev_err(&pdev->dev, "Unable to map the PMU address space\n"); - ret = -ENOMEM; - goto out_err2; - } - -#ifdef CONFIG_DEBUG_FS - /* /sys/kernel/debug/mrst_pmu */ - (void) debugfs_create_file("mrst_pmu", S_IFREG | S_IRUGO, - NULL, NULL, &devices_state_operations); -#endif - pmu_reg = pmu; /* success */ - - if (request_irq(pdev->irq, pmu_irq, 0, MRST_PMU_DRV_NAME, NULL)) { - dev_err(&pdev->dev, "Registering isr has failed\n"); - ret = -1; - goto out_err3; - } - - pmu_scu_firmware_debug(); - - pmu_write_wkc(S0I3_WAKE_SOURCES); /* Enable S0i3 wakeup sources */ - - pmu_wait_ready(); - - pmu_write_ssc(D0I1_ACG_SSS_TARGET); /* Enable Auto-Clock_Gating */ - pmu_write_cmd(0x201); - - spin_lock_init(&mrst_pmu_power_state_lock); - - /* Enable the hardware interrupt */ - pmu_irq_enable(); - return 0; - -out_err3: - free_irq(pdev->irq, NULL); - pci_iounmap(pdev, pmu_reg); - pmu_reg = NULL; -out_err2: - pci_release_region(pdev, 0); -out_err1: - pci_disable_device(pdev); - return ret; -} - -static void __devexit pmu_remove(struct pci_dev *pdev) -{ - dev_err(&pdev->dev, "Mid PM pmu_remove called\n"); - - /* Freeing up the irq */ - free_irq(pdev->irq, NULL); - - pci_iounmap(pdev, pmu_reg); - pmu_reg = NULL; - - /* disable the current PCI device */ - pci_release_region(pdev, 0); - pci_disable_device(pdev); -} - -static DEFINE_PCI_DEVICE_TABLE(pmu_pci_ids) = { - { PCI_VDEVICE(INTEL, PCI_DEV_ID_MRST_PMU), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, pmu_pci_ids); - -static struct pci_driver driver = { - .name = MRST_PMU_DRV_NAME, - .id_table = pmu_pci_ids, - .probe = pmu_probe, - .remove = __devexit_p(pmu_remove), -}; - -/** - * pmu_pci_register - register the PMU driver as PCI device - */ -static int __init pmu_pci_register(void) -{ - return pci_register_driver(&driver); -} - -/* Register and probe via fs_initcall() to preceed device_initcall() */ -fs_initcall(pmu_pci_register); - -static void __exit mid_pci_cleanup(void) -{ - pci_unregister_driver(&driver); -} - -static int ia_major; -static int ia_minor; - -static int pmu_sfi_parse_oem(struct sfi_table_header *table) -{ - struct sfi_table_simple *sb; - - sb = (struct sfi_table_simple *)table; - ia_major = (sb->pentry[1] >> 0) & 0xFFFF; - ia_minor = (sb->pentry[1] >> 16) & 0xFFFF; - printk(KERN_INFO "mrst_pmu: IA FW version v%x.%x\n", - ia_major, ia_minor); - - return 0; -} - -static int __init scu_fw_check(void) -{ - int ret; - u32 fw_version; - - if (!pmu_reg) - return 0; /* this driver didn't probe-out */ - - sfi_table_parse("OEMB", NULL, NULL, pmu_sfi_parse_oem); - - if (ia_major < 0x6005 || ia_minor < 0x1525) { - WARN(1, "mrst_pmu: IA FW version too old\n"); - return -1; - } - - ret = intel_scu_ipc_command(IPCMSG_FW_REVISION, 0, NULL, 0, - &fw_version, 1); - - if (ret) { - WARN(1, "mrst_pmu: IPC FW version? %d\n", ret); - } else { - int scu_major = (fw_version >> 8) & 0xFF; - int scu_minor = (fw_version >> 0) & 0xFF; - - printk(KERN_INFO "mrst_pmu: firmware v%x\n", fw_version); - - if ((scu_major >= 0xC0) && (scu_minor >= 0x49)) { - printk(KERN_INFO "mrst_pmu: enabling S0i3\n"); - mrst_pmu_s0i3_enable = true; - } else { - WARN(1, "mrst_pmu: S0i3 disabled, old firmware %X.%X", - scu_major, scu_minor); - } - } - return 0; -} -late_initcall(scu_fw_check); -module_exit(mid_pci_cleanup); diff --git a/arch/x86/platform/mrst/pmu.h b/arch/x86/platform/mrst/pmu.h deleted file mode 100644 index bfbfe64b167b..000000000000 --- a/arch/x86/platform/mrst/pmu.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * mrst/pmu.h - private definitions for MRST Power Management Unit mrst/pmu.c - * - * Copyright (c) 2011, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _MRST_PMU_H_ -#define _MRST_PMU_H_ - -#define PCI_DEV_ID_MRST_PMU 0x0810 -#define MRST_PMU_DRV_NAME "mrst_pmu" -#define PCI_SUB_CLASS_MASK 0xFF00 - -#define PCI_VENDOR_CAP_LOG_ID_MASK 0x7F -#define PCI_VENDOR_CAP_LOG_SS_MASK 0x80 - -#define SUB_SYS_ALL_D0I1 0x01155555 -#define S0I3_WAKE_SOURCES 0x00001FFF - -#define PM_S0I3_COMMAND \ - ((0 << 31) | /* Reserved */ \ - (0 << 30) | /* Core must be idle */ \ - (0xc2 << 22) | /* ACK C6 trigger */ \ - (3 << 19) | /* Trigger on DMI message */ \ - (3 << 16) | /* Enter S0i3 */ \ - (0 << 13) | /* Numeric mode ID (sw) */ \ - (3 << 9) | /* Trigger mode */ \ - (0 << 8) | /* Do not interrupt */ \ - (1 << 0)) /* Set configuration */ - -#define LSS_DMI 0 -#define LSS_SD_HC0 1 -#define LSS_SD_HC1 2 -#define LSS_NAND 3 -#define LSS_IMAGING 4 -#define LSS_SECURITY 5 -#define LSS_DISPLAY 6 -#define LSS_USB_HC 7 -#define LSS_USB_OTG 8 -#define LSS_AUDIO 9 -#define LSS_AUDIO_LPE 9 -#define LSS_AUDIO_SSP 9 -#define LSS_I2C0 10 -#define LSS_I2C1 10 -#define LSS_I2C2 10 -#define LSS_KBD 10 -#define LSS_SPI0 10 -#define LSS_SPI1 10 -#define LSS_SPI2 10 -#define LSS_GPIO 10 -#define LSS_SRAM 11 /* used by SCU, do not touch */ -#define LSS_SD_HC2 12 -/* LSS hardware bits 15,14,13 are hardwired to 0, thus unusable */ -#define MRST_NUM_LSS 13 - -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - -#define SSMSK(mask, lss) ((mask) << ((lss) * 2)) -#define D0 0 -#define D0i1 1 -#define D0i2 2 -#define D0i3 3 - -#define S0I3_SSS_TARGET ( \ - SSMSK(D0i1, LSS_DMI) | \ - SSMSK(D0i3, LSS_SD_HC0) | \ - SSMSK(D0i3, LSS_SD_HC1) | \ - SSMSK(D0i3, LSS_NAND) | \ - SSMSK(D0i3, LSS_SD_HC2) | \ - SSMSK(D0i3, LSS_IMAGING) | \ - SSMSK(D0i3, LSS_SECURITY) | \ - SSMSK(D0i3, LSS_DISPLAY) | \ - SSMSK(D0i3, LSS_USB_HC) | \ - SSMSK(D0i3, LSS_USB_OTG) | \ - SSMSK(D0i3, LSS_AUDIO) | \ - SSMSK(D0i1, LSS_I2C0)) - -/* - * D0i1 on Langwell is Autonomous Clock Gating (ACG). - * Enable ACG on every LSS except camera and audio - */ -#define D0I1_ACG_SSS_TARGET \ - (SUB_SYS_ALL_D0I1 & ~SSMSK(D0i1, LSS_IMAGING) & ~SSMSK(D0i1, LSS_AUDIO)) - -enum cm_mode { - CM_NOP, /* ignore the config mode value */ - CM_IMMEDIATE, - CM_DELAY, - CM_TRIGGER, - CM_INVALID -}; - -enum sys_state { - SYS_STATE_S0I0, - SYS_STATE_S0I1, - SYS_STATE_S0I2, - SYS_STATE_S0I3, - SYS_STATE_S3, - SYS_STATE_S5 -}; - -#define SET_CFG_CMD 1 - -enum int_status { - INT_SPURIOUS = 0, - INT_CMD_DONE = 1, - INT_CMD_ERR = 2, - INT_WAKE_RX = 3, - INT_SS_ERROR = 4, - INT_S0IX_MISS = 5, - INT_NO_ACKC6 = 6, - INT_INVALID = 7, -}; - -/* PMU register interface */ -static struct mrst_pmu_reg { - u32 pm_sts; /* 0x00 */ - u32 pm_cmd; /* 0x04 */ - u32 pm_ics; /* 0x08 */ - u32 _resv1; /* 0x0C */ - u32 pm_wkc[2]; /* 0x10 */ - u32 pm_wks[2]; /* 0x18 */ - u32 pm_ssc[4]; /* 0x20 */ - u32 pm_sss[4]; /* 0x30 */ - u32 pm_wssc[4]; /* 0x40 */ - u32 pm_c3c4; /* 0x50 */ - u32 pm_c5c6; /* 0x54 */ - u32 pm_msi_disable; /* 0x58 */ -} *pmu_reg; - -static inline u32 pmu_read_sts(void) { return readl(&pmu_reg->pm_sts); } -static inline u32 pmu_read_ics(void) { return readl(&pmu_reg->pm_ics); } -static inline u32 pmu_read_wks(void) { return readl(&pmu_reg->pm_wks[0]); } -static inline u32 pmu_read_sss(void) { return readl(&pmu_reg->pm_sss[0]); } - -static inline void pmu_write_cmd(u32 arg) { writel(arg, &pmu_reg->pm_cmd); } -static inline void pmu_write_ics(u32 arg) { writel(arg, &pmu_reg->pm_ics); } -static inline void pmu_write_wkc(u32 arg) { writel(arg, &pmu_reg->pm_wkc[0]); } -static inline void pmu_write_ssc(u32 arg) { writel(arg, &pmu_reg->pm_ssc[0]); } -static inline void pmu_write_wssc(u32 arg) - { writel(arg, &pmu_reg->pm_wssc[0]); } - -static inline void pmu_msi_enable(void) { writel(0, &pmu_reg->pm_msi_disable); } -static inline u32 pmu_msi_is_disabled(void) - { return readl(&pmu_reg->pm_msi_disable); } - -union pmu_pm_ics { - struct { - u32 cause:8; - u32 enable:1; - u32 pending:1; - u32 reserved:22; - } bits; - u32 value; -}; - -static inline void pmu_irq_enable(void) -{ - union pmu_pm_ics pmu_ics; - - pmu_ics.value = pmu_read_ics(); - pmu_ics.bits.enable = 1; - pmu_write_ics(pmu_ics.value); -} - -union pmu_pm_status { - struct { - u32 pmu_rev:8; - u32 pmu_busy:1; - u32 mode_id:4; - u32 Reserved:19; - } pmu_status_parts; - u32 pmu_status_value; -}; - -static inline int pmu_read_busy_status(void) -{ - union pmu_pm_status result; - - result.pmu_status_value = pmu_read_sts(); - - return result.pmu_status_parts.pmu_busy; -} - -/* pmu set config parameters */ -struct cfg_delay_param_t { - u32 cmd:8; - u32 ioc:1; - u32 cfg_mode:4; - u32 mode_id:3; - u32 sys_state:3; - u32 cfg_delay:8; - u32 rsvd:5; -}; - -struct cfg_trig_param_t { - u32 cmd:8; - u32 ioc:1; - u32 cfg_mode:4; - u32 mode_id:3; - u32 sys_state:3; - u32 cfg_trig_type:3; - u32 cfg_trig_val:8; - u32 cmbi:1; - u32 rsvd1:1; -}; - -union pmu_pm_set_cfg_cmd_t { - union { - struct cfg_delay_param_t d_param; - struct cfg_trig_param_t t_param; - } pmu2_params; - u32 pmu_pm_set_cfg_cmd_value; -}; - -#ifdef FUTURE_PATCH -extern int mrst_s0i3_entry(u32 regval, u32 *regaddr); -#else -static inline int mrst_s0i3_entry(u32 regval, u32 *regaddr) { return -1; } -#endif -#endif diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c index 2b235b77d9ab..23e5b9d7977b 100644 --- a/arch/x86/platform/olpc/olpc-xo15-sci.c +++ b/arch/x86/platform/olpc/olpc-xo15-sci.c @@ -23,7 +23,66 @@ #define XO15_SCI_CLASS DRV_NAME #define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI" -static unsigned long xo15_sci_gpe; +static unsigned long xo15_sci_gpe; +static bool lid_wake_on_close; + +/* + * The normal ACPI LID wakeup behavior is wake-on-open, but not + * wake-on-close. This is implemented as standard by the XO-1.5 DSDT. + * + * We provide here a sysfs attribute that will additionally enable + * wake-on-close behavior. This is useful (e.g.) when we oportunistically + * suspend with the display running; if the lid is then closed, we want to + * wake up to turn the display off. + * + * This is controlled through a custom method in the XO-1.5 DSDT. + */ +static int set_lid_wake_behavior(bool wake_on_close) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = wake_on_close; + + status = acpi_evaluate_object(NULL, "\\_SB.PCI0.LID.LIDW", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + pr_warning(PFX "failed to set lid behavior\n"); + return 1; + } + + lid_wake_on_close = wake_on_close; + + return 0; +} + +static ssize_t +lid_wake_on_close_show(struct kobject *s, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", lid_wake_on_close); +} + +static ssize_t lid_wake_on_close_store(struct kobject *s, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned int val; + + if (sscanf(buf, "%u", &val) != 1) + return -EINVAL; + + set_lid_wake_behavior(!!val); + + return n; +} + +static struct kobj_attribute lid_wake_on_close_attr = + __ATTR(lid_wake_on_close, 0644, + lid_wake_on_close_show, + lid_wake_on_close_store); static void battery_status_changed(void) { @@ -91,6 +150,7 @@ static int xo15_sci_add(struct acpi_device *device) { unsigned long long tmp; acpi_status status; + int r; if (!device) return -EINVAL; @@ -112,6 +172,10 @@ static int xo15_sci_add(struct acpi_device *device) dev_info(&device->dev, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe); + r = sysfs_create_file(&device->dev.kobj, &lid_wake_on_close_attr.attr); + if (r) + goto err_sysfs; + /* Flush queue, and enable all SCI events */ process_sci_queue(); olpc_ec_mask_write(EC_SCI_SRC_ALL); @@ -123,6 +187,11 @@ static int xo15_sci_add(struct acpi_device *device) device_init_wakeup(&device->dev, true); return 0; + +err_sysfs: + acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler); + cancel_work_sync(&sci_work); + return r; } static int xo15_sci_remove(struct acpi_device *device, int type) @@ -130,6 +199,7 @@ static int xo15_sci_remove(struct acpi_device *device, int type) acpi_disable_gpe(NULL, xo15_sci_gpe); acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler); cancel_work_sync(&sci_work); + sysfs_remove_file(&device->dev.kobj, &lid_wake_on_close_attr.attr); return 0; } diff --git a/arch/x86/platform/scx200/scx200_32.c b/arch/x86/platform/scx200/scx200_32.c index 7e004acbe526..7a9ad30d6c9f 100644 --- a/arch/x86/platform/scx200/scx200_32.c +++ b/arch/x86/platform/scx200/scx200_32.c @@ -17,8 +17,6 @@ /* Verify that the configuration block really is there */ #define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base)) -#define NAME "scx200" - MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); MODULE_DESCRIPTION("NatSemi SCx200 Driver"); MODULE_LICENSE("GPL"); @@ -29,10 +27,10 @@ unsigned long scx200_gpio_shadow[2]; unsigned scx200_cb_base = 0; static struct pci_device_id scx200_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_XBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_XBUS) }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_XBUS) }, + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SC1100_XBUS) }, { }, }; MODULE_DEVICE_TABLE(pci,scx200_tbl); @@ -63,10 +61,11 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_ if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE || pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) { base = pci_resource_start(pdev, 0); - printk(KERN_INFO NAME ": GPIO base 0x%x\n", base); + pr_info("GPIO base 0x%x\n", base); - if (!request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO")) { - printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n"); + if (!request_region(base, SCx200_GPIO_SIZE, + "NatSemi SCx200 GPIO")) { + pr_err("can't allocate I/O for GPIOs\n"); return -EBUSY; } @@ -82,11 +81,11 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_ if (scx200_cb_probe(base)) { scx200_cb_base = base; } else { - printk(KERN_WARNING NAME ": Configuration Block not found\n"); + pr_warn("Configuration Block not found\n"); return -ENODEV; } } - printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base); + pr_info("Configuration Block base 0x%x\n", scx200_cb_base); } return 0; @@ -111,8 +110,7 @@ u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits) static int __init scx200_init(void) { - printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n"); - + pr_info("NatSemi SCx200 Driver\n"); return pci_register_driver(&scx200_pci_driver); } diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index 9f29a01ee1b3..5032e0d19b86 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c @@ -37,7 +37,7 @@ static void uv_rtc_timer_setup(enum clock_event_mode, static struct clocksource clocksource_uv = { .name = RTC_NAME, - .rating = 400, + .rating = 299, .read = uv_read_rtc, .mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK, .flags = CLOCK_SOURCE_IS_CONTINUOUS, @@ -379,10 +379,6 @@ static __init int uv_rtc_setup_clock(void) if (!is_uv_system()) return -ENODEV; - /* If single blade, prefer tsc */ - if (uv_num_possible_blades() == 1) - clocksource_uv.rating = 250; - rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second); if (rc) printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc); diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index f10c0afa1cb4..4889655ba784 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -20,6 +20,7 @@ #include <asm/xcr.h> #include <asm/suspend.h> #include <asm/debugreg.h> +#include <asm/fpu-internal.h> /* pcntxt_mask */ #ifdef CONFIG_X86_32 static struct saved_context saved_context; diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index bb06968be227..e36c68184920 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -75,5 +75,9 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 + +/* Instruct lower device to use last 4-bytes of skb data as FCS */ +#define SO_NOFCS 43 #endif /* _XTENSA_SOCKET_H */ diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index f2220b5bdce6..b69b000349fc 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -260,10 +260,7 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, frame)) goto badframe; @@ -336,8 +333,8 @@ gen_return_code(unsigned char *codemem) } -static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) +static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) { struct rt_sigframe *frame; int err = 0; @@ -422,12 +419,11 @@ static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, current->comm, current->pid, signal, frame, regs->pc); #endif - return; + return 0; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); + return -EFAULT; } /* @@ -449,11 +445,8 @@ asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&newset); regs->areg[2] = -EINTR; while (1) { @@ -536,17 +529,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) /* Whee! Actually deliver the signal. */ /* Set up the stack frame */ - setup_frame(signr, &ka, &info, oldset, regs); - - if (ka.sa.sa_flags & SA_ONESHOT) - ka.sa.sa_handler = SIG_DFL; + ret = setup_frame(signr, &ka, &info, oldset, regs); + if (ret) + return ret; - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); - if (!(ka.sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(&ka, signr); if (current->ptrace & PT_SINGLESTEP) task_pt_regs(current)->icountlevel = 1; |