From 3d53ceeca7bae807e5aba0935347f3757127a821 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 4 Mar 2013 17:15:19 -0800 Subject: [PATCH 0001/6183] ARM: smp: Remove duplicate dummy timer implementation Drop ARM's version of the dummy timer now that we have a generic implementation in drivers/clocksource. Acked-by: Marc Zyngier Cc: Russell King Signed-off-by: Stephen Boyd --- arch/arm/kernel/smp.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 47ab90563bf4..4dc883a77adc 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -503,24 +503,6 @@ void tick_broadcast(const struct cpumask *mask) } #endif -static void broadcast_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ -} - -static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt) -{ - evt->name = "dummy_timer"; - evt->features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_DUMMY; - evt->rating = 100; - evt->mult = 1; - evt->set_mode = broadcast_timer_set_mode; - - clockevents_register_device(evt); -} - static struct local_timer_ops *lt_ops; #ifdef CONFIG_LOCAL_TIMERS @@ -544,8 +526,8 @@ static void __cpuinit percpu_timer_setup(void) evt->cpumask = cpumask_of(cpu); - if (!lt_ops || lt_ops->setup(evt)) - broadcast_timer_setup(evt); + if (lt_ops) + lt_ops->setup(evt); } #ifdef CONFIG_HOTPLUG_CPU From a894fcc2d01a89e6fe3da0845a4d80a5312e1124 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 16:02:20 -0800 Subject: [PATCH 0002/6183] ARM: smp_twd: Divorce smp_twd from local timer API Separate the smp_twd timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Tested-by: Mark Rutland Acked-by: Marc Zyngier Cc: Russell King Cc: Tony Lindgren Signed-off-by: Stephen Boyd --- arch/arm/Kconfig | 2 +- arch/arm/kernel/smp_twd.c | 66 ++++++++++++++++++++++------------ arch/arm/mach-highbank/Kconfig | 2 +- arch/arm/mach-imx/Kconfig | 2 +- arch/arm/mach-omap2/Kconfig | 2 +- arch/arm/mach-realview/Kconfig | 8 ++--- arch/arm/mach-spear/Kconfig | 2 +- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-ux500/Kconfig | 2 +- arch/arm/mach-vexpress/Kconfig | 2 +- arch/arm/mach-zynq/Kconfig | 2 +- 11 files changed, 57 insertions(+), 35 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 53d3a356f61f..374a1d8900ec 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -638,7 +638,7 @@ config ARCH_SHMOBILE select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_CLK select HAVE_MACH_CLKDEV select HAVE_SMP diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 90525d9d290b..aac1495b44de 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include -#include /* set up by the platform code */ static void __iomem *twd_base; @@ -33,7 +33,7 @@ static struct clk *twd_clk; static unsigned long twd_timer_rate; static DEFINE_PER_CPU(bool, percpu_setup_called); -static struct clock_event_device __percpu **twd_evt; +static struct clock_event_device __percpu *twd_evt; static int twd_ppi; static void twd_set_mode(enum clock_event_mode mode, @@ -90,8 +90,10 @@ static int twd_timer_ack(void) return 0; } -static void twd_timer_stop(struct clock_event_device *clk) +static void twd_timer_stop(void) { + struct clock_event_device *clk = __this_cpu_ptr(twd_evt); + twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); disable_percpu_irq(clk->irq); } @@ -106,7 +108,7 @@ static void twd_update_frequency(void *new_rate) { twd_timer_rate = *((unsigned long *) new_rate); - clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate); + clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate); } static int twd_rate_change(struct notifier_block *nb, @@ -132,7 +134,7 @@ static struct notifier_block twd_clk_nb = { static int twd_clk_init(void) { - if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) + if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) return clk_notifier_register(twd_clk, &twd_clk_nb); return 0; @@ -151,7 +153,7 @@ static void twd_update_frequency(void *data) { twd_timer_rate = clk_get_rate(twd_clk); - clockevents_update_freq(*__this_cpu_ptr(twd_evt), twd_timer_rate); + clockevents_update_freq(__this_cpu_ptr(twd_evt), twd_timer_rate); } static int twd_cpufreq_transition(struct notifier_block *nb, @@ -177,7 +179,7 @@ static struct notifier_block twd_cpufreq_nb = { static int twd_cpufreq_init(void) { - if (twd_evt && *__this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) + if (twd_evt && __this_cpu_ptr(twd_evt) && !IS_ERR(twd_clk)) return cpufreq_register_notifier(&twd_cpufreq_nb, CPUFREQ_TRANSITION_NOTIFIER); @@ -228,7 +230,7 @@ static void __cpuinit twd_calibrate_rate(void) static irqreturn_t twd_handler(int irq, void *dev_id) { - struct clock_event_device *evt = *(struct clock_event_device **)dev_id; + struct clock_event_device *evt = dev_id; if (twd_timer_ack()) { evt->event_handler(evt); @@ -265,9 +267,9 @@ static void twd_get_clock(struct device_node *np) /* * Setup the local clock events for a CPU. */ -static int __cpuinit twd_timer_setup(struct clock_event_device *clk) +static void __cpuinit twd_timer_setup(void) { - struct clock_event_device **this_cpu_clk; + struct clock_event_device *clk = __this_cpu_ptr(twd_evt); int cpu = smp_processor_id(); /* @@ -276,9 +278,9 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk) */ if (per_cpu(percpu_setup_called, cpu)) { __raw_writel(0, twd_base + TWD_TIMER_CONTROL); - clockevents_register_device(*__this_cpu_ptr(twd_evt)); + clockevents_register_device(clk); enable_percpu_irq(clk->irq, 0); - return 0; + return; } per_cpu(percpu_setup_called, cpu) = true; @@ -297,27 +299,37 @@ static int __cpuinit twd_timer_setup(struct clock_event_device *clk) clk->set_mode = twd_set_mode; clk->set_next_event = twd_set_next_event; clk->irq = twd_ppi; - - this_cpu_clk = __this_cpu_ptr(twd_evt); - *this_cpu_clk = clk; + clk->cpumask = cpumask_of(cpu); clockevents_config_and_register(clk, twd_timer_rate, 0xf, 0xffffffff); enable_percpu_irq(clk->irq, 0); - - return 0; } -static struct local_timer_ops twd_lt_ops __cpuinitdata = { - .setup = twd_timer_setup, - .stop = twd_timer_stop, +static int __cpuinit twd_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + twd_timer_setup(); + break; + case CPU_DYING: + twd_timer_stop(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block twd_timer_cpu_nb __cpuinitdata = { + .notifier_call = twd_timer_cpu_notify, }; static int __init twd_local_timer_common_register(struct device_node *np) { int err; - twd_evt = alloc_percpu(struct clock_event_device *); + twd_evt = alloc_percpu(struct clock_event_device); if (!twd_evt) { err = -ENOMEM; goto out_free; @@ -329,12 +341,22 @@ static int __init twd_local_timer_common_register(struct device_node *np) goto out_free; } - err = local_timer_register(&twd_lt_ops); + err = register_cpu_notifier(&twd_timer_cpu_nb); if (err) goto out_irq; twd_get_clock(np); + /* + * Immediately configure the timer on the boot CPU, unless we need + * jiffies to be incrementing to calibrate the rate in which case + * setup the timer in late_time_init. + */ + if (twd_timer_rate) + twd_timer_setup(); + else + late_time_init = twd_timer_setup; + return 0; out_irq: diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig index cd9fcb1cd7ab..6acbdabf6222 100644 --- a/arch/arm/mach-highbank/Kconfig +++ b/arch/arm/mach-highbank/Kconfig @@ -12,7 +12,7 @@ config ARCH_HIGHBANK select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select MAILBOX select PL320_MBOX diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index ba44328464f3..c8adc79028b8 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -798,7 +798,7 @@ config SOC_IMX6Q select COMMON_CLK select CPU_V7 select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_CAN_FLEXCAN if CAN select HAVE_IMX_ANATOP select HAVE_IMX_GPC diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index f49cd51e162a..edb950a1af05 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -90,7 +90,7 @@ config ARCH_OMAP4 select CACHE_L2X0 select CPU_V7 select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select LOCAL_TIMERS if SMP select OMAP_INTERCONNECT diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index d210c0f9c2c4..9db2029aa632 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -13,7 +13,7 @@ config REALVIEW_EB_A9MP depends on MACH_REALVIEW_EB select CPU_V7 select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 help @@ -26,7 +26,7 @@ config REALVIEW_EB_ARM11MP select ARCH_HAS_BARRIERS if SMP select CPU_V6K select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 help @@ -48,7 +48,7 @@ config MACH_REALVIEW_PB11MP select ARM_GIC select CPU_V6K select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_PATA_PLATFORM select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 @@ -92,7 +92,7 @@ config MACH_REALVIEW_PBX select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET select ARM_GIC select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_PATA_PLATFORM select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 diff --git a/arch/arm/mach-spear/Kconfig b/arch/arm/mach-spear/Kconfig index 442917eedff3..df0d59afeb40 100644 --- a/arch/arm/mach-spear/Kconfig +++ b/arch/arm/mach-spear/Kconfig @@ -23,7 +23,7 @@ config ARCH_SPEAR13XX select CPU_V7 select GPIO_SPEAR_SPICS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 select PINCTRL diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 84d72fc36dfe..1f3ea1f6cedf 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -8,7 +8,7 @@ config ARCH_TEGRA select COMMON_CLK select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_CLK select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 6a4387e39df8..0614ee2b0523 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -8,7 +8,7 @@ config ARCH_U8500 select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 help diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 5907e10c37fd..5bfdd73dea19 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -10,7 +10,7 @@ config ARCH_VEXPRESS select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_CLK select HAVE_PATA_PLATFORM select HAVE_SMP diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index c1d61f281e68..04f8a4a6e755 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -6,7 +6,7 @@ config ARCH_ZYNQ select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select ICST select MIGHT_HAVE_CACHE_L2X0 select USE_OF From ef3160cd2f0a400751f2cf6fd2811225fee1d5a7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 4 Mar 2013 19:24:35 -0800 Subject: [PATCH 0003/6183] ARM: OMAP2+: Divorce from local timer API Now that the TWD doesn't rely on the local timer API, OMAP can stop selecting it in Kconfig and relying on the config option to decide if it should call smp_twd functions. Acked-by: Santosh Shilimkar Acked-by: Tony Lindgren Acked-by: Marc Zyngier Signed-off-by: Stephen Boyd --- arch/arm/mach-omap2/Kconfig | 1 - arch/arm/mach-omap2/timer.c | 7 ------- 2 files changed, 8 deletions(-) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index edb950a1af05..4e0049a60606 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -92,7 +92,6 @@ config ARCH_OMAP4 select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select HAVE_SMP - select LOCAL_TIMERS if SMP select OMAP_INTERCONNECT select PL310_ERRATA_588369 select PL310_ERRATA_727915 diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 4c069b0cab21..3b7cabacbcf5 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -600,7 +600,6 @@ static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon", #endif #ifdef CONFIG_ARCH_OMAP4 -#ifdef CONFIG_LOCAL_TIMERS static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); void __init omap4_local_timer_init(void) { @@ -619,12 +618,6 @@ void __init omap4_local_timer_init(void) pr_err("twd_local_timer_register failed %d\n", err); } } -#else /* CONFIG_LOCAL_TIMERS */ -void __init omap4_local_timer_init(void) -{ - omap4_sync32k_timer_init(); -} -#endif /* CONFIG_LOCAL_TIMERS */ #endif /* CONFIG_ARCH_OMAP4 */ #ifdef CONFIG_SOC_OMAP5 From ee98d27df6827b5ba4bd99cb7d5cb1239b6a1a31 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 16:40:51 -0800 Subject: [PATCH 0004/6183] ARM: EXYNOS4: Divorce mct from local timer API Separate the mct local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Acked-by: Kukjin Kim Acked-by: Marc Zyngier Cc: Thomas Abraham Signed-off-by: Stephen Boyd --- drivers/clocksource/exynos_mct.c | 60 +++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 662fcc065821..1c3f5a652044 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include -#include #include #define EXYNOS4_MCTREG(x) (x) @@ -80,7 +80,7 @@ static unsigned int mct_int_type; static int mct_irqs[MCT_NR_IRQS]; struct mct_clock_event_device { - struct clock_event_device *evt; + struct clock_event_device evt; unsigned long base; char name[10]; }; @@ -295,8 +295,6 @@ static void exynos4_clockevent_init(void) setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); } -#ifdef CONFIG_LOCAL_TIMERS - static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick); /* Clock event handling */ @@ -369,7 +367,7 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode, static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) { - struct clock_event_device *evt = mevt->evt; + struct clock_event_device *evt = &mevt->evt; /* * This is for supporting oneshot mode. @@ -391,7 +389,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) { struct mct_clock_event_device *mevt = dev_id; - struct clock_event_device *evt = mevt->evt; + struct clock_event_device *evt = &mevt->evt; exynos4_mct_tick_clear(mevt); @@ -417,8 +415,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); - mevt = this_cpu_ptr(&percpu_mct_tick); - mevt->evt = evt; + mevt = container_of(evt, struct mct_clock_event_device, evt); mevt->base = EXYNOS4_MCT_L_BASE(cpu); sprintf(mevt->name, "mct_tick%d", cpu); @@ -452,7 +449,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) return 0; } -static void exynos4_local_timer_stop(struct clock_event_device *evt) +static void __cpuinit exynos4_local_timer_stop(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); @@ -465,14 +462,37 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt) disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); } -static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { - .setup = exynos4_local_timer_setup, - .stop = exynos4_local_timer_stop, +static int __cpuinit exynos4_mct_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + struct mct_clock_event_device *mevt; + + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + mevt = this_cpu_ptr(&percpu_mct_tick); + exynos4_local_timer_setup(&mevt->evt); + break; + case CPU_DYING: + mevt = this_cpu_ptr(&percpu_mct_tick); + exynos4_local_timer_stop(&mevt->evt); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos4_mct_cpu_nb __cpuinitdata = { + .notifier_call = exynos4_mct_cpu_notify, }; -#endif /* CONFIG_LOCAL_TIMERS */ static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base) { + int err; + struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); struct clk *mct_clk, *tick_clk; tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : @@ -490,9 +510,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem if (!reg_base) panic("%s: unable to ioremap mct address space\n", __func__); -#ifdef CONFIG_LOCAL_TIMERS if (mct_int_type == MCT_INT_PPI) { - int err; err = request_percpu_irq(mct_irqs[MCT_L0_IRQ], exynos4_mct_tick_isr, "MCT", @@ -501,8 +519,16 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem mct_irqs[MCT_L0_IRQ], err); } - local_timer_register(&exynos4_mct_tick_ops); -#endif /* CONFIG_LOCAL_TIMERS */ + err = register_cpu_notifier(&exynos4_mct_cpu_nb); + if (err) + goto out_irq; + + /* Immediately configure the timer on the boot CPU */ + exynos4_local_timer_setup(&mevt->evt); + return; + +out_irq: + free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); } void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1) From 05a6548556d007143fcb291bfdfa6b2bb3e63e95 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 17:02:16 -0800 Subject: [PATCH 0005/6183] ARM: PRIMA2: Divorce timer-marco from local timer API Separate the marco local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Acked-by: Marc Zyngier Cc: Barry Song Signed-off-by: Stephen Boyd --- drivers/clocksource/timer-marco.c | 96 +++++++++++++++++-------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index e5dc9129ca26..01b9683557b2 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include #define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000 @@ -151,13 +151,7 @@ static void sirfsoc_clocksource_resume(struct clocksource *cs) BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL); } -static struct clock_event_device sirfsoc_clockevent = { - .name = "sirfsoc_clockevent", - .rating = 200, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sirfsoc_timer_set_mode, - .set_next_event = sirfsoc_timer_set_next_event, -}; +static struct clock_event_device __percpu *sirfsoc_clockevent; static struct clocksource sirfsoc_clocksource = { .name = "sirfsoc_clocksource", @@ -173,11 +167,8 @@ static struct irqaction sirfsoc_timer_irq = { .name = "sirfsoc_timer0", .flags = IRQF_TIMER | IRQF_NOBALANCING, .handler = sirfsoc_timer_interrupt, - .dev_id = &sirfsoc_clockevent, }; -#ifdef CONFIG_LOCAL_TIMERS - static struct irqaction sirfsoc_timer1_irq = { .name = "sirfsoc_timer1", .flags = IRQF_TIMER | IRQF_NOBALANCING, @@ -186,56 +177,77 @@ static struct irqaction sirfsoc_timer1_irq = { static int __cpuinit sirfsoc_local_timer_setup(struct clock_event_device *ce) { - /* Use existing clock_event for cpu 0 */ - if (!smp_processor_id()) - return 0; + int cpu = smp_processor_id(); + struct irqaction *action; - ce->irq = sirfsoc_timer1_irq.irq; + if (cpu == 0) + action = &sirfsoc_timer_irq; + else + action = &sirfsoc_timer1_irq; + + ce->irq = action->irq; ce->name = "local_timer"; - ce->features = sirfsoc_clockevent.features; - ce->rating = sirfsoc_clockevent.rating; + ce->features = CLOCK_EVT_FEAT_ONESHOT; + ce->rating = 200; ce->set_mode = sirfsoc_timer_set_mode; ce->set_next_event = sirfsoc_timer_set_next_event; - ce->shift = sirfsoc_clockevent.shift; - ce->mult = sirfsoc_clockevent.mult; - ce->max_delta_ns = sirfsoc_clockevent.max_delta_ns; - ce->min_delta_ns = sirfsoc_clockevent.min_delta_ns; + clockevents_calc_mult_shift(ce, CLOCK_TICK_RATE, 60); + ce->max_delta_ns = clockevent_delta2ns(-2, ce); + ce->min_delta_ns = clockevent_delta2ns(2, ce); + ce->cpumask = cpumask_of(cpu); - sirfsoc_timer1_irq.dev_id = ce; - BUG_ON(setup_irq(ce->irq, &sirfsoc_timer1_irq)); - irq_set_affinity(sirfsoc_timer1_irq.irq, cpumask_of(1)); + action->dev_id = ce; + BUG_ON(setup_irq(ce->irq, action)); + irq_set_affinity(action->irq, cpumask_of(cpu)); clockevents_register_device(ce); return 0; } -static void sirfsoc_local_timer_stop(struct clock_event_device *ce) +static void __cpuinit sirfsoc_local_timer_stop(struct clock_event_device *ce) { + int cpu = smp_processor_id(); + sirfsoc_timer_count_disable(1); - remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); + if (cpu == 0) + remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq); + else + remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq); } -static struct local_timer_ops sirfsoc_local_timer_ops __cpuinitdata = { - .setup = sirfsoc_local_timer_setup, - .stop = sirfsoc_local_timer_stop, +static int __cpuinit sirfsoc_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); + break; + case CPU_DYING: + sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block sirfsoc_cpu_nb __cpuinitdata = { + .notifier_call = sirfsoc_cpu_notify, }; -#endif /* CONFIG_LOCAL_TIMERS */ static void __init sirfsoc_clockevent_init(void) { - clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60); + sirfsoc_clockevent = alloc_percpu(struct clock_event_device); + BUG_ON(!sirfsoc_clockevent); - sirfsoc_clockevent.max_delta_ns = - clockevent_delta2ns(-2, &sirfsoc_clockevent); - sirfsoc_clockevent.min_delta_ns = - clockevent_delta2ns(2, &sirfsoc_clockevent); + BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb)); - sirfsoc_clockevent.cpumask = cpumask_of(0); - clockevents_register_device(&sirfsoc_clockevent); -#ifdef CONFIG_LOCAL_TIMERS - local_timer_register(&sirfsoc_local_timer_ops); -#endif + /* Immediately configure the timer on the boot CPU */ + sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent)); } /* initialize the kernel jiffy timer source */ @@ -273,8 +285,6 @@ static void __init sirfsoc_marco_timer_init(void) BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); - BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); - sirfsoc_clockevent_init(); } @@ -288,11 +298,9 @@ static void __init sirfsoc_of_timer_init(struct device_node *np) if (!sirfsoc_timer_irq.irq) panic("No irq passed for timer0 via DT\n"); -#ifdef CONFIG_LOCAL_TIMERS sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1); if (!sirfsoc_timer1_irq.irq) panic("No irq passed for timer1 via DT\n"); -#endif sirfsoc_marco_timer_init(); } From 4d70c59bb5be9e41a06b9f11ecfba75c14f9fea7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 17:31:31 -0800 Subject: [PATCH 0006/6183] ARM: msm: Divorce msm_timer from local timer API Separate the msm_timer from the local timer API. This will allow us to remove ARM local timer support in the near future and gets us closer to moving this driver to drivers/clocksource. Acked-by: David Brown Acked-by: Marc Zyngier Cc: Daniel Walker Cc: Bryan Huntsman Signed-off-by: Stephen Boyd --- arch/arm/mach-msm/timer.c | 128 +++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 57 deletions(-) diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index b6418fd5fe0d..dacdcfdbc342 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include -#include #include "common.h" @@ -49,7 +49,7 @@ static void __iomem *sts_base; static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { - struct clock_event_device *evt = *(struct clock_event_device **)dev_id; + struct clock_event_device *evt = dev_id; /* Stop the timer tick */ if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); @@ -101,18 +101,7 @@ static void msm_timer_set_mode(enum clock_event_mode mode, writel_relaxed(ctrl, event_base + TIMER_ENABLE); } -static struct clock_event_device msm_clockevent = { - .name = "gp_timer", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = msm_timer_set_next_event, - .set_mode = msm_timer_set_mode, -}; - -static union { - struct clock_event_device *evt; - struct clock_event_device * __percpu *percpu_evt; -} msm_evt; +static struct clock_event_device __percpu *msm_evt; static void __iomem *source_base; @@ -138,37 +127,65 @@ static struct clocksource msm_clocksource = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#ifdef CONFIG_LOCAL_TIMERS +static int msm_timer_irq; +static int msm_timer_has_ppi; + static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt) { - /* Use existing clock_event for cpu 0 */ - if (!smp_processor_id()) - return 0; + int cpu = smp_processor_id(); + int err; - evt->irq = msm_clockevent.irq; - evt->name = "local_timer"; - evt->features = msm_clockevent.features; - evt->rating = msm_clockevent.rating; + evt->irq = msm_timer_irq; + evt->name = "msm_timer"; + evt->features = CLOCK_EVT_FEAT_ONESHOT; + evt->rating = 200; evt->set_mode = msm_timer_set_mode; evt->set_next_event = msm_timer_set_next_event; + evt->cpumask = cpumask_of(cpu); + + clockevents_config_and_register(evt, GPT_HZ, 4, 0xffffffff); + + if (msm_timer_has_ppi) { + enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); + } else { + err = request_irq(evt->irq, msm_timer_interrupt, + IRQF_TIMER | IRQF_NOBALANCING | + IRQF_TRIGGER_RISING, "gp_timer", evt); + if (err) + pr_err("request_irq failed\n"); + } - *__this_cpu_ptr(msm_evt.percpu_evt) = evt; - clockevents_config_and_register(evt, GPT_HZ, 4, 0xf0000000); - enable_percpu_irq(evt->irq, IRQ_TYPE_EDGE_RISING); return 0; } -static void msm_local_timer_stop(struct clock_event_device *evt) +static void __cpuinit msm_local_timer_stop(struct clock_event_device *evt) { evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); disable_percpu_irq(evt->irq); } -static struct local_timer_ops msm_local_timer_ops __cpuinitdata = { - .setup = msm_local_timer_setup, - .stop = msm_local_timer_stop, +static int __cpuinit msm_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + msm_local_timer_setup(this_cpu_ptr(msm_evt)); + break; + case CPU_DYING: + msm_local_timer_stop(this_cpu_ptr(msm_evt)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block msm_timer_cpu_nb __cpuinitdata = { + .notifier_call = msm_timer_cpu_notify, }; -#endif /* CONFIG_LOCAL_TIMERS */ static notrace u32 msm_sched_clock_read(void) { @@ -178,38 +195,35 @@ static notrace u32 msm_sched_clock_read(void) static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, bool percpu) { - struct clock_event_device *ce = &msm_clockevent; struct clocksource *cs = &msm_clocksource; - int res; + int res = 0; - ce->cpumask = cpumask_of(0); - ce->irq = irq; + msm_timer_irq = irq; + msm_timer_has_ppi = percpu; - clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff); - if (percpu) { - msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); - if (!msm_evt.percpu_evt) { - pr_err("memory allocation failed for %s\n", ce->name); - goto err; - } - *__this_cpu_ptr(msm_evt.percpu_evt) = ce; - res = request_percpu_irq(ce->irq, msm_timer_interrupt, - ce->name, msm_evt.percpu_evt); - if (!res) { - enable_percpu_irq(ce->irq, IRQ_TYPE_EDGE_RISING); -#ifdef CONFIG_LOCAL_TIMERS - local_timer_register(&msm_local_timer_ops); -#endif - } - } else { - msm_evt.evt = ce; - res = request_irq(ce->irq, msm_timer_interrupt, - IRQF_TIMER | IRQF_NOBALANCING | - IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt); + msm_evt = alloc_percpu(struct clock_event_device); + if (!msm_evt) { + pr_err("memory allocation failed for clockevents\n"); + goto err; + } + + if (percpu) + res = request_percpu_irq(irq, msm_timer_interrupt, + "gp_timer", msm_evt); + + if (res) { + pr_err("request_percpu_irq failed\n"); + } else { + res = register_cpu_notifier(&msm_timer_cpu_nb); + if (res) { + free_percpu_irq(irq, msm_evt); + goto err; + } + + /* Immediately configure the timer on the boot CPU */ + msm_local_timer_setup(__this_cpu_ptr(msm_evt)); } - if (res) - pr_err("request_irq failed for %s\n", ce->name); err: writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); res = clocksource_register_hz(cs, dgt_hz); From faef31b482549640e2d0095afdf3dedb992cfa80 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 21 Feb 2013 15:04:08 -0800 Subject: [PATCH 0007/6183] clocksource: time-armada-370-xp: Fix sparse warning drivers/clocksource/time-armada-370-xp.c:217:13: warning: symbol 'armada_370_xp_timer_init' was not declared. Should it be static? Also remove the __init marking in the prototype as it's unnecessary and drop the init.h file. Acked-by: Gregory CLEMENT Acked-by: Marc Zyngier Signed-off-by: Stephen Boyd --- drivers/clocksource/time-armada-370-xp.c | 3 ++- include/linux/time-armada-370-xp.h | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index efdca3263afe..b1e1d92a8839 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -28,9 +28,10 @@ #include #include #include +#include +#include #include -#include /* * Timer block registers. */ diff --git a/include/linux/time-armada-370-xp.h b/include/linux/time-armada-370-xp.h index dfdfdc03115b..6fb0856b9405 100644 --- a/include/linux/time-armada-370-xp.h +++ b/include/linux/time-armada-370-xp.h @@ -11,8 +11,6 @@ #ifndef __TIME_ARMADA_370_XPPRCMU_H #define __TIME_ARMADA_370_XPPRCMU_H -#include - -void __init armada_370_xp_timer_init(void); +void armada_370_xp_timer_init(void); #endif From 5ddb6d21c30d10ae4a740a788bb9101bd384fea5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 17:02:16 -0800 Subject: [PATCH 0008/6183] clocksource: time-armada-370-xp: Divorce from local timer API Separate the armada 370xp local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and makes this driver multi-architecture friendly. Acked-by: Gregory CLEMENT Tested-by: Gregory CLEMENT Acked-by: Marc Zyngier Signed-off-by: Stephen Boyd --- drivers/clocksource/time-armada-370-xp.c | 89 +++++++++++------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index b1e1d92a8839..f86542002ee1 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include -#include /* * Timer block registers. */ @@ -70,7 +70,7 @@ static bool timer25Mhz = true; */ static u32 ticks_per_jiffy; -static struct clock_event_device __percpu **percpu_armada_370_xp_evt; +static struct clock_event_device __percpu *armada_370_xp_evt; static u32 notrace armada_370_xp_read_sched_clock(void) { @@ -143,21 +143,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, } } -static struct clock_event_device armada_370_xp_clkevt = { - .name = "armada_370_xp_per_cpu_tick", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 32, - .rating = 300, - .set_next_event = armada_370_xp_clkevt_next_event, - .set_mode = armada_370_xp_clkevt_mode, -}; +static int armada_370_xp_clkevt_irq; static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) { /* * ACK timer interrupt and call event handler. */ - struct clock_event_device *evt = *(struct clock_event_device **)dev_id; + struct clock_event_device *evt = dev_id; writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); evt->event_handler(evt); @@ -173,42 +166,55 @@ static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt) u32 u; int cpu = smp_processor_id(); - /* Use existing clock_event for cpu 0 */ - if (!smp_processor_id()) - return 0; - u = readl(local_base + TIMER_CTRL_OFF); if (timer25Mhz) writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); else writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); - evt->name = armada_370_xp_clkevt.name; - evt->irq = armada_370_xp_clkevt.irq; - evt->features = armada_370_xp_clkevt.features; - evt->shift = armada_370_xp_clkevt.shift; - evt->rating = armada_370_xp_clkevt.rating, + evt->name = "armada_370_xp_per_cpu_tick", + evt->features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC; + evt->shift = 32, + evt->rating = 300, evt->set_next_event = armada_370_xp_clkevt_next_event, evt->set_mode = armada_370_xp_clkevt_mode, + evt->irq = armada_370_xp_clkevt_irq; evt->cpumask = cpumask_of(cpu); - *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt; - clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); enable_percpu_irq(evt->irq, 0); return 0; } -static void armada_370_xp_timer_stop(struct clock_event_device *evt) +static void __cpuinit armada_370_xp_timer_stop(struct clock_event_device *evt) { evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); disable_percpu_irq(evt->irq); } -static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { - .setup = armada_370_xp_timer_setup, - .stop = armada_370_xp_timer_stop, +static int __cpuinit armada_370_xp_timer_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + /* + * Grab cpu pointer in each case to avoid spurious + * preemptible warnings + */ + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); + break; + case CPU_DYING: + armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block armada_370_xp_timer_cpu_nb __cpuinitdata = { + .notifier_call = armada_370_xp_timer_cpu_notify, }; void __init armada_370_xp_timer_init(void) @@ -224,9 +230,6 @@ void __init armada_370_xp_timer_init(void) if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { /* The fixed 25MHz timer is available so let's use it */ - u = readl(local_base + TIMER_CTRL_OFF); - writel(u | TIMER0_25MHZ, - local_base + TIMER_CTRL_OFF); u = readl(timer_base + TIMER_CTRL_OFF); writel(u | TIMER0_25MHZ, timer_base + TIMER_CTRL_OFF); @@ -236,9 +239,6 @@ void __init armada_370_xp_timer_init(void) struct clk *clk = of_clk_get(np, 0); WARN_ON(IS_ERR(clk)); rate = clk_get_rate(clk); - u = readl(local_base + TIMER_CTRL_OFF); - writel(u & ~(TIMER0_25MHZ), - local_base + TIMER_CTRL_OFF); u = readl(timer_base + TIMER_CTRL_OFF); writel(u & ~(TIMER0_25MHZ), @@ -252,7 +252,7 @@ void __init armada_370_xp_timer_init(void) * We use timer 0 as clocksource, and private(local) timer 0 * for clockevents */ - armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4); + armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4); ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; @@ -277,26 +277,19 @@ void __init armada_370_xp_timer_init(void) "armada_370_xp_clocksource", timer_clk, 300, 32, clocksource_mmio_readl_down); - /* Register the clockevent on the private timer of CPU 0 */ - armada_370_xp_clkevt.cpumask = cpumask_of(0); - clockevents_config_and_register(&armada_370_xp_clkevt, - timer_clk, 1, 0xfffffffe); + register_cpu_notifier(&armada_370_xp_timer_cpu_nb); - percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *); + armada_370_xp_evt = alloc_percpu(struct clock_event_device); /* * Setup clockevent timer (interrupt-driven). */ - *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt; - res = request_percpu_irq(armada_370_xp_clkevt.irq, + res = request_percpu_irq(armada_370_xp_clkevt_irq, armada_370_xp_timer_interrupt, - armada_370_xp_clkevt.name, - percpu_armada_370_xp_evt); - if (!res) { - enable_percpu_irq(armada_370_xp_clkevt.irq, 0); -#ifdef CONFIG_LOCAL_TIMERS - local_timer_register(&armada_370_xp_local_timer_ops); -#endif - } + "armada_370_xp_per_cpu_tick", + armada_370_xp_evt); + /* Immediately configure the timer on the boot CPU */ + if (!res) + armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); } From 060fd3043e5e3488504b9e70182e188dd9113aea Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Feb 2013 17:35:19 -0800 Subject: [PATCH 0009/6183] ARM: smp: Remove local timer API There are no more users of this API, remove it. Acked-by: Tony Lindgren Acked-by: Marc Zyngier Cc: Russell King Signed-off-by: Stephen Boyd --- arch/arm/Kconfig | 10 ----- arch/arm/include/asm/localtimer.h | 34 --------------- arch/arm/kernel/smp.c | 69 ------------------------------- 3 files changed, 113 deletions(-) delete mode 100644 arch/arm/include/asm/localtimer.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 374a1d8900ec..46fa88091631 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1544,16 +1544,6 @@ config ARM_PSCI 0022A ("Power State Coordination Interface System Software on ARM processors"). -config LOCAL_TIMERS - bool "Use local timer interrupts" - depends on SMP - default y - help - Enable support for local timers on SMP platforms, rather then the - legacy IPI broadcast method. Local timers allows the system - accounting to be spread across the timer interval, preventing a - "thundering herd" at every timer tick. - # The GPIO number here must be sorted by descending number. In case of # a multiplatform kernel, we just want the highest value required by the # selected platforms. diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h deleted file mode 100644 index f77ffc1eb0c2..000000000000 --- a/arch/arm/include/asm/localtimer.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * arch/arm/include/asm/localtimer.h - * - * Copyright (C) 2004-2005 ARM Ltd. - * - * 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. - */ -#ifndef __ASM_ARM_LOCALTIMER_H -#define __ASM_ARM_LOCALTIMER_H - -#include - -struct clock_event_device; - -struct local_timer_ops { - int (*setup)(struct clock_event_device *); - void (*stop)(struct clock_event_device *); -}; - -#ifdef CONFIG_LOCAL_TIMERS -/* - * Register a local timer driver - */ -int local_timer_register(struct local_timer_ops *); -#else -static inline int local_timer_register(struct local_timer_ops *ops) -{ - return -ENXIO; -} -#endif - -#endif diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 4dc883a77adc..54aa994c4b20 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -133,8 +132,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) } #ifdef CONFIG_HOTPLUG_CPU -static void percpu_timer_stop(void); - static int platform_cpu_kill(unsigned int cpu) { if (smp_ops.cpu_kill) @@ -177,11 +174,6 @@ int __cpuinit __cpu_disable(void) */ migrate_irqs(); - /* - * Stop the local timer for this CPU. - */ - percpu_timer_stop(); - /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. @@ -303,8 +295,6 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid) store_cpu_topology(cpuid); } -static void percpu_timer_setup(void); - /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. @@ -359,11 +349,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) set_cpu_online(cpu, true); complete(&cpu_running); - /* - * Setup the percpu timer for this CPU. - */ - percpu_timer_setup(); - local_irq_enable(); local_fiq_enable(); @@ -409,12 +394,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (max_cpus > ncores) max_cpus = ncores; if (ncores > 1 && max_cpus) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. A platform should @@ -491,11 +470,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu) return sum; } -/* - * Timer (local or broadcast) support - */ -static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); - #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST void tick_broadcast(const struct cpumask *mask) { @@ -503,49 +477,6 @@ void tick_broadcast(const struct cpumask *mask) } #endif -static struct local_timer_ops *lt_ops; - -#ifdef CONFIG_LOCAL_TIMERS -int local_timer_register(struct local_timer_ops *ops) -{ - if (!is_smp() || !setup_max_cpus) - return -ENXIO; - - if (lt_ops) - return -EBUSY; - - lt_ops = ops; - return 0; -} -#endif - -static void __cpuinit percpu_timer_setup(void) -{ - unsigned int cpu = smp_processor_id(); - struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); - - evt->cpumask = cpumask_of(cpu); - - if (lt_ops) - lt_ops->setup(evt); -} - -#ifdef CONFIG_HOTPLUG_CPU -/* - * The generic clock events code purposely does not stop the local timer - * on CPU_DEAD/CPU_DEAD_FROZEN hotplug events, so we have to do it - * manually here. - */ -static void percpu_timer_stop(void) -{ - unsigned int cpu = smp_processor_id(); - struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); - - if (lt_ops) - lt_ops->stop(evt); -} -#endif - static DEFINE_RAW_SPINLOCK(stop_lock); /* From 00e55a790706223c903ce6a450c18596a7bc9be0 Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Fri, 28 Jun 2013 04:50:45 -0700 Subject: [PATCH 0010/6183] x86: Use asm-goto to implement mutex fast path on x86-64 The new implementation allows the compiler to better optimize the code; the original implementation is still used when the kernel is compiled with older versions of gcc that don't support asm-goto. Compiling with gcc 4.7.3, the original mutex_lock() is 60 bytes with the fast path taking 16 instructions; the new mutex_lock() is 42 bytes, with the fast path taking 12 instructions. The original mutex_unlock() is 24 bytes with the fast path taking 7 instructions; the new mutex_unlock() is 25 bytes (because the compiler used a 2-byte ret) with the fast path taking 4 instructions. The two versions of the functions are included below for reference. Old: ffffffff817742a0 : ffffffff817742a0: 55 push %rbp ffffffff817742a1: 48 89 e5 mov %rsp,%rbp ffffffff817742a4: 48 83 ec 10 sub $0x10,%rsp ffffffff817742a8: 48 89 5d f0 mov %rbx,-0x10(%rbp) ffffffff817742ac: 48 89 fb mov %rdi,%rbx ffffffff817742af: 4c 89 65 f8 mov %r12,-0x8(%rbp) ffffffff817742b3: e8 28 15 00 00 callq ffffffff817757e0 <_cond_resched> ffffffff817742b8: 48 89 df mov %rbx,%rdi ffffffff817742bb: f0 ff 0f lock decl (%rdi) ffffffff817742be: 79 05 jns ffffffff817742c5 ffffffff817742c0: e8 cb 04 00 00 callq ffffffff81774790 <__mutex_lock_slowpath> ffffffff817742c5: 65 48 8b 04 25 c0 b7 mov %gs:0xb7c0,%rax ffffffff817742cc: 00 00 ffffffff817742ce: 4c 8b 65 f8 mov -0x8(%rbp),%r12 ffffffff817742d2: 48 89 43 18 mov %rax,0x18(%rbx) ffffffff817742d6: 48 8b 5d f0 mov -0x10(%rbp),%rbx ffffffff817742da: c9 leaveq ffffffff817742db: c3 retq ffffffff81774250 : ffffffff81774250: 55 push %rbp ffffffff81774251: 48 c7 47 18 00 00 00 movq $0x0,0x18(%rdi) ffffffff81774258: 00 ffffffff81774259: 48 89 e5 mov %rsp,%rbp ffffffff8177425c: f0 ff 07 lock incl (%rdi) ffffffff8177425f: 7f 05 jg ffffffff81774266 ffffffff81774261: e8 ea 04 00 00 callq ffffffff81774750 <__mutex_unlock_slowpath> ffffffff81774266: 5d pop %rbp ffffffff81774267: c3 retq New: ffffffff81774920 : ffffffff81774920: 55 push %rbp ffffffff81774921: 48 89 e5 mov %rsp,%rbp ffffffff81774924: 53 push %rbx ffffffff81774925: 48 89 fb mov %rdi,%rbx ffffffff81774928: e8 a3 0e 00 00 callq ffffffff817757d0 <_cond_resched> ffffffff8177492d: f0 ff 0b lock decl (%rbx) ffffffff81774930: 79 08 jns ffffffff8177493a ffffffff81774932: 48 89 df mov %rbx,%rdi ffffffff81774935: e8 16 fe ff ff callq ffffffff81774750 <__mutex_lock_slowpath> ffffffff8177493a: 65 48 8b 04 25 c0 b7 mov %gs:0xb7c0,%rax ffffffff81774941: 00 00 ffffffff81774943: 48 89 43 18 mov %rax,0x18(%rbx) ffffffff81774947: 5b pop %rbx ffffffff81774948: 5d pop %rbp ffffffff81774949: c3 retq ffffffff81774730 : ffffffff81774730: 48 c7 47 18 00 00 00 movq $0x0,0x18(%rdi) ffffffff81774737: 00 ffffffff81774738: f0 ff 07 lock incl (%rdi) ffffffff8177473b: 7f 0a jg ffffffff81774747 ffffffff8177473d: 55 push %rbp ffffffff8177473e: 48 89 e5 mov %rsp,%rbp ffffffff81774741: e8 aa ff ff ff callq ffffffff817746f0 <__mutex_unlock_slowpath> ffffffff81774746: 5d pop %rbp ffffffff81774747: f3 c3 repz retq Signed-off-by: Wedson Almeida Filho Link: http://lkml.kernel.org/r/1372420245-60021-1-git-send-email-wedsonaf@gmail.com Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/mutex_64.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/x86/include/asm/mutex_64.h b/arch/x86/include/asm/mutex_64.h index 68a87b0f8e29..c030bee7690a 100644 --- a/arch/x86/include/asm/mutex_64.h +++ b/arch/x86/include/asm/mutex_64.h @@ -16,6 +16,20 @@ * * Atomically decrements @v and calls if the result is negative. */ +#ifdef CC_HAVE_ASM_GOTO +static inline void __mutex_fastpath_lock(atomic_t *v, + void (*fail_fn)(atomic_t *)) +{ + asm volatile goto(LOCK_PREFIX " decl %0\n" + " jns %l[exit]\n" + : : "m" (v->counter) + : "memory", "cc" + : exit); + fail_fn(v); +exit: + return; +} +#else #define __mutex_fastpath_lock(v, fail_fn) \ do { \ unsigned long dummy; \ @@ -32,6 +46,7 @@ do { \ : "rax", "rsi", "rdx", "rcx", \ "r8", "r9", "r10", "r11", "memory"); \ } while (0) +#endif /** * __mutex_fastpath_lock_retval - try to take the lock by moving the count @@ -59,6 +74,20 @@ static inline int __mutex_fastpath_lock_retval(atomic_t *count, * * Atomically increments @v and calls if the result is nonpositive. */ +#ifdef CC_HAVE_ASM_GOTO +static inline void __mutex_fastpath_unlock(atomic_t *v, + void (*fail_fn)(atomic_t *)) +{ + asm volatile goto(LOCK_PREFIX " incl %0\n" + " jg %l[exit]\n" + : : "m" (v->counter) + : "memory", "cc" + : exit); + fail_fn(v); +exit: + return; +} +#else #define __mutex_fastpath_unlock(v, fail_fn) \ do { \ unsigned long dummy; \ @@ -75,6 +104,7 @@ do { \ : "rax", "rsi", "rdx", "rcx", \ "r8", "r9", "r10", "r11", "memory"); \ } while (0) +#endif #define __mutex_slowpath_needs_to_unlock() 1 From 62122fd7dadac09704782d8bc051fb898a0272bd Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 28 Jun 2013 18:41:41 +0200 Subject: [PATCH 0011/6183] x86, cpufeature: Use new CC_HAVE_ASM_GOTO ... for checking for "asm goto" compiler support. It is more explicit this way and we cover the cases where distros have backported that support even to gcc versions < 4.5. Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1372437701-13351-1-git-send-email-bp@alien8.de Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/cpufeature.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 47538a61c91b..d3f5c63078d8 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -366,9 +366,10 @@ extern bool __static_cpu_has_safe(u16 bit); */ static __always_inline __pure bool __static_cpu_has(u16 bit) { -#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5 +#ifdef CC_HAVE_ASM_GOTO #ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS + /* * Catch too early usage of this before alternatives * have run. @@ -384,6 +385,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) ".previous\n" /* skipping size check since replacement size = 0 */ : : "i" (X86_FEATURE_ALWAYS) : : t_warn); + #endif asm goto("1: jmp %l[t_no]\n" @@ -406,7 +408,9 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) warn_pre_alternatives(); return false; #endif -#else /* GCC_VERSION >= 40500 */ + +#else /* CC_HAVE_ASM_GOTO */ + u8 flag; /* Open-coded due to __stringify() in ALTERNATIVE() */ asm volatile("1: movb $0,%0\n" @@ -427,7 +431,8 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) ".previous\n" : "=qm" (flag) : "i" (bit)); return flag; -#endif + +#endif /* CC_HAVE_ASM_GOTO */ } #define static_cpu_has(bit) \ @@ -441,7 +446,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) static __always_inline __pure bool _static_cpu_has_safe(u16 bit) { -#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5 +#ifdef CC_HAVE_ASM_GOTO /* * We need to spell the jumps to the compiler because, depending on the offset, * the replacement jump can be bigger than the original jump, and this we cannot @@ -475,7 +480,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit) return false; t_dynamic: return __static_cpu_has_safe(bit); -#else /* GCC_VERSION >= 40500 */ +#else u8 flag; /* Open-coded due to __stringify() in ALTERNATIVE() */ asm volatile("1: movb $2,%0\n" @@ -511,7 +516,7 @@ static __always_inline __pure bool _static_cpu_has_safe(u16 bit) : "=qm" (flag) : "i" (bit), "i" (X86_FEATURE_ALWAYS)); return (flag == 2 ? __static_cpu_has_safe(bit) : flag); -#endif +#endif /* CC_HAVE_ASM_GOTO */ } #define static_cpu_has_safe(bit) \ From 237d1548543312fcc8c99d302ab68fbf8ef6f97f Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Fri, 28 Jun 2013 22:45:16 +0800 Subject: [PATCH 0012/6183] x86: Fix override new_cpu_data.x86 with 486 We should set X86 to 486 before use cpuid to detect the cpu type, if we set X86 to 486 after cpuid, then we will get 486 until cpu_detect runs. Signed-off-by: Wang YanQing Link: http://lkml.kernel.org/r/20130628144516.GA2177@udknight Acked-by: Borislav Petkov Signed-off-by: H. Peter Anvin --- arch/x86/kernel/head_32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index e65ddc62e113..fe79573c84b9 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -410,6 +410,7 @@ enable_paging: /* * Check if it is 486 */ + movb $4,X86 # at least 486 cmpl $-1,X86_CPUID je is486 @@ -437,7 +438,6 @@ enable_paging: movl %edx,X86_CAPABILITY is486: - movb $4,X86 movl $0x50022,%ecx # set AM, WP, NE and MP movl %cr0,%eax andl $0x80000011,%eax # Save PG,PE,ET From 6cdcb5e73fba29bf115f2677c59de63f95039e2b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:29 -0300 Subject: [PATCH 0013/6183] drm/i915: invert the verbosity of intel_enable_fbc We currently print a DRM_DEBUG_KMS message on the happy path and don't print anything on the "failed to allocate" path. On some desktop environments (e.g., Unity) I see the "scheduling delayed FBC enable" thousands and thousands of times on my dmesg. So kill the useless message for the happy case, saving a lot of dmesg space, and properly signal the "kzalloc fail" case. Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ccbdd83f5220..346bde1edc0e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -381,6 +381,7 @@ void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) work = kzalloc(sizeof *work, GFP_KERNEL); if (work == NULL) { + DRM_ERROR("Failed to allocate FBC work structure\n"); dev_priv->display.enable_fbc(crtc, interval); return; } @@ -392,8 +393,6 @@ void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dev_priv->fbc_work = work; - DRM_DEBUG_KMS("scheduling delayed FBC enable\n"); - /* Delay the actual enabling to let pageflipping cease and the * display to settle before starting the compression. Note that * this delay also serves a second purpose: it allows for a From b63fb44c65ac37ceac8acd258939fcdc9f223c42 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 16:22:01 +0100 Subject: [PATCH 0014/6183] drm/i915: Make intel_enable_fbc() static This function has no user outside of intel_pm.c. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_pm.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c8c9b6f48230..8eeee74f3d91 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -780,7 +780,6 @@ extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, extern void intel_init_pm(struct drm_device *dev); /* FBC */ extern bool intel_fbc_enabled(struct drm_device *dev); -extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern void intel_update_fbc(struct drm_device *dev); /* IPS */ extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 346bde1edc0e..e0de8b3337d8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -368,7 +368,7 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) dev_priv->fbc_work = NULL; } -void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct intel_fbc_work *work; struct drm_device *dev = crtc->dev; From 8a5729a37375c20a196e14ce49b4390d42bdb87b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 16:22:02 +0100 Subject: [PATCH 0015/6183] drm/i915: Fix reason for per-chip disabling of FBC When running on my snb machine, recent kernels display successively: [drm:intel_update_fbc], fbc set to per-chip default [drm:intel_update_fbc], fbc disabled per module param But no module param is set. This happens because the check for the module parameter uses a variable that has been overridden inside the "per-chip default" code. Fix up the logic and add another reason for the FBC to the be disabled. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 14 ++++++-------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 47d6c748057e..dca49828e3fc 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1518,6 +1518,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) case FBC_MODULE_PARAM: seq_printf(m, "disabled per module param (default off)"); break; + case FBC_CHIP_DEFAULT: + seq_printf(m, "disabled per chip default"); + break; default: seq_printf(m, "unknown reason"); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cc1d6056ab70..59c45f293ec9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -537,6 +537,7 @@ enum no_fbc_reason { FBC_NOT_TILED, /* buffer not tiled */ FBC_MULTIPLE_PIPES, /* more than one pipe active */ FBC_MODULE_PARAM, + FBC_CHIP_DEFAULT, /* disabled by default on this chip */ }; enum intel_pch { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e0de8b3337d8..adc7f3eb4ef3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -447,7 +447,6 @@ void intel_update_fbc(struct drm_device *dev) struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj; - int enable_fbc; unsigned int max_hdisplay, max_vdisplay; if (!i915_powersave) @@ -488,14 +487,13 @@ void intel_update_fbc(struct drm_device *dev) intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; - enable_fbc = i915_enable_fbc; - if (enable_fbc < 0) { - DRM_DEBUG_KMS("fbc set to per-chip default\n"); - enable_fbc = 1; - if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) - enable_fbc = 0; + if (i915_enable_fbc < 0 && + INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) { + DRM_DEBUG_KMS("disabled per chip default\n"); + dev_priv->no_fbc_reason = FBC_CHIP_DEFAULT; + goto out_disable; } - if (!enable_fbc) { + if (!i915_enable_fbc) { DRM_DEBUG_KMS("fbc disabled per module param\n"); dev_priv->no_fbc_reason = FBC_MODULE_PARAM; goto out_disable; From 267f0c90ac6728f70fade74ab89932a00e5e5a7e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 22:59:48 +0100 Subject: [PATCH 0016/6183] drm/i915: Use seq_puts/seq_putc when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Caught with checkpatch.pl. Suggested-by: Daniel Vetter Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 110 ++++++++++++++-------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index dca49828e3fc..b1e91f33e377 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -157,11 +157,11 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) switch (list) { case ACTIVE_LIST: - seq_printf(m, "Active:\n"); + seq_puts(m, "Active:\n"); head = &dev_priv->mm.active_list; break; case INACTIVE_LIST: - seq_printf(m, "Inactive:\n"); + seq_puts(m, "Inactive:\n"); head = &dev_priv->mm.inactive_list; break; default: @@ -171,9 +171,9 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) total_obj_size = total_gtt_size = count = 0; list_for_each_entry(obj, head, mm_list) { - seq_printf(m, " "); + seq_puts(m, " "); describe_obj(m, obj); - seq_printf(m, "\n"); + seq_putc(m, '\n'); total_obj_size += obj->base.size; total_gtt_size += obj->gtt_space->size; count++; @@ -290,7 +290,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) dev_priv->gtt.total, dev_priv->gtt.mappable_end - dev_priv->gtt.start); - seq_printf(m, "\n"); + seq_putc(m, '\n'); list_for_each_entry_reverse(file, &dev->filelist, lhead) { struct file_stats stats; @@ -329,9 +329,9 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data) if (list == PINNED_LIST && obj->pin_count == 0) continue; - seq_printf(m, " "); + seq_puts(m, " "); describe_obj(m, obj); - seq_printf(m, "\n"); + seq_putc(m, '\n'); total_obj_size += obj->base.size; total_gtt_size += obj->gtt_space->size; count++; @@ -371,9 +371,9 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) pipe, plane); } if (work->enable_stall_check) - seq_printf(m, "Stall check enabled, "); + seq_puts(m, "Stall check enabled, "); else - seq_printf(m, "Stall check waiting for page flip ioctl, "); + seq_puts(m, "Stall check waiting for page flip ioctl, "); seq_printf(m, "%d prepares\n", atomic_read(&work->pending)); if (work->old_fb_obj) { @@ -424,7 +424,7 @@ static int i915_gem_request_info(struct seq_file *m, void *data) mutex_unlock(&dev->struct_mutex); if (count == 0) - seq_printf(m, "No requests\n"); + seq_puts(m, "No requests\n"); return 0; } @@ -574,10 +574,10 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data) seq_printf(m, "Fence %d, pin count = %d, object = ", i, dev_priv->fence_regs[i].pin_count); if (obj == NULL) - seq_printf(m, "unused"); + seq_puts(m, "unused"); else describe_obj(m, obj); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } mutex_unlock(&dev->struct_mutex); @@ -1246,7 +1246,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) (freq_sts >> 8) & 0xff)); mutex_unlock(&dev_priv->rps.hw_lock); } else { - seq_printf(m, "no P-state info available\n"); + seq_puts(m, "no P-state info available\n"); } return 0; @@ -1341,28 +1341,28 @@ static int ironlake_drpc_info(struct seq_file *m) seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); seq_printf(m, "Render standby enabled: %s\n", (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes"); - seq_printf(m, "Current RS state: "); + seq_puts(m, "Current RS state: "); switch (rstdbyctl & RSX_STATUS_MASK) { case RSX_STATUS_ON: - seq_printf(m, "on\n"); + seq_puts(m, "on\n"); break; case RSX_STATUS_RC1: - seq_printf(m, "RC1\n"); + seq_puts(m, "RC1\n"); break; case RSX_STATUS_RC1E: - seq_printf(m, "RC1E\n"); + seq_puts(m, "RC1E\n"); break; case RSX_STATUS_RS1: - seq_printf(m, "RS1\n"); + seq_puts(m, "RS1\n"); break; case RSX_STATUS_RS2: - seq_printf(m, "RS2 (RC6)\n"); + seq_puts(m, "RS2 (RC6)\n"); break; case RSX_STATUS_RS3: - seq_printf(m, "RC3 (RC6+)\n"); + seq_puts(m, "RC3 (RC6+)\n"); break; default: - seq_printf(m, "unknown\n"); + seq_puts(m, "unknown\n"); break; } @@ -1389,8 +1389,8 @@ static int gen6_drpc_info(struct seq_file *m) spin_unlock_irq(&dev_priv->gt_lock); if (forcewake_count) { - seq_printf(m, "RC information inaccurate because somebody " - "holds a forcewake reference \n"); + seq_puts(m, "RC information inaccurate because somebody " + "holds a forcewake reference \n"); } else { /* NB: we cannot use forcewake, else we read the wrong values */ while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1)) @@ -1423,25 +1423,25 @@ static int gen6_drpc_info(struct seq_file *m) yesno(rcctl1 & GEN6_RC_CTL_RC6p_ENABLE)); seq_printf(m, "Deepest RC6 Enabled: %s\n", yesno(rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE)); - seq_printf(m, "Current RC state: "); + seq_puts(m, "Current RC state: "); switch (gt_core_status & GEN6_RCn_MASK) { case GEN6_RC0: if (gt_core_status & GEN6_CORE_CPD_STATE_MASK) - seq_printf(m, "Core Power Down\n"); + seq_puts(m, "Core Power Down\n"); else - seq_printf(m, "on\n"); + seq_puts(m, "on\n"); break; case GEN6_RC3: - seq_printf(m, "RC3\n"); + seq_puts(m, "RC3\n"); break; case GEN6_RC6: - seq_printf(m, "RC6\n"); + seq_puts(m, "RC6\n"); break; case GEN6_RC7: - seq_printf(m, "RC7\n"); + seq_puts(m, "RC7\n"); break; default: - seq_printf(m, "Unknown\n"); + seq_puts(m, "Unknown\n"); break; } @@ -1485,46 +1485,46 @@ static int i915_fbc_status(struct seq_file *m, void *unused) drm_i915_private_t *dev_priv = dev->dev_private; if (!I915_HAS_FBC(dev)) { - seq_printf(m, "FBC unsupported on this chipset\n"); + seq_puts(m, "FBC unsupported on this chipset\n"); return 0; } if (intel_fbc_enabled(dev)) { - seq_printf(m, "FBC enabled\n"); + seq_puts(m, "FBC enabled\n"); } else { - seq_printf(m, "FBC disabled: "); + seq_puts(m, "FBC disabled: "); switch (dev_priv->no_fbc_reason) { case FBC_NO_OUTPUT: - seq_printf(m, "no outputs"); + seq_puts(m, "no outputs"); break; case FBC_STOLEN_TOO_SMALL: - seq_printf(m, "not enough stolen memory"); + seq_puts(m, "not enough stolen memory"); break; case FBC_UNSUPPORTED_MODE: - seq_printf(m, "mode not supported"); + seq_puts(m, "mode not supported"); break; case FBC_MODE_TOO_LARGE: - seq_printf(m, "mode too large"); + seq_puts(m, "mode too large"); break; case FBC_BAD_PLANE: - seq_printf(m, "FBC unsupported on plane"); + seq_puts(m, "FBC unsupported on plane"); break; case FBC_NOT_TILED: - seq_printf(m, "scanout buffer not tiled"); + seq_puts(m, "scanout buffer not tiled"); break; case FBC_MULTIPLE_PIPES: - seq_printf(m, "multiple pipes are enabled"); + seq_puts(m, "multiple pipes are enabled"); break; case FBC_MODULE_PARAM: - seq_printf(m, "disabled per module param (default off)"); + seq_puts(m, "disabled per module param (default off)"); break; case FBC_CHIP_DEFAULT: - seq_printf(m, "disabled per chip default"); + seq_puts(m, "disabled per chip default"); break; default: - seq_printf(m, "unknown reason"); + seq_puts(m, "unknown reason"); } - seq_printf(m, "\n"); + seq_putc(m, '\n'); } return 0; } @@ -1607,7 +1607,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) int gpu_freq, ia_freq; if (!(IS_GEN6(dev) || IS_GEN7(dev))) { - seq_printf(m, "unsupported on this chipset\n"); + seq_puts(m, "unsupported on this chipset\n"); return 0; } @@ -1615,7 +1615,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) return ret; - seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); + seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); for (gpu_freq = dev_priv->rps.min_delay; gpu_freq <= dev_priv->rps.max_delay; @@ -1704,7 +1704,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fb->base.bits_per_pixel, atomic_read(&fb->base.refcount.refcount)); describe_obj(m, fb->obj); - seq_printf(m, "\n"); + seq_putc(m, '\n'); mutex_unlock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.fb_lock); @@ -1719,7 +1719,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) fb->base.bits_per_pixel, atomic_read(&fb->base.refcount.refcount)); describe_obj(m, fb->obj); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } mutex_unlock(&dev->mode_config.fb_lock); @@ -1739,22 +1739,22 @@ static int i915_context_status(struct seq_file *m, void *unused) return ret; if (dev_priv->ips.pwrctx) { - seq_printf(m, "power context "); + seq_puts(m, "power context "); describe_obj(m, dev_priv->ips.pwrctx); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } if (dev_priv->ips.renderctx) { - seq_printf(m, "render context "); + seq_puts(m, "render context "); describe_obj(m, dev_priv->ips.renderctx); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } for_each_ring(ring, dev_priv, i) { if (ring->default_context) { seq_printf(m, "HW default context %s ring ", ring->name); describe_obj(m, ring->default_context->obj); - seq_printf(m, "\n"); + seq_putc(m, '\n'); } } @@ -1871,7 +1871,7 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) if (dev_priv->mm.aliasing_ppgtt) { struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - seq_printf(m, "aliasing PPGTT:\n"); + seq_puts(m, "aliasing PPGTT:\n"); seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset); } seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK)); @@ -1889,7 +1889,7 @@ static int i915_dpio_info(struct seq_file *m, void *data) if (!IS_VALLEYVIEW(dev)) { - seq_printf(m, "unsupported\n"); + seq_puts(m, "unsupported\n"); return 0; } From aee56cff333d15e14c5bb2ff3b1e5c7cd15c3805 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 22:59:49 +0100 Subject: [PATCH 0017/6183] drm/i915: Fix a few style issues found by checkpatch.pl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missing spaces and misplaced '*'. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b1e91f33e377..c16926ca15be 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -222,7 +222,7 @@ static int per_file_stats(int id, void *ptr, void *data) return 0; } -static int i915_gem_object_info(struct seq_file *m, void* data) +static int i915_gem_object_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; @@ -310,7 +310,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) return 0; } -static int i915_gem_gtt_info(struct seq_file *m, void* data) +static int i915_gem_gtt_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; @@ -1377,8 +1377,7 @@ static int gen6_drpc_info(struct seq_file *m) struct drm_i915_private *dev_priv = dev->dev_private; u32 rpmodectl1, gt_core_status, rcctl1, rc6vids = 0; unsigned forcewake_count; - int count=0, ret; - + int count = 0, ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -1781,7 +1780,7 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data) static const char *swizzle_string(unsigned swizzle) { - switch(swizzle) { + switch (swizzle) { case I915_BIT_6_SWIZZLE_NONE: return "none"; case I915_BIT_6_SWIZZLE_9: From f4db9321a77258587d70cccdd4ff556df48eba2e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 22:59:50 +0100 Subject: [PATCH 0018/6183] drm/i915: Fix a couple of "should it be static?" sparse warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A genuine 'static' omission and 2 other warnings triggered by not including the header where those functions where defined. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index adc7f3eb4ef3..aa48fc6ba4db 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -30,6 +30,7 @@ #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" #include +#include #define FORCEWAKE_ACK_TIMEOUT_MS 2 @@ -2465,8 +2466,8 @@ static void hsw_compute_wm_results(struct drm_device *dev, /* Find the result with the highest level enabled. Check for enable_fbc_wm in * case both are at the same level. Prefer r1 in case they're the same. */ -struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1, - struct hsw_wm_values *r2) +static struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1, + struct hsw_wm_values *r2) { int i, val_r1 = 0, val_r2 = 0; From 3ef8fb5ae296c3b626b87ec1422aeb66dd338ee8 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 14:54:50 +0100 Subject: [PATCH 0019/6183] drm/i915: Bail out once we've found the context object Once we've found the the context object programmed in CCID, there's no need to look the other objects in the list. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3d92a7cef154..92e78167ca84 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1805,6 +1805,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring, if ((error->ccid & PAGE_MASK) == obj->gtt_offset) { ering->ctx = i915_error_object_create_sized(dev_priv, obj, 1); + break; } } } From 15bdd4cff43104cc0692f8694019c043cf19d102 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:23 +0200 Subject: [PATCH 0020/6183] drm/i915: consolidate pch pll enable sequence It's been splattered over 3 different places all doing random things. Now we have (mostly) the same sequence as i8xx/i9xx, but all called from the crtc_enable hook (through the pll->enable function): - write new dividers - enable vco and wait for stable clocks - write again for the pixel mutliplier I've left the seemingly random 200 usec delay in there, just in case. Also move the encoder->pre_pll_enable hook into the crtc_enable function, at the same spot we currently have a hack to enable the lvds port. Since that hack is now redundant, kill it. While doing this patch I've learned the hard way that we can only fire up the LVDS port if both the pch dpll _and_ the fdi rc pll are not yet enabled. Otherwise things go haywire, at least on cpt. v2: It is paramount to write the FPx divisors before we enable the the vco by writing to the DPLL registers, for otherwise the divisors won't get updated. This is in line with the i8xx/i9xx dpll. v3: To keep the nice abstraction add a ->mode_set callback to set the divisors. Also streamline the enabling/disabling code a bit by removing some cargo-cult duplication and clearing registers where possible in the ->disable hook. v4: Remove now unused local variable. Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 75 ++++++++++------------------ 2 files changed, 29 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 59c45f293ec9..dfb10fee83b6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -156,6 +156,8 @@ struct intel_shared_dpll { /* should match the index in the dev_priv->shared_dplls array */ enum intel_dpll_id id; struct intel_dpll_hw_state hw_state; + void (*mode_set)(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll); void (*enable)(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll); void (*disable)(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 85f3eb74d2b7..644be8aed396 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3096,13 +3096,7 @@ found: WARN_ON(pll->on); assert_shared_dpll_disabled(dev_priv, pll); - /* Wait for the clocks to stabilize before rewriting the regs */ - I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(PCH_DPLL(pll->id)); - udelay(150); - - I915_WRITE(PCH_FP0(pll->id), fp); - I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE); + pll->mode_set(dev_priv, pll); } pll->refcount++; @@ -3174,7 +3168,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - u32 temp; WARN_ON(!crtc->enabled); @@ -3188,12 +3181,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(dev); - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - if ((temp & LVDS_PORT_EN) == 0) - I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); - } - + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); if (intel_crtc->config.has_pch_encoder) { /* Note: FDI PLL enabling _must_ be done before we enable the @@ -5723,10 +5713,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) - if (encoder->pre_pll_enable) - encoder->pre_pll_enable(encoder); - if (is_lvds && has_reduced_clock && i915_powersave) intel_crtc->lowfreq_avail = true; else @@ -5735,23 +5721,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) { pll = intel_crtc_to_shared_dpll(intel_crtc); - I915_WRITE(PCH_DPLL(pll->id), dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(PCH_DPLL(pll->id)); - udelay(150); - - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(PCH_DPLL(pll->id), dpll); - - if (has_reduced_clock) - I915_WRITE(PCH_FP1(pll->id), fp2); - else - I915_WRITE(PCH_FP1(pll->id), fp); } intel_set_pipe_timings(intel_crtc); @@ -8800,19 +8769,32 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, return val & DPLL_VCO_ENABLE; } +static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + I915_WRITE(PCH_FP0(pll->id), pll->hw_state.fp0); + I915_WRITE(PCH_FP1(pll->id), pll->hw_state.fp1); +} + static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { - uint32_t reg, val; - /* PCH refclock must be enabled first */ assert_pch_refclk_enabled(dev_priv); - reg = PCH_DPLL(pll->id); - val = I915_READ(reg); - val |= DPLL_VCO_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); + I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(PCH_DPLL(pll->id)); + udelay(150); + + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll); + POSTING_READ(PCH_DPLL(pll->id)); udelay(200); } @@ -8821,7 +8803,6 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; struct intel_crtc *crtc; - uint32_t reg, val; /* Make sure no transcoder isn't still depending on us. */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { @@ -8829,11 +8810,8 @@ static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, assert_pch_transcoder_disabled(dev_priv, crtc->pipe); } - reg = PCH_DPLL(pll->id); - val = I915_READ(reg); - val &= ~DPLL_VCO_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); + I915_WRITE(PCH_DPLL(pll->id), 0); + POSTING_READ(PCH_DPLL(pll->id)); udelay(200); } @@ -8852,6 +8830,7 @@ static void ibx_pch_dpll_init(struct drm_device *dev) for (i = 0; i < dev_priv->num_shared_dpll; i++) { dev_priv->shared_dplls[i].id = i; dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i]; + dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set; dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable; dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable; dev_priv->shared_dplls[i].get_hw_state = From b89a1d395bf8bd209f1e14265c5b1d34c4a98d57 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:24 +0200 Subject: [PATCH 0021/6183] drm/i915: use sw tracked state to select shared dplls Just yet another prep step to be able to do all this up-front, before we've set up any of the shared dplls in the new state. This will eventually be useful for atomic modesetting. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 644be8aed396..6b379bcb031f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3031,7 +3031,7 @@ static void intel_put_shared_dpll(struct intel_crtc *crtc) crtc->config.shared_dpll = DPLL_ID_PRIVATE; } -static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, u32 dpll, u32 fp) +static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); @@ -3061,8 +3061,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, if (pll->refcount == 0) continue; - if (dpll == (I915_READ(PCH_DPLL(pll->id)) & 0x7fffffff) && - fp == I915_READ(PCH_FP0(pll->id))) { + if (memcmp(&crtc->config.dpll_hw_state, &pll->hw_state, + sizeof(pll->hw_state)) == 0) { DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n", crtc->base.base.id, pll->name, pll->refcount, pll->active); @@ -5701,7 +5701,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, else intel_crtc->config.dpll_hw_state.fp1 = fp; - pll = intel_get_shared_dpll(intel_crtc, dpll, fp); + pll = intel_get_shared_dpll(intel_crtc); if (pll == NULL) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", pipe_name(pipe)); From 87442f732bfad16a8b65fb5d86f69bc0417dc9db Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Jun 2013 00:52:17 +0200 Subject: [PATCH 0022/6183] drm/i915: duplicate intel_enable_pll into i9xx and vlv versions Mostly since I _really_ don't want to touch the vlv hell. No code change, just duplication. Also kill a now seriously outdated code comment - the remark about the dvo encoder is now handled with the pipe A quirk. v2: Update the BUG_ONs as suggested by Jani (both in vlv_ and i9xx_ functions, since the split happens here). Cc: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 51 ++++++++++++++++++---------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6b379bcb031f..e0efe4b015fb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1301,20 +1301,7 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); } -/** - * intel_enable_pll - enable a PLL - * @dev_priv: i915 private structure - * @pipe: pipe PLL to enable - * - * Enable @pipe's PLL so we can start pumping pixels from a plane. Check to - * make sure the PLL reg is writable first though, since the panel write - * protect mechanism may be enabled. - * - * Note! This is for pre-ILK only. - * - * Unfortunately needed by dvo_ns2501 since the dvo depends on it running. - */ -static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +static void vlv_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { int reg; u32 val; @@ -1322,7 +1309,37 @@ static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) assert_pipe_disabled(dev_priv, pipe); /* No really, not for ILK+ */ - BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= 5); + BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); + + /* PLL is protected by panel, make sure we can write it */ + if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) + assert_panel_unlocked(dev_priv, pipe); + + reg = DPLL(pipe); + val = I915_READ(reg); + val |= DPLL_VCO_ENABLE; + + /* We do this three times for luck */ + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ +} + +static void i9xx_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + int reg; + u32 val; + + assert_pipe_disabled(dev_priv, pipe); + + /* No really, not for ILK+ */ + BUG_ON(dev_priv->info->gen >= 5); /* PLL is protected by panel, make sure we can write it */ if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) @@ -3589,7 +3606,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); - intel_enable_pll(dev_priv, pipe); + vlv_enable_pll(dev_priv, pipe); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) @@ -3630,7 +3647,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_update_watermarks(dev); - intel_enable_pll(dev_priv, pipe); + i9xx_enable_pll(dev_priv, pipe); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) From 55607e8aaa86e68ed4f37d072ee9af404cc8a830 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 16 Jun 2013 21:42:39 +0200 Subject: [PATCH 0023/6183] drm/i915: asserts for lvds pre_enable Lots of bangin my head against the wall^UExperiments have shown that we really need to enable the lvds port before we enable plls. Strangely that seems to include the fdi rx pll on the pch. Note that the pch pll assert can fire since the lvds port has it's own special clock source settings in the DPLL register, which means it will never have a shared dpll (since there's only one LVDS port). Anyway, encode this new evidence with a few nice WARNs. v2: Incorporate review comments from Imre. - Explain why lvds can't have a shared dpll. - Update the WARN output. Cc: Imre Deak Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 26 +++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 16 ++++++++++++++++ drivers/gpu/drm/i915/intel_lvds.c | 17 ++++++++++++----- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e0efe4b015fb..66c6e383c7f7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -892,8 +892,8 @@ static const char *state_string(bool enabled) } /* Only for pre-ILK configs */ -static void assert_pll(struct drm_i915_private *dev_priv, - enum pipe pipe, bool state) +void assert_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) { int reg; u32 val; @@ -906,10 +906,8 @@ static void assert_pll(struct drm_i915_private *dev_priv, "PLL state assertion failure (expected %s, current %s)\n", state_string(state), state_string(cur_state)); } -#define assert_pll_enabled(d, p) assert_pll(d, p, true) -#define assert_pll_disabled(d, p) assert_pll(d, p, false) -static struct intel_shared_dpll * +struct intel_shared_dpll * intel_crtc_to_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; @@ -921,9 +919,9 @@ intel_crtc_to_shared_dpll(struct intel_crtc *crtc) } /* For ILK+ */ -static void assert_shared_dpll(struct drm_i915_private *dev_priv, - struct intel_shared_dpll *pll, - bool state) +void assert_shared_dpll(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + bool state) { bool cur_state; struct intel_dpll_hw_state hw_state; @@ -942,8 +940,6 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, "%s assertion failure (expected %s, current %s)\n", pll->name, state_string(state), state_string(cur_state)); } -#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true) -#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false) static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum pipe pipe, bool state) @@ -1007,15 +1003,19 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); } -static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv, - enum pipe pipe) +void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) { int reg; u32 val; + bool cur_state; reg = FDI_RX_CTL(pipe); val = I915_READ(reg); - WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n"); + cur_state = !!(val & FDI_RX_PLL_ENABLE); + WARN(cur_state != state, + "FDI RX PLL assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); } static void assert_panel_unlocked(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8eeee74f3d91..6f7f33e70e91 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -747,6 +747,22 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, extern void intel_fb_output_poll_changed(struct drm_device *dev); extern void intel_fb_restore_mode(struct drm_device *dev); +struct intel_shared_dpll * +intel_crtc_to_shared_dpll(struct intel_crtc *crtc); + +void assert_shared_dpll(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + bool state); +#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true) +#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false) +void assert_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state); +#define assert_pll_enabled(d, p) assert_pll(d, p, true) +#define assert_pll_disabled(d, p) assert_pll(d, p, false) +void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state); +#define assert_fdi_rx_pll_enabled(d, p) assert_fdi_rx_pll(d, p, true) +#define assert_fdi_rx_pll_disabled(d, p) assert_fdi_rx_pll(d, p, false) extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2abb2d3c727b..a510fa824027 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -120,12 +120,20 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); struct drm_display_mode *fixed_mode = lvds_encoder->attached_connector->base.panel.fixed_mode; - int pipe = intel_crtc->pipe; + int pipe = crtc->pipe; u32 temp; + if (HAS_PCH_SPLIT(dev)) { + assert_fdi_rx_pll_disabled(dev_priv, pipe); + assert_shared_dpll_disabled(dev_priv, + intel_crtc_to_shared_dpll(crtc)); + } else { + assert_pll_disabled(dev_priv, pipe); + } + temp = I915_READ(lvds_encoder->reg); temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; @@ -142,7 +150,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) /* set the corresponsding LVDS_BORDER bit */ temp &= ~LVDS_BORDER_ENABLE; - temp |= intel_crtc->config.gmch_pfit.lvds_border_bits; + temp |= crtc->config.gmch_pfit.lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. */ @@ -162,8 +170,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) if (INTEL_INFO(dev)->gen == 4) { /* Bspec wording suggests that LVDS port dithering only exists * for 18bpp panels. */ - if (intel_crtc->config.dither && - intel_crtc->config.pipe_bpp == 18) + if (crtc->config.dither && crtc->config.pipe_bpp == 18) temp |= LVDS_ENABLE_DITHER; else temp &= ~LVDS_ENABLE_DITHER; From 952735ee416f686fac55957b221461dfbd80ce1c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:27 +0200 Subject: [PATCH 0024/6183] drm/i915: move encoder pre enable hooks togther on ilk+ The ->pre_enable hook is only used for the cpu edp port on ilk-ivb, so we can safely move it up across the fdi pll enabling. Unfortunately we can't (yet) merge in the pre_pll enable hook despite that only lvds uses it on ilk-ivb: Since the same lvds hook is also need on i9xx platforms we need to fix up the pll enabling sequence there, too. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 66c6e383c7f7..f7d4c5eba6ba 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3198,9 +3198,12 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(dev); - for_each_encoder_on_crtc(dev, crtc, encoder) + for_each_encoder_on_crtc(dev, crtc, encoder) { if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); + if (encoder->pre_enable) + encoder->pre_enable(encoder); + } if (intel_crtc->config.has_pch_encoder) { /* Note: FDI PLL enabling _must_ be done before we enable the @@ -3212,10 +3215,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) assert_fdi_rx_disabled(dev_priv, pipe); } - for_each_encoder_on_crtc(dev, crtc, encoder) - if (encoder->pre_enable) - encoder->pre_enable(encoder); - ironlake_pfit_enable(intel_crtc); /* From 8bcc2795a68ad9c2010fd5a2548432fad930fcc1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:28 +0200 Subject: [PATCH 0025/6183] drm/i915: hw state readout for i9xx dplls In addition to existing stuff we also need to track DPLL_MD on gen4 and vlv. This is prep work so that we can move the dpll enable sequence out from the ->mode_set callback into the crtc enabling functions. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dfb10fee83b6..e9c8b588e14d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -144,6 +144,7 @@ enum intel_dpll_id { struct intel_dpll_hw_state { uint32_t dpll; + uint32_t dpll_md; uint32_t fp0; uint32_t fp1; }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f7d4c5eba6ba..4e451faf96c6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4272,14 +4272,17 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc, } I915_WRITE(FP0(pipe), fp); + crtc->config.dpll_hw_state.fp0 = fp; crtc->lowfreq_avail = false; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && reduced_clock && i915_powersave) { I915_WRITE(FP1(pipe), fp2); + crtc->config.dpll_hw_state.fp1 = fp2; crtc->lowfreq_avail = true; } else { I915_WRITE(FP1(pipe), fp); + crtc->config.dpll_hw_state.fp1 = fp; } } @@ -4457,6 +4460,8 @@ static void vlv_update_pll(struct intel_crtc *crtc) dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; dpll |= DPLL_VCO_ENABLE; + crtc->config.dpll_hw_state.dpll = dpll; + I915_WRITE(DPLL(pipe), dpll); POSTING_READ(DPLL(pipe)); udelay(150); @@ -4466,6 +4471,8 @@ static void vlv_update_pll(struct intel_crtc *crtc) dpll_md = (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + crtc->config.dpll_hw_state.dpll_md = dpll_md; + I915_WRITE(DPLL_MD(pipe), dpll_md); POSTING_READ(DPLL_MD(pipe)); @@ -4544,6 +4551,8 @@ static void i9xx_update_pll(struct intel_crtc *crtc, dpll |= PLL_REF_INPUT_DREFCLK; dpll |= DPLL_VCO_ENABLE; + crtc->config.dpll_hw_state.dpll = dpll; + I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); POSTING_READ(DPLL(pipe)); udelay(150); @@ -4564,6 +4573,8 @@ static void i9xx_update_pll(struct intel_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) { u32 dpll_md = (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; + crtc->config.dpll_hw_state.dpll_md = dpll_md; + I915_WRITE(DPLL_MD(pipe), dpll_md); } else { /* The pixel multiplier can only be updated once the @@ -4608,6 +4619,8 @@ static void i8xx_update_pll(struct intel_crtc *crtc, dpll |= PLL_REF_INPUT_DREFCLK; dpll |= DPLL_VCO_ENABLE; + crtc->config.dpll_hw_state.dpll = dpll; + I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); POSTING_READ(DPLL(pipe)); udelay(150); @@ -4964,6 +4977,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, pipe_config->pixel_multiplier = ((tmp & DPLL_MD_UDI_MULTIPLIER_MASK) >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1; + pipe_config->dpll_hw_state.dpll_md = tmp; } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { tmp = I915_READ(DPLL(crtc->pipe)); pipe_config->pixel_multiplier = @@ -4975,6 +4989,11 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, * function. */ pipe_config->pixel_multiplier = 1; } + pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe)); + if (!IS_VALLEYVIEW(dev)) { + pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe)); + pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe)); + } return true; } @@ -8126,6 +8145,7 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(shared_dpll); PIPE_CONF_CHECK_X(dpll_hw_state.dpll); + PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md); PIPE_CONF_CHECK_X(dpll_hw_state.fp0); PIPE_CONF_CHECK_X(dpll_hw_state.fp1); From 66e3d5c09940d08d94b03e65b420fadaa7484318 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 16 Jun 2013 21:24:16 +0200 Subject: [PATCH 0026/6183] drm/i915: move i9xx dpll enabling into crtc enable function Now that we have the proper pipe config to track this, we don't need to write any registers any more. Note that for platforms without DPLL_MD (pre-gen4) which store the pixel mutliplier in the DPLL register I've decided to keep the seemingly "redundant" write: The comment right below saying "do this trice for luck" doesn't instill confidence ... v2: Drop a few now unnecessary local variables and switch the enable function to take a struct intel_crtc * to simply arguments. v3: Rebase on top of the newly-colored BUG_ON. v4: Amend commit message to alliviate Imre's comment about the redudant DPLL write for the pixel mutliplier. Cc: Imre Deak Cc: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 100 ++++++++++----------------- 1 file changed, 36 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4e451faf96c6..1a8a01bc28a4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1331,32 +1331,48 @@ static void vlv_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) udelay(150); /* wait for warmup */ } -static void i9xx_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +static void i9xx_enable_pll(struct intel_crtc *crtc) { - int reg; - u32 val; + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int reg = DPLL(crtc->pipe); + u32 dpll = crtc->config.dpll_hw_state.dpll; - assert_pipe_disabled(dev_priv, pipe); + assert_pipe_disabled(dev_priv, crtc->pipe); /* No really, not for ILK+ */ BUG_ON(dev_priv->info->gen >= 5); /* PLL is protected by panel, make sure we can write it */ - if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) - assert_panel_unlocked(dev_priv, pipe); + if (IS_MOBILE(dev) && !IS_I830(dev)) + assert_panel_unlocked(dev_priv, crtc->pipe); - reg = DPLL(pipe); - val = I915_READ(reg); - val |= DPLL_VCO_ENABLE; + I915_WRITE(reg, dpll); + + /* Wait for the clocks to stabilize. */ + POSTING_READ(reg); + udelay(150); + + if (INTEL_INFO(dev)->gen >= 4) { + I915_WRITE(DPLL_MD(crtc->pipe), + crtc->config.dpll_hw_state.dpll_md); + } else { + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + I915_WRITE(reg, dpll); + } /* We do this three times for luck */ - I915_WRITE(reg, val); + I915_WRITE(reg, dpll); POSTING_READ(reg); udelay(150); /* wait for warmup */ - I915_WRITE(reg, val); + I915_WRITE(reg, dpll); POSTING_READ(reg); udelay(150); /* wait for warmup */ - I915_WRITE(reg, val); + I915_WRITE(reg, dpll); POSTING_READ(reg); udelay(150); /* wait for warmup */ } @@ -3646,7 +3662,11 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_update_watermarks(dev); - i9xx_enable_pll(dev_priv, pipe); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); + + i9xx_enable_pll(intel_crtc); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) @@ -4488,8 +4508,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *encoder; - int pipe = crtc->pipe; u32 dpll; bool is_sdvo; struct dpll *clock = &crtc->config.dpll; @@ -4553,37 +4571,14 @@ static void i9xx_update_pll(struct intel_crtc *crtc, dpll |= DPLL_VCO_ENABLE; crtc->config.dpll_hw_state.dpll = dpll; - I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(DPLL(pipe)); - udelay(150); - - for_each_encoder_on_crtc(dev, &crtc->base, encoder) - if (encoder->pre_pll_enable) - encoder->pre_pll_enable(encoder); - - if (crtc->config.has_dp_encoder) - intel_dp_set_m_n(crtc); - - I915_WRITE(DPLL(pipe), dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(DPLL(pipe)); - udelay(150); - if (INTEL_INFO(dev)->gen >= 4) { u32 dpll_md = (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; crtc->config.dpll_hw_state.dpll_md = dpll_md; - - I915_WRITE(DPLL_MD(pipe), dpll_md); - } else { - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(DPLL(pipe), dpll); } + + if (crtc->config.has_dp_encoder) + intel_dp_set_m_n(crtc); } static void i8xx_update_pll(struct intel_crtc *crtc, @@ -4592,8 +4587,6 @@ static void i8xx_update_pll(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *encoder; - int pipe = crtc->pipe; u32 dpll; struct dpll *clock = &crtc->config.dpll; @@ -4620,27 +4613,6 @@ static void i8xx_update_pll(struct intel_crtc *crtc, dpll |= DPLL_VCO_ENABLE; crtc->config.dpll_hw_state.dpll = dpll; - - I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(DPLL(pipe)); - udelay(150); - - for_each_encoder_on_crtc(dev, &crtc->base, encoder) - if (encoder->pre_pll_enable) - encoder->pre_pll_enable(encoder); - - I915_WRITE(DPLL(pipe), dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(DPLL(pipe)); - udelay(150); - - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(DPLL(pipe), dpll); } static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) From f6736a1a7b846d0af90135c7a7f121ab3ada9ee1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:30 +0200 Subject: [PATCH 0027/6183] drm/i915: s/pre_pll/pre/ on the lvds port enable function i9xx doesn't use pre_enable at all, so we can fold this in now. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 +++---------- drivers/gpu/drm/i915/intel_lvds.c | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1a8a01bc28a4..0497841f841e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3214,12 +3214,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(dev); - for_each_encoder_on_crtc(dev, crtc, encoder) { - if (encoder->pre_pll_enable) - encoder->pre_pll_enable(encoder); + for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) encoder->pre_enable(encoder); - } if (intel_crtc->config.has_pch_encoder) { /* Note: FDI PLL enabling _must_ be done before we enable the @@ -3662,16 +3659,12 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_update_watermarks(dev); - for_each_encoder_on_crtc(dev, crtc, encoder) - if (encoder->pre_pll_enable) - encoder->pre_pll_enable(encoder); - - i9xx_enable_pll(intel_crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) encoder->pre_enable(encoder); + i9xx_enable_pll(intel_crtc); + i9xx_pfit_enable(intel_crtc); intel_crtc_load_lut(crtc); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a510fa824027..b0e1088b2c97 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -115,7 +115,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, * This is an exception to the general rule that mode_set doesn't turn * things on. */ -static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) +static void intel_pre_enable_lvds(struct intel_encoder *encoder) { struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct drm_device *dev = encoder->base.dev; @@ -946,7 +946,7 @@ void intel_lvds_init(struct drm_device *dev) DRM_MODE_ENCODER_LVDS); intel_encoder->enable = intel_enable_lvds; - intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; + intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->compute_config = intel_lvds_compute_config; intel_encoder->disable = intel_disable_lvds; intel_encoder->get_hw_state = intel_lvds_get_hw_state; From 165e901caa4c9d768dd572aab6b95f89a2e9e204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Jun 2013 17:44:15 +0300 Subject: [PATCH 0028/6183] drm/i915: Mask out hardware status bits from VLV DPLL register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DPLL lock bit, and the DPIO phy status bits are read-only and controlled by the hardware, so they will never be set by the driver. Mask them out when reading the hw state, so that the state comparison won't fail. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes [danvet: Jesse asked for a code comment and I wholeheartly agree, so added one.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0497841f841e..d60684d9847c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4958,6 +4958,11 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, if (!IS_VALLEYVIEW(dev)) { pipe_config->dpll_hw_state.fp0 = I915_READ(FP0(crtc->pipe)); pipe_config->dpll_hw_state.fp1 = I915_READ(FP1(crtc->pipe)); + } else { + /* Mask out read-only status bits. */ + pipe_config->dpll_hw_state.dpll &= ~(DPLL_LOCK_VLV | + DPLL_PORTC_READY_MASK | + DPLL_PORTB_READY_MASK); } return true; From 5476f8505b4c4178dbb9f4e9d2bf17e52d8026ed Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:02 -0700 Subject: [PATCH 0029/6183] drm/i915: Remove extra error state NULL Not only was there an extra, but since we now kzalloc the error state, we don't need either. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 92e78167ca84..6a1ae614268e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1931,10 +1931,6 @@ static void i915_capture_error_state(struct drm_device *dev) i915_gem_record_fences(dev, error); i915_gem_record_rings(dev, error); - /* Record buffers on the active and pinned lists. */ - error->active_bo = NULL; - error->pinned_bo = NULL; - i = 0; list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) i++; @@ -1944,8 +1940,6 @@ static void i915_capture_error_state(struct drm_device *dev) i++; error->pinned_bo_count = i - error->active_bo_count; - error->active_bo = NULL; - error->pinned_bo = NULL; if (i) { error->active_bo = kmalloc(sizeof(*error->active_bo)*i, GFP_ATOMIC); From 26b7c22465cbfaa40d7f2de6d5933a66106eb778 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:03 -0700 Subject: [PATCH 0030/6183] drm/i915: Extract error buffer capture This helps when we have per VM buffer capturing. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 69 ++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6a1ae614268e..6ca6097aa48f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1855,6 +1855,42 @@ static void i915_gem_record_rings(struct drm_device *dev, } } +static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv, + struct drm_i915_error_state *error) +{ + struct drm_i915_gem_object *obj; + int i; + + i = 0; + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) + i++; + error->active_bo_count = i; + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) + if (obj->pin_count) + i++; + error->pinned_bo_count = i - error->active_bo_count; + + if (i) { + error->active_bo = kmalloc(sizeof(*error->active_bo)*i, + GFP_ATOMIC); + if (error->active_bo) + error->pinned_bo = + error->active_bo + error->active_bo_count; + } + + if (error->active_bo) + error->active_bo_count = + capture_active_bo(error->active_bo, + error->active_bo_count, + &dev_priv->mm.active_list); + + if (error->pinned_bo) + error->pinned_bo_count = + capture_pinned_bo(error->pinned_bo, + error->pinned_bo_count, + &dev_priv->mm.bound_list); +} + /** * i915_capture_error_state - capture an error record for later analysis * @dev: drm device @@ -1867,10 +1903,9 @@ static void i915_gem_record_rings(struct drm_device *dev, static void i915_capture_error_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj; struct drm_i915_error_state *error; unsigned long flags; - int i, pipe; + int pipe; spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); error = dev_priv->gpu_error.first_error; @@ -1928,38 +1963,10 @@ static void i915_capture_error_state(struct drm_device *dev) i915_get_extra_instdone(dev, error->extra_instdone); + i915_gem_capture_buffers(dev_priv, error); i915_gem_record_fences(dev, error); i915_gem_record_rings(dev, error); - i = 0; - list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) - i++; - error->active_bo_count = i; - list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (obj->pin_count) - i++; - error->pinned_bo_count = i - error->active_bo_count; - - if (i) { - error->active_bo = kmalloc(sizeof(*error->active_bo)*i, - GFP_ATOMIC); - if (error->active_bo) - error->pinned_bo = - error->active_bo + error->active_bo_count; - } - - if (error->active_bo) - error->active_bo_count = - capture_active_bo(error->active_bo, - error->active_bo_count, - &dev_priv->mm.active_list); - - if (error->pinned_bo) - error->pinned_bo_count = - capture_pinned_bo(error->pinned_bo, - error->pinned_bo_count, - &dev_priv->mm.bound_list); - do_gettimeofday(&error->time); error->overlay = intel_overlay_capture_error_state(dev); From 6670a5a5c77b8fc17962742f9bcf6f47e489aa62 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:04 -0700 Subject: [PATCH 0031/6183] drm/i915: make PDE|PTE platform specific Nothing outside of i915_gem_gtt.c and more specifically, the relevant gen specific init function should need to know about number of PDEs, or PTEs per PD. Exposing this will only lead to circumventing using the upcoming VM abstraction. To accomplish this, move the defines into the .c file, rename the PDE define to be GEN6, and make the PTE count less of a magic number. The remaining code in the global gtt setup is a bit messy, but an upcoming patch will clean that one up. v2: Don't hardcode number of PDEs (Daniel + Jesse) Reworded commit message to reflect change. Reviewed-by: Jesse Barnes Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_gem_gtt.c | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e9c8b588e14d..91c1fdc6a4ab 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -486,8 +486,6 @@ struct i915_gtt { }; #define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT) -#define I915_PPGTT_PD_ENTRIES 512 -#define I915_PPGTT_PT_ENTRIES 1024 struct i915_hw_ppgtt { struct drm_device *dev; unsigned num_pd_entries; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5101ab6869b4..216e7a19e63d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -28,6 +28,9 @@ #include "i915_trace.h" #include "intel_drv.h" +#define GEN6_PPGTT_PD_ENTRIES 512 +#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t)) + /* PPGTT stuff */ #define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) @@ -278,7 +281,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) } else { ppgtt->pte_encode = gen6_pte_encode; } - ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; + ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES; ppgtt->enable = gen6_ppgtt_enable; ppgtt->clear_range = gen6_ppgtt_clear_range; ppgtt->insert_entries = gen6_ppgtt_insert_entries; @@ -688,7 +691,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) if (INTEL_INFO(dev)->gen <= 7) { /* PPGTT pdes are stolen from global gtt ptes, so shrink the * aperture accordingly when using aliasing ppgtt. */ - gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + gtt_size -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE; } i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); @@ -699,7 +702,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) DRM_ERROR("Aliased PPGTT setup failed %d\n", ret); drm_mm_takedown(&dev_priv->mm.gtt_space); - gtt_size += I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + gtt_size += GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE; } i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); } From 84f135605898708ab692fc84555c31fbfe2983c1 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:17 -0700 Subject: [PATCH 0032/6183] drm/i915: Really share scratch page A previous patch had set up the ppgtt and ggtt to use the same scratch page, but still kept around both pointers. Kill it, it's not needed and gets in our way for upcoming cleanups. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 91c1fdc6a4ab..af8eadf796a8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -492,7 +492,6 @@ struct i915_hw_ppgtt { struct page **pt_pages; uint32_t pd_offset; dma_addr_t *pt_dma_addr; - dma_addr_t scratch_page_dma_addr; /* pte functions, mirroring the interface of the global gtt. */ void (*clear_range)(struct i915_hw_ppgtt *ppgtt, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 216e7a19e63d..46b9e32b1109 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -188,13 +188,14 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { + struct drm_i915_private *dev_priv = ppgtt->dev->dev_private; gen6_gtt_pte_t *pt_vaddr, scratch_pte; unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; scratch_pte = ppgtt->pte_encode(ppgtt->dev, - ppgtt->scratch_page_dma_addr, + dev_priv->gtt.scratch_page_dma, I915_CACHE_LLC); while (num_entries) { @@ -351,7 +352,6 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) return -ENOMEM; ppgtt->dev = dev; - ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; if (INTEL_INFO(dev)->gen < 8) ret = gen6_ppgtt_init(ppgtt); From 67167240063c9eff15d60754c8d786a7a237ffa2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:18 -0700 Subject: [PATCH 0033/6183] drm/i915: Combine scratch members into a struct There isn't any special reason to do this other than it makes it obvious that the two members are connected. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 17 ++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index af8eadf796a8..40bb23b3fa19 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -465,8 +465,10 @@ struct i915_gtt { void __iomem *gsm; bool do_idle_maps; - dma_addr_t scratch_page_dma; - struct page *scratch_page; + struct { + dma_addr_t addr; + struct page *page; + } scratch; /* global gtt ops */ int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 46b9e32b1109..cdd7b45cd501 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -195,7 +195,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned last_pte, i; scratch_pte = ppgtt->pte_encode(ppgtt->dev, - dev_priv->gtt.scratch_page_dma, + dev_priv->gtt.scratch.addr, I915_CACHE_LLC); while (num_entries) { @@ -521,8 +521,7 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = dev_priv->gtt.pte_encode(dev, - dev_priv->gtt.scratch_page_dma, + scratch_pte = dev_priv->gtt.pte_encode(dev, dev_priv->gtt.scratch.addr, I915_CACHE_LLC); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); @@ -727,8 +726,8 @@ static int setup_scratch_page(struct drm_device *dev) #else dma_addr = page_to_phys(page); #endif - dev_priv->gtt.scratch_page = page; - dev_priv->gtt.scratch_page_dma = dma_addr; + dev_priv->gtt.scratch.page = page; + dev_priv->gtt.scratch.addr = dma_addr; return 0; } @@ -736,11 +735,11 @@ static int setup_scratch_page(struct drm_device *dev) static void teardown_scratch_page(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - set_pages_wb(dev_priv->gtt.scratch_page, 1); - pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma, + set_pages_wb(dev_priv->gtt.scratch.page, 1); + pci_unmap_page(dev->pdev, dev_priv->gtt.scratch.addr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - put_page(dev_priv->gtt.scratch_page); - __free_page(dev_priv->gtt.scratch_page); + put_page(dev_priv->gtt.scratch.page); + __free_page(dev_priv->gtt.scratch.page); } static inline unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) From 80a74f7f9c3e57123b6c3d314d4340fc8195a524 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:19 -0700 Subject: [PATCH 0034/6183] drm/i915: Drop dev from pte_encode The original pte_encode function needed the dev argument so we could do platform specific handling via IS_GENX, etc. With the merging of a pte encoding function there should never been a need to quirk away gen specific details. The patch doesn't do much but makes the upcoming reworks in gtt/ppgtt/mm slightly (albeit, ever so) easier. Reviewed-by: Kenneth Graunke Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++---- drivers/gpu/drm/i915/i915_gem_gtt.c | 21 ++++++++------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 40bb23b3fa19..438cb0ab6889 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -482,8 +482,7 @@ struct i915_gtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); - gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev, - dma_addr_t addr, + gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr, enum i915_cache_level level); }; #define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT) @@ -503,8 +502,7 @@ struct i915_hw_ppgtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); - gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev, - dma_addr_t addr, + gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr, enum i915_cache_level level); int (*enable)(struct drm_device *dev); void (*cleanup)(struct i915_hw_ppgtt *ppgtt); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index cdd7b45cd501..42b5a4fc3932 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -45,8 +45,7 @@ #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, - dma_addr_t addr, +static gen6_gtt_pte_t gen6_pte_encode(dma_addr_t addr, enum i915_cache_level level) { gen6_gtt_pte_t pte = GEN6_PTE_VALID; @@ -72,8 +71,7 @@ static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, #define BYT_PTE_WRITEABLE (1 << 1) #define BYT_PTE_SNOOPED_BY_CPU_CACHES (1 << 2) -static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev, - dma_addr_t addr, +static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr, enum i915_cache_level level) { gen6_gtt_pte_t pte = GEN6_PTE_VALID; @@ -90,8 +88,7 @@ static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev, return pte; } -static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev, - dma_addr_t addr, +static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr, enum i915_cache_level level) { gen6_gtt_pte_t pte = GEN6_PTE_VALID; @@ -194,8 +191,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = ppgtt->pte_encode(ppgtt->dev, - dev_priv->gtt.scratch.addr, + scratch_pte = ppgtt->pte_encode(dev_priv->gtt.scratch.addr, I915_CACHE_LLC); while (num_entries) { @@ -231,8 +227,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, dma_addr_t page_addr; page_addr = sg_page_iter_dma_address(&sg_iter); - pt_vaddr[act_pte] = ppgtt->pte_encode(ppgtt->dev, page_addr, - cache_level); + pt_vaddr[act_pte] = ppgtt->pte_encode(page_addr, cache_level); if (++act_pte == I915_PPGTT_PT_ENTRIES) { kunmap_atomic(pt_vaddr); act_pt++; @@ -483,7 +478,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { addr = sg_page_iter_dma_address(&sg_iter); - iowrite32(dev_priv->gtt.pte_encode(dev, addr, level), + iowrite32(dev_priv->gtt.pte_encode(addr, level), >t_entries[i]); i++; } @@ -496,7 +491,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, */ if (i != 0) WARN_ON(readl(>t_entries[i-1]) - != dev_priv->gtt.pte_encode(dev, addr, level)); + != dev_priv->gtt.pte_encode(addr, level)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -521,7 +516,7 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = dev_priv->gtt.pte_encode(dev, dev_priv->gtt.scratch.addr, + scratch_pte = dev_priv->gtt.pte_encode(dev_priv->gtt.scratch.addr, I915_CACHE_LLC); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); From b2f21b4dfdd1e7396a99312c35092c8bb486a699 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:20 -0700 Subject: [PATCH 0035/6183] drm/i915: Use gtt shortform where possible Just for compactness. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 36 ++++++++++++----------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 42b5a4fc3932..66929eac6367 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -846,34 +846,28 @@ int i915_gem_gtt_init(struct drm_device *dev) int ret; if (INTEL_INFO(dev)->gen <= 5) { - dev_priv->gtt.gtt_probe = i915_gmch_probe; - dev_priv->gtt.gtt_remove = i915_gmch_remove; + gtt->gtt_probe = i915_gmch_probe; + gtt->gtt_remove = i915_gmch_remove; } else { - dev_priv->gtt.gtt_probe = gen6_gmch_probe; - dev_priv->gtt.gtt_remove = gen6_gmch_remove; - if (IS_HASWELL(dev)) { - dev_priv->gtt.pte_encode = hsw_pte_encode; - } else if (IS_VALLEYVIEW(dev)) { - dev_priv->gtt.pte_encode = byt_pte_encode; - } else { - dev_priv->gtt.pte_encode = gen6_pte_encode; - } + gtt->gtt_probe = gen6_gmch_probe; + gtt->gtt_remove = gen6_gmch_remove; + if (IS_HASWELL(dev)) + gtt->pte_encode = hsw_pte_encode; + else if (IS_VALLEYVIEW(dev)) + gtt->pte_encode = byt_pte_encode; + else + gtt->pte_encode = gen6_pte_encode; } - ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, - &dev_priv->gtt.stolen_size, - >t->mappable_base, - >t->mappable_end); + ret = gtt->gtt_probe(dev, >t->total, >t->stolen_size, + >t->mappable_base, >t->mappable_end); if (ret) return ret; /* GMADR is the PCI mmio aperture into the global GTT. */ - DRM_INFO("Memory usable by graphics device = %zdM\n", - dev_priv->gtt.total >> 20); - DRM_DEBUG_DRIVER("GMADR size = %ldM\n", - dev_priv->gtt.mappable_end >> 20); - DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", - dev_priv->gtt.stolen_size >> 20); + DRM_INFO("Memory usable by graphics device = %zdM\n", gtt->total >> 20); + DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20); + DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20); return 0; } From 5c3fe8b03ea6eb61617edb390d51c08609a495f7 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:21 -0700 Subject: [PATCH 0036/6183] drm/i915: Move fbc members out of line Signed-off-by: Ben Widawsky [danvet: Resolve conflict with Damien's FBC_CHIP_DEFAULT no fbc reason.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 50 ++++++++++++++----------- drivers/gpu/drm/i915/i915_gem_stolen.c | 20 +++++----- drivers/gpu/drm/i915/intel_display.c | 6 +-- drivers/gpu/drm/i915/intel_drv.h | 7 ---- drivers/gpu/drm/i915/intel_pm.c | 51 +++++++++++++------------- 6 files changed, 69 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c16926ca15be..f82134f8e9fb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1492,7 +1492,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) seq_puts(m, "FBC enabled\n"); } else { seq_puts(m, "FBC disabled: "); - switch (dev_priv->no_fbc_reason) { + switch (dev_priv->fbc.no_fbc_reason) { case FBC_NO_OUTPUT: seq_puts(m, "no outputs"); break; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 438cb0ab6889..d1db73a5ba0c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -528,18 +528,36 @@ struct i915_hw_context { struct i915_ctx_hang_stats hang_stats; }; -enum no_fbc_reason { - FBC_NO_OUTPUT, /* no outputs enabled to compress */ - FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */ - FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */ - FBC_MODE_TOO_LARGE, /* mode too large for compression */ - FBC_BAD_PLANE, /* fbc not supported on plane */ - FBC_NOT_TILED, /* buffer not tiled */ - FBC_MULTIPLE_PIPES, /* more than one pipe active */ - FBC_MODULE_PARAM, - FBC_CHIP_DEFAULT, /* disabled by default on this chip */ +struct i915_fbc { + unsigned long size; + unsigned int fb_id; + enum plane plane; + int y; + + struct drm_mm_node *compressed_fb; + struct drm_mm_node *compressed_llb; + + struct intel_fbc_work { + struct delayed_work work; + struct drm_crtc *crtc; + struct drm_framebuffer *fb; + int interval; + } *fbc_work; + + enum { + FBC_NO_OUTPUT, /* no outputs enabled to compress */ + FBC_STOLEN_TOO_SMALL, /* not enough space for buffers */ + FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */ + FBC_MODE_TOO_LARGE, /* mode too large for compression */ + FBC_BAD_PLANE, /* fbc not supported on plane */ + FBC_NOT_TILED, /* buffer not tiled */ + FBC_MULTIPLE_PIPES, /* more than one pipe active */ + FBC_MODULE_PARAM, + FBC_CHIP_DEFAULT, /* disabled by default on this chip */ + } no_fbc_reason; }; + enum intel_pch { PCH_NONE = 0, /* No PCH present */ PCH_IBX, /* Ibexpeak PCH */ @@ -1059,12 +1077,7 @@ typedef struct drm_i915_private { int num_plane; - unsigned long cfb_size; - unsigned int cfb_fb; - enum plane cfb_plane; - int cfb_y; - struct intel_fbc_work *fbc_work; - + struct i915_fbc fbc; struct intel_opregion opregion; struct intel_vbt_data vbt; @@ -1142,11 +1155,6 @@ typedef struct drm_i915_private { /* Haswell power well */ struct i915_power_well power_well; - enum no_fbc_reason no_fbc_reason; - - struct drm_mm_node *compressed_fb; - struct drm_mm_node *compressed_llb; - struct i915_gpu_error gpu_error; struct drm_i915_gem_object *vlv_pctx; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f713294618fe..8e023447b7eb 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -120,7 +120,7 @@ static int i915_setup_compression(struct drm_device *dev, int size) if (!compressed_llb) goto err_fb; - dev_priv->compressed_llb = compressed_llb; + dev_priv->fbc.compressed_llb = compressed_llb; I915_WRITE(FBC_CFB_BASE, dev_priv->mm.stolen_base + compressed_fb->start); @@ -128,8 +128,8 @@ static int i915_setup_compression(struct drm_device *dev, int size) dev_priv->mm.stolen_base + compressed_llb->start); } - dev_priv->compressed_fb = compressed_fb; - dev_priv->cfb_size = size; + dev_priv->fbc.compressed_fb = compressed_fb; + dev_priv->fbc.size = size; DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", size); @@ -150,7 +150,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) if (dev_priv->mm.stolen_base == 0) return -ENODEV; - if (size < dev_priv->cfb_size) + if (size < dev_priv->fbc.size) return 0; /* Release any current block */ @@ -163,16 +163,16 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->cfb_size == 0) + if (dev_priv->fbc.size == 0) return; - if (dev_priv->compressed_fb) - drm_mm_put_block(dev_priv->compressed_fb); + if (dev_priv->fbc.compressed_fb) + drm_mm_put_block(dev_priv->fbc.compressed_fb); - if (dev_priv->compressed_llb) - drm_mm_put_block(dev_priv->compressed_llb); + if (dev_priv->fbc.compressed_llb) + drm_mm_put_block(dev_priv->fbc.compressed_llb); - dev_priv->cfb_size = 0; + dev_priv->fbc.size = 0; } void i915_gem_cleanup_stolen(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d60684d9847c..112120e909ee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3408,7 +3408,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); - if (dev_priv->cfb_plane == plane) + if (dev_priv->fbc.plane == plane) intel_disable_fbc(dev); intel_crtc_update_cursor(crtc, false); @@ -3481,7 +3481,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) drm_vblank_off(dev, pipe); /* FBC must be disabled before disabling the plane on HSW. */ - if (dev_priv->cfb_plane == plane) + if (dev_priv->fbc.plane == plane) intel_disable_fbc(dev); hsw_disable_ips(intel_crtc); @@ -3720,7 +3720,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); - if (dev_priv->cfb_plane == plane) + if (dev_priv->fbc.plane == plane) intel_disable_fbc(dev); intel_crtc_dpms_overlay(intel_crtc, false); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6f7f33e70e91..5dfc1a0f2351 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -549,13 +549,6 @@ struct intel_unpin_work { bool enable_stall_check; }; -struct intel_fbc_work { - struct delayed_work work; - struct drm_crtc *crtc; - struct drm_framebuffer *fb; - int interval; -}; - int intel_pch_rawclk(struct drm_device *dev); int intel_connector_update_modes(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index aa48fc6ba4db..5b4ade682bd6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -87,7 +87,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) int plane, i; u32 fbc_ctl, fbc_ctl2; - cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; + cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; if (fb->pitches[0] < cfb_pitch) cfb_pitch = fb->pitches[0]; @@ -326,7 +326,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct drm_i915_private *dev_priv = dev->dev_private; mutex_lock(&dev->struct_mutex); - if (work == dev_priv->fbc_work) { + if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling * the prior work. */ @@ -334,12 +334,12 @@ static void intel_fbc_work_fn(struct work_struct *__work) dev_priv->display.enable_fbc(work->crtc, work->interval); - dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane; - dev_priv->cfb_fb = work->crtc->fb->base.id; - dev_priv->cfb_y = work->crtc->y; + dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane; + dev_priv->fbc.fb_id = work->crtc->fb->base.id; + dev_priv->fbc.y = work->crtc->y; } - dev_priv->fbc_work = NULL; + dev_priv->fbc.fbc_work = NULL; } mutex_unlock(&dev->struct_mutex); @@ -348,25 +348,25 @@ static void intel_fbc_work_fn(struct work_struct *__work) static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) { - if (dev_priv->fbc_work == NULL) + if (dev_priv->fbc.fbc_work == NULL) return; DRM_DEBUG_KMS("cancelling pending FBC enable\n"); /* Synchronisation is provided by struct_mutex and checking of - * dev_priv->fbc_work, so we can perform the cancellation + * dev_priv->fbc.fbc_work, so we can perform the cancellation * entirely asynchronously. */ - if (cancel_delayed_work(&dev_priv->fbc_work->work)) + if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work)) /* tasklet was killed before being run, clean up */ - kfree(dev_priv->fbc_work); + kfree(dev_priv->fbc.fbc_work); /* Mark the work as no longer wanted so that if it does * wake-up (because the work was already running and waiting * for our mutex), it will discover that is no longer * necessary to run. */ - dev_priv->fbc_work = NULL; + dev_priv->fbc.fbc_work = NULL; } static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) @@ -392,7 +392,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) work->interval = interval; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); - dev_priv->fbc_work = work; + dev_priv->fbc.fbc_work = work; /* Delay the actual enabling to let pageflipping cease and the * display to settle before starting the compression. Note that @@ -418,7 +418,7 @@ void intel_disable_fbc(struct drm_device *dev) return; dev_priv->display.disable_fbc(dev); - dev_priv->cfb_plane = -1; + dev_priv->fbc.plane = -1; } /** @@ -470,7 +470,8 @@ void intel_update_fbc(struct drm_device *dev) !to_intel_crtc(tmp_crtc)->primary_disabled) { if (crtc) { DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; + dev_priv->fbc.no_fbc_reason = + FBC_MULTIPLE_PIPES; goto out_disable; } crtc = tmp_crtc; @@ -479,7 +480,7 @@ void intel_update_fbc(struct drm_device *dev) if (!crtc || crtc->fb == NULL) { DRM_DEBUG_KMS("no output, disabling\n"); - dev_priv->no_fbc_reason = FBC_NO_OUTPUT; + dev_priv->fbc.no_fbc_reason = FBC_NO_OUTPUT; goto out_disable; } @@ -491,19 +492,19 @@ void intel_update_fbc(struct drm_device *dev) if (i915_enable_fbc < 0 && INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) { DRM_DEBUG_KMS("disabled per chip default\n"); - dev_priv->no_fbc_reason = FBC_CHIP_DEFAULT; + dev_priv->fbc.no_fbc_reason = FBC_CHIP_DEFAULT; goto out_disable; } if (!i915_enable_fbc) { DRM_DEBUG_KMS("fbc disabled per module param\n"); - dev_priv->no_fbc_reason = FBC_MODULE_PARAM; + dev_priv->fbc.no_fbc_reason = FBC_MODULE_PARAM; goto out_disable; } if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { DRM_DEBUG_KMS("mode incompatible with compression, " "disabling\n"); - dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; + dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED_MODE; goto out_disable; } @@ -517,13 +518,13 @@ void intel_update_fbc(struct drm_device *dev) if ((crtc->mode.hdisplay > max_hdisplay) || (crtc->mode.vdisplay > max_vdisplay)) { DRM_DEBUG_KMS("mode too large for compression, disabling\n"); - dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; + dev_priv->fbc.no_fbc_reason = FBC_MODE_TOO_LARGE; goto out_disable; } if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) && intel_crtc->plane != 0) { DRM_DEBUG_KMS("plane not 0, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_BAD_PLANE; + dev_priv->fbc.no_fbc_reason = FBC_BAD_PLANE; goto out_disable; } @@ -533,7 +534,7 @@ void intel_update_fbc(struct drm_device *dev) if (obj->tiling_mode != I915_TILING_X || obj->fence_reg == I915_FENCE_REG_NONE) { DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_NOT_TILED; + dev_priv->fbc.no_fbc_reason = FBC_NOT_TILED; goto out_disable; } @@ -543,7 +544,7 @@ void intel_update_fbc(struct drm_device *dev) if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) { DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + dev_priv->fbc.no_fbc_reason = FBC_STOLEN_TOO_SMALL; goto out_disable; } @@ -552,9 +553,9 @@ void intel_update_fbc(struct drm_device *dev) * cannot be unpinned (and have its GTT offset and fence revoked) * without first being decoupled from the scanout and FBC disabled. */ - if (dev_priv->cfb_plane == intel_crtc->plane && - dev_priv->cfb_fb == fb->base.id && - dev_priv->cfb_y == crtc->y) + if (dev_priv->fbc.plane == intel_crtc->plane && + dev_priv->fbc.fb_id == fb->base.id && + dev_priv->fbc.y == crtc->y) return; if (intel_fbc_enabled(dev)) { From 911bdf0ae6405db3313c6e5798cf08640fdd0714 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 27 Jun 2013 16:30:23 -0700 Subject: [PATCH 0037/6183] drm/i915: Move gtt_mtrr to i915_gtt for file in `ls drivers/gpu/drm/i915/*.c` ; do sed -i "s/mm.gtt_mtrr/gtt.mtrr/" $file; done Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 ++++---- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index adb319b53ecd..0e2214236083 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1558,8 +1558,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_rmmap; } - dev_priv->mm.gtt_mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base, - aperture_size); + dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base, + aperture_size); /* The i915 workqueue is primarily used for batched retirement of * requests (and thus managing bo) once the task has been completed @@ -1667,7 +1667,7 @@ out_gem_unload: intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); out_mtrrfree: - arch_phys_wc_del(dev_priv->mm.gtt_mtrr); + arch_phys_wc_del(dev_priv->gtt.mtrr); io_mapping_free(dev_priv->gtt.mappable); dev_priv->gtt.gtt_remove(dev); out_rmmap: @@ -1705,7 +1705,7 @@ int i915_driver_unload(struct drm_device *dev) cancel_delayed_work_sync(&dev_priv->mm.retire_work); io_mapping_free(dev_priv->gtt.mappable); - arch_phys_wc_del(dev_priv->mm.gtt_mtrr); + arch_phys_wc_del(dev_priv->gtt.mtrr); acpi_video_unregister(); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d1db73a5ba0c..da07f6f28854 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -470,6 +470,8 @@ struct i915_gtt { struct page *page; } scratch; + int mtrr; + /* global gtt ops */ int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, size_t *stolen, phys_addr_t *mappable_base, @@ -834,8 +836,6 @@ struct i915_gem_mm { /** Usable portion of the GTT for GEM */ unsigned long stolen_base; /* limited to low memory (32-bit) */ - int gtt_mtrr; - /** PPGTT used for aliasing the PPGTT with the GTT */ struct i915_hw_ppgtt *aliasing_ppgtt; From c93f54cf7de31d44b4036d0d1e291172b2bd5743 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 19:47:19 +0200 Subject: [PATCH 0038/6183] drm/i915: pixel multiplier readout support for pch ports Now that we painstakingly track the shared pch dplls we can finally implement pixel mutliplier readout support for pch ports, too. v2: Undo the temporary hack to disable the sdvo pixel multiplier cross-checking. Cc: Imre Deak Cc: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ drivers/gpu/drm/i915/intel_sdvo.c | 3 --- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 112120e909ee..65e8f5e512d2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5815,10 +5815,6 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, ironlake_get_fdi_m_n_config(crtc, pipe_config); - /* XXX: Can't properly read out the pch dpll pixel multiplier - * since we don't have state tracking for pch clocks yet. */ - pipe_config->pixel_multiplier = 1; - if (HAS_PCH_IBX(dev_priv->dev)) { pipe_config->shared_dpll = crtc->pipe; } else { @@ -5833,6 +5829,11 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, WARN_ON(!pll->get_hw_state(dev_priv, pll, &pipe_config->dpll_hw_state)); + + tmp = pipe_config->dpll_hw_state.dpll; + pipe_config->pixel_multiplier = + ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK) + >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1; } else { pipe_config->pixel_multiplier = 1; } @@ -8083,8 +8084,7 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start); PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end); - if (!HAS_PCH_SPLIT(dev)) - PIPE_CONF_CHECK_I(pixel_multiplier); + PIPE_CONF_CHECK_I(pixel_multiplier); PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, DRM_MODE_FLAG_INTERLACE); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2628d5622449..8415d6a610dd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1370,9 +1370,6 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, break; } - if(HAS_PCH_SPLIT(dev)) - return; /* no pixel multiplier readout support yet */ - WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier, "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n", pipe_config->pixel_multiplier, encoder_pixel_multiplier); From 2385bdf0787aef45ee1847b8508a417433da7e14 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 26 Jun 2013 01:38:15 +0300 Subject: [PATCH 0039/6183] drm/i915: add fastboot param for fast & loose mode setting Handling all the state properly for fastboot is still not yet done by far, but we need some way to be able to test what we currently have. So hide the not-yet-quite-complete stuff behind a module option. Signed-off-by: Jesse Barnes [danvet: Add a real commit message.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 5 +++++ drivers/gpu/drm/i915/i915_drv.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 062cbda1bf4a..33cb97388fc9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -132,6 +132,11 @@ int i915_enable_ips __read_mostly = 1; module_param_named(enable_ips, i915_enable_ips, int, 0600); MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)"); +bool i915_fastboot __read_mostly = 0; +module_param_named(fastboot, i915_fastboot, bool, 0600); +MODULE_PARM_DESC(fastboot, "Try to skip unnecessary mode sets at boot time " + "(default: false)"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index da07f6f28854..4a23e957b85c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1551,6 +1551,7 @@ extern int i915_enable_ppgtt __read_mostly; extern unsigned int i915_preliminary_hw_support __read_mostly; extern int i915_disable_power_well __read_mostly; extern int i915_enable_ips __read_mostly; +extern bool i915_fastboot __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); From f1f644dc66cbaf5a4c7dcde683361536b41885b9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 27 Jun 2013 00:39:25 +0300 Subject: [PATCH 0040/6183] drm/i915: get mode clock when reading the pipe config v9 We need this for comparing modes between configuration changes. The tricky part is to allow us to reuse the new get_clock stuff to recover the lvds clock on gen2/3 when neither the vbt has an lvds mode nor the panel a (useful) EDID. v2: try harder to calulate non-simple pixel clocks (Daniel) call get_clock after getting the encoder config, needed for pixel multiply (Jesse) v3: drop get_clock now that the pixel_multiply has been moved into get_pipe_config v4: re-add get_clock; we need to get the pixel multiplier in the encoder, so need to calculate the clock value after the encoder's get_config is called v5: drop hsw clock_get, still needs to be written v6: add fuzzy clock check (Daniel) v7: wrap fuzzy clock check under !IS_HASWELL use port_clock field rather than a new CPU eDP clock field in crtc_config v8: remove stale pixel_multiplier sets (Daniel) multiply by pixel_multiplier in 9xx clock get too (Daniel) v9: make sure we set pixel_multiplier before calling clock_get from mode_get for LVDS (Daniel) Signed-off-by: Jesse Barnes [danvet: Add some explanation to the commit message about why we have to jump through a few hoops. Also remove the rebase-fail hunk from intel_sdvo.c] [danvet: Squash in the fixup from Jesse to also call ->get_clock in the modeset state checker.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 126 ++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_dp.c | 7 ++ 3 files changed, 123 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4a23e957b85c..810c9fab525e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -367,6 +367,7 @@ struct drm_i915_display_funcs { * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, struct intel_crtc_config *); + void (*get_clock)(struct intel_crtc *, struct intel_crtc_config *); int (*crtc_mode_set)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 65e8f5e512d2..9c05e57fb7ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -45,6 +45,11 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type); static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); +static void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config); +static void ironlake_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config); + typedef struct { int min, max; } intel_range_t; @@ -6853,11 +6858,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, } /* Returns the clock of the currently programmed mode of the given pipe. */ -static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) +static void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) { + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; + int pipe = pipe_config->cpu_transcoder; u32 dpll = I915_READ(DPLL(pipe)); u32 fp; intel_clock_t clock; @@ -6896,7 +6902,8 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) default: DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed " "mode\n", (int)(dpll & DPLL_MODE_MASK)); - return 0; + pipe_config->adjusted_mode.clock = 0; + return; } if (IS_PINEVIEW(dev)) @@ -6933,12 +6940,55 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) } } - /* XXX: It would be nice to validate the clocks, but we can't reuse - * i830PllIsValid() because it relies on the xf86_config connector - * configuration being accurate, which it isn't necessarily. + pipe_config->adjusted_mode.clock = clock.dot * + pipe_config->pixel_multiplier; +} + +static void ironlake_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; + int link_freq, repeat; + u64 clock; + u32 link_m, link_n; + + repeat = pipe_config->pixel_multiplier; + + /* + * The calculation for the data clock is: + * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp + * But we want to avoid losing precison if possible, so: + * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp)) + * + * and the link clock is simpler: + * link_clock = (m * link_clock * repeat) / n */ - return clock.dot; + /* + * We need to get the FDI or DP link clock here to derive + * the M/N dividers. + * + * For FDI, we read it from the BIOS or use a fixed 2.7GHz. + * For DP, it's either 1.62GHz or 2.7GHz. + * We do our calculations in 10*MHz since we don't need much precison. + */ + if (pipe_config->has_pch_encoder) + link_freq = intel_fdi_link_freq(dev) * 10000; + else + link_freq = pipe_config->port_clock; + + link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder)); + link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder)); + + if (!link_m || !link_n) + return; + + clock = ((u64)link_m * (u64)link_freq * (u64)repeat); + do_div(clock, link_n); + + pipe_config->adjusted_mode.clock = clock; } /** Returns the currently programmed mode of the given pipe. */ @@ -6949,6 +6999,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; struct drm_display_mode *mode; + struct intel_crtc_config pipe_config; int htot = I915_READ(HTOTAL(cpu_transcoder)); int hsync = I915_READ(HSYNC(cpu_transcoder)); int vtot = I915_READ(VTOTAL(cpu_transcoder)); @@ -6958,7 +7009,18 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, if (!mode) return NULL; - mode->clock = intel_crtc_clock_get(dev, crtc); + /* + * Construct a pipe_config sufficient for getting the clock info + * back out of crtc_clock_get. + * + * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need + * to use a real value here instead. + */ + pipe_config.cpu_transcoder = intel_crtc->pipe; + pipe_config.pixel_multiplier = 1; + i9xx_crtc_clock_get(intel_crtc, &pipe_config); + + mode->clock = pipe_config.adjusted_mode.clock; mode->hdisplay = (htot & 0xffff) + 1; mode->htotal = ((htot & 0xffff0000) >> 16) + 1; mode->hsync_start = (hsync & 0xffff) + 1; @@ -8019,6 +8081,28 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) } +static bool intel_fuzzy_clock_check(struct intel_crtc_config *cur, + struct intel_crtc_config *new) +{ + int clock1, clock2, diff; + + clock1 = cur->adjusted_mode.clock; + clock2 = new->adjusted_mode.clock; + + if (clock1 == clock2) + return true; + + if (!clock1 || !clock2) + return false; + + diff = abs(clock1 - clock2); + + if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105) + return true; + + return false; +} + #define for_each_intel_crtc_masked(dev, mask, intel_crtc) \ list_for_each_entry((intel_crtc), \ &(dev)->mode_config.crtc_list, \ @@ -8124,6 +8208,15 @@ intel_pipe_config_compare(struct drm_device *dev, #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_QUIRK + if (!IS_HASWELL(dev)) { + if (!intel_fuzzy_clock_check(current_config, pipe_config)) { + DRM_ERROR("mismatch in clock (expected %d, found %d\n", + current_config->adjusted_mode.clock, + pipe_config->adjusted_mode.clock); + return false; + } + } + return true; } @@ -8249,8 +8342,12 @@ check_crtc_state(struct drm_device *dev) base.head) { if (encoder->base.crtc != &crtc->base) continue; - if (encoder->get_config) + if (encoder->get_config && + dev_priv->display.get_clock) { encoder->get_config(encoder, &pipe_config); + dev_priv->display.get_clock(crtc, + &pipe_config); + } } WARN(crtc->active != active, @@ -9253,6 +9350,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = ironlake_update_plane; } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.get_pipe_config = ironlake_get_pipe_config; + dev_priv->display.get_clock = ironlake_crtc_clock_get; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; @@ -9260,6 +9358,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = ironlake_update_plane; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.get_clock = i9xx_crtc_clock_get; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; @@ -9267,6 +9366,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = i9xx_update_plane; } else { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.get_clock = i9xx_crtc_clock_get; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; @@ -9813,8 +9913,12 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) if (encoder->get_hw_state(encoder, &pipe)) { crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); encoder->base.crtc = &crtc->base; - if (encoder->get_config) + if (encoder->get_config && + dev_priv->display.get_clock) { encoder->get_config(encoder, &crtc->config); + dev_priv->display.get_clock(crtc, + &crtc->config); + } } else { encoder->base.crtc = NULL; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b73971234013..11eb697dec01 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1355,6 +1355,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder, } pipe_config->adjusted_mode.flags |= flags; + + if (dp_to_dig_port(intel_dp)->port == PORT_A) { + if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ) + pipe_config->port_clock = 162000; + else + pipe_config->port_clock = 270000; + } } static void intel_disable_dp(struct intel_encoder *encoder) From babea61dfb82b4bdfdbc57ebf081ef6c16ffd524 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 26 Jun 2013 18:57:38 +0300 Subject: [PATCH 0041/6183] drm/i915: copy fetched mode state into crtc at setup_hw time v5 We already fetch and track other state into the main CRTC and encoder structs, and for fastboot we need to do the same with the mode and clock data we read out. v2: fix debug print v3: use fastboot param around state copy v4: set clock and flags for crtc here instead of in setup_hw_state v5: rename function to intel_crtc_mode_from_pipe_config for consistency (Chris) Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9c05e57fb7ae..2e6fc4ce8ec9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4716,6 +4716,27 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc, pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1; } +static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_crtc *crtc = &intel_crtc->base; + + crtc->mode.hdisplay = pipe_config->adjusted_mode.crtc_hdisplay; + crtc->mode.htotal = pipe_config->adjusted_mode.crtc_htotal; + crtc->mode.hsync_start = pipe_config->adjusted_mode.crtc_hsync_start; + crtc->mode.hsync_end = pipe_config->adjusted_mode.crtc_hsync_end; + + crtc->mode.vdisplay = pipe_config->adjusted_mode.crtc_vdisplay; + crtc->mode.vtotal = pipe_config->adjusted_mode.crtc_vtotal; + crtc->mode.vsync_start = pipe_config->adjusted_mode.crtc_vsync_start; + crtc->mode.vsync_end = pipe_config->adjusted_mode.crtc_vsync_end; + + crtc->mode.flags = pipe_config->adjusted_mode.flags; + + crtc->mode.clock = pipe_config->adjusted_mode.clock; + crtc->mode.flags |= pipe_config->adjusted_mode.flags; +} + static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; @@ -9961,6 +9982,22 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, intel_modeset_readout_hw_state(dev); + /* + * Now that we have the config, copy it to each CRTC struct + * Note that this could go away if we move to using crtc_config + * checking everywhere. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (crtc->active && i915_fastboot) { + intel_crtc_mode_from_pipe_config(crtc, &crtc->config); + + DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", + crtc->base.base.id); + drm_mode_debug_printmodeline(&crtc->base.mode); + } + } + /* HW state is read out, now we need to sanitize this mess. */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { From 4d6a3e63bce0cb604864e36585ca8983160a421a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 26 Jun 2013 01:38:18 +0300 Subject: [PATCH 0042/6183] drm/i915: turn off panel fitting at flip time if needed v2 Need better pfit tracking to do this right. v2: use fastboot param around this hack Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e6fc4ce8ec9..6c0014d84812 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2221,6 +2221,20 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } + /* Update pipe size and adjust fitter if needed */ + if (i915_fastboot) { + I915_WRITE(PIPESRC(intel_crtc->pipe), + ((crtc->mode.hdisplay - 1) << 16) | + (crtc->mode.vdisplay - 1)); + if (!intel_crtc->config.pch_pfit.size && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { + I915_WRITE(PF_CTL(intel_crtc->pipe), 0); + I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0); + I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0); + } + } + ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); From 319d9827ebb55d58d1b02d8a4eba48bbb2702376 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 26 Jun 2013 01:38:19 +0300 Subject: [PATCH 0043/6183] drm/i915: flip on a no fb -> fb transition if crtc is active v3 If the crtc is active, we can simply flip a new fb onto it, provided the other mode setting reqs are met. Otherwise, we'll need to do a full mode set to re-enable the crtc. v2: check for crtc active and set mode_changed accordingly v3: add module parameter, i915.fastboot, to control no fb -> fb flip behavior Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6c0014d84812..2ab34e57ba4a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8676,8 +8676,16 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, } else if (set->crtc->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ if (set->crtc->fb == NULL) { - DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); - config->mode_changed = true; + struct intel_crtc *intel_crtc = + to_intel_crtc(set->crtc); + + if (intel_crtc->active && i915_fastboot) { + DRM_DEBUG_KMS("crtc has no fb, will flip\n"); + config->fb_changed = true; + } else { + DRM_DEBUG_KMS("inactive crtc, full mode set\n"); + config->mode_changed = true; + } } else if (set->fb == NULL) { config->mode_changed = true; } else if (set->fb->pixel_format != From fc16b48be665d94337a861486dd25499971742a2 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 6 Jun 2013 15:18:39 +0300 Subject: [PATCH 0044/6183] drm/i915: export error state to string conversion In preparation for accessing error state from sysfs, export error state to string conversion function. Also tuck buffer error handling inside the function. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 24 ++++++++---------------- drivers/gpu/drm/i915/i915_drv.h | 7 +++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f82134f8e9fb..b64af15eb388 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -830,15 +830,8 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); } -struct i915_error_state_file_priv { - struct drm_device *dev; - struct drm_i915_error_state *error; -}; - - -static int i915_error_state(struct i915_error_state_file_priv *error_priv, - struct drm_i915_error_state_buf *m) - +int i915_error_state_to_str(struct drm_i915_error_state_buf *m, + const struct i915_error_state_file_priv *error_priv) { struct drm_device *dev = error_priv->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -848,7 +841,7 @@ static int i915_error_state(struct i915_error_state_file_priv *error_priv, if (!error) { err_printf(m, "no error state collected\n"); - return 0; + goto out; } err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, @@ -958,6 +951,10 @@ static int i915_error_state(struct i915_error_state_file_priv *error_priv, if (error->display) intel_display_print_error_state(m, dev, error->display); +out: + if (m->bytes == 0 && m->err) + return m->err; + return 0; } @@ -1051,15 +1048,10 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf, error_str.start = *pos; - ret = i915_error_state(error_priv, &error_str); + ret = i915_error_state_to_str(&error_str, error_priv); if (ret) goto out; - if (error_str.bytes == 0 && error_str.err) { - ret = error_str.err; - goto out; - } - ret_count = simple_read_from_buffer(userbuf, count, &tmp_pos, error_str.buf, error_str.bytes); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 810c9fab525e..52fe9763b969 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -916,6 +916,11 @@ struct drm_i915_error_state_buf { loff_t pos; }; +struct i915_error_state_file_priv { + struct drm_device *dev; + struct drm_i915_error_state *error; +}; + struct i915_gpu_error { /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ @@ -1921,6 +1926,8 @@ int i915_debugfs_init(struct drm_minor *minor); void i915_debugfs_cleanup(struct drm_minor *minor); __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); +int i915_error_state_to_str(struct drm_i915_error_state_buf *estr, + const struct i915_error_state_file_priv *error); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); From 95d5bfb3ac4cf5d7311f496761506c676f6b6323 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 6 Jun 2013 15:18:40 +0300 Subject: [PATCH 0045/6183] drm/i915: export error state ref handling In preparation for sysfs error state access, export ref error state ref counting interface. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 31 ++++++++++++++++++++--------- drivers/gpu/drm/i915/i915_drv.h | 3 +++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b64af15eb388..eef4c01ab61a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -980,12 +980,30 @@ i915_error_state_write(struct file *filp, return cnt; } +void i915_error_state_get(struct drm_device *dev, + struct i915_error_state_file_priv *error_priv) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error_priv->error = dev_priv->gpu_error.first_error; + if (error_priv->error) + kref_get(&error_priv->error->ref); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + +} + +void i915_error_state_put(struct i915_error_state_file_priv *error_priv) +{ + if (error_priv->error) + kref_put(&error_priv->error->ref, i915_error_state_free); +} + static int i915_error_state_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; - drm_i915_private_t *dev_priv = dev->dev_private; struct i915_error_state_file_priv *error_priv; - unsigned long flags; error_priv = kzalloc(sizeof(*error_priv), GFP_KERNEL); if (!error_priv) @@ -993,11 +1011,7 @@ static int i915_error_state_open(struct inode *inode, struct file *file) error_priv->dev = dev; - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - error_priv->error = dev_priv->gpu_error.first_error; - if (error_priv->error) - kref_get(&error_priv->error->ref); - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + i915_error_state_get(dev, error_priv); file->private_data = error_priv; @@ -1008,8 +1022,7 @@ static int i915_error_state_release(struct inode *inode, struct file *file) { struct i915_error_state_file_priv *error_priv = file->private_data; - if (error_priv->error) - kref_put(&error_priv->error->ref, i915_error_state_free); + i915_error_state_put(error_priv); kfree(error_priv); return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 52fe9763b969..bc4a84ac04cb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1928,6 +1928,9 @@ __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); int i915_error_state_to_str(struct drm_i915_error_state_buf *estr, const struct i915_error_state_file_priv *error); +void i915_error_state_get(struct drm_device *dev, + struct i915_error_state_file_priv *error_priv); +void i915_error_state_put(struct i915_error_state_file_priv *error_priv); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); From 4dc955f7f5241a92767e2b3ffd74f49a82938999 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 6 Jun 2013 15:18:41 +0300 Subject: [PATCH 0046/6183] drm/i915: introduce i915_error_state_buf_init Make function for struct i915_error_state_buf initialization and export it, for sysfs and debugfs. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 60 +++++++++++++++++------------ drivers/gpu/drm/i915/i915_drv.h | 7 ++++ 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index eef4c01ab61a..3e36756d0439 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1028,6 +1028,36 @@ static int i915_error_state_release(struct inode *inode, struct file *file) return 0; } +int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf, + size_t count, loff_t pos) +{ + memset(ebuf, 0, sizeof(*ebuf)); + + /* We need to have enough room to store any i915_error_state printf + * so that we can move it to start position. + */ + ebuf->size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE; + ebuf->buf = kmalloc(ebuf->size, + GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN); + + if (ebuf->buf == NULL) { + ebuf->size = PAGE_SIZE; + ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY); + } + + if (ebuf->buf == NULL) { + ebuf->size = 128; + ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY); + } + + if (ebuf->buf == NULL) + return -ENOMEM; + + ebuf->start = pos; + + return 0; +} + static ssize_t i915_error_state_read(struct file *file, char __user *userbuf, size_t count, loff_t *pos) { @@ -1035,31 +1065,11 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf, struct drm_i915_error_state_buf error_str; loff_t tmp_pos = 0; ssize_t ret_count = 0; - int ret = 0; + int ret; - memset(&error_str, 0, sizeof(error_str)); - - /* We need to have enough room to store any i915_error_state printf - * so that we can move it to start position. - */ - error_str.size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE; - error_str.buf = kmalloc(error_str.size, - GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN); - - if (error_str.buf == NULL) { - error_str.size = PAGE_SIZE; - error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY); - } - - if (error_str.buf == NULL) { - error_str.size = 128; - error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY); - } - - if (error_str.buf == NULL) - return -ENOMEM; - - error_str.start = *pos; + ret = i915_error_state_buf_init(&error_str, count, *pos); + if (ret) + return ret; ret = i915_error_state_to_str(&error_str, error_priv); if (ret) @@ -1074,7 +1084,7 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf, else *pos = error_str.start + ret_count; out: - kfree(error_str.buf); + i915_error_state_buf_release(&error_str); return ret ?: ret_count; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bc4a84ac04cb..a7c2cfb3ee97 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1931,6 +1931,13 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *estr, void i915_error_state_get(struct drm_device *dev, struct i915_error_state_file_priv *error_priv); void i915_error_state_put(struct i915_error_state_file_priv *error_priv); +int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb, + size_t count, loff_t pos); +static inline void i915_error_state_buf_release( + struct drm_i915_error_state_buf *eb) +{ + kfree(eb->buf); +} /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); From ef86ddced720fddc3835558447a7f594d3609c73 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 6 Jun 2013 17:38:54 +0300 Subject: [PATCH 0047/6183] drm/i915: add error_state sysfs entry As getting error state doesn't anymore require big kmallocs, make error state accessible also from sysfs. v2: - error state clearing (Chris Wilson) - user hint, proper access mode bits and name (Daniel Vetter) v3: release resources in proper order (Chris Wilson) Suggested-by: Daniel Vetter Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson [danvet: Apply Chris' s/error_state/error/ bikeshed on the sysfs name. Also update the dmesg message, spotted by Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 3 +- drivers/gpu/drm/i915/i915_sysfs.c | 71 +++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6ca6097aa48f..4c1b1e3dbf79 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1921,8 +1921,7 @@ static void i915_capture_error_state(struct drm_device *dev) } DRM_INFO("capturing error event; look for more information in " - "/sys/kernel/debug/dri/%d/i915_error_state\n", - dev->primary->index); + "/sys/class/drm/card%d/error\n", dev->primary->index); kref_init(&error->ref); error->eir = I915_READ(EIR); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 6875b5654c63..a777e7f3b0df 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -409,6 +409,71 @@ static const struct attribute *gen6_attrs[] = { NULL, }; +static ssize_t error_state_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + + struct device *kdev = container_of(kobj, struct device, kobj); + struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); + struct drm_device *dev = minor->dev; + struct i915_error_state_file_priv error_priv; + struct drm_i915_error_state_buf error_str; + ssize_t ret_count = 0; + int ret; + + memset(&error_priv, 0, sizeof(error_priv)); + + ret = i915_error_state_buf_init(&error_str, count, off); + if (ret) + return ret; + + error_priv.dev = dev; + i915_error_state_get(dev, &error_priv); + + ret = i915_error_state_to_str(&error_str, &error_priv); + if (ret) + goto out; + + ret_count = count < error_str.bytes ? count : error_str.bytes; + + memcpy(buf, error_str.buf, ret_count); +out: + i915_error_state_put(&error_priv); + i915_error_state_buf_release(&error_str); + + return ret ?: ret_count; +} + +static ssize_t error_state_write(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *kdev = container_of(kobj, struct device, kobj); + struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); + struct drm_device *dev = minor->dev; + int ret; + + DRM_DEBUG_DRIVER("Resetting error state\n"); + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + i915_destroy_error_state(dev); + mutex_unlock(&dev->struct_mutex); + + return count; +} + +static struct bin_attribute error_state_attr = { + .attr.name = "error", + .attr.mode = S_IRUSR | S_IWUSR, + .size = 0, + .read = error_state_read, + .write = error_state_write, +}; + void i915_setup_sysfs(struct drm_device *dev) { int ret; @@ -432,10 +497,16 @@ void i915_setup_sysfs(struct drm_device *dev) if (ret) DRM_ERROR("gen6 sysfs setup failed\n"); } + + ret = sysfs_create_bin_file(&dev->primary->kdev.kobj, + &error_state_attr); + if (ret) + DRM_ERROR("error_state sysfs setup failed\n"); } void i915_teardown_sysfs(struct drm_device *dev) { + sysfs_remove_bin_file(&dev->primary->kdev.kobj, &error_state_attr); sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs); device_remove_bin_file(&dev->primary->kdev, &dpf_attrs); #ifdef CONFIG_PM From 6f02488e3a5cbd76974b9d56140b11f3aa012124 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 1 Jul 2013 10:19:09 -0700 Subject: [PATCH 0048/6183] drm/i915: fixup messages in pipe_config_compare Print out the flag that failed and fix up a mismatched paren. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2ab34e57ba4a..6b0013cc962f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8169,7 +8169,7 @@ intel_pipe_config_compare(struct drm_device *dev, #define PIPE_CONF_CHECK_FLAGS(name, mask) \ if ((current_config->name ^ pipe_config->name) & (mask)) { \ - DRM_ERROR("mismatch in " #name " " \ + DRM_ERROR("mismatch in " #name "(" #mask ") " \ "(expected %i, found %i)\n", \ current_config->name & (mask), \ pipe_config->name & (mask)); \ @@ -8245,7 +8245,7 @@ intel_pipe_config_compare(struct drm_device *dev, if (!IS_HASWELL(dev)) { if (!intel_fuzzy_clock_check(current_config, pipe_config)) { - DRM_ERROR("mismatch in clock (expected %d, found %d\n", + DRM_ERROR("mismatch in clock (expected %d, found %d)\n", current_config->adjusted_mode.clock, pipe_config->adjusted_mode.clock); return false; From 510d5f2f6b97eccbfa08234e21b0577c1748807d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 1 Jul 2013 15:50:17 -0700 Subject: [PATCH 0049/6183] drm/i915: split encoder get_config calls from crtc get_clock calls This should help on HSW, where we don't currently have a get_clock call. Reported-by: Paulo Zanoni Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6b0013cc962f..76796b179170 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8377,14 +8377,13 @@ check_crtc_state(struct drm_device *dev) base.head) { if (encoder->base.crtc != &crtc->base) continue; - if (encoder->get_config && - dev_priv->display.get_clock) { + if (encoder->get_config) encoder->get_config(encoder, &pipe_config); - dev_priv->display.get_clock(crtc, - &pipe_config); - } } + if (dev_priv->display.get_clock) + dev_priv->display.get_clock(crtc, &pipe_config); + WARN(crtc->active != active, "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); @@ -9956,12 +9955,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) if (encoder->get_hw_state(encoder, &pipe)) { crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); encoder->base.crtc = &crtc->base; - if (encoder->get_config && - dev_priv->display.get_clock) { + if (encoder->get_config) encoder->get_config(encoder, &crtc->config); - dev_priv->display.get_clock(crtc, - &crtc->config); - } } else { encoder->base.crtc = NULL; } @@ -9974,6 +9969,15 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) pipe); } + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (!crtc->active) + continue; + if (dev_priv->display.get_clock) + dev_priv->display.get_clock(crtc, + &crtc->config); + } + list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { if (connector->get_hw_state(connector)) { From f825c736e75b11adb59ec52a4a1096efddd2ec97 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 2 Jul 2013 11:15:15 +0530 Subject: [PATCH 0050/6183] mm/cma: Move dma contiguous changes into a seperate config We want to use CMA for allocating hash page table and real mode area for PPC64. Hence move DMA contiguous related changes into a seperate config so that ppc64 can enable CMA without requiring DMA contiguous. Acked-by: Michal Nazarewicz Acked-by: Paul Mackerras Signed-off-by: Aneesh Kumar K.V [removed defconfig changes] Signed-off-by: Marek Szyprowski --- arch/arm/include/asm/dma-contiguous.h | 2 +- arch/arm/mm/dma-mapping.c | 6 +++--- drivers/base/Kconfig | 20 ++++---------------- drivers/base/Makefile | 2 +- include/linux/dma-contiguous.h | 2 +- mm/Kconfig | 24 ++++++++++++++++++++++++ 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h index 3ed37b4d93da..e072bb2ba1b1 100644 --- a/arch/arm/include/asm/dma-contiguous.h +++ b/arch/arm/include/asm/dma-contiguous.h @@ -2,7 +2,7 @@ #define ASMARM_DMA_CONTIGUOUS_H #ifdef __KERNEL__ -#ifdef CONFIG_CMA +#ifdef CONFIG_DMA_CMA #include #include diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index ef3e0f3aac96..1fb40dc37ec2 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -358,7 +358,7 @@ static int __init atomic_pool_init(void) if (!pages) goto no_pages; - if (IS_ENABLED(CONFIG_CMA)) + if (IS_ENABLED(CONFIG_DMA_CMA)) ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page, atomic_pool_init); else @@ -670,7 +670,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, addr = __alloc_simple_buffer(dev, size, gfp, &page); else if (!(gfp & __GFP_WAIT)) addr = __alloc_from_pool(size, &page); - else if (!IS_ENABLED(CONFIG_CMA)) + else if (!IS_ENABLED(CONFIG_DMA_CMA)) addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); else addr = __alloc_from_contiguous(dev, size, prot, &page, caller); @@ -759,7 +759,7 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr, __dma_free_buffer(page, size); } else if (__free_from_pool(cpu_addr, size)) { return; - } else if (!IS_ENABLED(CONFIG_CMA)) { + } else if (!IS_ENABLED(CONFIG_DMA_CMA)) { __dma_free_remap(cpu_addr, size); __dma_free_buffer(page, size); } else { diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 07abd9d76f7f..10cd80af2aec 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -202,11 +202,9 @@ config DMA_SHARED_BUFFER APIs extension; the file's descriptor can then be passed on to other driver. -config CMA - bool "Contiguous Memory Allocator" - depends on HAVE_DMA_CONTIGUOUS && HAVE_MEMBLOCK - select MIGRATION - select MEMORY_ISOLATION +config DMA_CMA + bool "DMA Contiguous Memory Allocator" + depends on HAVE_DMA_CONTIGUOUS && CMA help This enables the Contiguous Memory Allocator which allows drivers to allocate big physically-contiguous blocks of memory for use with @@ -215,17 +213,7 @@ config CMA For more information see . If unsure, say "n". -if CMA - -config CMA_DEBUG - bool "CMA debug messages (DEVELOPMENT)" - depends on DEBUG_KERNEL - help - Turns on debug messages in CMA. This produces KERN_DEBUG - messages for every CMA call as well as various messages while - processing calls such as dma_alloc_from_contiguous(). - This option does not affect warning and error messages. - +if DMA_CMA comment "Default contiguous memory area size:" config CMA_SIZE_MBYTES diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 4e22ce3ed73d..5d93bb519753 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -6,7 +6,7 @@ obj-y := core.o bus.o dd.o syscore.o \ attribute_container.o transport_class.o \ topology.o obj-$(CONFIG_DEVTMPFS) += devtmpfs.o -obj-$(CONFIG_CMA) += dma-contiguous.o +obj-$(CONFIG_DMA_CMA) += dma-contiguous.o obj-y += power/ obj-$(CONFIG_HAS_DMA) += dma-mapping.o obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h index 01b5c84be828..00141d3325fe 100644 --- a/include/linux/dma-contiguous.h +++ b/include/linux/dma-contiguous.h @@ -57,7 +57,7 @@ struct cma; struct page; struct device; -#ifdef CONFIG_CMA +#ifdef CONFIG_DMA_CMA /* * There is always at least global CMA area and a few optional device diff --git a/mm/Kconfig b/mm/Kconfig index e742d06285b7..26a5f815cfc3 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -477,3 +477,27 @@ config FRONTSWAP and swap data is stored as normal on the matching swap device. If unsure, say Y to enable frontswap. + +config CMA + bool "Contiguous Memory Allocator" + depends on HAVE_MEMBLOCK + select MIGRATION + select MEMORY_ISOLATION + help + This enables the Contiguous Memory Allocator which allows other + subsystems to allocate big physically-contiguous blocks of memory. + CMA reserves a region of memory and allows only movable pages to + be allocated from it. This way, the kernel can use the memory for + pagecache and when a subsystem requests for contiguous area, the + allocated pages are migrated away to serve the contiguous request. + + If unsure, say "n". + +config CMA_DEBUG + bool "CMA debug messages (DEVELOPMENT)" + depends on DEBUG_KERNEL && CMA + help + Turns on debug messages in CMA. This produces KERN_DEBUG + messages for every CMA call as well as various messages while + processing calls such as dma_alloc_from_contiguous(). + This option does not affect warning and error messages. From e8474409d7ab6dac38d4a3a6a365504b302f6c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Jun 2013 17:43:24 +0300 Subject: [PATCH 0051/6183] drm/i915: Use wait_for() to wait for Punit to change GPU freq on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use wait_for() instead of the open coded loop to avoid spreading the same old timeout related bugs. This changes the loop to use msleep(1) instead of udelay(10) when the Punit had not yet completed the frequency change. In practice that doesn't seem to hurt performance as the Punit appears to be ready pretty much always. Also give the status bit a name, instead of using the magic number 1. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 11 ++--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index f2326fc60ac9..9b51be800961 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -363,6 +363,7 @@ #define PUNIT_REG_GPU_LFM 0xd3 #define PUNIT_REG_GPU_FREQ_REQ 0xd4 #define PUNIT_REG_GPU_FREQ_STS 0xd8 +#define GENFREQSTATUS (1<<0) #define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc #define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5b4ade682bd6..7cfd3b74d9b7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3075,19 +3075,12 @@ void gen6_set_rps(struct drm_device *dev, u8 val) */ static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) { - unsigned long timeout = jiffies + msecs_to_jiffies(10); u32 pval; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); - do { - pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - if (time_after(jiffies, timeout)) { - DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); - break; - } - udelay(10); - } while (pval & 1); + if (wait_for(((pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS)) & GENFREQSTATUS) == 0, 10)) + DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); pval >>= 8; From 56a942e9315877b8a9a3d2482d4c3b0da840d713 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:57:35 +0100 Subject: [PATCH 0052/6183] regulator: lp8755: Provide map_voltage() Improve performance when setting voltages by avoiding a scan through the selectors when we can simply calculate the selector we want. Signed-off-by: Mark Brown --- drivers/regulator/lp8755.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index f0f6ea05065b..e29634148ed2 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -229,6 +229,7 @@ err_i2c: } static struct regulator_ops lp8755_buck_ops = { + .map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, From 1a39b5e1f932b0ab292c1737724f17bd6a73d630 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 14:32:16 +0200 Subject: [PATCH 0053/6183] ALSA: hda - Add GPIO control to AD1884 HP fixup The AD1884 HP laptop/mobile quirks control GPIO1 bit as the primary mute as well. Add the similar control to ad1884 fixup for auto parser, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index d97f0d61a15b..2ae7dc54ab1d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3599,14 +3599,34 @@ static void ad1884_fixup_amp_override(struct hda_codec *codec, (1 << AC_AMPCAP_MUTE_SHIFT)); } +/* toggle GPIO1 according to the mute state */ +static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct ad198x_spec *spec = codec->spec; + + if (spec->eapd_nid) + ad_vmaster_eapd_hook(private_data, enabled); + snd_hda_codec_update_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, + enabled ? 0x00 : 0x02); +} + static void ad1884_fixup_hp_eapd(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct ad198x_spec *spec = codec->spec; + static const struct hda_verb gpio_init_verbs[] = { + {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, + {}, + }; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook; + snd_hda_sequence_write_cache(codec, gpio_init_verbs); break; case HDA_FIXUP_ACT_PROBE: if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) From 6a699bec88d5755c0f1be4e967649b3cfeac0205 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 14:45:37 +0200 Subject: [PATCH 0054/6183] ALSA: hda - Add fixup for Lenovo Thinkpad with AD1984 codec Ported from the static quirk (model=thinkpad). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2ae7dc54ab1d..0262ffb96538 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3637,9 +3637,17 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec, } } +/* set magic COEFs for dmic */ +static const struct hda_verb ad1884_dmic_init_verbs[] = { + {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, + {0x01, AC_VERB_SET_PROC_COEF, 0x08}, + {} +}; + enum { AD1884_FIXUP_AMP_OVERRIDE, AD1884_FIXUP_HP_EAPD, + AD1884_FIXUP_DMIC_COEF, }; static const struct hda_fixup ad1884_fixups[] = { @@ -3653,10 +3661,15 @@ static const struct hda_fixup ad1884_fixups[] = { .chained = true, .chain_id = AD1884_FIXUP_AMP_OVERRIDE, }, + [AD1884_FIXUP_DMIC_COEF] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = ad1884_dmic_init_verbs, + }, }; static const struct snd_pci_quirk ad1884_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF), {} }; From f404627d27b27d79287dee7c6dba934790959ee3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 15:14:17 +0200 Subject: [PATCH 0055/6183] ALSA: hda - Add fixup for HP TouchSmart with AD1984A codec Ported from the static quirk. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0262ffb96538..a667256984fd 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3648,6 +3648,7 @@ enum { AD1884_FIXUP_AMP_OVERRIDE, AD1884_FIXUP_HP_EAPD, AD1884_FIXUP_DMIC_COEF, + AD1884_FIXUP_HP_TOUCHSMART, }; static const struct hda_fixup ad1884_fixups[] = { @@ -3665,9 +3666,16 @@ static const struct hda_fixup ad1884_fixups[] = { .type = HDA_FIXUP_VERBS, .v.verbs = ad1884_dmic_init_verbs, }, + [AD1884_FIXUP_HP_TOUCHSMART] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = ad1884_dmic_init_verbs, + .chained = true, + .chain_id = AD1884_FIXUP_HP_EAPD, + }, }; static const struct snd_pci_quirk ad1884_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF), {} From aa95d61b43e0fcb0b2ce68e5efa37174fd9e5cd3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 15:16:31 +0200 Subject: [PATCH 0056/6183] ALSA: hda - Remove static quirks for AD1882 Now the generic parser can work stably enough, we can get rid of the static quirks. Let's start from AD1882. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 384 +---------------------------------- 1 file changed, 1 insertion(+), 383 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index a667256984fd..876d836ef742 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -4891,299 +4891,7 @@ static int patch_ad1884a(struct hda_codec *codec) * port-G - rear clfe-out (6stack) */ -#ifdef ENABLE_AD_STATIC_QUIRKS -static const hda_nid_t ad1882_dac_nids[3] = { - 0x04, 0x03, 0x05 -}; - -static const hda_nid_t ad1882_adc_nids[2] = { - 0x08, 0x09, -}; - -static const hda_nid_t ad1882_capsrc_nids[2] = { - 0x0c, 0x0d, -}; - -#define AD1882_SPDIF_OUT 0x02 - -/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ -static const struct hda_input_mux ad1882_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x1 }, - { "Mic", 0x4 }, - { "Line", 0x2 }, - { "CD", 0x3 }, - { "Mix", 0x7 }, - }, -}; - -/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ -static const struct hda_input_mux ad1882a_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x1 }, - { "Mic", 0x4}, - { "Line", 0x2 }, - { "Digital Mic", 0x06 }, - { "Mix", 0x7 }, - }, -}; - -static const struct snd_kcontrol_new ad1882_base_mixers[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - { } /* end */ -}; - -/* simple auto-mute control for AD1882 3-stack board */ -#define AD1882_HP_EVENT 0x01 - -static void ad1882_3stack_automute(struct hda_codec *codec) -{ - bool mute = snd_hda_jack_detect(codec, 0x11); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - mute ? 0 : PIN_OUT); -} - -static int ad1882_3stack_automute_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1882_3stack_automute(codec); - return 0; -} - -static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (res >> 26) { - case AD1882_HP_EVENT: - ad1882_3stack_automute(codec); - break; - } -} - -static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { - HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb ad1882_ch2_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } /* end */ -}; - -static const struct hda_verb ad1882_ch4_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } /* end */ -}; - -static const struct hda_verb ad1882_ch6_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } /* end */ -}; - -static const struct hda_channel_mode ad1882_modes[3] = { - { 2, ad1882_ch2_init }, - { 4, ad1882_ch4_init }, - { 6, ad1882_ch6_init }, -}; - -/* - * initialization verbs - */ -static const struct hda_verb ad1882_init_verbs[] = { - /* DACs; mute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-A (HP) mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* HP selector - select DAC2 */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-D (Line-out) mixer */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ - /* Port-C (line-in) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ - /* Port-C mixer - mute as input */ - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Port-E (mic-in) pin */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ - /* Port-E mixer - mute as input */ - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Port-F (surround) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-G (CLFE) */ - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - /* SPDIF output selector */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; - -static const struct hda_verb ad1882_3stack_automute_verbs[] = { - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1882_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Mic */ - { 0x20, HDA_INPUT, 4 }, /* Line */ - { 0x20, HDA_INPUT, 6 }, /* CD */ - { } /* end */ -}; -#endif - -/* models */ -enum { - AD1882_AUTO, - AD1882_3STACK, - AD1882_6STACK, - AD1882_3STACK_AUTOMUTE, - AD1882_MODELS -}; - -static const char * const ad1882_models[AD1986A_MODELS] = { - [AD1882_AUTO] = "auto", - [AD1882_3STACK] = "3stack", - [AD1882_6STACK] = "6stack", - [AD1882_3STACK_AUTOMUTE] = "3stack-automute", -}; -#endif /* ENABLE_AD_STATIC_QUIRKS */ - -static int ad1882_parse_auto_config(struct hda_codec *codec) +static int patch_ad1882(struct hda_codec *codec) { struct ad198x_spec *spec; int err; @@ -5210,96 +4918,6 @@ static int ad1882_parse_auto_config(struct hda_codec *codec) return err; } -#ifdef ENABLE_AD_STATIC_QUIRKS -static int patch_ad1882(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err, board_config; - - board_config = snd_hda_check_board_config(codec, AD1882_MODELS, - ad1882_models, NULL); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1882_AUTO; - } - - if (board_config == AD1882_AUTO) - return ad1882_parse_auto_config(codec); - - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = 3; - spec->multiout.dac_nids = ad1882_dac_nids; - spec->multiout.dig_out_nid = AD1882_SPDIF_OUT; - spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); - spec->adc_nids = ad1882_adc_nids; - spec->capsrc_nids = ad1882_capsrc_nids; - if (codec->vendor_id == 0x11d41882) - spec->input_mux = &ad1882_capture_source; - else - spec->input_mux = &ad1882a_capture_source; - spec->num_mixers = 2; - spec->mixers[0] = ad1882_base_mixers; - if (codec->vendor_id == 0x11d41882) - spec->mixers[1] = ad1882_loopback_mixers; - else - spec->mixers[1] = ad1882a_loopback_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1882_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1882_loopbacks; -#endif - spec->vmaster_nid = 0x04; - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - switch (board_config) { - default: - case AD1882_3STACK: - case AD1882_3STACK_AUTOMUTE: - spec->num_mixers = 3; - spec->mixers[2] = ad1882_3stack_mixers; - spec->channel_mode = ad1882_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1882_modes); - spec->need_dac_fix = 1; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - if (board_config != AD1882_3STACK) { - spec->init_verbs[spec->num_init_verbs++] = - ad1882_3stack_automute_verbs; - codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; - codec->patch_ops.init = ad1882_3stack_automute_init; - } - break; - case AD1882_6STACK: - spec->num_mixers = 3; - spec->mixers[2] = ad1882_6stack_mixers; - break; - } - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1882 ad1882_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - /* * patch entries From 5ccc618fee67f0f0b2122dd4b32a02fd2b6a1569 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 15:36:56 +0200 Subject: [PATCH 0057/6183] ALSA: hda - Remove static quirks for AD1884/1984 & variants Since the necessary device-specific fixups for Thinkpad and HP devices have been already ported, we can remove all static quirks for AD1884, AD1984, AD1884A and AD1984A codecs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 1348 +--------------------------------- 1 file changed, 18 insertions(+), 1330 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 876d836ef742..bfa8f532841d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3423,168 +3423,20 @@ static int patch_ad1988(struct hda_codec *codec) * * AD1984 = AD1884 + two digital mic-ins * - * FIXME: - * For simplicity, we share the single DAC for both HP and line-outs - * right now. The inidividual playbacks could be easily implemented, - * but no build-up framework is given, so far. + * AD1883 / AD1884A / AD1984A / AD1984B + * + * port-B (0x14) - front mic-in + * port-E (0x1c) - rear mic-in + * port-F (0x16) - CD / ext out + * port-C (0x15) - rear line-in + * port-D (0x12) - rear line-out + * port-A (0x11) - front hp-out + * + * AD1984A = AD1884A + digital-mic + * AD1883 = equivalent with AD1984A + * AD1984B = AD1984A + extra SPDIF-out */ -#ifdef ENABLE_AD_STATIC_QUIRKS -static const hda_nid_t ad1884_dac_nids[1] = { - 0x04, -}; - -static const hda_nid_t ad1884_adc_nids[2] = { - 0x08, 0x09, -}; - -static const hda_nid_t ad1884_capsrc_nids[2] = { - 0x0c, 0x0d, -}; - -#define AD1884_SPDIF_OUT 0x02 - -static const struct hda_input_mux ad1884_capture_source = { - .num_items = 4, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x1 }, - { "CD", 0x2 }, - { "Mix", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new ad1884_base_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { - HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, - HDA_INPUT), - HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, - HDA_INPUT), - { } /* end */ -}; - -/* - * initialization verbs - */ -static const struct hda_verb ad1884_init_verbs[] = { - /* DACs; mute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-A (HP) mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* HP selector - select DAC2 */ - {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-D (Line-out) mixer */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono selector */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Port-C (rear mic) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - /* SPDIF output selector */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1884_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Mic */ - { 0x20, HDA_INPUT, 2 }, /* CD */ - { 0x20, HDA_INPUT, 4 }, /* Docking */ - { } /* end */ -}; -#endif - -static const char * const ad1884_slave_vols[] = { - "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", - "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958", - NULL -}; - -enum { - AD1884_AUTO, - AD1884_BASIC, - AD1884_MODELS -}; - -static const char * const ad1884_models[AD1884_MODELS] = { - [AD1884_AUTO] = "auto", - [AD1884_BASIC] = "basic", -}; -#endif /* ENABLE_AD_STATIC_QUIRKS */ - - /* set the upper-limit for mixer amp to 0dB for avoiding the possible * damage by overloading */ @@ -3682,7 +3534,7 @@ static const struct snd_pci_quirk ad1884_fixup_tbl[] = { }; -static int ad1884_parse_auto_config(struct hda_codec *codec) +static int patch_ad1884(struct hda_codec *codec) { struct ad198x_spec *spec; int err; @@ -3715,1170 +3567,6 @@ static int ad1884_parse_auto_config(struct hda_codec *codec) return err; } -#ifdef ENABLE_AD_STATIC_QUIRKS -static int patch_ad1884_basic(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err; - - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); - spec->multiout.dac_nids = ad1884_dac_nids; - spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; - spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); - spec->adc_nids = ad1884_adc_nids; - spec->capsrc_nids = ad1884_capsrc_nids; - spec->input_mux = &ad1884_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1884_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1884_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1884_loopbacks; -#endif - spec->vmaster_nid = 0x04; - /* we need to cover all playback volumes */ - spec->slave_vols = ad1884_slave_vols; - /* slaves may contain input volumes, so we can't raise to 0dB blindly */ - spec->avoid_init_slave_vol = 1; - - codec->patch_ops = ad198x_patch_ops; - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} - -static int patch_ad1884(struct hda_codec *codec) -{ - int board_config; - - board_config = snd_hda_check_board_config(codec, AD1884_MODELS, - ad1884_models, NULL); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1884_AUTO; - } - - if (board_config == AD1884_AUTO) - return ad1884_parse_auto_config(codec); - else - return patch_ad1884_basic(codec); -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1884 ad1884_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - - -#ifdef ENABLE_AD_STATIC_QUIRKS -/* - * Lenovo Thinkpad T61/X61 - */ -static const struct hda_input_mux ad1984_thinkpad_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Mix", 0x3 }, - { "Dock Mic", 0x4 }, - }, -}; - - -/* - * Dell Precision T3400 - */ -static const struct hda_input_mux ad1984_dell_desktop_capture_source = { - .num_items = 3, - .items = { - { "Front Mic", 0x0 }, - { "Line-In", 0x1 }, - { "Mix", 0x3 }, - }, -}; - - -static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -/* additional verbs */ -static const struct hda_verb ad1984_thinkpad_init_verbs[] = { - /* Port-E (docking station mic) pin */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* docking mic boost */ - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Analog PC Beeper - allow firmware/ACPI beeps */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, - /* Analog mixer - docking mic; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* enable EAPD bit */ - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - { } /* end */ -}; - -/* - * Dell Precision T3400 - */ -static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* Digial MIC ADC NID 0x05 + 0x06 */ -static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_setup_stream(codec, 0x05 + substream->number, - stream_tag, 0, format); - return 0; -} - -static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); - return 0; -} - -static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x05, - .ops = { - .prepare = ad1984_pcm_dmic_prepare, - .cleanup = ad1984_pcm_dmic_cleanup - }, -}; - -static int ad1984_build_pcms(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_pcm *info; - int err; - - err = ad198x_build_pcms(codec); - if (err < 0) - return err; - - info = spec->pcm_rec + codec->num_pcms; - codec->num_pcms++; - info->name = "AD1984 Digital Mic"; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; - return 0; -} - -/* models */ -enum { - AD1984_AUTO, - AD1984_BASIC, - AD1984_THINKPAD, - AD1984_DELL_DESKTOP, - AD1984_MODELS -}; - -static const char * const ad1984_models[AD1984_MODELS] = { - [AD1984_AUTO] = "auto", - [AD1984_BASIC] = "basic", - [AD1984_THINKPAD] = "thinkpad", - [AD1984_DELL_DESKTOP] = "dell_desktop", -}; - -static const struct snd_pci_quirk ad1984_cfg_tbl[] = { - /* Lenovo Thinkpad T61/X61 */ - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), - SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), - SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), - {} -}; - -static int patch_ad1984(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config, err; - - board_config = snd_hda_check_board_config(codec, AD1984_MODELS, - ad1984_models, ad1984_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1984_AUTO; - } - - if (board_config == AD1984_AUTO) - return ad1884_parse_auto_config(codec); - - err = patch_ad1884_basic(codec); - if (err < 0) - return err; - spec = codec->spec; - - switch (board_config) { - case AD1984_BASIC: - /* additional digital mics */ - spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; - codec->patch_ops.build_pcms = ad1984_build_pcms; - break; - case AD1984_THINKPAD: - if (codec->subsystem_id == 0x17aa20fb) { - /* Thinpad X300 does not have the ability to do SPDIF, - or attach to docking station to use SPDIF */ - spec->multiout.dig_out_nid = 0; - } else - spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; - spec->input_mux = &ad1984_thinkpad_capture_source; - spec->mixers[0] = ad1984_thinkpad_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; - spec->analog_beep = 1; - break; - case AD1984_DELL_DESKTOP: - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1984_dell_desktop_capture_source; - spec->mixers[0] = ad1984_dell_desktop_mixers; - break; - } - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1984 ad1884_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - - -/* - * AD1883 / AD1884A / AD1984A / AD1984B - * - * port-B (0x14) - front mic-in - * port-E (0x1c) - rear mic-in - * port-F (0x16) - CD / ext out - * port-C (0x15) - rear line-in - * port-D (0x12) - rear line-out - * port-A (0x11) - front hp-out - * - * AD1984A = AD1884A + digital-mic - * AD1883 = equivalent with AD1984A - * AD1984B = AD1984A + extra SPDIF-out - * - * FIXME: - * We share the single DAC for both HP and line-outs (see AD1884/1984). - */ - -#ifdef ENABLE_AD_STATIC_QUIRKS -static const hda_nid_t ad1884a_dac_nids[1] = { - 0x03, -}; - -#define ad1884a_adc_nids ad1884_adc_nids -#define ad1884a_capsrc_nids ad1884_capsrc_nids - -#define AD1884A_SPDIF_OUT 0x02 - -static const struct hda_input_mux ad1884a_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x4 }, - { "Line", 0x1 }, - { "CD", 0x2 }, - { "Mix", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new ad1884a_base_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -/* - * initialization verbs - */ -static const struct hda_verb ad1884a_init_verbs[] = { - /* DACs; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - /* Port-A (HP) mixer - route only from analog mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-D (Line-out) mixer - route only from analog mixer */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer - route only from analog mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Port-C (rear line-in) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Port-E (rear mic) pin */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ - /* Port-F (CD) pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* capture sources */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* SPDIF output amp */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1884a_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Mic */ - { 0x20, HDA_INPUT, 2 }, /* CD */ - { 0x20, HDA_INPUT, 4 }, /* Docking */ - { } /* end */ -}; -#endif - -/* - * Laptop model - * - * Port A: Headphone jack - * Port B: MIC jack - * Port C: Internal MIC - * Port D: Dock Line Out (if enabled) - * Port E: Dock Line In (if enabled) - * Port F: Internal speakers - */ - -static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - int mute = (!ucontrol->value.integer.value[0] && - !ucontrol->value.integer.value[1]); - /* toggle GPIO1 according to the mute state */ - snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - mute ? 0x02 : 0x0); - return ret; -} - -static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1884a_mobile_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1884a_mobile_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* mute internal speaker if HP is plugged */ -static void ad1884a_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x11); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, - present ? 0x00 : 0x02); -} - -/* switch to external mic if plugged */ -static void ad1884a_hp_automic(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x14); - snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0 : 1); -} - -#define AD1884A_HP_EVENT 0x37 -#define AD1884A_MIC_EVENT 0x36 - -/* unsolicited event for HP jack sensing */ -static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (res >> 26) { - case AD1884A_HP_EVENT: - ad1884a_hp_automute(codec); - break; - case AD1884A_MIC_EVENT: - ad1884a_hp_automic(codec); - break; - } -} - -/* initialize jack-sensing, too */ -static int ad1884a_hp_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1884a_hp_automute(codec); - ad1884a_hp_automic(codec); - return 0; -} - -/* mute internal speaker if HP or docking HP is plugged */ -static void ad1884a_laptop_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x11); - if (!present) - present = snd_hda_jack_detect(codec, 0x12); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, - present ? 0x00 : 0x02); -} - -/* switch to external mic if plugged */ -static void ad1884a_laptop_automic(struct hda_codec *codec) -{ - unsigned int idx; - - if (snd_hda_jack_detect(codec, 0x14)) - idx = 0; - else if (snd_hda_jack_detect(codec, 0x1c)) - idx = 4; - else - idx = 1; - snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); -} - -/* unsolicited event for HP jack sensing */ -static void ad1884a_laptop_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case AD1884A_HP_EVENT: - ad1884a_laptop_automute(codec); - break; - case AD1884A_MIC_EVENT: - ad1884a_laptop_automic(codec); - break; - } -} - -/* initialize jack-sensing, too */ -static int ad1884a_laptop_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1884a_laptop_automute(codec); - ad1884a_laptop_automic(codec); - return 0; -} - -/* additional verbs for laptop model */ -static const struct hda_verb ad1884a_laptop_verbs[] = { - /* Port-A (HP) pin - always unmuted */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-F (int speaker) mixer - route only from analog mixer */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-F (int speaker) pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* required for compaq 6530s/6531s speaker output */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-C pin - internal mic-in */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* Port-D (docking line-out) pin - default unmuted */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - /* allow to touch GPIO1 (for mute control) */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ - { } /* end */ -}; - -static const struct hda_verb ad1884a_mobile_verbs[] = { - /* DACs; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - /* Port-A (HP) mixer - route only from analog mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-A (HP) pin - always unmuted */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-B (mic jack) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* Port-C (int mic) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* Port-F (int speaker) mixer - route only from analog mixer */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-F pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* capture sources */ - /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - /* allow to touch GPIO1 (for mute control) */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ - { } /* end */ -}; - -/* - * Thinkpad X300 - * 0x11 - HP - * 0x12 - speaker - * 0x14 - mic-in - * 0x17 - built-in mic - */ - -static const struct hda_verb ad1984a_thinkpad_verbs[] = { - /* HP unmute */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* turn on EAPD */ - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - /* internal mic - dmic */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* set magic COEFs for dmic */ - {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, - {0x01, AC_VERB_SET_PROC_COEF, 0x08}, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -static const struct hda_input_mux ad1984a_thinkpad_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x5 }, - { "Mix", 0x3 }, - }, -}; - -/* mute internal speaker if HP is plugged */ -static void ad1984a_thinkpad_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x11); - snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -/* unsolicited event for HP jack sensing */ -static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != AD1884A_HP_EVENT) - return; - ad1984a_thinkpad_automute(codec); -} - -/* initialize jack-sensing, too */ -static int ad1984a_thinkpad_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1984a_thinkpad_automute(codec); - return 0; -} - -/* - * Precision R5500 - * 0x12 - HP/line-out - * 0x13 - speaker (mono) - * 0x15 - mic-in - */ - -static const struct hda_verb ad1984a_precision_verbs[] = { - /* Unmute main output path */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Select mic as input */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ - /* Configure as mic */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* HP unmute */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* turn on EAPD */ - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - /* unsolicited event for pin-sense */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -/* mute internal speaker if HP is plugged */ -static void ad1984a_precision_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x12); - snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - - -/* unsolicited event for HP jack sensing */ -static void ad1984a_precision_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != AD1884A_HP_EVENT) - return; - ad1984a_precision_automute(codec); -} - -/* initialize jack-sensing, too */ -static int ad1984a_precision_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1984a_precision_automute(codec); - return 0; -} - - -/* - * HP Touchsmart - * port-A (0x11) - front hp-out - * port-B (0x14) - unused - * port-C (0x15) - unused - * port-D (0x12) - rear line out - * port-E (0x1c) - front mic-in - * port-F (0x16) - Internal speakers - * digital-mic (0x17) - Internal mic - */ - -static const struct hda_verb ad1984a_touchsmart_verbs[] = { - /* DACs; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - /* Port-A (HP) mixer - route only from analog mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-A (HP) pin - always unmuted */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-E (int speaker) mixer - route only from analog mixer */ - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03}, - /* Port-E pin */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Port-F (int speaker) mixer - route only from analog mixer */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-F pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* capture sources */ - /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - /* allow to touch GPIO1 (for mute control) */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ - /* internal mic - dmic */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* set magic COEFs for dmic */ - {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, - {0x01, AC_VERB_SET_PROC_COEF, 0x08}, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), -/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .subdevice = HDA_SUBDEV_AMP_FLAG, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1884a_mobile_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* switch to external mic if plugged */ -static void ad1984a_touchsmart_automic(struct hda_codec *codec) -{ - if (snd_hda_jack_detect(codec, 0x1c)) - snd_hda_codec_write(codec, 0x0c, 0, - AC_VERB_SET_CONNECT_SEL, 0x4); - else - snd_hda_codec_write(codec, 0x0c, 0, - AC_VERB_SET_CONNECT_SEL, 0x5); -} - - -/* unsolicited event for HP jack sensing */ -static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case AD1884A_HP_EVENT: - ad1884a_hp_automute(codec); - break; - case AD1884A_MIC_EVENT: - ad1984a_touchsmart_automic(codec); - break; - } -} - -/* initialize jack-sensing, too */ -static int ad1984a_touchsmart_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1884a_hp_automute(codec); - ad1984a_touchsmart_automic(codec); - return 0; -} - - -/* - */ - -enum { - AD1884A_AUTO, - AD1884A_DESKTOP, - AD1884A_LAPTOP, - AD1884A_MOBILE, - AD1884A_THINKPAD, - AD1984A_TOUCHSMART, - AD1984A_PRECISION, - AD1884A_MODELS -}; - -static const char * const ad1884a_models[AD1884A_MODELS] = { - [AD1884A_AUTO] = "auto", - [AD1884A_DESKTOP] = "desktop", - [AD1884A_LAPTOP] = "laptop", - [AD1884A_MOBILE] = "mobile", - [AD1884A_THINKPAD] = "thinkpad", - [AD1984A_TOUCHSMART] = "touchsmart", - [AD1984A_PRECISION] = "precision", -}; - -static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { - SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), - SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), - SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), - SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), - SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), - SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART), - {} -}; - -static int patch_ad1884a(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err, board_config; - - board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, - ad1884a_models, - ad1884a_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1884A_AUTO; - } - - if (board_config == AD1884A_AUTO) - return ad1884_parse_auto_config(codec); - - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); - spec->multiout.dac_nids = ad1884a_dac_nids; - spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; - spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); - spec->adc_nids = ad1884a_adc_nids; - spec->capsrc_nids = ad1884a_capsrc_nids; - spec->input_mux = &ad1884a_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1884a_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1884a_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1884a_loopbacks; -#endif - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - switch (board_config) { - case AD1884A_LAPTOP: - spec->mixers[0] = ad1884a_laptop_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; - codec->patch_ops.init = ad1884a_laptop_init; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1884A_MOBILE: - spec->mixers[0] = ad1884a_mobile_mixers; - spec->init_verbs[0] = ad1884a_mobile_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; - codec->patch_ops.init = ad1884a_hp_init; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1884A_THINKPAD: - spec->mixers[0] = ad1984a_thinkpad_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1984a_thinkpad_verbs; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1984a_thinkpad_capture_source; - codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; - codec->patch_ops.init = ad1984a_thinkpad_init; - break; - case AD1984A_PRECISION: - spec->mixers[0] = ad1984a_precision_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1984a_precision_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; - codec->patch_ops.init = ad1984a_precision_init; - break; - case AD1984A_TOUCHSMART: - spec->mixers[0] = ad1984a_touchsmart_mixers; - spec->init_verbs[0] = ad1984a_touchsmart_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event; - codec->patch_ops.init = ad1984a_touchsmart_init; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1884a ad1884_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - - /* * AD1882 / AD1882A * @@ -4923,15 +3611,15 @@ static int patch_ad1882(struct hda_codec *codec) * patch entries */ static const struct hda_codec_preset snd_hda_preset_analog[] = { - { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, + { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, - { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, + { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, - { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, - { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, + { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, + { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, - { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, + { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, From bd450dcc357646cc277c560ab24b35f940efa585 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 15:48:04 +0200 Subject: [PATCH 0058/6183] ALSA: hda - Remove static quirks for AD1981 and AD1983 codecs These are relatively easy ones, as we already converted all static quirks to the generic parser. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 684 +---------------------------------- 1 file changed, 2 insertions(+), 682 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index bfa8f532841d..4fedd9dfd85a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1427,161 +1427,6 @@ static int patch_ad1986a(struct hda_codec *codec) * AD1983 specific */ -#ifdef ENABLE_AD_STATIC_QUIRKS -#define AD1983_SPDIF_OUT 0x02 -#define AD1983_DAC 0x03 -#define AD1983_ADC 0x04 - -static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; -static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; -static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; - -static const struct hda_input_mux ad1983_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x1 }, - { "Mix", 0x2 }, - { "Mix Mono", 0x3 }, - }, -}; - -/* - * SPDIF playback route - */ -static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { "PCM", "ADC" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->spdif_route; - return 0; -} - -static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - if (ucontrol->value.enumerated.item[0] > 1) - return -EINVAL; - if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { - spec->spdif_route = ucontrol->value.enumerated.item[0]; - snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, - AC_VERB_SET_CONNECT_SEL, - spec->spdif_route); - return 1; - } - return 0; -} - -static const struct snd_kcontrol_new ad1983_mixers[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct hda_verb ad1983_init_verbs[] = { - /* Front, HP, Mono; mute as default */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Beep, PCM, Mic, Line-In: mute */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Front, HP selectors; from Mix */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* Mono selector; from Mix */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic selector; Mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Line-in selector: Line-in */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic boost: 0dB */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* Record selector: mic */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* SPDIF route: PCM */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Front Pin */ - {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* HP Pin */ - {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Mono Pin */ - {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mic Pin */ - {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line Pin */ - {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1983_loopbacks[] = { - { 0x12, HDA_OUTPUT, 0 }, /* Mic */ - { 0x13, HDA_OUTPUT, 0 }, /* Line */ - { } /* end */ -}; -#endif - -/* models */ -enum { - AD1983_AUTO, - AD1983_BASIC, - AD1983_MODELS -}; - -static const char * const ad1983_models[AD1983_MODELS] = { - [AD1983_AUTO] = "auto", - [AD1983_BASIC] = "basic", -}; -#endif /* ENABLE_AD_STATIC_QUIRKS */ - - /* * SPDIF mux control for AD1983 auto-parser */ @@ -1656,7 +1501,7 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) return 0; } -static int ad1983_parse_auto_config(struct hda_codec *codec) +static int patch_ad1983(struct hda_codec *codec) { struct ad198x_spec *spec; int err; @@ -1681,432 +1526,11 @@ static int ad1983_parse_auto_config(struct hda_codec *codec) return err; } -#ifdef ENABLE_AD_STATIC_QUIRKS -static int patch_ad1983(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config; - int err; - - board_config = snd_hda_check_board_config(codec, AD1983_MODELS, - ad1983_models, NULL); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1983_AUTO; - } - - if (board_config == AD1983_AUTO) - return ad1983_parse_auto_config(codec); - - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); - spec->multiout.dac_nids = ad1983_dac_nids; - spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1983_adc_nids; - spec->capsrc_nids = ad1983_capsrc_nids; - spec->input_mux = &ad1983_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1983_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1983_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1983_loopbacks; -#endif - spec->vmaster_nid = 0x05; - - codec->patch_ops = ad198x_patch_ops; - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1983 ad1983_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - /* * AD1981 HD specific */ -#ifdef ENABLE_AD_STATIC_QUIRKS -#define AD1981_SPDIF_OUT 0x02 -#define AD1981_DAC 0x03 -#define AD1981_ADC 0x04 - -static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; -static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; -static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; - -/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ -static const struct hda_input_mux ad1981_capture_source = { - .num_items = 7, - .items = { - { "Front Mic", 0x0 }, - { "Line", 0x1 }, - { "Mix", 0x2 }, - { "Mix Mono", 0x3 }, - { "CD", 0x4 }, - { "Mic", 0x6 }, - { "Aux", 0x7 }, - }, -}; - -static const struct snd_kcontrol_new ad1981_mixers[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* identical with AD1983 */ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct hda_verb ad1981_init_verbs[] = { - /* Front, HP, Mono; mute as default */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Front, HP selectors; from Mix */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* Mono selector; from Mix */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic Mixer; select Front Mic */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Mic boost: 0dB */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Record selector: Front mic */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* SPDIF route: PCM */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Front Pin */ - {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* HP Pin */ - {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Mono Pin */ - {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Front & Rear Mic Pins */ - {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line Pin */ - {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* Digital Beep */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Line-Out as Input: disabled */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1981_loopbacks[] = { - { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ - { 0x13, HDA_OUTPUT, 0 }, /* Line */ - { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ - { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ - { 0x1d, HDA_OUTPUT, 0 }, /* CD */ - { } /* end */ -}; -#endif - -/* - * Patch for HP nx6320 - * - * nx6320 uses EAPD in the reverse way - EAPD-on means the internal - * speaker output enabled _and_ mute-LED off. - */ - -#define AD1981_HP_EVENT 0x37 -#define AD1981_MIC_EVENT 0x38 - -static const struct hda_verb ad1981_hp_init_verbs[] = { - {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ - /* pin sensing on HP and Mic jacks */ - {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, - {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, - {} -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - if (! ad198x_eapd_put(kcontrol, ucontrol)) - return 0; - /* change speaker pin appropriately */ - snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0); - /* toggle HP mute appropriately */ - snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - spec->cur_eapd ? 0 : HDA_AMP_MUTE); - return 1; -} - -/* bind volumes of both NID 0x05 and 0x06 */ -static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* mute internal speaker if HP is plugged */ -static void ad1981_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x06); - snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -/* toggle input of built-in and mic jack appropriately */ -static void ad1981_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x08); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void ad1981_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - switch (res) { - case AD1981_HP_EVENT: - ad1981_hp_automute(codec); - break; - case AD1981_MIC_EVENT: - ad1981_hp_automic(codec); - break; - } -} - -static const struct hda_input_mux ad1981_hp_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Dock Mic", 0x1 }, - { "Mix", 0x2 }, - }, -}; - -static const struct snd_kcontrol_new ad1981_hp_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, - .name = "Master Playback Switch", - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad1981_hp_master_sw_put, - .private_value = 0x05, - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), -#if 0 - /* FIXME: analog mic/line loopback doesn't work with my tests... - * (although recording is OK) - */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - /* FIXME: does this laptop have analog CD connection? */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), -#endif - HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int ad1981_hp_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1981_hp_automute(codec); - ad1981_hp_automic(codec); - return 0; -} - -/* configuration for Toshiba Laptops */ -static const struct hda_verb ad1981_toshiba_init_verbs[] = { - {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ - /* pin sensing on HP and Mic jacks */ - {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, - {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, - {} -}; - -static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { - HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), - { } -}; - -/* configuration for Lenovo Thinkpad T60 */ -static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* identical with AD1983 */ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct hda_input_mux ad1981_thinkpad_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Mix", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* models */ -enum { - AD1981_AUTO, - AD1981_BASIC, - AD1981_HP, - AD1981_THINKPAD, - AD1981_TOSHIBA, - AD1981_MODELS -}; - -static const char * const ad1981_models[AD1981_MODELS] = { - [AD1981_AUTO] = "auto", - [AD1981_HP] = "hp", - [AD1981_THINKPAD] = "thinkpad", - [AD1981_BASIC] = "basic", - [AD1981_TOSHIBA] = "toshiba" -}; - -static const struct snd_pci_quirk ad1981_cfg_tbl[] = { - SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), - SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), - /* All HP models */ - SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP), - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), - /* Lenovo Thinkpad T60/X60/Z6xx */ - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD), - /* HP nx6320 (reversed SSID, H/W bug) */ - SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), - {} -}; -#endif /* ENABLE_AD_STATIC_QUIRKS */ - - /* follow EAPD via vmaster hook */ static void ad_vmaster_eapd_hook(void *private_data, int enabled) { @@ -2172,7 +1596,7 @@ static const struct snd_pci_quirk ad1981_fixup_tbl[] = { {} }; -static int ad1981_parse_auto_config(struct hda_codec *codec) +static int patch_ad1981(struct hda_codec *codec) { struct ad198x_spec *spec; int err; @@ -2205,110 +1629,6 @@ static int ad1981_parse_auto_config(struct hda_codec *codec) return err; } -#ifdef ENABLE_AD_STATIC_QUIRKS -static int patch_ad1981(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err, board_config; - - board_config = snd_hda_check_board_config(codec, AD1981_MODELS, - ad1981_models, - ad1981_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1981_AUTO; - } - - if (board_config == AD1981_AUTO) - return ad1981_parse_auto_config(codec); - - err = alloc_ad_spec(codec); - if (err < 0) - return -ENOMEM; - spec = codec->spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); - spec->multiout.dac_nids = ad1981_dac_nids; - spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1981_adc_nids; - spec->capsrc_nids = ad1981_capsrc_nids; - spec->input_mux = &ad1981_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1981_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1981_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1981_loopbacks; -#endif - spec->vmaster_nid = 0x05; - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - switch (board_config) { - case AD1981_HP: - spec->mixers[0] = ad1981_hp_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1981_hp_init_verbs; - if (!is_jack_available(codec, 0x0a)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1981_hp_capture_source; - - codec->patch_ops.init = ad1981_hp_init; - codec->patch_ops.unsol_event = ad1981_hp_unsol_event; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1981_THINKPAD: - spec->mixers[0] = ad1981_thinkpad_mixers; - spec->input_mux = &ad1981_thinkpad_capture_source; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1981_TOSHIBA: - spec->mixers[0] = ad1981_hp_mixers; - spec->mixers[1] = ad1981_toshiba_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1981_toshiba_init_verbs; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1981_hp_capture_source; - codec->patch_ops.init = ad1981_hp_init; - codec->patch_ops.unsol_event = ad1981_hp_unsol_event; - break; - } - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1981 ad1981_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - /* * AD1988 From 36ad45309be840d652394cfb032b592b6a20a3dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 16:34:20 +0200 Subject: [PATCH 0059/6183] ALSA: hda - Remove static quirks for AD1988 codecs For removing static quirks for AD1988 variants, a new fixup defining the 6stack pinconfig has been added for the buggy BIOS. Other than that, we can cut off straightforwardly. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 845 ++--------------------------------- 1 file changed, 35 insertions(+), 810 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4fedd9dfd85a..7777a3a5f59a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1715,90 +1715,7 @@ static int patch_ad1981(struct hda_codec *codec) * E/F quad mic array */ - #ifdef ENABLE_AD_STATIC_QUIRKS -/* models */ -enum { - AD1988_AUTO, - AD1988_6STACK, - AD1988_6STACK_DIG, - AD1988_3STACK, - AD1988_3STACK_DIG, - AD1988_LAPTOP, - AD1988_LAPTOP_DIG, - AD1988_MODEL_LAST, -}; - -/* reivision id to check workarounds */ -#define AD1988A_REV2 0x100200 - -#define is_rev2(codec) \ - ((codec)->vendor_id == 0x11d41988 && \ - (codec)->revision_id == AD1988A_REV2) - -/* - * mixers - */ - -static const hda_nid_t ad1988_6stack_dac_nids[4] = { - 0x04, 0x06, 0x05, 0x0a -}; - -static const hda_nid_t ad1988_3stack_dac_nids[3] = { - 0x04, 0x05, 0x0a -}; - -/* for AD1988A revision-2, DAC2-4 are swapped */ -static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { - 0x04, 0x05, 0x0a, 0x06 -}; - -static const hda_nid_t ad1988_alt_dac_nid[1] = { - 0x03 -}; - -static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { - 0x04, 0x0a, 0x06 -}; - -static const hda_nid_t ad1988_adc_nids[3] = { - 0x08, 0x09, 0x0f -}; - -static const hda_nid_t ad1988_capsrc_nids[3] = { - 0x0c, 0x0d, 0x0e -}; - -#define AD1988_SPDIF_OUT 0x02 -#define AD1988_SPDIF_OUT_HDMI 0x0b -#define AD1988_SPDIF_IN 0x07 - -static const hda_nid_t ad1989b_slave_dig_outs[] = { - AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 -}; - -static const struct hda_input_mux ad1988_6stack_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x1 }, /* port-B */ - { "Line", 0x2 }, /* port-C */ - { "Mic", 0x4 }, /* port-E */ - { "CD", 0x5 }, - { "Mix", 0x9 }, - }, -}; - -static const struct hda_input_mux ad1988_laptop_capture_source = { - .num_items = 3, - .items = { - { "Mic/Line", 0x1 }, /* port-B */ - { "CD", 0x5 }, - { "Mix", 0x9 }, - }, -}; - -/* - */ static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1829,569 +1746,6 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, spec->multiout.num_dacs = spec->multiout.max_channels / 2; return err; } - -/* 6-stack mode */ -static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* 3-stack mode */ -static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - - { } /* end */ -}; - -/* laptop mode */ -static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x12, /* port-D */ - }, - - { } /* end */ -}; - -/* capture */ -static const struct snd_kcontrol_new ad1988_capture_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "PCM", "ADC1", "ADC2", "ADC3" - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int sel; - - sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT); - if (!(sel & 0x80)) - ucontrol->value.enumerated.item[0] = 0; - else { - sel = snd_hda_codec_read(codec, 0x0b, 0, - AC_VERB_GET_CONNECT_SEL, 0); - if (sel < 3) - sel++; - else - sel = 0; - ucontrol->value.enumerated.item[0] = sel; - } - return 0; -} - -static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int val, sel; - int change; - - val = ucontrol->value.enumerated.item[0]; - if (val > 3) - return -EINVAL; - if (!val) { - sel = snd_hda_codec_read(codec, 0x1d, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT); - change = sel & 0x80; - if (change) { - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(1)); - } - } else { - sel = snd_hda_codec_read(codec, 0x1d, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT | 0x01); - change = sel & 0x80; - if (change) { - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); - } - sel = snd_hda_codec_read(codec, 0x0b, 0, - AC_VERB_GET_CONNECT_SEL, 0) + 1; - change |= sel != val; - if (change) - snd_hda_codec_write_cache(codec, 0x0b, 0, - AC_VERB_SET_CONNECT_SEL, - val - 1); - } - return change; -} - -static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "IEC958 Playback Source", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, - .info = ad1988_spdif_playback_source_info, - .get = ad1988_spdif_playback_source_get, - .put = ad1988_spdif_playback_source_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* - * initialization verbs - */ - -/* - * for 6-stack (+dig) - */ -static const struct hda_verb ad1988_6stack_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-F surround path */ - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-G CLFE path */ - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-H side path */ - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in path */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in path */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Analog CD Input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - - { } -}; - -static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { - /* Headphone; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - { } -}; - -static const struct hda_verb ad1988_capture_init_verbs[] = { - /* mute analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - front-mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - - { } -}; - -static const struct hda_verb ad1988_spdif_init_verbs[] = { - /* SPDIF out sel */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* SPDIF out pin */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - - { } -}; - -static const struct hda_verb ad1988_spdif_in_init_verbs[] = { - /* unmute SPDIF input pin */ - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - { } -}; - -/* AD1989 has no ADC -> SPDIF route */ -static const struct hda_verb ad1989_spdif_init_verbs[] = { - /* SPDIF-1 out pin */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - /* SPDIF-2/HDMI out pin */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } -}; - -/* - * verbs for 3stack (+dig) - */ -static const struct hda_verb ad1988_3stack_ch2_init[] = { - /* set port-C to line-in */ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* set port-E to mic-in */ - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } /* end */ -}; - -static const struct hda_verb ad1988_3stack_ch6_init[] = { - /* set port-C to surround out */ - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - /* set port-E to CLFE out */ - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode ad1988_3stack_modes[2] = { - { 2, ad1988_3stack_ch2_init }, - { 6, ad1988_3stack_ch6_init }, -}; - -static const struct hda_verb ad1988_3stack_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in/surround path - 6ch mode as default */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in/CLFE path - 6ch mode as default */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */ - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* mute analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - front-mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - { } -}; - -/* - * verbs for laptop mode (+dig) - */ -static const struct hda_verb ad1988_laptop_hp_on[] = { - /* unmute port-A and mute port-D */ - { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; -static const struct hda_verb ad1988_laptop_hp_off[] = { - /* mute port-A and unmute port-D */ - { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -#define AD1988_HP_EVENT 0x01 - -static const struct hda_verb ad1988_laptop_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, - /* Port-D line-out path + EAPD */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C docking station - try to output */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* mute analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - { } -}; - -static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != AD1988_HP_EVENT) - return; - if (snd_hda_jack_detect(codec, 0x11)) - snd_hda_sequence_write(codec, ad1988_laptop_hp_on); - else - snd_hda_sequence_write(codec, ad1988_laptop_hp_off); -} - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1988_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Line */ - { 0x20, HDA_INPUT, 4 }, /* Mic */ - { 0x20, HDA_INPUT, 6 }, /* CD */ - { } /* end */ -}; -#endif #endif /* ENABLE_AD_STATIC_QUIRKS */ static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, @@ -2540,7 +1894,34 @@ static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) /* */ -static int ad1988_parse_auto_config(struct hda_codec *codec) +enum { + AD1988_FIXUP_6STACK_DIG, +}; + +static const struct hda_fixup ad1988_fixups[] = { + [AD1988_FIXUP_6STACK_DIG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x11, 0x02214130 }, /* front-hp */ + { 0x12, 0x01014010 }, /* line-out */ + { 0x14, 0x02a19122 }, /* front-mic */ + { 0x15, 0x01813021 }, /* line-in */ + { 0x16, 0x01011012 }, /* line-out */ + { 0x17, 0x01a19020 }, /* mic */ + { 0x1b, 0x0145f1f0 }, /* SPDIF */ + { 0x24, 0x01016011 }, /* line-out */ + { 0x25, 0x01012013 }, /* line-out */ + { } + } + }, +}; + +static const struct hda_model_fixup ad1988_fixup_models[] = { + { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" }, + {} +}; + +static int patch_ad1988(struct hda_codec *codec) { struct ad198x_spec *spec; int err; @@ -2554,12 +1935,19 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) spec->gen.mixer_merge_nid = 0x21; spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); + + snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + err = ad198x_parse_auto_config(codec); if (err < 0) goto error; err = ad1988_add_spdif_mux_ctl(codec); if (err < 0) goto error; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; error: @@ -2567,169 +1955,6 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) return err; } -/* - */ - -#ifdef ENABLE_AD_STATIC_QUIRKS -static const char * const ad1988_models[AD1988_MODEL_LAST] = { - [AD1988_6STACK] = "6stack", - [AD1988_6STACK_DIG] = "6stack-dig", - [AD1988_3STACK] = "3stack", - [AD1988_3STACK_DIG] = "3stack-dig", - [AD1988_LAPTOP] = "laptop", - [AD1988_LAPTOP_DIG] = "laptop-dig", - [AD1988_AUTO] = "auto", -}; - -static const struct snd_pci_quirk ad1988_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), - {} -}; - -static int patch_ad1988(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err, board_config; - - board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, - ad1988_models, ad1988_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1988_AUTO; - } - - if (board_config == AD1988_AUTO) - return ad1988_parse_auto_config(codec); - - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - - if (is_rev2(codec)) - snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = ad1988_alt_dac_nid[0]; - switch (board_config) { - case AD1988_6STACK: - case AD1988_6STACK_DIG: - spec->multiout.max_channels = 8; - spec->multiout.num_dacs = 4; - if (is_rev2(codec)) - spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; - else - spec->multiout.dac_nids = ad1988_6stack_dac_nids; - spec->input_mux = &ad1988_6stack_capture_source; - spec->num_mixers = 2; - if (is_rev2(codec)) - spec->mixers[0] = ad1988_6stack_mixers1_rev2; - else - spec->mixers[0] = ad1988_6stack_mixers1; - spec->mixers[1] = ad1988_6stack_mixers2; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_6stack_init_verbs; - if (board_config == AD1988_6STACK_DIG) { - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - spec->dig_in_nid = AD1988_SPDIF_IN; - } - break; - case AD1988_3STACK: - case AD1988_3STACK_DIG: - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = 3; - if (is_rev2(codec)) - spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; - else - spec->multiout.dac_nids = ad1988_3stack_dac_nids; - spec->input_mux = &ad1988_6stack_capture_source; - spec->channel_mode = ad1988_3stack_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); - spec->num_mixers = 2; - if (is_rev2(codec)) - spec->mixers[0] = ad1988_3stack_mixers1_rev2; - else - spec->mixers[0] = ad1988_3stack_mixers1; - spec->mixers[1] = ad1988_3stack_mixers2; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_3stack_init_verbs; - if (board_config == AD1988_3STACK_DIG) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - break; - case AD1988_LAPTOP: - case AD1988_LAPTOP_DIG: - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1988_3stack_dac_nids; - spec->input_mux = &ad1988_laptop_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1988_laptop_mixers; - codec->inv_eapd = 1; /* inverted EAPD */ - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_laptop_init_verbs; - if (board_config == AD1988_LAPTOP_DIG) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - break; - } - - spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); - spec->adc_nids = ad1988_adc_nids; - spec->capsrc_nids = ad1988_capsrc_nids; - spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; - if (spec->multiout.dig_out_nid) { - if (codec->vendor_id >= 0x11d4989a) { - spec->mixers[spec->num_mixers++] = - ad1989_spdif_out_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1989_spdif_init_verbs; - codec->slave_dig_outs = ad1989b_slave_dig_outs; - } else { - spec->mixers[spec->num_mixers++] = - ad1988_spdif_out_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1988_spdif_init_verbs; - } - } - if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { - spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1988_spdif_in_init_verbs; - } - - codec->patch_ops = ad198x_patch_ops; - switch (board_config) { - case AD1988_LAPTOP: - case AD1988_LAPTOP_DIG: - codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; - break; - } -#ifdef CONFIG_PM - spec->loopback.amplist = ad1988_loopbacks; -#endif - spec->vmaster_nid = 0x04; - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1988 ad1988_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ - /* * AD1884 / AD1984 From e0b27167c2d6464ff7ae7e35725024349e44596b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 16:50:46 +0200 Subject: [PATCH 0060/6183] ALSA: hda - Convert the static quirk for Samsung Q1 Ultra ... to a fixup entry. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 7777a3a5f59a..056810c14e71 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1063,17 +1063,6 @@ static const struct hda_verb ad1986a_automic_verbs[] = { {} }; -/* Ultra initialization */ -static const struct hda_verb ad1986a_ultra_init[] = { - /* eapd initialization */ - { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, - /* CLFE -> Mic in */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - /* pin sensing on HP jack */ static const struct hda_verb ad1986a_hp_init_verbs[] = { {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, @@ -1110,7 +1099,6 @@ enum { AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, AD1986A_LAPTOP_AUTOMUTE, - AD1986A_ULTRA, AD1986A_SAMSUNG, AD1986A_SAMSUNG_P50, AD1986A_MODELS @@ -1123,7 +1111,6 @@ static const char * const ad1986a_models[AD1986A_MODELS] = { [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", - [AD1986A_ULTRA] = "ultra", [AD1986A_SAMSUNG] = "samsung", [AD1986A_SAMSUNG_P50] = "samsung-p50", }; @@ -1149,7 +1136,6 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), - SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), @@ -1203,6 +1189,7 @@ static void ad_fixup_inv_jack_detect(struct hda_codec *codec, enum { AD1986A_FIXUP_INV_JACK_DETECT, + AD1986A_FIXUP_ULTRA, }; static const struct hda_fixup ad1986a_fixups[] = { @@ -1210,9 +1197,18 @@ static const struct hda_fixup ad1986a_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = ad_fixup_inv_jack_detect, }, + [AD1986A_FIXUP_ULTRA] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170110 }, /* speaker */ + { 0x1d, 0x90a7013e }, /* int mic */ + {} + }, + }, }; static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { + SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), {} }; @@ -1395,15 +1391,6 @@ static int patch_ad1986a(struct hda_codec *codec) */ spec->inv_jack_detect = 1; break; - case AD1986A_ULTRA: - spec->mixers[0] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_ultra_init; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - spec->multiout.dig_out_nid = 0; - break; } /* AD1986A has a hardware problem that it can't share a stream From f8c0ab1798b601493f29cb4836ccdaa3811ba390 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 17:06:04 +0200 Subject: [PATCH 0061/6183] ALSA: hda - Convert static quirks for AD1986A Samsung laptops Just need to override some pin-configurations. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 108 ++++------------------------------- 1 file changed, 12 insertions(+), 96 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 056810c14e71..1e4dc98e321a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -857,33 +857,6 @@ static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { { } /* end */ }; -/* re-connect the mic boost input according to the jack sensing */ -static void ad1986a_automic(struct hda_codec *codec) -{ - unsigned int present; - present = snd_hda_jack_detect(codec, 0x1f); - /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ - snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0 : 2); -} - -#define AD1986A_MIC_EVENT 0x36 - -static void ad1986a_automic_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != AD1986A_MIC_EVENT) - return; - ad1986a_automic(codec); -} - -static int ad1986a_automic_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1986a_automic(codec); - return 0; -} - /* laptop-automute - 2ch only */ static void ad1986a_update_hp(struct hda_codec *codec) @@ -1054,42 +1027,12 @@ static const struct hda_verb ad1986a_eapd_init_verbs[] = { {} }; -static const struct hda_verb ad1986a_automic_verbs[] = { - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ - {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT}, - {} -}; - /* pin sensing on HP jack */ static const struct hda_verb ad1986a_hp_init_verbs[] = { {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, {} }; -static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case AD1986A_HP_EVENT: - ad1986a_hp_automute(codec); - break; - case AD1986A_MIC_EVENT: - ad1986a_automic(codec); - break; - } -} - -static int ad1986a_samsung_p50_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1986a_hp_automute(codec); - ad1986a_automic(codec); - return 0; -} - /* models */ enum { @@ -1099,8 +1042,6 @@ enum { AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, AD1986A_LAPTOP_AUTOMUTE, - AD1986A_SAMSUNG, - AD1986A_SAMSUNG_P50, AD1986A_MODELS }; @@ -1111,8 +1052,6 @@ static const char * const ad1986a_models[AD1986A_MODELS] = { [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", - [AD1986A_SAMSUNG] = "samsung", - [AD1986A_SAMSUNG_P50] = "samsung-p50", }; static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { @@ -1135,8 +1074,6 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), - SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), @@ -1190,6 +1127,7 @@ static void ad_fixup_inv_jack_detect(struct hda_codec *codec, enum { AD1986A_FIXUP_INV_JACK_DETECT, AD1986A_FIXUP_ULTRA, + AD1986A_FIXUP_SAMSUNG, }; static const struct hda_fixup ad1986a_fixups[] = { @@ -1205,9 +1143,20 @@ static const struct hda_fixup ad1986a_fixups[] = { {} }, }, + [AD1986A_FIXUP_SAMSUNG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170110 }, /* speaker */ + { 0x1d, 0x90a7013e }, /* int mic */ + { 0x20, 0x411111f0 }, /* N/A */ + { 0x24, 0x411111f0 }, /* N/A */ + {} + }, + }, }; static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { + SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), {} @@ -1337,39 +1286,6 @@ static int patch_ad1986a(struct hda_codec *codec) spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1986a_laptop_eapd_capture_source; break; - case AD1986A_SAMSUNG: - spec->num_mixers = 2; - spec->mixers[0] = ad1986a_laptop_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 3; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->init_verbs[2] = ad1986a_automic_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_automic_capture_source; - codec->patch_ops.unsol_event = ad1986a_automic_unsol_event; - codec->patch_ops.init = ad1986a_automic_init; - break; - case AD1986A_SAMSUNG_P50: - spec->num_mixers = 2; - spec->mixers[0] = ad1986a_automute_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 4; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->init_verbs[2] = ad1986a_automic_verbs; - spec->init_verbs[3] = ad1986a_hp_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_automic_capture_source; - codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event; - codec->patch_ops.init = ad1986a_samsung_p50_init; - break; case AD1986A_LAPTOP_AUTOMUTE: spec->num_mixers = 3; spec->mixers[0] = ad1986a_automute_master_mixers; From 7fc116ec27cf51831d2d4e555c89d899be410340 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 17:18:48 +0200 Subject: [PATCH 0062/6183] ALSA: hda - Drop static quirks for other AD1986A Samsung machines BIOS on Samsung R55, M55 and M50 provide the proper pin-configs, so we can remove the corresponding static quirk entries gracefully. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1e4dc98e321a..3f2434ad7ce7 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1072,13 +1072,10 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), - SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), {} }; From fc39a7ea9235104b06ee43385d4265f2d078e62b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 17:25:03 +0200 Subject: [PATCH 0063/6183] ALSA: hda - Drop static quirk for Toshiba Satellite L40-10Q The BIOS provides good pin-configurations, so we can drop the static quirk now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3f2434ad7ce7..a41e121fe056 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1071,7 +1071,6 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), - SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), From 0f7dbda0ec3bc4d778d7acf741b220fbf4318a20 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Jul 2013 18:03:56 +0200 Subject: [PATCH 0064/6183] ALSA: hda - Drop a few other static quirks for AD1986A Most of ASUS laptops and Lenovo N100 provide proper BIOS pin-configs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index a41e121fe056..3b23280ff3a6 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1056,15 +1056,6 @@ static const char * const ad1986a_models[AD1986A_MODELS] = { static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), @@ -1074,7 +1065,6 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), {} }; From 632408adfe70be6706cb89522b0d5b3dce188d84 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Jul 2013 14:14:14 +0200 Subject: [PATCH 0065/6183] ALSA: hda - Remove static quirks for AD1986A codec Finally all the static quirks in patch_analog.c are reduced by this patch. As machines with AD1986A codec are all old and often their BIOS are buggy, we need to keep at least a few static pin conifgs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 1069 ++-------------------------------- 1 file changed, 57 insertions(+), 1012 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3b23280ff3a6..0cbdd87dde6d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -32,7 +32,6 @@ #include "hda_jack.h" #include "hda_generic.h" -#define ENABLE_AD_STATIC_QUIRKS struct ad198x_spec { struct hda_gen_spec gen; @@ -43,114 +42,8 @@ struct ad198x_spec { hda_nid_t eapd_nid; unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - -#ifdef ENABLE_AD_STATIC_QUIRKS - const struct snd_kcontrol_new *mixers[6]; - int num_mixers; - const struct hda_verb *init_verbs[6]; /* initialization verbs - * don't forget NULL termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int need_dac_fix; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - /* capture source */ - const struct hda_input_mux *input_mux; - const hda_nid_t *capsrc_nids; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - - unsigned int spdif_route; - - unsigned int jack_present: 1; - unsigned int inv_jack_detect: 1;/* inverted jack-detection */ - unsigned int analog_beep: 1; /* analog beep input present */ - unsigned int avoid_init_slave_vol:1; - -#ifdef CONFIG_PM - struct hda_loopback_check loopback; -#endif - /* for virtual master */ - hda_nid_t vmaster_nid; - const char * const *slave_vols; - const char * const *slave_sws; -#endif /* ENABLE_AD_STATIC_QUIRKS */ }; -#ifdef ENABLE_AD_STATIC_QUIRKS -/* - * input MUX handling (common part) - */ -static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -/* - * initialization (common callbacks) - */ -static int ad198x_init(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} - -static const char * const ad_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Mono", "Speaker", "IEC958", - NULL -}; - -static const char * const ad1988_6stack_fp_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", "IEC958", - NULL -}; -#endif /* ENABLE_AD_STATIC_QUIRKS */ #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ @@ -160,12 +53,6 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = { { } /* end */ }; -static const struct snd_kcontrol_new ad_beep2_mixer[] = { - HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), - HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), - { } /* end */ -}; - #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ #else @@ -181,8 +68,7 @@ static int create_beep_ctls(struct hda_codec *codec) if (!spec->beep_amp) return 0; - knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; - for ( ; knew->name; knew++) { + for (knew = ad_beep_mixer ; knew->name; knew++) { int err; struct snd_kcontrol *kctl; kctl = snd_ctl_new1(knew, codec); @@ -199,268 +85,6 @@ static int create_beep_ctls(struct hda_codec *codec) #define create_beep_ctls(codec) 0 #endif -#ifdef ENABLE_AD_STATIC_QUIRKS -static int ad198x_build_controls(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct snd_kcontrol *kctl; - unsigned int i; - int err; - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* create beep controls if needed */ - err = create_beep_ctls(codec); - if (err < 0) - return err; - - /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = __snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, - (spec->slave_vols ? - spec->slave_vols : ad_slave_pfxs), - "Playback Volume", - !spec->avoid_init_slave_vol, NULL); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, - (spec->slave_sws ? - spec->slave_sws : ad_slave_pfxs), - "Playback Switch"); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); - if (err < 0) - return err; - } - - /* assign IEC958 enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, - SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); - if (kctl) { - err = snd_hda_add_nid(codec, kctl, 0, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - - return 0; -} - -#ifdef CONFIG_PM -static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); -} -#endif - -/* - * Analog playback callbacks - */ -static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - -/* - * Analog capture - */ -static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - -/* - */ -static const struct hda_pcm_stream ad198x_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 6, /* changed later */ - .nid = 0, /* fill later */ - .ops = { - .open = ad198x_playback_pcm_open, - .prepare = ad198x_playback_pcm_prepare, - .cleanup = ad198x_playback_pcm_cleanup, - }, -}; - -static const struct hda_pcm_stream ad198x_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = ad198x_capture_pcm_prepare, - .cleanup = ad198x_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ad198x_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = ad198x_dig_playback_pcm_open, - .close = ad198x_dig_playback_pcm_close, - .prepare = ad198x_dig_playback_pcm_prepare, - .cleanup = ad198x_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ad198x_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int ad198x_build_pcms(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "AD198x Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - if (spec->multiout.dig_out_nid) { - info++; - codec->num_pcms++; - codec->spdif_status_reset = 1; - info->name = "AD198x Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} -#endif /* ENABLE_AD_STATIC_QUIRKS */ static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, hda_nid_t hp) @@ -507,18 +131,6 @@ static void ad198x_shutup(struct hda_codec *codec) ad198x_power_eapd(codec); } -static void ad198x_free(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - - if (!spec) - return; - - snd_hda_gen_spec_free(&spec->gen); - kfree(spec); - snd_hda_detach_beep_device(codec); -} - #ifdef CONFIG_PM static int ad198x_suspend(struct hda_codec *codec) { @@ -527,65 +139,6 @@ static int ad198x_suspend(struct hda_codec *codec) } #endif -#ifdef ENABLE_AD_STATIC_QUIRKS -static const struct hda_codec_ops ad198x_patch_ops = { - .build_controls = ad198x_build_controls, - .build_pcms = ad198x_build_pcms, - .init = ad198x_init, - .free = ad198x_free, -#ifdef CONFIG_PM - .check_power_status = ad198x_check_power_status, - .suspend = ad198x_suspend, -#endif - .reboot_notify = ad198x_shutup, -}; - - -/* - * EAPD control - * the private value = nid - */ -#define ad198x_eapd_info snd_ctl_boolean_mono_info - -static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - if (codec->inv_eapd) - ucontrol->value.integer.value[0] = ! spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; -} - -static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - eapd = !!ucontrol->value.integer.value[0]; - if (codec->inv_eapd) - eapd = !eapd; - if (eapd == spec->cur_eapd) - return 0; - spec->cur_eapd = eapd; - snd_hda_codec_write_cache(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; -} - -static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -#endif /* ENABLE_AD_STATIC_QUIRKS */ - /* * Automatic parse of I/O pins from the BIOS configuration @@ -646,446 +199,6 @@ static int ad198x_parse_auto_config(struct hda_codec *codec) * AD1986A specific */ -#ifdef ENABLE_AD_STATIC_QUIRKS -#define AD1986A_SPDIF_OUT 0x02 -#define AD1986A_FRONT_DAC 0x03 -#define AD1986A_SURR_DAC 0x04 -#define AD1986A_CLFE_DAC 0x05 -#define AD1986A_ADC 0x06 - -static const hda_nid_t ad1986a_dac_nids[3] = { - AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC -}; -static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; -static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; - -static const struct hda_input_mux ad1986a_capture_source = { - .num_items = 7, - .items = { - { "Mic", 0x0 }, - { "CD", 0x1 }, - { "Aux", 0x3 }, - { "Line", 0x4 }, - { "Mix", 0x5 }, - { "Mono", 0x6 }, - { "Phone", 0x7 }, - }, -}; - - -static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* - * mixers - */ -static const struct snd_kcontrol_new ad1986a_mixers[] = { - /* - * bind volumes/mutes of 3 DACs as a single PCM control for simplicity - */ - HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), - HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), - HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* additional mixers for 3stack mode */ -static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - { } /* end */ -}; - -/* laptop model - 2ch only */ -static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; - -/* master controls both pins 0x1a and 0x1b */ -static const struct hda_bind_ctls ad1986a_laptop_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0, - }, -}; - -static const struct hda_bind_ctls ad1986a_laptop_master_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0, - }, -}; - -static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), - /* - HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* laptop-eapd model - 2ch only */ - -static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x4 }, - { "Mix", 0x5 }, - }, -}; - -static const struct hda_input_mux ad1986a_automic_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Mix", 0x5 }, - }, -}; - -static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x1b, /* port-D */ - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), - { } /* end */ -}; - -/* laptop-automute - 2ch only */ - -static void ad1986a_update_hp(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - unsigned int mute; - - if (spec->jack_present) - mute = HDA_AMP_MUTE; /* mute internal speaker */ - else - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); -} - -static void ad1986a_hp_automute(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - - spec->jack_present = snd_hda_jack_detect(codec, 0x1a); - if (spec->inv_jack_detect) - spec->jack_present = !spec->jack_present; - ad1986a_update_hp(codec); -} - -#define AD1986A_HP_EVENT 0x37 - -static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != AD1986A_HP_EVENT) - return; - ad1986a_hp_automute(codec); -} - -static int ad1986a_hp_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1986a_hp_automute(codec); - return 0; -} - -/* bind hp and internal speaker mute (with plug check) */ -static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - if (change) - ad1986a_update_hp(codec); - return change; -} - -static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1986a_hp_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, - { } /* end */ -}; - - -/* - * initialization verbs - */ -static const struct hda_verb ad1986a_init_verbs[] = { - /* Front, Surround, CLFE DAC; mute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Downmix - off */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* HP, Line-Out, Surround, CLFE selectors */ - {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mono selector */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic selector: Mic 1/2 pin */ - {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Line-in selector: Line-in */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic 1/2 swap */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Record selector: mic */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* PC beep */ - {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* HP Pin */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Front, Surround, CLFE Pins */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mono Pin */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mic Pin */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line, Aux, CD, Beep-In Pin */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - { } /* end */ -}; - -static const struct hda_verb ad1986a_ch2_init[] = { - /* Surround out -> Line In */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* Line-in selectors */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, - /* CLFE -> Mic in */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, - { } /* end */ -}; - -static const struct hda_verb ad1986a_ch4_init[] = { - /* Surround out -> Surround */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* CLFE -> Mic in */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, - { } /* end */ -}; - -static const struct hda_verb ad1986a_ch6_init[] = { - /* Surround out -> Surround out */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* CLFE -> CLFE */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { } /* end */ -}; - -static const struct hda_channel_mode ad1986a_modes[3] = { - { 2, ad1986a_ch2_init }, - { 4, ad1986a_ch4_init }, - { 6, ad1986a_ch6_init }, -}; - -/* eapd initialization */ -static const struct hda_verb ad1986a_eapd_init_verbs[] = { - {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, - {} -}; - -/* pin sensing on HP jack */ -static const struct hda_verb ad1986a_hp_init_verbs[] = { - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, - {} -}; - - -/* models */ -enum { - AD1986A_AUTO, - AD1986A_6STACK, - AD1986A_3STACK, - AD1986A_LAPTOP, - AD1986A_LAPTOP_EAPD, - AD1986A_LAPTOP_AUTOMUTE, - AD1986A_MODELS -}; - -static const char * const ad1986a_models[AD1986A_MODELS] = { - [AD1986A_AUTO] = "auto", - [AD1986A_6STACK] = "6stack", - [AD1986A_3STACK] = "3stack", - [AD1986A_LAPTOP] = "laptop", - [AD1986A_LAPTOP_EAPD] = "laptop-eapd", - [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", -}; - -static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), - SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - {} -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1986a_loopbacks[] = { - { 0x13, HDA_OUTPUT, 0 }, /* Mic */ - { 0x14, HDA_OUTPUT, 0 }, /* Phone */ - { 0x15, HDA_OUTPUT, 0 }, /* CD */ - { 0x16, HDA_OUTPUT, 0 }, /* Aux */ - { 0x17, HDA_OUTPUT, 0 }, /* Line */ - { } /* end */ -}; -#endif - -static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); - return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; -} -#endif /* ENABLE_AD_STATIC_QUIRKS */ - static int alloc_ad_spec(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -1114,6 +227,9 @@ enum { AD1986A_FIXUP_INV_JACK_DETECT, AD1986A_FIXUP_ULTRA, AD1986A_FIXUP_SAMSUNG, + AD1986A_FIXUP_3STACK, + AD1986A_FIXUP_LAPTOP, + AD1986A_FIXUP_LAPTOP_IMIC, }; static const struct hda_fixup ad1986a_fixups[] = { @@ -1139,18 +255,68 @@ static const struct hda_fixup ad1986a_fixups[] = { {} }, }, + [AD1986A_FIXUP_3STACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x02214021 }, /* headphone */ + { 0x1b, 0x01014011 }, /* front */ + { 0x1c, 0x01013012 }, /* surround */ + { 0x1d, 0x01019015 }, /* clfe */ + { 0x1e, 0x411111f0 }, /* N/A */ + { 0x1f, 0x02a190f0 }, /* mic */ + { 0x20, 0x018130f0 }, /* line-in */ + {} + }, + }, + [AD1986A_FIXUP_LAPTOP] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x02214021 }, /* headphone */ + { 0x1b, 0x90170110 }, /* speaker */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x411111f0 }, /* N/A */ + { 0x1f, 0x02a191f0 }, /* mic */ + { 0x20, 0x411111f0 }, /* N/A */ + {} + }, + }, + [AD1986A_FIXUP_LAPTOP_IMIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1d, 0x90a7013e }, /* int mic */ + {} + }, + .chained_before = 1, + .chain_id = AD1986A_FIXUP_LAPTOP, + }, }; static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), + SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), + SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK), + {} +}; + +static const struct hda_model_fixup ad1986a_fixup_models[] = { + { .id = AD1986A_FIXUP_3STACK, .name = "3stack" }, + { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" }, + { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" }, + { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */ {} }; /* */ -static int ad1986a_parse_auto_config(struct hda_codec *codec) +static int patch_ad1986a(struct hda_codec *codec) { int err; struct ad198x_spec *spec; @@ -1175,7 +341,8 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) */ spec->gen.multiout.no_share_stream = 1; - snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups); + snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl, + ad1986a_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); err = ad198x_parse_auto_config(codec); @@ -1189,128 +356,6 @@ static int ad1986a_parse_auto_config(struct hda_codec *codec) return 0; } -#ifdef ENABLE_AD_STATIC_QUIRKS -static int patch_ad1986a(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err, board_config; - - board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, - ad1986a_models, - ad1986a_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1986A_AUTO; - } - - if (board_config == AD1986A_AUTO) - return ad1986a_parse_auto_config(codec); - - err = alloc_ad_spec(codec); - if (err < 0) - return err; - spec = codec->spec; - - err = snd_hda_attach_beep_device(codec, 0x19); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); - spec->multiout.dac_nids = ad1986a_dac_nids; - spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1986a_adc_nids; - spec->capsrc_nids = ad1986a_capsrc_nids; - spec->input_mux = &ad1986a_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1986a_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1986a_init_verbs; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1986a_loopbacks; -#endif - spec->vmaster_nid = 0x1b; - codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - switch (board_config) { - case AD1986A_3STACK: - spec->num_mixers = 2; - spec->mixers[1] = ad1986a_3st_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_ch2_init; - spec->channel_mode = ad1986a_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); - spec->need_dac_fix = 1; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - break; - case AD1986A_LAPTOP: - spec->mixers[0] = ad1986a_laptop_mixers; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - break; - case AD1986A_LAPTOP_EAPD: - spec->num_mixers = 3; - spec->mixers[0] = ad1986a_laptop_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->mixers[2] = ad1986a_laptop_intmic_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_laptop_eapd_capture_source; - break; - case AD1986A_LAPTOP_AUTOMUTE: - spec->num_mixers = 3; - spec->mixers[0] = ad1986a_automute_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->mixers[2] = ad1986a_laptop_intmic_mixers; - spec->num_init_verbs = 3; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->init_verbs[2] = ad1986a_hp_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_laptop_eapd_capture_source; - codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; - codec->patch_ops.init = ad1986a_hp_init; - /* Lenovo N100 seems to report the reversed bit - * for HP jack-sensing - */ - spec->inv_jack_detect = 1; - break; - } - - /* AD1986A has a hardware problem that it can't share a stream - * with multiple output pins. The copy of front to surrounds - * causes noisy or silent outputs at a certain timing, e.g. - * changing the volume. - * So, let's disable the shared stream. - */ - spec->multiout.no_share_stream = 1; - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} -#else /* ENABLE_AD_STATIC_QUIRKS */ -#define patch_ad1986a ad1986a_parse_auto_config -#endif /* ENABLE_AD_STATIC_QUIRKS */ /* * AD1983 specific From 384f778fd924cc843acf93c23f52cb168cb3f02a Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:53 +0200 Subject: [PATCH 0066/6183] ALSA: hdspm - Add missing defines for RME AIO and RayDAT The driver did not support all possible configurations. These defines will be used by later commits to add the missing functionality. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bd501931ee23..a0fc961bc347 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -258,6 +258,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wclk_sel (1<<30) +/* additional control register bits for AIO*/ +#define HDSPM_c0_Wck48 0x20 /* also RayDAT */ +#define HDSPM_c0_Input0 0x1000 +#define HDSPM_c0_Input1 0x2000 +#define HDSPM_c0_Spdif_Opt 0x4000 +#define HDSPM_c0_Pro 0x8000 +#define HDSPM_c0_clr_tms 0x10000 +#define HDSPM_c0_AEB1 0x20000 +#define HDSPM_c0_AEB2 0x40000 +#define HDSPM_c0_LineOut 0x80000 +#define HDSPM_c0_AD_GAIN0 0x100000 +#define HDSPM_c0_AD_GAIN1 0x200000 +#define HDSPM_c0_DA_GAIN0 0x400000 +#define HDSPM_c0_DA_GAIN1 0x800000 +#define HDSPM_c0_PH_GAIN0 0x1000000 +#define HDSPM_c0_PH_GAIN1 0x2000000 +#define HDSPM_c0_Sym6db 0x4000000 + + /* --- bit helper defines */ #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ From b2ed6326874b1bf5410871d83df4086a395ab13b Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:54 +0200 Subject: [PATCH 0067/6183] ALSA: hdspm - Introduce hdspm_is_raydat_or_aio() RME RayDAT and AIO cards are new designs with different register settings. Since we need to distinguish them from older cards multiple times in the driver, refactor the code into a separate helper function. No functional change intended. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a0fc961bc347..32a87dcecfa3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1011,6 +1011,12 @@ static inline int HDSPM_bit2freq(int n) return bit2freq_tab[n]; } +static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) +{ + return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); +} + + /* Write/read to/from HDSPM with Adresses in Bytes not words but only 32Bit writes are allowed */ @@ -5142,9 +5148,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) all_in_all_mixer(hdspm, 0 * UNITY_GAIN); - if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) { + if (hdspm_is_raydat_or_aio(hdspm)) hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); - } /* set a default rate so that the channel map is set up. */ hdspm_set_rate(hdspm, 48000, 1); From ce13f3f33a32895da9304a9f9cb865f337dd0933 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:55 +0200 Subject: [PATCH 0068/6183] ALSA: hdspm - Augment HDSPM_TOGGLE_SETTING for AIO/RayDAT The HDSPM_TOGGLE_SETTING functions alter the control_register on older cards. On newer cards (AIO/RayDAT), they have to operate on the settings_register instead. This patch augments the existing functions to work with AIO/RayDAT, too. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 32a87dcecfa3..118d727150e7 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3092,16 +3092,35 @@ static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) { - return (hdspm->control_register & regmask) ? 1 : 0; + u32 reg; + + if (hdspm_is_raydat_or_aio(hdspm)) + reg = hdspm->settings_register; + else + reg = hdspm->control_register; + + return (reg & regmask) ? 1 : 0; } static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) { + u32 *reg; + u32 target_reg; + + if (hdspm_is_raydat_or_aio(hdspm)) { + reg = &(hdspm->settings_register); + target_reg = HDSPM_WR_SETTINGS; + } else { + reg = &(hdspm->control_register); + target_reg = HDSPM_controlRegister; + } + if (out) - hdspm->control_register |= regmask; + *reg |= regmask; else - hdspm->control_register &= ~regmask; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + *reg &= ~regmask; + + hdspm_write(hdspm, target_reg, *reg); return 0; } From 34be7ebbb4488818a2c413290b7b5835173fe44d Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:56 +0200 Subject: [PATCH 0069/6183] ALSA: hdspm - Drop duplicate code in hdspm_set_system_clock_mode() hdspm_set_system_clock_mode() is almost a one-by-one copy of hdspm_set_toggle_setting(). To improve code quality, remove the duplication. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 118d727150e7..631c54601013 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -995,6 +995,7 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); static inline int hdspm_get_pll_freq(struct hdspm *hdspm); static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); static int hdspm_autosync_ref(struct hdspm *hdspm); +static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); static int snd_hdspm_set_defaults(struct hdspm *hdspm); static int hdspm_system_clock_mode(struct hdspm *hdspm); static void hdspm_set_sgbuf(struct hdspm *hdspm, @@ -2384,26 +2385,10 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm) **/ static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) { - switch (hdspm->io_type) { - case AIO: - case RayDAT: - if (0 == mode) - hdspm->settings_register |= HDSPM_c0Master; - else - hdspm->settings_register &= ~HDSPM_c0Master; - - hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); - break; - - default: - if (0 == mode) - hdspm->control_register |= HDSPM_ClockModeMaster; - else - hdspm->control_register &= ~HDSPM_ClockModeMaster; - - hdspm_write(hdspm, HDSPM_controlRegister, - hdspm->control_register); - } + hdspm_set_toggle_setting(hdspm, + (hdspm_is_raydat_or_aio(hdspm)) ? + HDSPM_c0Master : HDSPM_ClockModeMaster, + (0 == mode)); } From 11a5cd3c950ee27b165b5c170e588dff22cadeca Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:57 +0200 Subject: [PATCH 0070/6183] ALSA: hdspm - Add S/PDIF and WCK48 controls for RME RayDAT This commit adds new ALSA controls to send single-speed WordClock and S/PDIF-Professional on RME RayDAT cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 631c54601013..4a3a82249153 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -4364,7 +4364,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), - HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8) + HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), + HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) }; static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { From fb0f121e0f346bec45810a9439e936ae62fd2441 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:58 +0200 Subject: [PATCH 0071/6183] ALSA: hdspm - Add S/PDIF, XLR, WCK48 and ADAT-in controls for RME AIO cards This commit adds the following ALSA controls: - S/PDIF Out Optical to switch S/PDIF Out from coaxial to optical - S/PDIF Out Professional to send the Pro bit in the output stream - ADAT-Internal to enable ADAT/TDIF Expansion Board (AEB/TEB) - XLR Breakout Cable if analogue I/O uses the XLR breakout cable - WCK48 to force WordClock to the 32-48kHz range (single speed) if the card is operating at higher frequencies Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 4a3a82249153..15f1e7b37c9f 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -4327,7 +4327,12 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), - HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5) + HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), + HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), + HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), + HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), + HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) /* HDSPM_INPUT_SELECT("Input Select", 0), From 8cea57104273909ab0825df48149840aad9d2b14 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:27:59 +0200 Subject: [PATCH 0072/6183] ALSA: hdspm - Refactor ENUMERATED_CTL_INFO into function ENUMERATED_CTL_INFO is a macro, so the binary code is generated multiple times. To avoid code duplication, refactor the involved functionality into a function and make ENUMERATED_CTL_INFO a call to this function. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 15f1e7b37c9f..b271853e2e52 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2221,16 +2221,22 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) return (status >> (idx*4)) & 0xF; } -#define ENUMERATED_CTL_INFO(info, texts) \ -{ \ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \ - uinfo->count = 1; \ - uinfo->value.enumerated.items = ARRAY_SIZE(texts); \ - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \ - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; \ - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \ +static void snd_hdspm_set_infotext(struct snd_ctl_elem_info *uinfo, + char **texts, const int count) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = count; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); } +#define ENUMERATED_CTL_INFO(info, texts) \ + snd_hdspm_set_infotext(info, texts, ARRAY_SIZE(texts)) + #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ From acf14767e17ab7ee8b6213f9e56d07d9ffa033da Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:00 +0200 Subject: [PATCH 0073/6183] ALSA: hdspm - Introduce generic AIO tristate control AIO cards offer at least four individual settings options with three states each. Those settings are represented as two bits in the settings register with the following meaning: 0*some_base_bit --> Option value 0 1*some_base_bit --> Option value 1 2*some_base_bit --> Option value 2 3*some_base_bit --> mask to select the two involved bits This patch adds a generic ALSA control macro for such a value-to-bit pattern mapping. It will be used in a later commit to expose four new controls. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b271853e2e52..d9532c42e2ce 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3348,6 +3348,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, return change; } +#define HDSPM_CONTROL_TRISTATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .info = snd_hdspm_info_tristate, \ + .get = snd_hdspm_get_tristate, \ + .put = snd_hdspm_put_tristate \ +} + +static int hdspm_tristate(struct hdspm *hdspm, u32 regmask) +{ + u32 reg = hdspm->settings_register & (regmask * 3); + return reg / regmask; +} + +static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) +{ + hdspm->settings_register &= ~(regmask * 3); + hdspm->settings_register |= (regmask * mode); + hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); + + return 0; +} + +static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + u32 regmask = kcontrol->private_value; + + static char *texts_spdif[] = { "Optical", "Coaxial", "Internal" }; + static char *texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; + + switch (regmask) { + case HDSPM_c0_Input0: + ENUMERATED_CTL_INFO(uinfo, texts_spdif); + break; + default: + ENUMERATED_CTL_INFO(uinfo, texts_levels); + break; + } + return 0; +} + +static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; + int change; + int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0]; + if (val < 0) + val = 0; + if (val > 2) + val = 2; + + spin_lock_irq(&hdspm->lock); + change = val != hdspm_tristate(hdspm, regmask); + hdspm_set_tristate(hdspm, val, regmask); + spin_unlock_irq(&hdspm->lock); + return change; +} + #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ From 42f4c12dcf46cbca8b7bb17610c0cb7ffbd7ab2e Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:01 +0200 Subject: [PATCH 0074/6183] ALSA: hdspm - Enable AD/DA/PH gains and S/PDIF-Input select on AIO This patch uses the newly introduced HDSPM_CONTROL_TRISTATE functions to create and expose the following ALSA controls: - Gain selection for Input, Output and Phones (HiGain, +4dBu, -10dbV) - S/PDIF Input select (Coaxial, Optical, Internal) Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index d9532c42e2ce..778fc23105fa 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -4412,11 +4412,15 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), + HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), - HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), + HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), + HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), + HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) /* HDSPM_INPUT_SELECT("Input Select", 0), From 3de9db264cef4bc984f928e08cccf36304f30d0a Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:02 +0200 Subject: [PATCH 0075/6183] ALSA: hdspm - Add support for AEBs on RME AIO AIO cards allow to use AEB (Analogue Expansion Boards) to add four input and/or output channels. This patch adds the necessary code to detect and enable the additional I/O channels. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 54 +++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 778fc23105fa..ad416365dc68 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -648,7 +648,8 @@ static char *texts_ports_aio_in_ss[] = { "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", - "ADAT.7", "ADAT.8" + "ADAT.7", "ADAT.8", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_ss[] = { @@ -657,14 +658,16 @@ static char *texts_ports_aio_out_ss[] = { "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", "ADAT.7", "ADAT.8", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_in_ds[] = { "Analogue.L", "Analogue.R", "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", - "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" + "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_ds[] = { @@ -672,14 +675,16 @@ static char *texts_ports_aio_out_ds[] = { "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_in_qs[] = { "Analogue.L", "Analogue.R", "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", - "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" + "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_qs[] = { @@ -687,7 +692,8 @@ static char *texts_ports_aio_out_qs[] = { "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aes32[] = { @@ -764,8 +770,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { 8, 9, /* aes in, */ 10, 11, /* spdif in */ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ - -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -779,7 +785,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { 10, 11, /* spdif out */ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 6, 7, /* phone out */ - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -792,7 +799,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { 8, 9, /* aes in */ 10, 11, /* spdif in */ 12, 14, 16, 18, /* adat in */ - -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -807,7 +815,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { 10, 11, /* spdif out */ 12, 14, 16, 18, /* adat out */ 6, 7, /* phone out */ - -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -821,7 +829,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { 8, 9, /* aes in */ 10, 11, /* spdif in */ 12, 16, /* adat in */ - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -836,7 +845,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { 10, 11, /* spdif out */ 12, 16, /* adat out */ 6, 7, /* phone out */ - -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -6602,10 +6612,6 @@ static int snd_hdspm_create(struct snd_card *card, break; case AIO: - if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { - snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n"); - } - hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; @@ -6613,6 +6619,20 @@ static int snd_hdspm_create(struct snd_card *card, hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; + if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { + snd_printk(KERN_INFO "HDSPM: AEB input board found\n"); + hdspm->ss_in_channels += 4; + hdspm->ds_in_channels += 4; + hdspm->qs_in_channels += 4; + } + + if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { + snd_printk(KERN_INFO "HDSPM: AEB output board found\n"); + hdspm->ss_out_channels += 4; + hdspm->ds_out_channels += 4; + hdspm->qs_out_channels += 4; + } + hdspm->channel_map_out_ss = channel_map_aio_out_ss; hdspm->channel_map_out_ds = channel_map_aio_out_ds; hdspm->channel_map_out_qs = channel_map_aio_out_qs; From 1cb7dbf489f9985b7a117e34d00f20799adb138a Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:03 +0200 Subject: [PATCH 0076/6183] ALSA: hdspm - Fix S/PDIF Sync status and frequency on RME AIO This is a left-over mistake from old code, the correct register offset is provided in kcontrol->private_value, not in the index. Cf. RayDAT case, where it has already been corrected. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index ad416365dc68..06e69de0801e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2312,7 +2312,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, default: ucontrol->value.enumerated.item[0] = hdspm_get_s1_sample_rate(hdspm, - ucontrol->id.index-1); + kcontrol->private_value-1); } break; @@ -3930,7 +3930,8 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, case 5: /* SYNC IN */ val = hdspm_sync_in_sync_check(hdspm); break; default: - val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); + val = hdspm_s1_sync_check(hdspm, + kcontrol->private_value-1); } break; From 5760107c8263cf518968ece65453b7d9b8ca3d0a Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:04 +0200 Subject: [PATCH 0077/6183] ALSA: hdspm - Create TCO readout function This patch separates the TCO bits from snd_hdspm_proc_read_madi(), so the new function can later be shared between MADI and AES32 cards. It's essentially only moving code around, no new functionality. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 137 +++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 06e69de0801e..58b21048c2e8 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -4636,77 +4636,22 @@ static int snd_hdspm_create_controls(struct snd_card *card, ------------------------------------------------------------*/ static void -snd_hdspm_proc_read_madi(struct snd_info_entry * entry, - struct snd_info_buffer *buffer) +snd_hdspm_proc_read_tco(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct hdspm *hdspm = entry->private_data; - unsigned int status, status2, control, freq; - - char *pref_sync_ref; - char *autosync_ref; - char *system_clock_mode; - char *insel; - int x, x2; - - /* TCO stuff */ + unsigned int status, control; int a, ltc, frames, seconds, minutes, hours; unsigned int period; u64 freq_const = 0; u32 rate; + snd_iprintf(buffer, "--- TCO ---\n"); + status = hdspm_read(hdspm, HDSPM_statusRegister); - status2 = hdspm_read(hdspm, HDSPM_statusRegister2); control = hdspm->control_register; - freq = hdspm_read(hdspm, HDSPM_timecodeRegister); - snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", - hdspm->card_name, hdspm->card->number + 1, - hdspm->firmware_rev, - (status2 & HDSPM_version0) | - (status2 & HDSPM_version1) | (status2 & - HDSPM_version2)); - snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", - (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, - hdspm->serial); - - snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", - hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); - - snd_iprintf(buffer, "--- System ---\n"); - - snd_iprintf(buffer, - "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", - status & HDSPM_audioIRQPending, - (status & HDSPM_midi0IRQPending) ? 1 : 0, - (status & HDSPM_midi1IRQPending) ? 1 : 0, - hdspm->irq_count); - snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) " - "estimated= %ld (bytes)\n", - ((status & HDSPM_BufferID) ? 1 : 0), - (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % - (2 * (int)hdspm->period_bytes), - ((status & HDSPM_BufferPositionMask) - 64) % - (2 * (int)hdspm->period_bytes), - (long) hdspm_hw_pointer(hdspm) * 4); - - snd_iprintf(buffer, - "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", - hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); - snd_iprintf(buffer, - "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", - hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); - snd_iprintf(buffer, - "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " - "status2=0x%x\n", - hdspm->control_register, hdspm->control2_register, - status, status2); if (status & HDSPM_tco_detect) { snd_iprintf(buffer, "TCO module detected.\n"); a = hdspm_read(hdspm, HDSPM_RD_TCO+4); @@ -4800,6 +4745,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, } else { snd_iprintf(buffer, "No TCO module detected.\n"); } +} + +static void +snd_hdspm_proc_read_madi(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdspm *hdspm = entry->private_data; + unsigned int status, status2, control, freq; + + char *pref_sync_ref; + char *autosync_ref; + char *system_clock_mode; + char *insel; + int x, x2; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + control = hdspm->control_register; + freq = hdspm_read(hdspm, HDSPM_timecodeRegister); + + snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", + hdspm->card_name, hdspm->card->number + 1, + hdspm->firmware_rev, + (status2 & HDSPM_version0) | + (status2 & HDSPM_version1) | (status2 & + HDSPM_version2)); + + snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", + (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, + hdspm->serial); + + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); + + snd_iprintf(buffer, "--- System ---\n"); + + snd_iprintf(buffer, + "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", + status & HDSPM_audioIRQPending, + (status & HDSPM_midi0IRQPending) ? 1 : 0, + (status & HDSPM_midi1IRQPending) ? 1 : 0, + hdspm->irq_count); + snd_iprintf(buffer, + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", + ((status & HDSPM_BufferID) ? 1 : 0), + (status & HDSPM_BufferPositionMask), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), + (long) hdspm_hw_pointer(hdspm) * 4); + + snd_iprintf(buffer, + "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); + snd_iprintf(buffer, + "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); + snd_iprintf(buffer, + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " + "status2=0x%x\n", + hdspm->control_register, hdspm->control2_register, + status, status2); + snd_iprintf(buffer, "--- Settings ---\n"); @@ -4903,6 +4917,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, (status & HDSPM_RX_64ch) ? "64 channels" : "56 channels"); + /* call readout function for TCO specific status */ + snd_hdspm_proc_read_tco(entry, buffer); + snd_iprintf(buffer, "\n"); } From b0bf550476a5a6238baf1309ba913ca9f7a379ba Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:05 +0200 Subject: [PATCH 0078/6183] ALSA: hdspm - AES32: Fix TCO sync check reporting HDSPM_tco_lock and HDSPM_tcoLock were too close, so the previous code didn't honour the difference between the two. Let's be more verbose and use HDSPM_tcoLockMadi for MADI cards, HDSPM_tcoLockAes for AES(32) and fix the code that makes use of both. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 58b21048c2e8..bdd8c7742a1f 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -360,11 +360,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ #define HDSPM_madiSync (1<<18) /* MADI is in sync */ -#define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */ -#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */ +#define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ +#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ -#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */ -#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */ +#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ +#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ /* since 64byte accurate, last 6 bits are not used */ @@ -382,7 +382,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); * Interrupt */ #define HDSPM_tco_detect 0x08000000 -#define HDSPM_tco_lock 0x20000000 +#define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ #define HDSPM_s2_tco_detect 0x00000040 #define HDSPM_s2_AEBO_D 0x00000080 @@ -480,7 +480,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 -#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 +#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 +#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 +#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 /* status2 */ /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ @@ -3868,9 +3870,18 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm) if (hdspm->tco) { switch (hdspm->io_type) { case MADI: + status = hdspm_read(hdspm, HDSPM_statusRegister); + if (status & HDSPM_tcoLockMadi) { + if (status & HDSPM_tcoSync) + return 2; + else + return 1; + } + return 0; + break; case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); - if (status & HDSPM_tcoLock) { + if (status & HDSPM_tcoLockAes) { if (status & HDSPM_tcoSync) return 2; else From e71b95ad71e3ee44ec634e242b186e3ff03bd459 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:06 +0200 Subject: [PATCH 0079/6183] ALSA: hdspm - Cosmetics, no real change This patch does nothing, it's sole intent is to clean up the code. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bdd8c7742a1f..d95100e7bd22 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2926,7 +2926,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm) case HDSPM_SelSyncRef_NVALID: return HDSPM_AUTOSYNC_FROM_NONE; default: - return 0; + return HDSPM_AUTOSYNC_FROM_NONE; } } @@ -5260,7 +5260,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) case AES32: hdspm->control_register = - HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + HDSPM_ClockModeMaster | /* Master Clock Mode on */ hdspm_encode_latency(7) | /* latency max=8192samples */ HDSPM_SyncRef0 | /* AES1 is syncclock */ HDSPM_LineOut | /* Analog output in */ @@ -6737,7 +6737,7 @@ static int snd_hdspm_create(struct snd_card *card, if (NULL != hdspm->tco) { hdspm_tco_write(hdspm); } - snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n"); + snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n"); } else { hdspm->tco = NULL; } @@ -6752,10 +6752,12 @@ static int snd_hdspm_create(struct snd_card *card, case AES32: if (hdspm->tco) { hdspm->texts_autosync = texts_autosync_aes_tco; - hdspm->texts_autosync_items = 10; + hdspm->texts_autosync_items = + ARRAY_SIZE(texts_autosync_aes_tco); } else { hdspm->texts_autosync = texts_autosync_aes; - hdspm->texts_autosync_items = 9; + hdspm->texts_autosync_items = + ARRAY_SIZE(texts_autosync_aes); } break; From 3c32de58ae9a3d534ba1a66274bf43631e36eb5c Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:07 +0200 Subject: [PATCH 0080/6183] ALSA: hdspm - AIO: Drop superfluous HDSPM_AUTOSYNC_REF The HDSPM_AUTOSYNC_REF macro is only implemented for MADI and AES32 cards, so it doesn't make sense to call it on AIO boards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index d95100e7bd22..d1e05828cee6 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -4419,7 +4419,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { HDSPM_INTERNAL_CLOCK("Internal Clock", 0), HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), - HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("WC SyncCheck", 0), From db2d1a913d838ecfab5b903508bcdd4e4ad42419 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:08 +0200 Subject: [PATCH 0081/6183] ALSA: hdspm - AES32: Add TCO and Sync-In text entries Provide the text for the two new clock options "TCO" and "Sync In" on AES32 cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index d1e05828cee6..8e6ce1473333 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -561,10 +561,13 @@ static char *hdspm_speed_names[] = { "single", "double", "quad" }; static char *texts_autosync_aes_tco[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", "AES5", "AES6", "AES7", "AES8", - "TCO" }; + "TCO", "Sync In" +}; static char *texts_autosync_aes[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", - "AES5", "AES6", "AES7", "AES8" }; + "AES5", "AES6", "AES7", "AES8", + "Sync In" +}; static char *texts_autosync_madi_tco[] = { "Word Clock", "MADI", "TCO", "Sync In" }; static char *texts_autosync_madi[] = { "Word Clock", @@ -2941,11 +2944,11 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, if (AES32 == hdspm->io_type) { static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", - "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; + "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 10; + uinfo->value.enumerated.items = ARRAY_SIZE(texts); if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = From d3c36ed8e578185b752dac4277819965fa5f6879 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:09 +0200 Subject: [PATCH 0082/6183] ALSA: hdspm - Introduce hdspm_get_aes_sample_rate() Helper function to return the AES sample rate class. This class needs to be translated via HDSPM_bit2freq() to get the more common representation. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 8e6ce1473333..b7702b225c3e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2224,6 +2224,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) return 0; } +/** + * Returns the AES sample rate class for the given card. + **/ +static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) +{ + int timecode; + + switch (hdspm->io_type) { + case AES32: + timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + return (timecode >> (4*index)) & 0xF; + break; + default: + break; + } + return 0; +} /** * Returns the sample rate class for input source for From 5b266354b91087d8f1b1d1b6853a2c012f3e1518 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:10 +0200 Subject: [PATCH 0083/6183] ALSA: hdspm - Add prototype declarations This patch only introduces prototype declarations, no real change. The functions themselves are already present. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b7702b225c3e..367dd411247d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1017,6 +1017,17 @@ static void hdspm_set_sgbuf(struct hdspm *hdspm, struct snd_pcm_substream *substream, unsigned int reg, int channels); +static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); +static int hdspm_wc_sync_check(struct hdspm *hdspm); +static int hdspm_tco_sync_check(struct hdspm *hdspm); +static int hdspm_sync_in_sync_check(struct hdspm *hdspm); + +static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); +static int hdspm_get_tco_sample_rate(struct hdspm *hdspm); +static int hdspm_get_wc_sample_rate(struct hdspm *hdspm); + + + static inline int HDSPM_bit2freq(int n) { static const int bit2freq_tab[] = { @@ -1152,10 +1163,7 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) return rate; } -static int hdspm_tco_sync_check(struct hdspm *hdspm); -static int hdspm_sync_in_sync_check(struct hdspm *hdspm); - -/* check for external sample rate */ +/* check for external sample rate, returns the sample rate in Hz*/ static int hdspm_external_sample_rate(struct hdspm *hdspm) { unsigned int status, status2, timecode; From a57fea8ed44a2d32f8cbdd5455262aca88e72aa6 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:11 +0200 Subject: [PATCH 0084/6183] ALSA: hdspm - Enable AES32 in hdspm_get_wc_sample_rate This patch adds AES32 specific code to hdspm_get_wc_sample_rate() to query the wordclock frequency. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 367dd411247d..a69957cba0f4 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2178,6 +2178,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 16) & 0xF; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister); + return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; default: break; } From 051c44fec7e250a93d8f3b6704a3ce880a11bb0f Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:12 +0200 Subject: [PATCH 0085/6183] ALSA: hdspm - Enable AES32 in hdspm_get_tco_sample_rate This patch adds AES32 specific code to hdspm_get_tco_sample_rate to query the TCO sample rate. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a69957cba0f4..c0143cf83cf3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2204,6 +2204,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 20) & 0xF; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister); + return (status >> 1) & 0xF; default: break; } From 3ac9b0acc34fbe56e2d31b8f2f7e59d45c53cb3b Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:13 +0200 Subject: [PATCH 0086/6183] ALSA: hdspm - AES32: Ignore float/int format bit As mentioned in the comment, the AES32 cards must not set the format bit, since it is used to indicate the preferred sync setting instead. We hence simply skip the corresponding part in the hw_params function. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index c0143cf83cf3..a9f4c7c4b6f4 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -5566,6 +5566,16 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, */ + /* For AES cards, the float format bit is the same as the + * preferred sync reference. Since we don't want to break + * sync settings, we have to skip the remaining part of this + * function. + */ + if (hdspm->io_type == AES32) { + return 0; + } + + /* Switch to native float format if requested */ if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) From dbae4a0c8d8794df1a6bd7e644ed94b915f46f7e Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:14 +0200 Subject: [PATCH 0087/6183] ALSA: hdspm - AES32: Enable TCO input in hdspm_external_sample_rate() This patch adds support to read the TCO sample rate in hdspm_external_sample_rate() on RME AES(32) cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a9f4c7c4b6f4..80b2247dc8f9 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1176,17 +1176,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); syncref = hdspm_autosync_ref(hdspm); + switch (syncref) { + case HDSPM_AES32_AUTOSYNC_FROM_WORD: + /* Check WC sync and get sample rate */ + if (hdspm_wc_sync_check(hdspm)) + return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); + break; - if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && - status & HDSPM_AES32_wcLock) - return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); + case HDSPM_AES32_AUTOSYNC_FROM_AES1: + case HDSPM_AES32_AUTOSYNC_FROM_AES2: + case HDSPM_AES32_AUTOSYNC_FROM_AES3: + case HDSPM_AES32_AUTOSYNC_FROM_AES4: + case HDSPM_AES32_AUTOSYNC_FROM_AES5: + case HDSPM_AES32_AUTOSYNC_FROM_AES6: + case HDSPM_AES32_AUTOSYNC_FROM_AES7: + case HDSPM_AES32_AUTOSYNC_FROM_AES8: + /* Check AES sync and get sample rate */ + if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) + return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, + syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); + break; - if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && - syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && - status2 & (HDSPM_LockAES >> - (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) - return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); - return 0; + + case HDSPM_AES32_AUTOSYNC_FROM_TCO: + /* Check TCO sync and get sample rate */ + if (hdspm_tco_sync_check(hdspm)) + return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); + break; + default: + return 0; + } /* end switch(syncref) */ break; case MADIface: From 2d60fc7f7d3d79e5646646bb34811961f19d111a Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:15 +0200 Subject: [PATCH 0088/6183] ALSA: hdspm - AES32: Enable TCO/Sync-In in snd_hdspm_put_sync_ref() This patch enables the user to select "TCO" and "Sync In" as a preferred sync reference on RME AES(32) cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 80b2247dc8f9..73d96269c9b2 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2954,19 +2954,20 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, static int hdspm_autosync_ref(struct hdspm *hdspm) { + /* This looks at the autosync selected sync reference */ if (AES32 == hdspm->io_type) { - unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int syncref = - (status >> HDSPM_AES32_syncref_bit) & 0xF; - if (syncref == 0) - return HDSPM_AES32_AUTOSYNC_FROM_WORD; - if (syncref <= 8) - return syncref; - return HDSPM_AES32_AUTOSYNC_FROM_NONE; - } else if (MADI == hdspm->io_type) { - /* This looks at the autosync selected sync reference */ - unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); + unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; + if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) && + (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) { + return syncref; + } + return HDSPM_AES32_AUTOSYNC_FROM_NONE; + + } else if (MADI == hdspm->io_type) { + + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); switch (status2 & HDSPM_SelSyncRefMask) { case HDSPM_SelSyncRef_WORD: return HDSPM_AUTOSYNC_FROM_WORD; From 194062daba00688dfd47caaf01f3131700cd726f Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:16 +0200 Subject: [PATCH 0089/6183] ALSA: hdspm - AES32: Include TCO and Sync-In in proc output Also report TCO status and Sync-In via /proc/ on AES(32) cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 73d96269c9b2..f6e922cf3fd3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -5125,11 +5125,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, autosync_ref = "AES7"; break; case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref = "AES8"; break; + case HDSPM_AES32_AUTOSYNC_FROM_TCO: + autosync_ref = "TCO"; break; + case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: + autosync_ref = "Sync In"; break; default: autosync_ref = "---"; break; } snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); + /* call readout function for TCO specific status */ + snd_hdspm_proc_read_tco(entry, buffer); + snd_iprintf(buffer, "\n"); } From 2336142fc0470db2ac831225936b8e37b3ecb2bd Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:17 +0200 Subject: [PATCH 0090/6183] ALSA: hdspm - Introduce hdspm_external_rate_to_enum() helper function This patch refactors the code to query the external sample rate and its translation into the corresponding enum into a helper function to prevent future code duplication. A later commit will make use of this new helper function. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index f6e922cf3fd3..26f10fdbfcd6 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2303,6 +2303,21 @@ static void snd_hdspm_set_infotext(struct snd_ctl_elem_info *uinfo, snd_hdspm_set_infotext(info, texts, ARRAY_SIZE(texts)) +/* Helper function to query the external sample rate and return the + * corresponding enum to be returned to userspace. + */ +static int hdspm_external_rate_to_enum(struct hdspm *hdspm) +{ + int rate = hdspm_external_sample_rate(hdspm); + int i, selected_rate = 0; + for (i = 1; i < 10; i++) + if (HDSPM_bit2freq(i) == rate) { + selected_rate = i; + break; + } + return selected_rate; +} + #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ @@ -2396,18 +2411,9 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, case MADI: case MADIface: - { - int rate = hdspm_external_sample_rate(hdspm); - int i, selected_rate = 0; - for (i = 1; i < 10; i++) - if (HDSPM_bit2freq(i) == rate) { - selected_rate = i; - break; - } - ucontrol->value.enumerated.item[0] = selected_rate; - } + ucontrol->value.enumerated.item[0] = + hdspm_external_rate_to_enum(hdspm); break; - default: break; } From 2d63ec38f5bb1f598baa003a964805c852a80b33 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:18 +0200 Subject: [PATCH 0091/6183] ALSA: hdspm - AES32: Report external sample rate to userspace This patch adds a new ALSA control to read the external sample rate from userspace on RME AES(32) cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 26f10fdbfcd6..2f58e0721ea3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2401,10 +2401,15 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, ucontrol->value.enumerated.item[0] = hdspm_get_sync_in_sample_rate(hdspm); break; + case 11: /* External Rate */ + ucontrol->value.enumerated.item[0] = + hdspm_external_rate_to_enum(hdspm); + break; default: /* AES1 to AES8 */ ucontrol->value.enumerated.item[0] = - hdspm_get_s1_sample_rate(hdspm, - kcontrol->private_value-1); + hdspm_get_aes_sample_rate(hdspm, + kcontrol->private_value - + HDSPM_AES32_AUTOSYNC_FROM_AES1); break; } break; @@ -4550,7 +4555,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), - HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), HDSPM_SYNC_CHECK("WC Sync Check", 0), HDSPM_SYNC_CHECK("AES1 Sync Check", 1), HDSPM_SYNC_CHECK("AES2 Sync Check", 2), From 0dc831b9bca98a0d8dafb00fa7f20b3aef6cab67 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:19 +0200 Subject: [PATCH 0092/6183] ALSA: hdspm - AES32: Enable TCO support This patch finally enables TCO support on RME AES(32) cards. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 2f58e0721ea3..630316c108c0 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6811,6 +6811,7 @@ static int snd_hdspm_create(struct snd_card *card, break; case MADI: + case AES32: if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { hdspm->midiPorts++; hdspm->tco = kzalloc(sizeof(struct hdspm_tco), From 38816545a2cc6f436e5f9b26ebcb4cc2813eeb5c Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:20 +0200 Subject: [PATCH 0093/6183] ALSA: hdspm - Use snd_ctl_enum_info for most text arrays Use snd_ctl_enum_info() to fill most of the enumerated controls. More non-trivial occurrences will follow in separate commits. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 50 +++++++++++++++------------------------ 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 630316c108c0..5a2eb644458e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -590,7 +590,7 @@ static char *texts_autosync_aio_tco[] = { static char *texts_autosync_aio[] = { "Word Clock", "ADAT", "AES", "SPDIF", "Sync In" }; -static char *texts_freq[] = { +static const char *const texts_freq[] = { "No Lock", "32 kHz", "44.1 kHz", @@ -2286,21 +2286,8 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) return (status >> (idx*4)) & 0xF; } -static void snd_hdspm_set_infotext(struct snd_ctl_elem_info *uinfo, - char **texts, const int count) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = count; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); -} - #define ENUMERATED_CTL_INFO(info, texts) \ - snd_hdspm_set_infotext(info, texts, ARRAY_SIZE(texts)) + snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) /* Helper function to query the external sample rate and return the @@ -2477,7 +2464,7 @@ static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Master", "AutoSync" }; + static const char *const texts[] = { "Master", "AutoSync" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3057,7 +3044,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"No video", "NTSC", "PAL"}; + static const char *const texts[] = {"No video", "NTSC", "PAL"}; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3103,7 +3090,7 @@ static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", + static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", "30 fps"}; ENUMERATED_CTL_INFO(uinfo, texts); return 0; @@ -3253,7 +3240,7 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out) static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "optical", "coaxial" }; + static const char *const texts[] = { "optical", "coaxial" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3315,7 +3302,7 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double" }; + static const char *const texts[] = { "Single", "Double" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3388,7 +3375,7 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double", "Quad" }; + static const char *const texts[] = { "Single", "Double", "Quad" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3454,8 +3441,8 @@ static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, { u32 regmask = kcontrol->private_value; - static char *texts_spdif[] = { "Optical", "Coaxial", "Internal" }; - static char *texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; + static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; + static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; switch (regmask) { case HDSPM_c0_Input0: @@ -3542,7 +3529,7 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double", "Quad" }; + static const char *const texts[] = { "Single", "Double", "Quad" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3777,7 +3764,7 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; + static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3785,7 +3772,7 @@ static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "No Lock", "Lock" }; + static const char *const texts[] = { "No Lock", "Lock" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4175,7 +4162,7 @@ static void hdspm_tco_write(struct hdspm *hdspm) static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "44.1 kHz", "48 kHz" }; + static const char *const texts[] = { "44.1 kHz", "48 kHz" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4221,7 +4208,8 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; + static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", + "+ 4 %", "- 4 %" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4266,7 +4254,7 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; + static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4312,7 +4300,7 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "24 fps", "25 fps", "29.97fps", + static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", "29.97 dfps", "30 fps", "30 dfps" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; @@ -4359,7 +4347,7 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "LTC", "Video", "WCK" }; + static const char *const texts[] = { "LTC", "Video", "WCK" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; } From eb0d4dbf3d7f503f435022da46ef1495ca570d85 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:21 +0200 Subject: [PATCH 0094/6183] ALSA: hdspm - Use snd_ctl_enum_info() for texts_autosync Also use snd_ctl_enum_info() to fill the autosync enumerated controls. Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 5a2eb644458e..ffd5d7c08a4b 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -558,36 +558,36 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); /* names for speed modes */ static char *hdspm_speed_names[] = { "single", "double", "quad" }; -static char *texts_autosync_aes_tco[] = { "Word Clock", +static const char *const texts_autosync_aes_tco[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In" }; -static char *texts_autosync_aes[] = { "Word Clock", +static const char *const texts_autosync_aes[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", "AES5", "AES6", "AES7", "AES8", "Sync In" }; -static char *texts_autosync_madi_tco[] = { "Word Clock", +static const char *const texts_autosync_madi_tco[] = { "Word Clock", "MADI", "TCO", "Sync In" }; -static char *texts_autosync_madi[] = { "Word Clock", +static const char *const texts_autosync_madi[] = { "Word Clock", "MADI", "Sync In" }; -static char *texts_autosync_raydat_tco[] = { +static const char *const texts_autosync_raydat_tco[] = { "Word Clock", "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", "AES", "SPDIF", "TCO", "Sync In" }; -static char *texts_autosync_raydat[] = { +static const char *const texts_autosync_raydat[] = { "Word Clock", "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", "AES", "SPDIF", "Sync In" }; -static char *texts_autosync_aio_tco[] = { +static const char *const texts_autosync_aio_tco[] = { "Word Clock", "ADAT", "AES", "SPDIF", "TCO", "Sync In" }; -static char *texts_autosync_aio[] = { "Word Clock", +static const char *const texts_autosync_aio[] = { "Word Clock", "ADAT", "AES", "SPDIF", "Sync In" }; static const char *const texts_freq[] = { @@ -975,7 +975,7 @@ struct hdspm { struct hdspm_tco *tco; /* NULL if no TCO detected */ - char **texts_autosync; + const char *const *texts_autosync; int texts_autosync_items; cycles_t last_interrupt; @@ -2888,16 +2888,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = hdspm->texts_autosync_items; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - hdspm->texts_autosync[uinfo->value.enumerated.item]); + snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); return 0; } From 04659f9e9e6f2493d0e2dc52c72c4f20c22d9c61 Mon Sep 17 00:00:00 2001 From: Adrian Knoth Date: Fri, 5 Jul 2013 11:28:22 +0200 Subject: [PATCH 0095/6183] ALSA: hdspm - Use snd_ctl_enum_info() in snd_hdspm_info_autosync_ref Also use snd_ctl_enum_info() to fill the autosync text fields on AES32 and MADI cards (only users of snd_hdspm_info_autosync_ref). Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index ffd5d7c08a4b..7a09b2de907b 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2983,31 +2983,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); if (AES32 == hdspm->io_type) { - static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", + static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(texts); - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); } else if (MADI == hdspm->io_type) { - static char *texts[] = {"Word Clock", "MADI", "TCO", + static const char *const texts[] = {"Word Clock", "MADI", "TCO", "Sync In", "None" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); } return 0; } From 69358fca4203eda93e008f234fabf603d9dba15e Mon Sep 17 00:00:00 2001 From: Martin Dausel Date: Fri, 5 Jul 2013 11:28:23 +0200 Subject: [PATCH 0096/6183] ALSA: hdspm - Added some comments and control register documentation Signed-off-by: Martin Dausel Signed-off-by: Adrian Knoth Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 106 +++++++++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 7a09b2de907b..a3a71ac513f1 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -38,6 +38,97 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ + +/* ************* Register Documentation ******************************************************* + * + * Work in progress! Documentation is based on the code in this file. + * + * --------- HDSPM_controlRegister --------- + * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number + * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits + * : . : . : . : . x: HDSPM_Start / enables audio IO + * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave + * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency + * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, + * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 + * :x . : . : . x:xx . : HDSPM_FrequencyMask + * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? + * : . : . : . x: . : HDSPM_DoubleSpeed + * :x . : . : . : . : HDSPM_QuadSpeed + * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : + * : . : . x: . : . : HDSPM_SyncRef0 + * : . : . x : . : . : HDSPM_SyncRef1 + * : . : . : x . : . : HDSPM_SyncRef2 + * : . x : . : . : . : HDSPM_SyncRef3 + * : . : . 10: . : . : sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn + * : . 3 : . 10: 2 . : . : 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? + * : . x : . : . : . : HDSPe_FLOAT_FORMAT + * : . : . : x . : . : HDSPM_InputSelect0 : 0=optical,1=coax + * : . : . :x . : . : HDSPM_InputSelect1 + * : . : .x : . : . : HDSPM_clr_tms + * : . : . : . x : . : HDSPM_TX_64ch + * : . : . : . x : . : HDSPM_Emphasis + * : . : . : .x : . : HDSPM_AutoInp + * : . : . x : . : . : HDSPM_SMUX + * : . : .x : . : . : HDSPM_clr_tms + * : . : x. : . : . : HDSPM_taxi_reset + * : . x: . : . : . : HDSPM_LineOut + * : . x: . : . : . : ?????????????????? + * : . : x. : . : . : HDSPM_WCK48 + * : . : . : .x : . : HDSPM_Dolby + * : . : x . : . : . : HDSPM_Midi0InterruptEnable + * : . :x . : . : . : HDSPM_Midi1InterruptEnable + * : . : x . : . : . : HDSPM_Midi2InterruptEnable + * : . x : . : . : . : HDSPM_Midi3InterruptEnable + * : . x : . : . : . : HDSPM_DS_DoubleWire + * : .x : . : . : . : HDSPM_QS_DoubleWire + * : x. : . : . : . : HDSPM_QS_QuadWire + * : . : . : . x : . : HDSPM_Professional + * : x . : . : . : . : HDSPM_wclk_sel + * : . : . : . : . : + * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number + * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit + * + * + * + * AIO / RayDAT only + * + * ------------ HDSPM_WR_SETTINGS ---------- + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte + * :1098.7654:3210.9876:5432.1098:7654.3210: + * :||||.||||:||||.||||:||||.||||:||||.||||: bit number + * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave + * : . : . : . : . x : HDSPM_c0_SyncRef0 + * : . : . : . : . x : HDSPM_c0_SyncRef1 + * : . : . : . : .x : HDSPM_c0_SyncRef2 + * : . : . : . : x. : HDSPM_c0_SyncRef3 + * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: + * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, + * : . : . : . : . : 9:TCO, 10:SyncIn + * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, + * : . : . : . : . : 9:TCO, 10:SyncIn + * : . : . : . : . : + * : . : . : . : . : + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte + * :1098.7654:3210.9876:5432.1098:7654.3210: + * :||||.||||:||||.||||:||||.||||:||||.||||: bit number + * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * + */ #include #include #include @@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_controlRegister 64 #define HDSPM_interruptConfirmation 96 #define HDSPM_control2Reg 256 /* not in specs ???????? */ -#define HDSPM_freqReg 256 /* for AES32 */ +#define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ #define HDSPM_midiDataOut0 352 /* just believe in old code */ #define HDSPM_midiDataOut1 356 #define HDSPM_eeprom_wr 384 /* for AES32 */ @@ -890,11 +981,11 @@ struct hdspm_midi { }; struct hdspm_tco { - int input; - int framerate; - int wordclock; - int samplerate; - int pull; + int input; /* 0: LTC, 1:Video, 2: WC*/ + int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ + int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ + int samplerate; /* 0=44.1, 1=48, 2= freq from app */ + int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ int term; /* 0 = off, 1 = on */ }; @@ -913,7 +1004,7 @@ struct hdspm { u32 control_register; /* cached value */ u32 control2_register; /* cached value */ - u32 settings_register; + u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ struct hdspm_midi midi[4]; struct tasklet_struct midi_tasklet; @@ -4137,6 +4228,7 @@ static void hdspm_tco_write(struct hdspm *hdspm) static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + /* TODO freq from app could be supported here, see tco->samplerate */ static const char *const texts[] = { "44.1 kHz", "48 kHz" }; ENUMERATED_CTL_INFO(uinfo, texts); return 0; From e143a21c4d60d13dbdad133b7b2c9d9bb2dfb982 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 12:01:15 +0200 Subject: [PATCH 0097/6183] drm/i915: explicitly cast pipe -> cpu_transcoder This makes sparse happy and also makes it a bit more obvious where we pull off this trick - after all we're only allowed to do it eithe as a default or on platforms where there is no disdinction between the pipe and the cpu transcoder. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 76796b179170..be15187a49aa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4966,7 +4966,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; - pipe_config->cpu_transcoder = crtc->pipe; + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; tmp = I915_READ(PIPECONF(crtc->pipe)); @@ -5837,7 +5837,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; - pipe_config->cpu_transcoder = crtc->pipe; + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; tmp = I915_READ(PIPECONF(crtc->pipe)); @@ -5953,7 +5953,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, enum intel_display_power_domain pfit_domain; uint32_t tmp; - pipe_config->cpu_transcoder = crtc->pipe; + pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); @@ -7051,7 +7051,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, * Note, if LVDS ever uses a non-1 pixel multiplier, we'll need * to use a real value here instead. */ - pipe_config.cpu_transcoder = intel_crtc->pipe; + pipe_config.cpu_transcoder = (enum transcoder) intel_crtc->pipe; pipe_config.pixel_multiplier = 1; i9xx_crtc_clock_get(intel_crtc, &pipe_config); @@ -7881,7 +7881,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, drm_mode_copy(&pipe_config->adjusted_mode, mode); drm_mode_copy(&pipe_config->requested_mode, mode); - pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe; + pipe_config->cpu_transcoder = + (enum transcoder) to_intel_crtc(crtc)->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; /* Compute a starting value for pipe_config->pipe_bpp taking the source From d94ab068277bda17bfeb0e976049035153299a1a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 12:01:16 +0200 Subject: [PATCH 0098/6183] drm/i915: Explicitly cast pipe -> intel_dpll_id We only do this on IBX where there's a fixed pch dpll to pipe assignment. Being explicit about it can't really hurt and makes sparse happy. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index be15187a49aa..aaa9a752b7b6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3097,7 +3097,7 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc) if (HAS_PCH_IBX(dev_priv->dev)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ - i = crtc->pipe; + i = (enum intel_dpll_id) crtc->pipe; pll = &dev_priv->shared_dplls[i]; DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", @@ -5856,7 +5856,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, ironlake_get_fdi_m_n_config(crtc, pipe_config); if (HAS_PCH_IBX(dev_priv->dev)) { - pipe_config->shared_dpll = crtc->pipe; + pipe_config->shared_dpll = + (enum intel_dpll_id) crtc->pipe; } else { tmp = I915_READ(PCH_DPLL_SEL); if (tmp & TRANS_DPLLB_SEL(crtc->pipe)) From 190d6cd5cd3606dd13a3ca5bf0c23dc520659c15 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 13:06:28 +0200 Subject: [PATCH 0099/6183] drm/i915: less magic for stolen preallocated objects w/o gtt offset A magic -1 is a obscure, especially since it's actually passed as an unsigned, so depends upon the magic sign extension rules in C. This has been added in commit 3727d55e4d85836aa6cb759a965daaef88074150 Author: Jesse Barnes Date: Wed May 8 10:45:14 2013 -0700 drm/i915: allow stolen, pre-allocated objects to avoid GTT allocation v2 Use a proper #define instead. Spotted while reviewing Ben's drm_mm_create_block changes. v2: Cast the constant to u32 since otherwise we again have a type mismatch. Suggested by Chris Wilson. Cc: Ben Widawsky Cc: Jesse Barnes Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a7c2cfb3ee97..0a91554e0aa1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1202,6 +1202,7 @@ enum hdmi_force_audio { }; #define I915_GTT_RESERVED ((struct drm_mm_node *)0x1) +#define I915_GTT_OFFSET_NONE ((u32)-1) struct drm_i915_gem_object_ops { /* Interface between the GEM object and its backing storage. diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 8e023447b7eb..0f18d75fa9f8 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -360,7 +360,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, } /* Some objects just need physical mem from stolen space */ - if (gtt_offset == -1) + if (gtt_offset == I915_GTT_OFFSET_NONE) return obj; /* To simplify the initialisation sequence between KMS and GTT, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7cfd3b74d9b7..0eed35da3ea5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3474,7 +3474,7 @@ static void valleyview_setup_pctx(struct drm_device *dev) pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base; pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev, pcbr_offset, - -1, + I915_GTT_OFFSET_NONE, pctx_size); goto out; } From b79480ba5074ae81d1c32073bce3981652e0f717 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 17:52:10 +0200 Subject: [PATCH 0100/6183] drm/i915: assert_spin_locked for pipestat interrupt enable/disable Just to keep the paranoia equal also sprinkle locking asserts over the pipestat interrupt enable/disable functions. Again this results in false positives in the interrupt setup. Add bogo-locking for these and a big comment explaining why it's there and that it's indeed unnecessary. v2: Fix up the spelling fail Paulo spotted in comments. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4c1b1e3dbf79..c2e11a0fa40c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -319,6 +319,8 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) u32 reg = PIPESTAT(pipe); u32 pipestat = I915_READ(reg) & 0x7fff0000; + assert_spin_locked(&dev_priv->irq_lock); + if ((pipestat & mask) == mask) return; @@ -334,6 +336,8 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) u32 reg = PIPESTAT(pipe); u32 pipestat = I915_READ(reg) & 0x7fff0000; + assert_spin_locked(&dev_priv->irq_lock); + if ((pipestat & mask) == 0) return; @@ -2818,6 +2822,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev) u32 gt_irqs; u32 enable_mask; u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; + unsigned long irqflags; enable_mask = I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | @@ -2843,9 +2848,13 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(PIPESTAT(1), 0xffff); POSTING_READ(VLV_IER); + /* Interrupt setup is already guaranteed to be single-threaded, this is + * just to make the assert_spin_locked check happy. */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); i915_enable_pipestat(dev_priv, 0, pipestat_enable); i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); i915_enable_pipestat(dev_priv, 1, pipestat_enable); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IIR, 0xffffffff); @@ -3324,6 +3333,7 @@ static int i965_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask; u32 error_mask; + unsigned long irqflags; /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT | @@ -3342,7 +3352,11 @@ static int i965_irq_postinstall(struct drm_device *dev) if (IS_G4X(dev)) enable_mask |= I915_BSD_USER_INTERRUPT; + /* Interrupt setup is already guaranteed to be single-threaded, this is + * just to make the assert_spin_locked check happy. */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); /* * Enable some error detection, note the instruction error mask From 8ecada16512c90ae782b00f15ebff0c32e4cd92a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 28 Jun 2013 15:49:39 +0200 Subject: [PATCH 0101/6183] doc: printk-formats: fix format specifier to %p[Ii]4[hnbl] This might have been an oversight, as '4' is needed as %pI4/%pi4 are format specifiers and [hnbl] are extensions of it. Signed-off-by: Daniel Borkmann CC: Joe Perches Signed-off-by: Jiri Kosina --- Documentation/printk-formats.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 3af5ae6c9c11..1525e91f94d8 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -97,7 +97,7 @@ IPv4 addresses: %pI4 1.2.3.4 %pi4 001.002.003.004 - %p[Ii][hnbl] + %p[Ii]4[hnbl] For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4' specifiers result in a printed address with ('i4') or without ('I4') From f35320288c5306ddbcb5ecac046b73519837299c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 2 Jul 2013 16:15:10 +0200 Subject: [PATCH 0102/6183] KVM: PPC: Book3S: Ignore DABR register We don't emulate breakpoints yet, so just ignore reads and writes to / from DABR. This fixes booting of more recent Linux guest kernels for me. Reported-by: Nello Martuscielli Tested-by: Nello Martuscielli Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_emulate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 1f6344c4408d..360ce68c9809 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c @@ -458,6 +458,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) case SPRN_PMC4_GEKKO: case SPRN_WPAR_GEKKO: case SPRN_MSSSR0: + case SPRN_DABR: break; unprivileged: default: @@ -555,6 +556,7 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) case SPRN_PMC4_GEKKO: case SPRN_WPAR_GEKKO: case SPRN_MSSSR0: + case SPRN_DABR: *spr_val = 0; break; default: From fa61a4e376d2129690c82dfb05b31705a67d6e0b Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 2 Jul 2013 11:15:16 +0530 Subject: [PATCH 0103/6183] powerpc/kvm: Contiguous memory allocator based hash page table allocation Powerpc architecture uses a hash based page table mechanism for mapping virtual addresses to physical address. The architecture require this hash page table to be physically contiguous. With KVM on Powerpc currently we use early reservation mechanism for allocating guest hash page table. This implies that we need to reserve a big memory region to ensure we can create large number of guest simultaneously with KVM on Power. Another disadvantage is that the reserved memory is not available to rest of the subsystems and and that implies we limit the total available memory in the host. This patch series switch the guest hash page table allocation to use contiguous memory allocator. Signed-off-by: Aneesh Kumar K.V Acked-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/include/asm/kvm_book3s_64.h | 1 - arch/powerpc/include/asm/kvm_host.h | 2 +- arch/powerpc/include/asm/kvm_ppc.h | 8 +- arch/powerpc/kernel/setup_64.c | 2 + arch/powerpc/kvm/Kconfig | 1 + arch/powerpc/kvm/Makefile | 1 + arch/powerpc/kvm/book3s_64_mmu_hv.c | 37 ++-- arch/powerpc/kvm/book3s_hv_builtin.c | 91 ++++++--- arch/powerpc/kvm/book3s_hv_cma.c | 227 +++++++++++++++++++++++ arch/powerpc/kvm/book3s_hv_cma.h | 22 +++ 10 files changed, 341 insertions(+), 51 deletions(-) create mode 100644 arch/powerpc/kvm/book3s_hv_cma.c create mode 100644 arch/powerpc/kvm/book3s_hv_cma.h diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 9c1ff330c805..f8355a902ac5 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -37,7 +37,6 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu) #ifdef CONFIG_KVM_BOOK3S_64_HV #define KVM_DEFAULT_HPT_ORDER 24 /* 16MB HPT by default */ -extern int kvm_hpt_order; /* order of preallocated HPTs */ #endif #define VRMA_VSID 0x1ffffffUL /* 1TB VSID reserved for VRMA */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index af326cde7cb6..0097dab3d601 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -259,7 +259,7 @@ struct kvm_arch { spinlock_t slot_phys_lock; cpumask_t need_tlb_flush; struct kvmppc_vcore *vcores[KVM_MAX_VCORES]; - struct kvmppc_linear_info *hpt_li; + int hpt_cma_alloc; #endif /* CONFIG_KVM_BOOK3S_64_HV */ #ifdef CONFIG_PPC_BOOK3S_64 struct list_head spapr_tce_tables; diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index a5287fe03d77..b5ef7a3c606b 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -139,8 +139,8 @@ extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *rma); extern struct kvmppc_linear_info *kvm_alloc_rma(void); extern void kvm_release_rma(struct kvmppc_linear_info *ri); -extern struct kvmppc_linear_info *kvm_alloc_hpt(void); -extern void kvm_release_hpt(struct kvmppc_linear_info *li); +extern struct page *kvm_alloc_hpt(unsigned long nr_pages); +extern void kvm_release_hpt(struct page *page, unsigned long nr_pages); extern int kvmppc_core_init_vm(struct kvm *kvm); extern void kvmppc_core_destroy_vm(struct kvm *kvm); extern void kvmppc_core_free_memslot(struct kvm_memory_slot *free, @@ -261,6 +261,7 @@ void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid); struct openpic; #ifdef CONFIG_KVM_BOOK3S_64_HV +extern void kvm_cma_reserve(void) __init; static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) { paca[cpu].kvm_hstate.xics_phys = addr; @@ -284,6 +285,9 @@ extern void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu); extern void kvm_linear_init(void); #else +static inline void __init kvm_cma_reserve(void) +{} + static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) {} diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e379d3fd1694..ee28d1f4b853 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -229,6 +229,8 @@ void __init early_setup(unsigned long dt_ptr) /* Initialize the hash table or TLB handling */ early_init_mmu(); + kvm_cma_reserve(); + /* * Reserve any gigantic pages requested on the command line. * memblock needs to have been initialized by the time this is diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index eb643f862579..ffaef2cb101a 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -72,6 +72,7 @@ config KVM_BOOK3S_64_HV bool "KVM support for POWER7 and PPC970 using hypervisor mode in host" depends on KVM_BOOK3S_64 select MMU_NOTIFIER + select CMA ---help--- Support running unmodified book3s_64 guest kernels in virtual machines on POWER7 and PPC970 processors that have diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 008cd856c5b5..6646c952c5e3 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -81,6 +81,7 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ book3s_64_vio_hv.o \ book3s_hv_ras.o \ book3s_hv_builtin.o \ + book3s_hv_cma.o \ $(kvm-book3s_64-builtin-xics-objs-y) kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 5880dfb31074..354f4bb21f5c 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -52,8 +52,8 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp) { unsigned long hpt; struct revmap_entry *rev; - struct kvmppc_linear_info *li; - long order = kvm_hpt_order; + struct page *page = NULL; + long order = KVM_DEFAULT_HPT_ORDER; if (htab_orderp) { order = *htab_orderp; @@ -61,26 +61,22 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp) order = PPC_MIN_HPT_ORDER; } + kvm->arch.hpt_cma_alloc = 0; /* - * If the user wants a different size from default, * try first to allocate it from the kernel page allocator. + * We keep the CMA reserved for failed allocation. */ - hpt = 0; - if (order != kvm_hpt_order) { - hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT| - __GFP_NOWARN, order - PAGE_SHIFT); - if (!hpt) - --order; - } + hpt = __get_free_pages(GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT | + __GFP_NOWARN, order - PAGE_SHIFT); /* Next try to allocate from the preallocated pool */ if (!hpt) { - li = kvm_alloc_hpt(); - if (li) { - hpt = (ulong)li->base_virt; - kvm->arch.hpt_li = li; - order = kvm_hpt_order; - } + page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT)); + if (page) { + hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page)); + kvm->arch.hpt_cma_alloc = 1; + } else + --order; } /* Lastly try successively smaller sizes from the page allocator */ @@ -118,8 +114,8 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp) return 0; out_freehpt: - if (kvm->arch.hpt_li) - kvm_release_hpt(kvm->arch.hpt_li); + if (kvm->arch.hpt_cma_alloc) + kvm_release_hpt(page, 1 << (order - PAGE_SHIFT)); else free_pages(hpt, order - PAGE_SHIFT); return -ENOMEM; @@ -165,8 +161,9 @@ void kvmppc_free_hpt(struct kvm *kvm) { kvmppc_free_lpid(kvm->arch.lpid); vfree(kvm->arch.revmap); - if (kvm->arch.hpt_li) - kvm_release_hpt(kvm->arch.hpt_li); + if (kvm->arch.hpt_cma_alloc) + kvm_release_hpt(virt_to_page(kvm->arch.hpt_virt), + 1 << (kvm->arch.hpt_order - PAGE_SHIFT)); else free_pages(kvm->arch.hpt_virt, kvm->arch.hpt_order - PAGE_SHIFT); diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index ec0a9e5de100..4b865c553331 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -13,20 +13,30 @@ #include #include #include +#include +#include #include #include #include +#include "book3s_hv_cma.h" + #define KVM_LINEAR_RMA 0 #define KVM_LINEAR_HPT 1 static void __init kvm_linear_init_one(ulong size, int count, int type); static struct kvmppc_linear_info *kvm_alloc_linear(int type); static void kvm_release_linear(struct kvmppc_linear_info *ri); - -int kvm_hpt_order = KVM_DEFAULT_HPT_ORDER; -EXPORT_SYMBOL_GPL(kvm_hpt_order); +/* + * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206) + * should be power of 2. + */ +#define HPT_ALIGN_PAGES ((1 << 18) >> PAGE_SHIFT) /* 256k */ +/* + * By default we reserve 5% of memory for hash pagetable allocation. + */ +static unsigned long kvm_cma_resv_ratio = 5; /*************** RMA *************/ @@ -101,36 +111,29 @@ void kvm_release_rma(struct kvmppc_linear_info *ri) } EXPORT_SYMBOL_GPL(kvm_release_rma); -/*************** HPT *************/ - -/* - * This maintains a list of big linear HPT tables that contain the GVA->HPA - * memory mappings. If we don't reserve those early on, we might not be able - * to get a big (usually 16MB) linear memory region from the kernel anymore. - */ - -static unsigned long kvm_hpt_count; - -static int __init early_parse_hpt_count(char *p) +static int __init early_parse_kvm_cma_resv(char *p) { + pr_debug("%s(%s)\n", __func__, p); if (!p) - return 1; - - kvm_hpt_count = simple_strtoul(p, NULL, 0); - - return 0; + return -EINVAL; + return kstrtoul(p, 0, &kvm_cma_resv_ratio); } -early_param("kvm_hpt_count", early_parse_hpt_count); +early_param("kvm_cma_resv_ratio", early_parse_kvm_cma_resv); -struct kvmppc_linear_info *kvm_alloc_hpt(void) +struct page *kvm_alloc_hpt(unsigned long nr_pages) { - return kvm_alloc_linear(KVM_LINEAR_HPT); + unsigned long align_pages = HPT_ALIGN_PAGES; + + /* Old CPUs require HPT aligned on a multiple of its size */ + if (!cpu_has_feature(CPU_FTR_ARCH_206)) + align_pages = nr_pages; + return kvm_alloc_cma(nr_pages, align_pages); } EXPORT_SYMBOL_GPL(kvm_alloc_hpt); -void kvm_release_hpt(struct kvmppc_linear_info *li) +void kvm_release_hpt(struct page *page, unsigned long nr_pages) { - kvm_release_linear(li); + kvm_release_cma(page, nr_pages); } EXPORT_SYMBOL_GPL(kvm_release_hpt); @@ -211,9 +214,6 @@ static void kvm_release_linear(struct kvmppc_linear_info *ri) */ void __init kvm_linear_init(void) { - /* HPT */ - kvm_linear_init_one(1 << kvm_hpt_order, kvm_hpt_count, KVM_LINEAR_HPT); - /* RMA */ /* Only do this on PPC970 in HV mode */ if (!cpu_has_feature(CPU_FTR_HVMODE) || @@ -231,3 +231,40 @@ void __init kvm_linear_init(void) kvm_linear_init_one(kvm_rma_size, kvm_rma_count, KVM_LINEAR_RMA); } + +/** + * kvm_cma_reserve() - reserve area for kvm hash pagetable + * + * This function reserves memory from early allocator. It should be + * called by arch specific code once the early allocator (memblock or bootmem) + * has been activated and all other subsystems have already allocated/reserved + * memory. + */ +void __init kvm_cma_reserve(void) +{ + unsigned long align_size; + struct memblock_region *reg; + phys_addr_t selected_size = 0; + /* + * We cannot use memblock_phys_mem_size() here, because + * memblock_analyze() has not been called yet. + */ + for_each_memblock(memory, reg) + selected_size += memblock_region_memory_end_pfn(reg) - + memblock_region_memory_base_pfn(reg); + + selected_size = (selected_size * kvm_cma_resv_ratio / 100) << PAGE_SHIFT; + if (selected_size) { + pr_debug("%s: reserving %ld MiB for global area\n", __func__, + (unsigned long)selected_size / SZ_1M); + /* + * Old CPUs require HPT aligned on a multiple of its size. So for them + * make the alignment as max size we could request. + */ + if (!cpu_has_feature(CPU_FTR_ARCH_206)) + align_size = __rounddown_pow_of_two(selected_size); + else + align_size = HPT_ALIGN_PAGES << PAGE_SHIFT; + kvm_cma_declare_contiguous(selected_size, align_size); + } +} diff --git a/arch/powerpc/kvm/book3s_hv_cma.c b/arch/powerpc/kvm/book3s_hv_cma.c new file mode 100644 index 000000000000..e04b269b9c5b --- /dev/null +++ b/arch/powerpc/kvm/book3s_hv_cma.c @@ -0,0 +1,227 @@ +/* + * Contiguous Memory Allocator for ppc KVM hash pagetable based on CMA + * for DMA mapping framework + * + * Copyright IBM Corporation, 2013 + * Author Aneesh Kumar K.V + * + * 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 optional) any later version of the license. + * + */ +#define pr_fmt(fmt) "kvm_cma: " fmt + +#ifdef CONFIG_CMA_DEBUG +#ifndef DEBUG +# define DEBUG +#endif +#endif + +#include +#include +#include +#include + +struct kvm_cma { + unsigned long base_pfn; + unsigned long count; + unsigned long *bitmap; +}; + +static DEFINE_MUTEX(kvm_cma_mutex); +static struct kvm_cma kvm_cma_area; + +/** + * kvm_cma_declare_contiguous() - reserve area for contiguous memory handling + * for kvm hash pagetable + * @size: Size of the reserved memory. + * @alignment: Alignment for the contiguous memory area + * + * This function reserves memory for kvm cma area. It should be + * called by arch code when early allocator (memblock or bootmem) + * is still activate. + */ +long __init kvm_cma_declare_contiguous(phys_addr_t size, phys_addr_t alignment) +{ + long base_pfn; + phys_addr_t addr; + struct kvm_cma *cma = &kvm_cma_area; + + pr_debug("%s(size %lx)\n", __func__, (unsigned long)size); + + if (!size) + return -EINVAL; + /* + * Sanitise input arguments. + * We should be pageblock aligned for CMA. + */ + alignment = max(alignment, (phys_addr_t)(PAGE_SIZE << pageblock_order)); + size = ALIGN(size, alignment); + /* + * Reserve memory + * Use __memblock_alloc_base() since + * memblock_alloc_base() panic()s. + */ + addr = __memblock_alloc_base(size, alignment, 0); + if (!addr) { + base_pfn = -ENOMEM; + goto err; + } else + base_pfn = PFN_DOWN(addr); + + /* + * Each reserved area must be initialised later, when more kernel + * subsystems (like slab allocator) are available. + */ + cma->base_pfn = base_pfn; + cma->count = size >> PAGE_SHIFT; + pr_info("CMA: reserved %ld MiB\n", (unsigned long)size / SZ_1M); + return 0; +err: + pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); + return base_pfn; +} + +/** + * kvm_alloc_cma() - allocate pages from contiguous area + * @nr_pages: Requested number of pages. + * @align_pages: Requested alignment in number of pages + * + * This function allocates memory buffer for hash pagetable. + */ +struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages) +{ + int ret; + struct page *page = NULL; + struct kvm_cma *cma = &kvm_cma_area; + unsigned long mask, pfn, pageno, start = 0; + + + if (!cma || !cma->count) + return NULL; + + pr_debug("%s(cma %p, count %lu, align pages %lu)\n", __func__, + (void *)cma, nr_pages, align_pages); + + if (!nr_pages) + return NULL; + + VM_BUG_ON(!is_power_of_2(align_pages)); + mask = align_pages - 1; + + mutex_lock(&kvm_cma_mutex); + for (;;) { + pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count, + start, nr_pages, mask); + if (pageno >= cma->count) + break; + + pfn = cma->base_pfn + pageno; + ret = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_CMA); + if (ret == 0) { + bitmap_set(cma->bitmap, pageno, nr_pages); + page = pfn_to_page(pfn); + memset(pfn_to_kaddr(pfn), 0, nr_pages << PAGE_SHIFT); + break; + } else if (ret != -EBUSY) { + break; + } + pr_debug("%s(): memory range at %p is busy, retrying\n", + __func__, pfn_to_page(pfn)); + /* try again with a bit different memory target */ + start = pageno + mask + 1; + } + mutex_unlock(&kvm_cma_mutex); + pr_debug("%s(): returned %p\n", __func__, page); + return page; +} + +/** + * kvm_release_cma() - release allocated pages for hash pagetable + * @pages: Allocated pages. + * @nr_pages: Number of allocated pages. + * + * This function releases memory allocated by kvm_alloc_cma(). + * It returns false when provided pages do not belong to contiguous area and + * true otherwise. + */ +bool kvm_release_cma(struct page *pages, unsigned long nr_pages) +{ + unsigned long pfn; + struct kvm_cma *cma = &kvm_cma_area; + + + if (!cma || !pages) + return false; + + pr_debug("%s(page %p count %lu)\n", __func__, (void *)pages, nr_pages); + + pfn = page_to_pfn(pages); + + if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count) + return false; + + VM_BUG_ON(pfn + nr_pages > cma->base_pfn + cma->count); + + mutex_lock(&kvm_cma_mutex); + bitmap_clear(cma->bitmap, pfn - cma->base_pfn, nr_pages); + free_contig_range(pfn, nr_pages); + mutex_unlock(&kvm_cma_mutex); + + return true; +} + +static int __init kvm_cma_activate_area(unsigned long base_pfn, + unsigned long count) +{ + unsigned long pfn = base_pfn; + unsigned i = count >> pageblock_order; + struct zone *zone; + + WARN_ON_ONCE(!pfn_valid(pfn)); + zone = page_zone(pfn_to_page(pfn)); + do { + unsigned j; + base_pfn = pfn; + for (j = pageblock_nr_pages; j; --j, pfn++) { + WARN_ON_ONCE(!pfn_valid(pfn)); + /* + * alloc_contig_range requires the pfn range + * specified to be in the same zone. Make this + * simple by forcing the entire CMA resv range + * to be in the same zone. + */ + if (page_zone(pfn_to_page(pfn)) != zone) + return -EINVAL; + } + init_cma_reserved_pageblock(pfn_to_page(base_pfn)); + } while (--i); + return 0; +} + +static int __init kvm_cma_init_reserved_areas(void) +{ + int bitmap_size, ret; + struct kvm_cma *cma = &kvm_cma_area; + + pr_debug("%s()\n", __func__); + if (!cma->count) + return 0; + + bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long); + cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!cma->bitmap) + return -ENOMEM; + + ret = kvm_cma_activate_area(cma->base_pfn, cma->count); + if (ret) + goto error; + return 0; + +error: + kfree(cma->bitmap); + return ret; +} +core_initcall(kvm_cma_init_reserved_areas); diff --git a/arch/powerpc/kvm/book3s_hv_cma.h b/arch/powerpc/kvm/book3s_hv_cma.h new file mode 100644 index 000000000000..788bc3b73104 --- /dev/null +++ b/arch/powerpc/kvm/book3s_hv_cma.h @@ -0,0 +1,22 @@ +/* + * Contiguous Memory Allocator for ppc KVM hash pagetable based on CMA + * for DMA mapping framework + * + * Copyright IBM Corporation, 2013 + * Author Aneesh Kumar K.V + * + * 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 optional) any later version of the license. + * + */ + +#ifndef __POWERPC_KVM_CMA_ALLOC_H__ +#define __POWERPC_KVM_CMA_ALLOC_H__ +extern struct page *kvm_alloc_cma(unsigned long nr_pages, + unsigned long align_pages); +extern bool kvm_release_cma(struct page *pages, unsigned long nr_pages); +extern long kvm_cma_declare_contiguous(phys_addr_t size, + phys_addr_t alignment) __init; +#endif From 6c45b810989d1c04194499d666f695d3f811965f Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 2 Jul 2013 11:15:17 +0530 Subject: [PATCH 0104/6183] powerpc/kvm: Contiguous memory allocator based RMA allocation Older version of power architecture use Real Mode Offset register and Real Mode Limit Selector for mapping guest Real Mode Area. The guest RMA should be physically contigous since we use the range when address translation is not enabled. This patch switch RMA allocation code to use contigous memory allocator. The patch also remove the the linear allocator which not used any more Acked-by: Paul Mackerras Signed-off-by: Aneesh Kumar K.V Signed-off-by: Alexander Graf --- arch/powerpc/include/asm/kvm_book3s_64.h | 1 + arch/powerpc/include/asm/kvm_host.h | 12 +- arch/powerpc/include/asm/kvm_ppc.h | 8 +- arch/powerpc/kernel/setup_64.c | 2 - arch/powerpc/kvm/book3s_hv.c | 27 ++-- arch/powerpc/kvm/book3s_hv_builtin.c | 165 ++++++----------------- 6 files changed, 64 insertions(+), 151 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index f8355a902ac5..76ff0b5c9996 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -37,6 +37,7 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu) #ifdef CONFIG_KVM_BOOK3S_64_HV #define KVM_DEFAULT_HPT_ORDER 24 /* 16MB HPT by default */ +extern unsigned long kvm_rma_pages; #endif #define VRMA_VSID 0x1ffffffUL /* 1TB VSID reserved for VRMA */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 0097dab3d601..33283532e9d8 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -183,13 +183,9 @@ struct kvmppc_spapr_tce_table { struct page *pages[0]; }; -struct kvmppc_linear_info { - void *base_virt; - unsigned long base_pfn; - unsigned long npages; - struct list_head list; - atomic_t use_count; - int type; +struct kvm_rma_info { + atomic_t use_count; + unsigned long base_pfn; }; /* XICS components, defined in book3s_xics.c */ @@ -246,7 +242,7 @@ struct kvm_arch { int tlbie_lock; unsigned long lpcr; unsigned long rmor; - struct kvmppc_linear_info *rma; + struct kvm_rma_info *rma; unsigned long vrma_slb_v; int rma_setup_done; int using_mmu_notifiers; diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index b5ef7a3c606b..5a26bfcd0bbc 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -137,8 +137,8 @@ extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, unsigned long ioba, unsigned long tce); extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *rma); -extern struct kvmppc_linear_info *kvm_alloc_rma(void); -extern void kvm_release_rma(struct kvmppc_linear_info *ri); +extern struct kvm_rma_info *kvm_alloc_rma(void); +extern void kvm_release_rma(struct kvm_rma_info *ri); extern struct page *kvm_alloc_hpt(unsigned long nr_pages); extern void kvm_release_hpt(struct page *page, unsigned long nr_pages); extern int kvmppc_core_init_vm(struct kvm *kvm); @@ -282,7 +282,6 @@ static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi) } extern void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu); -extern void kvm_linear_init(void); #else static inline void __init kvm_cma_reserve(void) @@ -291,9 +290,6 @@ static inline void __init kvm_cma_reserve(void) static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) {} -static inline void kvm_linear_init(void) -{} - static inline u32 kvmppc_get_xics_latch(void) { return 0; diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index ee28d1f4b853..8a022f5de0ef 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -611,8 +611,6 @@ void __init setup_arch(char **cmdline_p) /* Initialize the MMU context management stuff */ mmu_context_init(); - kvm_linear_init(); - /* Interrupt code needs to be 64K-aligned */ if ((unsigned long)_stext & 0xffff) panic("Kernelbase not 64K-aligned (0x%lx)!\n", diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 2efa9dde741a..2b95c45e17d9 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1511,10 +1511,10 @@ static inline int lpcr_rmls(unsigned long rma_size) static int kvm_rma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - struct kvmppc_linear_info *ri = vma->vm_file->private_data; struct page *page; + struct kvm_rma_info *ri = vma->vm_file->private_data; - if (vmf->pgoff >= ri->npages) + if (vmf->pgoff >= kvm_rma_pages) return VM_FAULT_SIGBUS; page = pfn_to_page(ri->base_pfn + vmf->pgoff); @@ -1536,7 +1536,7 @@ static int kvm_rma_mmap(struct file *file, struct vm_area_struct *vma) static int kvm_rma_release(struct inode *inode, struct file *filp) { - struct kvmppc_linear_info *ri = filp->private_data; + struct kvm_rma_info *ri = filp->private_data; kvm_release_rma(ri); return 0; @@ -1549,8 +1549,17 @@ static const struct file_operations kvm_rma_fops = { long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret) { - struct kvmppc_linear_info *ri; long fd; + struct kvm_rma_info *ri; + /* + * Only do this on PPC970 in HV mode + */ + if (!cpu_has_feature(CPU_FTR_HVMODE) || + !cpu_has_feature(CPU_FTR_ARCH_201)) + return -EINVAL; + + if (!kvm_rma_pages) + return -EINVAL; ri = kvm_alloc_rma(); if (!ri) @@ -1560,7 +1569,7 @@ long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret) if (fd < 0) kvm_release_rma(ri); - ret->rma_size = ri->npages << PAGE_SHIFT; + ret->rma_size = kvm_rma_pages << PAGE_SHIFT; return fd; } @@ -1725,7 +1734,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) { int err = 0; struct kvm *kvm = vcpu->kvm; - struct kvmppc_linear_info *ri = NULL; + struct kvm_rma_info *ri = NULL; unsigned long hva; struct kvm_memory_slot *memslot; struct vm_area_struct *vma; @@ -1803,7 +1812,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) } else { /* Set up to use an RMO region */ - rma_size = ri->npages; + rma_size = kvm_rma_pages; if (rma_size > memslot->npages) rma_size = memslot->npages; rma_size <<= PAGE_SHIFT; @@ -1831,14 +1840,14 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) /* POWER7 */ lpcr &= ~(LPCR_VPM0 | LPCR_VRMA_L); lpcr |= rmls << LPCR_RMLS_SH; - kvm->arch.rmor = kvm->arch.rma->base_pfn << PAGE_SHIFT; + kvm->arch.rmor = ri->base_pfn << PAGE_SHIFT; } kvm->arch.lpcr = lpcr; pr_info("KVM: Using RMO at %lx size %lx (LPCR = %lx)\n", ri->base_pfn << PAGE_SHIFT, rma_size, lpcr); /* Initialize phys addrs of pages in RMO */ - npages = ri->npages; + npages = kvm_rma_pages; porder = __ilog2(npages); physp = memslot->arch.slot_phys; if (physp) { diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 4b865c553331..8cd0daebb82d 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -21,13 +21,6 @@ #include #include "book3s_hv_cma.h" - -#define KVM_LINEAR_RMA 0 -#define KVM_LINEAR_HPT 1 - -static void __init kvm_linear_init_one(ulong size, int count, int type); -static struct kvmppc_linear_info *kvm_alloc_linear(int type); -static void kvm_release_linear(struct kvmppc_linear_info *ri); /* * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206) * should be power of 2. @@ -37,19 +30,17 @@ static void kvm_release_linear(struct kvmppc_linear_info *ri); * By default we reserve 5% of memory for hash pagetable allocation. */ static unsigned long kvm_cma_resv_ratio = 5; - -/*************** RMA *************/ - /* - * This maintains a list of RMAs (real mode areas) for KVM guests to use. + * We allocate RMAs (real mode areas) for KVM guests from the KVM CMA area. * Each RMA has to be physically contiguous and of a size that the * hardware supports. PPC970 and POWER7 support 64MB, 128MB and 256MB, * and other larger sizes. Since we are unlikely to be allocate that * much physically contiguous memory after the system is up and running, - * we preallocate a set of RMAs in early boot for KVM to use. + * we preallocate a set of RMAs in early boot using CMA. + * should be power of 2. */ -static unsigned long kvm_rma_size = 64 << 20; /* 64MB */ -static unsigned long kvm_rma_count; +unsigned long kvm_rma_pages = (1 << 27) >> PAGE_SHIFT; /* 128MB */ +EXPORT_SYMBOL_GPL(kvm_rma_pages); /* Work out RMLS (real mode limit selector) field value for a given RMA size. Assumes POWER7 or PPC970. */ @@ -79,35 +70,50 @@ static inline int lpcr_rmls(unsigned long rma_size) static int __init early_parse_rma_size(char *p) { + unsigned long kvm_rma_size; + + pr_debug("%s(%s)\n", __func__, p); if (!p) - return 1; - + return -EINVAL; kvm_rma_size = memparse(p, &p); - + /* + * Check that the requested size is one supported in hardware + */ + if (lpcr_rmls(kvm_rma_size) < 0) { + pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size); + return -EINVAL; + } + kvm_rma_pages = kvm_rma_size >> PAGE_SHIFT; return 0; } early_param("kvm_rma_size", early_parse_rma_size); -static int __init early_parse_rma_count(char *p) +struct kvm_rma_info *kvm_alloc_rma() { - if (!p) - return 1; + struct page *page; + struct kvm_rma_info *ri; - kvm_rma_count = simple_strtoul(p, NULL, 0); - - return 0; -} -early_param("kvm_rma_count", early_parse_rma_count); - -struct kvmppc_linear_info *kvm_alloc_rma(void) -{ - return kvm_alloc_linear(KVM_LINEAR_RMA); + ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL); + if (!ri) + return NULL; + page = kvm_alloc_cma(kvm_rma_pages, kvm_rma_pages); + if (!page) + goto err_out; + atomic_set(&ri->use_count, 1); + ri->base_pfn = page_to_pfn(page); + return ri; +err_out: + kfree(ri); + return NULL; } EXPORT_SYMBOL_GPL(kvm_alloc_rma); -void kvm_release_rma(struct kvmppc_linear_info *ri) +void kvm_release_rma(struct kvm_rma_info *ri) { - kvm_release_linear(ri); + if (atomic_dec_and_test(&ri->use_count)) { + kvm_release_cma(pfn_to_page(ri->base_pfn), kvm_rma_pages); + kfree(ri); + } } EXPORT_SYMBOL_GPL(kvm_release_rma); @@ -137,101 +143,6 @@ void kvm_release_hpt(struct page *page, unsigned long nr_pages) } EXPORT_SYMBOL_GPL(kvm_release_hpt); -/*************** generic *************/ - -static LIST_HEAD(free_linears); -static DEFINE_SPINLOCK(linear_lock); - -static void __init kvm_linear_init_one(ulong size, int count, int type) -{ - unsigned long i; - unsigned long j, npages; - void *linear; - struct page *pg; - const char *typestr; - struct kvmppc_linear_info *linear_info; - - if (!count) - return; - - typestr = (type == KVM_LINEAR_RMA) ? "RMA" : "HPT"; - - npages = size >> PAGE_SHIFT; - linear_info = alloc_bootmem(count * sizeof(struct kvmppc_linear_info)); - for (i = 0; i < count; ++i) { - linear = alloc_bootmem_align(size, size); - pr_debug("Allocated KVM %s at %p (%ld MB)\n", typestr, linear, - size >> 20); - linear_info[i].base_virt = linear; - linear_info[i].base_pfn = __pa(linear) >> PAGE_SHIFT; - linear_info[i].npages = npages; - linear_info[i].type = type; - list_add_tail(&linear_info[i].list, &free_linears); - atomic_set(&linear_info[i].use_count, 0); - - pg = pfn_to_page(linear_info[i].base_pfn); - for (j = 0; j < npages; ++j) { - atomic_inc(&pg->_count); - ++pg; - } - } -} - -static struct kvmppc_linear_info *kvm_alloc_linear(int type) -{ - struct kvmppc_linear_info *ri, *ret; - - ret = NULL; - spin_lock(&linear_lock); - list_for_each_entry(ri, &free_linears, list) { - if (ri->type != type) - continue; - - list_del(&ri->list); - atomic_inc(&ri->use_count); - memset(ri->base_virt, 0, ri->npages << PAGE_SHIFT); - ret = ri; - break; - } - spin_unlock(&linear_lock); - return ret; -} - -static void kvm_release_linear(struct kvmppc_linear_info *ri) -{ - if (atomic_dec_and_test(&ri->use_count)) { - spin_lock(&linear_lock); - list_add_tail(&ri->list, &free_linears); - spin_unlock(&linear_lock); - - } -} - -/* - * Called at boot time while the bootmem allocator is active, - * to allocate contiguous physical memory for the hash page - * tables for guests. - */ -void __init kvm_linear_init(void) -{ - /* RMA */ - /* Only do this on PPC970 in HV mode */ - if (!cpu_has_feature(CPU_FTR_HVMODE) || - !cpu_has_feature(CPU_FTR_ARCH_201)) - return; - - if (!kvm_rma_size || !kvm_rma_count) - return; - - /* Check that the requested size is one supported in hardware */ - if (lpcr_rmls(kvm_rma_size) < 0) { - pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size); - return; - } - - kvm_linear_init_one(kvm_rma_size, kvm_rma_count, KVM_LINEAR_RMA); -} - /** * kvm_cma_reserve() - reserve area for kvm hash pagetable * @@ -265,6 +176,8 @@ void __init kvm_cma_reserve(void) align_size = __rounddown_pow_of_two(selected_size); else align_size = HPT_ALIGN_PAGES << PAGE_SHIFT; + + align_size = max(kvm_rma_pages << PAGE_SHIFT, align_size); kvm_cma_declare_contiguous(selected_size, align_size); } } From 990978e99359e1f3a843563b9f96f9dc7bb7c05a Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 2 Jul 2013 11:15:18 +0530 Subject: [PATCH 0105/6183] powerpc/kvm: Use 256K chunk to track both RMA and hash page table allocation. Both RMA and hash page table request will be a multiple of 256K. We can use a chunk size of 256K to track the free/used 256K chunk in the bitmap. This should help to reduce the bitmap size. Signed-off-by: Aneesh Kumar K.V Acked-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_64_mmu_hv.c | 3 +++ arch/powerpc/kvm/book3s_hv_cma.c | 35 ++++++++++++++++++++--------- arch/powerpc/kvm/book3s_hv_cma.h | 5 +++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 354f4bb21f5c..7eb5ddab1203 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -37,6 +37,8 @@ #include #include +#include "book3s_hv_cma.h" + /* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */ #define MAX_LPID_970 63 @@ -71,6 +73,7 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp) /* Next try to allocate from the preallocated pool */ if (!hpt) { + VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER); page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT)); if (page) { hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page)); diff --git a/arch/powerpc/kvm/book3s_hv_cma.c b/arch/powerpc/kvm/book3s_hv_cma.c index e04b269b9c5b..d9d3d8553d51 100644 --- a/arch/powerpc/kvm/book3s_hv_cma.c +++ b/arch/powerpc/kvm/book3s_hv_cma.c @@ -24,6 +24,8 @@ #include #include +#include "book3s_hv_cma.h" + struct kvm_cma { unsigned long base_pfn; unsigned long count; @@ -96,6 +98,7 @@ struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages) int ret; struct page *page = NULL; struct kvm_cma *cma = &kvm_cma_area; + unsigned long chunk_count, nr_chunk; unsigned long mask, pfn, pageno, start = 0; @@ -107,21 +110,27 @@ struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages) if (!nr_pages) return NULL; - + /* + * align mask with chunk size. The bit tracks pages in chunk size + */ VM_BUG_ON(!is_power_of_2(align_pages)); - mask = align_pages - 1; + mask = (align_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT)) - 1; + BUILD_BUG_ON(PAGE_SHIFT > KVM_CMA_CHUNK_ORDER); + + chunk_count = cma->count >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT); + nr_chunk = nr_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT); mutex_lock(&kvm_cma_mutex); for (;;) { - pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count, - start, nr_pages, mask); - if (pageno >= cma->count) + pageno = bitmap_find_next_zero_area(cma->bitmap, chunk_count, + start, nr_chunk, mask); + if (pageno >= chunk_count) break; - pfn = cma->base_pfn + pageno; + pfn = cma->base_pfn + (pageno << (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT)); ret = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_CMA); if (ret == 0) { - bitmap_set(cma->bitmap, pageno, nr_pages); + bitmap_set(cma->bitmap, pageno, nr_chunk); page = pfn_to_page(pfn); memset(pfn_to_kaddr(pfn), 0, nr_pages << PAGE_SHIFT); break; @@ -150,9 +159,9 @@ struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages) bool kvm_release_cma(struct page *pages, unsigned long nr_pages) { unsigned long pfn; + unsigned long nr_chunk; struct kvm_cma *cma = &kvm_cma_area; - if (!cma || !pages) return false; @@ -164,9 +173,12 @@ bool kvm_release_cma(struct page *pages, unsigned long nr_pages) return false; VM_BUG_ON(pfn + nr_pages > cma->base_pfn + cma->count); + nr_chunk = nr_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT); mutex_lock(&kvm_cma_mutex); - bitmap_clear(cma->bitmap, pfn - cma->base_pfn, nr_pages); + bitmap_clear(cma->bitmap, + (pfn - cma->base_pfn) >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT), + nr_chunk); free_contig_range(pfn, nr_pages); mutex_unlock(&kvm_cma_mutex); @@ -204,13 +216,14 @@ static int __init kvm_cma_activate_area(unsigned long base_pfn, static int __init kvm_cma_init_reserved_areas(void) { int bitmap_size, ret; + unsigned long chunk_count; struct kvm_cma *cma = &kvm_cma_area; pr_debug("%s()\n", __func__); if (!cma->count) return 0; - - bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long); + chunk_count = cma->count >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT); + bitmap_size = BITS_TO_LONGS(chunk_count) * sizeof(long); cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL); if (!cma->bitmap) return -ENOMEM; diff --git a/arch/powerpc/kvm/book3s_hv_cma.h b/arch/powerpc/kvm/book3s_hv_cma.h index 788bc3b73104..655144f75fa5 100644 --- a/arch/powerpc/kvm/book3s_hv_cma.h +++ b/arch/powerpc/kvm/book3s_hv_cma.h @@ -14,6 +14,11 @@ #ifndef __POWERPC_KVM_CMA_ALLOC_H__ #define __POWERPC_KVM_CMA_ALLOC_H__ +/* + * Both RMA and Hash page allocation will be multiple of 256K. + */ +#define KVM_CMA_CHUNK_ORDER 18 + extern struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages); extern bool kvm_release_cma(struct page *pages, unsigned long nr_pages); From 0773d73d818702191dd568e1e20bcafc5c64661a Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 22 May 2013 10:38:53 +0200 Subject: [PATCH 0106/6183] ARM: move VFP init to an earlier boot stage In order to use the NEON unit in the kernel, we should initialize it a bit earlier in the boot process so NEON users that like to do a quick benchmark at load time (like the xor_blocks or RAID-6 code) find the NEON/VFP unit already enabled. Replaced late_initcall() with core_initcall(). Signed-off-by: Ard Biesheuvel Acked-by: Nicolas Pitre --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 5dfbb0b8e7f4..791993aed75a 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -731,4 +731,4 @@ static int __init vfp_init(void) return 0; } -late_initcall(vfp_init); +core_initcall(vfp_init); From c3d1fb567a634dcdff4c6f6095b2053260988336 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Mon, 1 Jul 2013 21:08:47 +0530 Subject: [PATCH 0107/6183] mce: acpi/apei: Honour Firmware First for MCA banks listed in APEI HEST CMC The Corrected Machine Check structure (CMC) in HEST has a flag which can be set by the firmware to indicate to the OS that it prefers to process the corrected error events first. In this scenario, the OS is expected to not monitor for corrected errors (through CMCI/polling). Instead, the firmware notifies the OS on corrected error events through GHES. Linux already has support for GHES. This patch adds support for parsing CMC structure and to disable CMCI/polling if the firmware first flag is set. Further, the list of machine check bank structures at the end of CMC is used to determine which MCA banks function in FF mode, so that we continue to monitor error events on the other banks. Signed-off-by: Naveen N. Rao Acked-by: Borislav Petkov Signed-off-by: Tony Luck --- arch/x86/include/asm/mce.h | 3 ++ arch/x86/kernel/cpu/mcheck/mce-internal.h | 3 ++ arch/x86/kernel/cpu/mcheck/mce.c | 28 +++++++++++++++ arch/x86/kernel/cpu/mcheck/mce_intel.c | 42 +++++++++++++++++------ drivers/acpi/apei/hest.c | 37 ++++++++++++++++++++ 5 files changed, 103 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index fa5f71e021d5..9c91683ab5e6 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -188,6 +188,9 @@ extern void register_mce_write_callback(ssize_t (*)(struct file *filp, const char __user *ubuf, size_t usize, loff_t *off)); +/* Disable CMCI/polling for MCA bank claimed by firmware */ +extern void mce_disable_bank(int bank); + /* * Exception handler */ diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h index 5b7d4fa5d3b7..09edd0b65fef 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-internal.h +++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h @@ -25,15 +25,18 @@ int mce_severity(struct mce *a, int tolerant, char **msg); struct dentry *mce_get_debugfs_dir(void); extern struct mce_bank *mce_banks; +extern mce_banks_t mce_banks_ce_disabled; #ifdef CONFIG_X86_MCE_INTEL unsigned long mce_intel_adjust_timer(unsigned long interval); void mce_intel_cmci_poll(void); void mce_intel_hcpu_update(unsigned long cpu); +void cmci_disable_bank(int bank); #else # define mce_intel_adjust_timer mce_adjust_timer_default static inline void mce_intel_cmci_poll(void) { } static inline void mce_intel_hcpu_update(unsigned long cpu) { } +static inline void cmci_disable_bank(int bank) { } #endif void mce_timer_kick(unsigned long interval); diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 9239504b41cb..5bf32c70a9c0 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -94,6 +94,15 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL }; +/* + * MCA banks controlled through firmware first for corrected errors. + * This is a global list of banks for which we won't enable CMCI and we + * won't poll. Firmware controls these banks and is responsible for + * reporting corrected errors through GHES. Uncorrected/recoverable + * errors are still notified through a machine check. + */ +mce_banks_t mce_banks_ce_disabled; + static DEFINE_PER_CPU(struct work_struct, mce_work); static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs); @@ -1932,6 +1941,25 @@ static struct miscdevice mce_chrdev_device = { &mce_chrdev_ops, }; +static void __mce_disable_bank(void *arg) +{ + int bank = *((int *)arg); + __clear_bit(bank, __get_cpu_var(mce_poll_banks)); + cmci_disable_bank(bank); +} + +void mce_disable_bank(int bank) +{ + if (bank >= mca_cfg.banks) { + pr_warn(FW_BUG + "Ignoring request to disable invalid MCA bank %d.\n", + bank); + return; + } + set_bit(bank, mce_banks_ce_disabled); + on_each_cpu(__mce_disable_bank, &bank, 1); +} + /* * mce=off Disables machine check * mce=no_cmci Disables CMCI diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c index ae1697c2afe3..488eae3ec3e2 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_intel.c +++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -191,6 +191,10 @@ static void cmci_discover(int banks) if (test_bit(i, owned)) continue; + /* Skip banks in firmware first mode */ + if (test_bit(i, mce_banks_ce_disabled)) + continue; + rdmsrl(MSR_IA32_MCx_CTL2(i), val); /* Already owned by someone else? */ @@ -259,6 +263,19 @@ void cmci_recheck(void) local_irq_restore(flags); } +/* Caller must hold the lock on cmci_discover_lock */ +static void __cmci_disable_bank(int bank) +{ + u64 val; + + if (!test_bit(bank, __get_cpu_var(mce_banks_owned))) + return; + rdmsrl(MSR_IA32_MCx_CTL2(bank), val); + val &= ~MCI_CTL2_CMCI_EN; + wrmsrl(MSR_IA32_MCx_CTL2(bank), val); + __clear_bit(bank, __get_cpu_var(mce_banks_owned)); +} + /* * Disable CMCI on this CPU for all banks it owns when it goes down. * This allows other CPUs to claim the banks on rediscovery. @@ -268,20 +285,12 @@ void cmci_clear(void) unsigned long flags; int i; int banks; - u64 val; if (!cmci_supported(&banks)) return; raw_spin_lock_irqsave(&cmci_discover_lock, flags); - for (i = 0; i < banks; i++) { - if (!test_bit(i, __get_cpu_var(mce_banks_owned))) - continue; - /* Disable CMCI */ - rdmsrl(MSR_IA32_MCx_CTL2(i), val); - val &= ~MCI_CTL2_CMCI_EN; - wrmsrl(MSR_IA32_MCx_CTL2(i), val); - __clear_bit(i, __get_cpu_var(mce_banks_owned)); - } + for (i = 0; i < banks; i++) + __cmci_disable_bank(i); raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); } @@ -315,6 +324,19 @@ void cmci_reenable(void) cmci_discover(banks); } +void cmci_disable_bank(int bank) +{ + int banks; + unsigned long flags; + + if (!cmci_supported(&banks)) + return; + + raw_spin_lock_irqsave(&cmci_discover_lock, flags); + __cmci_disable_bank(bank); + raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); +} + static void intel_init_cmci(void) { int banks; diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index f5ef5d54e4ac..b108b116bf28 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "apei-internal.h" @@ -121,6 +122,40 @@ int apei_hest_parse(apei_hest_func_t func, void *data) } EXPORT_SYMBOL_GPL(apei_hest_parse); +/* + * Check if firmware advertises firmware first mode. We need FF bit to be set + * along with a set of MC banks which work in FF mode. + */ +static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data) +{ + int i; + struct acpi_hest_ia_corrected *cmc; + struct acpi_hest_ia_error_bank *mc_bank; + + if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) + return 0; + + cmc = (struct acpi_hest_ia_corrected *)hest_hdr; + if (!cmc->enabled) + return 0; + + /* + * We expect HEST to provide a list of MC banks that report errors + * in firmware first mode. Otherwise, return non-zero value to + * indicate that we are done parsing HEST. + */ + if (!(cmc->flags & ACPI_HEST_FIRMWARE_FIRST) || !cmc->num_hardware_banks) + return 1; + + pr_info(HEST_PFX "Enabling Firmware First mode for corrected errors.\n"); + + mc_bank = (struct acpi_hest_ia_error_bank *)(cmc + 1); + for (i = 0; i < cmc->num_hardware_banks; i++, mc_bank++) + mce_disable_bank(mc_bank->bank_number); + + return 1; +} + struct ghes_arr { struct platform_device **ghes_devs; unsigned int count; @@ -227,6 +262,8 @@ void __init acpi_hest_init(void) goto err; } + apei_hest_parse(hest_parse_cmc, NULL); + if (!ghes_disable) { rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); if (rc) From 9ad95879cd1b22ed016c804f8d686ff83a41a9d4 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Mon, 1 Jul 2013 21:08:54 +0530 Subject: [PATCH 0108/6183] mce: acpi/apei: Add a boot option to disable ff mode for corrected errors Add a boot option to disable firmware first mode for corrected errors. Signed-off-by: Naveen N. Rao Acked-by: Borislav Petkov Signed-off-by: Tony Luck --- Documentation/x86/x86_64/boot-options.txt | 5 +++++ arch/x86/include/asm/acpi.h | 2 ++ arch/x86/kernel/acpi/boot.c | 5 +++++ drivers/acpi/apei/hest.c | 3 ++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index e9e8ddbbf376..1228b22e142b 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -176,6 +176,11 @@ ACPI acpi=noirq Don't route interrupts + acpi=nocmcff Disable firmware first mode for corrected errors. This + disables parsing the HEST CMC error source to check if + firmware has set the FF flag. This may result in + duplicate corrected error reports. + PCI pci=off Don't use PCI diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index b31bf97775fc..42db2b88953b 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -86,6 +86,7 @@ extern int acpi_pci_disabled; extern int acpi_skip_timer_override; extern int acpi_use_timer_override; extern int acpi_fix_pin2_polarity; +extern int acpi_disable_cmcff; extern u8 acpi_sci_flags; extern int acpi_sci_override_gsi; @@ -168,6 +169,7 @@ static inline void arch_acpi_set_pdc_bits(u32 *buf) #define acpi_lapic 0 #define acpi_ioapic 0 +#define acpi_disable_cmcff 0 static inline void acpi_noirq_set(void) { } static inline void acpi_disable_pci(void) { } static inline void disable_acpi(void) { } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 230c8ea878e5..d1998d580080 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -66,6 +66,7 @@ EXPORT_SYMBOL(acpi_pci_disabled); int acpi_lapic; int acpi_ioapic; int acpi_strict; +int acpi_disable_cmcff; u8 acpi_sci_flags __initdata; int acpi_sci_override_gsi __initdata; @@ -1619,6 +1620,10 @@ static int __init parse_acpi(char *arg) /* "acpi=copy_dsdt" copys DSDT */ else if (strcmp(arg, "copy_dsdt") == 0) { acpi_gbl_copy_dsdt_locally = 1; + } + /* "acpi=nocmcff" disables FF mode for corrected errors */ + else if (strcmp(arg, "nocmcff") == 0) { + acpi_disable_cmcff = 1; } else { /* Core will printk when we return error. */ return -EINVAL; diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index b108b116bf28..502024502b13 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -262,7 +262,8 @@ void __init acpi_hest_init(void) goto err; } - apei_hest_parse(hest_parse_cmc, NULL); + if (!acpi_disable_cmcff) + apei_hest_parse(hest_parse_cmc, NULL); if (!ghes_disable) { rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); From b3a070cccb9135f8bec63d9f194ddaa422136fb0 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Jul 2013 14:41:02 -0700 Subject: [PATCH 0109/6183] drm: pre allocate node for create_block For an upcoming patch where we introduce the i915 VMA, it's ideal to have the drm_mm_node as part of the VMA struct (ie. it's pre-allocated). Part of the conversion to VMAs is to kill off obj->gtt_space. Doing this will break a bunch of code, but amongst them are 2 callers of drm_mm_create_block(), both related to stolen memory. It also allows us to embed the drm_mm_node into the object currently which provides a nice transition over to the new code. v2: Reordered to do before ripping out obj->gtt_offset. Some minor cleanups made available because of reordering. v3: s/continue/break on failed stolen node allocation (David) Set obj->gtt_space on failed node allocation (David) Only unref stolen (fix double free) on failed create_stolen (David) Free node, and NULL it in failed create_stolen (David) Add back accidentally removed newline (David) CC: Reviewed-by: David Herrmann Signed-off-by: Ben Widawsky Acked-by: David Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_mm.c | 16 ++++------- drivers/gpu/drm/i915/i915_gem_gtt.c | 20 +++++++++++--- drivers/gpu/drm/i915/i915_gem_stolen.c | 37 +++++++++++++++++++------- include/drm/drm_mm.h | 9 ++++--- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 07cf99cc8862..9e8dfbc1955e 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -147,12 +147,10 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, } } -struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, - unsigned long start, - unsigned long size, - bool atomic) +int drm_mm_create_block(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long start, unsigned long size) { - struct drm_mm_node *hole, *node; + struct drm_mm_node *hole; unsigned long end = start + size; unsigned long hole_start; unsigned long hole_end; @@ -161,10 +159,6 @@ struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, if (hole_start > start || hole_end < end) continue; - node = drm_mm_kmalloc(mm, atomic); - if (unlikely(node == NULL)) - return NULL; - node->start = start; node->size = size; node->mm = mm; @@ -184,11 +178,11 @@ struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, node->hole_follows = 1; } - return node; + return 0; } WARN(1, "no hole found for block 0x%lx + 0x%lx\n", start, size); - return NULL; + return -ENOSPC; } EXPORT_SYMBOL(drm_mm_create_block); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 66929eac6367..88180a597c0a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -629,14 +629,26 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, /* Mark any preallocated objects as occupied */ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { + int ret; DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n", obj->gtt_offset, obj->base.size); BUG_ON(obj->gtt_space != I915_GTT_RESERVED); - obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space, - obj->gtt_offset, - obj->base.size, - false); + obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); + if (!obj->gtt_space) { + DRM_ERROR("Failed to preserve object at offset %x\n", + obj->gtt_offset); + continue; + } + ret = drm_mm_create_block(&dev_priv->mm.gtt_space, + obj->gtt_space, + obj->gtt_offset, + obj->base.size); + if (ret) { + DRM_DEBUG_KMS("Reservation failed\n"); + kfree(obj->gtt_space); + obj->gtt_space = NULL; + } obj->has_global_gtt_mapping = 1; } diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 0f18d75fa9f8..2746ff2d846a 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -330,6 +330,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct drm_mm_node *stolen; + int ret; if (dev_priv->mm.stolen_base == 0) return NULL; @@ -344,11 +345,15 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, if (WARN_ON(size == 0)) return NULL; - stolen = drm_mm_create_block(&dev_priv->mm.stolen, - stolen_offset, size, - false); - if (stolen == NULL) { + stolen = kzalloc(sizeof(*stolen), GFP_KERNEL); + if (!stolen) + return NULL; + + ret = drm_mm_create_block(&dev_priv->mm.stolen, stolen, stolen_offset, + size); + if (ret) { DRM_DEBUG_KMS("failed to allocate stolen space\n"); + kfree(stolen); return NULL; } @@ -369,13 +374,18 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, * later. */ if (drm_mm_initialized(&dev_priv->mm.gtt_space)) { - obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space, - gtt_offset, size, - false); - if (obj->gtt_space == NULL) { + obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); + if (!obj->gtt_space) { + DRM_DEBUG_KMS("-ENOMEM stolen GTT space\n"); + goto unref_out; + } + + ret = drm_mm_create_block(&dev_priv->mm.gtt_space, + obj->gtt_space, + gtt_offset, size); + if (ret) { DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); - drm_gem_object_unreference(&obj->base); - return NULL; + goto free_out; } } else obj->gtt_space = I915_GTT_RESERVED; @@ -387,6 +397,13 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); return obj; + +free_out: + kfree(obj->gtt_space); + obj->gtt_space = NULL; +unref_out: + drm_gem_object_unreference(&obj->base); + return NULL; } void diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 88591ef8fa24..d8b56b7d1839 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -138,10 +138,10 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) /* * Basic range manager support (drm_mm.c) */ -extern struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, - unsigned long start, - unsigned long size, - bool atomic); +extern int drm_mm_create_block(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long start, + unsigned long size); extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, unsigned long size, unsigned alignment, @@ -155,6 +155,7 @@ extern struct drm_mm_node *drm_mm_get_block_range_generic( unsigned long start, unsigned long end, int atomic); + static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, unsigned long size, unsigned alignment) From 338710e7aff3428dc8170a03704a8ae981b58dcd Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Jul 2013 14:41:03 -0700 Subject: [PATCH 0110/6183] drm: Change create block to reserve node With the previous patch we no longer actually create a node, we simply find the correct hole and occupy it. This very well could have been squashed with the last patch, but since I already had David's review, I figured it's easiest to keep it distinct. Also update the users in i915. Conveniently this is the only user of the interface. CC: David Airlie CC: Signed-off-by: Ben Widawsky Acked-by: David Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_mm.c | 19 ++++++++++--------- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 ++++---- drivers/gpu/drm/i915/i915_gem_stolen.c | 12 +++++++----- include/drm/drm_mm.h | 5 +---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 9e8dfbc1955e..52e0ee7f4a6f 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -147,27 +147,27 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, } } -int drm_mm_create_block(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long start, unsigned long size) +int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) { struct drm_mm_node *hole; - unsigned long end = start + size; + unsigned long end = node->start + node->size; unsigned long hole_start; unsigned long hole_end; + BUG_ON(node == NULL); + + /* Find the relevant hole to add our node to */ drm_mm_for_each_hole(hole, mm, hole_start, hole_end) { - if (hole_start > start || hole_end < end) + if (hole_start > node->start || hole_end < end) continue; - node->start = start; - node->size = size; node->mm = mm; node->allocated = 1; INIT_LIST_HEAD(&node->hole_stack); list_add(&node->node_list, &hole->node_list); - if (start == hole_start) { + if (node->start == hole_start) { hole->hole_follows = 0; list_del_init(&hole->hole_stack); } @@ -181,10 +181,11 @@ int drm_mm_create_block(struct drm_mm *mm, struct drm_mm_node *node, return 0; } - WARN(1, "no hole found for block 0x%lx + 0x%lx\n", start, size); + WARN(1, "no hole found for node 0x%lx + 0x%lx\n", + node->start, node->size); return -ENOSPC; } -EXPORT_SYMBOL(drm_mm_create_block); +EXPORT_SYMBOL(drm_mm_reserve_node); struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node, unsigned long size, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 88180a597c0a..afba7e5e7739 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -640,10 +640,10 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, obj->gtt_offset); continue; } - ret = drm_mm_create_block(&dev_priv->mm.gtt_space, - obj->gtt_space, - obj->gtt_offset, - obj->base.size); + obj->gtt_space->start = obj->gtt_offset; + obj->gtt_space->size = obj->base.size; + ret = drm_mm_reserve_node(&dev_priv->mm.gtt_space, + obj->gtt_space); if (ret) { DRM_DEBUG_KMS("Reservation failed\n"); kfree(obj->gtt_space); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 2746ff2d846a..4e6dbbb47dfe 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -349,8 +349,9 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, if (!stolen) return NULL; - ret = drm_mm_create_block(&dev_priv->mm.stolen, stolen, stolen_offset, - size); + stolen->start = stolen_offset; + stolen->size = size; + ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen); if (ret) { DRM_DEBUG_KMS("failed to allocate stolen space\n"); kfree(stolen); @@ -380,9 +381,10 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, goto unref_out; } - ret = drm_mm_create_block(&dev_priv->mm.gtt_space, - obj->gtt_space, - gtt_offset, size); + obj->gtt_space->start = gtt_offset; + obj->gtt_space->size = size; + ret = drm_mm_reserve_node(&dev_priv->mm.gtt_space, + obj->gtt_space); if (ret) { DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); goto free_out; diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index d8b56b7d1839..2de91e3da5cc 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -138,10 +138,7 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) /* * Basic range manager support (drm_mm.c) */ -extern int drm_mm_create_block(struct drm_mm *mm, - struct drm_mm_node *node, - unsigned long start, - unsigned long size); +extern int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node); extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, unsigned long size, unsigned alignment, From f343c5f6477354967ee1e331a68a56b9fece2f36 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Jul 2013 14:41:04 -0700 Subject: [PATCH 0111/6183] drm/i915: Getter/setter for object attributes Soon we want to gut a lot of our existing assumptions how many address spaces an object can live in, and in doing so, embed the drm_mm_node in the object (and later the VMA). It's possible in the future we'll want to add more getter/setter methods, but for now this is enough to enable the VMAs. v2: Reworked commit message (Ben) Added comments to the main functions (Ben) sed -i "s/i915_gem_obj_set_color/i915_gem_obj_ggtt_set_color/" drivers/gpu/drm/i915/*.[ch] sed -i "s/i915_gem_obj_bound/i915_gem_obj_ggtt_bound/" drivers/gpu/drm/i915/*.[ch] sed -i "s/i915_gem_obj_size/i915_gem_obj_ggtt_size/" drivers/gpu/drm/i915/*.[ch] sed -i "s/i915_gem_obj_offset/i915_gem_obj_ggtt_offset/" drivers/gpu/drm/i915/*.[ch] (Daniel) v3: Rebased on new reserve_node patch Changed DRM_DEBUG_KMS to actually work (will need fixing later) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 26 ++++--- drivers/gpu/drm/i915/i915_drv.h | 31 ++++++++ drivers/gpu/drm/i915/i915_gem.c | 89 +++++++++++----------- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 19 ++--- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 +- drivers/gpu/drm/i915/i915_gem_tiling.c | 14 ++-- drivers/gpu/drm/i915/i915_irq.c | 15 ++-- drivers/gpu/drm/i915/i915_trace.h | 8 +- drivers/gpu/drm/i915/intel_display.c | 28 +++---- drivers/gpu/drm/i915/intel_fb.c | 8 +- drivers/gpu/drm/i915/intel_overlay.c | 14 ++-- drivers/gpu/drm/i915/intel_pm.c | 8 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 12 +-- drivers/gpu/drm/i915/intel_sprite.c | 8 +- 15 files changed, 164 insertions(+), 126 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3e36756d0439..396387ed207a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -122,9 +122,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) seq_printf(m, " (pinned x %d)", obj->pin_count); if (obj->fence_reg != I915_FENCE_REG_NONE) seq_printf(m, " (fence: %d)", obj->fence_reg); - if (obj->gtt_space != NULL) - seq_printf(m, " (gtt offset: %08x, size: %08x)", - obj->gtt_offset, (unsigned int)obj->gtt_space->size); + if (i915_gem_obj_ggtt_bound(obj)) + seq_printf(m, " (gtt offset: %08lx, size: %08x)", + i915_gem_obj_ggtt_offset(obj), (unsigned int)i915_gem_obj_ggtt_size(obj)); if (obj->stolen) seq_printf(m, " (stolen: %08lx)", obj->stolen->start); if (obj->pin_mappable || obj->fault_mappable) { @@ -175,7 +175,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) describe_obj(m, obj); seq_putc(m, '\n'); total_obj_size += obj->base.size; - total_gtt_size += obj->gtt_space->size; + total_gtt_size += i915_gem_obj_ggtt_size(obj); count++; } mutex_unlock(&dev->struct_mutex); @@ -187,10 +187,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) #define count_objects(list, member) do { \ list_for_each_entry(obj, list, member) { \ - size += obj->gtt_space->size; \ + size += i915_gem_obj_ggtt_size(obj); \ ++count; \ if (obj->map_and_fenceable) { \ - mappable_size += obj->gtt_space->size; \ + mappable_size += i915_gem_obj_ggtt_size(obj); \ ++mappable_count; \ } \ } \ @@ -209,7 +209,7 @@ static int per_file_stats(int id, void *ptr, void *data) stats->count++; stats->total += obj->base.size; - if (obj->gtt_space) { + if (i915_gem_obj_ggtt_bound(obj)) { if (!list_empty(&obj->ring_list)) stats->active += obj->base.size; else @@ -267,11 +267,11 @@ static int i915_gem_object_info(struct seq_file *m, void *data) size = count = mappable_size = mappable_count = 0; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { if (obj->fault_mappable) { - size += obj->gtt_space->size; + size += i915_gem_obj_ggtt_size(obj); ++count; } if (obj->pin_mappable) { - mappable_size += obj->gtt_space->size; + mappable_size += i915_gem_obj_ggtt_size(obj); ++mappable_count; } if (obj->madv == I915_MADV_DONTNEED) { @@ -333,7 +333,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) describe_obj(m, obj); seq_putc(m, '\n'); total_obj_size += obj->base.size; - total_gtt_size += obj->gtt_space->size; + total_gtt_size += i915_gem_obj_ggtt_size(obj); count++; } @@ -379,12 +379,14 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) if (work->old_fb_obj) { struct drm_i915_gem_object *obj = work->old_fb_obj; if (obj) - seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj->gtt_offset); + seq_printf(m, "Old framebuffer gtt_offset 0x%08lx\n", + i915_gem_obj_ggtt_offset(obj)); } if (work->pending_flip_obj) { struct drm_i915_gem_object *obj = work->pending_flip_obj; if (obj) - seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj->gtt_offset); + seq_printf(m, "New framebuffer gtt_offset 0x%08lx\n", + i915_gem_obj_ggtt_offset(obj)); } } spin_unlock_irqrestore(&dev->event_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0a91554e0aa1..8a92174109c2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1361,6 +1361,37 @@ struct drm_i915_gem_object { #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base) +/* Offset of the first PTE pointing to this object */ +static inline unsigned long +i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o) +{ + return o->gtt_space->start; +} + +/* Whether or not this object is currently mapped by the translation tables */ +static inline bool +i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *o) +{ + return o->gtt_space != NULL; +} + +/* The size used in the translation tables may be larger than the actual size of + * the object on GEN2/GEN3 because of the way tiling is handled. See + * i915_gem_get_gtt_size() for more details. + */ +static inline unsigned long +i915_gem_obj_ggtt_size(struct drm_i915_gem_object *o) +{ + return o->gtt_space->size; +} + +static inline void +i915_gem_obj_ggtt_set_color(struct drm_i915_gem_object *o, + enum i915_cache_level color) +{ + o->gtt_space->color = color; +} + /** * Request queue structure. * diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 769f75262feb..b8a0d91f2e2d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -135,7 +135,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) static inline bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) { - return obj->gtt_space && !obj->active; + return i915_gem_obj_ggtt_bound(obj) && !obj->active; } int @@ -178,7 +178,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) if (obj->pin_count) - pinned += obj->gtt_space->size; + pinned += i915_gem_obj_ggtt_size(obj); mutex_unlock(&dev->struct_mutex); args->aper_size = dev_priv->gtt.total; @@ -422,7 +422,7 @@ i915_gem_shmem_pread(struct drm_device *dev, * anyway again before the next pread happens. */ if (obj->cache_level == I915_CACHE_NONE) needs_clflush = 1; - if (obj->gtt_space) { + if (i915_gem_obj_ggtt_bound(obj)) { ret = i915_gem_object_set_to_gtt_domain(obj, false); if (ret) return ret; @@ -609,7 +609,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, user_data = to_user_ptr(args->data_ptr); remain = args->size; - offset = obj->gtt_offset + args->offset; + offset = i915_gem_obj_ggtt_offset(obj) + args->offset; while (remain > 0) { /* Operation in this page @@ -739,7 +739,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev, * right away and we therefore have to clflush anyway. */ if (obj->cache_level == I915_CACHE_NONE) needs_clflush_after = 1; - if (obj->gtt_space) { + if (i915_gem_obj_ggtt_bound(obj)) { ret = i915_gem_object_set_to_gtt_domain(obj, true); if (ret) return ret; @@ -1360,8 +1360,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) obj->fault_mappable = true; - pfn = ((dev_priv->gtt.mappable_base + obj->gtt_offset) >> PAGE_SHIFT) + - page_offset; + pfn = dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj); + pfn >>= PAGE_SHIFT; + pfn += page_offset; /* Finally, remap it using the new GTT offset */ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); @@ -1667,7 +1668,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj) if (obj->pages == NULL) return 0; - BUG_ON(obj->gtt_space); + BUG_ON(i915_gem_obj_ggtt_bound(obj)); if (obj->pages_pin_count) return -EBUSY; @@ -2117,8 +2118,8 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj) { - if (acthd >= obj->gtt_offset && - acthd < obj->gtt_offset + obj->base.size) + if (acthd >= i915_gem_obj_ggtt_offset(obj) && + acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) return true; return false; @@ -2176,11 +2177,11 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring, if (ring->hangcheck.action != wait && i915_request_guilty(request, acthd, &inside)) { - DRM_ERROR("%s hung %s bo (0x%x ctx %d) at 0x%x\n", + DRM_ERROR("%s hung %s bo (0x%lx ctx %d) at 0x%x\n", ring->name, inside ? "inside" : "flushing", request->batch_obj ? - request->batch_obj->gtt_offset : 0, + i915_gem_obj_ggtt_offset(request->batch_obj) : 0, request->ctx ? request->ctx->id : 0, acthd); @@ -2592,7 +2593,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) drm_i915_private_t *dev_priv = obj->base.dev->dev_private; int ret; - if (obj->gtt_space == NULL) + if (!i915_gem_obj_ggtt_bound(obj)) return 0; if (obj->pin_count) @@ -2675,11 +2676,11 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, } if (obj) { - u32 size = obj->gtt_space->size; + u32 size = i915_gem_obj_ggtt_size(obj); - val = (uint64_t)((obj->gtt_offset + size - 4096) & + val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & 0xfffff000) << 32; - val |= obj->gtt_offset & 0xfffff000; + val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; @@ -2699,15 +2700,15 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg, u32 val; if (obj) { - u32 size = obj->gtt_space->size; + u32 size = i915_gem_obj_ggtt_size(obj); int pitch_val; int tile_width; - WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) || + WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) || (size & -size) != size || - (obj->gtt_offset & (size - 1)), - "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", - obj->gtt_offset, obj->map_and_fenceable, size); + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", + i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size); if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) tile_width = 128; @@ -2718,7 +2719,7 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg, pitch_val = obj->stride / tile_width; pitch_val = ffs(pitch_val) - 1; - val = obj->gtt_offset; + val = i915_gem_obj_ggtt_offset(obj); if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; val |= I915_FENCE_SIZE_BITS(size); @@ -2743,19 +2744,19 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg, uint32_t val; if (obj) { - u32 size = obj->gtt_space->size; + u32 size = i915_gem_obj_ggtt_size(obj); uint32_t pitch_val; - WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) || + WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) || (size & -size) != size || - (obj->gtt_offset & (size - 1)), - "object 0x%08x not 512K or pot-size 0x%08x aligned\n", - obj->gtt_offset, size); + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx not 512K or pot-size 0x%08x aligned\n", + i915_gem_obj_ggtt_offset(obj), size); pitch_val = obj->stride / 128; pitch_val = ffs(pitch_val) - 1; - val = obj->gtt_offset; + val = i915_gem_obj_ggtt_offset(obj); if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; val |= I830_FENCE_SIZE_BITS(size); @@ -3044,8 +3045,8 @@ static void i915_gem_verify_gtt(struct drm_device *dev) if (obj->cache_level != obj->gtt_space->color) { printk(KERN_ERR "object reserved space [%08lx, %08lx] with wrong color, cache_level=%x, color=%lx\n", - obj->gtt_space->start, - obj->gtt_space->start + obj->gtt_space->size, + i915_gem_obj_ggtt_offset(obj), + i915_gem_obj_ggtt_offset(obj) + i915_gem_obj_ggtt_size(obj), obj->cache_level, obj->gtt_space->color); err++; @@ -3056,8 +3057,8 @@ static void i915_gem_verify_gtt(struct drm_device *dev) obj->gtt_space, obj->cache_level)) { printk(KERN_ERR "invalid GTT space found at [%08lx, %08lx] - color=%x\n", - obj->gtt_space->start, - obj->gtt_space->start + obj->gtt_space->size, + i915_gem_obj_ggtt_offset(obj), + i915_gem_obj_ggtt_offset(obj) + i915_gem_obj_ggtt_size(obj), obj->cache_level); err++; continue; @@ -3169,8 +3170,8 @@ search_free: node->size == fence_size && (node->start & (fence_alignment - 1)) == 0; - mappable = - obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end; + mappable = i915_gem_obj_ggtt_offset(obj) + obj->base.size <= + dev_priv->gtt.mappable_end; obj->map_and_fenceable = mappable && fenceable; @@ -3272,7 +3273,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) int ret; /* Not valid to be called on unbound objects. */ - if (obj->gtt_space == NULL) + if (!i915_gem_obj_ggtt_bound(obj)) return -EINVAL; if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) @@ -3337,7 +3338,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return ret; } - if (obj->gtt_space) { + if (i915_gem_obj_ggtt_bound(obj)) { ret = i915_gem_object_finish_gpu(obj); if (ret) return ret; @@ -3360,7 +3361,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, obj, cache_level); - obj->gtt_space->color = cache_level; + i915_gem_obj_ggtt_set_color(obj, cache_level); } if (cache_level == I915_CACHE_NONE) { @@ -3641,14 +3642,14 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) return -EBUSY; - if (obj->gtt_space != NULL) { - if ((alignment && obj->gtt_offset & (alignment - 1)) || + if (i915_gem_obj_ggtt_bound(obj)) { + if ((alignment && i915_gem_obj_ggtt_offset(obj) & (alignment - 1)) || (map_and_fenceable && !obj->map_and_fenceable)) { WARN(obj->pin_count, "bo is already pinned with incorrect alignment:" - " offset=%x, req.alignment=%x, req.map_and_fenceable=%d," + " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d," " obj->map_and_fenceable=%d\n", - obj->gtt_offset, alignment, + i915_gem_obj_ggtt_offset(obj), alignment, map_and_fenceable, obj->map_and_fenceable); ret = i915_gem_object_unbind(obj); @@ -3657,7 +3658,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, } } - if (obj->gtt_space == NULL) { + if (!i915_gem_obj_ggtt_bound(obj)) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; ret = i915_gem_object_bind_to_gtt(obj, alignment, @@ -3683,7 +3684,7 @@ void i915_gem_object_unpin(struct drm_i915_gem_object *obj) { BUG_ON(obj->pin_count == 0); - BUG_ON(obj->gtt_space == NULL); + BUG_ON(!i915_gem_obj_ggtt_bound(obj)); if (--obj->pin_count == 0) obj->pin_mappable = false; @@ -3733,7 +3734,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, * as the X server doesn't manage domains yet */ i915_gem_object_flush_cpu_write_domain(obj); - args->offset = obj->gtt_offset; + args->offset = i915_gem_obj_ggtt_offset(obj); out: drm_gem_object_unreference(&obj->base); unlock: diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 51b7a2171cae..2074544682cf 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -377,7 +377,7 @@ mi_set_context(struct intel_ring_buffer *ring, intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_SET_CONTEXT); - intel_ring_emit(ring, new_context->obj->gtt_offset | + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->obj) | MI_MM_SPACE_GTT | MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN | diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 87a3227e5179..5aeb447ead6b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -188,7 +188,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, return -ENOENT; target_i915_obj = to_intel_bo(target_obj); - target_offset = target_i915_obj->gtt_offset; + target_offset = i915_gem_obj_ggtt_offset(target_i915_obj); /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and * pipe_control writes because the gpu doesn't properly redirect them @@ -280,7 +280,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, return ret; /* Map the page containing the relocation we're going to perform. */ - reloc->offset += obj->gtt_offset; + reloc->offset += i915_gem_obj_ggtt_offset(obj); reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, reloc->offset & PAGE_MASK); reloc_entry = (uint32_t __iomem *) @@ -436,8 +436,8 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, obj->has_aliasing_ppgtt_mapping = 1; } - if (entry->offset != obj->gtt_offset) { - entry->offset = obj->gtt_offset; + if (entry->offset != i915_gem_obj_ggtt_offset(obj)) { + entry->offset = i915_gem_obj_ggtt_offset(obj); *need_reloc = true; } @@ -458,7 +458,7 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj) { struct drm_i915_gem_exec_object2 *entry; - if (!obj->gtt_space) + if (!i915_gem_obj_ggtt_bound(obj)) return; entry = obj->exec_entry; @@ -530,7 +530,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; bool need_fence, need_mappable; - if (!obj->gtt_space) + if (!i915_gem_obj_ggtt_bound(obj)) continue; need_fence = @@ -539,7 +539,8 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, obj->tiling_mode != I915_TILING_NONE; need_mappable = need_fence || need_reloc_mappable(obj); - if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) || + if ((entry->alignment && + i915_gem_obj_ggtt_offset(obj) & (entry->alignment - 1)) || (need_mappable && !obj->map_and_fenceable)) ret = i915_gem_object_unbind(obj); else @@ -550,7 +551,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, /* Bind fresh objects */ list_for_each_entry(obj, objects, exec_list) { - if (obj->gtt_space) + if (i915_gem_obj_ggtt_bound(obj)) continue; ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); @@ -1058,7 +1059,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - exec_start = batch_obj->gtt_offset + args->batch_start_offset; + exec_start = i915_gem_obj_ggtt_offset(batch_obj) + args->batch_start_offset; exec_len = args->batch_len; if (cliprects) { for (i = 0; i < args->num_cliprects; i++) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index afba7e5e7739..6f0a4c09e26a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -378,7 +378,7 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, enum i915_cache_level cache_level) { ppgtt->insert_entries(ppgtt, obj->pages, - obj->gtt_space->start >> PAGE_SHIFT, + i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, cache_level); } @@ -386,7 +386,7 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj) { ppgtt->clear_range(ppgtt, - obj->gtt_space->start >> PAGE_SHIFT, + i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT); } @@ -551,7 +551,7 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->gtt.gtt_insert_entries(dev, obj->pages, - obj->gtt_space->start >> PAGE_SHIFT, + i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, cache_level); obj->has_global_gtt_mapping = 1; @@ -563,7 +563,7 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->gtt.gtt_clear_range(obj->base.dev, - obj->gtt_space->start >> PAGE_SHIFT, + i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, obj->base.size >> PAGE_SHIFT); obj->has_global_gtt_mapping = 0; diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 537545be69db..92a8d279ca39 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -268,18 +268,18 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) return true; if (INTEL_INFO(obj->base.dev)->gen == 3) { - if (obj->gtt_offset & ~I915_FENCE_START_MASK) + if (i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) return false; } else { - if (obj->gtt_offset & ~I830_FENCE_START_MASK) + if (i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) return false; } size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode); - if (obj->gtt_space->size != size) + if (i915_gem_obj_ggtt_size(obj) != size) return false; - if (obj->gtt_offset & (size - 1)) + if (i915_gem_obj_ggtt_offset(obj) & (size - 1)) return false; return true; @@ -359,8 +359,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, */ obj->map_and_fenceable = - obj->gtt_space == NULL || - (obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end && + !i915_gem_obj_ggtt_bound(obj) || + (i915_gem_obj_ggtt_offset(obj) + obj->base.size <= dev_priv->gtt.mappable_end && i915_gem_object_fence_ok(obj, args->tiling_mode)); /* Rebind if we need a change of alignment */ @@ -369,7 +369,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, i915_gem_get_gtt_alignment(dev, obj->base.size, args->tiling_mode, false); - if (obj->gtt_offset & (unfenced_alignment - 1)) + if (i915_gem_obj_ggtt_offset(obj) & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c2e11a0fa40c..4aedd387c8b5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1520,7 +1520,7 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, if (dst == NULL) return NULL; - reloc_offset = src->gtt_offset; + reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src); for (i = 0; i < num_pages; i++) { unsigned long flags; void *d; @@ -1572,7 +1572,6 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv, reloc_offset += PAGE_SIZE; } dst->page_count = num_pages; - dst->gtt_offset = src->gtt_offset; return dst; @@ -1626,7 +1625,7 @@ static void capture_bo(struct drm_i915_error_buffer *err, err->name = obj->base.name; err->rseqno = obj->last_read_seqno; err->wseqno = obj->last_write_seqno; - err->gtt_offset = obj->gtt_offset; + err->gtt_offset = i915_gem_obj_ggtt_offset(obj); err->read_domains = obj->base.read_domains; err->write_domain = obj->base.write_domain; err->fence_reg = obj->fence_reg; @@ -1724,8 +1723,8 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, return NULL; obj = ring->private; - if (acthd >= obj->gtt_offset && - acthd < obj->gtt_offset + obj->base.size) + if (acthd >= i915_gem_obj_ggtt_offset(obj) && + acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) return i915_error_object_create(dev_priv, obj); } @@ -1806,7 +1805,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring, return; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - if ((error->ccid & PAGE_MASK) == obj->gtt_offset) { + if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) { ering->ctx = i915_error_object_create_sized(dev_priv, obj, 1); break; @@ -2160,10 +2159,10 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in if (INTEL_INFO(dev)->gen >= 4) { int dspsurf = DSPSURF(intel_crtc->plane); stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) == - obj->gtt_offset; + i915_gem_obj_ggtt_offset(obj); } else { int dspaddr = DSPADDR(intel_crtc->plane); - stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + + stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) + crtc->y * crtc->fb->pitches[0] + crtc->x * crtc->fb->bits_per_pixel/8); } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 3db4a6817713..7d283b5fcbf9 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -46,8 +46,8 @@ TRACE_EVENT(i915_gem_object_bind, TP_fast_assign( __entry->obj = obj; - __entry->offset = obj->gtt_space->start; - __entry->size = obj->gtt_space->size; + __entry->offset = i915_gem_obj_ggtt_offset(obj); + __entry->size = i915_gem_obj_ggtt_size(obj); __entry->mappable = mappable; ), @@ -68,8 +68,8 @@ TRACE_EVENT(i915_gem_object_unbind, TP_fast_assign( __entry->obj = obj; - __entry->offset = obj->gtt_space->start; - __entry->size = obj->gtt_space->size; + __entry->offset = i915_gem_obj_ggtt_offset(obj); + __entry->size = i915_gem_obj_ggtt_size(obj); ), TP_printk("obj=%p, offset=%08x size=%x", diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aaa9a752b7b6..a45bb92f35ad 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1980,16 +1980,17 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, intel_crtc->dspaddr_offset = linear_offset; } - DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n", - obj->gtt_offset, linear_offset, x, y, fb->pitches[0]); + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + i915_gem_obj_ggtt_offset(obj), linear_offset, x, y, + fb->pitches[0]); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); if (INTEL_INFO(dev)->gen >= 4) { I915_MODIFY_DISPBASE(DSPSURF(plane), - obj->gtt_offset + intel_crtc->dspaddr_offset); + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPLINOFF(plane), linear_offset); } else - I915_WRITE(DSPADDR(plane), obj->gtt_offset + linear_offset); + I915_WRITE(DSPADDR(plane), i915_gem_obj_ggtt_offset(obj) + linear_offset); POSTING_READ(reg); return 0; @@ -2069,11 +2070,12 @@ static int ironlake_update_plane(struct drm_crtc *crtc, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; - DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n", - obj->gtt_offset, linear_offset, x, y, fb->pitches[0]); + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + i915_gem_obj_ggtt_offset(obj), linear_offset, x, y, + fb->pitches[0]); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); I915_MODIFY_DISPBASE(DSPSURF(plane), - obj->gtt_offset + intel_crtc->dspaddr_offset); + i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); if (IS_HASWELL(dev)) { I915_WRITE(DSPOFFSET(plane), (y << 16) | x); } else { @@ -6567,7 +6569,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, goto fail_unpin; } - addr = obj->gtt_offset; + addr = i915_gem_obj_ggtt_offset(obj); } else { int align = IS_I830(dev) ? 16 * 1024 : 256; ret = i915_gem_attach_phys_object(dev, obj, @@ -7339,7 +7341,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); intel_ring_emit(ring, fb->pitches[0]); - intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); intel_ring_emit(ring, 0); /* aux display base address, unused */ intel_mark_page_flip_active(intel_crtc); @@ -7380,7 +7382,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); intel_ring_emit(ring, fb->pitches[0]); - intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); intel_ring_emit(ring, MI_NOOP); intel_mark_page_flip_active(intel_crtc); @@ -7420,7 +7422,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev, MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); intel_ring_emit(ring, fb->pitches[0]); intel_ring_emit(ring, - (obj->gtt_offset + intel_crtc->dspaddr_offset) | + (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) | obj->tiling_mode); /* XXX Enabling the panel-fitter across page-flip is so far @@ -7463,7 +7465,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode); - intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); /* Contrary to the suggestions in the documentation, * "Enable Panel Fitter" does not seem to be required when page @@ -7528,7 +7530,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit); intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); - intel_ring_emit(ring, obj->gtt_offset + intel_crtc->dspaddr_offset); + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); intel_ring_emit(ring, (MI_NOOP)); intel_mark_page_flip_active(intel_crtc); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index dff669e2387f..f3c97e05b0d8 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -139,11 +139,11 @@ static int intelfb_create(struct drm_fb_helper *helper, info->apertures->ranges[0].base = dev->mode_config.fb_base; info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; - info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; + info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj); info->fix.smem_len = size; info->screen_base = - ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset, + ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), size); if (!info->screen_base) { ret = -ENOSPC; @@ -166,9 +166,9 @@ static int intelfb_create(struct drm_fb_helper *helper, /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", + DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, fb->height, - obj->gtt_offset, obj); + i915_gem_obj_ggtt_offset(obj), obj); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index a3698812e9c7..81c3ca14fa92 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -196,7 +196,7 @@ intel_overlay_map_regs(struct intel_overlay *overlay) regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr; else regs = io_mapping_map_wc(dev_priv->gtt.mappable, - overlay->reg_bo->gtt_offset); + i915_gem_obj_ggtt_offset(overlay->reg_bo)); return regs; } @@ -740,7 +740,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, swidth = params->src_w; swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width); sheight = params->src_h; - iowrite32(new_bo->gtt_offset + params->offset_Y, ®s->OBUF_0Y); + iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, ®s->OBUF_0Y); ostride = params->stride_Y; if (params->format & I915_OVERLAY_YUV_PLANAR) { @@ -754,8 +754,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, params->src_w/uv_hscale); swidthsw |= max_t(u32, tmp_U, tmp_V) << 16; sheight |= (params->src_h/uv_vscale) << 16; - iowrite32(new_bo->gtt_offset + params->offset_U, ®s->OBUF_0U); - iowrite32(new_bo->gtt_offset + params->offset_V, ®s->OBUF_0V); + iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, ®s->OBUF_0U); + iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, ®s->OBUF_0V); ostride |= params->stride_UV << 16; } @@ -1355,7 +1355,7 @@ void intel_setup_overlay(struct drm_device *dev) DRM_ERROR("failed to pin overlay register bo\n"); goto out_free_bo; } - overlay->flip_addr = reg_bo->gtt_offset; + overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo); ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); if (ret) { @@ -1435,7 +1435,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay) overlay->reg_bo->phys_obj->handle->vaddr; else regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, - overlay->reg_bo->gtt_offset); + i915_gem_obj_ggtt_offset(overlay->reg_bo)); return regs; } @@ -1468,7 +1468,7 @@ intel_overlay_capture_error_state(struct drm_device *dev) if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) error->base = (__force long)overlay->reg_bo->phys_obj->handle->vaddr; else - error->base = overlay->reg_bo->gtt_offset; + error->base = i915_gem_obj_ggtt_offset(overlay->reg_bo); regs = intel_overlay_map_regs_atomic(overlay); if (!regs) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0eed35da3ea5..125a741eed86 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -218,7 +218,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); - I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); + I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); @@ -275,7 +275,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset); + I915_WRITE(IVB_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj)); I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X | IVB_DPFC_CTL_FENCE_EN | @@ -3700,7 +3700,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); intel_ring_emit(ring, MI_SET_CONTEXT); - intel_ring_emit(ring, dev_priv->ips.renderctx->gtt_offset | + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(dev_priv->ips.renderctx) | MI_MM_SPACE_GTT | MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN | @@ -3723,7 +3723,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) return; } - I915_WRITE(PWRCTXA, dev_priv->ips.pwrctx->gtt_offset | PWRCTX_EN); + I915_WRITE(PWRCTXA, i915_gem_obj_ggtt_offset(dev_priv->ips.pwrctx) | PWRCTX_EN); I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e51ab552046c..54495df2403e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -424,14 +424,14 @@ static int init_ring_common(struct intel_ring_buffer *ring) * registers with the above sequence (the readback of the HEAD registers * also enforces ordering), otherwise the hw might lose the new ring * register values. */ - I915_WRITE_START(ring, obj->gtt_offset); + I915_WRITE_START(ring, i915_gem_obj_ggtt_offset(obj)); I915_WRITE_CTL(ring, ((ring->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID); /* If the head is still not zero, the ring is dead */ if (wait_for((I915_READ_CTL(ring) & RING_VALID) != 0 && - I915_READ_START(ring) == obj->gtt_offset && + I915_READ_START(ring) == i915_gem_obj_ggtt_offset(obj) && (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) { DRM_ERROR("%s initialization failed " "ctl %08x head %08x tail %08x start %08x\n", @@ -489,7 +489,7 @@ init_pipe_control(struct intel_ring_buffer *ring) if (ret) goto err_unref; - pc->gtt_offset = obj->gtt_offset; + pc->gtt_offset = i915_gem_obj_ggtt_offset(obj); pc->cpu_page = kmap(sg_page(obj->pages->sgl)); if (pc->cpu_page == NULL) { ret = -ENOMEM; @@ -1129,7 +1129,7 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring, intel_ring_advance(ring); } else { struct drm_i915_gem_object *obj = ring->private; - u32 cs_offset = obj->gtt_offset; + u32 cs_offset = i915_gem_obj_ggtt_offset(obj); if (len > I830_BATCH_LIMIT) return -ENOSPC; @@ -1214,7 +1214,7 @@ static int init_status_page(struct intel_ring_buffer *ring) goto err_unref; } - ring->status_page.gfx_addr = obj->gtt_offset; + ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj); ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl)); if (ring->status_page.page_addr == NULL) { ret = -ENOMEM; @@ -1308,7 +1308,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, goto err_unpin; ring->virtual_start = - ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset, + ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), ring->size); if (ring->virtual_start == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 1fa5612a4572..55bdf70b548b 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -133,7 +133,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb, I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); I915_WRITE(SPCNTR(pipe, plane), sprctl); - I915_MODIFY_DISPBASE(SPSURF(pipe, plane), obj->gtt_offset + + I915_MODIFY_DISPBASE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); POSTING_READ(SPSURF(pipe, plane)); } @@ -308,7 +308,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, if (intel_plane->can_scale) I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); - I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset); + I915_MODIFY_DISPBASE(SPRSURF(pipe), + i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); /* potentially re-enable LP watermarks */ @@ -478,7 +479,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); - I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset + dvssurf_offset); + I915_MODIFY_DISPBASE(DVSSURF(pipe), + i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); POSTING_READ(DVSSURF(pipe)); } From edd41a870f11157a1bf4c15080421f9770912e09 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Jul 2013 14:41:05 -0700 Subject: [PATCH 0112/6183] drm/i915: Kill obj->gtt_offset With the getters in place from the previous patch this members serves no purpose other than saving one spare pointer chase, which will be killed in the next patch anyway. Moving to VMAs, this members adds unnecessary confusion since an object may exist at different offsets in different VMs. v2: Properly preserve the stolen offset. This code is a bit hacky but it all goes away when we embed the drm_mm_node and removes the need for the incorrect patch I submitted previously: "Use gtt_space->start for stolen reservation" Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 9 +-------- drivers/gpu/drm/i915/i915_gem.c | 2 -- drivers/gpu/drm/i915/i915_gem_gtt.c | 14 ++++++++------ drivers/gpu/drm/i915/i915_gem_stolen.c | 9 ++++++--- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8a92174109c2..7b8fbba4c6e7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1201,7 +1201,7 @@ enum hdmi_force_audio { HDMI_AUDIO_ON, /* force turn on HDMI audio */ }; -#define I915_GTT_RESERVED ((struct drm_mm_node *)0x1) +#define I915_GTT_RESERVED (1<<0) #define I915_GTT_OFFSET_NONE ((u32)-1) struct drm_i915_gem_object_ops { @@ -1329,13 +1329,6 @@ struct drm_i915_gem_object { unsigned long exec_handle; struct drm_i915_gem_exec_object2 *exec_entry; - /** - * Current offset of the object in GTT space. - * - * This is the same as gtt_space->start - */ - uint32_t gtt_offset; - struct intel_ring_buffer *ring; /** Breadcrumb of last rendering to the buffer. */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b8a0d91f2e2d..3ea54c8eec24 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2634,7 +2634,6 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) drm_mm_put_block(obj->gtt_space); obj->gtt_space = NULL; - obj->gtt_offset = 0; return 0; } @@ -3164,7 +3163,6 @@ search_free: list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); obj->gtt_space = node; - obj->gtt_offset = node->start; fenceable = node->size == fence_size && diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6f0a4c09e26a..76a4095452c7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -629,18 +629,20 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, /* Mark any preallocated objects as occupied */ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { + uintptr_t offset = (uintptr_t) obj->gtt_space; int ret; - DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n", - obj->gtt_offset, obj->base.size); + DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n", + offset, obj->base.size); - BUG_ON(obj->gtt_space != I915_GTT_RESERVED); + BUG_ON((offset & I915_GTT_RESERVED) != 0); + offset &= ~I915_GTT_RESERVED; obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); if (!obj->gtt_space) { - DRM_ERROR("Failed to preserve object at offset %x\n", - obj->gtt_offset); + DRM_ERROR("Failed to preserve object at offset %lx\n", + offset); continue; } - obj->gtt_space->start = obj->gtt_offset; + obj->gtt_space->start = (unsigned long)offset; obj->gtt_space->size = obj->base.size; ret = drm_mm_reserve_node(&dev_priv->mm.gtt_space, obj->gtt_space); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 4e6dbbb47dfe..559f75450d35 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -389,10 +389,13 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); goto free_out; } - } else - obj->gtt_space = I915_GTT_RESERVED; + } else { + if (WARN_ON(gtt_offset & ~PAGE_MASK)) + DRM_DEBUG_KMS("Cannot preserve non page aligned offset\n"); + obj->gtt_space = + (struct drm_mm_node *)((uintptr_t)(I915_GTT_RESERVED | gtt_offset)); + } - obj->gtt_offset = gtt_offset; obj->has_global_gtt_mapping = 1; list_add_tail(&obj->global_list, &dev_priv->mm.bound_list); From c6cfb325677ea6305fb19acf3a4d14ea267f923e Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Jul 2013 14:41:06 -0700 Subject: [PATCH 0113/6183] drm/i915: Embed drm_mm_node in i915 gem obj Embedding the node in the obj is more natural in the transition to VMAs which will also have embedded nodes. This change also helps transition away from put_block to remove node. Though it's quite an uncommon occurrence, it's somewhat convenient to not fail at bind time because we cannot allocate the node. Though in practice there are other allocations (like the request structure) which would probably make this point not terribly useful. Quoting Daniel: Note that the only difference between put_block and remove_node is that the former fills up the preallocation cache. Which we don't need anyway and hence is just wasted space. v2: Clean up the stolen preallocation code. Rebased on the reserve_node patches renames ggtt_ stuff to gtt_ stuff WARN_ON if the object is already bound (which doesn't mean it's in the bound list, tricky) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 11 +++++---- drivers/gpu/drm/i915/i915_gem.c | 31 +++++++++----------------- drivers/gpu/drm/i915/i915_gem_evict.c | 6 ++--- drivers/gpu/drm/i915/i915_gem_gtt.c | 21 ++++------------- drivers/gpu/drm/i915/i915_gem_stolen.c | 22 ++++-------------- 5 files changed, 27 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7b8fbba4c6e7..993fd2c8a457 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1201,7 +1201,6 @@ enum hdmi_force_audio { HDMI_AUDIO_ON, /* force turn on HDMI audio */ }; -#define I915_GTT_RESERVED (1<<0) #define I915_GTT_OFFSET_NONE ((u32)-1) struct drm_i915_gem_object_ops { @@ -1228,7 +1227,7 @@ struct drm_i915_gem_object { const struct drm_i915_gem_object_ops *ops; /** Current space allocated to this object in the GTT, if any. */ - struct drm_mm_node *gtt_space; + struct drm_mm_node gtt_space; /** Stolen memory for this object, instead of being backed by shmem. */ struct drm_mm_node *stolen; struct list_head global_list; @@ -1358,14 +1357,14 @@ struct drm_i915_gem_object { static inline unsigned long i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o) { - return o->gtt_space->start; + return o->gtt_space.start; } /* Whether or not this object is currently mapped by the translation tables */ static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *o) { - return o->gtt_space != NULL; + return drm_mm_node_allocated(&o->gtt_space); } /* The size used in the translation tables may be larger than the actual size of @@ -1375,14 +1374,14 @@ i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *o) static inline unsigned long i915_gem_obj_ggtt_size(struct drm_i915_gem_object *o) { - return o->gtt_space->size; + return o->gtt_space.size; } static inline void i915_gem_obj_ggtt_set_color(struct drm_i915_gem_object *o, enum i915_cache_level color) { - o->gtt_space->color = color; + o->gtt_space.color = color; } /** diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3ea54c8eec24..339404937ab9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2632,8 +2632,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) /* Avoid an unnecessary call to unbind on rebind. */ obj->map_and_fenceable = true; - drm_mm_put_block(obj->gtt_space); - obj->gtt_space = NULL; + drm_mm_remove_node(&obj->gtt_space); return 0; } @@ -3011,7 +3010,7 @@ static bool i915_gem_valid_gtt_space(struct drm_device *dev, if (HAS_LLC(dev)) return true; - if (gtt_space == NULL) + if (!drm_mm_node_allocated(gtt_space)) return true; if (list_empty(>t_space->node_list)) @@ -3079,7 +3078,6 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_mm_node *node; u32 size, fence_size, fence_alignment, unfenced_alignment; bool mappable, fenceable; size_t gtt_max = map_and_fenceable ? @@ -3124,14 +3122,9 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, i915_gem_object_pin_pages(obj); - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (node == NULL) { - i915_gem_object_unpin_pages(obj); - return -ENOMEM; - } - search_free: - ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, + ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, + &obj->gtt_space, size, alignment, obj->cache_level, 0, gtt_max); if (ret) { @@ -3143,30 +3136,28 @@ search_free: goto search_free; i915_gem_object_unpin_pages(obj); - kfree(node); return ret; } - if (WARN_ON(!i915_gem_valid_gtt_space(dev, node, obj->cache_level))) { + if (WARN_ON(!i915_gem_valid_gtt_space(dev, &obj->gtt_space, + obj->cache_level))) { i915_gem_object_unpin_pages(obj); - drm_mm_put_block(node); + drm_mm_remove_node(&obj->gtt_space); return -EINVAL; } ret = i915_gem_gtt_prepare_object(obj); if (ret) { i915_gem_object_unpin_pages(obj); - drm_mm_put_block(node); + drm_mm_remove_node(&obj->gtt_space); return ret; } list_move_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - obj->gtt_space = node; - fenceable = - node->size == fence_size && - (node->start & (fence_alignment - 1)) == 0; + i915_gem_obj_ggtt_size(obj) == fence_size && + (i915_gem_obj_ggtt_offset(obj) & (fence_alignment - 1)) == 0; mappable = i915_gem_obj_ggtt_offset(obj) + obj->base.size <= dev_priv->gtt.mappable_end; @@ -3330,7 +3321,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return -EBUSY; } - if (!i915_gem_valid_gtt_space(dev, obj->gtt_space, cache_level)) { + if (!i915_gem_valid_gtt_space(dev, &obj->gtt_space, cache_level)) { ret = i915_gem_object_unbind(obj); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index c86d5d9356fd..5f8afc48bb7e 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -38,7 +38,7 @@ mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) return false; list_add(&obj->exec_list, unwind); - return drm_mm_scan_add_block(obj->gtt_space); + return drm_mm_scan_add_block(&obj->gtt_space); } int @@ -107,7 +107,7 @@ none: struct drm_i915_gem_object, exec_list); - ret = drm_mm_scan_remove_block(obj->gtt_space); + ret = drm_mm_scan_remove_block(&obj->gtt_space); BUG_ON(ret); list_del_init(&obj->exec_list); @@ -127,7 +127,7 @@ found: obj = list_first_entry(&unwind_list, struct drm_i915_gem_object, exec_list); - if (drm_mm_scan_remove_block(obj->gtt_space)) { + if (drm_mm_scan_remove_block(&obj->gtt_space)) { list_move(&obj->exec_list, &eviction_list); drm_gem_object_reference(&obj->base); continue; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 76a4095452c7..242d0f9bb9e4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -629,28 +629,15 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, /* Mark any preallocated objects as occupied */ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - uintptr_t offset = (uintptr_t) obj->gtt_space; int ret; DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n", - offset, obj->base.size); + i915_gem_obj_ggtt_offset(obj), obj->base.size); - BUG_ON((offset & I915_GTT_RESERVED) != 0); - offset &= ~I915_GTT_RESERVED; - obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); - if (!obj->gtt_space) { - DRM_ERROR("Failed to preserve object at offset %lx\n", - offset); - continue; - } - obj->gtt_space->start = (unsigned long)offset; - obj->gtt_space->size = obj->base.size; + WARN_ON(i915_gem_obj_ggtt_bound(obj)); ret = drm_mm_reserve_node(&dev_priv->mm.gtt_space, - obj->gtt_space); - if (ret) { + &obj->gtt_space); + if (ret) DRM_DEBUG_KMS("Reservation failed\n"); - kfree(obj->gtt_space); - obj->gtt_space = NULL; - } obj->has_global_gtt_mapping = 1; } diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 559f75450d35..08dd923c87d8 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -374,26 +374,15 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, * setting up the GTT space. The actual reservation will occur * later. */ + obj->gtt_space.start = gtt_offset; + obj->gtt_space.size = size; if (drm_mm_initialized(&dev_priv->mm.gtt_space)) { - obj->gtt_space = kzalloc(sizeof(*obj->gtt_space), GFP_KERNEL); - if (!obj->gtt_space) { - DRM_DEBUG_KMS("-ENOMEM stolen GTT space\n"); - goto unref_out; - } - - obj->gtt_space->start = gtt_offset; - obj->gtt_space->size = size; ret = drm_mm_reserve_node(&dev_priv->mm.gtt_space, - obj->gtt_space); + &obj->gtt_space); if (ret) { DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); - goto free_out; + goto unref_out; } - } else { - if (WARN_ON(gtt_offset & ~PAGE_MASK)) - DRM_DEBUG_KMS("Cannot preserve non page aligned offset\n"); - obj->gtt_space = - (struct drm_mm_node *)((uintptr_t)(I915_GTT_RESERVED | gtt_offset)); } obj->has_global_gtt_mapping = 1; @@ -403,9 +392,6 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, return obj; -free_out: - kfree(obj->gtt_space); - obj->gtt_space = NULL; unref_out: drm_gem_object_unreference(&obj->base); return NULL; From 4a33e48d0e121953342194b45d33dc752353d62b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 6 Jul 2013 12:52:05 +0200 Subject: [PATCH 0114/6183] drm/i915: fix dvo DPLL regression I've missed that intel_dvo_mode_set changes the dpll configuration. Hence when I've reworked the sequence to only enable the dpll in the crtc_enable callback in commit 66e3d5c09940d08d94b03e65b420fadaa7484318 Author: Daniel Vetter Date: Sun Jun 16 21:24:16 2013 +0200 drm/i915: move i9xx dpll enabling into crtc enable function that special DVO bit was lost. Some BSpec reading confirms that it's only needed for DVO encoders. Section 1.5.4, "DPLL A Control Register" for bit 30: "2X Clock Enable. When driving In non-gang DVO modes such as a connected flat panel or TV, a 2X" version of the clock is needed. When not using the 2X output it should be disabled. This bit cannot be set when driving the integrated LVDS port on devices such as Montara-GM." Fix this regression up. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66516 Cc: Chris Wilson Reported-by: Chris Wilson Reviewed-by: Chris Wilson Partially-tested-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_display.c | 11 +++++++---- drivers/gpu/drm/i915/intel_dvo.c | 3 --- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9b51be800961..e9c50fab94af 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1126,7 +1126,8 @@ #define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) #define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) -#define DPLL_DVO_HIGH_SPEED (1 << 30) +#define DPLL_SDVO_HIGH_SPEED (1 << 30) +#define DPLL_DVO_2X_MODE (1 << 30) #define DPLL_EXT_BUFFER_ENABLE_VLV (1 << 30) #define DPLL_SYNCLOCK_ENABLE (1 << 29) #define DPLL_REFA_CLK_ENABLE_VLV (1 << 29) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a45bb92f35ad..41efd3519e35 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4544,10 +4544,10 @@ static void i9xx_update_pll(struct intel_crtc *crtc, } if (is_sdvo) - dpll |= DPLL_DVO_HIGH_SPEED; + dpll |= DPLL_SDVO_HIGH_SPEED; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) - dpll |= DPLL_DVO_HIGH_SPEED; + dpll |= DPLL_SDVO_HIGH_SPEED; /* compute bitmask from p1 value */ if (IS_PINEVIEW(dev)) @@ -4619,6 +4619,9 @@ static void i8xx_update_pll(struct intel_crtc *crtc, dpll |= PLL_P2_DIVIDE_BY_4; } + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DVO)) + dpll |= DPLL_DVO_2X_MODE; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; @@ -5650,9 +5653,9 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; if (is_sdvo) - dpll |= DPLL_DVO_HIGH_SPEED; + dpll |= DPLL_SDVO_HIGH_SPEED; if (intel_crtc->config.has_dp_encoder) - dpll |= DPLL_DVO_HIGH_SPEED; + dpll |= DPLL_SDVO_HIGH_SPEED; /* compute bitmask from p1 value */ dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index eb2020eb2b7e..cbbc49dc03be 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -283,7 +283,6 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, int pipe = intel_crtc->pipe; u32 dvo_val; u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg; - int dpll_reg = DPLL(pipe); switch (dvo_reg) { case DVOA: @@ -314,8 +313,6 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) dvo_val |= DVO_VSYNC_ACTIVE_HIGH; - I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); - /*I915_WRITE(DVOB_SRCDIM, (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ From 5d536e2858ead64ea945552ec6a491f968c55888 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 6 Jul 2013 12:52:06 +0200 Subject: [PATCH 0115/6183] drm/i915: dvo needs a P2 divisor of 4 Section 1.5.4, "DPLL A Control Register" from Bspec about bit 23 "FPA0/A1 P2 Clock Divide": 0 = Divide by 2 1 = Divide by 4. This bit must be set in DVO non-gang mode So copy the current limits (which should be good for i8xx) and create a new set for dvo encoders. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 41efd3519e35..01939513b8c2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -89,7 +89,7 @@ intel_fdi_link_freq(struct drm_device *dev) return 27; } -static const intel_limit_t intel_limits_i8xx_dvo = { +static const intel_limit_t intel_limits_i8xx_dac = { .dot = { .min = 25000, .max = 350000 }, .vco = { .min = 930000, .max = 1400000 }, .n = { .min = 3, .max = 16 }, @@ -102,6 +102,19 @@ static const intel_limit_t intel_limits_i8xx_dvo = { .p2_slow = 4, .p2_fast = 2 }, }; +static const intel_limit_t intel_limits_i8xx_dvo = { + .dot = { .min = 25000, .max = 350000 }, + .vco = { .min = 930000, .max = 1400000 }, + .n = { .min = 3, .max = 16 }, + .m = { .min = 96, .max = 140 }, + .m1 = { .min = 18, .max = 26 }, + .m2 = { .min = 6, .max = 16 }, + .p = { .min = 4, .max = 128 }, + .p1 = { .min = 2, .max = 33 }, + .p2 = { .dot_limit = 165000, + .p2_slow = 4, .p2_fast = 4 }, +}; + static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = 25000, .max = 350000 }, .vco = { .min = 930000, .max = 1400000 }, @@ -410,8 +423,10 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int refclk) } else { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits_i8xx_lvds; - else + else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO)) limit = &intel_limits_i8xx_dvo; + else + limit = &intel_limits_i8xx_dac; } return limit; } From 34b9674c786c73e5472e8b98a729bcdde9197859 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 20:49:44 +0200 Subject: [PATCH 0116/6183] drm/i915: convert debugfs creation/destruction to table At least for the common cases where we only need special file operations. The forcewake file is still rather more special. v2: Fix up the debugfs unregister code. v3: Actually squash in the right fixup. Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 94 +++++++++-------------------- 1 file changed, 30 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 396387ed207a..d4138124d993 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2375,61 +2375,35 @@ static struct drm_info_list i915_debugfs_list[] = { }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) +struct i915_debugfs_files { + const char *name; + const struct file_operations *fops; +} i915_debugfs_files[] = { + {"i915_wedged", &i915_wedged_fops}, + {"i915_max_freq", &i915_max_freq_fops}, + {"i915_min_freq", &i915_min_freq_fops}, + {"i915_cache_sharing", &i915_cache_sharing_fops}, + {"i915_ring_stop", &i915_ring_stop_fops}, + {"i915_gem_drop_caches", &i915_drop_caches_fops}, + {"i915_error_state", &i915_error_state_fops}, + {"i915_next_seqno", &i915_next_seqno_fops}, +}; + int i915_debugfs_init(struct drm_minor *minor) { - int ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_wedged", - &i915_wedged_fops); - if (ret) - return ret; + int ret, i; ret = i915_forcewake_create(minor->debugfs_root, minor); if (ret) return ret; - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_max_freq", - &i915_max_freq_fops); - if (ret) - return ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_min_freq", - &i915_min_freq_fops); - if (ret) - return ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_cache_sharing", - &i915_cache_sharing_fops); - if (ret) - return ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_ring_stop", - &i915_ring_stop_fops); - if (ret) - return ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_gem_drop_caches", - &i915_drop_caches_fops); - if (ret) - return ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_error_state", - &i915_error_state_fops); - if (ret) - return ret; - - ret = i915_debugfs_create(minor->debugfs_root, minor, - "i915_next_seqno", - &i915_next_seqno_fops); - if (ret) - return ret; + for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) { + ret = i915_debugfs_create(minor->debugfs_root, minor, + i915_debugfs_files[i].name, + i915_debugfs_files[i].fops); + if (ret) + return ret; + } return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, @@ -2438,26 +2412,18 @@ int i915_debugfs_init(struct drm_minor *minor) void i915_debugfs_cleanup(struct drm_minor *minor) { + int i; + drm_debugfs_remove_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops, 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_min_freq_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_drop_caches_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_error_state_fops, - 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_next_seqno_fops, - 1, minor); + for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) { + struct drm_info_list *info_list = + (struct drm_info_list *) i915_debugfs_files[i].fops; + + drm_debugfs_remove_files(info_list, 1, minor); + } } #endif /* CONFIG_DEBUG_FS */ From ab3da15643469ab2d206dee3d9cfa4194ba77f25 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 24 May 2013 16:23:28 +0200 Subject: [PATCH 0117/6183] ARM: be strict about FP exceptions in kernel mode The support code in vfp_support_entry does not care whether the exception that caused it to be invoked occurred in kernel mode or in user mode. However, neither condition that could trigger this exception (lazy restore and VFP bounce to support code) is currently allowable in kernel mode. In either case, print a message describing the condition before letting the undefined instruction handler run its course and trigger an oops. Signed-off-by: Ard Biesheuvel Acked-by: Nicolas Pitre --- arch/arm/vfp/vfphw.S | 5 +++++ arch/arm/vfp/vfpmodule.c | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 8d10dc8a1e17..3e5d3115a2a6 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -78,6 +78,11 @@ ENTRY(vfp_support_entry) DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 + ldr r3, [sp, #S_PSR] @ Neither lazy restore nor FP exceptions + and r3, r3, #MODE_MASK @ are supported in kernel mode + teq r3, #USR_MODE + bne vfp_kmode_exception @ Returns through lr + VFPFMRX r1, FPEXC @ Is the VFP enabled? DBGSTR1 "fpexc %08x", r1 tst r1, #FPEXC_EN diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 791993aed75a..7620831a0c66 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -648,6 +648,26 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action, return NOTIFY_OK; } +void vfp_kmode_exception(void) +{ + /* + * If we reach this point, a floating point exception has been raised + * while running in kernel mode. If the NEON/VFP unit was enabled at the + * time, it means a VFP instruction has been issued that requires + * software assistance to complete, something which is not currently + * supported in kernel mode. + * If the NEON/VFP unit was disabled, and the location pointed to below + * is properly preceded by a call to kernel_neon_begin(), something has + * caused the task to be scheduled out and back in again. In this case, + * rebuilding and running with CONFIG_DEBUG_ATOMIC_SLEEP enabled should + * be helpful in localizing the problem. + */ + if (fmrx(FPEXC) & FPEXC_EN) + pr_crit("BUG: unsupported FP instruction in kernel mode\n"); + else + pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n"); +} + /* * VFP support code initialisation. */ From 73c132c15da504789b924871e2491479a18e4f6a Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 16 May 2013 11:41:48 +0200 Subject: [PATCH 0118/6183] ARM: add support for kernel mode NEON In order to safely support the use of NEON instructions in kernel mode, some precautions need to be taken: - the userland context that may be present in the registers (even if the NEON/VFP is currently disabled) must be stored under the correct task (which may not be 'current' in the UP case), - to avoid having to keep track of additional vfpstates for the kernel side, disallow the use of NEON in interrupt context and run with preemption disabled, - after use, re-enable preemption and re-enable the lazy restore machinery by disabling the NEON/VFP unit. This patch adds the functions kernel_neon_begin() and kernel_neon_end() which take care of the above. It also adds the Kconfig symbol KERNEL_MODE_NEON to enable it. Signed-off-by: Ard Biesheuvel Acked-by: Nicolas Pitre --- arch/arm/Kconfig | 7 ++++++ arch/arm/include/asm/neon.h | 36 ++++++++++++++++++++++++++++ arch/arm/vfp/vfpmodule.c | 47 +++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 arch/arm/include/asm/neon.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 136f263ed47b..d6068b435151 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2197,6 +2197,13 @@ config NEON Say Y to include support code for NEON, the ARMv7 Advanced SIMD Extension. +config KERNEL_MODE_NEON + bool "Support for NEON in kernel mode" + default n + depends on NEON + help + Say Y to include support for NEON in kernel mode. + endmenu menu "Userspace binary formats" diff --git a/arch/arm/include/asm/neon.h b/arch/arm/include/asm/neon.h new file mode 100644 index 000000000000..8f730fe70093 --- /dev/null +++ b/arch/arm/include/asm/neon.h @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/include/asm/neon.h + * + * Copyright (C) 2013 Linaro Ltd + * + * 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 + +#define cpu_has_neon() (!!(elf_hwcap & HWCAP_NEON)) + +#ifdef __ARM_NEON__ + +/* + * If you are affected by the BUILD_BUG below, it probably means that you are + * using NEON code /and/ calling the kernel_neon_begin() function from the same + * compilation unit. To prevent issues that may arise from GCC reordering or + * generating(1) NEON instructions outside of these begin/end functions, the + * only supported way of using NEON code in the kernel is by isolating it in a + * separate compilation unit, and calling it from another unit from inside a + * kernel_neon_begin/kernel_neon_end pair. + * + * (1) Current GCC (4.7) might generate NEON instructions at O3 level if + * -mpfu=neon is set. + */ + +#define kernel_neon_begin() \ + BUILD_BUG_ON_MSG(1, "kernel_neon_begin() called from NEON code") + +#else +void kernel_neon_begin(void); +#endif +void kernel_neon_end(void); diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 7620831a0c66..52b8f40b1c73 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -668,6 +669,52 @@ void vfp_kmode_exception(void) pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n"); } +#ifdef CONFIG_KERNEL_MODE_NEON + +/* + * Kernel-side NEON support functions + */ +void kernel_neon_begin(void) +{ + struct thread_info *thread = current_thread_info(); + unsigned int cpu; + u32 fpexc; + + /* + * Kernel mode NEON is only allowed outside of interrupt context + * with preemption disabled. This will make sure that the kernel + * mode NEON register contents never need to be preserved. + */ + BUG_ON(in_interrupt()); + cpu = get_cpu(); + + fpexc = fmrx(FPEXC) | FPEXC_EN; + fmxr(FPEXC, fpexc); + + /* + * Save the userland NEON/VFP state. Under UP, + * the owner could be a task other than 'current' + */ + if (vfp_state_in_hw(cpu, thread)) + vfp_save_state(&thread->vfpstate, fpexc); +#ifndef CONFIG_SMP + else if (vfp_current_hw_state[cpu] != NULL) + vfp_save_state(vfp_current_hw_state[cpu], fpexc); +#endif + vfp_current_hw_state[cpu] = NULL; +} +EXPORT_SYMBOL(kernel_neon_begin); + +void kernel_neon_end(void) +{ + /* Disable the NEON/VFP unit. */ + fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); + put_cpu(); +} +EXPORT_SYMBOL(kernel_neon_end); + +#endif /* CONFIG_KERNEL_MODE_NEON */ + /* * VFP support code initialisation. */ From 01956597cbc46df072f20f90a40eebe356200c38 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 17 May 2013 18:51:23 +0200 Subject: [PATCH 0119/6183] ARM: crypto: add NEON accelerated XOR implementation Add a source file xor-neon.c (which is really just the reference C implementation passed through the GCC vectorizer) and hook it up to the XOR framework. Signed-off-by: Ard Biesheuvel Acked-by: Nicolas Pitre --- arch/arm/include/asm/xor.h | 73 ++++++++++++++++++++++++++++++++++++++ arch/arm/lib/Makefile | 6 ++++ arch/arm/lib/xor-neon.c | 42 ++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 arch/arm/lib/xor-neon.c diff --git a/arch/arm/include/asm/xor.h b/arch/arm/include/asm/xor.h index 7604673dc427..4ffb26d4cad8 100644 --- a/arch/arm/include/asm/xor.h +++ b/arch/arm/include/asm/xor.h @@ -7,7 +7,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include +#include +#include #define __XOR(a1, a2) a1 ^= a2 @@ -138,4 +141,74 @@ static struct xor_block_template xor_block_arm4regs = { xor_speed(&xor_block_arm4regs); \ xor_speed(&xor_block_8regs); \ xor_speed(&xor_block_32regs); \ + NEON_TEMPLATES; \ } while (0) + +#ifdef CONFIG_KERNEL_MODE_NEON + +extern struct xor_block_template const xor_block_neon_inner; + +static void +xor_neon_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + if (in_interrupt()) { + xor_arm4regs_2(bytes, p1, p2); + } else { + kernel_neon_begin(); + xor_block_neon_inner.do_2(bytes, p1, p2); + kernel_neon_end(); + } +} + +static void +xor_neon_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + if (in_interrupt()) { + xor_arm4regs_3(bytes, p1, p2, p3); + } else { + kernel_neon_begin(); + xor_block_neon_inner.do_3(bytes, p1, p2, p3); + kernel_neon_end(); + } +} + +static void +xor_neon_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + if (in_interrupt()) { + xor_arm4regs_4(bytes, p1, p2, p3, p4); + } else { + kernel_neon_begin(); + xor_block_neon_inner.do_4(bytes, p1, p2, p3, p4); + kernel_neon_end(); + } +} + +static void +xor_neon_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + if (in_interrupt()) { + xor_arm4regs_5(bytes, p1, p2, p3, p4, p5); + } else { + kernel_neon_begin(); + xor_block_neon_inner.do_5(bytes, p1, p2, p3, p4, p5); + kernel_neon_end(); + } +} + +static struct xor_block_template xor_block_neon = { + .name = "neon", + .do_2 = xor_neon_2, + .do_3 = xor_neon_3, + .do_4 = xor_neon_4, + .do_5 = xor_neon_5 +}; + +#define NEON_TEMPLATES \ + do { if (cpu_has_neon()) xor_speed(&xor_block_neon); } while (0) +#else +#define NEON_TEMPLATES +#endif diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index af72969820b4..aaf3a8731136 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -45,3 +45,9 @@ lib-$(CONFIG_ARCH_SHARK) += io-shark.o $(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S $(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S + +ifeq ($(CONFIG_KERNEL_MODE_NEON),y) + NEON_FLAGS := -mfloat-abi=softfp -mfpu=neon + CFLAGS_xor-neon.o += $(NEON_FLAGS) + lib-$(CONFIG_XOR_BLOCKS) += xor-neon.o +endif diff --git a/arch/arm/lib/xor-neon.c b/arch/arm/lib/xor-neon.c new file mode 100644 index 000000000000..f485e5a2af4b --- /dev/null +++ b/arch/arm/lib/xor-neon.c @@ -0,0 +1,42 @@ +/* + * linux/arch/arm/lib/xor-neon.c + * + * Copyright (C) 2013 Linaro Ltd + * + * 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 + +#ifndef __ARM_NEON__ +#error You should compile this file with '-mfloat-abi=softfp -mfpu=neon' +#endif + +/* + * Pull in the reference implementations while instructing GCC (through + * -ftree-vectorize) to attempt to exploit implicit parallelism and emit + * NEON instructions. + */ +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC optimize "tree-vectorize" +#else +/* + * While older versions of GCC do not generate incorrect code, they fail to + * recognize the parallel nature of these functions, and emit plain ARM code, + * which is known to be slower than the optimized ARM code in asm-arm/xor.h. + */ +#warning This code requires at least version 4.6 of GCC +#endif + +#pragma GCC diagnostic ignored "-Wunused-variable" +#include + +struct xor_block_template const xor_block_neon_inner = { + .name = "__inner_neon__", + .do_2 = xor_8regs_2, + .do_3 = xor_8regs_3, + .do_4 = xor_8regs_4, + .do_5 = xor_8regs_5, +}; From 7d11965ddb9b9b1e0a5d13c58345ada1ccbc663b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 16 May 2013 17:20:32 +0200 Subject: [PATCH 0120/6183] lib/raid6: add ARM-NEON accelerated syndrome calculation Rebased/reworked a patch contributed by Rob Herring that uses NEON intrinsics to perform the RAID-6 syndrome calculations. It uses the existing unroll.awk code to generate several unrolled versions of which the best performing one is selected at boot time. Signed-off-by: Ard Biesheuvel Acked-by: Nicolas Pitre Cc: hpa@linux.intel.com --- include/linux/raid/pq.h | 5 +++ lib/raid6/.gitignore | 1 + lib/raid6/Makefile | 40 +++++++++++++++++++++ lib/raid6/algos.c | 6 ++++ lib/raid6/neon.c | 58 ++++++++++++++++++++++++++++++ lib/raid6/neon.uc | 80 +++++++++++++++++++++++++++++++++++++++++ lib/raid6/test/Makefile | 26 +++++++++++++- 7 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 lib/raid6/neon.c create mode 100644 lib/raid6/neon.uc diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h index 8dfaa2ce2e95..0f424698064f 100644 --- a/include/linux/raid/pq.h +++ b/include/linux/raid/pq.h @@ -114,6 +114,11 @@ extern const struct raid6_recov_calls raid6_recov_intx1; extern const struct raid6_recov_calls raid6_recov_ssse3; extern const struct raid6_recov_calls raid6_recov_avx2; +extern const struct raid6_calls raid6_neonx1; +extern const struct raid6_calls raid6_neonx2; +extern const struct raid6_calls raid6_neonx4; +extern const struct raid6_calls raid6_neonx8; + /* Algorithm list */ extern const struct raid6_calls * const raid6_algos[]; extern const struct raid6_recov_calls *const raid6_recov_algos[]; diff --git a/lib/raid6/.gitignore b/lib/raid6/.gitignore index 162becacf97c..0a7e494b2bcd 100644 --- a/lib/raid6/.gitignore +++ b/lib/raid6/.gitignore @@ -2,3 +2,4 @@ mktables altivec*.c int*.c tables.c +neon?.c diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile index 9f7c184725d7..b4625787c7ee 100644 --- a/lib/raid6/Makefile +++ b/lib/raid6/Makefile @@ -5,6 +5,7 @@ raid6_pq-y += algos.o recov.o tables.o int1.o int2.o int4.o \ raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o +raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o hostprogs-y += mktables @@ -16,6 +17,21 @@ ifeq ($(CONFIG_ALTIVEC),y) altivec_flags := -maltivec -mabi=altivec endif +# The GCC option -ffreestanding is required in order to compile code containing +# ARM/NEON intrinsics in a non C99-compliant environment (such as the kernel) +ifeq ($(CONFIG_KERNEL_MODE_NEON),y) +NEON_FLAGS := -ffreestanding +ifeq ($(ARCH),arm) +NEON_FLAGS += -mfloat-abi=softfp -mfpu=neon +endif +ifeq ($(ARCH),arm64) +CFLAGS_REMOVE_neon1.o += -mgeneral-regs-only +CFLAGS_REMOVE_neon2.o += -mgeneral-regs-only +CFLAGS_REMOVE_neon4.o += -mgeneral-regs-only +CFLAGS_REMOVE_neon8.o += -mgeneral-regs-only +endif +endif + targets += int1.c $(obj)/int1.c: UNROLL := 1 $(obj)/int1.c: $(src)/int.uc $(src)/unroll.awk FORCE @@ -70,6 +86,30 @@ $(obj)/altivec8.c: UNROLL := 8 $(obj)/altivec8.c: $(src)/altivec.uc $(src)/unroll.awk FORCE $(call if_changed,unroll) +CFLAGS_neon1.o += $(NEON_FLAGS) +targets += neon1.c +$(obj)/neon1.c: UNROLL := 1 +$(obj)/neon1.c: $(src)/neon.uc $(src)/unroll.awk FORCE + $(call if_changed,unroll) + +CFLAGS_neon2.o += $(NEON_FLAGS) +targets += neon2.c +$(obj)/neon2.c: UNROLL := 2 +$(obj)/neon2.c: $(src)/neon.uc $(src)/unroll.awk FORCE + $(call if_changed,unroll) + +CFLAGS_neon4.o += $(NEON_FLAGS) +targets += neon4.c +$(obj)/neon4.c: UNROLL := 4 +$(obj)/neon4.c: $(src)/neon.uc $(src)/unroll.awk FORCE + $(call if_changed,unroll) + +CFLAGS_neon8.o += $(NEON_FLAGS) +targets += neon8.c +$(obj)/neon8.c: UNROLL := 8 +$(obj)/neon8.c: $(src)/neon.uc $(src)/unroll.awk FORCE + $(call if_changed,unroll) + quiet_cmd_mktable = TABLE $@ cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 ) diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c index 6d7316fe9f30..74e6f5629dbc 100644 --- a/lib/raid6/algos.c +++ b/lib/raid6/algos.c @@ -70,6 +70,12 @@ const struct raid6_calls * const raid6_algos[] = { &raid6_intx2, &raid6_intx4, &raid6_intx8, +#ifdef CONFIG_KERNEL_MODE_NEON + &raid6_neonx1, + &raid6_neonx2, + &raid6_neonx4, + &raid6_neonx8, +#endif NULL }; diff --git a/lib/raid6/neon.c b/lib/raid6/neon.c new file mode 100644 index 000000000000..36ad4705df1a --- /dev/null +++ b/lib/raid6/neon.c @@ -0,0 +1,58 @@ +/* + * linux/lib/raid6/neon.c - RAID6 syndrome calculation using ARM NEON intrinsics + * + * Copyright (C) 2013 Linaro Ltd + * + * 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 + +#ifdef __KERNEL__ +#include +#else +#define kernel_neon_begin() +#define kernel_neon_end() +#define cpu_has_neon() (1) +#endif + +/* + * There are 2 reasons these wrappers are kept in a separate compilation unit + * from the actual implementations in neonN.c (generated from neon.uc by + * unroll.awk): + * - the actual implementations use NEON intrinsics, and the GCC support header + * (arm_neon.h) is not fully compatible (type wise) with the kernel; + * - the neonN.c files are compiled with -mfpu=neon and optimization enabled, + * and we have to make sure that we never use *any* NEON/VFP instructions + * outside a kernel_neon_begin()/kernel_neon_end() pair. + */ + +#define RAID6_NEON_WRAPPER(_n) \ + static void raid6_neon ## _n ## _gen_syndrome(int disks, \ + size_t bytes, void **ptrs) \ + { \ + void raid6_neon ## _n ## _gen_syndrome_real(int, \ + unsigned long, void**); \ + kernel_neon_begin(); \ + raid6_neon ## _n ## _gen_syndrome_real(disks, \ + (unsigned long)bytes, ptrs); \ + kernel_neon_end(); \ + } \ + struct raid6_calls const raid6_neonx ## _n = { \ + raid6_neon ## _n ## _gen_syndrome, \ + raid6_have_neon, \ + "neonx" #_n, \ + 0 \ + } + +static int raid6_have_neon(void) +{ + return cpu_has_neon(); +} + +RAID6_NEON_WRAPPER(1); +RAID6_NEON_WRAPPER(2); +RAID6_NEON_WRAPPER(4); +RAID6_NEON_WRAPPER(8); diff --git a/lib/raid6/neon.uc b/lib/raid6/neon.uc new file mode 100644 index 000000000000..1b9ed793342d --- /dev/null +++ b/lib/raid6/neon.uc @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------- + * + * neon.uc - RAID-6 syndrome calculation using ARM NEON instructions + * + * Copyright (C) 2012 Rob Herring + * + * Based on altivec.uc: + * Copyright 2002-2004 H. Peter Anvin - All Rights Reserved + * + * 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, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * neon$#.c + * + * $#-way unrolled NEON intrinsics math RAID-6 instruction set + * + * This file is postprocessed using unroll.awk + */ + +#include + +typedef uint8x16_t unative_t; + +#define NBYTES(x) ((unative_t){x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}) +#define NSIZE sizeof(unative_t) + +/* + * The SHLBYTE() operation shifts each byte left by 1, *not* + * rolling over into the next byte + */ +static inline unative_t SHLBYTE(unative_t v) +{ + return vshlq_n_u8(v, 1); +} + +/* + * The MASK() operation returns 0xFF in any byte for which the high + * bit is 1, 0x00 for any byte for which the high bit is 0. + */ +static inline unative_t MASK(unative_t v) +{ + const uint8x16_t temp = NBYTES(0); + return (unative_t)vcltq_s8((int8x16_t)v, (int8x16_t)temp); +} + +void raid6_neon$#_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) +{ + uint8_t **dptr = (uint8_t **)ptrs; + uint8_t *p, *q; + int d, z, z0; + + register unative_t wd$$, wq$$, wp$$, w1$$, w2$$; + const unative_t x1d = NBYTES(0x1d); + + z0 = disks - 3; /* Highest data disk */ + p = dptr[z0+1]; /* XOR parity */ + q = dptr[z0+2]; /* RS syndrome */ + + for ( d = 0 ; d < bytes ; d += NSIZE*$# ) { + wq$$ = wp$$ = vld1q_u8(&dptr[z0][d+$$*NSIZE]); + for ( z = z0-1 ; z >= 0 ; z-- ) { + wd$$ = vld1q_u8(&dptr[z][d+$$*NSIZE]); + wp$$ = veorq_u8(wp$$, wd$$); + w2$$ = MASK(wq$$); + w1$$ = SHLBYTE(wq$$); + + w2$$ = vandq_u8(w2$$, x1d); + w1$$ = veorq_u8(w1$$, w2$$); + wq$$ = veorq_u8(w1$$, wd$$); + } + vst1q_u8(&p[d+NSIZE*$$], wp$$); + vst1q_u8(&q[d+NSIZE*$$], wq$$); + } +} diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile index 087332dbf8aa..28afa1a06e03 100644 --- a/lib/raid6/test/Makefile +++ b/lib/raid6/test/Makefile @@ -22,11 +22,23 @@ ifeq ($(ARCH),x86_64) IS_X86 = yes endif +ifeq ($(ARCH),arm) + CFLAGS += -I../../../arch/arm/include -mfpu=neon + HAS_NEON = yes +endif +ifeq ($(ARCH),arm64) + CFLAGS += -I../../../arch/arm64/include + HAS_NEON = yes +endif + ifeq ($(IS_X86),yes) OBJS += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" | \ gcc -c -x assembler - >&/dev/null && \ rm ./-.o && echo -DCONFIG_AS_AVX2=1) +else ifeq ($(HAS_NEON),yes) + OBJS += neon.o neon1.o neon2.o neon4.o neon8.o + CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1 else HAS_ALTIVEC := $(shell echo -e '\#include \nvector int a;' |\ gcc -c -x c - >&/dev/null && \ @@ -55,6 +67,18 @@ raid6.a: $(OBJS) raid6test: test.c raid6.a $(CC) $(CFLAGS) -o raid6test $^ +neon1.c: neon.uc ../unroll.awk + $(AWK) ../unroll.awk -vN=1 < neon.uc > $@ + +neon2.c: neon.uc ../unroll.awk + $(AWK) ../unroll.awk -vN=2 < neon.uc > $@ + +neon4.c: neon.uc ../unroll.awk + $(AWK) ../unroll.awk -vN=4 < neon.uc > $@ + +neon8.c: neon.uc ../unroll.awk + $(AWK) ../unroll.awk -vN=8 < neon.uc > $@ + altivec1.c: altivec.uc ../unroll.awk $(AWK) ../unroll.awk -vN=1 < altivec.uc > $@ @@ -89,7 +113,7 @@ tables.c: mktables ./mktables > tables.c clean: - rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c tables.c raid6test + rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c neon*.c tables.c raid6test spotless: clean rm -f *~ From eaba1b8f3379b5d100bd146b9a41d28348bdfd09 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 4 Jul 2013 12:28:35 +0100 Subject: [PATCH 0121/6183] drm/i915: Verify that our stolen memory doesn't conflict Sanity check that the memory region found through the Graphics Base of Stolen Memory is reserved and hidden from the rest of the system through the use of the resource API. v2: "Graphics Stolen Memory" is such a more bodacious name than the lame "i915 stolen", and convert to using devres for automagical cleanup of the resource. (danvet) Signed-off-by: Chris Wilson Cc: Daniel Vetter [danvet: Dump proper hexcodes.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 08dd923c87d8..a3ce2cbb9221 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -46,6 +46,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct pci_dev *pdev = dev_priv->bridge_dev; + struct resource *r; u32 base; /* On the machines I have tested the Graphics Base of Stolen Memory @@ -88,6 +89,22 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) #endif } + if (base == 0) + return 0; + + /* Verify that nothing else uses this physical address. Stolen + * memory should be reserved by the BIOS and hidden from the + * kernel. So if the region is already marked as busy, something + * is seriously wrong. + */ + r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size, + "Graphics Stolen Memory"); + if (r == NULL) { + DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n", + base, base + (uint32_t)dev_priv->gtt.stolen_size); + base = 0; + } + return base; } From 36c0cc616e518bfc2b685bed7fb3243d1242eca4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 9 Jul 2013 14:44:26 +0200 Subject: [PATCH 0122/6183] drm/i915: clean up media reset on gm45 Originally I've thought that this fixes up the reset issues on my gm45, but that was just a red herring due to b0rked testing. Still I much prefer writing the right values (all other fields are reserved) instead of potentially dragging gunk around. Hence also clear the register to 0 after a reset. Note that Cspec is a bit confused and doesn't explicitly say that all the other bits in this register are "reserved, mbz" like usually. Instead they're marked as "r/o, default value = 0" which semantically amounts to the same thing. v2: Stop claiming this fixes anything and return 0 if successful instead of stack garbage. v3: Pimp the commit message to explain exactly why I think the docs allow us to ditch the rmw cycle, spurred by a discussion with Chris. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 33cb97388fc9..ed9262c42b7b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -798,28 +798,29 @@ static int i965_reset_complete(struct drm_device *dev) static int i965_do_reset(struct drm_device *dev) { int ret; - u8 gdrst; /* * Set the domains we want to reset (GRDOM/bits 2 and 3) as * well as the reset bit (GR/bit 0). Setting the GR bit * triggers the reset; when done, the hardware will clear it. */ - pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); pci_write_config_byte(dev->pdev, I965_GDRST, - gdrst | GRDOM_RENDER | - GRDOM_RESET_ENABLE); + GRDOM_RENDER | GRDOM_RESET_ENABLE); ret = wait_for(i965_reset_complete(dev), 500); if (ret) return ret; /* We can't reset render&media without also resetting display ... */ - pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); pci_write_config_byte(dev->pdev, I965_GDRST, - gdrst | GRDOM_MEDIA | - GRDOM_RESET_ENABLE); + GRDOM_MEDIA | GRDOM_RESET_ENABLE); - return wait_for(i965_reset_complete(dev), 500); + ret = wait_for(i965_reset_complete(dev), 500); + if (ret) + return ret; + + pci_write_config_byte(dev->pdev, I965_GDRST, 0); + + return 0; } static int ironlake_do_reset(struct drm_device *dev) From 897f9ed00a906dd3edc69f64d590bba87c45617b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 9 Jul 2013 14:44:27 +0200 Subject: [PATCH 0123/6183] drm/i915: WARN if the bios reserved range is bigger than stolen size v2: Bail out if we hit the WARN_ON to avoid fallout later on. Spotted by Chris Wilson. Suggested-by: Chris Wilson Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index a3ce2cbb9221..76c3b8699168 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -215,6 +215,9 @@ int i915_gem_init_stolen(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) bios_reserved = 1024*1024; /* top 1M on VLV/BYT */ + if (WARN_ON(bios_reserved > dev_priv->gtt.stolen_size)) + return 0; + /* Basic memrange allocator for stolen space */ drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size - bios_reserved); From 885b012008583ba70e5537d479454450f5bdfa09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Jul 2013 19:21:38 +0300 Subject: [PATCH 0124/6183] drm/i915: Fix VLV DP RBR/HDMI/DAC PLL LPF coefficients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I just got confirmation that we're using some old values for the PLL LPF coefficients for DP RBR/HDMI/DAC on VLV. The VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_9 document lists both values by mistake, and apparently we had picked the wrong one. Change the coefficients to the recommended values. Changing the value doesn't appear to destabilize the VGA output picture even with my sensitive HP ZR24w display. Also HDMI output to my TV still works fine. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 01939513b8c2..d2b76b695349 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4465,7 +4465,7 @@ static void vlv_update_pll(struct intel_crtc *crtc) intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe), - 0x005f0021); + 0x009f0003); else vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe), 0x00d0000f); From aa2faec1a05f1ebc2856be911f83e696f8dc2122 Mon Sep 17 00:00:00 2001 From: Vakul Garg Date: Wed, 10 Jul 2013 06:27:21 +0000 Subject: [PATCH 0125/6183] crypto: caam - Moved macro DESC_JOB_IO_LEN to desc_constr.h DESC_JOB_IO_LEN is a generic macro which indicates the space required in the descriptor for placing SEQIN/OUT commands, job descriptor header, shared descriptor pointer. Moving it to descriptor construction file which can be supposedly included by different algo offload files. Change-Id: Ic8900990d465e9079827b0c7fcacc61766d7efb6 Signed-off-by: Vakul Garg Reviewed-by: Geanta Neag Horia Ioan-B05471 Reviewed-by: Fleming Andrew-AFLEMING Tested-by: Fleming Andrew-AFLEMING Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 2 -- drivers/crypto/caam/caamhash.c | 2 -- drivers/crypto/caam/desc_constr.h | 1 + 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index bf416a8391a7..7a9052c44238 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -65,8 +65,6 @@ #define CAAM_MAX_IV_LENGTH 16 /* length of descriptors text */ -#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) - #define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) #define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 16 * CAAM_CMD_SZ) #define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 21 * CAAM_CMD_SZ) diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 5996521a1caf..77ad2b68f8f3 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -72,8 +72,6 @@ #define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE /* length of descriptors text */ -#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) - #define DESC_AHASH_BASE (4 * CAAM_CMD_SZ) #define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ) #define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index fe3bfd1b08ca..cd5f678847ce 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -10,6 +10,7 @@ #define CAAM_CMD_SZ sizeof(u32) #define CAAM_PTR_SZ sizeof(dma_addr_t) #define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE) +#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3) #ifdef DEBUG #define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\ From 5448050124d9d289bc2f5177318c68c0484ca413 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Jul 2013 20:08:25 +1000 Subject: [PATCH 0126/6183] KVM: PPC: Book3S HV: Correct tlbie usage This corrects the usage of the tlbie (TLB invalidate entry) instruction in HV KVM. The tlbie instruction changed between PPC970 and POWER7. On the PPC970, the bit to select large vs. small page is in the instruction, not in the RB register value. This changes the code to use the correct form on PPC970. On POWER7 we were calculating the AVAL (Abbreviated Virtual Address, Lower) field of the RB value incorrectly for 64k pages. This fixes it. Since we now have several cases to handle for the tlbie instruction, this factors out the code to do a sequence of tlbies into a new function, do_tlbies(), and calls that from the various places where the code was doing tlbie instructions inline. It also makes kvmppc_h_bulk_remove() use the same global_invalidates() function for determining whether to do local or global TLB invalidations as is used in other places, for consistency, and also to make sure that kvm->arch.need_tlb_flush gets updated properly. Signed-off-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/include/asm/kvm_book3s_64.h | 2 +- arch/powerpc/kvm/book3s_hv_rm_mmu.c | 139 +++++++++++++---------- 2 files changed, 82 insertions(+), 59 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 76ff0b5c9996..154ba3f6b7a9 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -100,7 +100,7 @@ static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r, /* (masks depend on page size) */ rb |= 0x1000; /* page encoding in LP field */ rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ - rb |= (va_low & 0xfe); /* AVAL field (P7 doesn't seem to care) */ + rb |= ((va_low << 4) & 0xf0); /* AVAL field (P7 doesn't seem to care) */ } } else { /* 4kB page */ diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 6dcbb49105a4..105b00f24f27 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -385,6 +385,80 @@ static inline int try_lock_tlbie(unsigned int *lock) return old == 0; } +/* + * tlbie/tlbiel is a bit different on the PPC970 compared to later + * processors such as POWER7; the large page bit is in the instruction + * not RB, and the top 16 bits and the bottom 12 bits of the VA + * in RB must be 0. + */ +static void do_tlbies_970(struct kvm *kvm, unsigned long *rbvalues, + long npages, int global, bool need_sync) +{ + long i; + + if (global) { + while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) + cpu_relax(); + if (need_sync) + asm volatile("ptesync" : : : "memory"); + for (i = 0; i < npages; ++i) { + unsigned long rb = rbvalues[i]; + + if (rb & 1) /* large page */ + asm volatile("tlbie %0,1" : : + "r" (rb & 0x0000fffffffff000ul)); + else + asm volatile("tlbie %0,0" : : + "r" (rb & 0x0000fffffffff000ul)); + } + asm volatile("eieio; tlbsync; ptesync" : : : "memory"); + kvm->arch.tlbie_lock = 0; + } else { + if (need_sync) + asm volatile("ptesync" : : : "memory"); + for (i = 0; i < npages; ++i) { + unsigned long rb = rbvalues[i]; + + if (rb & 1) /* large page */ + asm volatile("tlbiel %0,1" : : + "r" (rb & 0x0000fffffffff000ul)); + else + asm volatile("tlbiel %0,0" : : + "r" (rb & 0x0000fffffffff000ul)); + } + asm volatile("ptesync" : : : "memory"); + } +} + +static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues, + long npages, int global, bool need_sync) +{ + long i; + + if (cpu_has_feature(CPU_FTR_ARCH_201)) { + /* PPC970 tlbie instruction is a bit different */ + do_tlbies_970(kvm, rbvalues, npages, global, need_sync); + return; + } + if (global) { + while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) + cpu_relax(); + if (need_sync) + asm volatile("ptesync" : : : "memory"); + for (i = 0; i < npages; ++i) + asm volatile(PPC_TLBIE(%1,%0) : : + "r" (rbvalues[i]), "r" (kvm->arch.lpid)); + asm volatile("eieio; tlbsync; ptesync" : : : "memory"); + kvm->arch.tlbie_lock = 0; + } else { + if (need_sync) + asm volatile("ptesync" : : : "memory"); + for (i = 0; i < npages; ++i) + asm volatile("tlbiel %0" : : "r" (rbvalues[i])); + asm volatile("ptesync" : : : "memory"); + } +} + long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags, unsigned long pte_index, unsigned long avpn, unsigned long *hpret) @@ -410,19 +484,7 @@ long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags, if (v & HPTE_V_VALID) { hpte[0] &= ~HPTE_V_VALID; rb = compute_tlbie_rb(v, hpte[1], pte_index); - if (global_invalidates(kvm, flags)) { - while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync" - : : "r" (rb), "r" (kvm->arch.lpid)); - asm volatile("ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; - } else { - asm volatile("ptesync" : : : "memory"); - asm volatile("tlbiel %0" : : "r" (rb)); - asm volatile("ptesync" : : : "memory"); - } + do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true); /* Read PTE low word after tlbie to get final R/C values */ remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]); } @@ -450,12 +512,11 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu) unsigned long *hp, *hptes[4], tlbrb[4]; long int i, j, k, n, found, indexes[4]; unsigned long flags, req, pte_index, rcbits; - long int local = 0; + int global; long int ret = H_SUCCESS; struct revmap_entry *rev, *revs[4]; - if (atomic_read(&kvm->online_vcpus) == 1) - local = 1; + global = global_invalidates(kvm, 0); for (i = 0; i < 4 && ret == H_SUCCESS; ) { n = 0; for (; i < 4; ++i) { @@ -531,22 +592,7 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu) break; /* Now that we've collected a batch, do the tlbies */ - if (!local) { - while(!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - for (k = 0; k < n; ++k) - asm volatile(PPC_TLBIE(%1,%0) : : - "r" (tlbrb[k]), - "r" (kvm->arch.lpid)); - asm volatile("eieio; tlbsync; ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; - } else { - asm volatile("ptesync" : : : "memory"); - for (k = 0; k < n; ++k) - asm volatile("tlbiel %0" : : "r" (tlbrb[k])); - asm volatile("ptesync" : : : "memory"); - } + do_tlbies(kvm, tlbrb, n, global, true); /* Read PTE low words after tlbie to get final R/C values */ for (k = 0; k < n; ++k) { @@ -605,19 +651,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags, if (v & HPTE_V_VALID) { rb = compute_tlbie_rb(v, r, pte_index); hpte[0] = v & ~HPTE_V_VALID; - if (global_invalidates(kvm, flags)) { - while(!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync" - : : "r" (rb), "r" (kvm->arch.lpid)); - asm volatile("ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; - } else { - asm volatile("ptesync" : : : "memory"); - asm volatile("tlbiel %0" : : "r" (rb)); - asm volatile("ptesync" : : : "memory"); - } + do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true); /* * If the host has this page as readonly but the guest * wants to make it read/write, reduce the permissions. @@ -688,13 +722,7 @@ void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep, hptep[0] &= ~HPTE_V_VALID; rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index); - while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile("ptesync" : : : "memory"); - asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync" - : : "r" (rb), "r" (kvm->arch.lpid)); - asm volatile("ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; + do_tlbies(kvm, &rb, 1, 1, true); } EXPORT_SYMBOL_GPL(kvmppc_invalidate_hpte); @@ -708,12 +736,7 @@ void kvmppc_clear_ref_hpte(struct kvm *kvm, unsigned long *hptep, rbyte = (hptep[1] & ~HPTE_R_R) >> 8; /* modify only the second-last byte, which contains the ref bit */ *((char *)hptep + 14) = rbyte; - while (!try_lock_tlbie(&kvm->arch.tlbie_lock)) - cpu_relax(); - asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync" - : : "r" (rb), "r" (kvm->arch.lpid)); - asm volatile("ptesync" : : : "memory"); - kvm->arch.tlbie_lock = 0; + do_tlbies(kvm, &rb, 1, 1, false); } EXPORT_SYMBOL_GPL(kvmppc_clear_ref_hpte); From 4baa1d871c8c959084aa5367a9bf211f383941e5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 8 Jul 2013 20:09:53 +1000 Subject: [PATCH 0127/6183] KVM: PPC: Book3S HV: Allow negative offsets to real-mode hcall handlers The table of offsets to real-mode hcall handlers in book3s_hv_rmhandlers.S can contain negative values, if some of the handlers end up before the table in the vmlinux binary. Thus we need to use a sign-extending load to read the values in the table rather than a zero-extending load. Without this, the host crashes when the guest does one of the hcalls with negative offsets, due to jumping to a bogus address. Signed-off-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index b02f91e4c70d..60dce5bfab3f 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1381,7 +1381,7 @@ hcall_try_real_mode: cmpldi r3,hcall_real_table_end - hcall_real_table bge guest_exit_cont LOAD_REG_ADDR(r4, hcall_real_table) - lwzx r3,r3,r4 + lwax r3,r3,r4 cmpwi r3,0 beq guest_exit_cont add r3,r3,r4 From db1b76ca6a79c774074ae87bee7afc0825a478f5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 9 Jul 2013 16:51:37 +0200 Subject: [PATCH 0128/6183] drm/i915: don't frob mm.suspended when not using ums In kernel modeset driver mode we're in full control of the chip, always. So there's no need at all to set mm.suspended in i915_gem_idle. Hence move that out into the leavevt ioctl. Since i915_gem_idle doesn't suspend gem any more we can also drop the re-enabling for KMS in the thaw function. Also clean up the handling of mm.suspend at driver load by coalescing all the assignments. Stumbled over while reading through our resume code for unrelated reasons. v2: Shovel mm.suspended into the (newly created) ums dungeon as suggested by Chris Wilson. The plan is that once we've completely stopped relying on the register save/restore code we could shovel even that in there. v3: Improve the locking for the entervt/leavevt ioctls a bit by moving the dev->struct_mutex locking outside of i915_gem_idle. Also don't clear dev_priv->ums.mm_suspended for the kms case, we allocate it with kzalloc. Both suggested by Chris Wilson. Cc: Chris Wilson Reviewed-by: Chris Wilson (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 13 +++---- drivers/gpu/drm/i915/i915_drv.c | 11 +++--- drivers/gpu/drm/i915/i915_drv.h | 24 +++++++------ drivers/gpu/drm/i915/i915_gem.c | 40 +++++++++++++--------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0e2214236083..bece9973e1b5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1323,10 +1323,8 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; - if (INTEL_INFO(dev)->num_pipes == 0) { - dev_priv->mm.suspended = 0; + if (INTEL_INFO(dev)->num_pipes == 0) return 0; - } ret = intel_fbdev_init(dev); if (ret) @@ -1352,9 +1350,6 @@ static int i915_load_modeset_init(struct drm_device *dev) drm_kms_helper_poll_init(dev); - /* We're off and running w/KMS */ - dev_priv->mm.suspended = 0; - return 0; cleanup_gem: @@ -1629,9 +1624,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_gem_unload; } - /* Start out suspended */ - dev_priv->mm.suspended = 1; - if (HAS_POWER_WELL(dev)) i915_init_power_well(dev); @@ -1641,6 +1633,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) DRM_ERROR("failed to init modeset\n"); goto out_gem_unload; } + } else { + /* Start out suspended in ums mode. */ + dev_priv->ums.mm_suspended = 1; } i915_setup_sysfs(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ed9262c42b7b..0485f435eeea 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -556,7 +556,11 @@ static int i915_drm_freeze(struct drm_device *dev) /* If KMS is active, we do the leavevt stuff here */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { - int error = i915_gem_idle(dev); + int error; + + mutex_lock(&dev->struct_mutex); + error = i915_gem_idle(dev); + mutex_unlock(&dev->struct_mutex); if (error) { dev_err(&dev->pdev->dev, "GEM idle failed, resume might fail\n"); @@ -661,7 +665,6 @@ static int __i915_drm_thaw(struct drm_device *dev) intel_init_pch_refclk(dev); mutex_lock(&dev->struct_mutex); - dev_priv->mm.suspended = 0; error = i915_gem_init_hw(dev); mutex_unlock(&dev->struct_mutex); @@ -961,11 +964,11 @@ int i915_reset(struct drm_device *dev) * switched away). */ if (drm_core_check_feature(dev, DRIVER_MODESET) || - !dev_priv->mm.suspended) { + !dev_priv->ums.mm_suspended) { struct intel_ring_buffer *ring; int i; - dev_priv->mm.suspended = 0; + dev_priv->ums.mm_suspended = 0; i915_gem_init_swizzling(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 993fd2c8a457..c81ac155f5b9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -814,6 +814,18 @@ struct i915_dri1_state { uint32_t counter; }; +struct i915_ums_state { + /** + * Flag if the X Server, and thus DRM, is not currently in + * control of the device. + * + * This is set between LeaveVT and EnterVT. It needs to be + * replaced with a semaphore. It also needs to be + * transitioned away from for kernel modesetting. + */ + int mm_suspended; +}; + struct intel_l3_parity { u32 *remap_info; struct work_struct error_work; @@ -884,16 +896,6 @@ struct i915_gem_mm { */ bool interruptible; - /** - * Flag if the X Server, and thus DRM, is not currently in - * control of the device. - * - * This is set between LeaveVT and EnterVT. It needs to be - * replaced with a semaphore. It also needs to be - * transitioned away from for kernel modesetting. - */ - int suspended; - /** Bit 6 swizzling required for X tiling */ uint32_t bit_6_swizzle_x; /** Bit 6 swizzling required for Y tiling */ @@ -1187,6 +1189,8 @@ typedef struct drm_i915_private { /* Old dri1 support infrastructure, beware the dragons ya fools entering * here! */ struct i915_dri1_state dri1; + /* Old ums support infrastructure, same warning applies. */ + struct i915_ums_state ums; } drm_i915_private_t; /* Iterate over initialised rings */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 339404937ab9..20b10a0fa452 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2082,7 +2082,7 @@ int __i915_add_request(struct intel_ring_buffer *ring, trace_i915_gem_request_add(ring, request->seqno); ring->outstanding_lazy_request = 0; - if (!dev_priv->mm.suspended) { + if (!dev_priv->ums.mm_suspended) { if (i915_enable_hangcheck) { mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); @@ -2398,7 +2398,7 @@ i915_gem_retire_work_handler(struct work_struct *work) idle &= list_empty(&ring->request_list); } - if (!dev_priv->mm.suspended && !idle) + if (!dev_priv->ums.mm_suspended && !idle) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, round_jiffies_up_relative(HZ)); if (idle) @@ -3992,9 +3992,7 @@ i915_gem_idle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int ret; - mutex_lock(&dev->struct_mutex); - - if (dev_priv->mm.suspended) { + if (dev_priv->ums.mm_suspended) { mutex_unlock(&dev->struct_mutex); return 0; } @@ -4012,18 +4010,11 @@ i915_gem_idle(struct drm_device *dev) i915_gem_reset_fences(dev); - /* Hack! Don't let anybody do execbuf while we don't control the chip. - * We need to replace this with a semaphore, or something. - * And not confound mm.suspended! - */ - dev_priv->mm.suspended = 1; del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); - mutex_unlock(&dev->struct_mutex); - /* Cancel the retire work handler, which should be idle now. */ cancel_delayed_work_sync(&dev_priv->mm.retire_work); @@ -4233,7 +4224,7 @@ int i915_gem_entervt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; if (drm_core_check_feature(dev, DRIVER_MODESET)) @@ -4245,7 +4236,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, } mutex_lock(&dev->struct_mutex); - dev_priv->mm.suspended = 0; + dev_priv->ums.mm_suspended = 0; ret = i915_gem_init_hw(dev); if (ret != 0) { @@ -4265,7 +4256,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, cleanup_ringbuffer: mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); - dev_priv->mm.suspended = 1; + dev_priv->ums.mm_suspended = 1; mutex_unlock(&dev->struct_mutex); return ret; @@ -4275,11 +4266,26 @@ int i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; drm_irq_uninstall(dev); - return i915_gem_idle(dev); + + mutex_lock(&dev->struct_mutex); + ret = i915_gem_idle(dev); + + /* Hack! Don't let anybody do execbuf while we don't control the chip. + * We need to replace this with a semaphore, or something. + * And not confound ums.mm_suspended! + */ + if (ret != 0) + dev_priv->ums.mm_suspended = 1; + mutex_unlock(&dev->struct_mutex); + + return ret; } void @@ -4290,9 +4296,11 @@ i915_gem_lastclose(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; + mutex_lock(&dev->struct_mutex); ret = i915_gem_idle(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); + mutex_unlock(&dev->struct_mutex); } static void diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 5aeb447ead6b..64eda4463b70 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -973,7 +973,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto pre_mutex_err; - if (dev_priv->mm.suspended) { + if (dev_priv->ums.mm_suspended) { mutex_unlock(&dev->struct_mutex); ret = -EBUSY; goto pre_mutex_err; From 12f56f51925dfca7caf079a6e6ccd22b63cdb39a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 10 Jul 2013 14:27:31 +0200 Subject: [PATCH 0129/6183] drm/i915: remove unused members from drm_i915_private Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c81ac155f5b9..f2f1be110101 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1102,8 +1102,6 @@ typedef struct drm_i915_private { } backlight; /* LVDS info */ - struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ - struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ bool no_aux_handshake; struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ From 761a86b10725d314cad73a75020a2544c38d5a83 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Jul 2013 17:34:43 +0300 Subject: [PATCH 0130/6183] spi: tle62x0: dump small buffers using %*ph We have nice specifier in kernel for that. It changes separator from ',' (comma) to space, though it's not a big deal since it's just a debug message. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-tle62x0.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 6b0874d782ed..3e528c0396e7 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -52,8 +52,7 @@ static inline int tle62x0_write(struct tle62x0_state *st) buff[1] = gpio_state; } - dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n", - buff[0], buff[1], buff[2]); + dev_dbg(&st->us->dev, "buff %3ph\n", buff); return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2); } From b6c44f41823e50a5e109e929e07d787eabf4b0d3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 10 Jul 2013 00:22:46 +0900 Subject: [PATCH 0131/6183] ALSA: firewire-speakers: remove not-reused member from structure "pcm" member in struct fwspk is used to set pcm operations but is not used again. This commit remove this member and set pcm operations with snd_pcm_set_ops(). Signed-off-by: Takashi Sakamoto Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/firewire/speakers.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c index d6846557f270..0f1e5d88ed15 100644 --- a/sound/firewire/speakers.c +++ b/sound/firewire/speakers.c @@ -49,7 +49,6 @@ struct fwspk { struct snd_card *card; struct fw_unit *unit; const struct device_info *device_info; - struct snd_pcm_substream *pcm; struct mutex mutex; struct cmp_connection connection; struct amdtp_out_stream stream; @@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk) return err; pcm->private_data = fwspk; strcpy(pcm->name, fwspk->device_info->short_name); - fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; - fwspk->pcm->ops = &ops; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); return 0; } From cf870c70a194443f8fc654ddc9d6cfd02c58003b Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Wed, 10 Jul 2013 14:57:01 +0530 Subject: [PATCH 0132/6183] mce: acpi/apei: Soft-offline a page on firmware GHES notification If the firmware indicates in GHES error data entry that the error threshold has exceeded for a corrected error event, then we try to soft-offline the page. This could be called in interrupt context, so we queue this up similar to how we handle memory failure scenarios. Signed-off-by: Naveen N. Rao Acked-by: Borislav Petkov Signed-off-by: Tony Luck --- drivers/acpi/apei/ghes.c | 38 +++++++++++++++++++++++++++++--------- include/linux/mm.h | 1 + mm/memory-failure.c | 5 ++++- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index fcd7d91cec34..a8f362acc8ec 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -409,6 +409,34 @@ static void ghes_clear_estatus(struct ghes *ghes) ghes->flags &= ~GHES_TO_CLEAR; } +static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev) +{ +#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE + unsigned long pfn; + int sec_sev = ghes_severity(gdata->error_severity); + struct cper_sec_mem_err *mem_err; + mem_err = (struct cper_sec_mem_err *)(gdata + 1); + + if (sec_sev == GHES_SEV_CORRECTED && + (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && + (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)) { + pfn = mem_err->physical_addr >> PAGE_SHIFT; + if (pfn_valid(pfn)) + memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); + else if (printk_ratelimit()) + pr_warn(FW_WARN GHES_PFX + "Invalid address in generic error data: %#llx\n", + mem_err->physical_addr); + } + if (sev == GHES_SEV_RECOVERABLE && + sec_sev == GHES_SEV_RECOVERABLE && + mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { + pfn = mem_err->physical_addr >> PAGE_SHIFT; + memory_failure_queue(pfn, 0, 0); + } +#endif +} + static void ghes_do_proc(struct ghes *ghes, const struct acpi_hest_generic_status *estatus) { @@ -428,15 +456,7 @@ static void ghes_do_proc(struct ghes *ghes, apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, mem_err); #endif -#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE - if (sev == GHES_SEV_RECOVERABLE && - sec_sev == GHES_SEV_RECOVERABLE && - mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { - unsigned long pfn; - pfn = mem_err->physical_addr >> PAGE_SHIFT; - memory_failure_queue(pfn, 0, 0); - } -#endif + ghes_handle_memory_failure(gdata, sev); } #ifdef CONFIG_ACPI_APEI_PCIEAER else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, diff --git a/include/linux/mm.h b/include/linux/mm.h index e0c8528a41a4..958e9efd02a7 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1784,6 +1784,7 @@ enum mf_flags { MF_COUNT_INCREASED = 1 << 0, MF_ACTION_REQUIRED = 1 << 1, MF_MUST_KILL = 1 << 2, + MF_SOFT_OFFLINE = 1 << 3, }; extern int memory_failure(unsigned long pfn, int trapno, int flags); extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index ceb0c7f1932f..0d6717e52ea2 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1286,7 +1286,10 @@ static void memory_failure_work_func(struct work_struct *work) spin_unlock_irqrestore(&mf_cpu->lock, proc_flags); if (!gotten) break; - memory_failure(entry.pfn, entry.trapno, entry.flags); + if (entry.flags & MF_SOFT_OFFLINE) + soft_offline_page(pfn_to_page(entry.pfn), entry.flags); + else + memory_failure(entry.pfn, entry.trapno, entry.flags); } } From 5f1c248f52c12e155e0fe6a614178181f7629901 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 10 Jul 2013 17:47:39 -0500 Subject: [PATCH 0133/6183] kvm/ppc: Call trace_hardirqs_on before entry Currently this is only being done on 64-bit. Rather than just move it out of the 64-bit ifdef, move it to kvm_lazy_ee_enable() so that it is consistent with lazy ee state, and so that we don't track more host code as interrupts-enabled than necessary. Rename kvm_lazy_ee_enable() to kvm_fix_ee_before_entry() to reflect that this function now has a role on 32-bit as well. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- arch/powerpc/include/asm/kvm_ppc.h | 11 ++++++++--- arch/powerpc/kvm/book3s_pr.c | 4 ++-- arch/powerpc/kvm/booke.c | 4 ++-- arch/powerpc/kvm/powerpc.c | 2 -- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 5a26bfcd0bbc..b15554a26c20 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -394,10 +394,15 @@ static inline void kvmppc_mmu_flush_icache(pfn_t pfn) } } -/* Please call after prepare_to_enter. This function puts the lazy ee state - back to normal mode, without actually enabling interrupts. */ -static inline void kvmppc_lazy_ee_enable(void) +/* + * Please call after prepare_to_enter. This function puts the lazy ee and irq + * disabled tracking state back to normal mode, without actually enabling + * interrupts. + */ +static inline void kvmppc_fix_ee_before_entry(void) { + trace_hardirqs_on(); + #ifdef CONFIG_PPC64 /* Only need to enable IRQs by hard enabling them after this */ local_paca->irq_happened = 0; diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 19498a567a81..ddfaf560e503 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -890,7 +890,7 @@ program_interrupt: local_irq_enable(); r = s; } else { - kvmppc_lazy_ee_enable(); + kvmppc_fix_ee_before_entry(); } } @@ -1161,7 +1161,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) if (vcpu->arch.shared->msr & MSR_FP) kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); - kvmppc_lazy_ee_enable(); + kvmppc_fix_ee_before_entry(); ret = __kvmppc_vcpu_run(kvm_run, vcpu); diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index dcc94f016007..6e353517c4ad 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -698,7 +698,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) kvmppc_load_guest_fp(vcpu); #endif - kvmppc_lazy_ee_enable(); + kvmppc_fix_ee_before_entry(); ret = __kvmppc_vcpu_run(kvm_run, vcpu); @@ -1168,7 +1168,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, local_irq_enable(); r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV); } else { - kvmppc_lazy_ee_enable(); + kvmppc_fix_ee_before_entry(); } } diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 6316ee336e88..4e05f8c693b4 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -117,8 +117,6 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) kvm_guest_exit(); continue; } - - trace_hardirqs_on(); #endif kvm_guest_enter(); From c09ec198eb7d5d55fe2f23012a063b7ee107b34a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 10 Jul 2013 17:47:41 -0500 Subject: [PATCH 0134/6183] kvm/ppc/booke: Don't call kvm_guest_enter twice kvm_guest_enter() was already called by kvmppc_prepare_to_enter(). Don't call it again. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- arch/powerpc/kvm/booke.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 6e353517c4ad..17722d82f1d1 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -674,8 +674,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) goto out; } - kvm_guest_enter(); - #ifdef CONFIG_PPC_FPU /* Save userspace FPU state in stack */ enable_kernel_fp(); From fee884ed285a110b665c00b07b134cd2616122bc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:21 +0200 Subject: [PATCH 0135/6183] drm/i915: extract ibx_display_interrupt_update This way all changes to SDEIMR all go through the same function, with the exception of the (single-threaded) setup/teardown code. For paranoia again add an assert_spin_locked. v2: For even more paranoia also sprinkle a spinlock assert over cpt_can_enable_serr_int since we need to have that one there, too. v3: Fix the logic of interrupt enabling, add enable/disable macros for the simple cases in the fifo code and add a comment. All requested by Paulo. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 51 +++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4aedd387c8b5..80b88c868cd2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -128,6 +128,8 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev) enum pipe pipe; struct intel_crtc *crtc; + assert_spin_locked(&dev_priv->irq_lock); + for_each_pipe(pipe) { crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); @@ -170,6 +172,30 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, } } +/** + * ibx_display_interrupt_update - update SDEIMR + * @dev_priv: driver private + * @interrupt_mask: mask of interrupt bits to update + * @enabled_irq_mask: mask of interrupt bits to enable + */ +static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, + uint32_t interrupt_mask, + uint32_t enabled_irq_mask) +{ + uint32_t sdeimr = I915_READ(SDEIMR); + sdeimr &= ~interrupt_mask; + sdeimr |= (~enabled_irq_mask & interrupt_mask); + + assert_spin_locked(&dev_priv->irq_lock); + + I915_WRITE(SDEIMR, sdeimr); + POSTING_READ(SDEIMR); +} +#define ibx_enable_display_interrupt(dev_priv, bits) \ + ibx_display_interrupt_update((dev_priv), (bits), (bits)) +#define ibx_disable_display_interrupt(dev_priv, bits) \ + ibx_display_interrupt_update((dev_priv), (bits), 0) + static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc, bool enable) { @@ -179,11 +205,9 @@ static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc, SDE_TRANSB_FIFO_UNDER; if (enable) - I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit); + ibx_enable_display_interrupt(dev_priv, bit); else - I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit); - - POSTING_READ(SDEIMR); + ibx_disable_display_interrupt(dev_priv, bit); } static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, @@ -200,12 +224,10 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, SERR_INT_TRANS_B_FIFO_UNDERRUN | SERR_INT_TRANS_C_FIFO_UNDERRUN); - I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT); + ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); } else { - I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT); + ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); } - - POSTING_READ(SDEIMR); } /** @@ -2652,22 +2674,21 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *intel_encoder; - u32 mask = ~I915_READ(SDEIMR); - u32 hotplug; + u32 hotplug_irqs, hotplug, enabled_irqs = 0; if (HAS_PCH_IBX(dev)) { - mask &= ~SDE_HOTPLUG_MASK; + hotplug_irqs = SDE_HOTPLUG_MASK; list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) - mask |= hpd_ibx[intel_encoder->hpd_pin]; + enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin]; } else { - mask &= ~SDE_HOTPLUG_MASK_CPT; + hotplug_irqs = SDE_HOTPLUG_MASK_CPT; list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) - mask |= hpd_cpt[intel_encoder->hpd_pin]; + enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin]; } - I915_WRITE(SDEIMR, ~mask); + ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs); /* * Enable digital hotplug on the PCH, and configure the DP short pulse From 1dd246fb165819d31119e988c2887934c255fadc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 10 Jul 2013 08:30:23 +0200 Subject: [PATCH 0136/6183] drm/i915: improve SERR_INT clearing for fifo underrun reporting The current code won't report any fifo underruns on cpt if just one pipe has fifo underrun reporting disabled. We can't enable the interrupts, but we can still check the per-transcoder bits and so report the underrun delayed if: - We always clear the transcoder's bit (and none of the other bits) when enabling. - We check the transcoder's bit after disabling (to avoid racing with the interrupt handler). v2: I've forgotten to actually remove the old SERR_INT clearing. v3: Use transcoder_name as suggested by Paulo Zanoni. Paulo also noticed a logic bug: When an underrun interrupt fires we report it both in the interrupt handler and when checking for underruns when disabling it in cpt_set_fifo_underrun_reporting. But that second check is only required if the interrupt is disabled and we're switching of underrun reporting (e.g. because we're disabling the crtc). Hence check for that condition. At first I wanted to rework the code to pass that bit of information from the uppper functions down to cpt_set_fifo_underrun_reporting. But that turned out too messy. Hence the quick&dirty check whether the south error interrupt source is masked off or not. v4: Streamline the control flow a bit. v5: s/pipe/pch transcoder/ in the dmesg output, suggested by Paulo. v6: Review from Paulo: - Reorder the was_enabled assignment to only read the register when we need it. Also add a comment that we need to do that before updating the register. - s/%i/%c/ fix for the debug output. - Fix the checkpath complaint in the SERR_INT_TRANS_FIFO_UNDERRUN #define. v7: Hopefully put that elusive SERR hunk back into this patch, spotted by Paulo. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 17 +++++++++++++---- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 80b88c868cd2..dd9d9997e90b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -217,16 +217,25 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; if (enable) { + I915_WRITE(SERR_INT, + SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)); + if (!cpt_can_enable_serr_int(dev)) return; - I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN | - SERR_INT_TRANS_B_FIFO_UNDERRUN | - SERR_INT_TRANS_C_FIFO_UNDERRUN); - ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT); } else { + uint32_t tmp = I915_READ(SERR_INT); + bool was_enabled = !(I915_READ(SDEIMR) & SDE_ERROR_CPT); + + /* Change the state _after_ we've read out the current one. */ ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT); + + if (!was_enabled && + (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))) { + DRM_DEBUG_KMS("uncleared pch fifo underrun on pch transcoder %c\n", + transcoder_name(pch_transcoder)); + } } } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e9c50fab94af..7e2684fe4d3a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3882,6 +3882,7 @@ #define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6) #define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3) #define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0) +#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<(pipe*3)) /* digital port hotplug */ #define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ From 7336df6512440a494d3a705dfc6a883a42733c8f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 9 Jul 2013 22:59:16 +0200 Subject: [PATCH 0137/6183] drm/i915: improve GEN7_ERR_INT clearing for fifo underrun reporting Same treatment as for SERR_INT: If we clear only the bit for the pipe we're enabling (but unconditionally) then we can always check for possible underruns after having disabled the interrupt. That way pipe underruns won't be lost, but at worst only get reported in a delayed fashion. v2: The same logic bug as in the SERR handling change also existed here. The same bugfix of only reporting missed underruns when the error interrupt was masked applies, too. v3: Do the same fixes as for the SERR handling that Paulo suggested in his review: - s/%i/%c/ fix in the debug output - move the DE_ERR_INT_IVB read into the respective if block Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni [danvet: Fix up the checkpatch bikeshed Paulo noticed.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 20 +++++++++++++------- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dd9d9997e90b..76e977b0070e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -154,21 +154,27 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, } static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, - bool enable) + enum pipe pipe, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; - if (enable) { + I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe)); + if (!ivb_can_enable_err_int(dev)) return; - I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A | - ERR_INT_FIFO_UNDERRUN_B | - ERR_INT_FIFO_UNDERRUN_C); - ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); } else { + bool was_enabled = !(I915_READ(DEIMR) & DE_ERR_INT_IVB); + + /* Change the state _after_ we've read out the current one. */ ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); + + if (!was_enabled && + (I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe))) { + DRM_DEBUG_KMS("uncleared fifo underrun on pipe %c\n", + pipe_name(pipe)); + } } } @@ -274,7 +280,7 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, if (IS_GEN5(dev) || IS_GEN6(dev)) ironlake_set_fifo_underrun_reporting(dev, pipe, enable); else if (IS_GEN7(dev)) - ivybridge_set_fifo_underrun_reporting(dev, enable); + ivybridge_set_fifo_underrun_reporting(dev, pipe, enable); done: spin_unlock_irqrestore(&dev_priv->irq_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7e2684fe4d3a..dc3d6a74f391 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -681,6 +681,7 @@ #define ERR_INT_FIFO_UNDERRUN_C (1<<6) #define ERR_INT_FIFO_UNDERRUN_B (1<<3) #define ERR_INT_FIFO_UNDERRUN_A (1<<0) +#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<(pipe*3)) #define FPGA_DBG 0x42300 #define FPGA_DBG_RM_NOCLAIM (1<<31) From de28075d5bb3e1e9f92d19da214b6a96f544b66d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:24 +0200 Subject: [PATCH 0138/6183] drm/i915: kill lpt pch transcoder->crtc mapping code for fifo underruns It's racy: There's no guarantee that we won't walk this code (due to a pch fifo underrun interrupt) while someone is changing the pointers around. The only reason we do this is to use the righ crtc for the pch fifo underrun accounting. But we never expose this to userspace, so essentially no one really cares if we use the "wrong" crtc. So let's just rip it out. With this patch fifo underrun code will always use crtc A for tracking underruns on the (only) pch transcoder on LPT. v2: Add a big comment explaining what's going on. Requested by Paulo. v3: Fixup spelling in comment as spotted by Paulo. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 76e977b0070e..69957f889432 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -202,13 +202,13 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv, #define ibx_disable_display_interrupt(dev_priv, bits) \ ibx_display_interrupt_update((dev_priv), (bits), 0) -static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc, +static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, + enum transcoder pch_transcoder, bool enable) { - struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER : - SDE_TRANSB_FIFO_UNDER; + uint32_t bit = (pch_transcoder == TRANSCODER_A) ? + SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER; if (enable) ibx_enable_display_interrupt(dev_priv, bit); @@ -306,29 +306,19 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe p; - struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); unsigned long flags; bool ret; - if (HAS_PCH_LPT(dev)) { - crtc = NULL; - for_each_pipe(p) { - struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p]; - if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) { - crtc = c; - break; - } - } - if (!crtc) { - DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n"); - return false; - } - } else { - crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; - } - intel_crtc = to_intel_crtc(crtc); + /* + * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT + * has only one pch transcoder A that all pipes can use. To avoid racy + * pch transcoder -> pipe lookups from interrupt code simply store the + * underrun statistics in crtc A. Since we never expose this anywhere + * nor use it outside of the fifo underrun code here using the "wrong" + * crtc on LPT won't cause issues. + */ spin_lock_irqsave(&dev_priv->irq_lock, flags); @@ -340,7 +330,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, intel_crtc->pch_fifo_underrun_disabled = !enable; if (HAS_PCH_IBX(dev)) - ibx_set_fifo_underrun_reporting(intel_crtc, enable); + ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable); else cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable); From d0ecd7e221c87514b1eca84b11fee1e262f5d816 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:25 +0200 Subject: [PATCH 0139/6183] drm/i915: irq handlers don't need interrupt-safe spinlocks Since we only have one interrupt handler and interrupt handlers are non-reentrant. To drive the point really home give them all an _irq_handler suffix. This is a tiny micro-optimization but even more important it makes it clearer what locking we actually need. And in case someone screws this up: lockdep will catch hardirq vs. other context deadlocks. v2: Fix up compile fail. Reviewed-by: Paulo Zanoni Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 42 ++++++++++++++------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 69957f889432..a7c0a730a6e1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -656,14 +656,13 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_kms_helper_hotplug_event(dev); } -static void ironlake_handle_rps_change(struct drm_device *dev) +static void ironlake_rps_change_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 busy_up, busy_down, max_avg, min_avg; u8 new_delay; - unsigned long flags; - spin_lock_irqsave(&mchdev_lock, flags); + spin_lock(&mchdev_lock); I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); @@ -691,7 +690,7 @@ static void ironlake_handle_rps_change(struct drm_device *dev) if (ironlake_set_drps(dev, new_delay)) dev_priv->ips.cur_delay = new_delay; - spin_unlock_irqrestore(&mchdev_lock, flags); + spin_unlock(&mchdev_lock); return; } @@ -835,18 +834,17 @@ static void ivybridge_parity_work(struct work_struct *work) kfree(parity_event[1]); } -static void ivybridge_handle_parity_error(struct drm_device *dev) +static void ivybridge_parity_error_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long flags; if (!HAS_L3_GPU_CACHE(dev)) return; - spin_lock_irqsave(&dev_priv->irq_lock, flags); + spin_lock(&dev_priv->irq_lock); dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - spin_unlock_irqrestore(&dev_priv->irq_lock, flags); + spin_unlock(&dev_priv->irq_lock); queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work); } @@ -872,15 +870,13 @@ static void snb_gt_irq_handler(struct drm_device *dev, } if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) - ivybridge_handle_parity_error(dev); + ivybridge_parity_error_irq_handler(dev); } /* Legacy way of handling PM interrupts */ -static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, - u32 pm_iir) +static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, + u32 pm_iir) { - unsigned long flags; - /* * IIR bits should never already be set because IMR should * prevent an interrupt from being shown in IIR. The warning @@ -891,11 +887,11 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, * The mask bit in IMR is cleared by dev_priv->rps.work. */ - spin_lock_irqsave(&dev_priv->rps.lock, flags); + spin_lock(&dev_priv->rps.lock); dev_priv->rps.pm_iir |= pm_iir; I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps.lock, flags); + spin_unlock(&dev_priv->rps.lock); queue_work(dev_priv->wq, &dev_priv->rps.work); } @@ -959,7 +955,7 @@ static void dp_aux_irq_handler(struct drm_device *dev) wake_up_all(&dev_priv->gmbus_wait_queue); } -/* Unlike gen6_queue_rps_work() from which this function is originally derived, +/* Unlike gen6_rps_irq_handler() from which this function is originally derived, * we must be able to deal with other PM interrupts. This is complicated because * of the way in which we use the masks to defer the RPS work (which for * posterity is necessary because of forcewake). @@ -967,9 +963,7 @@ static void dp_aux_irq_handler(struct drm_device *dev) static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) { - unsigned long flags; - - spin_lock_irqsave(&dev_priv->rps.lock, flags); + spin_lock(&dev_priv->rps.lock); dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; if (dev_priv->rps.pm_iir) { I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); @@ -978,7 +972,7 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, /* TODO: if queue_work is slow, move it out of the spinlock */ queue_work(dev_priv->wq, &dev_priv->rps.work); } - spin_unlock_irqrestore(&dev_priv->rps.lock, flags); + spin_unlock(&dev_priv->rps.lock); if (pm_iir & ~GEN6_PM_RPS_EVENTS) { if (pm_iir & PM_VEBOX_USER_INTERRUPT) @@ -1060,7 +1054,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) gmbus_irq_handler(dev); if (pm_iir & GEN6_PM_RPS_EVENTS) - gen6_queue_rps_work(dev_priv, pm_iir); + gen6_rps_irq_handler(dev_priv, pm_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(GEN6_PMIIR, pm_iir); @@ -1298,7 +1292,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) if (IS_HASWELL(dev)) hsw_pm_irq_handler(dev_priv, pm_iir); else if (pm_iir & GEN6_PM_RPS_EVENTS) - gen6_queue_rps_work(dev_priv, pm_iir); + gen6_rps_irq_handler(dev_priv, pm_iir); I915_WRITE(GEN6_PMIIR, pm_iir); ret = IRQ_HANDLED; } @@ -1415,10 +1409,10 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) } if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT) - ironlake_handle_rps_change(dev); + ironlake_rps_change_irq_handler(dev); if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS) - gen6_queue_rps_work(dev_priv, pm_iir); + gen6_rps_irq_handler(dev_priv, pm_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(DEIIR, de_iir); From 41a05a3a5cdc5d731014588b9a24759af1804d48 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:26 +0200 Subject: [PATCH 0140/6183] drm/i915: streamline hsw_pm_irq_handler The if (pm_iir & ~GEN6_PM_RPS_EVENTS) check was redunandant. Otoh adding a check for rps events allows us to avoid the spinlock grabbing for VECS interrupts. v2: Drop misplaced hunk which now moved to the right patch. Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a7c0a730a6e1..d4af11541287 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -963,25 +963,23 @@ static void dp_aux_irq_handler(struct drm_device *dev) static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) { - spin_lock(&dev_priv->rps.lock); - dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; - if (dev_priv->rps.pm_iir) { + if (pm_iir & GEN6_PM_RPS_EVENTS) { + spin_lock(&dev_priv->rps.lock); + dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); /* never want to mask useful interrupts. (also posting read) */ WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); /* TODO: if queue_work is slow, move it out of the spinlock */ queue_work(dev_priv->wq, &dev_priv->rps.work); + spin_unlock(&dev_priv->rps.lock); } - spin_unlock(&dev_priv->rps.lock); - if (pm_iir & ~GEN6_PM_RPS_EVENTS) { - if (pm_iir & PM_VEBOX_USER_INTERRUPT) - notify_ring(dev_priv->dev, &dev_priv->ring[VECS]); + if (pm_iir & PM_VEBOX_USER_INTERRUPT) + notify_ring(dev_priv->dev, &dev_priv->ring[VECS]); - if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) { - DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir); - i915_handle_error(dev_priv->dev, false); - } + if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) { + DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir); + i915_handle_error(dev_priv->dev, false); } } From 2adbee62e00d869a30cb93ea2269e5ea26a9bbc4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:27 +0200 Subject: [PATCH 0141/6183] drm/i915: queue work outside spinlock in hsw_pm_irq_handler And kill the comment about it. Queueing work is a barrier type event, no amount of locking will help in ordering things (as long as we queue the work after having updated all relevant data structures). Also, the queue_work works itself as a sufficient memory barrier. Again on the surface this is just a tiny micro-optimization to reduce the hold-time of dev_priv->irq_lock. But the better reason is that it reduces superficial locking and so makes it clearer what we actually need for correctness. Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d4af11541287..04861995fe1b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -969,9 +969,9 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); /* never want to mask useful interrupts. (also posting read) */ WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); - /* TODO: if queue_work is slow, move it out of the spinlock */ - queue_work(dev_priv->wq, &dev_priv->rps.work); spin_unlock(&dev_priv->rps.lock); + + queue_work(dev_priv->wq, &dev_priv->rps.work); } if (pm_iir & PM_VEBOX_USER_INTERRUPT) From 59cdb63d529c81fc8ac0620ad50f29d5fb4411c9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:28 +0200 Subject: [PATCH 0142/6183] drm/i915: kill dev_priv->rps.lock Now that the rps interrupt locking isn't clearly separated (at elast conceptually) from all the other interrupt locking having a different lock stopped making sense: It protects much more than just the rps workqueue it started out with. But with the addition of VECS the separation started to blurr and resulted in some more complex locking for the ring interrupt refcount. With this we can (again) unifiy the ringbuffer irq refcounts without causing a massive confusion, but that's for the next patch. v2: Explain better why the rps.lock once made sense and why no longer, requested by Ben. Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 - drivers/gpu/drm/i915/i915_drv.h | 8 ++++---- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++------ drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 6 files changed, 23 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index bece9973e1b5..6ce903306320 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1607,7 +1607,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); - spin_lock_init(&dev_priv->rps.lock); spin_lock_init(&dev_priv->backlight.lock); mutex_init(&dev_priv->dpio_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f2f1be110101..846500a8586c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -743,12 +743,12 @@ struct i915_suspend_saved_registers { }; struct intel_gen6_power_mgmt { + /* work and pm_iir are protected by dev_priv->irq_lock */ struct work_struct work; - struct delayed_work vlv_work; u32 pm_iir; - /* lock - irqsave spinlock that protectects the work_struct and - * pm_iir. */ - spinlock_t lock; + + /* On vlv we need to manually drop to Vmin with a delayed work. */ + struct delayed_work vlv_work; /* The below variables an all the rps hw state are protected by * dev->struct mutext. */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 04861995fe1b..f4d5569834c2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -719,13 +719,13 @@ static void gen6_pm_rps_work(struct work_struct *work) u32 pm_iir, pm_imr; u8 new_delay; - spin_lock_irq(&dev_priv->rps.lock); + spin_lock_irq(&dev_priv->irq_lock); pm_iir = dev_priv->rps.pm_iir; dev_priv->rps.pm_iir = 0; pm_imr = I915_READ(GEN6_PMIMR); /* Make sure not to corrupt PMIMR state used by ringbuffer code */ I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS); - spin_unlock_irq(&dev_priv->rps.lock); + spin_unlock_irq(&dev_priv->irq_lock); if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0) return; @@ -887,11 +887,11 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, * The mask bit in IMR is cleared by dev_priv->rps.work. */ - spin_lock(&dev_priv->rps.lock); + spin_lock(&dev_priv->irq_lock); dev_priv->rps.pm_iir |= pm_iir; I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); POSTING_READ(GEN6_PMIMR); - spin_unlock(&dev_priv->rps.lock); + spin_unlock(&dev_priv->irq_lock); queue_work(dev_priv->wq, &dev_priv->rps.work); } @@ -964,12 +964,12 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) { if (pm_iir & GEN6_PM_RPS_EVENTS) { - spin_lock(&dev_priv->rps.lock); + spin_lock(&dev_priv->irq_lock); dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); /* never want to mask useful interrupts. (also posting read) */ WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); - spin_unlock(&dev_priv->rps.lock); + spin_unlock(&dev_priv->irq_lock); queue_work(dev_priv->wq, &dev_priv->rps.work); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 125a741eed86..a9be0d1c173d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3135,9 +3135,9 @@ static void gen6_disable_rps(struct drm_device *dev) * register (PMIMR) to mask PM interrupts. The only risk is in leaving * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ - spin_lock_irq(&dev_priv->rps.lock); + spin_lock_irq(&dev_priv->irq_lock); dev_priv->rps.pm_iir = 0; - spin_unlock_irq(&dev_priv->rps.lock); + spin_unlock_irq(&dev_priv->irq_lock); I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); } @@ -3154,9 +3154,9 @@ static void valleyview_disable_rps(struct drm_device *dev) * register (PMIMR) to mask PM interrupts. The only risk is in leaving * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ - spin_lock_irq(&dev_priv->rps.lock); + spin_lock_irq(&dev_priv->irq_lock); dev_priv->rps.pm_iir = 0; - spin_unlock_irq(&dev_priv->rps.lock); + spin_unlock_irq(&dev_priv->irq_lock); I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); @@ -3321,13 +3321,13 @@ static void gen6_enable_rps(struct drm_device *dev) /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS); - spin_lock_irq(&dev_priv->rps.lock); + spin_lock_irq(&dev_priv->irq_lock); /* FIXME: Our interrupt enabling sequence is bonghits. * dev_priv->rps.pm_iir really should be 0 here. */ dev_priv->rps.pm_iir = 0; I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); - spin_unlock_irq(&dev_priv->rps.lock); + spin_unlock_irq(&dev_priv->irq_lock); /* unmask all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); @@ -3601,10 +3601,10 @@ static void valleyview_enable_rps(struct drm_device *dev) /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); - spin_lock_irq(&dev_priv->rps.lock); + spin_lock_irq(&dev_priv->irq_lock); WARN_ON(dev_priv->rps.pm_iir != 0); I915_WRITE(GEN6_PMIMR, 0); - spin_unlock_irq(&dev_priv->rps.lock); + spin_unlock_irq(&dev_priv->irq_lock); /* enable all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 54495df2403e..33a74a803008 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1055,14 +1055,14 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring) if (!dev->irq_enabled) return false; - spin_lock_irqsave(&dev_priv->rps.lock, flags); + spin_lock_irqsave(&dev_priv->irq_lock, flags); if (ring->irq_refcount.pm++ == 0) { u32 pm_imr = I915_READ(GEN6_PMIMR); I915_WRITE_IMR(ring, ~ring->irq_enable_mask); I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask); POSTING_READ(GEN6_PMIMR); } - spin_unlock_irqrestore(&dev_priv->rps.lock, flags); + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); return true; } @@ -1077,14 +1077,14 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring) if (!dev->irq_enabled) return; - spin_lock_irqsave(&dev_priv->rps.lock, flags); + spin_lock_irqsave(&dev_priv->irq_lock, flags); if (--ring->irq_refcount.pm == 0) { u32 pm_imr = I915_READ(GEN6_PMIMR); I915_WRITE_IMR(ring, ~0); I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask); POSTING_READ(GEN6_PMIMR); } - spin_unlock_irqrestore(&dev_priv->rps.lock, flags); + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); } static int diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 799f04c9da45..8a87b3f9974c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -80,7 +80,7 @@ struct intel_ring_buffer { struct { u32 gt; /* protected by dev_priv->irq_lock */ - u32 pm; /* protected by dev_priv->rps.lock (sucks) */ + u32 pm; /* protected by dev_priv->irq_lock */ } irq_refcount; u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 trace_irq_seqno; From c7113cc35f59b46b301367b947c4f71ac8f0d5bb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:29 +0200 Subject: [PATCH 0143/6183] drm/i915: unify ring irq refcounts (again) With the simplified locking there's no reason any more to keep the refcounts seperate. v2: Readd the lost comment that ring->irq_refcount is protected by dev_priv->irq_lock. Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 33a74a803008..23ffe1d06220 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -821,7 +821,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount.gt++ == 0) { + if (ring->irq_refcount++ == 0) { dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); POSTING_READ(GTIMR); @@ -839,7 +839,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount.gt == 0) { + if (--ring->irq_refcount == 0) { dev_priv->gt_irq_mask |= ring->irq_enable_mask; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); POSTING_READ(GTIMR); @@ -858,7 +858,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount.gt++ == 0) { + if (ring->irq_refcount++ == 0) { dev_priv->irq_mask &= ~ring->irq_enable_mask; I915_WRITE(IMR, dev_priv->irq_mask); POSTING_READ(IMR); @@ -876,7 +876,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount.gt == 0) { + if (--ring->irq_refcount == 0) { dev_priv->irq_mask |= ring->irq_enable_mask; I915_WRITE(IMR, dev_priv->irq_mask); POSTING_READ(IMR); @@ -895,7 +895,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount.gt++ == 0) { + if (ring->irq_refcount++ == 0) { dev_priv->irq_mask &= ~ring->irq_enable_mask; I915_WRITE16(IMR, dev_priv->irq_mask); POSTING_READ16(IMR); @@ -913,7 +913,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount.gt == 0) { + if (--ring->irq_refcount == 0) { dev_priv->irq_mask |= ring->irq_enable_mask; I915_WRITE16(IMR, dev_priv->irq_mask); POSTING_READ16(IMR); @@ -1006,7 +1006,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) gen6_gt_force_wake_get(dev_priv); spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount.gt++ == 0) { + if (ring->irq_refcount++ == 0) { if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | @@ -1030,7 +1030,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount.gt == 0) { + if (--ring->irq_refcount == 0) { if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT); @@ -1056,7 +1056,7 @@ hsw_vebox_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount.pm++ == 0) { + if (ring->irq_refcount++ == 0) { u32 pm_imr = I915_READ(GEN6_PMIMR); I915_WRITE_IMR(ring, ~ring->irq_enable_mask); I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask); @@ -1078,7 +1078,7 @@ hsw_vebox_put_irq(struct intel_ring_buffer *ring) return; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount.pm == 0) { + if (--ring->irq_refcount == 0) { u32 pm_imr = I915_READ(GEN6_PMIMR); I915_WRITE_IMR(ring, ~0); I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8a87b3f9974c..6e38256d41e1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -78,10 +78,7 @@ struct intel_ring_buffer { */ u32 last_retired_head; - struct { - u32 gt; /* protected by dev_priv->irq_lock */ - u32 pm; /* protected by dev_priv->irq_lock */ - } irq_refcount; + unsigned irq_refcount; /* protected by dev_priv->irq_lock */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 trace_irq_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; From c0d6a3dd61d46a640ead0a9d38b78ca22d37a304 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:30 +0200 Subject: [PATCH 0144/6183] drm/i915: don't enable PM_VEBOX_CS_ERROR_INTERRUPT The code to handle it is broken - there's simply no code to clear CS parser errors on gen5+. And behold, for all the other rings we also don't enable it! Leave the handling code itself in place just to be consistent with the existing mess though. And in case someone feels like fixing it all up. This has been errornously enabled in commit 12638c57f31952127c734c26315e1348fa1334c2 Author: Ben Widawsky Date: Tue May 28 19:22:31 2013 -0700 drm/i915: Enable vebox interrupts Cc: Damien Lespiau Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 3 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f4d5569834c2..cf1a21a9728a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2814,8 +2814,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); if (HAS_VEBOX(dev)) - pm_irqs |= PM_VEBOX_USER_INTERRUPT | - PM_VEBOX_CS_ERROR_INTERRUPT; + pm_irqs |= PM_VEBOX_USER_INTERRUPT; /* Our enable/disable rps functions may touch these registers so * make sure to set a known state for only the non-RPS bits. diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 23ffe1d06220..815e30332247 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2000,8 +2000,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT | - PM_VEBOX_CS_ERROR_INTERRUPT; + ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT; ring->irq_get = hsw_vebox_get_irq; ring->irq_put = hsw_vebox_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; From 08e2a7de8ec86054a1272e4fc9d15fa6c18d3b16 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 11 Jul 2013 20:10:54 +0100 Subject: [PATCH 0145/6183] drm/i915: Use for_each_pipe() when possible Came accross two open coding of for_each_pipe(), might as well use the macro. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d2b76b695349..bca81eecd31e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1131,7 +1131,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, } /* Need to check both planes against the pipe */ - for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { + for_each_pipe(i) { reg = DSPCNTR(i); val = I915_READ(reg); cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> @@ -9715,7 +9715,7 @@ void intel_modeset_init(struct drm_device *dev) INTEL_INFO(dev)->num_pipes, INTEL_INFO(dev)->num_pipes > 1 ? "s" : ""); - for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { + for_each_pipe(i) { intel_crtc_init(dev, i); for (j = 0; j < dev_priv->num_plane; j++) { ret = intel_plane_init(dev, i, j); From ddf7540e9c3a3d65739daa339c8838fa39cf2758 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 12 Jul 2013 11:01:02 +0200 Subject: [PATCH 0146/6183] HID: logitech-dj: use inlined helpers hid_hw_open/close Use the inlined helpers hid_hw_open/close instead of direct calls to ->ll_driver->open() and ->ll_driver->close(). Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-dj.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 5207591a598c..db3192b24e6e 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -756,10 +756,10 @@ static int logi_dj_probe(struct hid_device *hdev, } /* This is enabling the polling urb on the IN endpoint */ - retval = hdev->ll_driver->open(hdev); + retval = hid_hw_open(hdev); if (retval < 0) { - dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned " - "error:%d\n", __func__, retval); + dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n", + __func__, retval); goto llopen_failed; } @@ -776,7 +776,7 @@ static int logi_dj_probe(struct hid_device *hdev, return retval; logi_dj_recv_query_paired_devices_failed: - hdev->ll_driver->close(hdev); + hid_hw_close(hdev); llopen_failed: switch_to_dj_mode_fail: @@ -818,7 +818,7 @@ static void logi_dj_remove(struct hid_device *hdev) cancel_work_sync(&djrcv_dev->work); - hdev->ll_driver->close(hdev); + hid_hw_close(hdev); hid_hw_stop(hdev); /* I suppose that at this point the only context that can access From 67516844625f45f0ce148a01c27bf41f591872b2 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 9 Jul 2013 18:56:31 +0200 Subject: [PATCH 0147/6183] perf: Remove the 'match' callback for auxiliary events processing It gives the following benefits: - only one function pointer is passed along the way - the 'match' function is called within output function and could be inlined by the compiler Suggested-by: Peter Zijlstra Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Arnaldo Carvalho de Melo Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/1373388991-9711-1-git-send-email-jolsa@redhat.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 79 ++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index eba8fb5834ae..708ab70ca442 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4680,12 +4680,10 @@ perf_event_read_event(struct perf_event *event, perf_output_end(&handle); } -typedef int (perf_event_aux_match_cb)(struct perf_event *event, void *data); typedef void (perf_event_aux_output_cb)(struct perf_event *event, void *data); static void perf_event_aux_ctx(struct perf_event_context *ctx, - perf_event_aux_match_cb match, perf_event_aux_output_cb output, void *data) { @@ -4696,15 +4694,12 @@ perf_event_aux_ctx(struct perf_event_context *ctx, continue; if (!event_filter_match(event)) continue; - if (match(event, data)) - output(event, data); + output(event, data); } } static void -perf_event_aux(perf_event_aux_match_cb match, - perf_event_aux_output_cb output, - void *data, +perf_event_aux(perf_event_aux_output_cb output, void *data, struct perf_event_context *task_ctx) { struct perf_cpu_context *cpuctx; @@ -4717,7 +4712,7 @@ perf_event_aux(perf_event_aux_match_cb match, cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); if (cpuctx->unique_pmu != pmu) goto next; - perf_event_aux_ctx(&cpuctx->ctx, match, output, data); + perf_event_aux_ctx(&cpuctx->ctx, output, data); if (task_ctx) goto next; ctxn = pmu->task_ctx_nr; @@ -4725,14 +4720,14 @@ perf_event_aux(perf_event_aux_match_cb match, goto next; ctx = rcu_dereference(current->perf_event_ctxp[ctxn]); if (ctx) - perf_event_aux_ctx(ctx, match, output, data); + perf_event_aux_ctx(ctx, output, data); next: put_cpu_ptr(pmu->pmu_cpu_context); } if (task_ctx) { preempt_disable(); - perf_event_aux_ctx(task_ctx, match, output, data); + perf_event_aux_ctx(task_ctx, output, data); preempt_enable(); } rcu_read_unlock(); @@ -4759,6 +4754,12 @@ struct perf_task_event { } event_id; }; +static int perf_event_task_match(struct perf_event *event) +{ + return event->attr.comm || event->attr.mmap || + event->attr.mmap_data || event->attr.task; +} + static void perf_event_task_output(struct perf_event *event, void *data) { @@ -4768,6 +4769,9 @@ static void perf_event_task_output(struct perf_event *event, struct task_struct *task = task_event->task; int ret, size = task_event->event_id.header.size; + if (!perf_event_task_match(event)) + return; + perf_event_header__init_id(&task_event->event_id.header, &sample, event); ret = perf_output_begin(&handle, event, @@ -4790,13 +4794,6 @@ out: task_event->event_id.header.size = size; } -static int perf_event_task_match(struct perf_event *event, - void *data __maybe_unused) -{ - return event->attr.comm || event->attr.mmap || - event->attr.mmap_data || event->attr.task; -} - static void perf_event_task(struct task_struct *task, struct perf_event_context *task_ctx, int new) @@ -4825,8 +4822,7 @@ static void perf_event_task(struct task_struct *task, }, }; - perf_event_aux(perf_event_task_match, - perf_event_task_output, + perf_event_aux(perf_event_task_output, &task_event, task_ctx); } @@ -4853,6 +4849,11 @@ struct perf_comm_event { } event_id; }; +static int perf_event_comm_match(struct perf_event *event) +{ + return event->attr.comm; +} + static void perf_event_comm_output(struct perf_event *event, void *data) { @@ -4862,6 +4863,9 @@ static void perf_event_comm_output(struct perf_event *event, int size = comm_event->event_id.header.size; int ret; + if (!perf_event_comm_match(event)) + return; + perf_event_header__init_id(&comm_event->event_id.header, &sample, event); ret = perf_output_begin(&handle, event, comm_event->event_id.header.size); @@ -4883,12 +4887,6 @@ out: comm_event->event_id.header.size = size; } -static int perf_event_comm_match(struct perf_event *event, - void *data __maybe_unused) -{ - return event->attr.comm; -} - static void perf_event_comm_event(struct perf_comm_event *comm_event) { char comm[TASK_COMM_LEN]; @@ -4903,8 +4901,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; - perf_event_aux(perf_event_comm_match, - perf_event_comm_output, + perf_event_aux(perf_event_comm_output, comm_event, NULL); } @@ -4967,6 +4964,17 @@ struct perf_mmap_event { } event_id; }; +static int perf_event_mmap_match(struct perf_event *event, + void *data) +{ + struct perf_mmap_event *mmap_event = data; + struct vm_area_struct *vma = mmap_event->vma; + int executable = vma->vm_flags & VM_EXEC; + + return (!executable && event->attr.mmap_data) || + (executable && event->attr.mmap); +} + static void perf_event_mmap_output(struct perf_event *event, void *data) { @@ -4976,6 +4984,9 @@ static void perf_event_mmap_output(struct perf_event *event, int size = mmap_event->event_id.header.size; int ret; + if (!perf_event_mmap_match(event, data)) + return; + perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); ret = perf_output_begin(&handle, event, mmap_event->event_id.header.size); @@ -4996,17 +5007,6 @@ out: mmap_event->event_id.header.size = size; } -static int perf_event_mmap_match(struct perf_event *event, - void *data) -{ - struct perf_mmap_event *mmap_event = data; - struct vm_area_struct *vma = mmap_event->vma; - int executable = vma->vm_flags & VM_EXEC; - - return (!executable && event->attr.mmap_data) || - (executable && event->attr.mmap); -} - static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) { struct vm_area_struct *vma = mmap_event->vma; @@ -5070,8 +5070,7 @@ got_name: mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; - perf_event_aux(perf_event_mmap_match, - perf_event_mmap_output, + perf_event_aux(perf_event_mmap_output, mmap_event, NULL); From a51805efae5dda0da66f79268ffcf0715f9dbea4 Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Mon, 8 Jul 2013 14:23:49 -0700 Subject: [PATCH 0148/6183] lockdep: Introduce lock_acquire_exclusive()/shared() helper macros In lockdep.h, the spinlock/mutex/rwsem/rwlock/lock_map acquire macros have different definitions based on the value of CONFIG_PROVE_LOCKING. We have separate ifdefs for each of these definitions, which seems redundant. Introduce lock_acquire_{exclusive,shared,shared_recursive} helpers which will have different definitions based on CONFIG_PROVE_LOCKING. Then all other helper macros can be defined based on the above ones, which reduces the amount of ifdefined code. Signed-off-by: Michel Lespinasse Signed-off-by: Andrew Morton Signed-off-by: Peter Zijlstra Cc: Oleg Nesterov Cc: Lai Jiangshan Cc: "Srivatsa S. Bhat" Cc: Rusty Russell Cc: Andi Kleen Cc: "Paul E. McKenney" Cc: Steven Rostedt Link: http://lkml.kernel.org/r/20130708212350.6DD1931C15E@corp2gmr1-1.hot.corp.google.com Signed-off-by: Ingo Molnar --- include/linux/lockdep.h | 92 +++++++++++------------------------------ 1 file changed, 23 insertions(+), 69 deletions(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index f1e877b79ed8..cfc2f119779a 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -365,7 +365,7 @@ extern void lockdep_trace_alloc(gfp_t mask); #define lockdep_recursing(tsk) ((tsk)->lockdep_recursion) -#else /* !LOCKDEP */ +#else /* !CONFIG_LOCKDEP */ static inline void lockdep_off(void) { @@ -479,82 +479,36 @@ static inline void print_irqtrace_events(struct task_struct *curr) * on the per lock-class debug mode: */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, NULL, i) -# define spin_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 2, n, i) -# else -# define spin_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, NULL, i) -# define spin_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, NULL, i) -# endif -# define spin_release(l, n, i) lock_release(l, n, i) +#ifdef CONFIG_PROVE_LOCKING + #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 2, n, i) + #define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 2, n, i) + #define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 2, n, i) #else -# define spin_acquire(l, s, t, i) do { } while (0) -# define spin_release(l, n, i) do { } while (0) + #define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) + #define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 1, n, i) + #define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 1, n, i) #endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, NULL, i) -# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 2, NULL, i) -# else -# define rwlock_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, NULL, i) -# define rwlock_acquire_read(l, s, t, i) lock_acquire(l, s, t, 2, 1, NULL, i) -# endif -# define rwlock_release(l, n, i) lock_release(l, n, i) -#else -# define rwlock_acquire(l, s, t, i) do { } while (0) -# define rwlock_acquire_read(l, s, t, i) do { } while (0) -# define rwlock_release(l, n, i) do { } while (0) -#endif +#define spin_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) +#define spin_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) +#define spin_release(l, n, i) lock_release(l, n, i) -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, NULL, i) -# define mutex_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 2, n, i) -# else -# define mutex_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, NULL, i) -# define mutex_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) -# endif -# define mutex_release(l, n, i) lock_release(l, n, i) -#else -# define mutex_acquire(l, s, t, i) do { } while (0) -# define mutex_acquire_nest(l, s, t, n, i) do { } while (0) -# define mutex_release(l, n, i) do { } while (0) -#endif +#define rwlock_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) +#define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) +#define rwlock_release(l, n, i) lock_release(l, n, i) -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 2, NULL, i) -# define rwsem_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 2, n, i) -# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 2, NULL, i) -# else -# define rwsem_acquire(l, s, t, i) lock_acquire(l, s, t, 0, 1, NULL, i) -# define rwsem_acquire_nest(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) -# define rwsem_acquire_read(l, s, t, i) lock_acquire(l, s, t, 1, 1, NULL, i) -# endif +#define mutex_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) +#define mutex_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) +#define mutex_release(l, n, i) lock_release(l, n, i) + +#define rwsem_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) +#define rwsem_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) +#define rwsem_acquire_read(l, s, t, i) lock_acquire_shared(l, s, t, NULL, i) # define rwsem_release(l, n, i) lock_release(l, n, i) -#else -# define rwsem_acquire(l, s, t, i) do { } while (0) -# define rwsem_acquire_nest(l, s, t, n, i) do { } while (0) -# define rwsem_acquire_read(l, s, t, i) do { } while (0) -# define rwsem_release(l, n, i) do { } while (0) -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# ifdef CONFIG_PROVE_LOCKING -# define lock_map_acquire(l) lock_acquire(l, 0, 0, 0, 2, NULL, _THIS_IP_) -# define lock_map_acquire_read(l) lock_acquire(l, 0, 0, 2, 2, NULL, _THIS_IP_) -# else -# define lock_map_acquire(l) lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_) -# define lock_map_acquire_read(l) lock_acquire(l, 0, 0, 2, 1, NULL, _THIS_IP_) -# endif +#define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) +#define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) # define lock_map_release(l) lock_release(l, 1, _THIS_IP_) -#else -# define lock_map_acquire(l) do { } while (0) -# define lock_map_acquire_read(l) do { } while (0) -# define lock_map_release(l) do { } while (0) -#endif #ifdef CONFIG_PROVE_LOCKING # define might_lock(lock) \ From c4be9cb4f19cbd534a6c4c334cd48d8bb483e17a Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Mon, 8 Jul 2013 14:23:51 -0700 Subject: [PATCH 0149/6183] lglock: Update lockdep annotations to report recursive local locks Oleg Nesterov recently noticed that the lockdep annotations in lglock.c are not sufficient to detect some obvious deadlocks, such as lg_local_lock(LOCK) + lg_local_lock(LOCK) or spin_lock(X) + lg_local_lock(Y) vs lg_local_lock(Y) + spin_lock(X). Both issues are easily fixed by indicating to lockdep that lglock's local locks are not recursive. We shouldn't use the rwlock acquire/release functions here, as lglock doesn't share the same semantics. Instead we can base our lockdep annotations on the lock_acquire_shared (for local lglock) and lock_acquire_exclusive (for global lglock) helpers. I am not proposing new lglock specific helpers as I don't see the point of the existing second level of helpers :) Noticed-by: Oleg Nesterov Signed-off-by: Michel Lespinasse Cc: Lai Jiangshan Cc: "Srivatsa S. Bhat" Cc: Rusty Russell Cc: Andi Kleen Cc: "Paul E. McKenney" Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20130708212352.1769031C15E@corp2gmr1-1.hot.corp.google.com Signed-off-by: Ingo Molnar --- kernel/lglock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/lglock.c b/kernel/lglock.c index 6535a667a5a7..86ae2aebf004 100644 --- a/kernel/lglock.c +++ b/kernel/lglock.c @@ -21,7 +21,7 @@ void lg_local_lock(struct lglock *lg) arch_spinlock_t *lock; preempt_disable(); - rwlock_acquire_read(&lg->lock_dep_map, 0, 0, _RET_IP_); + lock_acquire_shared(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_); lock = this_cpu_ptr(lg->lock); arch_spin_lock(lock); } @@ -31,7 +31,7 @@ void lg_local_unlock(struct lglock *lg) { arch_spinlock_t *lock; - rwlock_release(&lg->lock_dep_map, 1, _RET_IP_); + lock_release(&lg->lock_dep_map, 1, _RET_IP_); lock = this_cpu_ptr(lg->lock); arch_spin_unlock(lock); preempt_enable(); @@ -43,7 +43,7 @@ void lg_local_lock_cpu(struct lglock *lg, int cpu) arch_spinlock_t *lock; preempt_disable(); - rwlock_acquire_read(&lg->lock_dep_map, 0, 0, _RET_IP_); + lock_acquire_shared(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_); lock = per_cpu_ptr(lg->lock, cpu); arch_spin_lock(lock); } @@ -53,7 +53,7 @@ void lg_local_unlock_cpu(struct lglock *lg, int cpu) { arch_spinlock_t *lock; - rwlock_release(&lg->lock_dep_map, 1, _RET_IP_); + lock_release(&lg->lock_dep_map, 1, _RET_IP_); lock = per_cpu_ptr(lg->lock, cpu); arch_spin_unlock(lock); preempt_enable(); @@ -65,7 +65,7 @@ void lg_global_lock(struct lglock *lg) int i; preempt_disable(); - rwlock_acquire(&lg->lock_dep_map, 0, 0, _RET_IP_); + lock_acquire_exclusive(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_); for_each_possible_cpu(i) { arch_spinlock_t *lock; lock = per_cpu_ptr(lg->lock, i); @@ -78,7 +78,7 @@ void lg_global_unlock(struct lglock *lg) { int i; - rwlock_release(&lg->lock_dep_map, 1, _RET_IP_); + lock_release(&lg->lock_dep_map, 1, _RET_IP_); for_each_possible_cpu(i) { arch_spinlock_t *lock; lock = per_cpu_ptr(lg->lock, i); From cedce3e730833d26a37826a96e1905b6ef387df9 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Thu, 4 Jul 2013 22:48:20 +0400 Subject: [PATCH 0150/6183] sched/__wake_up_sync_key(): Fix nr_exclusive tasks which lead to WF_SYNC clearing Only one task can replace the waker. Signed-off-by: Kirill Tkhai CC: Steven Rostedt Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/512421372963700@web25f.yandex.ru Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0d8eb4525e76..f73787159188 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2660,7 +2660,7 @@ void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, if (unlikely(!q)) return; - if (unlikely(!nr_exclusive)) + if (unlikely(nr_exclusive != 1)) wake_flags = 0; spin_lock_irqsave(&q->lock, flags); From 53b914084950e5766b40228c4e08706e28745fa5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 12 Jul 2013 16:24:40 +0100 Subject: [PATCH 0151/6183] drm/i915: Don't attempt to read an unitialized stack value If intel_sdvo_get_value() fails here, val is unitialized and the cross check will compare the pipe config multiplier with a bogus value. Instead, only set encoder_pixel_multiplier when the sdvo command has been successful. The cross check will compare the pipe config value with 0 otherwise. v2: Do the cross check with the initial value of encoder_pixel_multiplier (0) if the sdvo command fails (and thus keep the warning) (Daniel Vetter) Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 8415d6a610dd..798df114cfd3 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1357,17 +1357,19 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, } /* Cross check the port pixel multiplier with the sdvo encoder state. */ - intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1); - switch (val) { - case SDVO_CLOCK_RATE_MULT_1X: - encoder_pixel_multiplier = 1; - break; - case SDVO_CLOCK_RATE_MULT_2X: - encoder_pixel_multiplier = 2; - break; - case SDVO_CLOCK_RATE_MULT_4X: - encoder_pixel_multiplier = 4; - break; + if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, + &val, 1)) { + switch (val) { + case SDVO_CLOCK_RATE_MULT_1X: + encoder_pixel_multiplier = 1; + break; + case SDVO_CLOCK_RATE_MULT_2X: + encoder_pixel_multiplier = 2; + break; + case SDVO_CLOCK_RATE_MULT_4X: + encoder_pixel_multiplier = 4; + break; + } } WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier, From ec1e7e437ac47ecf7b4e07241036b1e1c3366012 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Wed, 22 May 2013 17:42:38 -0700 Subject: [PATCH 0152/6183] perf tools: Rename cpu_map__all() to cpu_map__empty() The CPU map is in an "empty" (or not-applicable) state when monitoring specific threads. cpu_map__all() returns true if the CPU map is in this empty state (i.e for the 'empty_cpu_map' or if we created the map via cpu_map__dummy_new(). The name, cpu_map__all(), is misleading, because even when monitoring all CPUs, (eg: perf record -a), cpu_map__all() returns false. Rename cpu_map__all() to cpu_map__empty(). Signed-off-by: Sukadev Bhattiprolu Cc: Jiri Olsa Link: http://lkml.kernel.org/r/20130523012620.GA27733@us.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.h | 2 +- tools/perf/util/evlist.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 9bed02e5fb3d..b123bb9d6f55 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map) return map ? map->nr : 1; } -static inline bool cpu_map__all(const struct cpu_map *map) +static inline bool cpu_map__empty(const struct cpu_map *map) { return map ? map->map[0] == -1 : true; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 8065ce8fa9a5..4a901be599ed 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -421,7 +421,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) { evlist->nr_mmaps = cpu_map__nr(evlist->cpus); - if (cpu_map__all(evlist->cpus)) + if (cpu_map__empty(evlist->cpus)) evlist->nr_mmaps = thread_map__nr(evlist->threads); evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); return evlist->mmap != NULL ? 0 : -ENOMEM; @@ -573,7 +573,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, return -ENOMEM; } - if (cpu_map__all(cpus)) + if (cpu_map__empty(cpus)) return perf_evlist__mmap_per_thread(evlist, prot, mask); return perf_evlist__mmap_per_cpu(evlist, prot, mask); From 0d3942dbcf7f7e8955ba89deed4749b0ad64d721 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Tue, 14 May 2013 22:56:51 -0700 Subject: [PATCH 0153/6183] perf top: Add --objdump option perf: Add objdump option to 'perf top' Like with 'perf annotate' add the --objdump option to perf top so users can specify an alternate path to the /usr/bin/objdump binary. Reported-by: David A. Gilbert Signed-off-by: Sukadev Bhattiprolu Cc: DavidAGilbert@uk.ibm.com Cc: Jiri Olsa Cc: Maynard Johnson Link: http://lkml.kernel.org/r/20130515055651.GA9985@us.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e06c4f869330..a237059f51cf 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -40,6 +40,7 @@ #include "util/xyarray.h" #include "util/sort.h" #include "util/intlist.h" +#include "arch/common.h" #include "util/debug.h" @@ -939,6 +940,12 @@ static int __cmd_top(struct perf_top *top) if (top->session == NULL) return -ENOMEM; + if (!objdump_path) { + ret = perf_session_env__lookup_objdump(&top->session->header.env); + if (ret) + goto out_delete; + } + ret = perf_top__setup_sample_type(top); if (ret) goto out_delete; @@ -1114,6 +1121,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "Interleave source code with assembly code (default)"), OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, "Display raw encoding of assembly instructions (default)"), + OPT_STRING(0, "objdump", &objdump_path, "path", + "objdump binary to use for disassembly and annotations"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), From eb4fe9cbb1599a673bde0d6dad50e609404275c7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 7 Jun 2013 15:37:01 +0200 Subject: [PATCH 0154/6183] perf tools: Remove cwd from perf_session struct Removing 'cwd' from perf_session struct as it's no longer needed. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370612223-19188-1-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index f3b235ec7bf4..ad8d3d4ef14e 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -37,7 +37,6 @@ struct perf_session { int fd; bool fd_pipe; bool repipe; - char *cwd; struct ordered_samples ordered_samples; char filename[1]; }; From 5888a8c26e5f8e76334d579637f9ed55036cec5a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 7 Jun 2013 15:37:02 +0200 Subject: [PATCH 0155/6183] perf tests: Omit end of the symbol check failure for test 1 Omitting end of the function check failure for test 1, since there's no way to get exact symbol end via kallsyms. Leaving the debug message. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370612223-19188-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/vmlinux-kallsyms.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 7b4c4d26d1ba..add15392c622 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -139,11 +139,18 @@ next_pair: * _really_ have a problem. */ s64 skew = sym->end - pair->end; - if (llabs(skew) < page_size) - continue; + if (llabs(skew) >= page_size) + pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", + sym->start, sym->name, sym->end, pair->end); + + /* + * Do not count this as a failure, because we + * could really find a case where it's not + * possible to get proper function end from + * kallsyms. + */ + continue; - pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", - sym->start, sym->name, sym->end, pair->end); } else { struct rb_node *nnd; detour: From 450ac18d8f8076f0c522af1afb8519614a3b32f5 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 7 Jun 2013 15:37:03 +0200 Subject: [PATCH 0156/6183] perf tests: Make TEST_ASSERT_VAL global Making TEST_ASSERT_VAL global as it's used in multiple objects. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370612223-19188-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/dso-data.c | 8 -------- tools/perf/tests/parse-events.c | 8 -------- tools/perf/tests/tests.h | 8 ++++++++ 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 5eaffa2de9c5..dffe0551acaa 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -10,14 +10,6 @@ #include "symbol.h" #include "tests.h" -#define TEST_ASSERT_VAL(text, cond) \ -do { \ - if (!(cond)) { \ - pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ - return -1; \ - } \ -} while (0) - static char *test_file(int size) { static char buf_templ[] = "/tmp/test-XXXXXX"; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0275bab4ea9e..ad950f57d85b 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -7,14 +7,6 @@ #include "tests.h" #include -#define TEST_ASSERT_VAL(text, cond) \ -do { \ - if (!(cond)) { \ - pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ - return -1; \ - } \ -} while (0) - #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index dd7feae2d37b..07a92f9c6712 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -1,6 +1,14 @@ #ifndef TESTS_H #define TESTS_H +#define TEST_ASSERT_VAL(text, cond) \ +do { \ + if (!(cond)) { \ + pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ + return -1; \ + } \ +} while (0) + enum { TEST_OK = 0, TEST_FAIL = -1, From 4e319027a7aee58ce8d409f5597b418f08307841 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 11 Jun 2013 17:29:18 +0200 Subject: [PATCH 0157/6183] perf tools: Use default include path notation for libtraceevent headers Header files of libtraceevent or no longer local headers. Thus, use default path notation for them. Also removing extra traceevent include path and instead handle this similar to liblk. Signed-off-by: Robert Richter Signed-off-by: Robert Richter Cc: Ingo Molnar Cc: Jiri Olsa Cc: Robert Richter Link: http://lkml.kernel.org/r/1370964558-8599-1-git-send-email-rric@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/config/Makefile | 5 +++-- tools/perf/tests/evsel-tp-sched.c | 2 +- tools/perf/util/evsel.c | 8 ++++---- tools/perf/util/session.c | 2 +- tools/perf/util/trace-event.h | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 641fccddb249..5b7c6db87fde 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -281,7 +281,7 @@ LIB_H += util/cpumap.h LIB_H += util/top.h LIB_H += $(ARCH_INCLUDE) LIB_H += util/cgroup.h -LIB_H += $(TRACE_EVENT_DIR)event-parse.h +LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h LIB_H += util/target.h LIB_H += util/rblist.h LIB_H += util/intlist.h diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ab3ed4af1466..87fc7d08ca02 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1,3 +1,4 @@ +#include #include "builtin.h" #include "util/color.h" #include "util/evlist.h" @@ -5,7 +6,6 @@ #include "util/thread.h" #include "util/parse-options.h" #include "util/thread_map.h" -#include "event-parse.h" #include #include diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index b5d9238cb181..214e17e97e5c 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -46,6 +46,8 @@ ifneq ($(obj-perf),) obj-perf := $(abspath $(obj-perf))/ endif +LIB_INCLUDE := $(srctree)/tools/lib/ + # include ARCH specific config -include $(src-perf)/arch/$(ARCH)/Makefile @@ -121,8 +123,7 @@ endif CFLAGS += -I$(src-perf)/util CFLAGS += -I$(src-perf) -CFLAGS += -I$(TRACE_EVENT_DIR) -CFLAGS += -I$(srctree)/tools/lib/ +CFLAGS += -I$(LIB_INCLUDE) CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index a5d2fcc5ae35..f79e7d059820 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -1,6 +1,6 @@ +#include #include "evsel.h" #include "tests.h" -#include "event-parse.h" static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, int size, bool should_be_signed) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c9c7494506a1..a6354619fa5d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -9,17 +9,17 @@ #include #include -#include "asm/bug.h" #include -#include "event-parse.h" +#include +#include +#include +#include "asm/bug.h" #include "evsel.h" #include "evlist.h" #include "util.h" #include "cpumap.h" #include "thread_map.h" #include "target.h" -#include -#include #include "perf_regs.h" static struct { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index cf1fe01b7e89..ad47fb9d0204 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,7 +13,6 @@ #include "sort.h" #include "util.h" #include "cpumap.h" -#include "event-parse.h" #include "perf_regs.h" #include "vdso.h" diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 1978c398ad87..11eb7fd37608 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -1,8 +1,8 @@ #ifndef _PERF_UTIL_TRACE_EVENT_H #define _PERF_UTIL_TRACE_EVENT_H +#include #include "parse-events.h" -#include "event-parse.h" #include "session.h" struct machine; From ba58041a8f0f0437c6c33414aa0d3fcf62ba90a5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 7 Jun 2013 16:22:12 -0600 Subject: [PATCH 0158/6183] perf tools: Add methods for setting/retrieving priv element of thread struct Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1370643734-9579-3-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/thread.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index eeb7ac62b9e3..5e7ba35a5517 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -47,4 +47,14 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine, u8 cpumode, enum map_type type, u64 addr, struct addr_location *al, symbol_filter_t filter); + +static inline void *thread__priv(struct thread *thread) +{ + return thread->priv; +} + +static inline void thread__set_priv(struct thread *thread, void *p) +{ + thread->priv = p; +} #endif /* __PERF_THREAD_H */ From fa1531fdd7b6332aa61bcc9fda495583acba460d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 10 Jun 2013 16:31:28 -0400 Subject: [PATCH 0159/6183] perf tools: Remove callchain_cursor_reset call Removing callchain_cursor_reset call as it is called in subsequent machine__resolve_callchain_sample function. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-ic53wabwmmgvvwve2ymv3yf7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b2ecad6ec46b..93527afb09d5 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1242,8 +1242,6 @@ int machine__resolve_callchain(struct machine *machine, { int ret; - callchain_cursor_reset(&callchain_cursor); - ret = machine__resolve_callchain_sample(machine, thread, sample->callchain, parent); if (ret) From 167aedc44e1743777e6aee71b0fe7ed94c6298cd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 26 Jun 2013 16:14:04 +0900 Subject: [PATCH 0160/6183] perf util: Move debugfs/tracing helper functions to util.c Since they're generic helpers move them to util.c so that they can be used by others. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1372230862-15861-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-info.c | 59 ------------------------------ tools/perf/util/util.c | 59 ++++++++++++++++++++++++++++++ tools/perf/util/util.h | 3 ++ 3 files changed, 62 insertions(+), 59 deletions(-) diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 3917eb9a8479..615c0628678b 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -46,65 +46,6 @@ static int output_fd; -static const char *find_debugfs(void) -{ - const char *path = perf_debugfs_mount(NULL); - - if (!path) - pr_debug("Your kernel does not support the debugfs filesystem"); - - return path; -} - -/* - * Finds the path to the debugfs/tracing - * Allocates the string and stores it. - */ -static const char *find_tracing_dir(void) -{ - static char *tracing; - static int tracing_found; - const char *debugfs; - - if (tracing_found) - return tracing; - - debugfs = find_debugfs(); - if (!debugfs) - return NULL; - - tracing = malloc(strlen(debugfs) + 9); - if (!tracing) - return NULL; - - sprintf(tracing, "%s/tracing", debugfs); - - tracing_found = 1; - return tracing; -} - -static char *get_tracing_file(const char *name) -{ - const char *tracing; - char *file; - - tracing = find_tracing_dir(); - if (!tracing) - return NULL; - - file = malloc(strlen(tracing) + strlen(name) + 2); - if (!file) - return NULL; - - sprintf(file, "%s/%s", tracing, name); - return file; -} - -static void put_tracing_file(char *file) -{ - free(file); -} - int bigendian(void) { unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 59d868add275..9a0658405760 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -269,3 +269,62 @@ void perf_debugfs_set_path(const char *mntpt) snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); set_tracing_events_path(mntpt); } + +static const char *find_debugfs(void) +{ + const char *path = perf_debugfs_mount(NULL); + + if (!path) + fprintf(stderr, "Your kernel does not support the debugfs filesystem"); + + return path; +} + +/* + * Finds the path to the debugfs/tracing + * Allocates the string and stores it. + */ +const char *find_tracing_dir(void) +{ + static char *tracing; + static int tracing_found; + const char *debugfs; + + if (tracing_found) + return tracing; + + debugfs = find_debugfs(); + if (!debugfs) + return NULL; + + tracing = malloc(strlen(debugfs) + 9); + if (!tracing) + return NULL; + + sprintf(tracing, "%s/tracing", debugfs); + + tracing_found = 1; + return tracing; +} + +char *get_tracing_file(const char *name) +{ + const char *tracing; + char *file; + + tracing = find_tracing_dir(); + if (!tracing) + return NULL; + + file = malloc(strlen(tracing) + strlen(name) + 2); + if (!file) + return NULL; + + sprintf(file, "%s/%s", tracing, name); + return file; +} + +void put_tracing_file(char *file) +{ + free(file); +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 2732fad03908..cc1574edcd9a 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -80,6 +80,9 @@ extern char buildid_dir[]; extern char tracing_events_path[]; extern void perf_debugfs_set_path(const char *mountpoint); const char *perf_debugfs_mount(const char *mountpoint); +const char *find_tracing_dir(void); +char *get_tracing_file(const char *name); +void put_tracing_file(char *file); /* On most systems would have given us this, but * not on some systems (e.g. GNU/Hurd). From e7c93f09b83be25281cf129674e0035664715033 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 26 Jun 2013 16:14:05 +0900 Subject: [PATCH 0161/6183] perf util: Use evsel->name to get tracepoint_paths Most tracepoint events already have their system and event name in ->name field so that searching whole event tracing directory for each evsel to match given id is suboptimal. Factor out this routine into tracepoint_name_to_path(). In case of en invalid name, it'll try to find path using id again. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1372230862-15861-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 23 +++++++++++++++++++++++ tools/perf/util/parse-events.h | 1 + tools/perf/util/trace-event-info.c | 15 +++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 995fc25db8c6..ef72e98a07a6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -217,6 +217,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) return NULL; } +struct tracepoint_path *tracepoint_name_to_path(const char *name) +{ + struct tracepoint_path *path = zalloc(sizeof(*path)); + char *str = strchr(name, ':'); + + if (path == NULL || str == NULL) { + free(path); + return NULL; + } + + path->system = strndup(name, str - name); + path->name = strdup(str+1); + + if (path->system == NULL || path->name == NULL) { + free(path->system); + free(path->name); + free(path); + path = NULL; + } + + return path; +} + const char *event_type(int type) { switch (type) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 8a4859315fd9..080f7cf25d99 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -23,6 +23,7 @@ struct tracepoint_path { }; extern struct tracepoint_path *tracepoint_id_to_path(u64 config); +extern struct tracepoint_path *tracepoint_name_to_path(const char *name); extern bool have_tracepoints(struct list_head *evlist); const char *event_type(int type); diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 615c0628678b..a42624a6cb5c 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -414,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs) if (pos->attr.type != PERF_TYPE_TRACEPOINT) continue; ++nr_tracepoints; + + if (pos->name) { + ppath->next = tracepoint_name_to_path(pos->name); + if (ppath->next) + goto next; + + if (strchr(pos->name, ':') == NULL) + goto try_id; + + goto error; + } + +try_id: ppath->next = tracepoint_id_to_path(pos->attr.config); if (!ppath->next) { +error: pr_debug("No memory to alloc tracepoints list\n"); put_tracepoints_path(&path); return NULL; } +next: ppath = ppath->next; } From ad3d6f508738323c0e843c4dbdd421c1aeb59cd8 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 17 Jun 2013 18:02:43 +0200 Subject: [PATCH 0162/6183] perf tools: Do not elide parent symbol column I found the parent symbol column data interesting even if there's another sorting enabled. Switching it on. Previous behaviour: $ perf report -i perf.data.delete -p perf_session__delete -x + 3.60% perf perf [.] __rb_change_child + 1.89% perf perf [.] rb_erase + 1.89% perf perf [.] rb_erase + 1.83% perf perf [.] free@plt Current behaviour: $ perf report -i perf.data.delete -p perf_session__delete -x + 3.60% perf perf [.] __rb_change_child perf_session__delete + 1.89% perf perf [.] rb_erase perf_session__delete_dead_threads + 1.89% perf perf [.] rb_erase perf_session__delete_threads + 1.83% perf perf [.] free@plt perf_session__delete Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-r79fn89bhqz16ixa5zmyflrd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3662047cc6b1..6ab49dafef25 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -931,14 +931,6 @@ repeat: if (parent_pattern != default_parent_pattern) { if (sort_dimension__add("parent") < 0) goto error; - - /* - * Only show the parent fields if we explicitly - * sort that way. If we only use parent machinery - * for filtering, we don't want it. - */ - if (!strstr(sort_order, "parent")) - sort_parent.elide = 1; } if (argc) { From d4ae0a6f7c79be64c8f3551dd149189f8c4480eb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 25 Jun 2013 13:54:13 +0200 Subject: [PATCH 0163/6183] perf report: Fix perf_session__delete removal There's no point of having out_delete label with perf_session__delete call within __cmd_report function, because it's called at the end of the cmd_report function. The speed up due to commenting out the perf_session__delete at the end does not seem relevant anymore. Measured speedup for ~1GB data file with 222466 FORKS events is around 0.5%. $ perf report -i perf.data.delete -P perf_session__delete -s parent + 99.51% [other] + 0.49% perf_session__delete Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372161253-22081-6-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6ab49dafef25..ee2ca3eb22df 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep) ret = perf_session__cpu_bitmap(session, rep->cpu_list, rep->cpu_bitmap); if (ret) - goto out_delete; + return ret; } if (use_browser <= 0) @@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep) ret = perf_report__setup_sample_type(rep); if (ret) - goto out_delete; + return ret; ret = perf_session__process_events(session, &rep->tool); if (ret) - goto out_delete; + return ret; kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; kernel_kmap = map__kmap(kernel_map); @@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep) if (dump_trace) { perf_session__fprintf_nr_events(session, stdout); - goto out_delete; + return 0; } nr_samples = 0; @@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep) if (nr_samples == 0) { ui__error("The %s file has no samples!\n", session->filename); - goto out_delete; + return 0; } list_for_each_entry(pos, &session->evlist->entries, node) @@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep) } else perf_evlist__tty_browse_hists(session->evlist, rep, help); -out_delete: - /* - * Speed up the exit process, for large files this can - * take quite a while. - * - * XXX Enable this when using valgrind or if we ever - * librarize this command. - * - * Also experiment with obstacks to see how much speed - * up we'll get here. - * - * perf_session__delete(session); - */ return ret; } From cfe0d8ba14a1d98245b371e486c68f37eba1ca52 Mon Sep 17 00:00:00 2001 From: Runzhen Wang Date: Fri, 28 Jun 2013 16:14:57 +0800 Subject: [PATCH 0164/6183] perf tools: Make Power7 events available for perf Power7 supports over 530 different perf events but only a small subset of these can be specified by name, for the remaining events, we must specify them by their raw code: perf stat -e r2003c This patch makes all the POWER7 events available in sysfs. So we can instead specify these as: perf stat -e 'cpu/PM_CMPLU_STALL_DFU/' where PM_CMPLU_STALL_DFU is the r2003c in previous example. Before this patch is applied, the size of power7-pmu.o is: $ size arch/powerpc/perf/power7-pmu.o text data bss dec hex filename 3073 2720 0 5793 16a1 arch/powerpc/perf/power7-pmu.o and after the patch is applied, it is: $ size arch/powerpc/perf/power7-pmu.o text data bss dec hex filename 15950 31112 0 47062 b7d6 arch/powerpc/perf/power7-pmu.o For the run time overhead, I use two scripts, one is "event_name.sh", which contains 50 event names, it looks like: # ./perf record -e 'cpu/PM_CMPLU_STALL_DFU/' -e ..... /bin/sleep 1 the other one is named "event_code.sh" which use corresponding events raw code instead of events names, it looks like: # ./perf record -e r2003c -e ...... /bin/sleep 1 below is the result. Using events name: [root@localhost perf]# time ./event_name.sh [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.002 MB perf.data (~102 samples) ] real 0m1.192s user 0m0.028s sys 0m0.106s Using events raw code: [root@localhost perf]# time ./event_code.sh [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.003 MB perf.data (~112 samples) ] real 0m1.198s user 0m0.028s sys 0m0.105s Signed-off-by: Runzhen Wang Acked-by: Michael Ellerman Cc: icycoder@gmail.com Cc: linuxppc-dev@lists.ozlabs.org Cc: Michael Ellerman Cc: Paul Mackerras Cc: Runzhen Wang Cc: Sukadev Bhattiprolu Cc: Xiao Guangrong Link: http://lkml.kernel.org/r/1372407297-6996-3-git-send-email-runzhen@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/powerpc/include/asm/perf_event_server.h | 4 +- arch/powerpc/perf/power7-events-list.h | 548 +++++++++++++++++++ arch/powerpc/perf/power7-pmu.c | 140 +---- 3 files changed, 578 insertions(+), 114 deletions(-) create mode 100644 arch/powerpc/perf/power7-events-list.h diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index f265049dd7d6..d9270d8eb087 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -136,11 +136,11 @@ extern ssize_t power_events_sysfs_show(struct device *dev, #define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr #define EVENT_ATTR(_name, _id, _suffix) \ - PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id, \ + PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_##_id, \ power_events_sysfs_show) #define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _g) #define GENERIC_EVENT_PTR(_id) EVENT_PTR(_id, _g) -#define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(PM_##_name, _id, _p) +#define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _p) #define POWER_EVENT_PTR(_id) EVENT_PTR(_id, _p) diff --git a/arch/powerpc/perf/power7-events-list.h b/arch/powerpc/perf/power7-events-list.h new file mode 100644 index 000000000000..687790a2c0b8 --- /dev/null +++ b/arch/powerpc/perf/power7-events-list.h @@ -0,0 +1,548 @@ +/* + * Performance counter support for POWER7 processors. + * + * Copyright 2013 Runzhen Wang, 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. + */ + +EVENT(PM_IC_DEMAND_L2_BR_ALL, 0x04898) +EVENT(PM_GCT_UTIL_7_TO_10_SLOTS, 0x020a0) +EVENT(PM_PMC2_SAVED, 0x10022) +EVENT(PM_CMPLU_STALL_DFU, 0x2003c) +EVENT(PM_VSU0_16FLOP, 0x0a0a4) +EVENT(PM_MRK_LSU_DERAT_MISS, 0x3d05a) +EVENT(PM_MRK_ST_CMPL, 0x10034) +EVENT(PM_NEST_PAIR3_ADD, 0x40881) +EVENT(PM_L2_ST_DISP, 0x46180) +EVENT(PM_L2_CASTOUT_MOD, 0x16180) +EVENT(PM_ISEG, 0x020a4) +EVENT(PM_MRK_INST_TIMEO, 0x40034) +EVENT(PM_L2_RCST_DISP_FAIL_ADDR, 0x36282) +EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM, 0x0d0b6) +EVENT(PM_IERAT_WR_64K, 0x040be) +EVENT(PM_MRK_DTLB_MISS_16M, 0x4d05e) +EVENT(PM_IERAT_MISS, 0x100f6) +EVENT(PM_MRK_PTEG_FROM_LMEM, 0x4d052) +EVENT(PM_FLOP, 0x100f4) +EVENT(PM_THRD_PRIO_4_5_CYC, 0x040b4) +EVENT(PM_BR_PRED_TA, 0x040aa) +EVENT(PM_CMPLU_STALL_FXU, 0x20014) +EVENT(PM_EXT_INT, 0x200f8) +EVENT(PM_VSU_FSQRT_FDIV, 0x0a888) +EVENT(PM_MRK_LD_MISS_EXPOSED_CYC, 0x1003e) +EVENT(PM_LSU1_LDF, 0x0c086) +EVENT(PM_IC_WRITE_ALL, 0x0488c) +EVENT(PM_LSU0_SRQ_STFWD, 0x0c0a0) +EVENT(PM_PTEG_FROM_RL2L3_MOD, 0x1c052) +EVENT(PM_MRK_DATA_FROM_L31_SHR, 0x1d04e) +EVENT(PM_DATA_FROM_L21_MOD, 0x3c046) +EVENT(PM_VSU1_SCAL_DOUBLE_ISSUED, 0x0b08a) +EVENT(PM_VSU0_8FLOP, 0x0a0a0) +EVENT(PM_POWER_EVENT1, 0x1006e) +EVENT(PM_DISP_CLB_HELD_BAL, 0x02092) +EVENT(PM_VSU1_2FLOP, 0x0a09a) +EVENT(PM_LWSYNC_HELD, 0x0209a) +EVENT(PM_PTEG_FROM_DL2L3_SHR, 0x3c054) +EVENT(PM_INST_FROM_L21_MOD, 0x34046) +EVENT(PM_IERAT_XLATE_WR_16MPLUS, 0x040bc) +EVENT(PM_IC_REQ_ALL, 0x04888) +EVENT(PM_DSLB_MISS, 0x0d090) +EVENT(PM_L3_MISS, 0x1f082) +EVENT(PM_LSU0_L1_PREF, 0x0d0b8) +EVENT(PM_VSU_SCALAR_SINGLE_ISSUED, 0x0b884) +EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE, 0x0d0be) +EVENT(PM_L2_INST, 0x36080) +EVENT(PM_VSU0_FRSP, 0x0a0b4) +EVENT(PM_FLUSH_DISP, 0x02082) +EVENT(PM_PTEG_FROM_L2MISS, 0x4c058) +EVENT(PM_VSU1_DQ_ISSUED, 0x0b09a) +EVENT(PM_CMPLU_STALL_LSU, 0x20012) +EVENT(PM_MRK_DATA_FROM_DMEM, 0x1d04a) +EVENT(PM_LSU_FLUSH_ULD, 0x0c8b0) +EVENT(PM_PTEG_FROM_LMEM, 0x4c052) +EVENT(PM_MRK_DERAT_MISS_16M, 0x3d05c) +EVENT(PM_THRD_ALL_RUN_CYC, 0x2000c) +EVENT(PM_MEM0_PREFETCH_DISP, 0x20083) +EVENT(PM_MRK_STALL_CMPLU_CYC_COUNT, 0x3003f) +EVENT(PM_DATA_FROM_DL2L3_MOD, 0x3c04c) +EVENT(PM_VSU_FRSP, 0x0a8b4) +EVENT(PM_MRK_DATA_FROM_L21_MOD, 0x3d046) +EVENT(PM_PMC1_OVERFLOW, 0x20010) +EVENT(PM_VSU0_SINGLE, 0x0a0a8) +EVENT(PM_MRK_PTEG_FROM_L3MISS, 0x2d058) +EVENT(PM_MRK_PTEG_FROM_L31_SHR, 0x2d056) +EVENT(PM_VSU0_VECTOR_SP_ISSUED, 0x0b090) +EVENT(PM_VSU1_FEST, 0x0a0ba) +EVENT(PM_MRK_INST_DISP, 0x20030) +EVENT(PM_VSU0_COMPLEX_ISSUED, 0x0b096) +EVENT(PM_LSU1_FLUSH_UST, 0x0c0b6) +EVENT(PM_INST_CMPL, 0x00002) +EVENT(PM_FXU_IDLE, 0x1000e) +EVENT(PM_LSU0_FLUSH_ULD, 0x0c0b0) +EVENT(PM_MRK_DATA_FROM_DL2L3_MOD, 0x3d04c) +EVENT(PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC, 0x3001c) +EVENT(PM_LSU1_REJECT_LMQ_FULL, 0x0c0a6) +EVENT(PM_INST_PTEG_FROM_L21_MOD, 0x3e056) +EVENT(PM_INST_FROM_RL2L3_MOD, 0x14042) +EVENT(PM_SHL_CREATED, 0x05082) +EVENT(PM_L2_ST_HIT, 0x46182) +EVENT(PM_DATA_FROM_DMEM, 0x1c04a) +EVENT(PM_L3_LD_MISS, 0x2f082) +EVENT(PM_FXU1_BUSY_FXU0_IDLE, 0x4000e) +EVENT(PM_DISP_CLB_HELD_RES, 0x02094) +EVENT(PM_L2_SN_SX_I_DONE, 0x36382) +EVENT(PM_GRP_CMPL, 0x30004) +EVENT(PM_STCX_CMPL, 0x0c098) +EVENT(PM_VSU0_2FLOP, 0x0a098) +EVENT(PM_L3_PREF_MISS, 0x3f082) +EVENT(PM_LSU_SRQ_SYNC_CYC, 0x0d096) +EVENT(PM_LSU_REJECT_ERAT_MISS, 0x20064) +EVENT(PM_L1_ICACHE_MISS, 0x200fc) +EVENT(PM_LSU1_FLUSH_SRQ, 0x0c0be) +EVENT(PM_LD_REF_L1_LSU0, 0x0c080) +EVENT(PM_VSU0_FEST, 0x0a0b8) +EVENT(PM_VSU_VECTOR_SINGLE_ISSUED, 0x0b890) +EVENT(PM_FREQ_UP, 0x4000c) +EVENT(PM_DATA_FROM_LMEM, 0x3c04a) +EVENT(PM_LSU1_LDX, 0x0c08a) +EVENT(PM_PMC3_OVERFLOW, 0x40010) +EVENT(PM_MRK_BR_MPRED, 0x30036) +EVENT(PM_SHL_MATCH, 0x05086) +EVENT(PM_MRK_BR_TAKEN, 0x10036) +EVENT(PM_CMPLU_STALL_BRU, 0x4004e) +EVENT(PM_ISLB_MISS, 0x0d092) +EVENT(PM_CYC, 0x0001e) +EVENT(PM_DISP_HELD_THERMAL, 0x30006) +EVENT(PM_INST_PTEG_FROM_RL2L3_SHR, 0x2e054) +EVENT(PM_LSU1_SRQ_STFWD, 0x0c0a2) +EVENT(PM_GCT_NOSLOT_BR_MPRED, 0x4001a) +EVENT(PM_1PLUS_PPC_CMPL, 0x100f2) +EVENT(PM_PTEG_FROM_DMEM, 0x2c052) +EVENT(PM_VSU_2FLOP, 0x0a898) +EVENT(PM_GCT_FULL_CYC, 0x04086) +EVENT(PM_MRK_DATA_FROM_L3_CYC, 0x40020) +EVENT(PM_LSU_SRQ_S0_ALLOC, 0x0d09d) +EVENT(PM_MRK_DERAT_MISS_4K, 0x1d05c) +EVENT(PM_BR_MPRED_TA, 0x040ae) +EVENT(PM_INST_PTEG_FROM_L2MISS, 0x4e058) +EVENT(PM_DPU_HELD_POWER, 0x20006) +EVENT(PM_RUN_INST_CMPL, 0x400fa) +EVENT(PM_MRK_VSU_FIN, 0x30032) +EVENT(PM_LSU_SRQ_S0_VALID, 0x0d09c) +EVENT(PM_GCT_EMPTY_CYC, 0x20008) +EVENT(PM_IOPS_DISP, 0x30014) +EVENT(PM_RUN_SPURR, 0x10008) +EVENT(PM_PTEG_FROM_L21_MOD, 0x3c056) +EVENT(PM_VSU0_1FLOP, 0x0a080) +EVENT(PM_SNOOP_TLBIE, 0x0d0b2) +EVENT(PM_DATA_FROM_L3MISS, 0x2c048) +EVENT(PM_VSU_SINGLE, 0x0a8a8) +EVENT(PM_DTLB_MISS_16G, 0x1c05e) +EVENT(PM_CMPLU_STALL_VECTOR, 0x2001c) +EVENT(PM_FLUSH, 0x400f8) +EVENT(PM_L2_LD_HIT, 0x36182) +EVENT(PM_NEST_PAIR2_AND, 0x30883) +EVENT(PM_VSU1_1FLOP, 0x0a082) +EVENT(PM_IC_PREF_REQ, 0x0408a) +EVENT(PM_L3_LD_HIT, 0x2f080) +EVENT(PM_GCT_NOSLOT_IC_MISS, 0x2001a) +EVENT(PM_DISP_HELD, 0x10006) +EVENT(PM_L2_LD, 0x16080) +EVENT(PM_LSU_FLUSH_SRQ, 0x0c8bc) +EVENT(PM_BC_PLUS_8_CONV, 0x040b8) +EVENT(PM_MRK_DATA_FROM_L31_MOD_CYC, 0x40026) +EVENT(PM_CMPLU_STALL_VECTOR_LONG, 0x4004a) +EVENT(PM_L2_RCST_BUSY_RC_FULL, 0x26282) +EVENT(PM_TB_BIT_TRANS, 0x300f8) +EVENT(PM_THERMAL_MAX, 0x40006) +EVENT(PM_LSU1_FLUSH_ULD, 0x0c0b2) +EVENT(PM_LSU1_REJECT_LHS, 0x0c0ae) +EVENT(PM_LSU_LRQ_S0_ALLOC, 0x0d09f) +EVENT(PM_L3_CO_L31, 0x4f080) +EVENT(PM_POWER_EVENT4, 0x4006e) +EVENT(PM_DATA_FROM_L31_SHR, 0x1c04e) +EVENT(PM_BR_UNCOND, 0x0409e) +EVENT(PM_LSU1_DC_PREF_STREAM_ALLOC, 0x0d0aa) +EVENT(PM_PMC4_REWIND, 0x10020) +EVENT(PM_L2_RCLD_DISP, 0x16280) +EVENT(PM_THRD_PRIO_2_3_CYC, 0x040b2) +EVENT(PM_MRK_PTEG_FROM_L2MISS, 0x4d058) +EVENT(PM_IC_DEMAND_L2_BHT_REDIRECT, 0x04098) +EVENT(PM_LSU_DERAT_MISS, 0x200f6) +EVENT(PM_IC_PREF_CANCEL_L2, 0x04094) +EVENT(PM_MRK_FIN_STALL_CYC_COUNT, 0x1003d) +EVENT(PM_BR_PRED_CCACHE, 0x040a0) +EVENT(PM_GCT_UTIL_1_TO_2_SLOTS, 0x0209c) +EVENT(PM_MRK_ST_CMPL_INT, 0x30034) +EVENT(PM_LSU_TWO_TABLEWALK_CYC, 0x0d0a6) +EVENT(PM_MRK_DATA_FROM_L3MISS, 0x2d048) +EVENT(PM_GCT_NOSLOT_CYC, 0x100f8) +EVENT(PM_LSU_SET_MPRED, 0x0c0a8) +EVENT(PM_FLUSH_DISP_TLBIE, 0x0208a) +EVENT(PM_VSU1_FCONV, 0x0a0b2) +EVENT(PM_DERAT_MISS_16G, 0x4c05c) +EVENT(PM_INST_FROM_LMEM, 0x3404a) +EVENT(PM_IC_DEMAND_L2_BR_REDIRECT, 0x0409a) +EVENT(PM_CMPLU_STALL_SCALAR_LONG, 0x20018) +EVENT(PM_INST_PTEG_FROM_L2, 0x1e050) +EVENT(PM_PTEG_FROM_L2, 0x1c050) +EVENT(PM_MRK_DATA_FROM_L21_SHR_CYC, 0x20024) +EVENT(PM_MRK_DTLB_MISS_4K, 0x2d05a) +EVENT(PM_VSU0_FPSCR, 0x0b09c) +EVENT(PM_VSU1_VECT_DOUBLE_ISSUED, 0x0b082) +EVENT(PM_MRK_PTEG_FROM_RL2L3_MOD, 0x1d052) +EVENT(PM_MEM0_RQ_DISP, 0x10083) +EVENT(PM_L2_LD_MISS, 0x26080) +EVENT(PM_VMX_RESULT_SAT_1, 0x0b0a0) +EVENT(PM_L1_PREF, 0x0d8b8) +EVENT(PM_MRK_DATA_FROM_LMEM_CYC, 0x2002c) +EVENT(PM_GRP_IC_MISS_NONSPEC, 0x1000c) +EVENT(PM_PB_NODE_PUMP, 0x10081) +EVENT(PM_SHL_MERGED, 0x05084) +EVENT(PM_NEST_PAIR1_ADD, 0x20881) +EVENT(PM_DATA_FROM_L3, 0x1c048) +EVENT(PM_LSU_FLUSH, 0x0208e) +EVENT(PM_LSU_SRQ_SYNC_COUNT, 0x0d097) +EVENT(PM_PMC2_OVERFLOW, 0x30010) +EVENT(PM_LSU_LDF, 0x0c884) +EVENT(PM_POWER_EVENT3, 0x3006e) +EVENT(PM_DISP_WT, 0x30008) +EVENT(PM_CMPLU_STALL_REJECT, 0x40016) +EVENT(PM_IC_BANK_CONFLICT, 0x04082) +EVENT(PM_BR_MPRED_CR_TA, 0x048ae) +EVENT(PM_L2_INST_MISS, 0x36082) +EVENT(PM_CMPLU_STALL_ERAT_MISS, 0x40018) +EVENT(PM_NEST_PAIR2_ADD, 0x30881) +EVENT(PM_MRK_LSU_FLUSH, 0x0d08c) +EVENT(PM_L2_LDST, 0x16880) +EVENT(PM_INST_FROM_L31_SHR, 0x1404e) +EVENT(PM_VSU0_FIN, 0x0a0bc) +EVENT(PM_LARX_LSU, 0x0c894) +EVENT(PM_INST_FROM_RMEM, 0x34042) +EVENT(PM_DISP_CLB_HELD_TLBIE, 0x02096) +EVENT(PM_MRK_DATA_FROM_DMEM_CYC, 0x2002e) +EVENT(PM_BR_PRED_CR, 0x040a8) +EVENT(PM_LSU_REJECT, 0x10064) +EVENT(PM_GCT_UTIL_3_TO_6_SLOTS, 0x0209e) +EVENT(PM_CMPLU_STALL_END_GCT_NOSLOT, 0x10028) +EVENT(PM_LSU0_REJECT_LMQ_FULL, 0x0c0a4) +EVENT(PM_VSU_FEST, 0x0a8b8) +EVENT(PM_NEST_PAIR0_AND, 0x10883) +EVENT(PM_PTEG_FROM_L3, 0x2c050) +EVENT(PM_POWER_EVENT2, 0x2006e) +EVENT(PM_IC_PREF_CANCEL_PAGE, 0x04090) +EVENT(PM_VSU0_FSQRT_FDIV, 0x0a088) +EVENT(PM_MRK_GRP_CMPL, 0x40030) +EVENT(PM_VSU0_SCAL_DOUBLE_ISSUED, 0x0b088) +EVENT(PM_GRP_DISP, 0x3000a) +EVENT(PM_LSU0_LDX, 0x0c088) +EVENT(PM_DATA_FROM_L2, 0x1c040) +EVENT(PM_MRK_DATA_FROM_RL2L3_MOD, 0x1d042) +EVENT(PM_LD_REF_L1, 0x0c880) +EVENT(PM_VSU0_VECT_DOUBLE_ISSUED, 0x0b080) +EVENT(PM_VSU1_2FLOP_DOUBLE, 0x0a08e) +EVENT(PM_THRD_PRIO_6_7_CYC, 0x040b6) +EVENT(PM_BC_PLUS_8_RSLV_TAKEN, 0x040ba) +EVENT(PM_BR_MPRED_CR, 0x040ac) +EVENT(PM_L3_CO_MEM, 0x4f082) +EVENT(PM_LD_MISS_L1, 0x400f0) +EVENT(PM_DATA_FROM_RL2L3_MOD, 0x1c042) +EVENT(PM_LSU_SRQ_FULL_CYC, 0x1001a) +EVENT(PM_TABLEWALK_CYC, 0x10026) +EVENT(PM_MRK_PTEG_FROM_RMEM, 0x3d052) +EVENT(PM_LSU_SRQ_STFWD, 0x0c8a0) +EVENT(PM_INST_PTEG_FROM_RMEM, 0x3e052) +EVENT(PM_FXU0_FIN, 0x10004) +EVENT(PM_LSU1_L1_SW_PREF, 0x0c09e) +EVENT(PM_PTEG_FROM_L31_MOD, 0x1c054) +EVENT(PM_PMC5_OVERFLOW, 0x10024) +EVENT(PM_LD_REF_L1_LSU1, 0x0c082) +EVENT(PM_INST_PTEG_FROM_L21_SHR, 0x4e056) +EVENT(PM_CMPLU_STALL_THRD, 0x1001c) +EVENT(PM_DATA_FROM_RMEM, 0x3c042) +EVENT(PM_VSU0_SCAL_SINGLE_ISSUED, 0x0b084) +EVENT(PM_BR_MPRED_LSTACK, 0x040a6) +EVENT(PM_MRK_DATA_FROM_RL2L3_MOD_CYC, 0x40028) +EVENT(PM_LSU0_FLUSH_UST, 0x0c0b4) +EVENT(PM_LSU_NCST, 0x0c090) +EVENT(PM_BR_TAKEN, 0x20004) +EVENT(PM_INST_PTEG_FROM_LMEM, 0x4e052) +EVENT(PM_GCT_NOSLOT_BR_MPRED_IC_MISS, 0x4001c) +EVENT(PM_DTLB_MISS_4K, 0x2c05a) +EVENT(PM_PMC4_SAVED, 0x30022) +EVENT(PM_VSU1_PERMUTE_ISSUED, 0x0b092) +EVENT(PM_SLB_MISS, 0x0d890) +EVENT(PM_LSU1_FLUSH_LRQ, 0x0c0ba) +EVENT(PM_DTLB_MISS, 0x300fc) +EVENT(PM_VSU1_FRSP, 0x0a0b6) +EVENT(PM_VSU_VECTOR_DOUBLE_ISSUED, 0x0b880) +EVENT(PM_L2_CASTOUT_SHR, 0x16182) +EVENT(PM_DATA_FROM_DL2L3_SHR, 0x3c044) +EVENT(PM_VSU1_STF, 0x0b08e) +EVENT(PM_ST_FIN, 0x200f0) +EVENT(PM_PTEG_FROM_L21_SHR, 0x4c056) +EVENT(PM_L2_LOC_GUESS_WRONG, 0x26480) +EVENT(PM_MRK_STCX_FAIL, 0x0d08e) +EVENT(PM_LSU0_REJECT_LHS, 0x0c0ac) +EVENT(PM_IC_PREF_CANCEL_HIT, 0x04092) +EVENT(PM_L3_PREF_BUSY, 0x4f080) +EVENT(PM_MRK_BRU_FIN, 0x2003a) +EVENT(PM_LSU1_NCLD, 0x0c08e) +EVENT(PM_INST_PTEG_FROM_L31_MOD, 0x1e054) +EVENT(PM_LSU_NCLD, 0x0c88c) +EVENT(PM_LSU_LDX, 0x0c888) +EVENT(PM_L2_LOC_GUESS_CORRECT, 0x16480) +EVENT(PM_THRESH_TIMEO, 0x10038) +EVENT(PM_L3_PREF_ST, 0x0d0ae) +EVENT(PM_DISP_CLB_HELD_SYNC, 0x02098) +EVENT(PM_VSU_SIMPLE_ISSUED, 0x0b894) +EVENT(PM_VSU1_SINGLE, 0x0a0aa) +EVENT(PM_DATA_TABLEWALK_CYC, 0x3001a) +EVENT(PM_L2_RC_ST_DONE, 0x36380) +EVENT(PM_MRK_PTEG_FROM_L21_MOD, 0x3d056) +EVENT(PM_LARX_LSU1, 0x0c096) +EVENT(PM_MRK_DATA_FROM_RMEM, 0x3d042) +EVENT(PM_DISP_CLB_HELD, 0x02090) +EVENT(PM_DERAT_MISS_4K, 0x1c05c) +EVENT(PM_L2_RCLD_DISP_FAIL_ADDR, 0x16282) +EVENT(PM_SEG_EXCEPTION, 0x028a4) +EVENT(PM_FLUSH_DISP_SB, 0x0208c) +EVENT(PM_L2_DC_INV, 0x26182) +EVENT(PM_PTEG_FROM_DL2L3_MOD, 0x4c054) +EVENT(PM_DSEG, 0x020a6) +EVENT(PM_BR_PRED_LSTACK, 0x040a2) +EVENT(PM_VSU0_STF, 0x0b08c) +EVENT(PM_LSU_FX_FIN, 0x10066) +EVENT(PM_DERAT_MISS_16M, 0x3c05c) +EVENT(PM_MRK_PTEG_FROM_DL2L3_MOD, 0x4d054) +EVENT(PM_GCT_UTIL_11_PLUS_SLOTS, 0x020a2) +EVENT(PM_INST_FROM_L3, 0x14048) +EVENT(PM_MRK_IFU_FIN, 0x3003a) +EVENT(PM_ITLB_MISS, 0x400fc) +EVENT(PM_VSU_STF, 0x0b88c) +EVENT(PM_LSU_FLUSH_UST, 0x0c8b4) +EVENT(PM_L2_LDST_MISS, 0x26880) +EVENT(PM_FXU1_FIN, 0x40004) +EVENT(PM_SHL_DEALLOCATED, 0x05080) +EVENT(PM_L2_SN_M_WR_DONE, 0x46382) +EVENT(PM_LSU_REJECT_SET_MPRED, 0x0c8a8) +EVENT(PM_L3_PREF_LD, 0x0d0ac) +EVENT(PM_L2_SN_M_RD_DONE, 0x46380) +EVENT(PM_MRK_DERAT_MISS_16G, 0x4d05c) +EVENT(PM_VSU_FCONV, 0x0a8b0) +EVENT(PM_ANY_THRD_RUN_CYC, 0x100fa) +EVENT(PM_LSU_LMQ_FULL_CYC, 0x0d0a4) +EVENT(PM_MRK_LSU_REJECT_LHS, 0x0d082) +EVENT(PM_MRK_LD_MISS_L1_CYC, 0x4003e) +EVENT(PM_MRK_DATA_FROM_L2_CYC, 0x20020) +EVENT(PM_INST_IMC_MATCH_DISP, 0x30016) +EVENT(PM_MRK_DATA_FROM_RMEM_CYC, 0x4002c) +EVENT(PM_VSU0_SIMPLE_ISSUED, 0x0b094) +EVENT(PM_CMPLU_STALL_DIV, 0x40014) +EVENT(PM_MRK_PTEG_FROM_RL2L3_SHR, 0x2d054) +EVENT(PM_VSU_FMA_DOUBLE, 0x0a890) +EVENT(PM_VSU_4FLOP, 0x0a89c) +EVENT(PM_VSU1_FIN, 0x0a0be) +EVENT(PM_NEST_PAIR1_AND, 0x20883) +EVENT(PM_INST_PTEG_FROM_RL2L3_MOD, 0x1e052) +EVENT(PM_RUN_CYC, 0x200f4) +EVENT(PM_PTEG_FROM_RMEM, 0x3c052) +EVENT(PM_LSU_LRQ_S0_VALID, 0x0d09e) +EVENT(PM_LSU0_LDF, 0x0c084) +EVENT(PM_FLUSH_COMPLETION, 0x30012) +EVENT(PM_ST_MISS_L1, 0x300f0) +EVENT(PM_L2_NODE_PUMP, 0x36480) +EVENT(PM_INST_FROM_DL2L3_SHR, 0x34044) +EVENT(PM_MRK_STALL_CMPLU_CYC, 0x3003e) +EVENT(PM_VSU1_DENORM, 0x0a0ae) +EVENT(PM_MRK_DATA_FROM_L31_SHR_CYC, 0x20026) +EVENT(PM_NEST_PAIR0_ADD, 0x10881) +EVENT(PM_INST_FROM_L3MISS, 0x24048) +EVENT(PM_EE_OFF_EXT_INT, 0x02080) +EVENT(PM_INST_PTEG_FROM_DMEM, 0x2e052) +EVENT(PM_INST_FROM_DL2L3_MOD, 0x3404c) +EVENT(PM_PMC6_OVERFLOW, 0x30024) +EVENT(PM_VSU_2FLOP_DOUBLE, 0x0a88c) +EVENT(PM_TLB_MISS, 0x20066) +EVENT(PM_FXU_BUSY, 0x2000e) +EVENT(PM_L2_RCLD_DISP_FAIL_OTHER, 0x26280) +EVENT(PM_LSU_REJECT_LMQ_FULL, 0x0c8a4) +EVENT(PM_IC_RELOAD_SHR, 0x04096) +EVENT(PM_GRP_MRK, 0x10031) +EVENT(PM_MRK_ST_NEST, 0x20034) +EVENT(PM_VSU1_FSQRT_FDIV, 0x0a08a) +EVENT(PM_LSU0_FLUSH_LRQ, 0x0c0b8) +EVENT(PM_LARX_LSU0, 0x0c094) +EVENT(PM_IBUF_FULL_CYC, 0x04084) +EVENT(PM_MRK_DATA_FROM_DL2L3_SHR_CYC, 0x2002a) +EVENT(PM_LSU_DC_PREF_STREAM_ALLOC, 0x0d8a8) +EVENT(PM_GRP_MRK_CYC, 0x10030) +EVENT(PM_MRK_DATA_FROM_RL2L3_SHR_CYC, 0x20028) +EVENT(PM_L2_GLOB_GUESS_CORRECT, 0x16482) +EVENT(PM_LSU_REJECT_LHS, 0x0c8ac) +EVENT(PM_MRK_DATA_FROM_LMEM, 0x3d04a) +EVENT(PM_INST_PTEG_FROM_L3, 0x2e050) +EVENT(PM_FREQ_DOWN, 0x3000c) +EVENT(PM_PB_RETRY_NODE_PUMP, 0x30081) +EVENT(PM_INST_FROM_RL2L3_SHR, 0x1404c) +EVENT(PM_MRK_INST_ISSUED, 0x10032) +EVENT(PM_PTEG_FROM_L3MISS, 0x2c058) +EVENT(PM_RUN_PURR, 0x400f4) +EVENT(PM_MRK_GRP_IC_MISS, 0x40038) +EVENT(PM_MRK_DATA_FROM_L3, 0x1d048) +EVENT(PM_CMPLU_STALL_DCACHE_MISS, 0x20016) +EVENT(PM_PTEG_FROM_RL2L3_SHR, 0x2c054) +EVENT(PM_LSU_FLUSH_LRQ, 0x0c8b8) +EVENT(PM_MRK_DERAT_MISS_64K, 0x2d05c) +EVENT(PM_INST_PTEG_FROM_DL2L3_MOD, 0x4e054) +EVENT(PM_L2_ST_MISS, 0x26082) +EVENT(PM_MRK_PTEG_FROM_L21_SHR, 0x4d056) +EVENT(PM_LWSYNC, 0x0d094) +EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE, 0x0d0bc) +EVENT(PM_MRK_LSU_FLUSH_LRQ, 0x0d088) +EVENT(PM_INST_IMC_MATCH_CMPL, 0x100f0) +EVENT(PM_NEST_PAIR3_AND, 0x40883) +EVENT(PM_PB_RETRY_SYS_PUMP, 0x40081) +EVENT(PM_MRK_INST_FIN, 0x30030) +EVENT(PM_MRK_PTEG_FROM_DL2L3_SHR, 0x3d054) +EVENT(PM_INST_FROM_L31_MOD, 0x14044) +EVENT(PM_MRK_DTLB_MISS_64K, 0x3d05e) +EVENT(PM_LSU_FIN, 0x30066) +EVENT(PM_MRK_LSU_REJECT, 0x40064) +EVENT(PM_L2_CO_FAIL_BUSY, 0x16382) +EVENT(PM_MEM0_WQ_DISP, 0x40083) +EVENT(PM_DATA_FROM_L31_MOD, 0x1c044) +EVENT(PM_THERMAL_WARN, 0x10016) +EVENT(PM_VSU0_4FLOP, 0x0a09c) +EVENT(PM_BR_MPRED_CCACHE, 0x040a4) +EVENT(PM_CMPLU_STALL_IFU, 0x4004c) +EVENT(PM_L1_DEMAND_WRITE, 0x0408c) +EVENT(PM_FLUSH_BR_MPRED, 0x02084) +EVENT(PM_MRK_DTLB_MISS_16G, 0x1d05e) +EVENT(PM_MRK_PTEG_FROM_DMEM, 0x2d052) +EVENT(PM_L2_RCST_DISP, 0x36280) +EVENT(PM_CMPLU_STALL, 0x4000a) +EVENT(PM_LSU_PARTIAL_CDF, 0x0c0aa) +EVENT(PM_DISP_CLB_HELD_SB, 0x020a8) +EVENT(PM_VSU0_FMA_DOUBLE, 0x0a090) +EVENT(PM_FXU0_BUSY_FXU1_IDLE, 0x3000e) +EVENT(PM_IC_DEMAND_CYC, 0x10018) +EVENT(PM_MRK_DATA_FROM_L21_SHR, 0x3d04e) +EVENT(PM_MRK_LSU_FLUSH_UST, 0x0d086) +EVENT(PM_INST_PTEG_FROM_L3MISS, 0x2e058) +EVENT(PM_VSU_DENORM, 0x0a8ac) +EVENT(PM_MRK_LSU_PARTIAL_CDF, 0x0d080) +EVENT(PM_INST_FROM_L21_SHR, 0x3404e) +EVENT(PM_IC_PREF_WRITE, 0x0408e) +EVENT(PM_BR_PRED, 0x0409c) +EVENT(PM_INST_FROM_DMEM, 0x1404a) +EVENT(PM_IC_PREF_CANCEL_ALL, 0x04890) +EVENT(PM_LSU_DC_PREF_STREAM_CONFIRM, 0x0d8b4) +EVENT(PM_MRK_LSU_FLUSH_SRQ, 0x0d08a) +EVENT(PM_MRK_FIN_STALL_CYC, 0x1003c) +EVENT(PM_L2_RCST_DISP_FAIL_OTHER, 0x46280) +EVENT(PM_VSU1_DD_ISSUED, 0x0b098) +EVENT(PM_PTEG_FROM_L31_SHR, 0x2c056) +EVENT(PM_DATA_FROM_L21_SHR, 0x3c04e) +EVENT(PM_LSU0_NCLD, 0x0c08c) +EVENT(PM_VSU1_4FLOP, 0x0a09e) +EVENT(PM_VSU1_8FLOP, 0x0a0a2) +EVENT(PM_VSU_8FLOP, 0x0a8a0) +EVENT(PM_LSU_LMQ_SRQ_EMPTY_CYC, 0x2003e) +EVENT(PM_DTLB_MISS_64K, 0x3c05e) +EVENT(PM_THRD_CONC_RUN_INST, 0x300f4) +EVENT(PM_MRK_PTEG_FROM_L2, 0x1d050) +EVENT(PM_PB_SYS_PUMP, 0x20081) +EVENT(PM_VSU_FIN, 0x0a8bc) +EVENT(PM_MRK_DATA_FROM_L31_MOD, 0x1d044) +EVENT(PM_THRD_PRIO_0_1_CYC, 0x040b0) +EVENT(PM_DERAT_MISS_64K, 0x2c05c) +EVENT(PM_PMC2_REWIND, 0x30020) +EVENT(PM_INST_FROM_L2, 0x14040) +EVENT(PM_GRP_BR_MPRED_NONSPEC, 0x1000a) +EVENT(PM_INST_DISP, 0x200f2) +EVENT(PM_MEM0_RD_CANCEL_TOTAL, 0x30083) +EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM, 0x0d0b4) +EVENT(PM_L1_DCACHE_RELOAD_VALID, 0x300f6) +EVENT(PM_VSU_SCALAR_DOUBLE_ISSUED, 0x0b888) +EVENT(PM_L3_PREF_HIT, 0x3f080) +EVENT(PM_MRK_PTEG_FROM_L31_MOD, 0x1d054) +EVENT(PM_CMPLU_STALL_STORE, 0x2004a) +EVENT(PM_MRK_FXU_FIN, 0x20038) +EVENT(PM_PMC4_OVERFLOW, 0x10010) +EVENT(PM_MRK_PTEG_FROM_L3, 0x2d050) +EVENT(PM_LSU0_LMQ_LHR_MERGE, 0x0d098) +EVENT(PM_BTAC_HIT, 0x0508a) +EVENT(PM_L3_RD_BUSY, 0x4f082) +EVENT(PM_LSU0_L1_SW_PREF, 0x0c09c) +EVENT(PM_INST_FROM_L2MISS, 0x44048) +EVENT(PM_LSU0_DC_PREF_STREAM_ALLOC, 0x0d0a8) +EVENT(PM_L2_ST, 0x16082) +EVENT(PM_VSU0_DENORM, 0x0a0ac) +EVENT(PM_MRK_DATA_FROM_DL2L3_SHR, 0x3d044) +EVENT(PM_BR_PRED_CR_TA, 0x048aa) +EVENT(PM_VSU0_FCONV, 0x0a0b0) +EVENT(PM_MRK_LSU_FLUSH_ULD, 0x0d084) +EVENT(PM_BTAC_MISS, 0x05088) +EVENT(PM_MRK_LD_MISS_EXPOSED_CYC_COUNT, 0x1003f) +EVENT(PM_MRK_DATA_FROM_L2, 0x1d040) +EVENT(PM_LSU_DCACHE_RELOAD_VALID, 0x0d0a2) +EVENT(PM_VSU_FMA, 0x0a884) +EVENT(PM_LSU0_FLUSH_SRQ, 0x0c0bc) +EVENT(PM_LSU1_L1_PREF, 0x0d0ba) +EVENT(PM_IOPS_CMPL, 0x10014) +EVENT(PM_L2_SYS_PUMP, 0x36482) +EVENT(PM_L2_RCLD_BUSY_RC_FULL, 0x46282) +EVENT(PM_LSU_LMQ_S0_ALLOC, 0x0d0a1) +EVENT(PM_FLUSH_DISP_SYNC, 0x02088) +EVENT(PM_MRK_DATA_FROM_DL2L3_MOD_CYC, 0x4002a) +EVENT(PM_L2_IC_INV, 0x26180) +EVENT(PM_MRK_DATA_FROM_L21_MOD_CYC, 0x40024) +EVENT(PM_L3_PREF_LDST, 0x0d8ac) +EVENT(PM_LSU_SRQ_EMPTY_CYC, 0x40008) +EVENT(PM_LSU_LMQ_S0_VALID, 0x0d0a0) +EVENT(PM_FLUSH_PARTIAL, 0x02086) +EVENT(PM_VSU1_FMA_DOUBLE, 0x0a092) +EVENT(PM_1PLUS_PPC_DISP, 0x400f2) +EVENT(PM_DATA_FROM_L2MISS, 0x200fe) +EVENT(PM_SUSPENDED, 0x00000) +EVENT(PM_VSU0_FMA, 0x0a084) +EVENT(PM_CMPLU_STALL_SCALAR, 0x40012) +EVENT(PM_STCX_FAIL, 0x0c09a) +EVENT(PM_VSU0_FSQRT_FDIV_DOUBLE, 0x0a094) +EVENT(PM_DC_PREF_DST, 0x0d0b0) +EVENT(PM_VSU1_SCAL_SINGLE_ISSUED, 0x0b086) +EVENT(PM_L3_HIT, 0x1f080) +EVENT(PM_L2_GLOB_GUESS_WRONG, 0x26482) +EVENT(PM_MRK_DFU_FIN, 0x20032) +EVENT(PM_INST_FROM_L1, 0x04080) +EVENT(PM_BRU_FIN, 0x10068) +EVENT(PM_IC_DEMAND_REQ, 0x04088) +EVENT(PM_VSU1_FSQRT_FDIV_DOUBLE, 0x0a096) +EVENT(PM_VSU1_FMA, 0x0a086) +EVENT(PM_MRK_LD_MISS_L1, 0x20036) +EVENT(PM_VSU0_2FLOP_DOUBLE, 0x0a08c) +EVENT(PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM, 0x0d8bc) +EVENT(PM_INST_PTEG_FROM_L31_SHR, 0x2e056) +EVENT(PM_MRK_LSU_REJECT_ERAT_MISS, 0x30064) +EVENT(PM_MRK_DATA_FROM_L2MISS, 0x4d048) +EVENT(PM_DATA_FROM_RL2L3_SHR, 0x1c04c) +EVENT(PM_INST_FROM_PREF, 0x14046) +EVENT(PM_VSU1_SQ, 0x0b09e) +EVENT(PM_L2_LD_DISP, 0x36180) +EVENT(PM_L2_DISP_ALL, 0x46080) +EVENT(PM_THRD_GRP_CMPL_BOTH_CYC, 0x10012) +EVENT(PM_VSU_FSQRT_FDIV_DOUBLE, 0x0a894) +EVENT(PM_BR_MPRED, 0x400f6) +EVENT(PM_INST_PTEG_FROM_DL2L3_SHR, 0x3e054) +EVENT(PM_VSU_1FLOP, 0x0a880) +EVENT(PM_HV_CYC, 0x2000a) +EVENT(PM_MRK_LSU_FIN, 0x40032) +EVENT(PM_MRK_DATA_FROM_RL2L3_SHR, 0x1d04c) +EVENT(PM_DTLB_MISS_16M, 0x4c05e) +EVENT(PM_LSU1_LMQ_LHR_MERGE, 0x0d09a) +EVENT(PM_IFU_FIN, 0x40066) diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index d1821b8bbc4c..56c67bca2f75 100644 --- a/arch/powerpc/perf/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c @@ -53,37 +53,13 @@ /* * Power7 event codes. */ -#define PME_PM_CYC 0x1e -#define PME_PM_GCT_NOSLOT_CYC 0x100f8 -#define PME_PM_CMPLU_STALL 0x4000a -#define PME_PM_INST_CMPL 0x2 -#define PME_PM_LD_REF_L1 0xc880 -#define PME_PM_LD_MISS_L1 0x400f0 -#define PME_PM_BRU_FIN 0x10068 -#define PME_PM_BR_MPRED 0x400f6 +#define EVENT(_name, _code) \ + PME_##_name = _code, -#define PME_PM_CMPLU_STALL_FXU 0x20014 -#define PME_PM_CMPLU_STALL_DIV 0x40014 -#define PME_PM_CMPLU_STALL_SCALAR 0x40012 -#define PME_PM_CMPLU_STALL_SCALAR_LONG 0x20018 -#define PME_PM_CMPLU_STALL_VECTOR 0x2001c -#define PME_PM_CMPLU_STALL_VECTOR_LONG 0x4004a -#define PME_PM_CMPLU_STALL_LSU 0x20012 -#define PME_PM_CMPLU_STALL_REJECT 0x40016 -#define PME_PM_CMPLU_STALL_ERAT_MISS 0x40018 -#define PME_PM_CMPLU_STALL_DCACHE_MISS 0x20016 -#define PME_PM_CMPLU_STALL_STORE 0x2004a -#define PME_PM_CMPLU_STALL_THRD 0x1001c -#define PME_PM_CMPLU_STALL_IFU 0x4004c -#define PME_PM_CMPLU_STALL_BRU 0x4004e -#define PME_PM_GCT_NOSLOT_IC_MISS 0x2001a -#define PME_PM_GCT_NOSLOT_BR_MPRED 0x4001a -#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS 0x4001c -#define PME_PM_GRP_CMPL 0x30004 -#define PME_PM_1PLUS_PPC_CMPL 0x100f2 -#define PME_PM_CMPLU_STALL_DFU 0x2003c -#define PME_PM_RUN_CYC 0x200f4 -#define PME_PM_RUN_INST_CMPL 0x400fa +enum { +#include "power7-events-list.h" +}; +#undef EVENT /* * Layout of constraint bits: @@ -398,96 +374,36 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { }; -GENERIC_EVENT_ATTR(cpu-cycles, CYC); -GENERIC_EVENT_ATTR(stalled-cycles-frontend, GCT_NOSLOT_CYC); -GENERIC_EVENT_ATTR(stalled-cycles-backend, CMPLU_STALL); -GENERIC_EVENT_ATTR(instructions, INST_CMPL); -GENERIC_EVENT_ATTR(cache-references, LD_REF_L1); -GENERIC_EVENT_ATTR(cache-misses, LD_MISS_L1); -GENERIC_EVENT_ATTR(branch-instructions, BRU_FIN); -GENERIC_EVENT_ATTR(branch-misses, BR_MPRED); +GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC); +GENERIC_EVENT_ATTR(stalled-cycles-frontend, PM_GCT_NOSLOT_CYC); +GENERIC_EVENT_ATTR(stalled-cycles-backend, PM_CMPLU_STALL); +GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL); +GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1); +GENERIC_EVENT_ATTR(cache-misses, PM_LD_MISS_L1); +GENERIC_EVENT_ATTR(branch-instructions, PM_BRU_FIN); +GENERIC_EVENT_ATTR(branch-misses, PM_BR_MPRED); -POWER_EVENT_ATTR(CYC, CYC); -POWER_EVENT_ATTR(GCT_NOSLOT_CYC, GCT_NOSLOT_CYC); -POWER_EVENT_ATTR(CMPLU_STALL, CMPLU_STALL); -POWER_EVENT_ATTR(INST_CMPL, INST_CMPL); -POWER_EVENT_ATTR(LD_REF_L1, LD_REF_L1); -POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1); -POWER_EVENT_ATTR(BRU_FIN, BRU_FIN) -POWER_EVENT_ATTR(BR_MPRED, BR_MPRED); +#define EVENT(_name, _code) POWER_EVENT_ATTR(_name, _name); +#include "power7-events-list.h" +#undef EVENT -POWER_EVENT_ATTR(CMPLU_STALL_FXU, CMPLU_STALL_FXU); -POWER_EVENT_ATTR(CMPLU_STALL_DIV, CMPLU_STALL_DIV); -POWER_EVENT_ATTR(CMPLU_STALL_SCALAR, CMPLU_STALL_SCALAR); -POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG, CMPLU_STALL_SCALAR_LONG); -POWER_EVENT_ATTR(CMPLU_STALL_VECTOR, CMPLU_STALL_VECTOR); -POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG, CMPLU_STALL_VECTOR_LONG); -POWER_EVENT_ATTR(CMPLU_STALL_LSU, CMPLU_STALL_LSU); -POWER_EVENT_ATTR(CMPLU_STALL_REJECT, CMPLU_STALL_REJECT); - -POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS, CMPLU_STALL_ERAT_MISS); -POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS, CMPLU_STALL_DCACHE_MISS); -POWER_EVENT_ATTR(CMPLU_STALL_STORE, CMPLU_STALL_STORE); -POWER_EVENT_ATTR(CMPLU_STALL_THRD, CMPLU_STALL_THRD); -POWER_EVENT_ATTR(CMPLU_STALL_IFU, CMPLU_STALL_IFU); -POWER_EVENT_ATTR(CMPLU_STALL_BRU, CMPLU_STALL_BRU); -POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS, GCT_NOSLOT_IC_MISS); - -POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED, GCT_NOSLOT_BR_MPRED); -POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS, GCT_NOSLOT_BR_MPRED_IC_MISS); -POWER_EVENT_ATTR(GRP_CMPL, GRP_CMPL); -POWER_EVENT_ATTR(1PLUS_PPC_CMPL, 1PLUS_PPC_CMPL); -POWER_EVENT_ATTR(CMPLU_STALL_DFU, CMPLU_STALL_DFU); -POWER_EVENT_ATTR(RUN_CYC, RUN_CYC); -POWER_EVENT_ATTR(RUN_INST_CMPL, RUN_INST_CMPL); +#define EVENT(_name, _code) POWER_EVENT_PTR(_name), static struct attribute *power7_events_attr[] = { - GENERIC_EVENT_PTR(CYC), - GENERIC_EVENT_PTR(GCT_NOSLOT_CYC), - GENERIC_EVENT_PTR(CMPLU_STALL), - GENERIC_EVENT_PTR(INST_CMPL), - GENERIC_EVENT_PTR(LD_REF_L1), - GENERIC_EVENT_PTR(LD_MISS_L1), - GENERIC_EVENT_PTR(BRU_FIN), - GENERIC_EVENT_PTR(BR_MPRED), + GENERIC_EVENT_PTR(PM_CYC), + GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC), + GENERIC_EVENT_PTR(PM_CMPLU_STALL), + GENERIC_EVENT_PTR(PM_INST_CMPL), + GENERIC_EVENT_PTR(PM_LD_REF_L1), + GENERIC_EVENT_PTR(PM_LD_MISS_L1), + GENERIC_EVENT_PTR(PM_BRU_FIN), + GENERIC_EVENT_PTR(PM_BR_MPRED), - POWER_EVENT_PTR(CYC), - POWER_EVENT_PTR(GCT_NOSLOT_CYC), - POWER_EVENT_PTR(CMPLU_STALL), - POWER_EVENT_PTR(INST_CMPL), - POWER_EVENT_PTR(LD_REF_L1), - POWER_EVENT_PTR(LD_MISS_L1), - POWER_EVENT_PTR(BRU_FIN), - POWER_EVENT_PTR(BR_MPRED), - - POWER_EVENT_PTR(CMPLU_STALL_FXU), - POWER_EVENT_PTR(CMPLU_STALL_DIV), - POWER_EVENT_PTR(CMPLU_STALL_SCALAR), - POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG), - POWER_EVENT_PTR(CMPLU_STALL_VECTOR), - POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG), - POWER_EVENT_PTR(CMPLU_STALL_LSU), - POWER_EVENT_PTR(CMPLU_STALL_REJECT), - - POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS), - POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS), - POWER_EVENT_PTR(CMPLU_STALL_STORE), - POWER_EVENT_PTR(CMPLU_STALL_THRD), - POWER_EVENT_PTR(CMPLU_STALL_IFU), - POWER_EVENT_PTR(CMPLU_STALL_BRU), - POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS), - POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED), - - POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS), - POWER_EVENT_PTR(GRP_CMPL), - POWER_EVENT_PTR(1PLUS_PPC_CMPL), - POWER_EVENT_PTR(CMPLU_STALL_DFU), - POWER_EVENT_PTR(RUN_CYC), - POWER_EVENT_PTR(RUN_INST_CMPL), + #include "power7-events-list.h" + #undef EVENT NULL }; - static struct attribute_group power7_pmu_events_group = { .name = "events", .attrs = power7_events_attr, From b3824404ebbd489858f3a7097c715120118fa5cd Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 2 Jul 2013 13:27:21 -0600 Subject: [PATCH 0165/6183] perf evlist: Fix use of uninitialized variable Fixes valgrind complaint: ==1870== Syscall param write(buf) points to uninitialised byte(s) ==1870== at 0x4E3F5B0: __write_nocancel (in /lib64/libpthread-2.14.90.so) ==1870== by 0x449D7C: perf_evlist__start_workload (evlist.c:846) ==1870== by 0x427BC1: cmd_record (builtin-record.c:561) ==1870== by 0x419D72: run_builtin (perf.c:319) ==1870== by 0x4195F2: main (perf.c:376) ==1870== Address 0x7feffcdd7 is on thread 1's stack Signed-off-by: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1372793245-4136-3-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 4a901be599ed..d8f34e0afbfb 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -838,7 +838,7 @@ out_close_ready_pipe: int perf_evlist__start_workload(struct perf_evlist *evlist) { if (evlist->workload.cork_fd > 0) { - char bf; + char bf = 0; int ret; /* * Remove the cork, let it rip! From 0142dab01cd690f6e376f1fb4d4462beb054dfaf Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 2 Jul 2013 13:27:23 -0600 Subject: [PATCH 0166/6183] perf tools: Don't free list head in parse_events__free_terms Function should only be freeing the entries in the list in case of failure, as those were allocated there, not the list_head itself. Signed-off-by: David Ahern Cc: Adrian Hunter Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1372793245-4136-5-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ef72e98a07a6..bcf83ee97e92 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1260,6 +1260,4 @@ void parse_events__free_terms(struct list_head *terms) list_for_each_entry_safe(term, h, terms, list) free(term); - - free(terms); } From c549aca50134640537bf0fbae43c08fd5ff91932 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 2 Jul 2013 13:27:24 -0600 Subject: [PATCH 0167/6183] perf tests: Make terms a stack variable in test_term No need to malloc the memory for it. Signed-off-by: David Ahern Cc: Adrian Hunter Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1372793245-4136-6-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index ad950f57d85b..344c844ffc1e 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1246,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt) static int test_term(struct terms_test *t) { - struct list_head *terms; + struct list_head terms; int ret; - terms = malloc(sizeof(*terms)); - if (!terms) - return -ENOMEM; + INIT_LIST_HEAD(&terms); - INIT_LIST_HEAD(terms); - - ret = parse_events_terms(terms, t->str); + ret = parse_events_terms(&terms, t->str); if (ret) { pr_debug("failed to parse terms '%s', err %d\n", t->str , ret); return ret; } - ret = t->check(terms); - parse_events__free_terms(terms); + ret = t->check(&terms); + parse_events__free_terms(&terms); return ret; } From c5cd8ac07e7ad5f21b1930b23b2e1bb231958430 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 2 Jul 2013 13:27:25 -0600 Subject: [PATCH 0168/6183] perf parse events: Demystify memory allocations List heads are currently allocated way down the function chain in __add_event and add_tracepoint and then freed when the scanner code calls parse_events_update_lists. Be more explicit with where memory is allocated and who should free it. With this patch the list_head is allocated in the scanner code and freed when the scanner code calls parse_events_update_lists. Signed-off-by: David Ahern Cc: Adrian Hunter Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1372793245-4136-7-git-send-email-dsahern@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 52 +++++++++------------------- tools/perf/util/parse-events.h | 10 +++--- tools/perf/util/parse-events.y | 62 ++++++++++++++++++++++------------ 3 files changed, 61 insertions(+), 63 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bcf83ee97e92..e85376999efc 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -264,40 +264,29 @@ const char *event_type(int type) -static int __add_event(struct list_head **_list, int *idx, +static int __add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, char *name, struct cpu_map *cpus) { struct perf_evsel *evsel; - struct list_head *list = *_list; - - if (!list) { - list = malloc(sizeof(*list)); - if (!list) - return -ENOMEM; - INIT_LIST_HEAD(list); - } event_attr_init(attr); evsel = perf_evsel__new(attr, (*idx)++); - if (!evsel) { - free(list); + if (!evsel) return -ENOMEM; - } evsel->cpus = cpus; if (name) evsel->name = strdup(name); list_add_tail(&evsel->node, list); - *_list = list; return 0; } -static int add_event(struct list_head **_list, int *idx, +static int add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, char *name) { - return __add_event(_list, idx, attr, name, NULL); + return __add_event(list, idx, attr, name, NULL); } static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) @@ -318,7 +307,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES] return -1; } -int parse_events_add_cache(struct list_head **list, int *idx, +int parse_events_add_cache(struct list_head *list, int *idx, char *type, char *op_result1, char *op_result2) { struct perf_event_attr attr; @@ -379,31 +368,21 @@ int parse_events_add_cache(struct list_head **list, int *idx, return add_event(list, idx, &attr, name); } -static int add_tracepoint(struct list_head **listp, int *idx, +static int add_tracepoint(struct list_head *list, int *idx, char *sys_name, char *evt_name) { struct perf_evsel *evsel; - struct list_head *list = *listp; - - if (!list) { - list = malloc(sizeof(*list)); - if (!list) - return -ENOMEM; - INIT_LIST_HEAD(list); - } evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); - if (!evsel) { - free(list); + if (!evsel) return -ENOMEM; - } list_add_tail(&evsel->node, list); - *listp = list; + return 0; } -static int add_tracepoint_multi_event(struct list_head **list, int *idx, +static int add_tracepoint_multi_event(struct list_head *list, int *idx, char *sys_name, char *evt_name) { char evt_path[MAXPATHLEN]; @@ -435,7 +414,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx, return ret; } -static int add_tracepoint_event(struct list_head **list, int *idx, +static int add_tracepoint_event(struct list_head *list, int *idx, char *sys_name, char *evt_name) { return strpbrk(evt_name, "*?") ? @@ -443,7 +422,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx, add_tracepoint(list, idx, sys_name, evt_name); } -static int add_tracepoint_multi_sys(struct list_head **list, int *idx, +static int add_tracepoint_multi_sys(struct list_head *list, int *idx, char *sys_name, char *evt_name) { struct dirent *events_ent; @@ -475,7 +454,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx, return ret; } -int parse_events_add_tracepoint(struct list_head **list, int *idx, +int parse_events_add_tracepoint(struct list_head *list, int *idx, char *sys, char *event) { int ret; @@ -530,7 +509,7 @@ do { \ return 0; } -int parse_events_add_breakpoint(struct list_head **list, int *idx, +int parse_events_add_breakpoint(struct list_head *list, int *idx, void *ptr, char *type) { struct perf_event_attr attr; @@ -611,7 +590,7 @@ static int config_attr(struct perf_event_attr *attr, return 0; } -int parse_events_add_numeric(struct list_head **list, int *idx, +int parse_events_add_numeric(struct list_head *list, int *idx, u32 type, u64 config, struct list_head *head_config) { @@ -644,7 +623,7 @@ static char *pmu_event_name(struct list_head *head_terms) return NULL; } -int parse_events_add_pmu(struct list_head **list, int *idx, +int parse_events_add_pmu(struct list_head *list, int *idx, char *name, struct list_head *head_config) { struct perf_event_attr attr; @@ -687,6 +666,7 @@ void parse_events__set_leader(char *name, struct list_head *list) leader->group_name = name ? strdup(name) : NULL; } +/* list_event is assumed to point to malloc'ed memory */ void parse_events_update_lists(struct list_head *list_event, struct list_head *list_all) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 080f7cf25d99..f1cb4c4b3c70 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -85,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms); int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events_name(struct list_head *list, char *name); -int parse_events_add_tracepoint(struct list_head **list, int *idx, +int parse_events_add_tracepoint(struct list_head *list, int *idx, char *sys, char *event); -int parse_events_add_numeric(struct list_head **list, int *idx, +int parse_events_add_numeric(struct list_head *list, int *idx, u32 type, u64 config, struct list_head *head_config); -int parse_events_add_cache(struct list_head **list, int *idx, +int parse_events_add_cache(struct list_head *list, int *idx, char *type, char *op_result1, char *op_result2); -int parse_events_add_breakpoint(struct list_head **list, int *idx, +int parse_events_add_breakpoint(struct list_head *list, int *idx, void *ptr, char *type); -int parse_events_add_pmu(struct list_head **list, int *idx, +int parse_events_add_pmu(struct list_head *list, int *idx, char *pmu , struct list_head *head_config); void parse_events__set_leader(char *name, struct list_head *list); void parse_events_update_lists(struct list_head *list_event, diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index afc44c18dfe1..4eb67ec333f1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -22,6 +22,13 @@ do { \ YYABORT; \ } while (0) +#define ALLOC_LIST(list) \ +do { \ + list = malloc(sizeof(*list)); \ + ABORT_ON(!list); \ + INIT_LIST_HEAD(list); \ +} while (0) + static inc_group_count(struct list_head *list, struct parse_events_evlist *data) { @@ -196,9 +203,10 @@ event_pmu: PE_NAME '/' event_config '/' { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); + ALLOC_LIST(list); + ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3)); parse_events__free_terms($3); $$ = list; } @@ -212,11 +220,12 @@ event_legacy_symbol: value_sym '/' event_config '/' { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; int type = $1 >> 16; int config = $1 & 255; - ABORT_ON(parse_events_add_numeric(&list, &data->idx, + ALLOC_LIST(list); + ABORT_ON(parse_events_add_numeric(list, &data->idx, type, config, $3)); parse_events__free_terms($3); $$ = list; @@ -225,11 +234,12 @@ value_sym '/' event_config '/' value_sym sep_slash_dc { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; int type = $1 >> 16; int config = $1 & 255; - ABORT_ON(parse_events_add_numeric(&list, &data->idx, + ALLOC_LIST(list); + ABORT_ON(parse_events_add_numeric(list, &data->idx, type, config, NULL)); $$ = list; } @@ -238,27 +248,30 @@ event_legacy_cache: PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); + ALLOC_LIST(list); + ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5)); $$ = list; } | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); + ALLOC_LIST(list); + ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL)); $$ = list; } | PE_NAME_CACHE_TYPE { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); + ALLOC_LIST(list); + ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL)); $$ = list; } @@ -266,9 +279,10 @@ event_legacy_mem: PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, + ALLOC_LIST(list); + ABORT_ON(parse_events_add_breakpoint(list, &data->idx, (void *) $2, $4)); $$ = list; } @@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc PE_PREFIX_MEM PE_VALUE sep_dc { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, + ALLOC_LIST(list); + ABORT_ON(parse_events_add_breakpoint(list, &data->idx, (void *) $2, NULL)); $$ = list; } @@ -287,9 +302,10 @@ event_legacy_tracepoint: PE_NAME ':' PE_NAME { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); + ALLOC_LIST(list); + ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3)); $$ = list; } @@ -297,9 +313,10 @@ event_legacy_numeric: PE_VALUE ':' PE_VALUE { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); + ALLOC_LIST(list); + ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL)); $$ = list; } @@ -307,9 +324,10 @@ event_legacy_raw: PE_RAW { struct parse_events_evlist *data = _data; - struct list_head *list = NULL; + struct list_head *list; - ABORT_ON(parse_events_add_numeric(&list, &data->idx, + ALLOC_LIST(list); + ABORT_ON(parse_events_add_numeric(list, &data->idx, PERF_TYPE_RAW, $1, NULL)); $$ = list; } From 9f1efa82640b4f06c8f6c847f088c53e4100395c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:16 +0900 Subject: [PATCH 0169/6183] tools lib traceevent: Remove unused install targets The html_install, img_install, install_plugin and install_python are unused in the Makefile. Get rid of them. Signed-off-by: Namhyung Kim Acked-by: Steven Rostedt Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/Makefile | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 0b0a90787db6..fd7510d99583 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -39,13 +39,8 @@ bindir_relative = bin bindir = $(prefix)/$(bindir_relative) man_dir = $(prefix)/share/man man_dir_SQ = '$(subst ','\'',$(man_dir))' -html_install = $(prefix)/share/kernelshark/html -html_install_SQ = '$(subst ','\'',$(html_install))' -img_install = $(prefix)/share/kernelshark/html/images -img_install_SQ = '$(subst ','\'',$(img_install))' -export man_dir man_dir_SQ html_install html_install_SQ INSTALL -export img_install img_install_SQ +export man_dir man_dir_SQ INSTALL export DESTDIR DESTDIR_SQ # copy a bit from Linux kbuild @@ -300,7 +295,7 @@ define do_install $(INSTALL) $1 '$(DESTDIR_SQ)$2' endef -install_lib: all_cmd install_plugins install_python +install_lib: all_cmd $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) install: install_lib From 4ccdf57d46843f5c03e390bdb652c9744e30ee20 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:17 +0900 Subject: [PATCH 0170/6183] tools lib traceevent: Get rid of unused gui target It's came from trace-cmd's kernelshark which is not a part of libtraceevent. Signed-off-by: Namhyung Kim Acked-by: Steven Rostedt Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/Makefile | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index fd7510d99583..4505de874929 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -71,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \ all: sub-make -gui: force - $(call build_output, all_cmd) - -$(filter-out gui,$(MAKECMDGOALS)): sub-make +$(MAKECMDGOALS): sub-make sub-make: force $(call build_output, $(MAKECMDGOALS)) @@ -253,9 +250,6 @@ define check_deps $(RM) $@.$$$$ endef -$(gui_deps): ks_version.h -$(non_gui_deps): tc_version.h - $(all_deps): .%.d: $(src)/%.c $(Q)$(call check_deps) From 79d5adf06dd530fe6a9ab3d086b2d23eb7560491 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:18 +0900 Subject: [PATCH 0171/6183] tools lib traceevent: Add const qualifier to string arguments If pevent_register_event_handler() received a string literal as @sys_name or @event_name parameter, it emitted a warning about const qualifier removal. Since they're not modified in the function we can make it have const qualifier. Signed-off-by: Namhyung Kim Acked-by: Steven Rostedt Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 7 +++---- tools/lib/traceevent/event-parse.h | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 82b0606dcb8a..d1c2a6a4cd32 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent, * If @id is >= 0, then it is used to find the event. * else @sys_name and @event_name are used. */ -int pevent_register_event_handler(struct pevent *pevent, - int id, char *sys_name, char *event_name, - pevent_event_handler_func func, - void *context) +int pevent_register_event_handler(struct pevent *pevent, int id, + const char *sys_name, const char *event_name, + pevent_event_handler_func func, void *context) { struct event_format *event; struct event_handler *handle; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 7be7e89533e4..bfceab948f22 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -561,7 +561,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, struct event_format *event, const char *name, struct pevent_record *record, int err); -int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, +int pevent_register_event_handler(struct pevent *pevent, int id, + const char *sys_name, const char *event_name, pevent_event_handler_func func, void *context); int pevent_register_print_function(struct pevent *pevent, pevent_func_handler func, From 6a48aec3a7179b0cdae2339d5a4072214ee6c6fe Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:19 +0900 Subject: [PATCH 0172/6183] tools lib traceevent: Add trace_seq_reset() Sometimes it'd be useful if existing trace_seq can be reused. But currently it's impossible since there's no API to reset the trace_seq. Let's add trace_seq_reset() for this case. Signed-off-by: Namhyung Kim Acked-by: Steven Rostedt Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.h | 1 + tools/lib/traceevent/trace-seq.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index bfceab948f22..39f0c1dca915 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -69,6 +69,7 @@ struct trace_seq { }; void trace_seq_init(struct trace_seq *s); +void trace_seq_reset(struct trace_seq *s); void trace_seq_destroy(struct trace_seq *s); extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index a57db805136a..d7f2e68bc5b9 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c @@ -48,6 +48,19 @@ void trace_seq_init(struct trace_seq *s) s->buffer = malloc_or_die(s->buffer_size); } +/** + * trace_seq_reset - re-initialize the trace_seq structure + * @s: a pointer to the trace_seq structure to reset + */ +void trace_seq_reset(struct trace_seq *s) +{ + if (!s) + return; + TRACE_SEQ_CHECK(s); + s->len = 0; + s->readpos = 0; +} + /** * trace_seq_destroy - free up memory of a trace_seq * @s: a pointer to the trace_seq to free the buffer From 012ac692575b1ea6ed930871850584e4c64f1382 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:20 +0900 Subject: [PATCH 0173/6183] tools lib traceevent: Add page_size field to pevent The page size of traced system can be different than current system's because the recorded data file might be analyzed in a different machine. In this case we should use original page size of traced system when accessing the data file, so this information needs to be saved. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 39f0c1dca915..c37b2026d04a 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -400,6 +400,7 @@ struct pevent { int cpus; int long_size; + int page_size; struct cmdline *cmdlines; struct cmdline_list *cmdlist; @@ -621,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size) pevent->long_size = long_size; } +static inline int pevent_get_page_size(struct pevent *pevent) +{ + return pevent->page_size; +} + +static inline void pevent_set_page_size(struct pevent *pevent, int _page_size) +{ + pevent->page_size = _page_size; +} + static inline int pevent_is_file_bigendian(struct pevent *pevent) { return pevent->file_bigendian; From d6c25223f6067c6889d8fc3f9576d34bbac161b0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:21 +0900 Subject: [PATCH 0174/6183] tools lib traceevent: Port kbuffer parser routines kbuffer code is for parsing ftrace ring-buffer binary data and used for trace-cmd. Move the code here in order to be used more widely. Signed-off-by: Namhyung Kim Original-patch-by: Steven Rostedt Acked-by: Steven Rostedt Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-7-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/Makefile | 1 + tools/lib/traceevent/kbuffer-parse.c | 732 +++++++++++++++++++++++++++ tools/lib/traceevent/kbuffer.h | 67 +++ 3 files changed, 800 insertions(+) create mode 100644 tools/lib/traceevent/kbuffer-parse.c create mode 100644 tools/lib/traceevent/kbuffer.h diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 4505de874929..0794acca46a3 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -181,6 +181,7 @@ $(obj)/%.o: $(src)/%.c $(Q)$(call do_compile) PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o +PEVENT_LIB_OBJS += kbuffer-parse.o ALL_OBJS = $(PEVENT_LIB_OBJS) diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c new file mode 100644 index 000000000000..dcc665228c71 --- /dev/null +++ b/tools/lib/traceevent/kbuffer-parse.c @@ -0,0 +1,732 @@ +/* + * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include + +#include "kbuffer.h" + +#define MISSING_EVENTS (1 << 31) +#define MISSING_STORED (1 << 30) + +#define COMMIT_MASK ((1 << 27) - 1) + +enum { + KBUFFER_FL_HOST_BIG_ENDIAN = (1<<0), + KBUFFER_FL_BIG_ENDIAN = (1<<1), + KBUFFER_FL_LONG_8 = (1<<2), + KBUFFER_FL_OLD_FORMAT = (1<<3), +}; + +#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN) + +/** kbuffer + * @timestamp - timestamp of current event + * @lost_events - # of lost events between this subbuffer and previous + * @flags - special flags of the kbuffer + * @subbuffer - pointer to the sub-buffer page + * @data - pointer to the start of data on the sub-buffer page + * @index - index from @data to the @curr event data + * @curr - offset from @data to the start of current event + * (includes metadata) + * @next - offset from @data to the start of next event + * @size - The size of data on @data + * @start - The offset from @subbuffer where @data lives + * + * @read_4 - Function to read 4 raw bytes (may swap) + * @read_8 - Function to read 8 raw bytes (may swap) + * @read_long - Function to read a long word (4 or 8 bytes with needed swap) + */ +struct kbuffer { + unsigned long long timestamp; + long long lost_events; + unsigned long flags; + void *subbuffer; + void *data; + unsigned int index; + unsigned int curr; + unsigned int next; + unsigned int size; + unsigned int start; + + unsigned int (*read_4)(void *ptr); + unsigned long long (*read_8)(void *ptr); + unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr); + int (*next_event)(struct kbuffer *kbuf); +}; + +static void *zmalloc(size_t size) +{ + return calloc(1, size); +} + +static int host_is_bigendian(void) +{ + unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; + unsigned int *ptr; + + ptr = (unsigned int *)str; + return *ptr == 0x01020304; +} + +static int do_swap(struct kbuffer *kbuf) +{ + return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) & + ENDIAN_MASK; +} + +static unsigned long long __read_8(void *ptr) +{ + unsigned long long data = *(unsigned long long *)ptr; + + return data; +} + +static unsigned long long __read_8_sw(void *ptr) +{ + unsigned long long data = *(unsigned long long *)ptr; + unsigned long long swap; + + swap = ((data & 0xffULL) << 56) | + ((data & (0xffULL << 8)) << 40) | + ((data & (0xffULL << 16)) << 24) | + ((data & (0xffULL << 24)) << 8) | + ((data & (0xffULL << 32)) >> 8) | + ((data & (0xffULL << 40)) >> 24) | + ((data & (0xffULL << 48)) >> 40) | + ((data & (0xffULL << 56)) >> 56); + + return swap; +} + +static unsigned int __read_4(void *ptr) +{ + unsigned int data = *(unsigned int *)ptr; + + return data; +} + +static unsigned int __read_4_sw(void *ptr) +{ + unsigned int data = *(unsigned int *)ptr; + unsigned int swap; + + swap = ((data & 0xffULL) << 24) | + ((data & (0xffULL << 8)) << 8) | + ((data & (0xffULL << 16)) >> 8) | + ((data & (0xffULL << 24)) >> 24); + + return swap; +} + +static unsigned long long read_8(struct kbuffer *kbuf, void *ptr) +{ + return kbuf->read_8(ptr); +} + +static unsigned int read_4(struct kbuffer *kbuf, void *ptr) +{ + return kbuf->read_4(ptr); +} + +static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr) +{ + return kbuf->read_8(ptr); +} + +static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr) +{ + return kbuf->read_4(ptr); +} + +static unsigned long long read_long(struct kbuffer *kbuf, void *ptr) +{ + return kbuf->read_long(kbuf, ptr); +} + +static int calc_index(struct kbuffer *kbuf, void *ptr) +{ + return (unsigned long)ptr - (unsigned long)kbuf->data; +} + +static int __next_event(struct kbuffer *kbuf); + +/** + * kbuffer_alloc - allocat a new kbuffer + * @size; enum to denote size of word + * @endian: enum to denote endianness + * + * Allocates and returns a new kbuffer. + */ +struct kbuffer * +kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian) +{ + struct kbuffer *kbuf; + int flags = 0; + + switch (size) { + case KBUFFER_LSIZE_4: + break; + case KBUFFER_LSIZE_8: + flags |= KBUFFER_FL_LONG_8; + break; + default: + return NULL; + } + + switch (endian) { + case KBUFFER_ENDIAN_LITTLE: + break; + case KBUFFER_ENDIAN_BIG: + flags |= KBUFFER_FL_BIG_ENDIAN; + break; + default: + return NULL; + } + + kbuf = zmalloc(sizeof(*kbuf)); + if (!kbuf) + return NULL; + + kbuf->flags = flags; + + if (host_is_bigendian()) + kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN; + + if (do_swap(kbuf)) { + kbuf->read_8 = __read_8_sw; + kbuf->read_4 = __read_4_sw; + } else { + kbuf->read_8 = __read_8; + kbuf->read_4 = __read_4; + } + + if (kbuf->flags & KBUFFER_FL_LONG_8) + kbuf->read_long = __read_long_8; + else + kbuf->read_long = __read_long_4; + + /* May be changed by kbuffer_set_old_format() */ + kbuf->next_event = __next_event; + + return kbuf; +} + +/** kbuffer_free - free an allocated kbuffer + * @kbuf: The kbuffer to free + * + * Can take NULL as a parameter. + */ +void kbuffer_free(struct kbuffer *kbuf) +{ + free(kbuf); +} + +static unsigned int type4host(struct kbuffer *kbuf, + unsigned int type_len_ts) +{ + if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) + return (type_len_ts >> 29) & 3; + else + return type_len_ts & 3; +} + +static unsigned int len4host(struct kbuffer *kbuf, + unsigned int type_len_ts) +{ + if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) + return (type_len_ts >> 27) & 7; + else + return (type_len_ts >> 2) & 7; +} + +static unsigned int type_len4host(struct kbuffer *kbuf, + unsigned int type_len_ts) +{ + if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) + return (type_len_ts >> 27) & ((1 << 5) - 1); + else + return type_len_ts & ((1 << 5) - 1); +} + +static unsigned int ts4host(struct kbuffer *kbuf, + unsigned int type_len_ts) +{ + if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) + return type_len_ts & ((1 << 27) - 1); + else + return type_len_ts >> 5; +} + +/* + * Linux 2.6.30 and earlier (not much ealier) had a different + * ring buffer format. It should be obsolete, but we handle it anyway. + */ +enum old_ring_buffer_type { + OLD_RINGBUF_TYPE_PADDING, + OLD_RINGBUF_TYPE_TIME_EXTEND, + OLD_RINGBUF_TYPE_TIME_STAMP, + OLD_RINGBUF_TYPE_DATA, +}; + +static unsigned int old_update_pointers(struct kbuffer *kbuf) +{ + unsigned long long extend; + unsigned int type_len_ts; + unsigned int type; + unsigned int len; + unsigned int delta; + unsigned int length; + void *ptr = kbuf->data + kbuf->curr; + + type_len_ts = read_4(kbuf, ptr); + ptr += 4; + + type = type4host(kbuf, type_len_ts); + len = len4host(kbuf, type_len_ts); + delta = ts4host(kbuf, type_len_ts); + + switch (type) { + case OLD_RINGBUF_TYPE_PADDING: + kbuf->next = kbuf->size; + return 0; + + case OLD_RINGBUF_TYPE_TIME_EXTEND: + extend = read_4(kbuf, ptr); + extend <<= TS_SHIFT; + extend += delta; + delta = extend; + ptr += 4; + break; + + case OLD_RINGBUF_TYPE_TIME_STAMP: + /* should never happen! */ + kbuf->curr = kbuf->size; + kbuf->next = kbuf->size; + kbuf->index = kbuf->size; + return -1; + default: + if (len) + length = len * 4; + else { + length = read_4(kbuf, ptr); + length -= 4; + ptr += 4; + } + break; + } + + kbuf->timestamp += delta; + kbuf->index = calc_index(kbuf, ptr); + kbuf->next = kbuf->index + length; + + return type; +} + +static int __old_next_event(struct kbuffer *kbuf) +{ + int type; + + do { + kbuf->curr = kbuf->next; + if (kbuf->next >= kbuf->size) + return -1; + type = old_update_pointers(kbuf); + } while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING); + + return 0; +} + +static unsigned int +translate_data(struct kbuffer *kbuf, void *data, void **rptr, + unsigned long long *delta, int *length) +{ + unsigned long long extend; + unsigned int type_len_ts; + unsigned int type_len; + + type_len_ts = read_4(kbuf, data); + data += 4; + + type_len = type_len4host(kbuf, type_len_ts); + *delta = ts4host(kbuf, type_len_ts); + + switch (type_len) { + case KBUFFER_TYPE_PADDING: + *length = read_4(kbuf, data); + data += *length; + break; + + case KBUFFER_TYPE_TIME_EXTEND: + extend = read_4(kbuf, data); + data += 4; + extend <<= TS_SHIFT; + extend += *delta; + *delta = extend; + *length = 0; + break; + + case KBUFFER_TYPE_TIME_STAMP: + data += 12; + *length = 0; + break; + case 0: + *length = read_4(kbuf, data) - 4; + *length = (*length + 3) & ~3; + data += 4; + break; + default: + *length = type_len * 4; + break; + } + + *rptr = data; + + return type_len; +} + +static unsigned int update_pointers(struct kbuffer *kbuf) +{ + unsigned long long delta; + unsigned int type_len; + int length; + void *ptr = kbuf->data + kbuf->curr; + + type_len = translate_data(kbuf, ptr, &ptr, &delta, &length); + + kbuf->timestamp += delta; + kbuf->index = calc_index(kbuf, ptr); + kbuf->next = kbuf->index + length; + + return type_len; +} + +/** + * kbuffer_translate_data - read raw data to get a record + * @swap: Set to 1 if bytes in words need to be swapped when read + * @data: The raw data to read + * @size: Address to store the size of the event data. + * + * Returns a pointer to the event data. To determine the entire + * record size (record metadata + data) just add the difference between + * @data and the returned value to @size. + */ +void *kbuffer_translate_data(int swap, void *data, unsigned int *size) +{ + unsigned long long delta; + struct kbuffer kbuf; + int type_len; + int length; + void *ptr; + + if (swap) { + kbuf.read_8 = __read_8_sw; + kbuf.read_4 = __read_4_sw; + kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN; + } else { + kbuf.read_8 = __read_8; + kbuf.read_4 = __read_4; + kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0; + } + + type_len = translate_data(&kbuf, data, &ptr, &delta, &length); + switch (type_len) { + case KBUFFER_TYPE_PADDING: + case KBUFFER_TYPE_TIME_EXTEND: + case KBUFFER_TYPE_TIME_STAMP: + return NULL; + }; + + *size = length; + + return ptr; +} + +static int __next_event(struct kbuffer *kbuf) +{ + int type; + + do { + kbuf->curr = kbuf->next; + if (kbuf->next >= kbuf->size) + return -1; + type = update_pointers(kbuf); + } while (type == KBUFFER_TYPE_TIME_EXTEND || type == KBUFFER_TYPE_PADDING); + + return 0; +} + +static int next_event(struct kbuffer *kbuf) +{ + return kbuf->next_event(kbuf); +} + +/** + * kbuffer_next_event - increment the current pointer + * @kbuf: The kbuffer to read + * @ts: Address to store the next record's timestamp (may be NULL to ignore) + * + * Increments the pointers into the subbuffer of the kbuffer to point to the + * next event so that the next kbuffer_read_event() will return a + * new event. + * + * Returns the data of the next event if a new event exists on the subbuffer, + * NULL otherwise. + */ +void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts) +{ + int ret; + + if (!kbuf || !kbuf->subbuffer) + return NULL; + + ret = next_event(kbuf); + if (ret < 0) + return NULL; + + if (ts) + *ts = kbuf->timestamp; + + return kbuf->data + kbuf->index; +} + +/** + * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer + * @kbuf: The kbuffer to load + * @subbuffer: The subbuffer to load into @kbuf. + * + * Load a new subbuffer (page) into @kbuf. This will reset all + * the pointers and update the @kbuf timestamp. The next read will + * return the first event on @subbuffer. + * + * Returns 0 on succes, -1 otherwise. + */ +int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer) +{ + unsigned long long flags; + void *ptr = subbuffer; + + if (!kbuf || !subbuffer) + return -1; + + kbuf->subbuffer = subbuffer; + + kbuf->timestamp = read_8(kbuf, ptr); + ptr += 8; + + kbuf->curr = 0; + + if (kbuf->flags & KBUFFER_FL_LONG_8) + kbuf->start = 16; + else + kbuf->start = 12; + + kbuf->data = subbuffer + kbuf->start; + + flags = read_long(kbuf, ptr); + kbuf->size = (unsigned int)flags & COMMIT_MASK; + + if (flags & MISSING_EVENTS) { + if (flags & MISSING_STORED) { + ptr = kbuf->data + kbuf->size; + kbuf->lost_events = read_long(kbuf, ptr); + } else + kbuf->lost_events = -1; + } else + kbuf->lost_events = 0; + + kbuf->index = 0; + kbuf->next = 0; + + next_event(kbuf); + + return 0; +} + +/** + * kbuffer_read_event - read the next event in the kbuffer subbuffer + * @kbuf: The kbuffer to read from + * @ts: The address to store the timestamp of the event (may be NULL to ignore) + * + * Returns a pointer to the data part of the current event. + * NULL if no event is left on the subbuffer. + */ +void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts) +{ + if (!kbuf || !kbuf->subbuffer) + return NULL; + + if (kbuf->curr >= kbuf->size) + return NULL; + + if (ts) + *ts = kbuf->timestamp; + return kbuf->data + kbuf->index; +} + +/** + * kbuffer_timestamp - Return the timestamp of the current event + * @kbuf: The kbuffer to read from + * + * Returns the timestamp of the current (next) event. + */ +unsigned long long kbuffer_timestamp(struct kbuffer *kbuf) +{ + return kbuf->timestamp; +} + +/** + * kbuffer_read_at_offset - read the event that is at offset + * @kbuf: The kbuffer to read from + * @offset: The offset into the subbuffer + * @ts: The address to store the timestamp of the event (may be NULL to ignore) + * + * The @offset must be an index from the @kbuf subbuffer beginning. + * If @offset is bigger than the stored subbuffer, NULL will be returned. + * + * Returns the data of the record that is at @offset. Note, @offset does + * not need to be the start of the record, the offset just needs to be + * in the record (or beginning of it). + * + * Note, the kbuf timestamp and pointers are updated to the + * returned record. That is, kbuffer_read_event() will return the same + * data and timestamp, and kbuffer_next_event() will increment from + * this record. + */ +void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, + unsigned long long *ts) +{ + void *data; + + if (offset < kbuf->start) + offset = 0; + else + offset -= kbuf->start; + + /* Reset the buffer */ + kbuffer_load_subbuffer(kbuf, kbuf->subbuffer); + + while (kbuf->curr < offset) { + data = kbuffer_next_event(kbuf, ts); + if (!data) + break; + } + + return data; +} + +/** + * kbuffer_subbuffer_size - the size of the loaded subbuffer + * @kbuf: The kbuffer to read from + * + * Returns the size of the subbuffer. Note, this size is + * where the last event resides. The stored subbuffer may actually be + * bigger due to padding and such. + */ +int kbuffer_subbuffer_size(struct kbuffer *kbuf) +{ + return kbuf->size; +} + +/** + * kbuffer_curr_index - Return the index of the record + * @kbuf: The kbuffer to read from + * + * Returns the index from the start of the data part of + * the subbuffer to the current location. Note this is not + * from the start of the subbuffer. An index of zero will + * point to the first record. Use kbuffer_curr_offset() for + * the actually offset (that can be used by kbuffer_read_at_offset()) + */ +int kbuffer_curr_index(struct kbuffer *kbuf) +{ + return kbuf->curr; +} + +/** + * kbuffer_curr_offset - Return the offset of the record + * @kbuf: The kbuffer to read from + * + * Returns the offset from the start of the subbuffer to the + * current location. + */ +int kbuffer_curr_offset(struct kbuffer *kbuf) +{ + return kbuf->curr + kbuf->start; +} + +/** + * kbuffer_event_size - return the size of the event data + * @kbuf: The kbuffer to read + * + * Returns the size of the event data (the payload not counting + * the meta data of the record) of the current event. + */ +int kbuffer_event_size(struct kbuffer *kbuf) +{ + return kbuf->next - kbuf->index; +} + +/** + * kbuffer_curr_size - return the size of the entire record + * @kbuf: The kbuffer to read + * + * Returns the size of the entire record (meta data and payload) + * of the current event. + */ +int kbuffer_curr_size(struct kbuffer *kbuf) +{ + return kbuf->next - kbuf->curr; +} + +/** + * kbuffer_missed_events - return the # of missed events from last event. + * @kbuf: The kbuffer to read from + * + * Returns the # of missed events (if recorded) before the current + * event. Note, only events on the beginning of a subbuffer can + * have missed events, all other events within the buffer will be + * zero. + */ +int kbuffer_missed_events(struct kbuffer *kbuf) +{ + /* Only the first event can have missed events */ + if (kbuf->curr) + return 0; + + return kbuf->lost_events; +} + +/** + * kbuffer_set_old_forma - set the kbuffer to use the old format parsing + * @kbuf: The kbuffer to set + * + * This is obsolete (or should be). The first kernels to use the + * new ring buffer had a slightly different ring buffer format + * (2.6.30 and earlier). It is still somewhat supported by kbuffer, + * but should not be counted on in the future. + */ +void kbuffer_set_old_format(struct kbuffer *kbuf) +{ + kbuf->flags |= KBUFFER_FL_OLD_FORMAT; + + kbuf->next_event = __old_next_event; +} diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h new file mode 100644 index 000000000000..c831f64b17a0 --- /dev/null +++ b/tools/lib/traceevent/kbuffer.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 Red Hat Inc, Steven Rostedt + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License (not later!) + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#ifndef _KBUFFER_H +#define _KBUFFER_H + +#ifndef TS_SHIFT +#define TS_SHIFT 27 +#endif + +enum kbuffer_endian { + KBUFFER_ENDIAN_BIG, + KBUFFER_ENDIAN_LITTLE, +}; + +enum kbuffer_long_size { + KBUFFER_LSIZE_4, + KBUFFER_LSIZE_8, +}; + +enum { + KBUFFER_TYPE_PADDING = 29, + KBUFFER_TYPE_TIME_EXTEND = 30, + KBUFFER_TYPE_TIME_STAMP = 31, +}; + +struct kbuffer; + +struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian); +void kbuffer_free(struct kbuffer *kbuf); +int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer); +void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts); +void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts); +unsigned long long kbuffer_timestamp(struct kbuffer *kbuf); + +void *kbuffer_translate_data(int swap, void *data, unsigned int *size); + +void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts); + +int kbuffer_curr_index(struct kbuffer *kbuf); + +int kbuffer_curr_offset(struct kbuffer *kbuf); +int kbuffer_curr_size(struct kbuffer *kbuf); +int kbuffer_event_size(struct kbuffer *kbuf); +int kbuffer_missed_events(struct kbuffer *kbuf); +int kbuffer_subbuffer_size(struct kbuffer *kbuf); + +void kbuffer_set_old_format(struct kbuffer *kbuf); + +#endif /* _K_BUFFER_H */ From 30f36762aab575f2894f7528d91ecd0b6e26e3e4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:22 +0900 Subject: [PATCH 0175/6183] perf util: Save page size in a trace file to pevent We now have page_size field in struct pevent, save the actual size of the system. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-8-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-read.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index af215c0d2379..c6b491bcb8cd 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -349,6 +349,7 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) int show_funcs = 0; int show_printk = 0; ssize_t size = -1; + int file_page_size; struct pevent *pevent; int err; @@ -393,10 +394,12 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) goto out; long_size = buf[0]; - page_size = read4(pevent); - if (!page_size) + file_page_size = read4(pevent); + if (!file_page_size) goto out; + pevent_set_page_size(pevent, file_page_size); + err = read_header_files(pevent); if (err) goto out; From 59657f9c8dd91363f1c94c1f749b33ecf626cfc2 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:23 +0900 Subject: [PATCH 0176/6183] perf util: Save long size of traced system Save size of long type of system to struct pevent. Since original static variable was not used anywhere, just get rid of it. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-9-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-read.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index c6b491bcb8cd..6166294d7f22 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -41,7 +41,6 @@ static int input_fd; int file_bigendian; int host_bigendian; -static int long_size; static ssize_t trace_data_size; static bool repipe; @@ -231,12 +230,6 @@ static int read_header_files(struct pevent *pevent) size = read8(pevent); skip(size); - /* - * The size field in the page is of type long, - * use that instead, since it represents the kernel. - */ - long_size = header_page_size_size; - if (do_read(buf, 13) < 0) return -1; @@ -349,6 +342,7 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) int show_funcs = 0; int show_printk = 0; ssize_t size = -1; + int file_long_size; int file_page_size; struct pevent *pevent; int err; @@ -392,12 +386,13 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) if (do_read(buf, 1) < 0) goto out; - long_size = buf[0]; + file_long_size = buf[0]; file_page_size = read4(pevent); if (!file_page_size) goto out; + pevent_set_long_size(pevent, file_long_size); pevent_set_page_size(pevent, file_page_size); err = read_header_files(pevent); From 63af28fa167374e470c32570b7c955c4d973dda4 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:24 +0900 Subject: [PATCH 0177/6183] perf util: Make file/host_bigendian variable local They're not used anywhere, just make them local variables. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-10-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-read.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 6166294d7f22..0dd9fbda88eb 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -39,9 +39,6 @@ static int input_fd; -int file_bigendian; -int host_bigendian; - static ssize_t trace_data_size; static bool repipe; @@ -342,6 +339,8 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) int show_funcs = 0; int show_printk = 0; ssize_t size = -1; + int file_bigendian; + int host_bigendian; int file_long_size; int file_page_size; struct pevent *pevent; From 2b2efc7fb8a3ede936580e870c5f809e491c925c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:25 +0900 Subject: [PATCH 0178/6183] perf util: Skip reading header_event file It seems perf does not parse header_event file so we can skip it as we do for header_page file. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-11-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-read.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 0dd9fbda88eb..fa45fca2a2d3 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -212,7 +212,6 @@ static int read_ftrace_printk(struct pevent *pevent) static int read_header_files(struct pevent *pevent) { unsigned long long size; - char *header_event; char buf[BUFSIZ]; int ret = 0; @@ -236,14 +235,8 @@ static int read_header_files(struct pevent *pevent) } size = read8(pevent); - header_event = malloc(size); - if (header_event == NULL) - return -1; + skip(size); - if (do_read(header_event, size) < 0) - ret = -1; - - free(header_event); return ret; } From 94b4d89e0021fe3e10415feede364a3fccaa2f89 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:26 +0900 Subject: [PATCH 0179/6183] perf util: Parse header_page to get proper long size The header_page file describes the format of the ring buffer page which is used by ftrace (not perf). And size of "commit" field (I guess it's older name was 'size') represents the real size of long type used for kernel. So update the pevent's long size. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-12-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-read.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index fa45fca2a2d3..f2112270c663 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -212,6 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent) static int read_header_files(struct pevent *pevent) { unsigned long long size; + char *header_page; char buf[BUFSIZ]; int ret = 0; @@ -224,7 +225,26 @@ static int read_header_files(struct pevent *pevent) } size = read8(pevent); - skip(size); + + header_page = malloc(size); + if (header_page == NULL) + return -1; + + if (do_read(header_page, size) < 0) { + pr_debug("did not read header page"); + free(header_page); + return -1; + } + + if (!pevent_parse_header_page(pevent, header_page, size, + pevent_get_long_size(pevent))) { + /* + * The commit field in the page is of type long, + * use that instead, since it represents the kernel. + */ + pevent_set_long_size(pevent, pevent->header_page_size_size); + } + free(header_page); if (do_read(buf, 13) < 0) return -1; From 9515b2eb7670a98fb9bdd8ceeefeea6ffb9f53fc Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:27 +0900 Subject: [PATCH 0180/6183] perf util: Get rid of unused header_page_* variables They're not used anywhere and same information is kept in a pevent already. So let's get rid of them. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-13-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-parse.c | 4 ---- tools/perf/util/trace-event.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 4454835a9ebc..0deae885c7ba 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -28,10 +28,6 @@ #include "util.h" #include "trace-event.h" -int header_page_size_size; -int header_page_ts_size; -int header_page_data_offset; - bool latency_format; struct pevent *read_trace_init(int file_bigendian, int host_bigendian) diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 11eb7fd37608..761c4846e0c7 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -10,10 +10,6 @@ struct perf_sample; union perf_event; struct perf_tool; -extern int header_page_size_size; -extern int header_page_ts_size; -extern int header_page_data_offset; - extern bool latency_format; extern struct pevent *perf_pevent; From 47390ae2afb6695c56810a9fc74fb930266addd0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:28 +0900 Subject: [PATCH 0181/6183] perf script: Adopt latency_format variable It's the only user of the variable, so move it. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-14-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 1 + tools/perf/util/trace-event-parse.c | 2 -- tools/perf/util/trace-event.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 92d4658f56fb..3de8979fe87d 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -24,6 +24,7 @@ static u64 last_timestamp; static u64 nr_unordered; extern const struct option record_options[]; static bool no_callchain; +static bool latency_format; static bool system_wide; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0deae885c7ba..fe7a27d67d2b 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -28,8 +28,6 @@ #include "util.h" #include "trace-event.h" -bool latency_format; - struct pevent *read_trace_init(int file_bigendian, int host_bigendian) { struct pevent *pevent = pevent_alloc(); diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 761c4846e0c7..ed30c9c09cd0 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -10,7 +10,6 @@ struct perf_sample; union perf_event; struct perf_tool; -extern bool latency_format; extern struct pevent *perf_pevent; enum { From 077f159d0402ac90a3ea9975f4089a042e0be065 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:29 +0900 Subject: [PATCH 0182/6183] perf util: Rename read_*() functions in trace-event-info.c It's confusing to have same name for two difference functions which does something opposite way. Since what they do in this file is read *AND* writing some of tracing metadata files, rename them to record_*() looks better to me. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-15-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-info.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index a42624a6cb5c..a800f2b8ccfc 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -101,7 +101,7 @@ out: return err; } -static int read_header_files(void) +static int record_header_files(void) { char *path; struct stat st; @@ -240,7 +240,7 @@ out: return err; } -static int read_ftrace_files(struct tracepoint_path *tps) +static int record_ftrace_files(struct tracepoint_path *tps) { char *path; int ret; @@ -269,7 +269,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) return false; } -static int read_event_files(struct tracepoint_path *tps) +static int record_event_files(struct tracepoint_path *tps) { struct dirent *dent; struct stat st; @@ -344,7 +344,7 @@ out: return err; } -static int read_proc_kallsyms(void) +static int record_proc_kallsyms(void) { unsigned int size; const char *path = "/proc/kallsyms"; @@ -362,7 +362,7 @@ static int read_proc_kallsyms(void) return record_file(path, 4); } -static int read_ftrace_printk(void) +static int record_ftrace_printk(void) { unsigned int size; char *path; @@ -539,19 +539,19 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, err = tracing_data_header(); if (err) goto out; - err = read_header_files(); + err = record_header_files(); if (err) goto out; - err = read_ftrace_files(tps); + err = record_ftrace_files(tps); if (err) goto out; - err = read_event_files(tps); + err = record_event_files(tps); if (err) goto out; - err = read_proc_kallsyms(); + err = record_proc_kallsyms(); if (err) goto out; - err = read_ftrace_printk(); + err = record_ftrace_printk(); out: /* From cfd0e8cf7fe7ad6f6c08e23ca4410bd718eeaf0b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:30 +0900 Subject: [PATCH 0183/6183] perf util: No need to call read_trace_init() in tracing_data_header() It's useless to call the read_trace_init() function at this time as we don't need a returned pevent and it makes me confusing. :) Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-16-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-info.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index a800f2b8ccfc..f3c9e551bd35 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -476,8 +476,6 @@ static int tracing_data_header(void) else buf[0] = 0; - read_trace_init(buf[0], buf[0]); - if (write(output_fd, buf, 1) != 1) return -1; From 45a9ee1b3fa2d8c3fb7a0c7e5a7b77281a4239a6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:20:31 +0900 Subject: [PATCH 0184/6183] perf util: Remove unused enum and macro in trace-event.h They're internals of ftrace ring-buffer and not used in perf code directly. As it now resides on libtraceevent/kbuffer.h, just get rid of them. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1370323231-14022-17-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index ed30c9c09cd0..669a64a660d7 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -12,16 +12,6 @@ struct perf_tool; extern struct pevent *perf_pevent; -enum { - RINGBUF_TYPE_PADDING = 29, - RINGBUF_TYPE_TIME_EXTEND = 30, - RINGBUF_TYPE_TIME_STAMP = 31, -}; - -#ifndef TS_SHIFT -#define TS_SHIFT 27 -#endif - int bigendian(void); struct pevent *read_trace_init(int file_bigendian, int host_bigendian); From f36f83f947ede547833e462696893f866df77324 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 14:46:19 +0900 Subject: [PATCH 0185/6183] perf sched: Move struct perf_sched definition out of cmd_sched() For some reason it consumed quite amount of compile time when declared as local variable, and it disappeared when moved out of the function. Moving other variables/tables didn't help. On my system this single-file-change build time reduced from 11s to 3s. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1370324779-16921-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index fed9ae432c16..fba4a940ba31 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv) return cmd_record(i, rec_argv, NULL); } +static const char default_sort_order[] = "avg, max, switch, runtime"; +static struct perf_sched sched = { + .tool = { + .sample = perf_sched__process_tracepoint_sample, + .comm = perf_event__process_comm, + .lost = perf_event__process_lost, + .fork = perf_event__process_fork, + .ordered_samples = true, + }, + .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), + .sort_list = LIST_HEAD_INIT(sched.sort_list), + .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, + .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, + .curr_pid = { [0 ... MAX_CPUS - 1] = -1 }, + .sort_order = default_sort_order, + .replay_repeat = 10, + .profile_cpu = -1, + .next_shortname1 = 'A', + .next_shortname2 = '0', +}; + int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) { - const char default_sort_order[] = "avg, max, switch, runtime"; - struct perf_sched sched = { - .tool = { - .sample = perf_sched__process_tracepoint_sample, - .comm = perf_event__process_comm, - .lost = perf_event__process_lost, - .fork = perf_event__process_fork, - .ordered_samples = true, - }, - .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), - .sort_list = LIST_HEAD_INIT(sched.sort_list), - .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, - .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, - .curr_pid = { [0 ... MAX_CPUS - 1] = -1 }, - .sort_order = default_sort_order, - .replay_repeat = 10, - .profile_cpu = -1, - .next_shortname1 = 'A', - .next_shortname2 = '0', - }; const struct option latency_options[] = { OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", "sort by key(s): runtime, switch, avg, max"), From f1d9a530553eed9e598d1597a2a348f01810dd4a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 18:22:12 +0900 Subject: [PATCH 0186/6183] perf gtk/hists: Use GtkTreeStore instead of GtkListStore The GtkTreeStore can save items in a tree-like way. This is a preparation for supporting callgraphs in the hist browser. Reviewed-by: Pekka Enberg Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370337737-30812-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 9708dd5fb8f3..cb6a9b45f789 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -131,7 +131,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, GType col_types[MAX_COLUMNS]; GtkCellRenderer *renderer; struct sort_entry *se; - GtkListStore *store; + GtkTreeStore *store; struct rb_node *nd; GtkWidget *view; int col_idx; @@ -156,7 +156,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, col_types[nr_cols++] = G_TYPE_STRING; } - store = gtk_list_store_newv(nr_cols, col_types); + store = gtk_tree_store_newv(nr_cols, col_types); view = gtk_tree_view_new(); @@ -199,7 +199,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, if (percent < min_pcnt) continue; - gtk_list_store_append(store, &iter); + gtk_tree_store_append(store, &iter, NULL); col_idx = 0; @@ -209,7 +209,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, else fmt->entry(&hpp, h); - gtk_list_store_set(store, &iter, col_idx++, s, -1); + gtk_tree_store_set(store, &iter, col_idx++, s, -1); } list_for_each_entry(se, &hist_entry__sort_list, list) { @@ -219,7 +219,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, se->se_snprintf(h, s, ARRAY_SIZE(s), hists__col_len(hists, se->se_width_idx)); - gtk_list_store_set(store, &iter, col_idx++, s, -1); + gtk_tree_store_set(store, &iter, col_idx++, s, -1); } } From 2bbc5874251830fee170a0fc97fa5788717d2fd9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 18:22:13 +0900 Subject: [PATCH 0187/6183] perf gtk/hists: Add support for callchains Display callchain information in the symbol column. It's only enabled when recorded with -g and has symbol sort key. Reviewed-by: Pekka Enberg Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370337737-30812-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index cb6a9b45f789..226c7e10f3cc 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -124,6 +124,55 @@ void perf_gtk__init_hpp(void) perf_gtk__hpp_color_overhead_guest_us; } +static void callchain_list__sym_name(struct callchain_list *cl, + char *bf, size_t bfsize) +{ + if (cl->ms.sym) + scnprintf(bf, bfsize, "%s", cl->ms.sym->name); + else + scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); +} + +static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, + GtkTreeIter *parent, int col) +{ + struct rb_node *nd; + bool has_single_node = (rb_first(root) == rb_last(root)); + + for (nd = rb_first(root); nd; nd = rb_next(nd)) { + struct callchain_node *node; + struct callchain_list *chain; + GtkTreeIter iter, new_parent; + bool need_new_parent; + + node = rb_entry(nd, struct callchain_node, rb_node); + + new_parent = *parent; + need_new_parent = !has_single_node && (node->val_nr > 1); + + list_for_each_entry(chain, &node->val, list) { + char buf[128]; + + gtk_tree_store_append(store, &iter, &new_parent); + + callchain_list__sym_name(chain, buf, sizeof(buf)); + gtk_tree_store_set(store, &iter, col, buf, -1); + + if (need_new_parent) { + /* + * Only show the top-most symbol in a callchain + * if it's not the only callchain. + */ + new_parent = iter; + need_new_parent = false; + } + } + + /* Now 'iter' contains info of the last callchain_list */ + perf_gtk__add_callchain(&node->rb_root, store, &iter, col); + } +} + static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, float min_pcnt) { @@ -135,6 +184,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, struct rb_node *nd; GtkWidget *view; int col_idx; + int sym_col = -1; int nr_cols; char s[512]; @@ -153,6 +203,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, if (se->elide) continue; + if (se == &sort_sym) + sym_col = nr_cols; + col_types[nr_cols++] = G_TYPE_STRING; } @@ -183,6 +236,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, col_idx++, NULL); } + if (symbol_conf.use_callchain && sort__has_sym) { + GtkTreeViewColumn *column; + + column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), sym_col); + gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view), column); + } + gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); g_object_unref(GTK_TREE_MODEL(store)); @@ -221,6 +281,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, gtk_tree_store_set(store, &iter, col_idx++, s, -1); } + + if (symbol_conf.use_callchain && sort__has_sym) { + perf_gtk__add_callchain(&h->sorted_chain, store, &iter, + sym_col); + } } gtk_container_add(GTK_CONTAINER(window), view); From cc60f24e225e50a0b57398f9ba105fd8ffcf4bb3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 18:22:14 +0900 Subject: [PATCH 0188/6183] perf gtk/hists: Display callchain overhead also Display callchain percent value in the overhead column. Signed-off-by: Namhyung Kim Reviewed-by: Pekka Enberg Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370337737-30812-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 226c7e10f3cc..fa9f8a09233e 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -134,7 +134,7 @@ static void callchain_list__sym_name(struct callchain_list *cl, } static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, - GtkTreeIter *parent, int col) + GtkTreeIter *parent, int col, u64 total) { struct rb_node *nd; bool has_single_node = (rb_first(root) == rb_last(root)); @@ -144,9 +144,14 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, struct callchain_list *chain; GtkTreeIter iter, new_parent; bool need_new_parent; + double percent; + u64 hits, child_total; node = rb_entry(nd, struct callchain_node, rb_node); + hits = callchain_cumul_hits(node); + percent = 100.0 * hits / total; + new_parent = *parent; need_new_parent = !has_single_node && (node->val_nr > 1); @@ -155,6 +160,9 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, gtk_tree_store_append(store, &iter, &new_parent); + scnprintf(buf, sizeof(buf), "%5.2f%%", percent); + gtk_tree_store_set(store, &iter, 0, buf, -1); + callchain_list__sym_name(chain, buf, sizeof(buf)); gtk_tree_store_set(store, &iter, col, buf, -1); @@ -168,8 +176,14 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, } } + if (callchain_param.mode == CHAIN_GRAPH_REL) + child_total = node->children_hit; + else + child_total = total; + /* Now 'iter' contains info of the last callchain_list */ - perf_gtk__add_callchain(&node->rb_root, store, &iter, col); + perf_gtk__add_callchain(&node->rb_root, store, &iter, col, + child_total); } } @@ -283,8 +297,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, } if (symbol_conf.use_callchain && sort__has_sym) { + u64 total; + + if (callchain_param.mode == CHAIN_GRAPH_REL) + total = h->stat.period; + else + total = hists->stats.total_period; + perf_gtk__add_callchain(&h->sorted_chain, store, &iter, - sym_col); + sym_col, total); } } From 1a309426b4fae258dbd86ac0c575a849bf163b7b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 18:22:15 +0900 Subject: [PATCH 0189/6183] perf gtk/hists: Make column headers resizable Sometimes it's annoying to see when some symbols have very wierd long names. So it might be a good idea to make column size changable. Reviewed-by: Pekka Enberg Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370337737-30812-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index fa9f8a09233e..b4a0dd2404a2 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -250,11 +250,16 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, col_idx++, NULL); } - if (symbol_conf.use_callchain && sort__has_sym) { + for (col_idx = 0; col_idx < nr_cols; col_idx++) { GtkTreeViewColumn *column; - column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), sym_col); - gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view), column); + column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx); + gtk_tree_view_column_set_resizable(column, TRUE); + + if (col_idx == sym_col) { + gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view), + column); + } } gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); From 450f390ad2538c5e35d830fa5c624708a77dce0a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 18:22:16 +0900 Subject: [PATCH 0190/6183] perf gtk/hists: Add a double-click handler for callchains If callchain is displayed, add "row-activated" signal handler for handling double-click or pressing ENTER key action. Reviewed-by: Pekka Enberg Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370337737-30812-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index b4a0dd2404a2..3a5d01319988 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -187,6 +187,18 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, } } +static void on_row_activated(GtkTreeView *view, GtkTreePath *path, + GtkTreeViewColumn *col __maybe_unused, + gpointer user_data __maybe_unused) +{ + bool expanded = gtk_tree_view_row_expanded(view, path); + + if (expanded) + gtk_tree_view_collapse_row(view, path); + else + gtk_tree_view_expand_row(view, path, FALSE); +} + static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, float min_pcnt) { @@ -314,6 +326,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, } } + g_signal_connect(view, "row-activated", + G_CALLBACK(on_row_activated), NULL); gtk_container_add(GTK_CONTAINER(window), view); } From 9d58d2f66c92fe47dd395947a3d51b9ace7dcc92 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 4 Jun 2013 18:22:17 +0900 Subject: [PATCH 0191/6183] perf gtk/hists: Set rules hint for the hist browser The 'rules' means that every second line of the tree view has a shaded background, which makes it easier to see which cell belongs to which row in the tree view. It can be useful for a tree view that has a lot of rows. Reviewed-by: Pekka Enberg Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1370337737-30812-7-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 3a5d01319988..32549035f50d 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -326,6 +326,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, } } + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); + g_signal_connect(view, "row-activated", G_CALLBACK(on_row_activated), NULL); gtk_container_add(GTK_CONTAINER(window), view); From 63c2c9f8f24378ebf46d4a9d542863bb733ef05c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:20 +0300 Subject: [PATCH 0192/6183] perf inject: Remove unused parameter The 'machine' parameter is unused in 'perf_event__repipe_synth()' and some callers pass NULL anyway. So remove it. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 84ad6abe4258..f299ddf29967 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -38,8 +38,7 @@ struct event_entry { }; static int perf_event__repipe_synth(struct perf_tool *tool, - union perf_event *event, - struct machine *machine __maybe_unused) + union perf_event *event) { struct perf_inject *inject = container_of(tool, struct perf_inject, tool); uint32_t size; @@ -65,20 +64,20 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool, struct perf_session *session __maybe_unused) { - return perf_event__repipe_synth(tool, event, NULL); + return perf_event__repipe_synth(tool, event); } static int perf_event__repipe_event_type_synth(struct perf_tool *tool, union perf_event *event) { - return perf_event__repipe_synth(tool, event, NULL); + return perf_event__repipe_synth(tool, event); } static int perf_event__repipe_tracing_data_synth(union perf_event *event, struct perf_session *session __maybe_unused) { - return perf_event__repipe_synth(NULL, event, NULL); + return perf_event__repipe_synth(NULL, event); } static int perf_event__repipe_attr(union perf_event *event, @@ -89,15 +88,15 @@ static int perf_event__repipe_attr(union perf_event *event, if (ret) return ret; - return perf_event__repipe_synth(NULL, event, NULL); + return perf_event__repipe_synth(NULL, event); } static int perf_event__repipe(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __maybe_unused, - struct machine *machine) + struct machine *machine __maybe_unused) { - return perf_event__repipe_synth(tool, event, machine); + return perf_event__repipe_synth(tool, event); } typedef int (*inject_handler)(struct perf_tool *tool, @@ -119,7 +118,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool, build_id__mark_dso_hit(tool, event, sample, evsel, machine); - return perf_event__repipe_synth(tool, event, machine); + return perf_event__repipe_synth(tool, event); } static int perf_event__repipe_mmap(struct perf_tool *tool, @@ -153,7 +152,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event, { int err; - perf_event__repipe_synth(NULL, event, NULL); + perf_event__repipe_synth(NULL, event); err = perf_event__process_tracing_data(event, session); return err; From 47c3d1091cb68e727b840efd6fa3709d5b1ddfc2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:21 +0300 Subject: [PATCH 0193/6183] perf tools: Fix missing tool parameter The 'inject' command expects to get a reference to 'struct perf_inject' from its 'tool' member. For that to work, 'tool' needs to be a parameter of all tool callbacks. Make it so. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 26 +++++++++++--------------- tools/perf/util/header.c | 6 ++++-- tools/perf/util/header.h | 6 ++++-- tools/perf/util/session.c | 11 +++++++---- tools/perf/util/tool.h | 9 ++++----- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index f299ddf29967..c943513d06be 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -73,22 +73,17 @@ static int perf_event__repipe_event_type_synth(struct perf_tool *tool, return perf_event__repipe_synth(tool, event); } -static int perf_event__repipe_tracing_data_synth(union perf_event *event, - struct perf_session *session - __maybe_unused) -{ - return perf_event__repipe_synth(NULL, event); -} - -static int perf_event__repipe_attr(union perf_event *event, - struct perf_evlist **pevlist __maybe_unused) +static int perf_event__repipe_attr(struct perf_tool *tool, + union perf_event *event, + struct perf_evlist **pevlist) { int ret; - ret = perf_event__process_attr(event, pevlist); + + ret = perf_event__process_attr(tool, event, pevlist); if (ret) return ret; - return perf_event__repipe_synth(NULL, event); + return perf_event__repipe_synth(tool, event); } static int perf_event__repipe(struct perf_tool *tool, @@ -147,13 +142,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool, return err; } -static int perf_event__repipe_tracing_data(union perf_event *event, +static int perf_event__repipe_tracing_data(struct perf_tool *tool, + union perf_event *event, struct perf_session *session) { int err; - perf_event__repipe_synth(NULL, event); - err = perf_event__process_tracing_data(event, session); + perf_event__repipe_synth(tool, event); + err = perf_event__process_tracing_data(tool, event, session); return err; } @@ -407,7 +403,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .unthrottle = perf_event__repipe, .attr = perf_event__repipe_attr, .event_type = perf_event__repipe_event_type_synth, - .tracing_data = perf_event__repipe_tracing_data_synth, + .tracing_data = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth, }, .input_name = "-", diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a4dafbee2511..d12d79cf8d32 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2922,7 +2922,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, return err; } -int perf_event__process_attr(union perf_event *event, +int perf_event__process_attr(struct perf_tool *tool __maybe_unused, + union perf_event *event, struct perf_evlist **pevlist) { u32 i, ids, n_ids; @@ -3065,7 +3066,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, return aligned_size; } -int perf_event__process_tracing_data(union perf_event *event, +int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, + union perf_event *event, struct perf_session *session) { ssize_t size_read, padding, size = event->tracing_data.size; diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 16a3e83c584e..2d1ca7d3ca9c 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -130,7 +130,8 @@ int perf_event__synthesize_attr(struct perf_tool *tool, int perf_event__synthesize_attrs(struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process); -int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); +int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, + struct perf_evlist **pevlist); int perf_event__synthesize_event_type(struct perf_tool *tool, u64 event_id, char *name, @@ -145,7 +146,8 @@ int perf_event__process_event_type(struct perf_tool *tool, int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process); -int perf_event__process_tracing_data(union perf_event *event, +int perf_event__process_tracing_data(struct perf_tool *tool, + union perf_event *event, struct perf_session *session); int perf_event__synthesize_build_id(struct perf_tool *tool, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ad47fb9d0204..6b71b88f95fa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -193,7 +193,9 @@ void perf_session__delete(struct perf_session *self) vdso__exit(); } -static int process_event_synth_tracing_data_stub(union perf_event *event +static int process_event_synth_tracing_data_stub(struct perf_tool *tool + __maybe_unused, + union perf_event *event __maybe_unused, struct perf_session *session __maybe_unused) @@ -202,7 +204,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event return 0; } -static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, +static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, struct perf_evlist **pevlist __maybe_unused) { @@ -921,7 +924,7 @@ static int perf_session__process_user_event(struct perf_session *session, union /* These events are processed right away */ switch (event->header.type) { case PERF_RECORD_HEADER_ATTR: - err = tool->attr(event, &session->evlist); + err = tool->attr(tool, event, &session->evlist); if (err == 0) perf_session__set_id_hdr_size(session); return err; @@ -930,7 +933,7 @@ static int perf_session__process_user_event(struct perf_session *session, union case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(session->fd, file_offset, SEEK_SET); - return tool->tracing_data(event, session); + return tool->tracing_data(tool, event, session); case PERF_RECORD_HEADER_BUILD_ID: return tool->build_id(tool, event, session); case PERF_RECORD_FINISHED_ROUND: diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index b0e1aadba8d5..88f8cbdb8a34 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -18,12 +18,11 @@ typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -typedef int (*event_attr_op)(union perf_event *event, +typedef int (*event_attr_op)(struct perf_tool *tool, + union perf_event *event, struct perf_evlist **pevlist); -typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event); -typedef int (*event_synth_op)(union perf_event *event, - struct perf_session *session); +typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event); typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, struct perf_session *session); @@ -39,7 +38,7 @@ struct perf_tool { throttle, unthrottle; event_attr_op attr; - event_synth_op tracing_data; + event_op2 tracing_data; event_simple_op event_type; event_op2 finished_round, build_id; From a609bda78203a21fb0e78b9d5b4ab911678e4ebb Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:22 +0300 Subject: [PATCH 0194/6183] perf inject: Add missing 'finished_round' By default, perf inject should "repipe" all events including 'finished_round'. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index c943513d06be..ad1296c6f88c 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -404,6 +404,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .attr = perf_event__repipe_attr, .event_type = perf_event__repipe_event_type_synth, .tracing_data = perf_event__repipe_op2_synth, + .finished_round = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth, }, .input_name = "-", From b6b96fb48f75d62858b39baf13c83c4504642f15 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:25 +0300 Subject: [PATCH 0195/6183] perf tools: Add const specifier to perf_pmu__find name parameter The name parameter is constant, declare it so. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 14 +++++++------- tools/perf/util/pmu.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 4c6f9c490a8d..1d1862dcbbbc 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -73,7 +73,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head) * located at: * /sys/bus/event_source/devices//format as sysfs group attributes. */ -static int pmu_format(char *name, struct list_head *format) +static int pmu_format(const char *name, struct list_head *format) { struct stat st; char path[PATH_MAX]; @@ -162,7 +162,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) * Reading the pmu event aliases definition, which should be located at: * /sys/bus/event_source/devices//events as sysfs group attributes. */ -static int pmu_aliases(char *name, struct list_head *head) +static int pmu_aliases(const char *name, struct list_head *head) { struct stat st; char path[PATH_MAX]; @@ -208,7 +208,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias, * located at: * /sys/bus/event_source/devices//type as sysfs attribute. */ -static int pmu_type(char *name, __u32 *type) +static int pmu_type(const char *name, __u32 *type) { struct stat st; char path[PATH_MAX]; @@ -266,7 +266,7 @@ static void pmu_read_sysfs(void) closedir(dir); } -static struct cpu_map *pmu_cpumask(char *name) +static struct cpu_map *pmu_cpumask(const char *name) { struct stat st; char path[PATH_MAX]; @@ -293,7 +293,7 @@ static struct cpu_map *pmu_cpumask(char *name) return cpus; } -static struct perf_pmu *pmu_lookup(char *name) +static struct perf_pmu *pmu_lookup(const char *name) { struct perf_pmu *pmu; LIST_HEAD(format); @@ -330,7 +330,7 @@ static struct perf_pmu *pmu_lookup(char *name) return pmu; } -static struct perf_pmu *pmu_find(char *name) +static struct perf_pmu *pmu_find(const char *name) { struct perf_pmu *pmu; @@ -356,7 +356,7 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) return NULL; } -struct perf_pmu *perf_pmu__find(char *name) +struct perf_pmu *perf_pmu__find(const char *name) { struct perf_pmu *pmu; diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 32fe55b659fa..d17b5656bacf 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -21,7 +21,7 @@ struct perf_pmu { struct list_head list; }; -struct perf_pmu *perf_pmu__find(char *name); +struct perf_pmu *perf_pmu__find(const char *name); int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, struct list_head *head_terms); int perf_pmu__config_terms(struct list_head *formats, From 93edcbd91d888c7530c7fc749176fc935b8e2287 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:26 +0300 Subject: [PATCH 0196/6183] perf evlist: Tidy duplicated munmap code The same lines of code are used in three places. Make it a new function '__perf_evlist__munmap()'. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d8f34e0afbfb..42ea4e947eb8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) return event; } +static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) +{ + if (evlist->mmap[idx].base != NULL) { + munmap(evlist->mmap[idx].base, evlist->mmap_len); + evlist->mmap[idx].base = NULL; + } +} + void perf_evlist__munmap(struct perf_evlist *evlist) { int i; - for (i = 0; i < evlist->nr_mmaps; i++) { - if (evlist->mmap[i].base != NULL) { - munmap(evlist->mmap[i].base, evlist->mmap_len); - evlist->mmap[i].base = NULL; - } - } + for (i = 0; i < evlist->nr_mmaps; i++) + __perf_evlist__munmap(evlist, i); free(evlist->mmap); evlist->mmap = NULL; @@ -477,12 +481,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m return 0; out_unmap: - for (cpu = 0; cpu < nr_cpus; cpu++) { - if (evlist->mmap[cpu].base != NULL) { - munmap(evlist->mmap[cpu].base, evlist->mmap_len); - evlist->mmap[cpu].base = NULL; - } - } + for (cpu = 0; cpu < nr_cpus; cpu++) + __perf_evlist__munmap(evlist, cpu); return -1; } @@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in return 0; out_unmap: - for (thread = 0; thread < nr_threads; thread++) { - if (evlist->mmap[thread].base != NULL) { - munmap(evlist->mmap[thread].base, evlist->mmap_len); - evlist->mmap[thread].base = NULL; - } - } + for (thread = 0; thread < nr_threads; thread++) + __perf_evlist__munmap(evlist, thread); return -1; } From 84734a049d0ef2f6f5fb0a1fe060cd51480dd855 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 12 Jul 2013 16:50:57 +0300 Subject: [PATCH 0197/6183] drm/i915: move error state to own compilation unit Move error state generation and stringification to it's own compilation unit. Sysfs also uses this so it can't be under CONFIG_DEBUG_FS This fixes a regression introduced in commit ef86ddced720fddc3835558447a7f594d3609c73 Author: Mika Kuoppala Date: Thu Jun 6 17:38:54 2013 +0300 drm/i915: add error_state sysfs entry Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66814 Signed-off-by: Mika Kuoppala Reported-by: kbuild test robot Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_debugfs.c | 415 +---------- drivers/gpu/drm/i915/i915_drv.h | 24 +- drivers/gpu/drm/i915/i915_gpu_error.c | 971 ++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_irq.c | 529 -------------- drivers/gpu/drm/i915/intel_display.c | 4 - drivers/gpu/drm/i915/intel_overlay.c | 4 - 7 files changed, 983 insertions(+), 965 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gpu_error.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 40034ecefd3b..9d1da7cceb21 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -5,6 +5,7 @@ ccflags-y := -Iinclude/drm i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915_debugfs.o \ + i915_gpu_error.o \ i915_suspend.o \ i915_gem.o \ i915_gem_context.o \ diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d4138124d993..86379799dab8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include "intel_drv.h" #include "intel_ringbuffer.h" @@ -90,16 +89,6 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj) } } -static const char *cache_level_str(int type) -{ - switch (type) { - case I915_CACHE_NONE: return " uncached"; - case I915_CACHE_LLC: return " snooped (LLC)"; - case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)"; - default: return ""; - } -} - static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { @@ -113,7 +102,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) obj->last_read_seqno, obj->last_write_seqno, obj->last_fenced_seqno, - cache_level_str(obj->cache_level), + i915_cache_level_str(obj->cache_level), obj->dirty ? " dirty" : "", obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); if (obj->base.name) @@ -608,358 +597,6 @@ static int i915_hws_info(struct seq_file *m, void *data) return 0; } -static const char *ring_str(int ring) -{ - switch (ring) { - case RCS: return "render"; - case VCS: return "bsd"; - case BCS: return "blt"; - case VECS: return "vebox"; - default: return ""; - } -} - -static const char *pin_flag(int pinned) -{ - if (pinned > 0) - return " P"; - else if (pinned < 0) - return " p"; - else - return ""; -} - -static const char *tiling_flag(int tiling) -{ - switch (tiling) { - default: - case I915_TILING_NONE: return ""; - case I915_TILING_X: return " X"; - case I915_TILING_Y: return " Y"; - } -} - -static const char *dirty_flag(int dirty) -{ - return dirty ? " dirty" : ""; -} - -static const char *purgeable_flag(int purgeable) -{ - return purgeable ? " purgeable" : ""; -} - -static bool __i915_error_ok(struct drm_i915_error_state_buf *e) -{ - - if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { - e->err = -ENOSPC; - return false; - } - - if (e->bytes == e->size - 1 || e->err) - return false; - - return true; -} - -static bool __i915_error_seek(struct drm_i915_error_state_buf *e, - unsigned len) -{ - if (e->pos + len <= e->start) { - e->pos += len; - return false; - } - - /* First vsnprintf needs to fit in its entirety for memmove */ - if (len >= e->size) { - e->err = -EIO; - return false; - } - - return true; -} - -static void __i915_error_advance(struct drm_i915_error_state_buf *e, - unsigned len) -{ - /* If this is first printf in this window, adjust it so that - * start position matches start of the buffer - */ - - if (e->pos < e->start) { - const size_t off = e->start - e->pos; - - /* Should not happen but be paranoid */ - if (off > len || e->bytes) { - e->err = -EIO; - return; - } - - memmove(e->buf, e->buf + off, len - off); - e->bytes = len - off; - e->pos = e->start; - return; - } - - e->bytes += len; - e->pos += len; -} - -static void i915_error_vprintf(struct drm_i915_error_state_buf *e, - const char *f, va_list args) -{ - unsigned len; - - if (!__i915_error_ok(e)) - return; - - /* Seek the first printf which is hits start position */ - if (e->pos < e->start) { - len = vsnprintf(NULL, 0, f, args); - if (!__i915_error_seek(e, len)) - return; - } - - len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); - if (len >= e->size - e->bytes) - len = e->size - e->bytes - 1; - - __i915_error_advance(e, len); -} - -static void i915_error_puts(struct drm_i915_error_state_buf *e, - const char *str) -{ - unsigned len; - - if (!__i915_error_ok(e)) - return; - - len = strlen(str); - - /* Seek the first printf which is hits start position */ - if (e->pos < e->start) { - if (!__i915_error_seek(e, len)) - return; - } - - if (len >= e->size - e->bytes) - len = e->size - e->bytes - 1; - memcpy(e->buf + e->bytes, str, len); - - __i915_error_advance(e, len); -} - -void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) -{ - va_list args; - - va_start(args, f); - i915_error_vprintf(e, f, args); - va_end(args); -} - -#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) -#define err_puts(e, s) i915_error_puts(e, s) - -static void print_error_buffers(struct drm_i915_error_state_buf *m, - const char *name, - struct drm_i915_error_buffer *err, - int count) -{ - err_printf(m, "%s [%d]:\n", name, count); - - while (count--) { - err_printf(m, " %08x %8u %02x %02x %x %x", - err->gtt_offset, - err->size, - err->read_domains, - err->write_domain, - err->rseqno, err->wseqno); - err_puts(m, pin_flag(err->pinned)); - err_puts(m, tiling_flag(err->tiling)); - err_puts(m, dirty_flag(err->dirty)); - err_puts(m, purgeable_flag(err->purgeable)); - err_puts(m, err->ring != -1 ? " " : ""); - err_puts(m, ring_str(err->ring)); - err_puts(m, cache_level_str(err->cache_level)); - - if (err->name) - err_printf(m, " (name: %d)", err->name); - if (err->fence_reg != I915_FENCE_REG_NONE) - err_printf(m, " (fence: %d)", err->fence_reg); - - err_puts(m, "\n"); - err++; - } -} - -static void i915_ring_error_state(struct drm_i915_error_state_buf *m, - struct drm_device *dev, - struct drm_i915_error_state *error, - unsigned ring) -{ - BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */ - err_printf(m, "%s command stream:\n", ring_str(ring)); - err_printf(m, " HEAD: 0x%08x\n", error->head[ring]); - err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); - err_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); - err_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); - err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); - err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); - err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); - if (ring == RCS && INTEL_INFO(dev)->gen >= 4) - err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); - - if (INTEL_INFO(dev)->gen >= 4) - err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); - err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); - err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); - if (INTEL_INFO(dev)->gen >= 6) { - err_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]); - err_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); - err_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n", - error->semaphore_mboxes[ring][0], - error->semaphore_seqno[ring][0]); - err_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n", - error->semaphore_mboxes[ring][1], - error->semaphore_seqno[ring][1]); - } - err_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); - err_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); - err_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]); - err_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); -} - -int i915_error_state_to_str(struct drm_i915_error_state_buf *m, - const struct i915_error_state_file_priv *error_priv) -{ - struct drm_device *dev = error_priv->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_error_state *error = error_priv->error; - struct intel_ring_buffer *ring; - int i, j, page, offset, elt; - - if (!error) { - err_printf(m, "no error state collected\n"); - goto out; - } - - err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, - error->time.tv_usec); - err_printf(m, "Kernel: " UTS_RELEASE "\n"); - err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); - err_printf(m, "EIR: 0x%08x\n", error->eir); - err_printf(m, "IER: 0x%08x\n", error->ier); - err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); - err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); - err_printf(m, "DERRMR: 0x%08x\n", error->derrmr); - err_printf(m, "CCID: 0x%08x\n", error->ccid); - - for (i = 0; i < dev_priv->num_fence_regs; i++) - err_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); - - for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++) - err_printf(m, " INSTDONE_%d: 0x%08x\n", i, - error->extra_instdone[i]); - - if (INTEL_INFO(dev)->gen >= 6) { - err_printf(m, "ERROR: 0x%08x\n", error->error); - err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); - } - - if (INTEL_INFO(dev)->gen == 7) - err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); - - for_each_ring(ring, dev_priv, i) - i915_ring_error_state(m, dev, error, i); - - if (error->active_bo) - print_error_buffers(m, "Active", - error->active_bo, - error->active_bo_count); - - if (error->pinned_bo) - print_error_buffers(m, "Pinned", - error->pinned_bo, - error->pinned_bo_count); - - for (i = 0; i < ARRAY_SIZE(error->ring); i++) { - struct drm_i915_error_object *obj; - - if ((obj = error->ring[i].batchbuffer)) { - err_printf(m, "%s --- gtt_offset = 0x%08x\n", - dev_priv->ring[i].name, - obj->gtt_offset); - offset = 0; - for (page = 0; page < obj->page_count; page++) { - for (elt = 0; elt < PAGE_SIZE/4; elt++) { - err_printf(m, "%08x : %08x\n", offset, - obj->pages[page][elt]); - offset += 4; - } - } - } - - if (error->ring[i].num_requests) { - err_printf(m, "%s --- %d requests\n", - dev_priv->ring[i].name, - error->ring[i].num_requests); - for (j = 0; j < error->ring[i].num_requests; j++) { - err_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n", - error->ring[i].requests[j].seqno, - error->ring[i].requests[j].jiffies, - error->ring[i].requests[j].tail); - } - } - - if ((obj = error->ring[i].ringbuffer)) { - err_printf(m, "%s --- ringbuffer = 0x%08x\n", - dev_priv->ring[i].name, - obj->gtt_offset); - offset = 0; - for (page = 0; page < obj->page_count; page++) { - for (elt = 0; elt < PAGE_SIZE/4; elt++) { - err_printf(m, "%08x : %08x\n", - offset, - obj->pages[page][elt]); - offset += 4; - } - } - } - - obj = error->ring[i].ctx; - if (obj) { - err_printf(m, "%s --- HW Context = 0x%08x\n", - dev_priv->ring[i].name, - obj->gtt_offset); - offset = 0; - for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { - err_printf(m, "[%04x] %08x %08x %08x %08x\n", - offset, - obj->pages[0][elt], - obj->pages[0][elt+1], - obj->pages[0][elt+2], - obj->pages[0][elt+3]); - offset += 16; - } - } - } - - if (error->overlay) - intel_overlay_print_error_state(m, error->overlay); - - if (error->display) - intel_display_print_error_state(m, dev, error->display); - -out: - if (m->bytes == 0 && m->err) - return m->err; - - return 0; -} - static ssize_t i915_error_state_write(struct file *filp, const char __user *ubuf, @@ -982,26 +619,6 @@ i915_error_state_write(struct file *filp, return cnt; } -void i915_error_state_get(struct drm_device *dev, - struct i915_error_state_file_priv *error_priv) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long flags; - - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - error_priv->error = dev_priv->gpu_error.first_error; - if (error_priv->error) - kref_get(&error_priv->error->ref); - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - -} - -void i915_error_state_put(struct i915_error_state_file_priv *error_priv) -{ - if (error_priv->error) - kref_put(&error_priv->error->ref, i915_error_state_free); -} - static int i915_error_state_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; @@ -1030,36 +647,6 @@ static int i915_error_state_release(struct inode *inode, struct file *file) return 0; } -int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf, - size_t count, loff_t pos) -{ - memset(ebuf, 0, sizeof(*ebuf)); - - /* We need to have enough room to store any i915_error_state printf - * so that we can move it to start position. - */ - ebuf->size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE; - ebuf->buf = kmalloc(ebuf->size, - GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN); - - if (ebuf->buf == NULL) { - ebuf->size = PAGE_SIZE; - ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY); - } - - if (ebuf->buf == NULL) { - ebuf->size = 128; - ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY); - } - - if (ebuf->buf == NULL) - return -ENOMEM; - - ebuf->start = pos; - - return 0; -} - static ssize_t i915_error_state_read(struct file *file, char __user *userbuf, size_t count, loff_t *pos) { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 846500a8586c..65d54edae176 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1627,21 +1627,12 @@ extern void intel_hpd_init(struct drm_device *dev); extern void intel_gt_init(struct drm_device *dev); extern void intel_gt_reset(struct drm_device *dev); -void i915_error_state_free(struct kref *error_ref); - void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); -#ifdef CONFIG_DEBUG_FS -extern void i915_destroy_error_state(struct drm_device *dev); -#else -#define i915_destroy_error_state(x) -#endif - - /* i915_gem.c */ int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -1950,13 +1941,12 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, /* i915_debugfs.c */ int i915_debugfs_init(struct drm_minor *minor); void i915_debugfs_cleanup(struct drm_minor *minor); + +/* i915_gpu_error.c */ __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); int i915_error_state_to_str(struct drm_i915_error_state_buf *estr, const struct i915_error_state_file_priv *error); -void i915_error_state_get(struct drm_device *dev, - struct i915_error_state_file_priv *error_priv); -void i915_error_state_put(struct i915_error_state_file_priv *error_priv); int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb, size_t count, loff_t pos); static inline void i915_error_state_buf_release( @@ -1964,6 +1954,14 @@ static inline void i915_error_state_buf_release( { kfree(eb->buf); } +void i915_capture_error_state(struct drm_device *dev); +void i915_error_state_get(struct drm_device *dev, + struct i915_error_state_file_priv *error_priv); +void i915_error_state_put(struct i915_error_state_file_priv *error_priv); +void i915_destroy_error_state(struct drm_device *dev); + +void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone); +const char *i915_cache_level_str(int type); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); @@ -2043,7 +2041,6 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data, struct drm_file *file); /* overlay */ -#ifdef CONFIG_DEBUG_FS extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, struct intel_overlay_error_state *error); @@ -2052,7 +2049,6 @@ extern struct intel_display_error_state *intel_display_capture_error_state(struc extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, struct drm_device *dev, struct intel_display_error_state *error); -#endif /* On SNB platform, before reading ring registers forcewake bit * must be set to prevent GT core from power down and stale values being diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c new file mode 100644 index 000000000000..58386cebb865 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Keith Packard + * Mika Kuoppala + * + */ + +#include +#include "i915_drv.h" + +static const char *yesno(int v) +{ + return v ? "yes" : "no"; +} + +static const char *ring_str(int ring) +{ + switch (ring) { + case RCS: return "render"; + case VCS: return "bsd"; + case BCS: return "blt"; + case VECS: return "vebox"; + default: return ""; + } +} + +static const char *pin_flag(int pinned) +{ + if (pinned > 0) + return " P"; + else if (pinned < 0) + return " p"; + else + return ""; +} + +static const char *tiling_flag(int tiling) +{ + switch (tiling) { + default: + case I915_TILING_NONE: return ""; + case I915_TILING_X: return " X"; + case I915_TILING_Y: return " Y"; + } +} + +static const char *dirty_flag(int dirty) +{ + return dirty ? " dirty" : ""; +} + +static const char *purgeable_flag(int purgeable) +{ + return purgeable ? " purgeable" : ""; +} + +static bool __i915_error_ok(struct drm_i915_error_state_buf *e) +{ + + if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { + e->err = -ENOSPC; + return false; + } + + if (e->bytes == e->size - 1 || e->err) + return false; + + return true; +} + +static bool __i915_error_seek(struct drm_i915_error_state_buf *e, + unsigned len) +{ + if (e->pos + len <= e->start) { + e->pos += len; + return false; + } + + /* First vsnprintf needs to fit in its entirety for memmove */ + if (len >= e->size) { + e->err = -EIO; + return false; + } + + return true; +} + +static void __i915_error_advance(struct drm_i915_error_state_buf *e, + unsigned len) +{ + /* If this is first printf in this window, adjust it so that + * start position matches start of the buffer + */ + + if (e->pos < e->start) { + const size_t off = e->start - e->pos; + + /* Should not happen but be paranoid */ + if (off > len || e->bytes) { + e->err = -EIO; + return; + } + + memmove(e->buf, e->buf + off, len - off); + e->bytes = len - off; + e->pos = e->start; + return; + } + + e->bytes += len; + e->pos += len; +} + +static void i915_error_vprintf(struct drm_i915_error_state_buf *e, + const char *f, va_list args) +{ + unsigned len; + + if (!__i915_error_ok(e)) + return; + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + len = vsnprintf(NULL, 0, f, args); + if (!__i915_error_seek(e, len)) + return; + } + + len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + + __i915_error_advance(e, len); +} + +static void i915_error_puts(struct drm_i915_error_state_buf *e, + const char *str) +{ + unsigned len; + + if (!__i915_error_ok(e)) + return; + + len = strlen(str); + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + if (!__i915_error_seek(e, len)) + return; + } + + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + memcpy(e->buf + e->bytes, str, len); + + __i915_error_advance(e, len); +} + +#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) +#define err_puts(e, s) i915_error_puts(e, s) + +static void print_error_buffers(struct drm_i915_error_state_buf *m, + const char *name, + struct drm_i915_error_buffer *err, + int count) +{ + err_printf(m, "%s [%d]:\n", name, count); + + while (count--) { + err_printf(m, " %08x %8u %02x %02x %x %x", + err->gtt_offset, + err->size, + err->read_domains, + err->write_domain, + err->rseqno, err->wseqno); + err_puts(m, pin_flag(err->pinned)); + err_puts(m, tiling_flag(err->tiling)); + err_puts(m, dirty_flag(err->dirty)); + err_puts(m, purgeable_flag(err->purgeable)); + err_puts(m, err->ring != -1 ? " " : ""); + err_puts(m, ring_str(err->ring)); + err_puts(m, i915_cache_level_str(err->cache_level)); + + if (err->name) + err_printf(m, " (name: %d)", err->name); + if (err->fence_reg != I915_FENCE_REG_NONE) + err_printf(m, " (fence: %d)", err->fence_reg); + + err_puts(m, "\n"); + err++; + } +} + +static void i915_ring_error_state(struct drm_i915_error_state_buf *m, + struct drm_device *dev, + struct drm_i915_error_state *error, + unsigned ring) +{ + BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */ + err_printf(m, "%s command stream:\n", ring_str(ring)); + err_printf(m, " HEAD: 0x%08x\n", error->head[ring]); + err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); + err_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); + err_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); + err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); + err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); + err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); + if (ring == RCS && INTEL_INFO(dev)->gen >= 4) + err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); + + if (INTEL_INFO(dev)->gen >= 4) + err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); + err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); + if (INTEL_INFO(dev)->gen >= 6) { + err_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]); + err_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); + err_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n", + error->semaphore_mboxes[ring][0], + error->semaphore_seqno[ring][0]); + err_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n", + error->semaphore_mboxes[ring][1], + error->semaphore_seqno[ring][1]); + } + err_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); + err_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); + err_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]); + err_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); +} + +void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) +{ + va_list args; + + va_start(args, f); + i915_error_vprintf(e, f, args); + va_end(args); +} + +int i915_error_state_to_str(struct drm_i915_error_state_buf *m, + const struct i915_error_state_file_priv *error_priv) +{ + struct drm_device *dev = error_priv->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_error_state *error = error_priv->error; + struct intel_ring_buffer *ring; + int i, j, page, offset, elt; + + if (!error) { + err_printf(m, "no error state collected\n"); + goto out; + } + + err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, + error->time.tv_usec); + err_printf(m, "Kernel: " UTS_RELEASE "\n"); + err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); + err_printf(m, "EIR: 0x%08x\n", error->eir); + err_printf(m, "IER: 0x%08x\n", error->ier); + err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); + err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); + err_printf(m, "DERRMR: 0x%08x\n", error->derrmr); + err_printf(m, "CCID: 0x%08x\n", error->ccid); + + for (i = 0; i < dev_priv->num_fence_regs; i++) + err_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); + + for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++) + err_printf(m, " INSTDONE_%d: 0x%08x\n", i, + error->extra_instdone[i]); + + if (INTEL_INFO(dev)->gen >= 6) { + err_printf(m, "ERROR: 0x%08x\n", error->error); + err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); + } + + if (INTEL_INFO(dev)->gen == 7) + err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); + + for_each_ring(ring, dev_priv, i) + i915_ring_error_state(m, dev, error, i); + + if (error->active_bo) + print_error_buffers(m, "Active", + error->active_bo, + error->active_bo_count); + + if (error->pinned_bo) + print_error_buffers(m, "Pinned", + error->pinned_bo, + error->pinned_bo_count); + + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { + struct drm_i915_error_object *obj; + + if ((obj = error->ring[i].batchbuffer)) { + err_printf(m, "%s --- gtt_offset = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (page = 0; page < obj->page_count; page++) { + for (elt = 0; elt < PAGE_SIZE/4; elt++) { + err_printf(m, "%08x : %08x\n", offset, + obj->pages[page][elt]); + offset += 4; + } + } + } + + if (error->ring[i].num_requests) { + err_printf(m, "%s --- %d requests\n", + dev_priv->ring[i].name, + error->ring[i].num_requests); + for (j = 0; j < error->ring[i].num_requests; j++) { + err_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n", + error->ring[i].requests[j].seqno, + error->ring[i].requests[j].jiffies, + error->ring[i].requests[j].tail); + } + } + + if ((obj = error->ring[i].ringbuffer)) { + err_printf(m, "%s --- ringbuffer = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (page = 0; page < obj->page_count; page++) { + for (elt = 0; elt < PAGE_SIZE/4; elt++) { + err_printf(m, "%08x : %08x\n", + offset, + obj->pages[page][elt]); + offset += 4; + } + } + } + + obj = error->ring[i].ctx; + if (obj) { + err_printf(m, "%s --- HW Context = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { + err_printf(m, "[%04x] %08x %08x %08x %08x\n", + offset, + obj->pages[0][elt], + obj->pages[0][elt+1], + obj->pages[0][elt+2], + obj->pages[0][elt+3]); + offset += 16; + } + } + } + + if (error->overlay) + intel_overlay_print_error_state(m, error->overlay); + + if (error->display) + intel_display_print_error_state(m, dev, error->display); + +out: + if (m->bytes == 0 && m->err) + return m->err; + + return 0; +} + +int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf, + size_t count, loff_t pos) +{ + memset(ebuf, 0, sizeof(*ebuf)); + + /* We need to have enough room to store any i915_error_state printf + * so that we can move it to start position. + */ + ebuf->size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE; + ebuf->buf = kmalloc(ebuf->size, + GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN); + + if (ebuf->buf == NULL) { + ebuf->size = PAGE_SIZE; + ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY); + } + + if (ebuf->buf == NULL) { + ebuf->size = 128; + ebuf->buf = kmalloc(ebuf->size, GFP_TEMPORARY); + } + + if (ebuf->buf == NULL) + return -ENOMEM; + + ebuf->start = pos; + + return 0; +} + +static void i915_error_object_free(struct drm_i915_error_object *obj) +{ + int page; + + if (obj == NULL) + return; + + for (page = 0; page < obj->page_count; page++) + kfree(obj->pages[page]); + + kfree(obj); +} + +static void i915_error_state_free(struct kref *error_ref) +{ + struct drm_i915_error_state *error = container_of(error_ref, + typeof(*error), ref); + int i; + + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { + i915_error_object_free(error->ring[i].batchbuffer); + i915_error_object_free(error->ring[i].ringbuffer); + i915_error_object_free(error->ring[i].ctx); + kfree(error->ring[i].requests); + } + + kfree(error->active_bo); + kfree(error->overlay); + kfree(error->display); + kfree(error); +} + +static struct drm_i915_error_object * +i915_error_object_create_sized(struct drm_i915_private *dev_priv, + struct drm_i915_gem_object *src, + const int num_pages) +{ + struct drm_i915_error_object *dst; + int i; + u32 reloc_offset; + + if (src == NULL || src->pages == NULL) + return NULL; + + dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC); + if (dst == NULL) + return NULL; + + reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src); + for (i = 0; i < num_pages; i++) { + unsigned long flags; + void *d; + + d = kmalloc(PAGE_SIZE, GFP_ATOMIC); + if (d == NULL) + goto unwind; + + local_irq_save(flags); + if (reloc_offset < dev_priv->gtt.mappable_end && + src->has_global_gtt_mapping) { + void __iomem *s; + + /* Simply ignore tiling or any overlapping fence. + * It's part of the error state, and this hopefully + * captures what the GPU read. + */ + + s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, + reloc_offset); + memcpy_fromio(d, s, PAGE_SIZE); + io_mapping_unmap_atomic(s); + } else if (src->stolen) { + unsigned long offset; + + offset = dev_priv->mm.stolen_base; + offset += src->stolen->start; + offset += i << PAGE_SHIFT; + + memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE); + } else { + struct page *page; + void *s; + + page = i915_gem_object_get_page(src, i); + + drm_clflush_pages(&page, 1); + + s = kmap_atomic(page); + memcpy(d, s, PAGE_SIZE); + kunmap_atomic(s); + + drm_clflush_pages(&page, 1); + } + local_irq_restore(flags); + + dst->pages[i] = d; + + reloc_offset += PAGE_SIZE; + } + dst->page_count = num_pages; + + return dst; + +unwind: + while (i--) + kfree(dst->pages[i]); + kfree(dst); + return NULL; +} +#define i915_error_object_create(dev_priv, src) \ + i915_error_object_create_sized((dev_priv), (src), \ + (src)->base.size>>PAGE_SHIFT) + +static void capture_bo(struct drm_i915_error_buffer *err, + struct drm_i915_gem_object *obj) +{ + err->size = obj->base.size; + err->name = obj->base.name; + err->rseqno = obj->last_read_seqno; + err->wseqno = obj->last_write_seqno; + err->gtt_offset = i915_gem_obj_ggtt_offset(obj); + err->read_domains = obj->base.read_domains; + err->write_domain = obj->base.write_domain; + err->fence_reg = obj->fence_reg; + err->pinned = 0; + if (obj->pin_count > 0) + err->pinned = 1; + if (obj->user_pin_count > 0) + err->pinned = -1; + err->tiling = obj->tiling_mode; + err->dirty = obj->dirty; + err->purgeable = obj->madv != I915_MADV_WILLNEED; + err->ring = obj->ring ? obj->ring->id : -1; + err->cache_level = obj->cache_level; +} + +static u32 capture_active_bo(struct drm_i915_error_buffer *err, + int count, struct list_head *head) +{ + struct drm_i915_gem_object *obj; + int i = 0; + + list_for_each_entry(obj, head, mm_list) { + capture_bo(err++, obj); + if (++i == count) + break; + } + + return i; +} + +static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, + int count, struct list_head *head) +{ + struct drm_i915_gem_object *obj; + int i = 0; + + list_for_each_entry(obj, head, global_list) { + if (obj->pin_count == 0) + continue; + + capture_bo(err++, obj); + if (++i == count) + break; + } + + return i; +} + +static void i915_gem_record_fences(struct drm_device *dev, + struct drm_i915_error_state *error) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + /* Fences */ + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + for (i = 0; i < dev_priv->num_fence_regs; i++) + error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); + break; + case 5: + case 4: + for (i = 0; i < 16; i++) + error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); + break; + case 3: + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + for (i = 0; i < 8; i++) + error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); + case 2: + for (i = 0; i < 8; i++) + error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); + break; + + default: + BUG(); + } +} + +static struct drm_i915_error_object * +i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, + struct intel_ring_buffer *ring) +{ + struct drm_i915_gem_object *obj; + u32 seqno; + + if (!ring->get_seqno) + return NULL; + + if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { + u32 acthd = I915_READ(ACTHD); + + if (WARN_ON(ring->id != RCS)) + return NULL; + + obj = ring->private; + if (acthd >= i915_gem_obj_ggtt_offset(obj) && + acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) + return i915_error_object_create(dev_priv, obj); + } + + seqno = ring->get_seqno(ring, false); + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { + if (obj->ring != ring) + continue; + + if (i915_seqno_passed(seqno, obj->last_read_seqno)) + continue; + + if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) + continue; + + /* We need to copy these to an anonymous buffer as the simplest + * method to avoid being overwritten by userspace. + */ + return i915_error_object_create(dev_priv, obj); + } + + return NULL; +} + +static void i915_record_ring_state(struct drm_device *dev, + struct drm_i915_error_state *error, + struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (INTEL_INFO(dev)->gen >= 6) { + error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50); + error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring)); + error->semaphore_mboxes[ring->id][0] + = I915_READ(RING_SYNC_0(ring->mmio_base)); + error->semaphore_mboxes[ring->id][1] + = I915_READ(RING_SYNC_1(ring->mmio_base)); + error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0]; + error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1]; + } + + if (INTEL_INFO(dev)->gen >= 4) { + error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base)); + error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base)); + error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); + error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); + error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); + if (ring->id == RCS) + error->bbaddr = I915_READ64(BB_ADDR); + } else { + error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); + error->ipeir[ring->id] = I915_READ(IPEIR); + error->ipehr[ring->id] = I915_READ(IPEHR); + error->instdone[ring->id] = I915_READ(INSTDONE); + } + + error->waiting[ring->id] = waitqueue_active(&ring->irq_queue); + error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base)); + error->seqno[ring->id] = ring->get_seqno(ring, false); + error->acthd[ring->id] = intel_ring_get_active_head(ring); + error->head[ring->id] = I915_READ_HEAD(ring); + error->tail[ring->id] = I915_READ_TAIL(ring); + error->ctl[ring->id] = I915_READ_CTL(ring); + + error->cpu_ring_head[ring->id] = ring->head; + error->cpu_ring_tail[ring->id] = ring->tail; +} + + +static void i915_gem_record_active_context(struct intel_ring_buffer *ring, + struct drm_i915_error_state *error, + struct drm_i915_error_ring *ering) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_gem_object *obj; + + /* Currently render ring is the only HW context user */ + if (ring->id != RCS || !error->ccid) + return; + + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { + if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) { + ering->ctx = i915_error_object_create_sized(dev_priv, + obj, 1); + break; + } + } +} + +static void i915_gem_record_rings(struct drm_device *dev, + struct drm_i915_error_state *error) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + struct drm_i915_gem_request *request; + int i, count; + + for_each_ring(ring, dev_priv, i) { + i915_record_ring_state(dev, error, ring); + + error->ring[i].batchbuffer = + i915_error_first_batchbuffer(dev_priv, ring); + + error->ring[i].ringbuffer = + i915_error_object_create(dev_priv, ring->obj); + + + i915_gem_record_active_context(ring, error, &error->ring[i]); + + count = 0; + list_for_each_entry(request, &ring->request_list, list) + count++; + + error->ring[i].num_requests = count; + error->ring[i].requests = + kmalloc(count*sizeof(struct drm_i915_error_request), + GFP_ATOMIC); + if (error->ring[i].requests == NULL) { + error->ring[i].num_requests = 0; + continue; + } + + count = 0; + list_for_each_entry(request, &ring->request_list, list) { + struct drm_i915_error_request *erq; + + erq = &error->ring[i].requests[count++]; + erq->seqno = request->seqno; + erq->jiffies = request->emitted_jiffies; + erq->tail = request->tail; + } + } +} + +static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv, + struct drm_i915_error_state *error) +{ + struct drm_i915_gem_object *obj; + int i; + + i = 0; + list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) + i++; + error->active_bo_count = i; + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) + if (obj->pin_count) + i++; + error->pinned_bo_count = i - error->active_bo_count; + + if (i) { + error->active_bo = kmalloc(sizeof(*error->active_bo)*i, + GFP_ATOMIC); + if (error->active_bo) + error->pinned_bo = + error->active_bo + error->active_bo_count; + } + + if (error->active_bo) + error->active_bo_count = + capture_active_bo(error->active_bo, + error->active_bo_count, + &dev_priv->mm.active_list); + + if (error->pinned_bo) + error->pinned_bo_count = + capture_pinned_bo(error->pinned_bo, + error->pinned_bo_count, + &dev_priv->mm.bound_list); +} + +/** + * i915_capture_error_state - capture an error record for later analysis + * @dev: drm device + * + * Should be called when an error is detected (either a hang or an error + * interrupt) to capture error state from the time of the error. Fills + * out a structure which becomes available in debugfs for user level tools + * to pick up. + */ +void i915_capture_error_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_error_state *error; + unsigned long flags; + int pipe; + + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + if (error) + return; + + /* Account for pipe specific data like PIPE*STAT */ + error = kzalloc(sizeof(*error), GFP_ATOMIC); + if (!error) { + DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); + return; + } + + DRM_INFO("capturing error event; look for more information in " + "/sys/class/drm/card%d/error\n", dev->primary->index); + + kref_init(&error->ref); + error->eir = I915_READ(EIR); + error->pgtbl_er = I915_READ(PGTBL_ER); + if (HAS_HW_CONTEXTS(dev)) + error->ccid = I915_READ(CCID); + + if (HAS_PCH_SPLIT(dev)) + error->ier = I915_READ(DEIER) | I915_READ(GTIER); + else if (IS_VALLEYVIEW(dev)) + error->ier = I915_READ(GTIER) | I915_READ(VLV_IER); + else if (IS_GEN2(dev)) + error->ier = I915_READ16(IER); + else + error->ier = I915_READ(IER); + + if (INTEL_INFO(dev)->gen >= 6) + error->derrmr = I915_READ(DERRMR); + + if (IS_VALLEYVIEW(dev)) + error->forcewake = I915_READ(FORCEWAKE_VLV); + else if (INTEL_INFO(dev)->gen >= 7) + error->forcewake = I915_READ(FORCEWAKE_MT); + else if (INTEL_INFO(dev)->gen == 6) + error->forcewake = I915_READ(FORCEWAKE); + + if (!HAS_PCH_SPLIT(dev)) + for_each_pipe(pipe) + error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); + + if (INTEL_INFO(dev)->gen >= 6) { + error->error = I915_READ(ERROR_GEN6); + error->done_reg = I915_READ(DONE_REG); + } + + if (INTEL_INFO(dev)->gen == 7) + error->err_int = I915_READ(GEN7_ERR_INT); + + i915_get_extra_instdone(dev, error->extra_instdone); + + i915_gem_capture_buffers(dev_priv, error); + i915_gem_record_fences(dev, error); + i915_gem_record_rings(dev, error); + + do_gettimeofday(&error->time); + + error->overlay = intel_overlay_capture_error_state(dev); + error->display = intel_display_capture_error_state(dev); + + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + if (dev_priv->gpu_error.first_error == NULL) { + dev_priv->gpu_error.first_error = error; + error = NULL; + } + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + + if (error) + i915_error_state_free(&error->ref); +} + +void i915_error_state_get(struct drm_device *dev, + struct i915_error_state_file_priv *error_priv) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error_priv->error = dev_priv->gpu_error.first_error; + if (error_priv->error) + kref_get(&error_priv->error->ref); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + +} + +void i915_error_state_put(struct i915_error_state_file_priv *error_priv) +{ + if (error_priv->error) + kref_put(&error_priv->error->ref, i915_error_state_free); +} + +void i915_destroy_error_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_error_state *error; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + dev_priv->gpu_error.first_error = NULL; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); + + if (error) + kref_put(&error->ref, i915_error_state_free); +} + +const char *i915_cache_level_str(int type) +{ + switch (type) { + case I915_CACHE_NONE: return " uncached"; + case I915_CACHE_LLC: return " snooped (LLC)"; + case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)"; + default: return ""; + } +} + +/* NB: please notice the memset */ +void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG); + + switch (INTEL_INFO(dev)->gen) { + case 2: + case 3: + instdone[0] = I915_READ(INSTDONE); + break; + case 4: + case 5: + case 6: + instdone[0] = I915_READ(INSTDONE_I965); + instdone[1] = I915_READ(INSTDONE1); + break; + default: + WARN_ONCE(1, "Unsupported platform\n"); + case 7: + instdone[0] = I915_READ(GEN7_INSTDONE_1); + instdone[1] = I915_READ(GEN7_SC_INSTDONE); + instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE); + instdone[3] = I915_READ(GEN7_ROW_INSTDONE); + break; + } +} diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index cf1a21a9728a..64db680fb7a4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1493,535 +1493,6 @@ static void i915_error_work_func(struct work_struct *work) } } -/* NB: please notice the memset */ -static void i915_get_extra_instdone(struct drm_device *dev, - uint32_t *instdone) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG); - - switch(INTEL_INFO(dev)->gen) { - case 2: - case 3: - instdone[0] = I915_READ(INSTDONE); - break; - case 4: - case 5: - case 6: - instdone[0] = I915_READ(INSTDONE_I965); - instdone[1] = I915_READ(INSTDONE1); - break; - default: - WARN_ONCE(1, "Unsupported platform\n"); - case 7: - instdone[0] = I915_READ(GEN7_INSTDONE_1); - instdone[1] = I915_READ(GEN7_SC_INSTDONE); - instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE); - instdone[3] = I915_READ(GEN7_ROW_INSTDONE); - break; - } -} - -#ifdef CONFIG_DEBUG_FS -static struct drm_i915_error_object * -i915_error_object_create_sized(struct drm_i915_private *dev_priv, - struct drm_i915_gem_object *src, - const int num_pages) -{ - struct drm_i915_error_object *dst; - int i; - u32 reloc_offset; - - if (src == NULL || src->pages == NULL) - return NULL; - - dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC); - if (dst == NULL) - return NULL; - - reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src); - for (i = 0; i < num_pages; i++) { - unsigned long flags; - void *d; - - d = kmalloc(PAGE_SIZE, GFP_ATOMIC); - if (d == NULL) - goto unwind; - - local_irq_save(flags); - if (reloc_offset < dev_priv->gtt.mappable_end && - src->has_global_gtt_mapping) { - void __iomem *s; - - /* Simply ignore tiling or any overlapping fence. - * It's part of the error state, and this hopefully - * captures what the GPU read. - */ - - s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, - reloc_offset); - memcpy_fromio(d, s, PAGE_SIZE); - io_mapping_unmap_atomic(s); - } else if (src->stolen) { - unsigned long offset; - - offset = dev_priv->mm.stolen_base; - offset += src->stolen->start; - offset += i << PAGE_SHIFT; - - memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE); - } else { - struct page *page; - void *s; - - page = i915_gem_object_get_page(src, i); - - drm_clflush_pages(&page, 1); - - s = kmap_atomic(page); - memcpy(d, s, PAGE_SIZE); - kunmap_atomic(s); - - drm_clflush_pages(&page, 1); - } - local_irq_restore(flags); - - dst->pages[i] = d; - - reloc_offset += PAGE_SIZE; - } - dst->page_count = num_pages; - - return dst; - -unwind: - while (i--) - kfree(dst->pages[i]); - kfree(dst); - return NULL; -} -#define i915_error_object_create(dev_priv, src) \ - i915_error_object_create_sized((dev_priv), (src), \ - (src)->base.size>>PAGE_SHIFT) - -static void -i915_error_object_free(struct drm_i915_error_object *obj) -{ - int page; - - if (obj == NULL) - return; - - for (page = 0; page < obj->page_count; page++) - kfree(obj->pages[page]); - - kfree(obj); -} - -void -i915_error_state_free(struct kref *error_ref) -{ - struct drm_i915_error_state *error = container_of(error_ref, - typeof(*error), ref); - int i; - - for (i = 0; i < ARRAY_SIZE(error->ring); i++) { - i915_error_object_free(error->ring[i].batchbuffer); - i915_error_object_free(error->ring[i].ringbuffer); - i915_error_object_free(error->ring[i].ctx); - kfree(error->ring[i].requests); - } - - kfree(error->active_bo); - kfree(error->overlay); - kfree(error->display); - kfree(error); -} -static void capture_bo(struct drm_i915_error_buffer *err, - struct drm_i915_gem_object *obj) -{ - err->size = obj->base.size; - err->name = obj->base.name; - err->rseqno = obj->last_read_seqno; - err->wseqno = obj->last_write_seqno; - err->gtt_offset = i915_gem_obj_ggtt_offset(obj); - err->read_domains = obj->base.read_domains; - err->write_domain = obj->base.write_domain; - err->fence_reg = obj->fence_reg; - err->pinned = 0; - if (obj->pin_count > 0) - err->pinned = 1; - if (obj->user_pin_count > 0) - err->pinned = -1; - err->tiling = obj->tiling_mode; - err->dirty = obj->dirty; - err->purgeable = obj->madv != I915_MADV_WILLNEED; - err->ring = obj->ring ? obj->ring->id : -1; - err->cache_level = obj->cache_level; -} - -static u32 capture_active_bo(struct drm_i915_error_buffer *err, - int count, struct list_head *head) -{ - struct drm_i915_gem_object *obj; - int i = 0; - - list_for_each_entry(obj, head, mm_list) { - capture_bo(err++, obj); - if (++i == count) - break; - } - - return i; -} - -static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, - int count, struct list_head *head) -{ - struct drm_i915_gem_object *obj; - int i = 0; - - list_for_each_entry(obj, head, global_list) { - if (obj->pin_count == 0) - continue; - - capture_bo(err++, obj); - if (++i == count) - break; - } - - return i; -} - -static void i915_gem_record_fences(struct drm_device *dev, - struct drm_i915_error_state *error) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - for (i = 0; i < dev_priv->num_fence_regs; i++) - error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); - break; - case 3: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); - case 2: - for (i = 0; i < 8; i++) - error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - break; - - default: - BUG(); - } -} - -static struct drm_i915_error_object * -i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, - struct intel_ring_buffer *ring) -{ - struct drm_i915_gem_object *obj; - u32 seqno; - - if (!ring->get_seqno) - return NULL; - - if (HAS_BROKEN_CS_TLB(dev_priv->dev)) { - u32 acthd = I915_READ(ACTHD); - - if (WARN_ON(ring->id != RCS)) - return NULL; - - obj = ring->private; - if (acthd >= i915_gem_obj_ggtt_offset(obj) && - acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size) - return i915_error_object_create(dev_priv, obj); - } - - seqno = ring->get_seqno(ring, false); - list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { - if (obj->ring != ring) - continue; - - if (i915_seqno_passed(seqno, obj->last_read_seqno)) - continue; - - if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) - continue; - - /* We need to copy these to an anonymous buffer as the simplest - * method to avoid being overwritten by userspace. - */ - return i915_error_object_create(dev_priv, obj); - } - - return NULL; -} - -static void i915_record_ring_state(struct drm_device *dev, - struct drm_i915_error_state *error, - struct intel_ring_buffer *ring) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (INTEL_INFO(dev)->gen >= 6) { - error->rc_psmi[ring->id] = I915_READ(ring->mmio_base + 0x50); - error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring)); - error->semaphore_mboxes[ring->id][0] - = I915_READ(RING_SYNC_0(ring->mmio_base)); - error->semaphore_mboxes[ring->id][1] - = I915_READ(RING_SYNC_1(ring->mmio_base)); - error->semaphore_seqno[ring->id][0] = ring->sync_seqno[0]; - error->semaphore_seqno[ring->id][1] = ring->sync_seqno[1]; - } - - if (INTEL_INFO(dev)->gen >= 4) { - error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base)); - error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base)); - error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); - error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); - error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); - if (ring->id == RCS) - error->bbaddr = I915_READ64(BB_ADDR); - } else { - error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); - error->ipeir[ring->id] = I915_READ(IPEIR); - error->ipehr[ring->id] = I915_READ(IPEHR); - error->instdone[ring->id] = I915_READ(INSTDONE); - } - - error->waiting[ring->id] = waitqueue_active(&ring->irq_queue); - error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base)); - error->seqno[ring->id] = ring->get_seqno(ring, false); - error->acthd[ring->id] = intel_ring_get_active_head(ring); - error->head[ring->id] = I915_READ_HEAD(ring); - error->tail[ring->id] = I915_READ_TAIL(ring); - error->ctl[ring->id] = I915_READ_CTL(ring); - - error->cpu_ring_head[ring->id] = ring->head; - error->cpu_ring_tail[ring->id] = ring->tail; -} - - -static void i915_gem_record_active_context(struct intel_ring_buffer *ring, - struct drm_i915_error_state *error, - struct drm_i915_error_ring *ering) -{ - struct drm_i915_private *dev_priv = ring->dev->dev_private; - struct drm_i915_gem_object *obj; - - /* Currently render ring is the only HW context user */ - if (ring->id != RCS || !error->ccid) - return; - - list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - if ((error->ccid & PAGE_MASK) == i915_gem_obj_ggtt_offset(obj)) { - ering->ctx = i915_error_object_create_sized(dev_priv, - obj, 1); - break; - } - } -} - -static void i915_gem_record_rings(struct drm_device *dev, - struct drm_i915_error_state *error) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; - struct drm_i915_gem_request *request; - int i, count; - - for_each_ring(ring, dev_priv, i) { - i915_record_ring_state(dev, error, ring); - - error->ring[i].batchbuffer = - i915_error_first_batchbuffer(dev_priv, ring); - - error->ring[i].ringbuffer = - i915_error_object_create(dev_priv, ring->obj); - - - i915_gem_record_active_context(ring, error, &error->ring[i]); - - count = 0; - list_for_each_entry(request, &ring->request_list, list) - count++; - - error->ring[i].num_requests = count; - error->ring[i].requests = - kmalloc(count*sizeof(struct drm_i915_error_request), - GFP_ATOMIC); - if (error->ring[i].requests == NULL) { - error->ring[i].num_requests = 0; - continue; - } - - count = 0; - list_for_each_entry(request, &ring->request_list, list) { - struct drm_i915_error_request *erq; - - erq = &error->ring[i].requests[count++]; - erq->seqno = request->seqno; - erq->jiffies = request->emitted_jiffies; - erq->tail = request->tail; - } - } -} - -static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv, - struct drm_i915_error_state *error) -{ - struct drm_i915_gem_object *obj; - int i; - - i = 0; - list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) - i++; - error->active_bo_count = i; - list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (obj->pin_count) - i++; - error->pinned_bo_count = i - error->active_bo_count; - - if (i) { - error->active_bo = kmalloc(sizeof(*error->active_bo)*i, - GFP_ATOMIC); - if (error->active_bo) - error->pinned_bo = - error->active_bo + error->active_bo_count; - } - - if (error->active_bo) - error->active_bo_count = - capture_active_bo(error->active_bo, - error->active_bo_count, - &dev_priv->mm.active_list); - - if (error->pinned_bo) - error->pinned_bo_count = - capture_pinned_bo(error->pinned_bo, - error->pinned_bo_count, - &dev_priv->mm.bound_list); -} - -/** - * i915_capture_error_state - capture an error record for later analysis - * @dev: drm device - * - * Should be called when an error is detected (either a hang or an error - * interrupt) to capture error state from the time of the error. Fills - * out a structure which becomes available in debugfs for user level tools - * to pick up. - */ -static void i915_capture_error_state(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_error_state *error; - unsigned long flags; - int pipe; - - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - error = dev_priv->gpu_error.first_error; - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - if (error) - return; - - /* Account for pipe specific data like PIPE*STAT */ - error = kzalloc(sizeof(*error), GFP_ATOMIC); - if (!error) { - DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); - return; - } - - DRM_INFO("capturing error event; look for more information in " - "/sys/class/drm/card%d/error\n", dev->primary->index); - - kref_init(&error->ref); - error->eir = I915_READ(EIR); - error->pgtbl_er = I915_READ(PGTBL_ER); - if (HAS_HW_CONTEXTS(dev)) - error->ccid = I915_READ(CCID); - - if (HAS_PCH_SPLIT(dev)) - error->ier = I915_READ(DEIER) | I915_READ(GTIER); - else if (IS_VALLEYVIEW(dev)) - error->ier = I915_READ(GTIER) | I915_READ(VLV_IER); - else if (IS_GEN2(dev)) - error->ier = I915_READ16(IER); - else - error->ier = I915_READ(IER); - - if (INTEL_INFO(dev)->gen >= 6) - error->derrmr = I915_READ(DERRMR); - - if (IS_VALLEYVIEW(dev)) - error->forcewake = I915_READ(FORCEWAKE_VLV); - else if (INTEL_INFO(dev)->gen >= 7) - error->forcewake = I915_READ(FORCEWAKE_MT); - else if (INTEL_INFO(dev)->gen == 6) - error->forcewake = I915_READ(FORCEWAKE); - - if (!HAS_PCH_SPLIT(dev)) - for_each_pipe(pipe) - error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); - - if (INTEL_INFO(dev)->gen >= 6) { - error->error = I915_READ(ERROR_GEN6); - error->done_reg = I915_READ(DONE_REG); - } - - if (INTEL_INFO(dev)->gen == 7) - error->err_int = I915_READ(GEN7_ERR_INT); - - i915_get_extra_instdone(dev, error->extra_instdone); - - i915_gem_capture_buffers(dev_priv, error); - i915_gem_record_fences(dev, error); - i915_gem_record_rings(dev, error); - - do_gettimeofday(&error->time); - - error->overlay = intel_overlay_capture_error_state(dev); - error->display = intel_display_capture_error_state(dev); - - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - if (dev_priv->gpu_error.first_error == NULL) { - dev_priv->gpu_error.first_error = error; - error = NULL; - } - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - - if (error) - i915_error_state_free(&error->ref); -} - -void i915_destroy_error_state(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_error_state *error; - unsigned long flags; - - spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); - error = dev_priv->gpu_error.first_error; - dev_priv->gpu_error.first_error = NULL; - spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - - if (error) - kref_put(&error->ref, i915_error_state_free); -} -#else -#define i915_capture_error_state(x) -#endif - static void i915_report_and_clear_eir(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bca81eecd31e..b1b1d2a38fc9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10176,9 +10176,6 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state) return 0; } -#ifdef CONFIG_DEBUG_FS -#include - struct intel_display_error_state { u32 power_well_driver; @@ -10322,4 +10319,3 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " BASE: %08x\n", error->cursor[i].base); } } -#endif diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 81c3ca14fa92..2abb53e6f1e0 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1412,9 +1412,6 @@ void intel_cleanup_overlay(struct drm_device *dev) kfree(dev_priv->overlay); } -#ifdef CONFIG_DEBUG_FS -#include - struct intel_overlay_error_state { struct overlay_registers regs; unsigned long base; @@ -1537,4 +1534,3 @@ intel_overlay_print_error_state(struct drm_i915_error_state_buf *m, P(UVSCALEV); #undef P } -#endif From 27389d7823f573be8eaff32fb4abe564e181eb71 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:27 +0300 Subject: [PATCH 0198/6183] perf tools: Validate perf event header size The 'size' variable includes the header so must be at least 'sizeof(struct perf_event_header)'. Error out immediately if that is not the case. Also don't byte-swap the header until it is actually "fetched" from the mmap region. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-9-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6b71b88f95fa..951a1cfb317c 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1094,8 +1094,10 @@ more: perf_event_header__bswap(&event->header); size = event->header.size; - if (size == 0) - size = 8; + if (size < sizeof(struct perf_event_header)) { + pr_err("bad event header size\n"); + goto out_err; + } if (size > cur_size) { void *new = realloc(buf, size); @@ -1164,8 +1166,12 @@ fetch_mmaped_event(struct perf_session *session, if (session->header.needs_swap) perf_event_header__bswap(&event->header); - if (head + event->header.size > mmap_size) + if (head + event->header.size > mmap_size) { + /* We're not fetching the event so swap back again */ + if (session->header.needs_swap) + perf_event_header__bswap(&event->header); return NULL; + } return event; } @@ -1245,7 +1251,7 @@ more: size = event->header.size; - if (size == 0 || + if (size < sizeof(struct perf_event_header) || perf_session__process_event(session, event, tool, file_pos) < 0) { pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", file_offset + head, event->header.size, From 380512345e13c3af64e59627f1b993c4faa94a84 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Jul 2013 16:20:31 +0300 Subject: [PATCH 0199/6183] perf tools: struct thread has a tid not a pid As evident from 'machine__process_fork_event()' and 'machine__process_exit_event()' the 'pid' member of struct thread is actually the tid. Rename 'pid' to 'tid' in struct thread accordingly. Signed-off-by: Adrian Hunter Acked-by: David Ahern Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1372944040-32690-13-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-sched.c | 12 ++++++------ tools/perf/builtin-trace.c | 4 ++-- tools/perf/ui/browsers/hists.c | 6 +++--- tools/perf/util/event.c | 2 +- tools/perf/util/machine.c | 20 ++++++++++---------- tools/perf/util/machine.h | 4 ++-- tools/perf/util/sort.c | 6 +++--- tools/perf/util/thread.c | 10 +++++----- tools/perf/util/thread.h | 4 ++-- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0259502638b4..b49f5c58e152 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, return -1; } - dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); if (evsel->handler.func != NULL) { tracepoint_handler f = evsel->handler.func; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index fba4a940ba31..948183adb6e5 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, if (!atoms) { if (thread_atoms_insert(sched, migrant)) return -1; - register_pid(sched, migrant->pid, migrant->comm); + register_pid(sched, migrant->tid, migrant->comm); atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); if (!atoms) { pr_err("migration-event: Internal tree error"); @@ -1115,7 +1115,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ sched->all_runtime += work_list->total_runtime; sched->all_count += work_list->nb_atoms; - ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); + ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid); for (i = 0; i < 24 - ret; i++) printf(" "); @@ -1131,9 +1131,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ static int pid_cmp(struct work_atoms *l, struct work_atoms *r) { - if (l->thread->pid < r->thread->pid) + if (l->thread->tid < r->thread->tid) return -1; - if (l->thread->pid > r->thread->pid) + if (l->thread->tid > r->thread->tid) return 1; return 0; @@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, printf("*"); if (sched->curr_thread[cpu]) { - if (sched->curr_thread[cpu]->pid) + if (sched->curr_thread[cpu]->tid) printf("%2s ", sched->curr_thread[cpu]->shortname); else printf(". "); @@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, printf(" %12.6f secs ", (double)timestamp/1e9); if (new_shortname) { printf("%s => %s:%d\n", - sched_in->shortname, sched_in->comm, sched_in->pid); + sched_in->shortname, sched_in->comm, sched_in->tid); } else { printf("\n"); } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 87fc7d08ca02..0e4b67f6bbd1 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre printed += fprintf_duration(duration, fp); if (trace->multiple_threads) - printed += fprintf(fp, "%d ", thread->pid); + printed += fprintf(fp, "%d ", thread->tid); return printed; } @@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) color = PERF_COLOR_YELLOW; printed += color_fprintf(fp, color, "%20s", thread->comm); - printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events); + printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); printed += color_fprintf(fp, color, "%5.1f%%", ratio); printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index fc0bd3843d34..06e892f1f8ca 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, printed += scnprintf(bf + printed, size - printed, ", Thread: %s(%d)", (thread->comm_set ? thread->comm : ""), - thread->pid); + thread->tid); if (dso) printed += scnprintf(bf + printed, size - printed, ", DSO: %s", dso->short_name); @@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, asprintf(&options[nr_options], "Zoom %s %s(%d) thread", (browser->hists->thread_filter ? "out of" : "into"), (thread->comm_set ? thread->comm : ""), - thread->pid) > 0) + thread->tid) > 0) zoom_thread = nr_options++; if (dso != NULL && @@ -1702,7 +1702,7 @@ zoom_out_thread: } else { ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", thread->comm_set ? thread->comm : "", - thread->pid); + thread->tid); browser->hists->thread_filter = thread; sort_thread.elide = true; pstack__push(fstack, &browser->hists->thread_filter); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 5cd13d768cec..95412705d0d2 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event, !strlist__has_entry(symbol_conf.comm_list, thread->comm)) goto out_filtered; - dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); /* * Have we already created the kernel maps for this machine? * diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 93527afb09d5..5dd5026a82ef 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -233,7 +233,7 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) return; } -static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, +static struct thread *__machine__findnew_thread(struct machine *machine, pid_t tid, bool create) { struct rb_node **p = &machine->threads.rb_node; @@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p struct thread *th; /* - * Font-end cache - PID lookups come in blocks, + * Front-end cache - TID lookups come in blocks, * so most of the time we dont have to look up * the full rbtree: */ - if (machine->last_match && machine->last_match->pid == pid) + if (machine->last_match && machine->last_match->tid == tid) return machine->last_match; while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); - if (th->pid == pid) { + if (th->tid == tid) { machine->last_match = th; return th; } - if (pid < th->pid) + if (tid < th->tid) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p if (!create) return NULL; - th = thread__new(pid); + th = thread__new(tid); if (th != NULL) { rb_link_node(&th->rb_node, parent, p); rb_insert_color(&th->rb_node, &machine->threads); @@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p return th; } -struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) +struct thread *machine__findnew_thread(struct machine *machine, pid_t tid) { - return __machine__findnew_thread(machine, pid, true); + return __machine__findnew_thread(machine, tid, true); } -struct thread *machine__find_thread(struct machine *machine, pid_t pid) +struct thread *machine__find_thread(struct machine *machine, pid_t tid) { - return __machine__findnew_thread(machine, pid, false); + return __machine__findnew_thread(machine, tid, false); } int machine__process_comm_event(struct machine *machine, union perf_event *event) diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 77940680f1fc..e49ba01b7937 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -36,7 +36,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) return machine->vmlinux_maps[type]; } -struct thread *machine__find_thread(struct machine *machine, pid_t pid); +struct thread *machine__find_thread(struct machine *machine, pid_t tid); int machine__process_comm_event(struct machine *machine, union perf_event *event); int machine__process_exit_event(struct machine *machine, union perf_event *event); @@ -99,7 +99,7 @@ static inline bool machine__is_host(struct machine *machine) return machine ? machine->pid == HOST_KERNEL_ID : false; } -struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); +struct thread *machine__findnew_thread(struct machine *machine, pid_t tid); size_t machine__fprintf(struct machine *machine, FILE *fp); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 313a5a730112..8deee19d2e7f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -55,14 +55,14 @@ static int64_t cmp_null(void *l, void *r) static int64_t sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) { - return right->thread->pid - left->thread->pid; + return right->thread->tid - left->thread->tid; } static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, size_t size, unsigned int width) { return repsep_snprintf(bf, size, "%*s:%5d", width - 6, - self->thread->comm ?: "", self->thread->pid); + self->thread->comm ?: "", self->thread->tid); } struct sort_entry sort_thread = { @@ -77,7 +77,7 @@ struct sort_entry sort_thread = { static int64_t sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) { - return right->thread->pid - left->thread->pid; + return right->thread->tid - left->thread->tid; } static int64_t diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 40399cbcca77..6feeb88eb5b0 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -7,17 +7,17 @@ #include "util.h" #include "debug.h" -struct thread *thread__new(pid_t pid) +struct thread *thread__new(pid_t tid) { struct thread *self = zalloc(sizeof(*self)); if (self != NULL) { map_groups__init(&self->mg); - self->pid = pid; + self->tid = tid; self->ppid = -1; self->comm = malloc(32); if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); + snprintf(self->comm, 32, ":%d", self->tid); } return self; @@ -57,7 +57,7 @@ int thread__comm_len(struct thread *self) size_t thread__fprintf(struct thread *thread, FILE *fp) { - return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + + return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) + map_groups__fprintf(&thread->mg, verbose, fp); } @@ -84,7 +84,7 @@ int thread__fork(struct thread *self, struct thread *parent) if (map_groups__clone(&self->mg, &parent->mg, i) < 0) return -ENOMEM; - self->ppid = parent->pid; + self->ppid = parent->tid; return 0; } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 5e7ba35a5517..0fe1f9c05865 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -12,7 +12,7 @@ struct thread { struct list_head node; }; struct map_groups mg; - pid_t pid; + pid_t tid; pid_t ppid; char shortname[3]; bool comm_set; @@ -24,7 +24,7 @@ struct thread { struct machine; -struct thread *thread__new(pid_t pid); +struct thread *thread__new(pid_t tid); void thread__delete(struct thread *self); int thread__set_comm(struct thread *self, const char *comm); From 50e200f07948400694238e08e7add73df5ba8f83 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 20 Apr 2013 11:02:28 -0700 Subject: [PATCH 0200/6183] perf tools: Default to cpu// for events v5 When an event fails to parse and it's not in a new style format, try to parse it again as a cpu event. This allows to use sysfs exported events directly without //, so you can use perf record -e mem-loads ... instead of perf record -e cpu/mem-loads/ Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1366480949-32292-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/include/linux/string.h | 1 + tools/perf/util/parse-events.c | 30 +++++++++++++++++++++++++- tools/perf/util/string.c | 24 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h index 6f19c548ecc0..97a800738226 100644 --- a/tools/perf/util/include/linux/string.h +++ b/tools/perf/util/include/linux/string.h @@ -1,3 +1,4 @@ #include void *memdup(const void *src, size_t len); +int str_append(char **s, int *len, const char *a); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index e85376999efc..a5076f4f6016 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -6,7 +6,7 @@ #include "parse-options.h" #include "parse-events.h" #include "exec_cmd.h" -#include "string.h" +#include "linux/string.h" #include "symbol.h" #include "cache.h" #include "header.h" @@ -823,6 +823,32 @@ int parse_events_name(struct list_head *list, char *name) return 0; } +static int parse_events__scanner(const char *str, void *data, int start_token); + +static int parse_events_fixup(int ret, const char *str, void *data, + int start_token) +{ + char *o = strdup(str); + char *s = NULL; + char *t = o; + char *p; + int len = 0; + + if (!o) + return ret; + while ((p = strsep(&t, ",")) != NULL) { + if (s) + str_append(&s, &len, ","); + str_append(&s, &len, "cpu/"); + str_append(&s, &len, p); + str_append(&s, &len, "/"); + } + free(o); + if (!s) + return -ENOMEM; + return parse_events__scanner(s, data, start_token); +} + static int parse_events__scanner(const char *str, void *data, int start_token) { YY_BUFFER_STATE buffer; @@ -843,6 +869,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token) parse_events__flush_buffer(buffer, scanner); parse_events__delete_buffer(buffer, scanner); parse_events_lex_destroy(scanner); + if (ret && !strchr(str, '/')) + ret = parse_events_fixup(ret, str, data, start_token); return ret; } diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 29c7b2cb2521..f0b0c008c507 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -387,3 +387,27 @@ void *memdup(const void *src, size_t len) return p; } + +/** + * str_append - reallocate string and append another + * @s: pointer to string pointer + * @len: pointer to len (initialized) + * @a: string to append. + */ +int str_append(char **s, int *len, const char *a) +{ + int olen = *s ? strlen(*s) : 0; + int nlen = olen + strlen(a) + 1; + if (*len < nlen) { + *len = *len * 2; + if (*len < nlen) + *len = nlen; + *s = realloc(*s, *len); + if (!*s) + return -ENOMEM; + if (olen == 0) + **s = 0; + } + strcat(*s, a); + return 0; +} From dc098b35b56f83ae088e4291a4e389a6ff126965 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 20 Apr 2013 11:02:29 -0700 Subject: [PATCH 0201/6183] perf list: List kernel supplied event aliases List the kernel supplied pmu event aliases in perf list It's better when the users can actually see them. Signed-off-by: Andi Kleen Link: http://lkml.kernel.org/r/1366480949-32292-2-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 4 +- tools/perf/builtin-list.c | 3 ++ tools/perf/util/parse-events.c | 5 +- tools/perf/util/pmu.c | 73 ++++++++++++++++++++++++++ tools/perf/util/pmu.h | 3 ++ 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index d1e39dc8c810..826f3d6d1d28 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -8,7 +8,7 @@ perf-list - List all symbolic event types SYNOPSIS -------- [verse] -'perf list' [hw|sw|cache|tracepoint|event_glob] +'perf list' [hw|sw|cache|tracepoint|pmu|event_glob] DESCRIPTION ----------- @@ -104,6 +104,8 @@ To limit the list use: 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, block, etc. +. 'pmu' to print the kernel supplied PMU events. + . If none of the above is matched, it will apply the supplied glob to all events, printing the ones that match. diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 1948eceb517a..e79f423cc302 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -13,6 +13,7 @@ #include "util/parse-events.h" #include "util/cache.h" +#include "util/pmu.h" int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) else if (strcmp(argv[i], "cache") == 0 || strcmp(argv[i], "hwcache") == 0) print_hwcache_events(NULL, false); + else if (strcmp(argv[i], "pmu") == 0) + print_pmu_events(NULL, false); else if (strcmp(argv[i], "--raw-dump") == 0) print_events(NULL, true); else { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a5076f4f6016..2c460ede0a69 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1110,6 +1110,8 @@ int print_hwcache_events(const char *event_glob, bool name_only) } } + if (printed) + printf("\n"); return printed; } @@ -1164,11 +1166,12 @@ void print_events(const char *event_glob, bool name_only) print_hwcache_events(event_glob, name_only); + print_pmu_events(event_glob, name_only); + if (event_glob != NULL) return; if (!name_only) { - printf("\n"); printf(" %-50s [%s]\n", "rNNN", event_type_descriptors[PERF_TYPE_RAW]); diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 1d1862dcbbbc..bc9d8069d376 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -564,3 +564,76 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) for (b = from; b <= to; b++) set_bit(b, bits); } + +static char *format_alias(char *buf, int len, struct perf_pmu *pmu, + struct perf_pmu_alias *alias) +{ + snprintf(buf, len, "%s/%s/", pmu->name, alias->name); + return buf; +} + +static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, + struct perf_pmu_alias *alias) +{ + snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); + return buf; +} + +static int cmp_string(const void *a, const void *b) +{ + const char * const *as = a; + const char * const *bs = b; + return strcmp(*as, *bs); +} + +void print_pmu_events(const char *event_glob, bool name_only) +{ + struct perf_pmu *pmu; + struct perf_pmu_alias *alias; + char buf[1024]; + int printed = 0; + int len, j; + char **aliases; + + pmu = NULL; + len = 0; + while ((pmu = perf_pmu__scan(pmu)) != NULL) + list_for_each_entry(alias, &pmu->aliases, list) + len++; + aliases = malloc(sizeof(char *) * len); + if (!aliases) + return; + pmu = NULL; + j = 0; + while ((pmu = perf_pmu__scan(pmu)) != NULL) + list_for_each_entry(alias, &pmu->aliases, list) { + char *name = format_alias(buf, sizeof(buf), pmu, alias); + bool is_cpu = !strcmp(pmu->name, "cpu"); + + if (event_glob != NULL && + !(strglobmatch(name, event_glob) || + (!is_cpu && strglobmatch(alias->name, + event_glob)))) + continue; + aliases[j] = name; + if (is_cpu && !name_only) + aliases[j] = format_alias_or(buf, sizeof(buf), + pmu, alias); + aliases[j] = strdup(aliases[j]); + j++; + } + len = j; + qsort(aliases, len, sizeof(char *), cmp_string); + for (j = 0; j < len; j++) { + if (name_only) { + printf("%s ", aliases[j]); + continue; + } + printf(" %-50s [Kernel PMU event]\n", aliases[j]); + free(aliases[j]); + printed++; + } + if (printed) + printf("\n"); + free(aliases); +} diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index d17b5656bacf..6b2cbe2d4cc3 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -3,6 +3,7 @@ #include #include +#include enum { PERF_PMU_FORMAT_VALUE_CONFIG, @@ -40,5 +41,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); +void print_pmu_events(const char *event_glob, bool name_only); + int perf_pmu__test(void); #endif /* __PMU_H */ From b21484f1a1f300d422cfe5d4f8f50015e22cea24 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Thu, 6 Dec 2012 21:48:05 -0800 Subject: [PATCH 0202/6183] perf report/top: Add option to collapse undesired parts of call graph For example, in an application with an expensive function implemented with deeply nested recursive calls, the default call-graph presentation is dominated by the different callchains within that function. By ignoring these callees, we can collect the callchains leading into the function and compactly identify what to blame for expensive calls. For example, in this report the callers of garbage_collect() are scattered across the tree: $ perf report -d ruby 2>- | grep -m10 ^[^#]*[a-z] 22.03% ruby [.] gc_mark --- gc_mark |--59.40%-- mark_keyvalue | st_foreach | gc_mark_children | |--99.75%-- rb_gc_mark | | rb_vm_mark | | gc_mark_children | | gc_marks | | |--99.00%-- garbage_collect If we ignore the callees of garbage_collect(), its callers are coalesced: $ perf report --ignore-callees garbage_collect -d ruby 2>- | grep -m10 ^[^#]*[a-z] 72.92% ruby [.] garbage_collect --- garbage_collect vm_xmalloc |--47.08%-- ruby_xmalloc | st_insert2 | rb_hash_aset | |--98.45%-- features_index_add | | rb_provide_feature | | rb_require_safe | | vm_call_method Signed-off-by: Greg Price Tested-by: Jiri Olsa Cc: David Ahern Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20130623031720.GW22203@biohazard-cafe.mit.edu Link: http://lkml.kernel.org/r/20130708115746.GO22203@biohazard-cafe.mit.edu Cc: Fengguang Wu [ remove spaces at beginning of line, reported by Fengguang Wu ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 5 +++++ tools/perf/Documentation/perf-top.txt | 5 +++++ tools/perf/builtin-report.c | 27 +++++++++++++++++++++--- tools/perf/builtin-top.c | 6 ++++-- tools/perf/util/machine.c | 24 +++++++++++++-------- tools/perf/util/machine.h | 4 +++- tools/perf/util/session.c | 3 +-- tools/perf/util/sort.c | 2 ++ tools/perf/util/sort.h | 4 ++++ 9 files changed, 63 insertions(+), 17 deletions(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 66dab7410c1d..747ff50284b7 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -135,6 +135,11 @@ OPTIONS --inverted:: alias for inverted caller based call graph. +--ignore-callees=:: + Ignore callees of the function(s) matching the given regex. + This has the effect of collecting the callers of each such + function into one place in the call-graph tree. + --pretty=:: Pretty printing style. key: normal, raw diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 7fdd1909e376..58d6598a9686 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -155,6 +155,11 @@ Default is to monitor all CPUS. Default: fractal,0.5,callee. +--ignore-callees=:: + Ignore callees of the function(s) matching the given regex. + This has the effect of collecting the callers of each such + function into one place in the call-graph tree. + --percent-limit:: Do not show entries which have an overhead under that percent. (Default: 0). diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ee2ca3eb22df..9a7e54d701cf 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool, if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { err = machine__resolve_callchain(machine, evsel, al->thread, - sample, &parent); + sample, &parent, al); if (err) return err; } @@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { err = machine__resolve_callchain(machine, evsel, al->thread, - sample, &parent); + sample, &parent, al); if (err) return err; } @@ -254,7 +254,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { err = machine__resolve_callchain(machine, evsel, al->thread, - sample, &parent); + sample, &parent, al); if (err) return err; } @@ -681,6 +681,24 @@ setup: return 0; } +int +report_parse_ignore_callees_opt(const struct option *opt __maybe_unused, + const char *arg, int unset __maybe_unused) +{ + if (arg) { + int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED); + if (err) { + char buf[BUFSIZ]; + regerror(err, &ignore_callees_regex, buf, sizeof(buf)); + pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf); + return -1; + } + have_ignore_callees = 1; + } + + return 0; +} + static int parse_branch_mode(const struct option *opt __maybe_unused, const char *str __maybe_unused, int unset) @@ -771,6 +789,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, "alias for inverted call graph"), + OPT_CALLBACK(0, "ignore-callees", NULL, "regex", + "ignore callees of these functions in call graphs", + report_parse_ignore_callees_opt), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a237059f51cf..bbf463572777 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -773,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool, sample->callchain) { err = machine__resolve_callchain(machine, evsel, al.thread, sample, - &parent); - + &parent, &al); if (err) return; } @@ -1109,6 +1108,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, "mode[,dump_size]", record_callchain_help, &parse_callchain_opt, "fp"), + OPT_CALLBACK(0, "ignore-callees", NULL, "regex", + "ignore callees of these functions in call graphs", + report_parse_ignore_callees_opt), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 5dd5026a82ef..f9f9d6381b9a 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event) return ret; } -static bool symbol__match_parent_regex(struct symbol *sym) +static bool symbol__match_regex(struct symbol *sym, regex_t *regex) { - if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) + if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) return 1; - return 0; } @@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine, static int machine__resolve_callchain_sample(struct machine *machine, struct thread *thread, struct ip_callchain *chain, - struct symbol **parent) - + struct symbol **parent, + struct addr_location *root_al) { u8 cpumode = PERF_RECORD_MISC_USER; unsigned int i; @@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine, MAP__FUNCTION, ip, &al, NULL); if (al.sym != NULL) { if (sort__has_parent && !*parent && - symbol__match_parent_regex(al.sym)) + symbol__match_regex(al.sym, &parent_regex)) *parent = al.sym; + else if (have_ignore_callees && root_al && + symbol__match_regex(al.sym, &ignore_callees_regex)) { + /* Treat this symbol as the root, + forgetting its callees. */ + *root_al = al; + callchain_cursor_reset(&callchain_cursor); + } if (!symbol_conf.use_callchain) break; } @@ -1237,13 +1243,13 @@ int machine__resolve_callchain(struct machine *machine, struct perf_evsel *evsel, struct thread *thread, struct perf_sample *sample, - struct symbol **parent) - + struct symbol **parent, + struct addr_location *root_al) { int ret; ret = machine__resolve_callchain_sample(machine, thread, - sample->callchain, parent); + sample->callchain, parent, root_al); if (ret) return ret; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e49ba01b7937..5bb6244194d5 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -5,6 +5,7 @@ #include #include "map.h" +struct addr_location; struct branch_stack; struct perf_evsel; struct perf_sample; @@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine, struct perf_evsel *evsel, struct thread *thread, struct perf_sample *sample, - struct symbol **parent); + struct symbol **parent, + struct addr_location *root_al); /* * Default guest kernel is defined by parameter --guestkallsyms diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 951a1cfb317c..1eb58eedcac1 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1406,9 +1406,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, if (symbol_conf.use_callchain && sample->callchain) { - if (machine__resolve_callchain(machine, evsel, al.thread, - sample, NULL) != 0) { + sample, NULL, NULL) != 0) { if (verbose) error("Failed to resolve callchain. Skipping\n"); return; diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8deee19d2e7f..cb2b108635ee 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -7,6 +7,8 @@ const char default_parent_pattern[] = "^sys_|^do_page_fault"; const char *parent_pattern = default_parent_pattern; const char default_sort_order[] = "comm,dso,symbol"; const char *sort_order = default_sort_order; +regex_t ignore_callees_regex; +int have_ignore_callees = 0; int sort__need_collapse = 0; int sort__has_parent = 0; int sort__has_sym = 0; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 45ac84c1e037..a4a6d0b1ea0e 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -29,6 +29,8 @@ extern const char *sort_order; extern const char default_parent_pattern[]; extern const char *parent_pattern; extern const char default_sort_order[]; +extern regex_t ignore_callees_regex; +extern int have_ignore_callees; extern int sort__need_collapse; extern int sort__has_parent; extern int sort__has_sym; @@ -183,4 +185,6 @@ int setup_sorting(void); extern int sort_dimension__add(const char *); void sort__setup_elide(FILE *fp); +int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); + #endif /* __PERF_SORT_H */ From 2c5d4b4a087c448d7818b89294c98d4977dfe76c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 31 Jan 2013 23:31:11 +0100 Subject: [PATCH 0203/6183] perf tools: Add struct perf_hpp_fmt into hpp callbacks Adding 'struct perf_hpp_fmt' into hpp callbacks, so commands can access their private data. It'll be handy for diff command in future to be able to access file related data for each column. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-7vy2m18574b1bicoljn8e9lw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 10 +++-- tools/perf/ui/gtk/hists.c | 9 ++-- tools/perf/ui/hist.c | 79 ++++++++++++++++++++++------------ tools/perf/ui/stdio/hist.c | 4 +- tools/perf/util/hist.h | 10 +++-- 5 files changed, 71 insertions(+), 41 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 06e892f1f8ca..2cb39164a1cd 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ - struct hist_entry *he) \ +static int \ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ { \ return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ } @@ -762,9 +764,9 @@ static int hist_browser__show_entry(struct hist_browser *browser, first = false; if (fmt->color) { - width -= fmt->color(&hpp, entry); + width -= fmt->color(fmt, &hpp, entry); } else { - width -= fmt->entry(&hpp, entry); + width -= fmt->entry(fmt, &hpp, entry); slsmg_printf("%s", s); } } diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 32549035f50d..cb2ed1980147 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ +static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp, \ struct hist_entry *he) \ { \ return __hpp__color_fmt(hpp, he, he_get_##_field); \ @@ -244,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, col_idx = 0; perf_hpp__for_each_format(fmt) { - fmt->header(&hpp); + fmt->header(fmt, &hpp); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, ltrim(s), @@ -296,9 +297,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, perf_hpp__for_each_format(fmt) { if (fmt->color) - fmt->color(&hpp, h); + fmt->color(fmt, &hpp, h); else - fmt->entry(&hpp, h); + fmt->entry(fmt, &hpp, h); gtk_tree_store_set(store, &iter, col_idx++, s, -1); } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 4bf91b09d62d..5440d56d884a 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -1,4 +1,5 @@ #include +#include #include "../util/hist.h" #include "../util/util.h" @@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, } #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ -static int hpp__header_##_type(struct perf_hpp *hpp) \ +static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp) \ { \ int len = _min_width; \ \ @@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \ } #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ -static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ +static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp __maybe_unused) \ { \ int len = _min_width; \ \ @@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ +static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ { \ return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ (hpp_snprint_fn)percent_color_snprintf, true); \ } #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ -static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ +static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ { \ const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ @@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ return he->stat._field; \ } \ \ -static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ +static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ { \ const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ @@ -158,12 +164,14 @@ HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) HPP_RAW_FNS(period, "Period", period, 12, 12) -static int hpp__header_baseline(struct perf_hpp *hpp) +static int hpp__header_baseline(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp) { return scnprintf(hpp->buf, hpp->size, "Baseline"); } -static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) +static int hpp__width_baseline(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp __maybe_unused) { return 8; } @@ -184,7 +192,8 @@ static double baseline_percent(struct hist_entry *he) return percent; } -static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__color_baseline(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { double percent = baseline_percent(he); @@ -194,7 +203,8 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, " "); } -static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__entry_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { double percent = baseline_percent(he); const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; @@ -205,19 +215,22 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, " "); } -static int hpp__header_period_baseline(struct perf_hpp *hpp) +static int hpp__header_period_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; return scnprintf(hpp->buf, hpp->size, fmt, "Period Base"); } -static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused) +static int hpp__width_period_baseline(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp __maybe_unused) { return 12; } -static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__entry_period_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { struct hist_entry *pair = hist_entry__next_pair(he); u64 period = pair ? pair->stat.period : 0; @@ -226,19 +239,22 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h return scnprintf(hpp->buf, hpp->size, fmt, period); } -static int hpp__header_delta(struct perf_hpp *hpp) +static int hpp__header_delta(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; return scnprintf(hpp->buf, hpp->size, fmt, "Delta"); } -static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) +static int hpp__width_delta(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp __maybe_unused) { return 7; } -static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__entry_delta(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; @@ -259,19 +275,22 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } -static int hpp__header_ratio(struct perf_hpp *hpp) +static int hpp__header_ratio(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; return scnprintf(hpp->buf, hpp->size, fmt, "Ratio"); } -static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) +static int hpp__width_ratio(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp __maybe_unused) { return 14; } -static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__entry_ratio(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; @@ -291,19 +310,22 @@ static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } -static int hpp__header_wdiff(struct perf_hpp *hpp) +static int hpp__header_wdiff(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff"); } -static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) +static int hpp__width_wdiff(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp __maybe_unused) { return 14; } -static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__entry_wdiff(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; @@ -323,19 +345,22 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } -static int hpp__header_formula(struct perf_hpp *hpp) +static int hpp__header_formula(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; return scnprintf(hpp->buf, hpp->size, fmt, "Formula"); } -static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) +static int hpp__width_formula(struct perf_hpp_fmt *fmt __maybe_unused, + struct perf_hpp *hpp __maybe_unused) { return 70; } -static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) +static int hpp__entry_formula(struct perf_hpp_fmt *_fmt __maybe_unused, + struct perf_hpp *hpp, struct hist_entry *he) { struct hist_entry *pair = hist_entry__next_pair(he); const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; @@ -454,9 +479,9 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, first = false; if (color && fmt->color) - ret = fmt->color(hpp, he); + ret = fmt->color(fmt, hpp, he); else - ret = fmt->entry(hpp, he); + ret = fmt->entry(fmt, hpp, he); advance_hpp(hpp, ret); } @@ -499,7 +524,7 @@ unsigned int hists__sort_list_width(struct hists *hists) if (i) ret += 2; - ret += fmt->width(&dummy_hpp); + ret += fmt->width(fmt, &dummy_hpp); } list_for_each_entry(se, &hist_entry__sort_list, list) diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index ae7a75432249..ee703720649d 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -365,7 +365,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, else first = false; - fmt->header(&dummy_hpp); + fmt->header(fmt, &dummy_hpp); fprintf(fp, "%s", bf); } @@ -410,7 +410,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, else first = false; - width = fmt->width(&dummy_hpp); + width = fmt->width(fmt, &dummy_hpp); for (i = 0; i < width; i++) fprintf(fp, "."); } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2d3790fd99bb..0c62116d4d3a 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -141,10 +141,12 @@ struct perf_hpp { }; struct perf_hpp_fmt { - int (*header)(struct perf_hpp *hpp); - int (*width)(struct perf_hpp *hpp); - int (*color)(struct perf_hpp *hpp, struct hist_entry *he); - int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); + int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp); + int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp); + int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he); + int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, + struct hist_entry *he); struct list_head list; }; From 2b8bfa6bb8a7d26935207710397386759b42125c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 31 Jan 2013 23:34:25 +0100 Subject: [PATCH 0204/6183] perf tools: Centralize default columns init in perf_hpp__init Now when diff command is separated from other standard outputs, we can use perf_hpp__init to initialize all standard columns. Moving PERF_HPP__OVERHEAD column init back to perf_hpp__init, and removing extra enable calls. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-nj2xk89tj972tbqswfs498ex@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 1 - tools/perf/ui/browsers/hists.c | 2 -- tools/perf/ui/hist.c | 2 ++ tools/perf/ui/setup.c | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9a7e54d701cf..188c265751c8 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -861,7 +861,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) setup_browser(true); else { use_browser = 0; - perf_hpp__column_enable(PERF_HPP__OVERHEAD); perf_hpp__init(); } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 2cb39164a1cd..7ef36c360471 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -703,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) void hist_browser__init_hpp(void) { - perf_hpp__column_enable(PERF_HPP__OVERHEAD); - perf_hpp__init(); perf_hpp__format[PERF_HPP__OVERHEAD].color = diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 5440d56d884a..f45c97f694da 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -421,6 +421,8 @@ LIST_HEAD(perf_hpp__list); void perf_hpp__init(void) { + perf_hpp__column_enable(PERF_HPP__OVERHEAD); + if (symbol_conf.show_cpu_utilization) { perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ae6a789cb0f6..47d9a571f261 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager) if (fallback_to_pager) setup_pager(); - perf_hpp__column_enable(PERF_HPP__OVERHEAD); perf_hpp__init(); break; } From ec308426ea743469ec6c2b0e06e20b3671546e8f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 25 Mar 2013 00:02:01 +0100 Subject: [PATCH 0205/6183] perf diff: Introducing diff_data object to hold files Introducing struct diff_data to hold data file specifics. It will be handy when dealing with more than 2 data files. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-981q265sf6h05zuu8fnvw842@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 145 +++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 49 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 0aac5f3e594d..015ca2d4fe90 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -19,10 +19,24 @@ #include -static char const *input_old = "perf.data.old", - *input_new = "perf.data"; -static char diff__default_sort_order[] = "dso,symbol"; -static bool force; +struct data__file { + struct perf_session *session; + const char *file; + int idx; +}; + +static struct data__file *data__files; +static int data__files_cnt; + +#define data__for_each_file_start(i, d, s) \ + for (i = s, d = &data__files[s]; \ + i < data__files_cnt; \ + i++, d = &data__files[i]) + +#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0) + +static char diff__default_sort_order[] = "dso,symbol"; +static bool force; static bool show_period; static bool show_formula; static bool show_baseline_only; @@ -467,56 +481,62 @@ static void hists__process(struct hists *old, struct hists *new) hists__fprintf(new, true, 0, 0, 0, stdout); } -static int __cmd_diff(void) +static void data_process(void) { - int ret, i; -#define older (session[0]) -#define newer (session[1]) - struct perf_session *session[2]; - struct perf_evlist *evlist_new, *evlist_old; - struct perf_evsel *evsel; + struct perf_evlist *evlist_old = data__files[0].session->evlist; + struct perf_evlist *evlist_new = data__files[1].session->evlist; + struct perf_evsel *evsel_old; bool first = true; - older = perf_session__new(input_old, O_RDONLY, force, false, - &tool); - newer = perf_session__new(input_new, O_RDONLY, force, false, - &tool); - if (session[0] == NULL || session[1] == NULL) - return -ENOMEM; + list_for_each_entry(evsel_old, &evlist_old->entries, node) { + struct perf_evsel *evsel_new; - for (i = 0; i < 2; ++i) { - ret = perf_session__process_events(session[i], &tool); - if (ret) - goto out_delete; - } - - evlist_old = older->evlist; - evlist_new = newer->evlist; - - perf_evlist__collapse_resort(evlist_old); - perf_evlist__collapse_resort(evlist_new); - - list_for_each_entry(evsel, &evlist_new->entries, node) { - struct perf_evsel *evsel_old; - - evsel_old = evsel_match(evsel, evlist_old); - if (!evsel_old) + evsel_new = evsel_match(evsel_old, evlist_new); + if (!evsel_new) continue; fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", - perf_evsel__name(evsel)); + perf_evsel__name(evsel_old)); first = false; - hists__process(&evsel_old->hists, &evsel->hists); + hists__process(&evsel_old->hists, &evsel_new->hists); + } +} + +static int __cmd_diff(void) +{ + struct data__file *d; + int ret = -EINVAL, i; + + data__for_each_file(i, d) { + d->session = perf_session__new(d->file, O_RDONLY, force, + false, &tool); + if (!d->session) { + pr_err("Failed to open %s\n", d->file); + ret = -ENOMEM; + goto out_delete; + } + + ret = perf_session__process_events(d->session, &tool); + if (ret) { + pr_err("Failed to process %s\n", d->file); + goto out_delete; + } + + perf_evlist__collapse_resort(d->session->evlist); } -out_delete: - for (i = 0; i < 2; ++i) - perf_session__delete(session[i]); + data_process(); + + out_delete: + data__for_each_file(i, d) { + if (d->session) + perf_session__delete(d->session); + } + + free(data__files); return ret; -#undef older -#undef newer } static const char * const diff_usage[] = { @@ -589,27 +609,54 @@ static void ui_init(void) } } -int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) +static int data_init(int argc, const char **argv) { - sort_order = diff__default_sort_order; - argc = parse_options(argc, argv, options, diff_usage, 0); + struct data__file *d; + static const char *defaults[] = { + "perf.data.old", + "perf.data", + }; + int i; + + data__files_cnt = 2; + if (argc) { if (argc > 2) usage_with_options(diff_usage, options); if (argc == 2) { - input_old = argv[0]; - input_new = argv[1]; + defaults[0] = argv[0]; + defaults[1] = argv[1]; } else - input_new = argv[0]; + defaults[1] = argv[0]; } else if (symbol_conf.default_guest_vmlinux_name || symbol_conf.default_guest_kallsyms) { - input_old = "perf.data.host"; - input_new = "perf.data.guest"; + defaults[0] = "perf.data.host"; + defaults[1] = "perf.data.guest"; } + data__files = zalloc(sizeof(*data__files) * data__files_cnt); + if (!data__files) + return -ENOMEM; + + data__for_each_file(i, d) { + d->file = defaults[i]; + d->idx = i; + } + + return 0; +} + +int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) +{ + sort_order = diff__default_sort_order; + argc = parse_options(argc, argv, options, diff_usage, 0); + if (symbol__init() < 0) return -1; + if (data_init(argc, argv) < 0) + return -1; + ui_init(); if (setup_sorting() < 0) From 426115cf5dd81d17a6322c493ca337e637ce2aed Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Jul 2013 22:13:42 +0200 Subject: [PATCH 0206/6183] drm/i915: clean up vlv ->pre_pll_enable and pll enable sequence No need to call the ->pre_pll_enable hook twice if we don't enable the dpll too early. This should make Jani a bit less grumpy. v2: Rebase on top of the newly-colored BUG_ONs. v3: Reinstate the lost write of the DPLL_MD register, spotted by Imre. Cc: Imre Deak Cc: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 47 ++++++++++++---------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b1b1d2a38fc9..abaae78f0c52 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1321,32 +1321,40 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID); } -static void vlv_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +static void vlv_enable_pll(struct intel_crtc *crtc) { - int reg; - u32 val; + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int reg = DPLL(crtc->pipe); + u32 dpll = crtc->config.dpll_hw_state.dpll; - assert_pipe_disabled(dev_priv, pipe); + assert_pipe_disabled(dev_priv, crtc->pipe); /* No really, not for ILK+ */ BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); /* PLL is protected by panel, make sure we can write it */ if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) - assert_panel_unlocked(dev_priv, pipe); + assert_panel_unlocked(dev_priv, crtc->pipe); - reg = DPLL(pipe); - val = I915_READ(reg); - val |= DPLL_VCO_ENABLE; + I915_WRITE(reg, dpll); + POSTING_READ(reg); + udelay(150); + + if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) + DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe); + + I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md); + POSTING_READ(DPLL_MD(crtc->pipe)); /* We do this three times for luck */ - I915_WRITE(reg, val); + I915_WRITE(reg, dpll); POSTING_READ(reg); udelay(150); /* wait for warmup */ - I915_WRITE(reg, val); + I915_WRITE(reg, dpll); POSTING_READ(reg); udelay(150); /* wait for warmup */ - I915_WRITE(reg, val); + I915_WRITE(reg, dpll); POSTING_READ(reg); udelay(150); /* wait for warmup */ } @@ -3654,7 +3662,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); - vlv_enable_pll(dev_priv, pipe); + vlv_enable_pll(intel_crtc); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) @@ -4409,7 +4417,6 @@ static void vlv_update_pll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *encoder; int pipe = crtc->pipe; u32 dpll, mdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; @@ -4498,10 +4505,6 @@ static void vlv_update_pll(struct intel_crtc *crtc) vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000); - for_each_encoder_on_crtc(dev, &crtc->base, encoder) - if (encoder->pre_pll_enable) - encoder->pre_pll_enable(encoder); - /* Enable DPIO clock input */ dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; @@ -4511,20 +4514,10 @@ static void vlv_update_pll(struct intel_crtc *crtc) dpll |= DPLL_VCO_ENABLE; crtc->config.dpll_hw_state.dpll = dpll; - I915_WRITE(DPLL(pipe), dpll); - POSTING_READ(DPLL(pipe)); - udelay(150); - - if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) - DRM_ERROR("DPLL %d failed to lock\n", pipe); - dpll_md = (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; crtc->config.dpll_hw_state.dpll_md = dpll_md; - I915_WRITE(DPLL_MD(pipe), dpll_md); - POSTING_READ(DPLL_MD(pipe)); - if (crtc->config.has_dp_encoder) intel_dp_set_m_n(crtc); From 3ad8a208abbe1bdfe31512053a81ac4938aed447 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:32 +0200 Subject: [PATCH 0207/6183] drm/i915: Fix up cpt pixel multiplier enable sequence Bspec for the "DPLL HDMI multiplier" field says: "Restriction : The DPLL must be enabled and stable before setting these bits. These bits must be programmed after DPLL_SEL is programmed." There is apparently no restriction on programming the DPLL_SEL register wrt the DPLL. So let's just move that up before we enable the pch dpll. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index abaae78f0c52..3d1c97abee28 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3004,15 +3004,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) /* For PCH output, training FDI link */ dev_priv->display.fdi_link_train(crtc); - /* XXX: pch pll's can be enabled any time before we enable the PCH - * transcoder, and we actually should do this to not upset any PCH - * transcoder that already use the clock when we share it. - * - * Note that enable_shared_dpll tries to do the right thing, but - * get_shared_dpll unconditionally resets the pll - we need that to have - * the right LVDS enable sequence. */ - ironlake_enable_shared_dpll(intel_crtc); - + /* We need to program the right clock selection before writing the pixel + * mutliplier into the DPLL. */ if (HAS_PCH_CPT(dev)) { u32 sel; @@ -3026,6 +3019,15 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) I915_WRITE(PCH_DPLL_SEL, temp); } + /* XXX: pch pll's can be enabled any time before we enable the PCH + * transcoder, and we actually should do this to not upset any PCH + * transcoder that already use the clock when we share it. + * + * Note that enable_shared_dpll tries to do the right thing, but + * get_shared_dpll unconditionally resets the pll - we need that to have + * the right LVDS enable sequence. */ + ironlake_enable_shared_dpll(intel_crtc); + /* set transcoder timing, panel must allow it */ assert_panel_unlocked(dev_priv, pipe); ironlake_pch_transcoder_set_timings(intel_crtc, pipe); From 9af303e22a317d1cc6f440e08f72428830708b37 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 1 Dec 2012 21:15:40 +0100 Subject: [PATCH 0208/6183] perf diff: Switching the base hists to be pairs head Making the baseline hists to act as a pairs head. So far we don't care which hists act as a pairs head, because we have only 2 files to deal with and any of them is suitable to do the job. But if we want to process more files, we need to pick up one hists to act as pairs head, and the baseline hists is the most suitable. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-cklmt2o4j87i9viz900245ae@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 60 +++++++++++++++++++-------------------- tools/perf/ui/hist.c | 25 ++++------------ 2 files changed, 35 insertions(+), 50 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 015ca2d4fe90..0cfe99ea9056 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -167,34 +167,34 @@ double perf_diff__period_percent(struct hist_entry *he, u64 period) double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) { - double new_percent = perf_diff__period_percent(he, he->stat.period); - double old_percent = perf_diff__period_percent(pair, pair->stat.period); + double old_percent = perf_diff__period_percent(he, he->stat.period); + double new_percent = perf_diff__period_percent(pair, pair->stat.period); - he->diff.period_ratio_delta = new_percent - old_percent; - he->diff.computed = true; - return he->diff.period_ratio_delta; + pair->diff.period_ratio_delta = new_percent - old_percent; + pair->diff.computed = true; + return pair->diff.period_ratio_delta; } double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) { - double new_period = he->stat.period; - double old_period = pair->stat.period; + double old_period = he->stat.period ?: 1; + double new_period = pair->stat.period; - he->diff.computed = true; - he->diff.period_ratio = new_period / old_period; - return he->diff.period_ratio; + pair->diff.computed = true; + pair->diff.period_ratio = new_period / old_period; + return pair->diff.period_ratio; } s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) { - u64 new_period = he->stat.period; - u64 old_period = pair->stat.period; + u64 old_period = he->stat.period; + u64 new_period = pair->stat.period; - he->diff.computed = true; - he->diff.wdiff = new_period * compute_wdiff_w2 - - old_period * compute_wdiff_w1; + pair->diff.computed = true; + pair->diff.wdiff = new_period * compute_wdiff_w2 - + old_period * compute_wdiff_w1; - return he->diff.wdiff; + return pair->diff.wdiff; } static int formula_delta(struct hist_entry *he, struct hist_entry *pair, @@ -203,15 +203,15 @@ static int formula_delta(struct hist_entry *he, struct hist_entry *pair, return scnprintf(buf, size, "(%" PRIu64 " * 100 / %" PRIu64 ") - " "(%" PRIu64 " * 100 / %" PRIu64 ")", - he->stat.period, he->hists->stats.total_period, - pair->stat.period, pair->hists->stats.total_period); + pair->stat.period, pair->hists->stats.total_period, + he->stat.period, he->hists->stats.total_period); } static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, char *buf, size_t size) { - double new_period = he->stat.period; - double old_period = pair->stat.period; + double old_period = he->stat.period; + double new_period = pair->stat.period; return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); } @@ -219,8 +219,8 @@ static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, char *buf, size_t size) { - u64 new_period = he->stat.period; - u64 old_period = pair->stat.period; + u64 old_period = he->stat.period; + u64 new_period = pair->stat.period; return scnprintf(buf, size, "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", @@ -462,23 +462,23 @@ static void hists__compute_resort(struct hists *hists) } } -static void hists__process(struct hists *old, struct hists *new) +static void hists__process(struct hists *base, struct hists *new) { - hists__match(new, old); + hists__match(base, new); if (show_baseline_only) - hists__baseline_only(new); + hists__baseline_only(base); else - hists__link(new, old); + hists__link(base, new); if (sort_compute) { - hists__precompute(new); - hists__compute_resort(new); + hists__precompute(base); + hists__compute_resort(base); } else { - hists__output_resort(new); + hists__output_resort(base); } - hists__fprintf(new, true, 0, 0, 0, stdout); + hists__fprintf(base, true, 0, 0, 0, stdout); } static void data_process(void) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index f45c97f694da..02313a9c4682 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -178,18 +178,8 @@ static int hpp__width_baseline(struct perf_hpp_fmt *fmt __maybe_unused, static double baseline_percent(struct hist_entry *he) { - struct hist_entry *pair = hist_entry__next_pair(he); - struct hists *pair_hists = pair ? pair->hists : NULL; - double percent = 0.0; - - if (pair) { - u64 total_period = pair_hists->stats.total_period; - u64 base_period = pair->stat.period; - - percent = 100.0 * base_period / total_period; - } - - return percent; + struct hists *hists = he->hists; + return 100.0 * he->stat.period / hists->stats.total_period; } static int hpp__color_baseline(struct perf_hpp_fmt *fmt __maybe_unused, @@ -197,10 +187,8 @@ static int hpp__color_baseline(struct perf_hpp_fmt *fmt __maybe_unused, { double percent = baseline_percent(he); - if (hist_entry__has_pairs(he) || symbol_conf.field_sep) - return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); - else - return scnprintf(hpp->buf, hpp->size, " "); + return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", + percent); } static int hpp__entry_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, @@ -209,10 +197,7 @@ static int hpp__entry_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, double percent = baseline_percent(he); const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; - if (hist_entry__has_pairs(he) || symbol_conf.field_sep) - return scnprintf(hpp->buf, hpp->size, fmt, percent); - else - return scnprintf(hpp->buf, hpp->size, " "); + return scnprintf(hpp->buf, hpp->size, fmt, percent); } static int hpp__header_period_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, From 50b44a449ff1a19712ebc36ffccf9ac0a68033bf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:33 +0200 Subject: [PATCH 0209/6183] drm/i915: clear DPLL reg when disabling i9xx dplls Toghether with the hw state readout this should catch cases where we don't properly updated the pll state (either in sw or hw). At least for the shared dpll code the equivalent tricke helped a lot in catching bugs. Also rename the function prefix, it's not a generic piece of infrastructure. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d1c97abee28..ae3dc5d1ff52 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1406,7 +1406,7 @@ static void i9xx_enable_pll(struct intel_crtc *crtc) } /** - * intel_disable_pll - disable a PLL + * i9xx_disable_pll - disable a PLL * @dev_priv: i915 private structure * @pipe: pipe PLL to disable * @@ -1414,11 +1414,8 @@ static void i9xx_enable_pll(struct intel_crtc *crtc) * * Note! This is for pre-ILK only. */ -static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +static void i9xx_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { - int reg; - u32 val; - /* Don't disable pipe A or pipe A PLLs if needed */ if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) return; @@ -1426,11 +1423,8 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) /* Make sure the pipe isn't still relying on us */ assert_pipe_disabled(dev_priv, pipe); - reg = DPLL(pipe); - val = I915_READ(reg); - val &= ~DPLL_VCO_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); + I915_WRITE(DPLL(pipe), 0); + POSTING_READ(DPLL(pipe)); } void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) @@ -3782,7 +3776,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (encoder->post_disable) encoder->post_disable(encoder); - intel_disable_pll(dev_priv, pipe); + i9xx_disable_pll(dev_priv, pipe); intel_crtc->active = false; intel_update_fbc(dev); From e0af43d2486fc50208076cfd93af55615fd4adfd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 1 Dec 2012 21:18:20 +0100 Subject: [PATCH 0210/6183] perf hists: Marking dummy hists entries It does not make sense to make some computation (ratio, wdiff), when the hist_entry is 'dummy' - added via hists__link. Adding dummy field to struct hist_entry which indicates that it was added by hists__link and avoiding some of the processing for such entries. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-g8bxml0n0pnqsrpyd98p0ird@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/hist.c | 21 ++++++++++++++------- tools/perf/util/hist.c | 1 + tools/perf/util/sort.h | 3 +++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 02313a9c4682..a359b75ce800 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -187,8 +187,11 @@ static int hpp__color_baseline(struct perf_hpp_fmt *fmt __maybe_unused, { double percent = baseline_percent(he); - return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", - percent); + if (!he->dummy) + return percent_color_snprintf(hpp->buf, hpp->size, + " %6.2f%%", percent); + else + return scnprintf(hpp->buf, hpp->size, " "); } static int hpp__entry_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, @@ -197,7 +200,10 @@ static int hpp__entry_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, double percent = baseline_percent(he); const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; - return scnprintf(hpp->buf, hpp->size, fmt, percent); + if (!he->dummy) + return scnprintf(hpp->buf, hpp->size, fmt, percent); + else + return scnprintf(hpp->buf, hpp->size, " "); } static int hpp__header_period_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, @@ -251,8 +257,7 @@ static int hpp__entry_delta(struct perf_hpp_fmt *_fmt __maybe_unused, diff = he->diff.period_ratio_delta; else diff = perf_diff__compute_delta(he, pair); - } else - diff = perf_diff__period_percent(he, he->stat.period); + } if (fabs(diff) >= 0.01) scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); @@ -282,7 +287,8 @@ static int hpp__entry_ratio(struct perf_hpp_fmt *_fmt __maybe_unused, char buf[32] = " "; double ratio = 0.0; - if (pair) { + /* No point for ratio number if we are dummy.. */ + if (!he->dummy && pair) { if (he->diff.computed) ratio = he->diff.period_ratio; else @@ -317,7 +323,8 @@ static int hpp__entry_wdiff(struct perf_hpp_fmt *_fmt __maybe_unused, char buf[32] = " "; s64 wdiff = 0; - if (pair) { + /* No point for wdiff number if we are dummy.. */ + if (!he->dummy && pair) { if (he->diff.computed) wdiff = he->diff.wdiff; else diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b11a6cfdb414..a9dd1b9d8907 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -912,6 +912,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, rb_link_node(&he->rb_node_in, parent, p); rb_insert_color(&he->rb_node_in, root); hists__inc_nr_entries(hists, he); + he->dummy = true; } out: return he; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index a4a6d0b1ea0e..586022dc3264 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -89,6 +89,9 @@ struct hist_entry { struct hist_entry_diff diff; + /* We are added by hists__add_dummy_entry. */ + bool dummy; + /* XXX These two should move to some tree widget lib */ u16 row_offset; u16 nr_rows; From 1d81c7fc25c0f0559e3306fc73ecfe78b740c9e8 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 1 Dec 2012 21:56:03 +0100 Subject: [PATCH 0211/6183] perf diff: Display data file info ahead of the diff output Data files are referenced through the index of the file on the command line. Adding list of data files for each index to ease up navigation for user. It's displayed only if in verbose mode. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-dfjxa6n116ughjjxohpkuvi8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 0cfe99ea9056..9574ba18bc7b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -481,6 +481,21 @@ static void hists__process(struct hists *base, struct hists *new) hists__fprintf(base, true, 0, 0, 0, stdout); } +static void data__fprintf(void) +{ + struct data__file *d; + int i; + + fprintf(stdout, "# Data files:\n"); + + data__for_each_file(i, d) + fprintf(stdout, "# [%d] %s %s\n", + d->idx, d->file, + !d->idx ? "(Baseline)" : ""); + + fprintf(stdout, "#\n"); +} + static void data_process(void) { struct perf_evlist *evlist_old = data__files[0].session->evlist; @@ -500,6 +515,9 @@ static void data_process(void) first = false; + if (verbose) + data__fprintf(); + hists__process(&evsel_old->hists, &evsel_new->hists); } } From 345dc0b45ecc37a239723f2b6392cab04d8b0eff Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 3 Feb 2013 20:08:34 +0100 Subject: [PATCH 0212/6183] perf diff: Move diff related columns into diff command Moving diff related columns into diff command, because they are not used by any other command. Also moving the column entry functions under generic one with baseline as an exception. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-v58qfl75xkqojz54h1v5fy6p@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 306 ++++++++++++++++++++++++++++++++++++-- tools/perf/ui/hist.c | 209 +------------------------- tools/perf/util/hist.h | 7 +- 3 files changed, 292 insertions(+), 230 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9574ba18bc7b..8734f1cee6dc 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -18,6 +18,27 @@ #include "util/util.h" #include +#include + +/* Diff command specific HPP columns. */ +enum { + PERF_HPP_DIFF__BASELINE, + PERF_HPP_DIFF__PERIOD, + PERF_HPP_DIFF__PERIOD_BASELINE, + PERF_HPP_DIFF__DELTA, + PERF_HPP_DIFF__RATIO, + PERF_HPP_DIFF__WEIGHTED_DIFF, + PERF_HPP_DIFF__FORMULA, + + PERF_HPP_DIFF__MAX_INDEX +}; + +struct diff_hpp_fmt { + struct perf_hpp_fmt fmt; + int idx; + char *header; + int header_width; +}; struct data__file { struct perf_session *session; @@ -60,6 +81,47 @@ const char *compute_names[COMPUTE_MAX] = { static int compute; +static int compute_2_hpp[COMPUTE_MAX] = { + [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA, + [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO, + [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF, +}; + +#define MAX_COL_WIDTH 70 + +static struct header_column { + const char *name; + int width; +} columns[PERF_HPP_DIFF__MAX_INDEX] = { + [PERF_HPP_DIFF__BASELINE] = { + .name = "Baseline", + }, + [PERF_HPP_DIFF__PERIOD] = { + .name = "Period", + .width = 14, + }, + [PERF_HPP_DIFF__PERIOD_BASELINE] = { + .name = "Base period", + .width = 14, + }, + [PERF_HPP_DIFF__DELTA] = { + .name = "Delta", + .width = 7, + }, + [PERF_HPP_DIFF__RATIO] = { + .name = "Ratio", + .width = 14, + }, + [PERF_HPP_DIFF__WEIGHTED_DIFF] = { + .name = "Weighted diff", + .width = 14, + }, + [PERF_HPP_DIFF__FORMULA] = { + .name = "Formula", + .width = MAX_COL_WIDTH, + } +}; + static int setup_compute_opt_wdiff(char *opt) { char *w1_str = opt; @@ -596,34 +658,246 @@ static const struct option options[] = { OPT_END() }; -static void ui_init(void) +static double baseline_percent(struct hist_entry *he) { - /* - * Display baseline/delta/ratio - * formula/periods columns. - */ - perf_hpp__column_enable(PERF_HPP__BASELINE); + struct hists *hists = he->hists; + return 100.0 * he->stat.period / hists->stats.total_period; +} - switch (compute) { - case COMPUTE_DELTA: - perf_hpp__column_enable(PERF_HPP__DELTA); +static int hpp__color_baseline(struct perf_hpp_fmt *fmt, + struct perf_hpp *hpp, struct hist_entry *he) +{ + struct diff_hpp_fmt *dfmt = + container_of(fmt, struct diff_hpp_fmt, fmt); + double percent = baseline_percent(he); + char pfmt[20] = " "; + + if (!he->dummy) { + scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1); + return percent_color_snprintf(hpp->buf, hpp->size, + pfmt, percent); + } else + return scnprintf(hpp->buf, hpp->size, "%*s", + dfmt->header_width, pfmt); +} + +static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size) +{ + double percent = baseline_percent(he); + const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; + int ret = 0; + + if (!he->dummy) + ret = scnprintf(buf, size, fmt, percent); + + return ret; +} + +static void +hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) +{ + switch (idx) { + case PERF_HPP_DIFF__PERIOD_BASELINE: + scnprintf(buf, size, "%" PRIu64, he->stat.period); break; - case COMPUTE_RATIO: - perf_hpp__column_enable(PERF_HPP__RATIO); + + default: break; - case COMPUTE_WEIGHTED_DIFF: - perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); + } +} + +static void +hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, + int idx, char *buf, size_t size) +{ + double diff; + double ratio; + s64 wdiff; + + switch (idx) { + case PERF_HPP_DIFF__DELTA: + if (pair->diff.computed) + diff = pair->diff.period_ratio_delta; + else + diff = perf_diff__compute_delta(he, pair); + + if (fabs(diff) >= 0.01) + scnprintf(buf, size, "%+4.2F%%", diff); break; + + case PERF_HPP_DIFF__RATIO: + /* No point for ratio number if we are dummy.. */ + if (he->dummy) + break; + + if (pair->diff.computed) + ratio = pair->diff.period_ratio; + else + ratio = perf_diff__compute_ratio(he, pair); + + if (ratio > 0.0) + scnprintf(buf, size, "%14.6F", ratio); + break; + + case PERF_HPP_DIFF__WEIGHTED_DIFF: + /* No point for wdiff number if we are dummy.. */ + if (he->dummy) + break; + + if (pair->diff.computed) + wdiff = pair->diff.wdiff; + else + wdiff = perf_diff__compute_wdiff(he, pair); + + if (wdiff != 0) + scnprintf(buf, size, "%14ld", wdiff); + break; + + case PERF_HPP_DIFF__FORMULA: + perf_diff__formula(he, pair, buf, size); + break; + + case PERF_HPP_DIFF__PERIOD: + scnprintf(buf, size, "%" PRIu64, pair->stat.period); + break; + default: BUG_ON(1); }; +} + +static void +__hpp__entry_global(struct hist_entry *he, int idx, char *buf, size_t size) +{ + struct hist_entry *pair = hist_entry__next_pair(he); + + /* baseline is special */ + if (idx == PERF_HPP_DIFF__BASELINE) + hpp__entry_baseline(he, buf, size); + else { + if (pair) + hpp__entry_pair(he, pair, idx, buf, size); + else + hpp__entry_unpair(he, idx, buf, size); + } +} + +static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, + struct hist_entry *he) +{ + struct diff_hpp_fmt *dfmt = + container_of(_fmt, struct diff_hpp_fmt, fmt); + char buf[MAX_COL_WIDTH] = " "; + + __hpp__entry_global(he, dfmt->idx, buf, MAX_COL_WIDTH); + + if (symbol_conf.field_sep) + return scnprintf(hpp->buf, hpp->size, "%s", buf); + else + return scnprintf(hpp->buf, hpp->size, "%*s", + dfmt->header_width, buf); +} + +static int hpp__header(struct perf_hpp_fmt *fmt, + struct perf_hpp *hpp) +{ + struct diff_hpp_fmt *dfmt = + container_of(fmt, struct diff_hpp_fmt, fmt); + + BUG_ON(!dfmt->header); + return scnprintf(hpp->buf, hpp->size, dfmt->header); +} + +static int hpp__width(struct perf_hpp_fmt *fmt, + struct perf_hpp *hpp __maybe_unused) +{ + struct diff_hpp_fmt *dfmt = + container_of(fmt, struct diff_hpp_fmt, fmt); + + BUG_ON(dfmt->header_width <= 0); + return dfmt->header_width; +} + +#define hpp__color_global hpp__entry_global + +#define FMT(_i, _entry, _color) \ + [_i] = { \ + .fmt = { \ + .header = hpp__header, \ + .width = hpp__width, \ + .entry = hpp__entry_ ## _entry, \ + .color = hpp__color_ ## _color, \ + }, \ + .idx = _i, \ + } + +#define FMT_GLOBAL(_i) FMT(_i, global, global) +#define FMT_BASELINE(_i) FMT(_i, global, baseline) + +static struct diff_hpp_fmt diff_fmt[] = { + FMT_BASELINE(PERF_HPP_DIFF__BASELINE), + FMT_GLOBAL(PERF_HPP_DIFF__PERIOD), + FMT_GLOBAL(PERF_HPP_DIFF__PERIOD_BASELINE), + FMT_GLOBAL(PERF_HPP_DIFF__DELTA), + FMT_GLOBAL(PERF_HPP_DIFF__RATIO), + FMT_GLOBAL(PERF_HPP_DIFF__WEIGHTED_DIFF), + FMT_GLOBAL(PERF_HPP_DIFF__FORMULA), +}; + +static void init_header(struct diff_hpp_fmt *dfmt) +{ +#define MAX_HEADER_NAME 100 + char buf_indent[MAX_HEADER_NAME]; + char buf[MAX_HEADER_NAME]; + const char *header = NULL; + int width = 0; + + BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX); + header = columns[dfmt->idx].name; + width = columns[dfmt->idx].width; + + /* Only our defined HPP fmts should appear here. */ + BUG_ON(!header); + +#define NAME (data__files_cnt > 2 ? buf : header) + dfmt->header_width = width; + width = (int) strlen(NAME); + if (dfmt->header_width < width) + dfmt->header_width = width; + + scnprintf(buf_indent, MAX_HEADER_NAME, "%*s", + dfmt->header_width, NAME); + + dfmt->header = strdup(buf_indent); +#undef MAX_HEADER_NAME +#undef NAME +} + +static void column_enable(unsigned col) +{ + struct diff_hpp_fmt *dfmt; + + BUG_ON(col >= PERF_HPP_DIFF__MAX_INDEX); + dfmt = &diff_fmt[col]; + init_header(dfmt); + perf_hpp__column_register(&dfmt->fmt); +} + +static void ui_init(void) +{ + /* + * Display baseline/delta/ratio/ + * formula/periods columns. + */ + column_enable(PERF_HPP_DIFF__BASELINE); + column_enable(compute_2_hpp[compute]); if (show_formula) - perf_hpp__column_enable(PERF_HPP__FORMULA); + column_enable(PERF_HPP_DIFF__FORMULA); if (show_period) { - perf_hpp__column_enable(PERF_HPP__PERIOD); - perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); + column_enable(PERF_HPP_DIFF__PERIOD); + column_enable(PERF_HPP_DIFF__PERIOD_BASELINE); } } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index a359b75ce800..dc900d7a190e 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -163,207 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) HPP_RAW_FNS(period, "Period", period, 12, 12) - -static int hpp__header_baseline(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp) -{ - return scnprintf(hpp->buf, hpp->size, "Baseline"); -} - -static int hpp__width_baseline(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp __maybe_unused) -{ - return 8; -} - -static double baseline_percent(struct hist_entry *he) -{ - struct hists *hists = he->hists; - return 100.0 * he->stat.period / hists->stats.total_period; -} - -static int hpp__color_baseline(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - double percent = baseline_percent(he); - - if (!he->dummy) - return percent_color_snprintf(hpp->buf, hpp->size, - " %6.2f%%", percent); - else - return scnprintf(hpp->buf, hpp->size, " "); -} - -static int hpp__entry_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - double percent = baseline_percent(he); - const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; - - if (!he->dummy) - return scnprintf(hpp->buf, hpp->size, fmt, percent); - else - return scnprintf(hpp->buf, hpp->size, " "); -} - -static int hpp__header_period_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp) -{ - const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; - - return scnprintf(hpp->buf, hpp->size, fmt, "Period Base"); -} - -static int hpp__width_period_baseline(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp __maybe_unused) -{ - return 12; -} - -static int hpp__entry_period_baseline(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - struct hist_entry *pair = hist_entry__next_pair(he); - u64 period = pair ? pair->stat.period : 0; - const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; - - return scnprintf(hpp->buf, hpp->size, fmt, period); -} - -static int hpp__header_delta(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp) -{ - const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; - - return scnprintf(hpp->buf, hpp->size, fmt, "Delta"); -} - -static int hpp__width_delta(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp __maybe_unused) -{ - return 7; -} - -static int hpp__entry_delta(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - struct hist_entry *pair = hist_entry__next_pair(he); - const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; - char buf[32] = " "; - double diff = 0.0; - - if (pair) { - if (he->diff.computed) - diff = he->diff.period_ratio_delta; - else - diff = perf_diff__compute_delta(he, pair); - } - - if (fabs(diff) >= 0.01) - scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); - - return scnprintf(hpp->buf, hpp->size, fmt, buf); -} - -static int hpp__header_ratio(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp) -{ - const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; - - return scnprintf(hpp->buf, hpp->size, fmt, "Ratio"); -} - -static int hpp__width_ratio(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp __maybe_unused) -{ - return 14; -} - -static int hpp__entry_ratio(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - struct hist_entry *pair = hist_entry__next_pair(he); - const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; - char buf[32] = " "; - double ratio = 0.0; - - /* No point for ratio number if we are dummy.. */ - if (!he->dummy && pair) { - if (he->diff.computed) - ratio = he->diff.period_ratio; - else - ratio = perf_diff__compute_ratio(he, pair); - } - - if (ratio > 0.0) - scnprintf(buf, sizeof(buf), "%+14.6F", ratio); - - return scnprintf(hpp->buf, hpp->size, fmt, buf); -} - -static int hpp__header_wdiff(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp) -{ - const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; - - return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff"); -} - -static int hpp__width_wdiff(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp __maybe_unused) -{ - return 14; -} - -static int hpp__entry_wdiff(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - struct hist_entry *pair = hist_entry__next_pair(he); - const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; - char buf[32] = " "; - s64 wdiff = 0; - - /* No point for wdiff number if we are dummy.. */ - if (!he->dummy && pair) { - if (he->diff.computed) - wdiff = he->diff.wdiff; - else - wdiff = perf_diff__compute_wdiff(he, pair); - } - - if (wdiff != 0) - scnprintf(buf, sizeof(buf), "%14ld", wdiff); - - return scnprintf(hpp->buf, hpp->size, fmt, buf); -} - -static int hpp__header_formula(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp) -{ - const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; - - return scnprintf(hpp->buf, hpp->size, fmt, "Formula"); -} - -static int hpp__width_formula(struct perf_hpp_fmt *fmt __maybe_unused, - struct perf_hpp *hpp __maybe_unused) -{ - return 70; -} - -static int hpp__entry_formula(struct perf_hpp_fmt *_fmt __maybe_unused, - struct perf_hpp *hpp, struct hist_entry *he) -{ - struct hist_entry *pair = hist_entry__next_pair(he); - const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; - char buf[96] = " "; - - if (pair) - perf_diff__formula(he, pair, buf, sizeof(buf)); - - return scnprintf(hpp->buf, hpp->size, fmt, buf); -} - #define HPP__COLOR_PRINT_FNS(_name) \ { \ .header = hpp__header_ ## _name, \ @@ -380,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp_fmt *_fmt __maybe_unused, } struct perf_hpp_fmt perf_hpp__format[] = { - HPP__COLOR_PRINT_FNS(baseline), HPP__COLOR_PRINT_FNS(overhead), HPP__COLOR_PRINT_FNS(overhead_sys), HPP__COLOR_PRINT_FNS(overhead_us), HPP__COLOR_PRINT_FNS(overhead_guest_sys), HPP__COLOR_PRINT_FNS(overhead_guest_us), HPP__PRINT_FNS(samples), - HPP__PRINT_FNS(period), - HPP__PRINT_FNS(period_baseline), - HPP__PRINT_FNS(delta), - HPP__PRINT_FNS(ratio), - HPP__PRINT_FNS(wdiff), - HPP__PRINT_FNS(formula) + HPP__PRINT_FNS(period) }; LIST_HEAD(perf_hpp__list); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 0c62116d4d3a..79681f62ef2b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -159,7 +159,7 @@ extern struct list_head perf_hpp__list; extern struct perf_hpp_fmt perf_hpp__format[]; enum { - PERF_HPP__BASELINE, + /* Matches perf_hpp__format array. */ PERF_HPP__OVERHEAD, PERF_HPP__OVERHEAD_SYS, PERF_HPP__OVERHEAD_US, @@ -167,11 +167,6 @@ enum { PERF_HPP__OVERHEAD_GUEST_US, PERF_HPP__SAMPLES, PERF_HPP__PERIOD, - PERF_HPP__PERIOD_BASELINE, - PERF_HPP__DELTA, - PERF_HPP__RATIO, - PERF_HPP__WEIGHTED_DIFF, - PERF_HPP__FORMULA, PERF_HPP__MAX_INDEX }; From c818b49820aea96d6a1b43815bae0ee38b09ca0d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 1 Dec 2012 21:57:04 +0100 Subject: [PATCH 0213/6183] perf diff: Move columns into struct data__file Another step towards multiple data files support. Having columns definition within struct data__file force each data file having its own columns. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Link: http://lkml.kernel.org/n/tip-lnfqj7k7fqw8bz07pupi5464@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 97 ++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 8734f1cee6dc..7787ee24a18a 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -44,6 +44,7 @@ struct data__file { struct perf_session *session; const char *file; int idx; + struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX]; }; static struct data__file *data__files; @@ -584,6 +585,17 @@ static void data_process(void) } } +static void data__free(struct data__file *d) +{ + int col; + + for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { + struct diff_hpp_fmt *fmt = &d->fmt[col]; + + free(fmt->header); + } +} + static int __cmd_diff(void) { struct data__file *d; @@ -613,6 +625,8 @@ static int __cmd_diff(void) data__for_each_file(i, d) { if (d->session) perf_session__delete(d->session); + + data__free(d); } free(data__files); @@ -818,32 +832,6 @@ static int hpp__width(struct perf_hpp_fmt *fmt, return dfmt->header_width; } -#define hpp__color_global hpp__entry_global - -#define FMT(_i, _entry, _color) \ - [_i] = { \ - .fmt = { \ - .header = hpp__header, \ - .width = hpp__width, \ - .entry = hpp__entry_ ## _entry, \ - .color = hpp__color_ ## _color, \ - }, \ - .idx = _i, \ - } - -#define FMT_GLOBAL(_i) FMT(_i, global, global) -#define FMT_BASELINE(_i) FMT(_i, global, baseline) - -static struct diff_hpp_fmt diff_fmt[] = { - FMT_BASELINE(PERF_HPP_DIFF__BASELINE), - FMT_GLOBAL(PERF_HPP_DIFF__PERIOD), - FMT_GLOBAL(PERF_HPP_DIFF__PERIOD_BASELINE), - FMT_GLOBAL(PERF_HPP_DIFF__DELTA), - FMT_GLOBAL(PERF_HPP_DIFF__RATIO), - FMT_GLOBAL(PERF_HPP_DIFF__WEIGHTED_DIFF), - FMT_GLOBAL(PERF_HPP_DIFF__FORMULA), -}; - static void init_header(struct diff_hpp_fmt *dfmt) { #define MAX_HEADER_NAME 100 @@ -873,31 +861,56 @@ static void init_header(struct diff_hpp_fmt *dfmt) #undef NAME } -static void column_enable(unsigned col) +static void data__hpp_register(struct data__file *d, int idx) { - struct diff_hpp_fmt *dfmt; + struct diff_hpp_fmt *dfmt = &d->fmt[idx]; + struct perf_hpp_fmt *fmt = &dfmt->fmt; + + dfmt->idx = idx; + + fmt->header = hpp__header; + fmt->width = hpp__width; + fmt->entry = hpp__entry_global; + + /* TODO more colors */ + if (idx == PERF_HPP_DIFF__BASELINE) + fmt->color = hpp__color_baseline; - BUG_ON(col >= PERF_HPP_DIFF__MAX_INDEX); - dfmt = &diff_fmt[col]; init_header(dfmt); - perf_hpp__column_register(&dfmt->fmt); + perf_hpp__column_register(fmt); } static void ui_init(void) { - /* - * Display baseline/delta/ratio/ - * formula/periods columns. - */ - column_enable(PERF_HPP_DIFF__BASELINE); - column_enable(compute_2_hpp[compute]); + struct data__file *d; + int i; - if (show_formula) - column_enable(PERF_HPP_DIFF__FORMULA); + data__for_each_file(i, d) { - if (show_period) { - column_enable(PERF_HPP_DIFF__PERIOD); - column_enable(PERF_HPP_DIFF__PERIOD_BASELINE); + /* + * Baseline or compute realted columns: + * + * PERF_HPP_DIFF__BASELINE + * PERF_HPP_DIFF__DELTA + * PERF_HPP_DIFF__RATIO + * PERF_HPP_DIFF__WEIGHTED_DIFF + */ + data__hpp_register(d, i ? compute_2_hpp[compute] : + PERF_HPP_DIFF__BASELINE); + + /* + * And the rest: + * + * PERF_HPP_DIFF__FORMULA + * PERF_HPP_DIFF__PERIOD + * PERF_HPP_DIFF__PERIOD_BASELINE + */ + if (show_formula && i) + data__hpp_register(d, PERF_HPP_DIFF__FORMULA); + + if (show_period) + data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD : + PERF_HPP_DIFF__PERIOD_BASELINE); } } From 22aeb7f597650284591ad0f61b069ded3ecf91db Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 1 Dec 2012 22:00:00 +0100 Subject: [PATCH 0214/6183] perf diff: Change diff command to work over multiple data files Adding diff command the flexibility to specify multiple data files on input. If not input file is given the standard behaviour stands and diff inspects 'perf.data' and 'perf.data.old' files. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-8j3xer54ltvs76t0fh01gcvu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 101 +++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 7787ee24a18a..cc7bf4faacd4 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -44,6 +44,7 @@ struct data__file { struct perf_session *session; const char *file; int idx; + struct hists *hists; struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX]; }; @@ -56,6 +57,7 @@ static int data__files_cnt; i++, d = &data__files[i]) #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0) +#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1) static char diff__default_sort_order[] = "dso,symbol"; static bool force; @@ -525,23 +527,19 @@ static void hists__compute_resort(struct hists *hists) } } -static void hists__process(struct hists *base, struct hists *new) +static void hists__process(struct hists *hists) { - hists__match(base, new); - if (show_baseline_only) - hists__baseline_only(base); - else - hists__link(base, new); + hists__baseline_only(hists); if (sort_compute) { - hists__precompute(base); - hists__compute_resort(base); + hists__precompute(hists); + hists__compute_resort(hists); } else { - hists__output_resort(base); + hists__output_resort(hists); } - hists__fprintf(base, true, 0, 0, 0, stdout); + hists__fprintf(hists, true, 0, 0, 0, stdout); } static void data__fprintf(void) @@ -561,27 +559,40 @@ static void data__fprintf(void) static void data_process(void) { - struct perf_evlist *evlist_old = data__files[0].session->evlist; - struct perf_evlist *evlist_new = data__files[1].session->evlist; - struct perf_evsel *evsel_old; + struct perf_evlist *evlist_base = data__files[0].session->evlist; + struct perf_evsel *evsel_base; bool first = true; - list_for_each_entry(evsel_old, &evlist_old->entries, node) { - struct perf_evsel *evsel_new; + list_for_each_entry(evsel_base, &evlist_base->entries, node) { + struct data__file *d; + int i; - evsel_new = evsel_match(evsel_old, evlist_new); - if (!evsel_new) - continue; + data__for_each_file_new(i, d) { + struct perf_evlist *evlist = d->session->evlist; + struct perf_evsel *evsel; + + evsel = evsel_match(evsel_base, evlist); + if (!evsel) + continue; + + d->hists = &evsel->hists; + + hists__match(&evsel_base->hists, &evsel->hists); + + if (!show_baseline_only) + hists__link(&evsel_base->hists, + &evsel->hists); + } fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", - perf_evsel__name(evsel_old)); + perf_evsel__name(evsel_base)); first = false; - if (verbose) + if (verbose || data__files_cnt > 2) data__fprintf(); - hists__process(&evsel_old->hists, &evsel_new->hists); + hists__process(&evsel_base->hists); } } @@ -780,10 +791,29 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, }; } -static void -__hpp__entry_global(struct hist_entry *he, int idx, char *buf, size_t size) +static struct hist_entry *get_pair(struct hist_entry *he, + struct diff_hpp_fmt *dfmt) { - struct hist_entry *pair = hist_entry__next_pair(he); + void *ptr = dfmt - dfmt->idx; + struct data__file *d = container_of(ptr, struct data__file, fmt); + + if (hist_entry__has_pairs(he)) { + struct hist_entry *pair; + + list_for_each_entry(pair, &he->pairs.head, pairs.node) + if (pair->hists == d->hists) + return pair; + } + + return NULL; +} + +static void +__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt, + char *buf, size_t size) +{ + struct hist_entry *pair = get_pair(he, dfmt); + int idx = dfmt->idx; /* baseline is special */ if (idx == PERF_HPP_DIFF__BASELINE) @@ -803,7 +833,7 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, container_of(_fmt, struct diff_hpp_fmt, fmt); char buf[MAX_COL_WIDTH] = " "; - __hpp__entry_global(he, dfmt->idx, buf, MAX_COL_WIDTH); + __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH); if (symbol_conf.field_sep) return scnprintf(hpp->buf, hpp->size, "%s", buf); @@ -832,7 +862,7 @@ static int hpp__width(struct perf_hpp_fmt *fmt, return dfmt->header_width; } -static void init_header(struct diff_hpp_fmt *dfmt) +static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt) { #define MAX_HEADER_NAME 100 char buf_indent[MAX_HEADER_NAME]; @@ -847,6 +877,9 @@ static void init_header(struct diff_hpp_fmt *dfmt) /* Only our defined HPP fmts should appear here. */ BUG_ON(!header); + if (data__files_cnt > 2) + scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx); + #define NAME (data__files_cnt > 2 ? buf : header) dfmt->header_width = width; width = (int) strlen(NAME); @@ -876,7 +909,7 @@ static void data__hpp_register(struct data__file *d, int idx) if (idx == PERF_HPP_DIFF__BASELINE) fmt->color = hpp__color_baseline; - init_header(dfmt); + init_header(d, dfmt); perf_hpp__column_register(fmt); } @@ -921,18 +954,18 @@ static int data_init(int argc, const char **argv) "perf.data.old", "perf.data", }; + bool use_default = true; int i; data__files_cnt = 2; if (argc) { - if (argc > 2) - usage_with_options(diff_usage, options); - if (argc == 2) { - defaults[0] = argv[0]; - defaults[1] = argv[1]; - } else + if (argc == 1) defaults[1] = argv[0]; + else { + data__files_cnt = argc; + use_default = false; + } } else if (symbol_conf.default_guest_vmlinux_name || symbol_conf.default_guest_kallsyms) { defaults[0] = "perf.data.host"; @@ -944,7 +977,7 @@ static int data_init(int argc, const char **argv) return -ENOMEM; data__for_each_file(i, d) { - d->file = defaults[i]; + d->file = use_default ? defaults[i] : argv[i]; d->idx = i; } From 3a3beae81dae4960cac99fb6deeaca371f0790eb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 24 Oct 2012 14:56:51 +0200 Subject: [PATCH 0215/6183] perf diff: Update perf diff documentation for multiple data comparison Updating perf diff documentation to include multiple perf data files comparison. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-tr6su3wfm20k2m5npjggyvtw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 73 ++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 5b3123d5721f..2d134f3f1c9d 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -3,17 +3,17 @@ perf-diff(1) NAME ---- -perf-diff - Read two perf.data files and display the differential profile +perf-diff - Read perf.data files and display the differential profile SYNOPSIS -------- [verse] -'perf diff' [oldfile] [newfile] +'perf diff' [baseline file] [data file1] [[data file2] ... ] DESCRIPTION ----------- -This command displays the performance difference amongst two perf.data files -captured via perf record. +This command displays the performance difference amongst two or more perf.data +files captured via perf record. If no parameters are passed it will assume perf.data.old and perf.data. @@ -87,6 +87,59 @@ OPTIONS --formula:: Show formula for given computation. +COMPARISON +---------- +The comparison is governed by the baseline file. The baseline perf.data +file is iterated for samples. All other perf.data files specified on +the command line are searched for the baseline sample pair. If the pair +is found, specified computation is made and result is displayed. + +All samples from non-baseline perf.data files, that do not match any +baseline entry, are displayed with empty space within baseline column +and possible computation results (delta) in their related column. + +Example files samples: +- file A with samples f1, f2, f3, f4, f6 +- file B with samples f2, f4, f5 +- file C with samples f1, f2, f5 + +Example output: + x - computation takes place for pair + b - baseline sample percentage + +- perf diff A B C + + baseline/A compute/B compute/C samples + --------------------------------------- + b x f1 + b x x f2 + b f3 + b x f4 + b f6 + x x f5 + +- perf diff B A C + + baseline/B compute/A compute/C samples + --------------------------------------- + b x x f2 + b x f4 + b x f5 + x x f1 + x f3 + x f6 + +- perf diff C B A + + baseline/C compute/B compute/A samples + --------------------------------------- + b x f1 + b x x f2 + b x f5 + x f3 + x x f4 + x f6 + COMPARISON METHODS ------------------ delta @@ -96,7 +149,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as: d = A->period_percent - B->period_percent with: - - A/B being matching hist entry from first/second file specified + - A/B being matching hist entry from data/baseline file specified (or perf.data/perf.data.old) respectively. - period_percent being the % of the hist entry period value within @@ -109,24 +162,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as: r = A->period / B->period with: - - A/B being matching hist entry from first/second file specified + - A/B being matching hist entry from data/baseline file specified (or perf.data/perf.data.old) respectively. - period being the hist entry period value -wdiff -~~~~~ +wdiff:WEIGHT-B,WEIGHT-A +~~~~~~~~~~~~~~~~~~~~~~~ If specified the 'Weighted diff' column is displayed with value 'd' computed as: d = B->period * WEIGHT-A - A->period * WEIGHT-B - - A/B being matching hist entry from first/second file specified + - A/B being matching hist entry from data/baseline file specified (or perf.data/perf.data.old) respectively. - period being the hist entry period value - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option behind ':' separator like '-c wdiff:1,2'. + - WIEGHT-A being the weight of the data file + - WIEGHT-B being the weight of the baseline data file SEE ALSO -------- From ef358e6dcaba76d1c00dba5fc6cd4cde1d1a2f13 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 21 Oct 2012 23:31:51 +0200 Subject: [PATCH 0216/6183] perf diff: Making compute functions static All compute functions are now local to the diff command, making them static. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-mpmm8l71mnlp7139voba3aak@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 30 +++++++++++++++--------------- tools/perf/util/hist.h | 7 ------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index cc7bf4faacd4..f2fbf69ad984 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -224,23 +224,23 @@ static int setup_compute(const struct option *opt, const char *str, return -EINVAL; } -double perf_diff__period_percent(struct hist_entry *he, u64 period) +static double period_percent(struct hist_entry *he, u64 period) { u64 total = he->hists->stats.total_period; return (period * 100.0) / total; } -double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) +static double compute_delta(struct hist_entry *he, struct hist_entry *pair) { - double old_percent = perf_diff__period_percent(he, he->stat.period); - double new_percent = perf_diff__period_percent(pair, pair->stat.period); + double old_percent = period_percent(he, he->stat.period); + double new_percent = period_percent(pair, pair->stat.period); pair->diff.period_ratio_delta = new_percent - old_percent; pair->diff.computed = true; return pair->diff.period_ratio_delta; } -double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) +static double compute_ratio(struct hist_entry *he, struct hist_entry *pair) { double old_period = he->stat.period ?: 1; double new_period = pair->stat.period; @@ -250,7 +250,7 @@ double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) return pair->diff.period_ratio; } -s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) +static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair) { u64 old_period = he->stat.period; u64 new_period = pair->stat.period; @@ -292,8 +292,8 @@ static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); } -int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, - char *buf, size_t size) +static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, + char *buf, size_t size) { switch (compute) { case COMPUTE_DELTA: @@ -421,13 +421,13 @@ static void hists__precompute(struct hists *hists) switch (compute) { case COMPUTE_DELTA: - perf_diff__compute_delta(he, pair); + compute_delta(he, pair); break; case COMPUTE_RATIO: - perf_diff__compute_ratio(he, pair); + compute_ratio(he, pair); break; case COMPUTE_WEIGHTED_DIFF: - perf_diff__compute_wdiff(he, pair); + compute_wdiff(he, pair); break; default: BUG_ON(1); @@ -744,7 +744,7 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, if (pair->diff.computed) diff = pair->diff.period_ratio_delta; else - diff = perf_diff__compute_delta(he, pair); + diff = compute_delta(he, pair); if (fabs(diff) >= 0.01) scnprintf(buf, size, "%+4.2F%%", diff); @@ -758,7 +758,7 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, if (pair->diff.computed) ratio = pair->diff.period_ratio; else - ratio = perf_diff__compute_ratio(he, pair); + ratio = compute_ratio(he, pair); if (ratio > 0.0) scnprintf(buf, size, "%14.6F", ratio); @@ -772,14 +772,14 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, if (pair->diff.computed) wdiff = pair->diff.wdiff; else - wdiff = perf_diff__compute_wdiff(he, pair); + wdiff = compute_wdiff(he, pair); if (wdiff != 0) scnprintf(buf, size, "%14ld", wdiff); break; case PERF_HPP_DIFF__FORMULA: - perf_diff__formula(he, pair, buf, size); + formula_fprintf(he, pair, buf, size); break; case PERF_HPP_DIFF__PERIOD: diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 79681f62ef2b..bfcbb11c2648 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -242,11 +242,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, #endif unsigned int hists__sort_list_width(struct hists *self); - -double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair); -double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair); -s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair); -int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, - char *buf, size_t size); -double perf_diff__period_percent(struct hist_entry *he, u64 period); #endif /* __PERF_HIST_H */ From 5f3f8d3b1207cba3664d57a33de43f5ee11c8a06 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 25 Nov 2012 23:10:20 +0100 Subject: [PATCH 0217/6183] perf diff: Add generic order option for compute sorting Adding option 'o' to allow sorting based on the input file number. By default (without -o option) the output is sorted on baseline. Also removing '+' sorting support from -c option, because it's not needed anymore. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-l7dvhgt0azm7yiqg3fbn4dxw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 6 +- tools/perf/builtin-diff.c | 95 ++++++++++++++++++-------- 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 2d134f3f1c9d..fdfceee0ffd0 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -75,8 +75,6 @@ OPTIONS -c:: --compute:: Differential computation selection - delta,ratio,wdiff (default is delta). - If '+' is specified as a first character, the output is sorted based - on the computation results. See COMPARISON METHODS section for more info. -p:: @@ -87,6 +85,10 @@ OPTIONS --formula:: Show formula for given computation. +-o:: +--order:: + Specify compute sorting column number. + COMPARISON ---------- The comparison is governed by the baseline file. The baseline perf.data diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index f2fbf69ad984..93de3ac177c5 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -64,7 +64,7 @@ static bool force; static bool show_period; static bool show_formula; static bool show_baseline_only; -static bool sort_compute; +static unsigned int sort_compute; static s64 compute_wdiff_w1; static s64 compute_wdiff_w2; @@ -188,13 +188,6 @@ static int setup_compute(const struct option *opt, const char *str, return 0; } - if (*str == '+') { - sort_compute = true; - cstr = (char *) ++str; - if (!*str) - return 0; - } - option = strchr(str, ':'); if (option) { unsigned len = option++ - str; @@ -378,6 +371,29 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) } } +static struct hist_entry* +get_pair_data(struct hist_entry *he, struct data__file *d) +{ + if (hist_entry__has_pairs(he)) { + struct hist_entry *pair; + + list_for_each_entry(pair, &he->pairs.head, pairs.node) + if (pair->hists == d->hists) + return pair; + } + + return NULL; +} + +static struct hist_entry* +get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt) +{ + void *ptr = dfmt - dfmt->idx; + struct data__file *d = container_of(ptr, struct data__file, fmt); + + return get_pair_data(he, d); +} + static void hists__baseline_only(struct hists *hists) { struct rb_root *root; @@ -412,10 +428,12 @@ static void hists__precompute(struct hists *hists) next = rb_first(root); while (next != NULL) { - struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); - struct hist_entry *pair = hist_entry__next_pair(he); + struct hist_entry *he, *pair; + he = rb_entry(next, struct hist_entry, rb_node_in); next = rb_next(&he->rb_node_in); + + pair = get_pair_data(he, &data__files[sort_compute]); if (!pair) continue; @@ -446,7 +464,7 @@ static int64_t cmp_doubles(double l, double r) } static int64_t -hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, +__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, int c) { switch (c) { @@ -478,6 +496,36 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, return 0; } +static int64_t +hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, + int c) +{ + bool pairs_left = hist_entry__has_pairs(left); + bool pairs_right = hist_entry__has_pairs(right); + struct hist_entry *p_right, *p_left; + + if (!pairs_left && !pairs_right) + return 0; + + if (!pairs_left || !pairs_right) + return pairs_left ? -1 : 1; + + p_left = get_pair_data(left, &data__files[sort_compute]); + p_right = get_pair_data(right, &data__files[sort_compute]); + + if (!p_left && !p_right) + return 0; + + if (!p_left || !p_right) + return p_left ? -1 : 1; + + /* + * We have 2 entries of same kind, let's + * make the data comparison. + */ + return __hist_entry__cmp_compute(p_left, p_right, c); +} + static void insert_hist_entry_by_compute(struct rb_root *root, struct hist_entry *he, int c) @@ -680,6 +728,7 @@ static const struct option options[] = { "columns '.' is reserved."), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), + OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_END() }; @@ -791,28 +840,11 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, }; } -static struct hist_entry *get_pair(struct hist_entry *he, - struct diff_hpp_fmt *dfmt) -{ - void *ptr = dfmt - dfmt->idx; - struct data__file *d = container_of(ptr, struct data__file, fmt); - - if (hist_entry__has_pairs(he)) { - struct hist_entry *pair; - - list_for_each_entry(pair, &he->pairs.head, pairs.node) - if (pair->hists == d->hists) - return pair; - } - - return NULL; -} - static void __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt, char *buf, size_t size) { - struct hist_entry *pair = get_pair(he, dfmt); + struct hist_entry *pair = get_pair_fmt(he, dfmt); int idx = dfmt->idx; /* baseline is special */ @@ -972,6 +1004,11 @@ static int data_init(int argc, const char **argv) defaults[1] = "perf.data.guest"; } + if (sort_compute >= (unsigned int) data__files_cnt) { + pr_err("Order option out of limit.\n"); + return -EINVAL; + } + data__files = zalloc(sizeof(*data__files) * data__files_cnt); if (!data__files) return -ENOMEM; From be0e6d105d31a5818608ae243411aef5c976147a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 4 Feb 2013 16:33:19 +0100 Subject: [PATCH 0218/6183] perf tools: Move hist_entry__period_snprintf into stdio code Moving hist_entry__period_snprintf function into stdio code and making it static, as it's no longer used anywhere else. Signed-off-by: Jiri Olsa Reviewed-by: Namhyung Kim Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-ah8ms343h8xygt20iqz91kz4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/hist.c | 40 ------------------------------------- tools/perf/ui/stdio/hist.c | 41 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 2 -- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index dc900d7a190e..0a193281eba8 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -236,46 +236,6 @@ void perf_hpp__column_enable(unsigned col) perf_hpp__column_register(&perf_hpp__format[col]); } -static inline void advance_hpp(struct perf_hpp *hpp, int inc) -{ - hpp->buf += inc; - hpp->size -= inc; -} - -int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, - bool color) -{ - const char *sep = symbol_conf.field_sep; - struct perf_hpp_fmt *fmt; - char *start = hpp->buf; - int ret; - bool first = true; - - if (symbol_conf.exclude_other && !he->parent) - return 0; - - perf_hpp__for_each_format(fmt) { - /* - * If there's no field_sep, we still need - * to display initial ' '. - */ - if (!sep || !first) { - ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); - advance_hpp(hpp, ret); - } else - first = false; - - if (color && fmt->color) - ret = fmt->color(fmt, hpp, he); - else - ret = fmt->entry(fmt, hpp, he); - - advance_hpp(hpp, ret); - } - - return hpp->buf - start; -} - int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, struct hists *hists) { diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index ee703720649d..5b4fb330f656 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -308,6 +308,47 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); } +static inline void advance_hpp(struct perf_hpp *hpp, int inc) +{ + hpp->buf += inc; + hpp->size -= inc; +} + +static int hist_entry__period_snprintf(struct perf_hpp *hpp, + struct hist_entry *he, + bool color) +{ + const char *sep = symbol_conf.field_sep; + struct perf_hpp_fmt *fmt; + char *start = hpp->buf; + int ret; + bool first = true; + + if (symbol_conf.exclude_other && !he->parent) + return 0; + + perf_hpp__for_each_format(fmt) { + /* + * If there's no field_sep, we still need + * to display initial ' '. + */ + if (!sep || !first) { + ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); + advance_hpp(hpp, ret); + } else + first = false; + + if (color && fmt->color) + ret = fmt->color(fmt, hpp, he); + else + ret = fmt->entry(fmt, hpp, he); + + advance_hpp(hpp, ret); + } + + return hpp->buf - start; +} + static int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, FILE *fp) { diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index bfcbb11c2648..1329b6b6ffe6 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -174,8 +174,6 @@ enum { void perf_hpp__init(void); void perf_hpp__column_register(struct perf_hpp_fmt *format); void perf_hpp__column_enable(unsigned col); -int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, - bool color); struct perf_evlist; From 8f89140ae41ccd9c63344e6823faa862aa7435e3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 16:24:10 -0700 Subject: [PATCH 0219/6183] cgroup: minor updates around cgroup_clear_directory() * Rename it to cgroup_clear_dir() and make it take the pointer to the target cgroup instead of the the dentry. This makes the function consistent with its counterpart - cgroup_populate_dir(). * Move cgroup_clear_directory() invocation from cgroup_d_remove_dir() to cgroup_remount() so that the function doesn't have to determine the cgroup pointer back from the dentry. cgroup_d_remove_dir() now only deals with vfs, which is slightly cleaner. This patch doesn't introduce any functional differences. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e5583d10a325..09bfa870e698 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -957,15 +957,14 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) } /** - * cgroup_clear_directory - selective removal of base and subsystem files - * @dir: directory containing the files + * cgroup_clear_dir - selective removal of base and subsystem files + * @cgrp: target cgroup * @base_files: true if the base files should be removed * @subsys_mask: mask of the subsystem ids whose files should be removed */ -static void cgroup_clear_directory(struct dentry *dir, bool base_files, - unsigned long subsys_mask) +static void cgroup_clear_dir(struct cgroup *cgrp, bool base_files, + unsigned long subsys_mask) { - struct cgroup *cgrp = __d_cgrp(dir); struct cgroup_subsys *ss; for_each_root_subsys(cgrp->root, ss) { @@ -987,9 +986,6 @@ static void cgroup_clear_directory(struct dentry *dir, bool base_files, static void cgroup_d_remove_dir(struct dentry *dentry) { struct dentry *parent; - struct cgroupfs_root *root = dentry->d_sb->s_fs_info; - - cgroup_clear_directory(dentry, true, root->subsys_mask); parent = dentry->d_parent; spin_lock(&parent->d_lock); @@ -1376,7 +1372,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) * this before rebind_subsystems, since rebind_subsystems may * change this hierarchy's subsys_list. */ - cgroup_clear_directory(cgrp->dentry, false, removed_mask); + cgroup_clear_dir(cgrp, false, removed_mask); ret = rebind_subsystems(root, added_mask, removed_mask); if (ret) { @@ -4541,9 +4537,10 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) raw_spin_unlock(&release_list_lock); /* - * Remove @cgrp directory. The removal puts the base ref but we - * aren't quite done with @cgrp yet, so hold onto it. + * Clear and remove @cgrp directory. The removal puts the base ref + * but we aren't quite done with @cgrp yet, so hold onto it. */ + cgroup_clear_dir(cgrp, true, cgrp->root->subsys_mask); dget(d); cgroup_d_remove_dir(d); From b1f28d3109349899e87377e89f9d8ab5bc95ec57 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 16:24:10 -0700 Subject: [PATCH 0220/6183] cgroup: fix error path of cgroup_addrm_files() cgroup_addrm_files() mishandled error return value from cgroup_add_file() and returns error iff the last file fails to create. As we're in the process of cleaning up file add/rm error handling and will reliably propagate file creation failures, there's no point in keeping adding files after a failure. Replace the broken error collection logic with immediate error return. While at it, add lockdep assertions and function comment. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 09bfa870e698..9b16d75bec63 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2780,11 +2780,26 @@ out: return error; } +/** + * cgroup_addrm_files - add or remove files to a cgroup directory + * @cgrp: the target cgroup + * @subsys: the subsystem of files to be added + * @cfts: array of cftypes to be added + * @is_add: whether to add or remove + * + * Depending on @is_add, add or remove files defined by @cfts on @cgrp. + * All @cfts should belong to @subsys. For removals, this function never + * fails. If addition fails, this function doesn't remove files already + * added. The caller is responsible for cleaning up. + */ static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, struct cftype cfts[], bool is_add) { struct cftype *cft; - int err, ret = 0; + int ret; + + lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex); + lockdep_assert_held(&cgroup_mutex); for (cft = cfts; cft->name[0] != '\0'; cft++) { /* does cft->flags tell us to skip this file on @cgrp? */ @@ -2796,16 +2811,17 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, continue; if (is_add) { - err = cgroup_add_file(cgrp, subsys, cft); - if (err) + ret = cgroup_add_file(cgrp, subsys, cft); + if (ret) { pr_warn("cgroup_addrm_files: failed to add %s, err=%d\n", - cft->name, err); - ret = err; + cft->name, ret); + return ret; + } } else { cgroup_rm_file(cgrp, cft); } } - return ret; + return 0; } static void cgroup_cfts_prepare(void) From 9ccece80ae19ed42439fc0ced76858f189cd41e8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 16:24:11 -0700 Subject: [PATCH 0221/6183] cgroup: fix cgroup_add_cftypes() error handling cgroup_add_cftypes() uses cgroup_cfts_commit() to actually create the files; however, both functions ignore actual file creation errors and just assume success. This can lead to, for example, blkio hierarchy with some of the cgroups with only subset of interface files populated after cfq-iosched is loaded under heavy memory pressure, which is nasty. This patch updates cgroup_cfts_commit() and cgroup_add_cftypes() to guarantee that all files are created on success and no file is created on failure. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9b16d75bec63..36c0ccc921f4 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2836,8 +2836,8 @@ static void cgroup_cfts_prepare(void) mutex_lock(&cgroup_mutex); } -static void cgroup_cfts_commit(struct cgroup_subsys *ss, - struct cftype *cfts, bool is_add) +static int cgroup_cfts_commit(struct cgroup_subsys *ss, + struct cftype *cfts, bool is_add) __releases(&cgroup_mutex) { LIST_HEAD(pending); @@ -2846,12 +2846,13 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss, struct dentry *prev = NULL; struct inode *inode; u64 update_before; + int ret = 0; /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */ if (!cfts || ss->root == &cgroup_dummy_root || !atomic_inc_not_zero(&sb->s_active)) { mutex_unlock(&cgroup_mutex); - return; + return 0; } /* @@ -2867,10 +2868,13 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss, inode = root->dentry->d_inode; mutex_lock(&inode->i_mutex); mutex_lock(&cgroup_mutex); - cgroup_addrm_files(root, ss, cfts, is_add); + ret = cgroup_addrm_files(root, ss, cfts, is_add); mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); + if (ret) + goto out_deact; + /* add/rm files for all cgroups created before */ rcu_read_lock(); cgroup_for_each_descendant_pre(cgrp, root) { @@ -2887,15 +2891,19 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss, mutex_lock(&inode->i_mutex); mutex_lock(&cgroup_mutex); if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) - cgroup_addrm_files(cgrp, ss, cfts, is_add); + ret = cgroup_addrm_files(cgrp, ss, cfts, is_add); mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); rcu_read_lock(); + if (ret) + break; } rcu_read_unlock(); dput(prev); +out_deact: deactivate_super(sb); + return ret; } /** @@ -2915,6 +2923,7 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss, int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) { struct cftype_set *set; + int ret; set = kzalloc(sizeof(*set), GFP_KERNEL); if (!set) @@ -2923,9 +2932,10 @@ int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) cgroup_cfts_prepare(); set->cfts = cfts; list_add_tail(&set->node, &ss->cftsets); - cgroup_cfts_commit(ss, cfts, true); - - return 0; + ret = cgroup_cfts_commit(ss, cfts, true); + if (ret) + cgroup_rm_cftypes(ss, cfts); + return ret; } EXPORT_SYMBOL_GPL(cgroup_add_cftypes); From 628f7cd47ab758cae0353d1a6decf3d1459dca24 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 16:24:11 -0700 Subject: [PATCH 0222/6183] cgroup: separate out cgroup_base_files[] handling out of cgroup_populate/clear_dir() cgroup_populate/clear_dir() currently take @base_files and adds and removes, respectively, cgroup_base_files[] to the directory. File additions and removals are being reorganized for proper error handling and more dynamic handling for the unified hierarchy, and mixing base and subsys file handling into the same functions gets a bit confusing. This patch moves base file handling out of cgroup_populate/clear_dir() into their users - cgroup_mount(), cgroup_create() and cgroup_destroy_locked(). Note that this changes the behavior of base file removal. If @base_files is %true, cgroup_clear_dir() used to delete files regardless of cftype until there's no files left. Now, only files with matching cfts are removed. As files can only be created by the base or registered cftypes, this shouldn't result in any behavior difference. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 36c0ccc921f4..9835a097f3c0 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -215,6 +215,8 @@ static u64 cgroup_serial_nr_next = 1; */ static int need_forkexit_callback __read_mostly; +static struct cftype cgroup_base_files[]; + static void cgroup_offline_fn(struct work_struct *work); static int cgroup_destroy_locked(struct cgroup *cgrp); static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, @@ -804,8 +806,7 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task, static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); static struct dentry *cgroup_lookup(struct inode *, struct dentry *, unsigned int); static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry); -static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files, - unsigned long subsys_mask); +static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask); static const struct inode_operations cgroup_dir_inode_operations; static const struct file_operations proc_cgroupstats_operations; @@ -957,13 +958,11 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) } /** - * cgroup_clear_dir - selective removal of base and subsystem files + * cgroup_clear_dir - remove subsys files in a cgroup directory * @cgrp: target cgroup - * @base_files: true if the base files should be removed * @subsys_mask: mask of the subsystem ids whose files should be removed */ -static void cgroup_clear_dir(struct cgroup *cgrp, bool base_files, - unsigned long subsys_mask) +static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask) { struct cgroup_subsys *ss; @@ -974,10 +973,6 @@ static void cgroup_clear_dir(struct cgroup *cgrp, bool base_files, list_for_each_entry(set, &ss->cftsets, node) cgroup_addrm_files(cgrp, NULL, set->cfts, false); } - if (base_files) { - while (!list_empty(&cgrp->files)) - cgroup_rm_file(cgrp, NULL); - } } /* @@ -1372,17 +1367,17 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) * this before rebind_subsystems, since rebind_subsystems may * change this hierarchy's subsys_list. */ - cgroup_clear_dir(cgrp, false, removed_mask); + cgroup_clear_dir(cgrp, removed_mask); ret = rebind_subsystems(root, added_mask, removed_mask); if (ret) { /* rebind_subsystems failed, re-populate the removed files */ - cgroup_populate_dir(cgrp, false, removed_mask); + cgroup_populate_dir(cgrp, removed_mask); goto out_unlock; } /* re-populate subsystem files */ - cgroup_populate_dir(cgrp, false, added_mask); + cgroup_populate_dir(cgrp, added_mask); if (opts.release_agent) strcpy(root->release_agent_path, opts.release_agent); @@ -1687,7 +1682,8 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, BUG_ON(root->number_of_cgroups != 1); cred = override_creds(&init_cred); - cgroup_populate_dir(root_cgrp, true, root->subsys_mask); + cgroup_addrm_files(root_cgrp, NULL, cgroup_base_files, true); + cgroup_populate_dir(root_cgrp, root->subsys_mask); revert_creds(cred); mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); @@ -4172,23 +4168,14 @@ static struct cftype cgroup_base_files[] = { }; /** - * cgroup_populate_dir - selectively creation of files in a directory + * cgroup_populate_dir - create subsys files in a cgroup directory * @cgrp: target cgroup - * @base_files: true if the base files should be added * @subsys_mask: mask of the subsystem ids whose files should be added */ -static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files, - unsigned long subsys_mask) +static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) { - int err; struct cgroup_subsys *ss; - if (base_files) { - err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true); - if (err < 0) - return err; - } - /* process cftsets of each subsystem */ for_each_root_subsys(cgrp->root, ss) { struct cftype_set *set; @@ -4410,7 +4397,11 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, } } - err = cgroup_populate_dir(cgrp, true, root->subsys_mask); + err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true); + if (err) + goto err_destroy; + + err = cgroup_populate_dir(cgrp, root->subsys_mask); if (err) goto err_destroy; @@ -4566,7 +4557,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) * Clear and remove @cgrp directory. The removal puts the base ref * but we aren't quite done with @cgrp yet, so hold onto it. */ - cgroup_clear_dir(cgrp, true, cgrp->root->subsys_mask); + cgroup_clear_dir(cgrp, cgrp->root->subsys_mask); + cgroup_addrm_files(cgrp, NULL, cgroup_base_files, false); dget(d); cgroup_d_remove_dir(d); From bee550994f6b0c1179bd3ccea58dc5c2c4ccf842 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 16:24:11 -0700 Subject: [PATCH 0223/6183] cgroup: update error handling in cgroup_populate_dir() cgroup_populate_dir() didn't use to check whether the actual file creations were successful and could return success with only subset of the requested files created, which is nasty. This patch udpates cgroup_populate_dir() so that it either succeeds with all files or fails with no file. v2: The original patch also converted for_each_root_subsys() usages to for_each_subsys() without explaining why. That part has been moved to a separate patch. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 9835a097f3c0..6b7324431b99 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -4171,10 +4171,13 @@ static struct cftype cgroup_base_files[] = { * cgroup_populate_dir - create subsys files in a cgroup directory * @cgrp: target cgroup * @subsys_mask: mask of the subsystem ids whose files should be added + * + * On failure, no file is added. */ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) { struct cgroup_subsys *ss; + int ret = 0; /* process cftsets of each subsystem */ for_each_root_subsys(cgrp->root, ss) { @@ -4182,8 +4185,11 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) if (!test_bit(ss->subsys_id, &subsys_mask)) continue; - list_for_each_entry(set, &ss->cftsets, node) - cgroup_addrm_files(cgrp, ss, set->cfts, true); + list_for_each_entry(set, &ss->cftsets, node) { + ret = cgroup_addrm_files(cgrp, ss, set->cfts, true); + if (ret < 0) + goto err; + } } /* This cgroup is ready now */ @@ -4201,6 +4207,9 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) } return 0; +err: + cgroup_clear_dir(cgrp, subsys_mask); + return ret; } static void css_dput_fn(struct work_struct *work) From b420ba7db15659253d4f286a0ba479d336371999 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 12 Jul 2013 12:34:02 -0700 Subject: [PATCH 0224/6183] cgroup: use for_each_subsys() instead of for_each_root_subsys() in cgroup_populate/clear_dir() rebind_subsystems() will be updated to handle file creations and removals with proper error handling and to do that will need to perform file operations before actually adding the subsystem to the hierarchy. To enable such usage, update cgroup_populate/clear_dir() to use for_each_subsys() instead of for_each_root_subsys() so that they operate on all subsystems specified by @subsys_mask whether that subsystem is currently bound to the hierarchy or not. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 6b7324431b99..8f70dc0c0c79 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -965,10 +965,12 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft) static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask) { struct cgroup_subsys *ss; + int i; - for_each_root_subsys(cgrp->root, ss) { + for_each_subsys(ss, i) { struct cftype_set *set; - if (!test_bit(ss->subsys_id, &subsys_mask)) + + if (!test_bit(i, &subsys_mask)) continue; list_for_each_entry(set, &ss->cftsets, node) cgroup_addrm_files(cgrp, NULL, set->cfts, false); @@ -4177,12 +4179,13 @@ static struct cftype cgroup_base_files[] = { static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask) { struct cgroup_subsys *ss; - int ret = 0; + int i, ret = 0; /* process cftsets of each subsystem */ - for_each_root_subsys(cgrp->root, ss) { + for_each_subsys(ss, i) { struct cftype_set *set; - if (!test_bit(ss->subsys_id, &subsys_mask)) + + if (!test_bit(i, &subsys_mask)) continue; list_for_each_entry(set, &ss->cftsets, node) { From 3126121fb30941552b1a806c7c2e686bde57e270 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 17:07:30 -0700 Subject: [PATCH 0225/6183] cgroup: make rebind_subsystems() handle file additions and removals with proper error handling Currently, creating and removing cgroup files in the root directory are handled separately from the actual subsystem binding and unbinding which happens in rebind_subsystems(). Also, rebind_subsystems() users aren't handling file creation errors properly. Let's integrate top_cgroup file handling into rebind_subsystems() so that it's simpler to use and everyone handles file creation errors correctly. * On a successful return, rebind_subsystems() is guaranteed to have created all files of the new subsystems and deleted the ones belonging to the removed subsystems. After a failure, no file is created or removed. * cgroup_remount() no longer needs to make explicit populate/clear calls as it's all handled by rebind_subsystems(), and it gets proper error handling automatically. * cgroup_mount() has been updated such that the root dentry and cgroup are linked before rebind_subsystems(). Also, the init_cred dancing and base file handling are moved right above rebind_subsystems() call and proper error handling for the base files is added. While at it, add a comment explaining what's going on with the cred thing. * cgroup_kill_sb() calls rebind_subsystems() to unbind all subsystems which now implies removing all subsystem files which requires the directory's i_mutex. Grab it. This means that files on the root cgroup are removed earlier - they used to be deleted from generic super_block cleanup from vfs. This doesn't lead to any functional difference and it's cleaner to do the clean up explicitly for all files. Combined with the previous changes, this makes all cgroup file creation errors handled correctly. v2: Added comment on init_cred. v3: Li spotted that cgroup_mount() wasn't freeing tmp_links after base file addition failure. Fix it by adding free_tmp_links error handling label. v4: v3 introduced build bugs which got noticed by Fengguang's awesome kbuild test robot. Fixed, and shame on me. Signed-off-by: Tejun Heo Acked-by: Li Zefan Cc: Fengguang Wu --- kernel/cgroup.c | 73 +++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 8f70dc0c0c79..4ec8d2da94d1 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1003,7 +1003,7 @@ static int rebind_subsystems(struct cgroupfs_root *root, { struct cgroup *cgrp = &root->top_cgroup; struct cgroup_subsys *ss; - int i; + int i, ret; BUG_ON(!mutex_is_locked(&cgroup_mutex)); BUG_ON(!mutex_is_locked(&cgroup_root_mutex)); @@ -1028,7 +1028,16 @@ static int rebind_subsystems(struct cgroupfs_root *root, if (root->number_of_cgroups > 1) return -EBUSY; - /* Process each subsystem */ + ret = cgroup_populate_dir(cgrp, added_mask); + if (ret) + return ret; + + /* + * Nothing can fail from this point on. Remove files for the + * removed subsystems and rebind each subsystem. + */ + cgroup_clear_dir(cgrp, removed_mask); + for_each_subsys(ss, i) { unsigned long bit = 1UL << i; @@ -1364,22 +1373,9 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) goto out_unlock; } - /* - * Clear out the files of subsystems that should be removed, do - * this before rebind_subsystems, since rebind_subsystems may - * change this hierarchy's subsys_list. - */ - cgroup_clear_dir(cgrp, removed_mask); - ret = rebind_subsystems(root, added_mask, removed_mask); - if (ret) { - /* rebind_subsystems failed, re-populate the removed files */ - cgroup_populate_dir(cgrp, removed_mask); + if (ret) goto out_unlock; - } - - /* re-populate subsystem files */ - cgroup_populate_dir(cgrp, added_mask); if (opts.release_agent) strcpy(root->release_agent_path, opts.release_agent); @@ -1578,7 +1574,9 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, int ret = 0; struct super_block *sb; struct cgroupfs_root *new_root; + struct list_head tmp_links; struct inode *inode; + const struct cred *cred; /* First find the desired set of subsystems */ mutex_lock(&cgroup_mutex); @@ -1610,10 +1608,8 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, BUG_ON(!root); if (root == opts.new_root) { /* We used the new root structure, so this is a new hierarchy */ - struct list_head tmp_links; struct cgroup *root_cgrp = &root->top_cgroup; struct cgroupfs_root *existing_root; - const struct cred *cred; int i; struct css_set *cset; @@ -1651,26 +1647,37 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, if (ret) goto unlock_drop; + sb->s_root->d_fsdata = root_cgrp; + root_cgrp->dentry = sb->s_root; + + /* + * We're inside get_sb() and will call lookup_one_len() to + * create the root files, which doesn't work if SELinux is + * in use. The following cred dancing somehow works around + * it. See 2ce9738ba ("cgroupfs: use init_cred when + * populating new cgroupfs mount") for more details. + */ + cred = override_creds(&init_cred); + + ret = cgroup_addrm_files(root_cgrp, NULL, cgroup_base_files, true); + if (ret) + goto rm_base_files; + ret = rebind_subsystems(root, root->subsys_mask, 0); - if (ret == -EBUSY) { - free_cgrp_cset_links(&tmp_links); - goto unlock_drop; - } + if (ret) + goto rm_base_files; + + revert_creds(cred); + /* * There must be no failure case after here, since rebinding * takes care of subsystems' refcounts, which are explicitly * dropped in the failure exit path. */ - /* EBUSY should be the only error here */ - BUG_ON(ret); - list_add(&root->root_list, &cgroup_roots); cgroup_root_count++; - sb->s_root->d_fsdata = root_cgrp; - root->top_cgroup.dentry = sb->s_root; - /* Link the top cgroup in this hierarchy into all * the css_set objects */ write_lock(&css_set_lock); @@ -1683,10 +1690,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, BUG_ON(!list_empty(&root_cgrp->children)); BUG_ON(root->number_of_cgroups != 1); - cred = override_creds(&init_cred); - cgroup_addrm_files(root_cgrp, NULL, cgroup_base_files, true); - cgroup_populate_dir(root_cgrp, root->subsys_mask); - revert_creds(cred); mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); @@ -1715,6 +1718,10 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, kfree(opts.name); return dget(sb->s_root); + rm_base_files: + free_cgrp_cset_links(&tmp_links); + cgroup_addrm_files(&root->top_cgroup, NULL, cgroup_base_files, false); + revert_creds(cred); unlock_drop: cgroup_exit_root_id(root); mutex_unlock(&cgroup_root_mutex); @@ -1741,6 +1748,7 @@ static void cgroup_kill_sb(struct super_block *sb) { BUG_ON(root->number_of_cgroups != 1); BUG_ON(!list_empty(&cgrp->children)); + mutex_lock(&cgrp->dentry->d_inode->i_mutex); mutex_lock(&cgroup_mutex); mutex_lock(&cgroup_root_mutex); @@ -1773,6 +1781,7 @@ static void cgroup_kill_sb(struct super_block *sb) { mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); + mutex_unlock(&cgrp->dentry->d_inode->i_mutex); simple_xattrs_free(&cgrp->xattrs); From f172e67cf9d842bc646d0f66792e38435a334b1e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 17:07:30 -0700 Subject: [PATCH 0226/6183] cgroup: move number_of_cgroups test out of rebind_subsystems() into cgroup_remount() rebind_subsystems() currently fails if the hierarchy has any !root cgroups; however, on the planned unified hierarchy, rebind_subsystems() will be used while populated. Move the test to cgroup_remount(), which is the only place the test is necessary anyway. As it's impossible for the other two callers of rebind_subsystems() to have populated hierarchy, this doesn't make any behavior changes. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 4ec8d2da94d1..c108d3d1ea30 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1021,13 +1021,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, } } - /* Currently we don't handle adding/removing subsystems when - * any child cgroups exist. This is theoretically supportable - * but involves complex error handling, so it's being left until - * later */ - if (root->number_of_cgroups > 1) - return -EBUSY; - ret = cgroup_populate_dir(cgrp, added_mask); if (ret) return ret; @@ -1373,6 +1366,12 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) goto out_unlock; } + /* remounting is not allowed for populated hierarchies */ + if (root->number_of_cgroups > 1) { + ret = -EBUSY; + goto out_unlock; + } + ret = rebind_subsystems(root, added_mask, removed_mask); if (ret) goto out_unlock; From 38ead6ef1d94e782bec49002ff65f2bdaddfeb15 Mon Sep 17 00:00:00 2001 From: Paul Chavent Date: Sun, 7 Jul 2013 17:43:56 +0200 Subject: [PATCH 0227/6183] HID: core: fix hid delimiter local tag parsing. When device with the DELIMITER tag in its report descriptor is encountered during parsing, it's mistakenly immediately refused by HID core for no justifiable reason. [jkosina@suse.cz: polish changelog] Signed-off-by: Paul Chavent Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e39dac68063c..8de5cb8319b9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -450,7 +450,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) } parser->local.delimiter_depth--; } - return 1; + return 0; case HID_LOCAL_ITEM_TAG_USAGE: From f22ff5523af8b365167cb79189f8b91470d57c8c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:34 +0800 Subject: [PATCH 0228/6183] ACPI / dock: avoid initializing acpi_dock_notifier_list multiple times Function dock_add() will be called multiple times if there are multiple dock stations, which causes acpi_dock_notifier_list to be initialized multiple times. To avoid that, move the initialization of acpi_dock_notifier_list from dock_add() to acpi_dock_init(). [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 826560753389..c36de862fd50 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -1007,7 +1007,6 @@ static int __init dock_add(acpi_handle handle) mutex_init(&dock_station->hp_lock); spin_lock_init(&dock_station->dd_lock); INIT_LIST_HEAD(&dock_station->sibling); - ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); INIT_LIST_HEAD(&dock_station->dependent_devices); /* we want the dock device to send uevents */ @@ -1078,6 +1077,7 @@ void __init acpi_dock_init(void) return; } + ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); register_acpi_bus_notifier(&dock_acpi_notifier); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); From ed633e709fa633c6bc24f4d6ecb55ad0c14fd335 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:35 +0800 Subject: [PATCH 0229/6183] ACPI / dock: drop redundant spin lock in dock station object All dock station objects are created during initialization and don't change at runtime, so drop the redundant spin lock from struct dock_station. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c36de862fd50..750f958ef0bf 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -63,7 +63,6 @@ struct dock_station { acpi_handle handle; unsigned long last_dock_time; u32 flags; - spinlock_t dd_lock; struct mutex hp_lock; struct list_head dependent_devices; @@ -112,10 +111,7 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) dd->handle = handle; INIT_LIST_HEAD(&dd->list); - - spin_lock(&ds->dd_lock); list_add_tail(&dd->list, &ds->dependent_devices); - spin_unlock(&ds->dd_lock); return 0; } @@ -220,14 +216,10 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) { struct dock_dependent_device *dd; - spin_lock(&ds->dd_lock); - list_for_each_entry(dd, &ds->dependent_devices, list) { - if (handle == dd->handle) { - spin_unlock(&ds->dd_lock); + list_for_each_entry(dd, &ds->dependent_devices, list) + if (handle == dd->handle) return dd; - } - } - spin_unlock(&ds->dd_lock); + return NULL; } @@ -1005,7 +997,6 @@ static int __init dock_add(acpi_handle handle) dock_station->last_dock_time = jiffies - HZ; mutex_init(&dock_station->hp_lock); - spin_lock_init(&dock_station->dd_lock); INIT_LIST_HEAD(&dock_station->sibling); INIT_LIST_HEAD(&dock_station->dependent_devices); From d423c083ff3b3adc1e42a2f2c03c8430a6e0220f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:36 +0800 Subject: [PATCH 0230/6183] ACPI / dock: mark initialization functions with __init Mark all initialization functions with __init to reduce runtime memory consumption. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 750f958ef0bf..f3ec722ae85a 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -100,7 +100,7 @@ struct dock_dependent_device { * * Add the dependent device to the dock's dependent device list. */ -static int +static int __init add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) { struct dock_dependent_device *dd; @@ -244,7 +244,7 @@ static int is_dock(acpi_handle handle) return 1; } -static int is_ejectable(acpi_handle handle) +static int __init is_ejectable(acpi_handle handle) { acpi_status status; acpi_handle tmp; @@ -255,7 +255,7 @@ static int is_ejectable(acpi_handle handle) return 1; } -static int is_ata(acpi_handle handle) +static int __init is_ata(acpi_handle handle) { acpi_handle tmp; @@ -268,7 +268,7 @@ static int is_ata(acpi_handle handle) return 0; } -static int is_battery(acpi_handle handle) +static int __init is_battery(acpi_handle handle) { struct acpi_device_info *info; int ret = 1; @@ -284,7 +284,7 @@ static int is_battery(acpi_handle handle) return ret; } -static int is_ejectable_bay(acpi_handle handle) +static int __init is_ejectable_bay(acpi_handle handle) { acpi_handle phandle; @@ -848,7 +848,7 @@ static struct notifier_block dock_acpi_notifier = { * check to see if an object has an _EJD method. If it does, then it * will see if it is dependent on the dock station. */ -static acpi_status +static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; From 472d963befe28b8614ea2789757b27536c8d79eb Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:37 +0800 Subject: [PATCH 0231/6183] ACPI / dock: simplify dock_create_acpi_device() The return value of dock_create_acpi_device() is not used at all, so change its signature to return void and simplify the implementation of it. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index f3ec722ae85a..1bdb1facc17b 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -351,10 +351,8 @@ static int dock_present(struct dock_station *ds) * handle if one does not exist already. This should cause * acpi to scan for drivers for the given devices, and call * matching driver's add routine. - * - * Returns a pointer to the acpi_device corresponding to the handle. */ -static struct acpi_device * dock_create_acpi_device(acpi_handle handle) +static void dock_create_acpi_device(acpi_handle handle) { struct acpi_device *device; int ret; @@ -367,10 +365,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) ret = acpi_bus_scan(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); - - acpi_bus_get_device(handle, &device); } - return device; } /** From 952c63e9512b63220886105cfc791507046fa39a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:38 +0800 Subject: [PATCH 0232/6183] ACPI: introduce helper function acpi_has_method() Introduce helper function acpi_has_method() and use it in a number of places to simplify code. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 11 +--- drivers/acpi/ec.c | 4 +- drivers/acpi/processor_perflib.c | 22 +++---- drivers/acpi/resource.c | 4 +- drivers/acpi/scan.c | 99 ++++++++++---------------------- drivers/acpi/utils.c | 15 +++++ drivers/acpi/video.c | 39 ++++--------- drivers/acpi/video_detect.c | 19 +++--- include/acpi/acpi_bus.h | 3 + 9 files changed, 80 insertions(+), 136 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd252a8..a7627166e18b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -548,12 +548,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) static int acpi_battery_init_alarm(struct acpi_battery *battery) { - acpi_status status = AE_OK; - acpi_handle handle = NULL; - /* See if alarms are supported, and if so, set default */ - status = acpi_get_handle(battery->device->handle, "_BTP", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(battery->device->handle, "_BTP")) { clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags); return 0; } @@ -1066,7 +1062,7 @@ static int acpi_battery_add(struct acpi_device *device) { int result = 0; struct acpi_battery *battery = NULL; - acpi_handle handle; + if (!device) return -EINVAL; battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); @@ -1078,8 +1074,7 @@ static int acpi_battery_add(struct acpi_device *device) device->driver_data = battery; mutex_init(&battery->lock); mutex_init(&battery->sysfs_lock); - if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, - "_BIX", &handle))) + if (acpi_has_method(battery->device->handle, "_BIX")) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); result = acpi_battery_update(battery); if (result) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 80403c1a89f8..84bf06cec1f2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1049,10 +1049,8 @@ int __init acpi_ec_ecdt_probe(void) * which needs it, has fake EC._INI method, so use it as flag. * Keep boot_ec struct as it will be needed soon. */ - acpi_handle dummy; if (!dmi_name_in_vendors("ASUS") || - ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", - &dummy))) + !acpi_has_method(boot_ec->handle, "_INI")) return -ENODEV; } install: diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 1e9732d809bf..51d7948611da 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -164,17 +164,12 @@ static void acpi_processor_ppc_ost(acpi_handle handle, int status) {.type = ACPI_TYPE_INTEGER,}, }; struct acpi_object_list arg_list = {2, params}; - acpi_handle temp; - params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; - params[1].integer.value = status; - - /* when there is no _OST , skip it */ - if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) - return; - - acpi_evaluate_object(handle, "_OST", &arg_list, NULL); - return; + if (acpi_has_method(handle, "_OST")) { + params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; + params[1].integer.value = status; + acpi_evaluate_object(handle, "_OST", &arg_list, NULL); + } } int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) @@ -468,14 +463,11 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr) int acpi_processor_get_performance_info(struct acpi_processor *pr) { int result = 0; - acpi_status status = AE_OK; - acpi_handle handle = NULL; if (!pr || !pr->performance || !pr->handle) return -EINVAL; - status = acpi_get_handle(pr->handle, "_PCT", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(pr->handle, "_PCT")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI-based processor performance control unavailable\n")); return -ENODEV; @@ -501,7 +493,7 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr) */ update_bios: #ifdef CONFIG_X86 - if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){ + if (acpi_has_method(pr->handle, "_PPC")) { if(boot_cpu_has(X86_FEATURE_EST)) printk(KERN_WARNING FW_BUG "BIOS needs update for CPU " "frequency support\n"); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3322b47ab7ca..b7201fc6f1e1 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -505,14 +505,12 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, void *preproc_data) { struct res_proc_context c; - acpi_handle not_used; acpi_status status; if (!adev || !adev->handle || !list_empty(list)) return -EINVAL; - status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, ¬_used); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) return 0; c.list = list; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 10985573aaa7..ada0b4cf2ba5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -193,7 +193,6 @@ static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl, static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; - acpi_handle not_used; struct acpi_object_list arg_list; union acpi_object arg; struct device *errdev; @@ -258,7 +257,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) put_device(&device->dev); device = NULL; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", ¬_used))) { + if (acpi_has_method(handle, "_LCK")) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; @@ -652,7 +651,6 @@ static int acpi_device_setup_files(struct acpi_device *dev) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; - acpi_handle temp; unsigned long long sun; int result = 0; @@ -678,8 +676,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) /* * If device has _STR, 'description' file is created */ - status = acpi_get_handle(dev->handle, "_STR", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(dev->handle, "_STR")) { status = acpi_evaluate_object(dev->handle, "_STR", NULL, &buffer); if (ACPI_FAILURE(status)) @@ -709,8 +706,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(dev->handle, "_EJ0")) { result = device_create_file(&dev->dev, &dev_attr_eject); if (result) return result; @@ -732,9 +728,6 @@ end: static void acpi_device_remove_files(struct acpi_device *dev) { - acpi_status status; - acpi_handle temp; - if (dev->flags.power_manageable) { device_remove_file(&dev->dev, &dev_attr_power_state); if (dev->power.flags.power_resources) @@ -745,20 +738,17 @@ static void acpi_device_remove_files(struct acpi_device *dev) /* * If device has _STR, remove 'description' file */ - status = acpi_get_handle(dev->handle, "_STR", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(dev->handle, "_STR")) { kfree(dev->pnp.str_obj); device_remove_file(&dev->dev, &dev_attr_description); } /* * If device has _EJ0, remove 'eject' file. */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(dev->handle, "_EJ0")) device_remove_file(&dev->dev, &dev_attr_eject); - status = acpi_get_handle(dev->handle, "_SUN", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(dev->handle, "_SUN")) device_remove_file(&dev->dev, &dev_attr_sun); if (dev->pnp.unique_id) @@ -1334,13 +1324,10 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) { - acpi_handle temp; - acpi_status status = 0; int err; /* Presence of _PRW indicates wake capable */ - status = acpi_get_handle(device->handle, "_PRW", &temp); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(device->handle, "_PRW")) return; err = acpi_bus_extract_wakeup_device_power_package(device->handle, @@ -1370,7 +1357,6 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) struct acpi_device_power_state *ps = &device->power.states[state]; char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_handle handle; acpi_status status; INIT_LIST_HEAD(&ps->resources); @@ -1393,8 +1379,7 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) /* Evaluate "_PSx" to see if we can do explicit sets */ pathname[2] = 'S'; - status = acpi_get_handle(device->handle, pathname, &handle); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, pathname)) ps->flags.explicit_set = 1; /* @@ -1413,28 +1398,21 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state) static void acpi_bus_get_power_flags(struct acpi_device *device) { - acpi_status status; - acpi_handle handle; u32 i; /* Presence of _PS0|_PR0 indicates 'power manageable' */ - status = acpi_get_handle(device->handle, "_PS0", &handle); - if (ACPI_FAILURE(status)) { - status = acpi_get_handle(device->handle, "_PR0", &handle); - if (ACPI_FAILURE(status)) - return; - } + if (!acpi_has_method(device->handle, "_PS0") && + !acpi_has_method(device->handle, "_PR0")) + return; device->flags.power_manageable = 1; /* * Power Management Flags */ - status = acpi_get_handle(device->handle, "_PSC", &handle); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_PSC")) device->power.flags.explicit_get = 1; - status = acpi_get_handle(device->handle, "_IRC", &handle); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_IRC")) device->power.flags.inrush_current = 1; /* @@ -1468,28 +1446,18 @@ static void acpi_bus_get_power_flags(struct acpi_device *device) static void acpi_bus_get_flags(struct acpi_device *device) { - acpi_status status = AE_OK; - acpi_handle temp = NULL; - /* Presence of _STA indicates 'dynamic_status' */ - status = acpi_get_handle(device->handle, "_STA", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_STA")) device->flags.dynamic_status = 1; /* Presence of _RMV indicates 'removable' */ - status = acpi_get_handle(device->handle, "_RMV", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_RMV")) device->flags.removable = 1; /* Presence of _EJD|_EJ0 indicates 'ejectable' */ - status = acpi_get_handle(device->handle, "_EJD", &temp); - if (ACPI_SUCCESS(status)) + if (acpi_has_method(device->handle, "_EJD") || + acpi_has_method(device->handle, "_EJ0")) device->flags.ejectable = 1; - else { - status = acpi_get_handle(device->handle, "_EJ0", &temp); - if (ACPI_SUCCESS(status)) - device->flags.ejectable = 1; - } } static void acpi_device_get_busid(struct acpi_device *device) @@ -1538,27 +1506,24 @@ static void acpi_device_get_busid(struct acpi_device *device) */ static int acpi_bay_match(acpi_handle handle) { - acpi_status status; - acpi_handle tmp; acpi_handle phandle; - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) + if (!acpi_has_method(handle, "_EJ0")) return -ENODEV; - if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + if (acpi_has_method(handle, "_GTF") || + acpi_has_method(handle, "_GTM") || + acpi_has_method(handle, "_STM") || + acpi_has_method(handle, "_SDD")) return 0; if (acpi_get_parent(handle, &phandle)) return -ENODEV; - if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) + if (acpi_has_method(phandle, "_GTF") || + acpi_has_method(phandle, "_GTM") || + acpi_has_method(phandle, "_STM") || + acpi_has_method(phandle, "_SDD")) return 0; return -ENODEV; @@ -1610,7 +1575,6 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id) */ static int acpi_ibm_smbus_match(acpi_handle handle) { - acpi_handle h_dummy; struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; int result; @@ -1629,9 +1593,9 @@ static int acpi_ibm_smbus_match(acpi_handle handle) /* Does it have the necessary (but misnamed) methods? */ result = -ENODEV; - if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy))) + if (acpi_has_method(handle, "SBI") && + acpi_has_method(handle, "SBR") && + acpi_has_method(handle, "SBW")) result = 0; out: kfree(path.pointer); @@ -1898,7 +1862,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, struct acpi_device *device = NULL; int type; unsigned long long sta; - acpi_status status; int result; acpi_bus_get_device(handle, &device); @@ -1919,10 +1882,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, if (!(sta & ACPI_STA_DEVICE_PRESENT) && !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { struct acpi_device_wakeup wakeup; - acpi_handle temp; - status = acpi_get_handle(handle, "_PRW", &temp); - if (ACPI_SUCCESS(status)) { + if (acpi_has_method(handle, "_PRW")) { acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); acpi_power_resources_list_free(&wakeup.resources); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 744371304313..b08d97376f84 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -495,3 +495,18 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) kfree(buffer.pointer); } EXPORT_SYMBOL(acpi_handle_printk); + +/** + * acpi_has_method: Check whether @handle has a method named @name + * @handle: ACPI device handle + * @name: name of object or method + * + * Check whether @handle has a method named @name. + */ +bool acpi_has_method(acpi_handle handle, char *name) +{ + acpi_handle tmp; + + return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp)); +} +EXPORT_SYMBOL(acpi_has_method); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5d7075d25700..a84533e67b9d 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -875,28 +875,21 @@ out: static void acpi_video_device_find_cap(struct acpi_video_device *device) { - acpi_handle h_dummy1; - - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_ADR")) device->cap._ADR = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_BCL")) device->cap._BCL = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_BCM")) device->cap._BCM = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) + if (acpi_has_method(device->dev->handle, "_BQC")) { device->cap._BQC = 1; - else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ", - &h_dummy1))) { + } else if (acpi_has_method(device->dev->handle, "_BCQ")) { printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n"); device->cap._BCQ = 1; } - if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { + if (acpi_has_method(device->dev->handle, "_DDC")) device->cap._DDC = 1; - } if (acpi_video_backlight_support()) { struct backlight_properties props; @@ -984,26 +977,18 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) static void acpi_video_bus_find_cap(struct acpi_video_bus *video) { - acpi_handle h_dummy1; - - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_DOS")) video->cap._DOS = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_DOD")) video->cap._DOD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_ROM")) video->cap._ROM = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_GPD")) video->cap._GPD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_SPD")) video->cap._SPD = 1; - } - if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) { + if (acpi_has_method(video->device->handle, "_VPO")) video->cap._VPO = 1; - } } /* diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index e6bd910bc6ed..ddefa5f954e2 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -51,14 +51,13 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, void **retyurn_value) { long *cap = context; - acpi_handle h_dummy; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) { + if (acpi_has_method(handle, "_BCM") && + acpi_has_method(handle, "_BCL")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " "support\n")); *cap |= ACPI_VIDEO_BACKLIGHT; - if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy))) + if (!acpi_has_method(handle, "_BQC")) printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, " "cannot determine initial brightness\n"); /* We have backlight support, no need to scan further */ @@ -77,22 +76,20 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, */ long acpi_is_video_device(acpi_handle handle) { - acpi_handle h_dummy; long video_caps = 0; /* Is this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) || - ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy))) + if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS")) video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; /* Is this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy))) + if (acpi_has_method(handle, "_ROM")) video_caps |= ACPI_VIDEO_ROM_AVAILABLE; /* Is this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) && - ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy))) + if (acpi_has_method(handle, "_VPO") && + acpi_has_method(handle, "_GPD") && + acpi_has_method(handle, "_SPD")) video_caps |= ACPI_VIDEO_DEVICE_POSTING; /* Only check for backlight functionality if one of the above hit. */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68c8d2f..62b2811bade4 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -56,6 +56,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, acpi_status acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld); + +bool acpi_has_method(acpi_handle handle, char *name); + #ifdef CONFIG_ACPI #include From 0db98202605c3d32e023d43c30b5bd878f520976 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:39 +0800 Subject: [PATCH 0233/6183] ACPI: introduce helper function acpi_execute_simple_method() Introduce helper function acpi_execute_simple_method() and use it in a number of places to simplify code. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 8 ++------ drivers/acpi/bus.c | 6 +----- drivers/acpi/power.c | 4 +--- drivers/acpi/sleep.c | 7 ++----- drivers/acpi/thermal.c | 18 ++++-------------- drivers/acpi/utils.c | 12 ++++++++++++ drivers/acpi/video.c | 17 +++++------------ include/acpi/acpi_bus.h | 2 ++ 8 files changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index a7627166e18b..74669ac4c615 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -525,18 +525,14 @@ static int acpi_battery_get_state(struct acpi_battery *battery) static int acpi_battery_set_alarm(struct acpi_battery *battery) { acpi_status status = 0; - union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg0 }; if (!acpi_battery_present(battery) || !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags)) return -ENODEV; - arg0.integer.value = battery->alarm; - mutex_lock(&battery->lock); - status = acpi_evaluate_object(battery->device->handle, "_BTP", - &arg_list, NULL); + status = acpi_execute_simple_method(battery->device->handle, "_BTP", + battery->alarm); mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5bb33bab448..a5a032e2344e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -593,8 +593,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) static int __init acpi_bus_init_irq(void) { acpi_status status; - union acpi_object arg = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg }; char *message = NULL; @@ -623,9 +621,7 @@ static int __init acpi_bus_init_irq(void) printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message); - arg.integer.value = acpi_irq_model; - - status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL); + status = acpi_execute_simple_method(NULL, "\\_PIC", acpi_irq_model); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC")); return -ENODEV; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5c28c894c0fc..1460c88a7c0e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -637,9 +637,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev, } /* Execute _PSW */ - arg_list.count = 1; - in_arg[0].integer.value = enable; - status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); + status = acpi_execute_simple_method(dev->handle, "_PSW", enable); if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { printk(KERN_ERR PREFIX "_PSW execution failed\n"); dev->wakeup.flags.valid = 0; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 187ab61889e6..81b0f03d97db 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -31,12 +31,9 @@ static u8 sleep_states[ACPI_S_STATE_COUNT]; static void acpi_sleep_tts_switch(u32 acpi_state) { - union acpi_object in_arg = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &in_arg }; - acpi_status status = AE_OK; + acpi_status status; - in_arg.integer.value = acpi_state; - status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL); + status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { /* * OS can't evaluate the _TTS object correctly. Some warning diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a33821ca3895..94523c79dc5f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -239,26 +239,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode) { - acpi_status status = AE_OK; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list arg_list = { 1, &arg0 }; - acpi_handle handle = NULL; - - if (!tz) return -EINVAL; - status = acpi_get_handle(tz->device->handle, "_SCP", &handle); - if (ACPI_FAILURE(status)) { + if (!acpi_has_method(tz->device->handle, "_SCP")) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n")); return -ENODEV; - } - - arg0.integer.value = mode; - - status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); - if (ACPI_FAILURE(status)) + } else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle, + "_SCP", mode))) { return -ENODEV; + } return 0; } diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index b08d97376f84..87b85882b5df 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -510,3 +510,15 @@ bool acpi_has_method(acpi_handle handle, char *name) return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp)); } EXPORT_SYMBOL(acpi_has_method); + +acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, + u64 arg) +{ + union acpi_object obj = { .type = ACPI_TYPE_INTEGER }; + struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, }; + + obj.integer.value = arg; + + return acpi_evaluate_object(handle, method, &arg_list, NULL); +} +EXPORT_SYMBOL(acpi_execute_simple_method); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a84533e67b9d..b862c7f74941 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -353,14 +353,10 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) { int status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; int state; - arg0.integer.value = level; - - status = acpi_evaluate_object(device->dev->handle, "_BCM", - &args, NULL); + status = acpi_execute_simple_method(device->dev->handle, + "_BCM", level); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); return -EIO; @@ -628,18 +624,15 @@ static int acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) { acpi_status status; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; if (!video->cap._DOS) return 0; if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) return -EINVAL; - arg0.integer.value = (lcd_flag << 2) | bios_flag; - video->dos_setting = arg0.integer.value; - status = acpi_evaluate_object(video->device->handle, "_DOS", - &args, NULL); + video->dos_setting = (lcd_flag << 2) | bios_flag; + status = acpi_execute_simple_method(video->device->handle, "_DOS", + (lcd_flag << 2) | bios_flag); if (ACPI_FAILURE(status)) return -EIO; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 62b2811bade4..e3862587b9de 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -58,6 +58,8 @@ acpi_status acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld); bool acpi_has_method(acpi_handle handle, char *name); +acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, + u64 arg); #ifdef CONFIG_ACPI From 7d2421f84b445dc48c68d33911f1fd6ce6853ee3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:40 +0800 Subject: [PATCH 0234/6183] ACPI: introduce two helper functions for _EJ0 and _LCK Introduce two helper functions, acpi_evaluate_ej0() and acpi_evaluate_lck(), that will execute the _EJ0 and _LCK ACPI control methods, respectively, and use them to simplify the ACPI scan code. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 31 ++++++----------------------- drivers/acpi/utils.c | 43 +++++++++++++++++++++++++++++++++++++++++ include/acpi/acpi_bus.h | 2 ++ 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ada0b4cf2ba5..4c25c3b7ef81 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -193,8 +193,6 @@ static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl, static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; - struct acpi_object_list arg_list; - union acpi_object arg; struct device *errdev; acpi_status status; unsigned long long sta; @@ -257,32 +255,15 @@ static int acpi_scan_hot_remove(struct acpi_device *device) put_device(&device->dev); device = NULL; - if (acpi_has_method(handle, "_LCK")) { - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 0; - acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); - } - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - + acpi_evaluate_lck(handle, 0); /* * TBD: _EJD support. */ - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - if (status == AE_NOT_FOUND) { - return -ENODEV; - } else { - acpi_handle_warn(handle, "Eject failed (0x%x)\n", - status); - return -EIO; - } - } + status = acpi_evaluate_ej0(handle); + if (status == AE_NOT_FOUND) + return -ENODEV; + else if (ACPI_FAILURE(status)) + return -EIO; /* * Verify if eject was indeed successful. If not, log an error diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 87b85882b5df..552248b0005b 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -522,3 +522,46 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, return acpi_evaluate_object(handle, method, &arg_list, NULL); } EXPORT_SYMBOL(acpi_execute_simple_method); + +/** + * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations + * @handle: ACPI device handle + * + * Evaluate device's _EJ0 method for hotplug operations. + */ +acpi_status acpi_evaluate_ej0(acpi_handle handle) +{ + acpi_status status; + + status = acpi_execute_simple_method(handle, "_EJ0", 1); + if (status == AE_NOT_FOUND) + acpi_handle_warn(handle, "No _EJ0 support for device\n"); + else if (ACPI_FAILURE(status)) + acpi_handle_warn(handle, "Eject failed (0x%x)\n", status); + + return status; +} + +/** + * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device + * @handle: ACPI device handle + * @lock: lock device if non-zero, otherwise unlock device + * + * Evaluate device's _LCK method if present to lock/unlock device + */ +acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) +{ + acpi_status status; + + status = acpi_execute_simple_method(handle, "_LCK", !!lock); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + if (lock) + acpi_handle_warn(handle, + "Locking device failed (0x%x)\n", status); + else + acpi_handle_warn(handle, + "Unlocking device failed (0x%x)\n", status); + } + + return status; +} diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e3862587b9de..f499157b04e8 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -60,6 +60,8 @@ acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld bool acpi_has_method(acpi_handle handle, char *name); acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, u64 arg); +acpi_status acpi_evaluate_ej0(acpi_handle handle); +acpi_status acpi_evaluate_lck(acpi_handle handle, int lock); #ifdef CONFIG_ACPI From ebf4df8db0e7e5db9f7fca5fcd0c2b90ac954385 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:41 +0800 Subject: [PATCH 0235/6183] ACPI: Export acpi_(bay)|(dock)_match() from scan.c Functions acpi_dock_match() and acpi_bay_match() in scan.c can be shared with dock.c to reduce code duplication, so export them as global functions. Also add a new function acpi_ata_match() to check whether an ACPI device object represents an ATA device. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 77 +++++++++++++++++++---------------------- include/acpi/acpi_bus.h | 3 ++ 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4c25c3b7ef81..62e2055e8806 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1479,44 +1479,46 @@ static void acpi_device_get_busid(struct acpi_device *device) } } +/* + * acpi_ata_match - see if an acpi object is an ATA device + * + * If an acpi object has one of the ACPI ATA methods defined, + * then we can safely call it an ATA device. + */ +bool acpi_ata_match(acpi_handle handle) +{ + return acpi_has_method(handle, "_GTF") || + acpi_has_method(handle, "_GTM") || + acpi_has_method(handle, "_STM") || + acpi_has_method(handle, "_SDD"); +} + /* * acpi_bay_match - see if an acpi object is an ejectable driver bay * * If an acpi object is ejectable and has one of the ACPI ATA methods defined, * then we can safely call it an ejectable drive bay */ -static int acpi_bay_match(acpi_handle handle) +bool acpi_bay_match(acpi_handle handle) { acpi_handle phandle; if (!acpi_has_method(handle, "_EJ0")) - return -ENODEV; + return false; + if (acpi_ata_match(handle)) + return true; + if (ACPI_FAILURE(acpi_get_parent(handle, &phandle))) + return false; - if (acpi_has_method(handle, "_GTF") || - acpi_has_method(handle, "_GTM") || - acpi_has_method(handle, "_STM") || - acpi_has_method(handle, "_SDD")) - return 0; - - if (acpi_get_parent(handle, &phandle)) - return -ENODEV; - - if (acpi_has_method(phandle, "_GTF") || - acpi_has_method(phandle, "_GTM") || - acpi_has_method(phandle, "_STM") || - acpi_has_method(phandle, "_SDD")) - return 0; - - return -ENODEV; + return acpi_ata_match(phandle); } /* * acpi_dock_match - see if an acpi object has a _DCK method */ -static int acpi_dock_match(acpi_handle handle) +bool acpi_dock_match(acpi_handle handle) { - acpi_handle tmp; - return acpi_get_handle(handle, "_DCK", &tmp); + return acpi_has_method(handle, "_DCK"); } const char *acpi_device_hid(struct acpi_device *device) @@ -1554,33 +1556,26 @@ static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id) * lacks the SMBUS01 HID and the methods do not have the necessary "_" * prefix. Work around this. */ -static int acpi_ibm_smbus_match(acpi_handle handle) +static bool acpi_ibm_smbus_match(acpi_handle handle) { - struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; - int result; + char node_name[ACPI_PATH_SEGMENT_LENGTH]; + struct acpi_buffer path = { sizeof(node_name), node_name }; if (!dmi_name_in_vendors("IBM")) - return -ENODEV; + return false; /* Look for SMBS object */ - result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path); - if (result) - return result; - - if (strcmp("SMBS", path.pointer)) { - result = -ENODEV; - goto out; - } + if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) || + strcmp("SMBS", path.pointer)) + return false; /* Does it have the necessary (but misnamed) methods? */ - result = -ENODEV; if (acpi_has_method(handle, "SBI") && acpi_has_method(handle, "SBR") && acpi_has_method(handle, "SBW")) - result = 0; -out: - kfree(path.pointer); - return result; + return true; + + return false; } static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, @@ -1628,11 +1623,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, */ if (acpi_is_video_device(handle)) acpi_add_id(pnp, ACPI_VIDEO_HID); - else if (ACPI_SUCCESS(acpi_bay_match(handle))) + else if (acpi_bay_match(handle)) acpi_add_id(pnp, ACPI_BAY_HID); - else if (ACPI_SUCCESS(acpi_dock_match(handle))) + else if (acpi_dock_match(handle)) acpi_add_id(pnp, ACPI_DOCK_HID); - else if (!acpi_ibm_smbus_match(handle)) + else if (acpi_ibm_smbus_match(handle)) acpi_add_id(pnp, ACPI_SMBUS_IBM_HID); else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) { acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index f499157b04e8..facc0ba6dd21 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -62,6 +62,9 @@ acpi_status acpi_execute_simple_method(acpi_handle handle, char *method, u64 arg); acpi_status acpi_evaluate_ej0(acpi_handle handle); acpi_status acpi_evaluate_lck(acpi_handle handle, int lock); +bool acpi_ata_match(acpi_handle handle); +bool acpi_bay_match(acpi_handle handle); +bool acpi_dock_match(acpi_handle handle); #ifdef CONFIG_ACPI From c9b5471f8866956919955b70ab27b4737b8bce30 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:42 +0800 Subject: [PATCH 0236/6183] ACPI: simplify dock driver with new helper functions Use helper functions introduced previously to simplify the ACPI dock driver. [rjw: Changelog] Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 122 +++++--------------------------------------- 1 file changed, 12 insertions(+), 110 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1bdb1facc17b..810d1d720b1f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -226,48 +226,6 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) /***************************************************************************** * Dock functions * *****************************************************************************/ -/** - * is_dock - see if a device is a dock station - * @handle: acpi handle of the device - * - * If an acpi object has a _DCK method, then it is by definition a dock - * station, so return true. - */ -static int is_dock(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_DCK", &tmp); - if (ACPI_FAILURE(status)) - return 0; - return 1; -} - -static int __init is_ejectable(acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) - return 0; - return 1; -} - -static int __init is_ata(acpi_handle handle) -{ - acpi_handle tmp; - - if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || - (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) - return 1; - - return 0; -} - static int __init is_battery(acpi_handle handle) { struct acpi_device_info *info; @@ -284,17 +242,13 @@ static int __init is_battery(acpi_handle handle) return ret; } -static int __init is_ejectable_bay(acpi_handle handle) +/* Check whether ACPI object is an ejectable battery or disk bay */ +static bool __init is_ejectable_bay(acpi_handle handle) { - acpi_handle phandle; + if (acpi_has_method(handle, "_EJ0") && is_battery(handle)) + return true; - if (!is_ejectable(handle)) - return 0; - if (is_battery(handle) || is_ata(handle)) - return 1; - if (!acpi_get_parent(handle, &phandle) && is_ata(phandle)) - return 1; - return 0; + return acpi_bay_match(handle); } /** @@ -312,7 +266,7 @@ int is_dock_device(acpi_handle handle) if (!dock_station_count) return 0; - if (is_dock(handle)) + if (acpi_dock_match(handle)) return 1; list_for_each_entry(dock_station, &dock_stations, sibling) @@ -446,37 +400,6 @@ static void dock_event(struct dock_station *ds, u32 event, int num) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } -/** - * eject_dock - respond to a dock eject request - * @ds: the dock station - * - * This is called after _DCK is called, to execute the dock station's - * _EJ0 method. - */ -static void eject_dock(struct dock_station *ds) -{ - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status; - acpi_handle tmp; - - /* all dock devices should have _EJ0, but check anyway */ - status = acpi_get_handle(ds->handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) { - pr_debug("No _EJ0 support for dock device\n"); - return; - } - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) - pr_debug("Failed to evaluate _EJ0!\n"); -} - /** * handle_dock - handle a dock event * @ds: the dock station @@ -537,27 +460,6 @@ static inline void complete_undock(struct dock_station *ds) ds->flags &= ~(DOCK_UNDOCKING); } -static void dock_lock(struct dock_station *ds, int lock) -{ - 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 = !!lock; - status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - if (lock) - acpi_handle_warn(ds->handle, - "Locking device failed (0x%x)\n", status); - else - acpi_handle_warn(ds->handle, - "Unlocking device failed (0x%x)\n", status); - } -} - /** * dock_in_progress - see if we are in the middle of handling a dock event * @ds: the dock station @@ -692,8 +594,8 @@ static int handle_eject_request(struct dock_station *ds, u32 event) hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); undock(ds); - dock_lock(ds, 0); - eject_dock(ds); + acpi_evaluate_lck(ds->handle, 0); + acpi_evaluate_ej0(ds->handle); if (dock_present(ds)) { acpi_handle_err(ds->handle, "Unable to undock!\n"); return -EBUSY; @@ -752,7 +654,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) hotplug_dock_devices(ds, event); complete_dock(ds); dock_event(ds, event, DOCK_EVENT); - dock_lock(ds, 1); + acpi_evaluate_lck(ds->handle, 1); acpi_update_all_gpes(); break; } @@ -998,9 +900,9 @@ static int __init dock_add(acpi_handle handle) /* we want the dock device to send uevents */ dev_set_uevent_suppress(&dd->dev, 0); - if (is_dock(handle)) + if (acpi_dock_match(handle)) dock_station->flags |= DOCK_IS_DOCK; - if (is_ata(handle)) + if (acpi_ata_match(handle)) dock_station->flags |= DOCK_IS_ATA; if (is_battery(handle)) dock_station->flags |= DOCK_IS_BAT; @@ -1043,7 +945,7 @@ err_unregister: static __init acpi_status find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) { - if (is_dock(handle) || is_ejectable_bay(handle)) + if (acpi_dock_match(handle) || is_ejectable_bay(handle)) dock_add(handle); return AE_OK; From ecd046da57d3327367b930478234e58f01bc9f0f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 29 Jun 2013 00:24:43 +0800 Subject: [PATCH 0237/6183] ACPI: simplify acpiphp driver with new helper functions Use the new helper functions introduced previously to simplify the ACPI-based PCI hotplug (acpiphp) driver. [rjw: Changelog] Signed-off-by: Jiang Liu Acked-by: Bjorn Helgaas Signed-off-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 59df8575a48c..a0a7133a1d12 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -201,7 +201,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; struct acpiphp_slot *slot; struct acpiphp_func *newfunc; - acpi_handle tmp; acpi_status status = AE_OK; unsigned long long adr, sun; int device, function, retval, found = 0; @@ -232,19 +231,19 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) newfunc->handle = handle; newfunc->function = function; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) + if (acpi_has_method(handle, "_EJ0")) newfunc->flags = FUNC_HAS_EJ0; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) + if (acpi_has_method(handle, "_STA")) newfunc->flags |= FUNC_HAS_STA; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) + if (acpi_has_method(handle, "_PS0")) newfunc->flags |= FUNC_HAS_PS0; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) + if (acpi_has_method(handle, "_PS3")) newfunc->flags |= FUNC_HAS_PS3; - if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) + if (acpi_has_method(handle, "_DCK")) newfunc->flags |= FUNC_HAS_DCK; status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); @@ -843,25 +842,14 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) */ int acpiphp_eject_slot(struct acpiphp_slot *slot) { - acpi_status status; struct acpiphp_func *func; - struct acpi_object_list arg_list; - union acpi_object arg; list_for_each_entry(func, &slot->funcs, sibling) { /* We don't want to call _EJ0 on non-existing functions. */ if ((func->flags & FUNC_HAS_EJ0)) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __func__); + if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle))) return -1; - } else + else break; } } @@ -1171,7 +1159,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, */ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) { - acpi_handle dummy_handle; struct acpiphp_bridge *bridge; if (acpiphp_disabled) @@ -1200,8 +1187,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle) get_device(&bus->dev); if (!pci_is_root_bus(bridge->pci_bus) && - ACPI_SUCCESS(acpi_get_handle(bridge->handle, - "_EJ0", &dummy_handle))) { + acpi_has_method(bridge->handle, "_EJ0")) { dbg("found ejectable p2p bridge\n"); bridge->flags |= BRIDGE_HAS_EJ0; bridge->func = acpiphp_bridge_handle_to_function(handle); From d460acebd7959cc91e7edc594d90adb9b72a0b05 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:42:51 +0200 Subject: [PATCH 0238/6183] ACPI / dock: Drop the hp_lock mutex from struct dock_station The only existing user of the hp_lock mutex in struct dock_station, hotplug_dock_devices(), is always called under acpi_scan_lock and cannot race with another instance of itself, so drop the mutex which is not necessary. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 810d1d720b1f..c10761533d6f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -63,7 +63,6 @@ struct dock_station { acpi_handle handle; unsigned long last_dock_time; u32 flags; - struct mutex hp_lock; struct list_head dependent_devices; struct list_head sibling; @@ -351,8 +350,6 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; - mutex_lock(&ds->hp_lock); - /* * First call driver specific hotplug functions */ @@ -371,7 +368,6 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) else dock_create_acpi_device(dd->handle); } - mutex_unlock(&ds->hp_lock); } static void dock_event(struct dock_station *ds, u32 event, int num) @@ -893,7 +889,6 @@ static int __init dock_add(acpi_handle handle) dock_station->dock_device = dd; dock_station->last_dock_time = jiffies - HZ; - mutex_init(&dock_station->hp_lock); INIT_LIST_HEAD(&dock_station->sibling); INIT_LIST_HEAD(&dock_station->dependent_devices); From 96c0a4d4902c3d5f56bde95d3e2d96689ca64b6d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:46:02 +0200 Subject: [PATCH 0239/6183] ACPI / dock: Rework and simplify find_dock_devices() Since acpi_walk_namespace() calls find_dock_devices() during tree pre-order visit, the latter doesn't need to add devices whose parents have _EJD pointing to the docking station to the list of that station's dependent devices, because those parents are going to be added to that list anyway and the removal of a parent will take care of the removal of its children in those cases. For this reason, rework find_dock_devices() to only call add_dock_dependent_device() for devices whose _EJD point directy to the docking station represented by its context argument and simplify it slightly. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c10761533d6f..7c86d01346e6 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -741,29 +741,16 @@ static struct notifier_block dock_acpi_notifier = { * check to see if an object has an _EJD method. If it does, then it * will see if it is dependent on the dock station. */ -static acpi_status __init -find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) +static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, + void *context, void **rv) { - acpi_status status; - acpi_handle tmp, parent; struct dock_station *ds = context; + acpi_handle ejd = NULL; - status = acpi_bus_get_ejd(handle, &tmp); - if (ACPI_FAILURE(status)) { - /* try the parent device as well */ - status = acpi_get_parent(handle, &parent); - if (ACPI_FAILURE(status)) - goto fdd_out; - /* see if parent is dependent on dock */ - status = acpi_bus_get_ejd(parent, &tmp); - if (ACPI_FAILURE(status)) - goto fdd_out; - } - - if (tmp == ds->handle) + acpi_bus_get_ejd(handle, &ejd); + if (ejd == ds->handle) add_dock_dependent_device(ds, handle); -fdd_out: return AE_OK; } From 37f908778f20bbcc35ab9a98a5b584329c6abf08 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:46:42 +0200 Subject: [PATCH 0240/6183] ACPI / dock: Walk list in reverse order during removal of devices If there are indirect dependencies between devices in a dock station's dependent devices list, they may be broken if the devices are removed in the same order in which they have been added. For this reason, make the code in handle_eject_request() walk the list of dependent devices in reverse order. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7c86d01346e6..41c5d04a89c1 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -337,9 +337,29 @@ static void dock_remove_acpi_device(acpi_handle handle) } /** - * hotplug_dock_devices - insert or remove devices on the dock station + * hot_remove_dock_devices - Remove dock station devices. + * @ds: Dock station. + */ +static void hot_remove_dock_devices(struct dock_station *ds) +{ + struct dock_dependent_device *dd; + + /* + * Walk the list in reverse order so that devices that have been added + * last are removed first (in case there are some indirect dependencies + * between them). + */ + list_for_each_entry_reverse(dd, &ds->dependent_devices, list) + dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false); + + list_for_each_entry_reverse(dd, &ds->dependent_devices, list) + dock_remove_acpi_device(dd->handle); +} + +/** + * hotplug_dock_devices - Insert devices on a dock station. * @ds: the dock station - * @event: either bus check or eject request + * @event: either bus check or device check request * * Some devices on the dock station need to have drivers called * to perform hotplug operations after a dock event has occurred. @@ -350,24 +370,17 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; - /* - * First call driver specific hotplug functions - */ + /* Call driver specific hotplug functions. */ list_for_each_entry(dd, &ds->dependent_devices, list) dock_hotplug_event(dd, event, false); /* - * Now make sure that an acpi_device is created for each - * dependent device, or removed if this is an eject request. - * This will cause acpi_drivers to be stopped/started if they - * exist + * Now make sure that an acpi_device is created for each dependent + * device. That will cause scan handlers to be attached to device + * objects or acpi_drivers to be stopped/started if they are present. */ - list_for_each_entry(dd, &ds->dependent_devices, list) { - if (event == ACPI_NOTIFY_EJECT_REQUEST) - dock_remove_acpi_device(dd->handle); - else - dock_create_acpi_device(dd->handle); - } + list_for_each_entry(dd, &ds->dependent_devices, list) + dock_create_acpi_device(dd->handle); } static void dock_event(struct dock_station *ds, u32 event, int num) @@ -588,7 +601,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) */ dock_event(ds, event, UNDOCK_EVENT); - hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + hot_remove_dock_devices(ds); undock(ds); acpi_evaluate_lck(ds->handle, 0); acpi_evaluate_ej0(ds->handle); From 4ec24065a65b4debfdeb591cc01a4aa092651f53 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:47:14 +0200 Subject: [PATCH 0241/6183] ACPI / dock: Simplify dock_init_hotplug() and dock_release_hotplug() Make dock_init_hotplug() and dock_release_hotplug() slightly simpler and move some checks in those functions to the code paths where they are needed. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 41c5d04a89c1..b1170d60a836 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -130,19 +130,16 @@ static int dock_init_hotplug(struct dock_dependent_device *dd, int ret = 0; mutex_lock(&hotplug_lock); - - if (dd->hp_context) { + if (WARN_ON(dd->hp_context)) { ret = -EEXIST; } else { dd->hp_refcount = 1; dd->hp_ops = ops; dd->hp_context = context; dd->hp_release = release; + if (init) + init(context); } - - if (!WARN_ON(ret) && init) - init(context); - mutex_unlock(&hotplug_lock); return ret; } @@ -157,22 +154,17 @@ static int dock_init_hotplug(struct dock_dependent_device *dd, */ static void dock_release_hotplug(struct dock_dependent_device *dd) { - void (*release)(void *) = NULL; - void *context = NULL; - mutex_lock(&hotplug_lock); - if (dd->hp_context && !--dd->hp_refcount) { + void (*release)(void *) = dd->hp_release; + void *context = dd->hp_context; + dd->hp_ops = NULL; - context = dd->hp_context; dd->hp_context = NULL; - release = dd->hp_release; dd->hp_release = NULL; + if (release) + release(context); } - - if (release && context) - release(context); - mutex_unlock(&hotplug_lock); } From 59401ccce8729e5c43f9781cc5570da5ca470e27 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:48:49 +0200 Subject: [PATCH 0242/6183] ACPI / dock: Rework the handling of notifications The ACPI dock driver uses register_acpi_bus_notifier() which installs a notifier triggered globally for all system notifications. That first of all is inefficient, because the dock driver is only interested in notifications associated with the devices it handles, but it has to handle all system notifies for all devices. Moreover, it does that even if no docking stations are present in the system (CONFIG_ACPI_DOCK set is sufficient for that to happen). Besides, that is inconvenient, because it requires the driver to do extra work for each notification to find the target dock station object. For these reasons, rework the dock driver to install a notify handler individually for each dock station in the system using acpi_install_notify_handler(). This allows the dock station object to be passed directly to the notify handler and makes it possible to simplify the dock driver quite a bit. It also reduces the overhead related to the handling of all system notifies when CONFIG_ACPI_DOCK is set. Signed-off-by: Rafael J. Wysocki Acked-by: Yinghai Lu --- drivers/acpi/dock.c | 67 ++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index b1170d60a836..a326c7993f4f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -607,18 +607,17 @@ static int handle_eject_request(struct dock_station *ds, u32 event) /** * dock_notify - act upon an acpi dock notification - * @handle: the dock station handle + * @ds: dock station * @event: the acpi event - * @data: our driver data struct * * If we are notified to dock, then check to see if the dock is * present and then dock. Notify all drivers of the dock event, * and then hotplug and devices that may need hotplugging. */ -static void dock_notify(acpi_handle handle, u32 event, void *data) +static void dock_notify(struct dock_station *ds, u32 event) { - struct dock_station *ds = data; - struct acpi_device *tmp; + acpi_handle handle = ds->handle; + struct acpi_device *ad; int surprise_removal = 0; /* @@ -641,8 +640,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle, - &tmp)) { + if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { @@ -679,9 +677,8 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) } struct dock_data { - acpi_handle handle; - unsigned long event; struct dock_station *ds; + u32 event; }; static void acpi_dock_deferred_cb(void *context) @@ -689,52 +686,31 @@ static void acpi_dock_deferred_cb(void *context) struct dock_data *data = context; acpi_scan_lock_acquire(); - dock_notify(data->handle, data->event, data->ds); + dock_notify(data->ds, data->event); acpi_scan_lock_release(); kfree(data); } -static int acpi_dock_notifier_call(struct notifier_block *this, - unsigned long event, void *data) +static void dock_notify_handler(acpi_handle handle, u32 event, void *data) { - struct dock_station *dock_station; - acpi_handle handle = data; + struct dock_data *dd; if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK && event != ACPI_NOTIFY_EJECT_REQUEST) - return 0; + return; - acpi_scan_lock_acquire(); + dd = kmalloc(sizeof(*dd), GFP_KERNEL); + if (dd) { + acpi_status status; - list_for_each_entry(dock_station, &dock_stations, sibling) { - if (dock_station->handle == handle) { - struct dock_data *dd; - acpi_status status; - - dd = kmalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - break; - - dd->handle = handle; - dd->event = event; - dd->ds = dock_station; - status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, - dd); - if (ACPI_FAILURE(status)) - kfree(dd); - - break; - } + dd->ds = data; + dd->event = event; + status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd); + if (ACPI_FAILURE(status)) + kfree(dd); } - - acpi_scan_lock_release(); - return 0; } -static struct notifier_block dock_acpi_notifier = { - .notifier_call = acpi_dock_notifier_call, -}; - /** * find_dock_devices - find devices on the dock station * @handle: the handle of the device we are examining @@ -868,6 +844,7 @@ static int __init dock_add(acpi_handle handle) int ret, id; struct dock_station ds, *dock_station; struct platform_device *dd; + acpi_status status; id = dock_station_count; memset(&ds, 0, sizeof(ds)); @@ -908,6 +885,11 @@ static int __init dock_add(acpi_handle handle) if (ret) goto err_rmgroup; + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + dock_notify_handler, dock_station); + if (ACPI_FAILURE(status)) + goto err_rmgroup; + dock_station_count++; list_add(&dock_station->sibling, &dock_stations); return 0; @@ -953,7 +935,6 @@ void __init acpi_dock_init(void) } ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); - register_acpi_bus_notifier(&dock_acpi_notifier); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } From f716fc2ac037c45a6c641eb9f20ec602e8d04e14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:49:55 +0200 Subject: [PATCH 0243/6183] ACPI: Drop ACPI bus notifier call chain There are no users of the ACPI bus notifier call chain, acpi_bus_notify_list, any more, so drop it. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 16 ---------------- include/acpi/acpi_bus.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5a032e2344e..6fd27a9abcda 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -499,19 +499,6 @@ static void acpi_bus_check_scope(acpi_handle handle) */ } -static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list); -int register_acpi_bus_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&acpi_bus_notify_list, nb); -} -EXPORT_SYMBOL_GPL(register_acpi_bus_notifier); - -void unregister_acpi_bus_notifier(struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier); - /** * acpi_bus_notify * --------------- @@ -525,9 +512,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n", type, handle)); - blocking_notifier_call_chain(&acpi_bus_notify_list, - type, (void *)handle); - switch (type) { case ACPI_NOTIFY_BUS_CHECK: diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index facc0ba6dd21..71f3fd429fd1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -366,8 +366,6 @@ extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int register_acpi_notifier(struct notifier_block *); extern int unregister_acpi_notifier(struct notifier_block *); -extern int register_acpi_bus_notifier(struct notifier_block *nb); -extern void unregister_acpi_bus_notifier(struct notifier_block *nb); /* * External Functions */ From a30c4c5ee85680bb66ed8a6c0b0bf4921125c378 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Jun 2013 23:50:24 +0200 Subject: [PATCH 0244/6183] ACPI / dock: Do not leak memory on falilures to add a dock station The function creating and registering dock station objects, dock_add(), leaks memory if there's an error after it's walked the ACPI namespace calling find_dock_devices(), because it doesn't free the list of dependent devices it's just created in those cases. Fix that issue by adding the missing code to free the list of dependent devices on errors. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index a326c7993f4f..3e20b13fa272 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -115,6 +115,16 @@ add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) return 0; } +static void remove_dock_dependent_devices(struct dock_station *ds) +{ + struct dock_dependent_device *dd, *aux; + + list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) { + list_del(&dd->list); + kfree(dd); + } +} + /** * dock_init_hotplug - Initialize a hotplug device on a docking station. * @dd: Dock-dependent device. @@ -895,6 +905,7 @@ static int __init dock_add(acpi_handle handle) return 0; err_rmgroup: + remove_dock_dependent_devices(dock_station); sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); err_unregister: platform_device_unregister(dd); From e6c215f15a1cbf4cdd6996d95fba0c0d6c0f3ccc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:02:25 +0200 Subject: [PATCH 0245/6183] ACPI / dock: Do not check CONFIG_ACPI_DOCK_MODULE Since commit 94add0f (ACPI / dock: Initialize ACPI dock subsystem upfront) the ACPI dock driver cannot be a module, so CONFIG_ACPI_DOCK_MODULE is never set. For this reason, simplify the preprocessor conditional in include/acpi/acpi_drivers.h referring to that sybbol unnecessarily. Signed-off-by: Rafael J. Wysocki --- include/acpi/acpi_drivers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index b420939f5eb5..0cf85786ed21 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -117,7 +117,7 @@ struct acpi_dock_ops { acpi_notify_handler uevent; }; -#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE) +#ifdef CONFIG_ACPI_DOCK extern int is_dock_device(acpi_handle handle); extern int register_dock_notifier(struct notifier_block *nb); extern void unregister_dock_notifier(struct notifier_block *nb); @@ -150,6 +150,6 @@ static inline int register_hotplug_dock_device(acpi_handle handle, static inline void unregister_hotplug_dock_device(acpi_handle handle) { } -#endif +#endif /* CONFIG_ACPI_DOCK */ #endif /*__ACPI_DRIVERS_H__*/ From f09ce741a03ad7de591aa47e760fbeee28567b63 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:03:25 +0200 Subject: [PATCH 0246/6183] ACPI / dock / PCI: Drop ACPI dock notifier chain The only user of the ACPI dock notifier chain is the ACPI-based PCI hotplug (acpiphp) driver that uses it to carry out post-dock fixups needed by some systems with broken _DCK. However, it is not necessary to use a separate notifier chain for that, as it can be simply replaced with a new callback in struct acpi_dock_ops. For this reason, add a new .fixup() callback to struct acpi_dock_ops and make hotplug_dock_devices() execute it for all dock devices with hotplug operations registered. Accordingly, make acpiphp point that callback to the function carrying out the post-dock fixups and do not register a separate dock notifier for each device registering dock operations. Finally, drop the ACPI dock notifier chain that has no more users. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 66 +++++++++++------------------- drivers/pci/hotplug/acpiphp.h | 1 - drivers/pci/hotplug/acpiphp_glue.c | 18 ++------ include/acpi/acpi_drivers.h | 10 +---- 4 files changed, 30 insertions(+), 65 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 3e20b13fa272..c89a9c3b48b4 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -51,8 +51,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " " the driver to wait for userspace to write the undock sysfs file " " before undocking"); -static struct atomic_notifier_head dock_notifier_list; - static const struct acpi_device_id dock_device_ids[] = { {"LNXDOCK", 0}, {"", 0}, @@ -89,6 +87,12 @@ struct dock_dependent_device { #define DOCK_EVENT 3 #define UNDOCK_EVENT 2 +enum dock_callback_type { + DOCK_CALL_HANDLER, + DOCK_CALL_FIXUP, + DOCK_CALL_UEVENT, +}; + /***************************************************************************** * Dock Dependent device functions * *****************************************************************************/ @@ -179,7 +183,7 @@ static void dock_release_hotplug(struct dock_dependent_device *dd) } static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, - bool uevent) + enum dock_callback_type cb_type) { acpi_notify_handler cb = NULL; bool run = false; @@ -189,8 +193,18 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event, if (dd->hp_context) { run = true; dd->hp_refcount++; - if (dd->hp_ops) - cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler; + if (dd->hp_ops) { + switch (cb_type) { + case DOCK_CALL_FIXUP: + cb = dd->hp_ops->fixup; + break; + case DOCK_CALL_UEVENT: + cb = dd->hp_ops->uevent; + break; + default: + cb = dd->hp_ops->handler; + } + } } mutex_unlock(&hotplug_lock); @@ -372,9 +386,13 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) { struct dock_dependent_device *dd; + /* Call driver specific post-dock fixups. */ + list_for_each_entry(dd, &ds->dependent_devices, list) + dock_hotplug_event(dd, event, DOCK_CALL_FIXUP); + /* Call driver specific hotplug functions. */ list_for_each_entry(dd, &ds->dependent_devices, list) - dock_hotplug_event(dd, event, false); + dock_hotplug_event(dd, event, DOCK_CALL_HANDLER); /* * Now make sure that an acpi_device is created for each dependent @@ -405,7 +423,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); list_for_each_entry(dd, &ds->dependent_devices, list) - dock_hotplug_event(dd, event, true); + dock_hotplug_event(dd, event, DOCK_CALL_UEVENT); if (num != DOCK_EVENT) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); @@ -487,37 +505,6 @@ static int dock_in_progress(struct dock_station *ds) return 0; } -/** - * register_dock_notifier - add yourself to the dock notifier list - * @nb: the callers notifier block - * - * If a driver wishes to be notified about dock events, they can - * use this function to put a notifier block on the dock notifier list. - * this notifier call chain will be called after a dock event, but - * before hotplugging any new devices. - */ -int register_dock_notifier(struct notifier_block *nb) -{ - if (!dock_station_count) - return -ENODEV; - - return atomic_notifier_chain_register(&dock_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(register_dock_notifier); - -/** - * unregister_dock_notifier - remove yourself from the dock notifier list - * @nb: the callers notifier block - */ -void unregister_dock_notifier(struct notifier_block *nb) -{ - if (!dock_station_count) - return; - - atomic_notifier_chain_unregister(&dock_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_dock_notifier); - /** * register_hotplug_dock_device - register a hotplug function * @handle: the handle of the device @@ -658,8 +645,6 @@ static void dock_notify(struct dock_station *ds, u32 event) complete_dock(ds); break; } - atomic_notifier_call_chain(&dock_notifier_list, - event, NULL); hotplug_dock_devices(ds, event); complete_dock(ds); dock_event(ds, event, DOCK_EVENT); @@ -945,7 +930,6 @@ void __init acpi_dock_init(void) return; } - ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); } diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 6fdd49c6f0b9..6c781edabcc6 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -122,7 +122,6 @@ struct acpiphp_func { struct acpiphp_slot *slot; /* parent */ struct list_head sibling; - struct notifier_block nb; acpi_handle handle; u8 function; /* pci function# */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a0a7133a1d12..8bfad0dc29ab 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -119,15 +119,14 @@ static void free_bridge(struct kref *kref) * TBD - figure out a way to only call fixups for * systems that require them. */ -static int post_dock_fixups(struct notifier_block *nb, unsigned long val, - void *v) +static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) { - struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb); + struct acpiphp_func *func = data; struct pci_bus *bus = func->slot->bridge->pci_bus; u32 buses; if (!bus->self) - return NOTIFY_OK; + return; /* fixup bad _DCK function that rewrites * secondary bridge on slot @@ -143,11 +142,11 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, | ((unsigned int)(bus->busn_res.end) << 16); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); } - return NOTIFY_OK; } static const struct acpi_dock_ops acpiphp_dock_ops = { + .fixup = post_dock_fixups, .handler = hotplug_event_func, }; @@ -315,14 +314,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) &acpiphp_dock_ops, newfunc, acpiphp_dock_init, acpiphp_dock_release)) dbg("failed to register dock device\n"); - - /* we need to be notified when dock events happen - * outside of the hotplug operation, since we may - * need to do fixups before we can hotplug. - */ - newfunc->nb.notifier_call = post_dock_fixups; - if (register_dock_notifier(&newfunc->nb)) - dbg("failed to register a dock notifier"); } /* install notify handler */ @@ -472,7 +463,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) list_for_each_entry(func, &slot->funcs, sibling) { if (is_dock_device(func->handle)) { unregister_hotplug_dock_device(func->handle); - unregister_dock_notifier(&func->nb); } if (!(func->flags & FUNC_HAS_DCK)) { status = acpi_remove_notify_handler(func->handle, diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 0cf85786ed21..1cedfcb1bd88 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -113,14 +113,13 @@ void pci_acpi_crs_quirks(void); Dock Station -------------------------------------------------------------------------- */ struct acpi_dock_ops { + acpi_notify_handler fixup; acpi_notify_handler handler; acpi_notify_handler uevent; }; #ifdef CONFIG_ACPI_DOCK extern int is_dock_device(acpi_handle handle); -extern int register_dock_notifier(struct notifier_block *nb); -extern void unregister_dock_notifier(struct notifier_block *nb); extern int register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context, @@ -132,13 +131,6 @@ static inline int is_dock_device(acpi_handle handle) { return 0; } -static inline int register_dock_notifier(struct notifier_block *nb) -{ - return -ENODEV; -} -static inline void unregister_dock_notifier(struct notifier_block *nb) -{ -} static inline int register_hotplug_dock_device(acpi_handle handle, const struct acpi_dock_ops *ops, void *context, From 2efbca4dfc7b43951de6dd1647f9eebda9d4372b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 5 Jul 2013 03:23:36 +0200 Subject: [PATCH 0247/6183] ACPI / dock: Drop unnecessary local variable from dock_add() The local variable id in dock_add() is not necessary, so drop it. While we're at it, use an initializer to clear the local variable ds and drop the memset() used for this purpose. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/dock.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c89a9c3b48b4..f601658a4ad2 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -836,14 +836,13 @@ static struct attribute_group dock_attribute_group = { */ static int __init dock_add(acpi_handle handle) { - int ret, id; - struct dock_station ds, *dock_station; + struct dock_station *dock_station, ds = { NULL, }; struct platform_device *dd; acpi_status status; + int ret; - id = dock_station_count; - memset(&ds, 0, sizeof(ds)); - dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds)); + dd = platform_device_register_data(NULL, "dock", dock_station_count, + &ds, sizeof(ds)); if (IS_ERR(dd)) return PTR_ERR(dd); From 137b944e100278d696826cf25c83014ac17473fe Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:48 +0200 Subject: [PATCH 0248/6183] cpuidle: Make it clear that governors cannot be modules cpufreq governors are defined as modules in the code, but the Kconfig options do not allow them to be built as modules. This is not really a problem, but the cpuidle init ordering is: the cpuidle init functions (framework and driver) and then the governors. That leads to some weirdness in the cpuidle framework. Namely, cpuidle_register_device() calls cpuidle_enable_device() which fails at the first attempt, because governors have not been registered yet. When a governor is registered, the framework calls cpuidle_enable_device() again which runs __cpuidle_register_device() only then. Of course, for that to work, the cpuidle_enable_device() return value has to be ignored by cpuidle_register_device(). Instead of having this cyclic call graph and relying on a positive side effects of the hackish back and forth cpuidle_enable_device() calls it is better to fix the cpuidle init ordering. To that end, replace the module init code with postcore_initcall() so we have: * cpuidle framework : core_initcall * cpuidle governors : postcore_initcall * cpuidle drivers : device_initcall and remove the corresponding module exit code as it is dead anyway (governors can't be built as modules). [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/ladder.c | 12 +----------- drivers/cpuidle/governors/menu.c | 12 +----------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 9b784051ec12..9f08e8cce1af 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -192,14 +192,4 @@ static int __init init_ladder(void) return cpuidle_register_governor(&ladder_governor); } -/** - * exit_ladder - exits the governor - */ -static void __exit exit_ladder(void) -{ - cpuidle_unregister_governor(&ladder_governor); -} - -MODULE_LICENSE("GPL"); -module_init(init_ladder); -module_exit(exit_ladder); +postcore_initcall(init_ladder); diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index fe343a06b7da..743138c309a1 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -540,14 +540,4 @@ static int __init init_menu(void) return cpuidle_register_governor(&menu_governor); } -/** - * exit_menu - exits the governor - */ -static void __exit exit_menu(void) -{ - cpuidle_unregister_governor(&menu_governor); -} - -MODULE_LICENSE("GPL"); -module_init(init_menu); -module_exit(exit_menu); +postcore_initcall(init_menu); From 10b9d3f8a4d5c82bff5b232a0063669dc0e0d725 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:49 +0200 Subject: [PATCH 0249/6183] cpuidle: Check cpuidle_enable_device() return value We previously changed the ordering of the cpuidle framework initialization so that the governors are registered before the drivers which can register their devices right from the start. Now, we can safely remove the __cpuidle_register_device() call hack in cpuidle_enable_device() and check if the driver has been registered before enabling it. Then, cpuidle_register_device() can consistently check the cpuidle_enable_device() return value when enabling the device. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index fdc432f18022..4deed977f209 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -292,15 +292,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev) if (!drv || !cpuidle_curr_governor) return -EIO; + if (!dev->registered) + return -EINVAL; + if (!dev->state_count) dev->state_count = drv->state_count; - if (dev->registered == 0) { - ret = __cpuidle_register_device(dev); - if (ret) - return ret; - } - poll_idle_init(drv); ret = cpuidle_add_device_sysfs(dev); @@ -415,13 +412,17 @@ int cpuidle_register_device(struct cpuidle_device *dev) return ret; } - cpuidle_enable_device(dev); + ret = cpuidle_enable_device(dev); + if (ret) { + mutex_unlock(&cpuidle_lock); + return ret; + } + cpuidle_install_idle_handler(); mutex_unlock(&cpuidle_lock); return 0; - } EXPORT_SYMBOL_GPL(cpuidle_register_device); From f89ae89e2790341587f7132f0552c941342115e9 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:50 +0200 Subject: [PATCH 0250/6183] cpuidle: Fix white space to follow CodingStyle Fix white space in the cpuidle code to follow the rules described in CodingStyle. No changes in behavior should result from this. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/sysfs.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 428754af6236..7d4448a9fbbd 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -33,7 +33,8 @@ static ssize_t show_available_governors(struct device *dev, mutex_lock(&cpuidle_lock); list_for_each_entry(tmp, &cpuidle_governors, governor_list) { - if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2)) + if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - + CPUIDLE_NAME_LEN - 2)) goto out; i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name); } @@ -168,11 +169,13 @@ struct cpuidle_attr { #define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj) #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) -static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf) + +static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, + char *buf) { int ret = -EIO; struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); - struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr); + struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->show) { mutex_lock(&cpuidle_lock); @@ -182,12 +185,12 @@ static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char return ret; } -static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { int ret = -EIO; struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); - struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr); + struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->store) { mutex_lock(&cpuidle_lock); @@ -237,8 +240,8 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ #define define_store_state_ull_function(_name) \ static ssize_t store_state_##_name(struct cpuidle_state *state, \ - struct cpuidle_state_usage *state_usage, \ - const char *buf, size_t size) \ + struct cpuidle_state_usage *state_usage, \ + const char *buf, size_t size) \ { \ unsigned long long value; \ int err; \ @@ -256,14 +259,16 @@ static ssize_t store_state_##_name(struct cpuidle_state *state, \ #define define_show_state_ull_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ - struct cpuidle_state_usage *state_usage, char *buf) \ + struct cpuidle_state_usage *state_usage, \ + char *buf) \ { \ return sprintf(buf, "%llu\n", state_usage->_name);\ } #define define_show_state_str_function(_name) \ static ssize_t show_state_##_name(struct cpuidle_state *state, \ - struct cpuidle_state_usage *state_usage, char *buf) \ + struct cpuidle_state_usage *state_usage, \ + char *buf) \ { \ if (state->_name[0] == '\0')\ return sprintf(buf, "\n");\ @@ -309,8 +314,9 @@ struct cpuidle_state_kobj { #define kobj_to_state(k) (kobj_to_state_obj(k)->state) #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) -static ssize_t cpuidle_state_show(struct kobject * kobj, - struct attribute * attr ,char * buf) + +static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr, + char * buf) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); @@ -323,8 +329,8 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, return ret; } -static ssize_t cpuidle_state_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t size) +static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); @@ -449,8 +455,8 @@ static void cpuidle_driver_sysfs_release(struct kobject *kobj) complete(&driver_kobj->kobj_unregister); } -static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr, - char * buf) +static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr, + char *buf) { int ret = -EIO; struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); From 728ce22b696f9f1404a74d7b2279a65933553a1b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:51 +0200 Subject: [PATCH 0251/6183] cpuidle: Make cpuidle's sysfs directory dynamically allocated The cpuidle sysfs code is designed to have a single instance of per CPU cpuidle directory. It is not possible to remove the sysfs entry and create it again. This is not a problem with the current code but future changes will add CPU hotplug support to enable/disable the device, so it will need to remove the sysfs entry like other subsystems do. That won't be possible without this change, because the kobj is a static object which can't be reused for kobj_init_and_add(). Add cpuidle_device_kobj to be allocated dynamically when adding/removing a sysfs entry which is consistent with the other cpuidle's sysfs entries. An added benefit is that the sysfs code is now more self-contained and the includes needed for sysfs can be moved from cpuidle.h directly into sysfs.c so as to reduce the total number of headers dragged along with cpuidle.h. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/sysfs.c | 63 +++++++++++++++++++++++++++++++---------- include/linux/cpuidle.h | 7 ++--- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 7d4448a9fbbd..8739cc05228c 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -11,8 +11,10 @@ #include #include #include +#include #include #include +#include #include "cpuidle.h" @@ -167,14 +169,27 @@ struct cpuidle_attr { #define define_one_rw(_name, show, store) \ static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store) -#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj) #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) +struct cpuidle_device_kobj { + struct cpuidle_device *dev; + struct completion kobj_unregister; + struct kobject kobj; +}; + +static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj) +{ + struct cpuidle_device_kobj *kdev = + container_of(kobj, struct cpuidle_device_kobj, kobj); + + return kdev->dev; +} + static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, char *buf) { int ret = -EIO; - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); + struct cpuidle_device *dev = to_cpuidle_device(kobj); struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->show) { @@ -189,7 +204,7 @@ static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { int ret = -EIO; - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); + struct cpuidle_device *dev = to_cpuidle_device(kobj); struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); if (cattr->store) { @@ -207,9 +222,10 @@ static const struct sysfs_ops cpuidle_sysfs_ops = { static void cpuidle_sysfs_release(struct kobject *kobj) { - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); + struct cpuidle_device_kobj *kdev = + container_of(kobj, struct cpuidle_device_kobj, kobj); - complete(&dev->kobj_unregister); + complete(&kdev->kobj_unregister); } static struct kobj_type ktype_cpuidle = { @@ -377,6 +393,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; + struct cpuidle_device_kobj *kdev = device->kobj_dev; struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); /* state statistics */ @@ -389,7 +406,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) init_completion(&kobj->kobj_unregister); ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, - &device->kobj, "state%d", i); + &kdev->kobj, "state%d", i); if (ret) { kfree(kobj); goto error_state; @@ -506,6 +523,7 @@ static struct kobj_type ktype_driver_cpuidle = { static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) { struct cpuidle_driver_kobj *kdrv; + struct cpuidle_device_kobj *kdev = dev->kobj_dev; struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); int ret; @@ -517,7 +535,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) init_completion(&kdrv->kobj_unregister); ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, - &dev->kobj, "driver"); + &kdev->kobj, "driver"); if (ret) { kfree(kdrv); return ret; @@ -586,16 +604,28 @@ void cpuidle_remove_device_sysfs(struct cpuidle_device *device) */ int cpuidle_add_sysfs(struct cpuidle_device *dev) { + struct cpuidle_device_kobj *kdev; struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; - init_completion(&dev->kobj_unregister); + kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); + if (!kdev) + return -ENOMEM; + kdev->dev = dev; + dev->kobj_dev = kdev; - error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, - "cpuidle"); - if (!error) - kobject_uevent(&dev->kobj, KOBJ_ADD); - return error; + init_completion(&kdev->kobj_unregister); + + error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj, + "cpuidle"); + if (error) { + kfree(kdev); + return error; + } + + kobject_uevent(&kdev->kobj, KOBJ_ADD); + + return 0; } /** @@ -604,6 +634,9 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) */ void cpuidle_remove_sysfs(struct cpuidle_device *dev) { - kobject_put(&dev->kobj); - wait_for_completion(&dev->kobj_unregister); + struct cpuidle_device_kobj *kdev = dev->kobj_dev; + + kobject_put(&kdev->kobj); + wait_for_completion(&kdev->kobj_unregister); + kfree(kdev); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 0bc4b74668e9..b922db53b7ab 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -13,8 +13,6 @@ #include #include -#include -#include #include #define CPUIDLE_STATE_MAX 10 @@ -61,6 +59,8 @@ struct cpuidle_state { #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) +struct cpuidle_device_kobj; + struct cpuidle_device { unsigned int registered:1; unsigned int enabled:1; @@ -71,9 +71,8 @@ struct cpuidle_device { struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; struct cpuidle_driver_kobj *kobj_driver; + struct cpuidle_device_kobj *kobj_dev; struct list_head device_list; - struct kobject kobj; - struct completion kobj_unregister; #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED int safe_state_index; From 1a7064380e6639e1cc5ed609ceb1ed46f3f188e3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:52 +0200 Subject: [PATCH 0252/6183] cpuidle: Add missing forward declarations of structures Add missing forward declarations of struct cpuidle_state_kobj and struct cpuidle_driver_kobj in cpuidle.h. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- include/linux/cpuidle.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index b922db53b7ab..781addc66f03 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -60,6 +60,8 @@ struct cpuidle_state { #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) struct cpuidle_device_kobj; +struct cpuidle_state_kobj; +struct cpuidle_driver_kobj; struct cpuidle_device { unsigned int registered:1; From f6bb51a53a7535c79d6c65862d6b48e83340b337 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:53 +0200 Subject: [PATCH 0253/6183] cpuidle: Introduce __cpuidle_unregister_device() To reduce code duplication related to the unregistration of cpuidle devices, introduce __cpuidle_unregister_device() and move all of the unregistration code to that function. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 62 ++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 4deed977f209..d78c6d89272f 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -42,8 +42,6 @@ void disable_cpuidle(void) off = 1; } -static int __cpuidle_register_device(struct cpuidle_device *dev); - /** * cpuidle_play_dead - cpu off-lining * @@ -357,6 +355,15 @@ void cpuidle_disable_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_disable_device); +static void __cpuidle_unregister_device(struct cpuidle_device *dev) +{ + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + + list_del(&dev->device_list); + per_cpu(cpuidle_devices, dev->cpu) = NULL; + module_put(drv->owner); +} + /** * __cpuidle_register_device - internal register function called before register * and enable routines @@ -374,24 +381,15 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); - ret = cpuidle_add_sysfs(dev); - if (ret) - goto err_sysfs; ret = cpuidle_coupled_register_device(dev); - if (ret) - goto err_coupled; + if (ret) { + __cpuidle_unregister_device(dev); + return ret; + } dev->registered = 1; return 0; - -err_coupled: - cpuidle_remove_sysfs(dev); -err_sysfs: - list_del(&dev->device_list); - per_cpu(cpuidle_devices, dev->cpu) = NULL; - module_put(drv->owner); - return ret; } /** @@ -407,22 +405,30 @@ int cpuidle_register_device(struct cpuidle_device *dev) mutex_lock(&cpuidle_lock); - if ((ret = __cpuidle_register_device(dev))) { - mutex_unlock(&cpuidle_lock); - return ret; - } + ret = __cpuidle_register_device(dev); + if (ret) + goto out_unlock; + + ret = cpuidle_add_sysfs(dev); + if (ret) + goto out_unregister; ret = cpuidle_enable_device(dev); - if (ret) { - mutex_unlock(&cpuidle_lock); - return ret; - } + if (ret) + goto out_sysfs; cpuidle_install_idle_handler(); +out_unlock: mutex_unlock(&cpuidle_lock); - return 0; + return ret; + +out_sysfs: + cpuidle_remove_sysfs(dev); +out_unregister: + __cpuidle_unregister_device(dev); + goto out_unlock; } EXPORT_SYMBOL_GPL(cpuidle_register_device); @@ -433,8 +439,6 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device); */ void cpuidle_unregister_device(struct cpuidle_device *dev) { - struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - if (dev->registered == 0) return; @@ -443,14 +447,12 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) cpuidle_disable_device(dev); cpuidle_remove_sysfs(dev); - list_del(&dev->device_list); - per_cpu(cpuidle_devices, dev->cpu) = NULL; + + __cpuidle_unregister_device(dev); cpuidle_coupled_unregister_device(dev); cpuidle_resume_and_unlock(); - - module_put(drv->owner); } EXPORT_SYMBOL_GPL(cpuidle_unregister_device); From 5df0aa7341bd94ca2023a60c64c63faeb6ec209d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:54 +0200 Subject: [PATCH 0254/6183] cpuidle: Introduce __cpuidle_device_init() Add __cpuidle_device_init() for initializing the cpuidle_device structure. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index d78c6d89272f..5b63185da59b 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -276,7 +276,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} */ int cpuidle_enable_device(struct cpuidle_device *dev) { - int ret, i; + int ret; struct cpuidle_driver *drv; if (!dev) @@ -306,12 +306,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev) (ret = cpuidle_curr_governor->enable(drv, dev))) goto fail_sysfs; - for (i = 0; i < dev->state_count; i++) { - dev->states_usage[i].usage = 0; - dev->states_usage[i].time = 0; - } - dev->last_residency = 0; - smp_wmb(); dev->enabled = 1; @@ -364,6 +358,14 @@ static void __cpuidle_unregister_device(struct cpuidle_device *dev) module_put(drv->owner); } +static int __cpuidle_device_init(struct cpuidle_device *dev) +{ + memset(dev->states_usage, 0, sizeof(dev->states_usage)); + dev->last_residency = 0; + + return 0; +} + /** * __cpuidle_register_device - internal register function called before register * and enable routines @@ -405,6 +407,10 @@ int cpuidle_register_device(struct cpuidle_device *dev) mutex_lock(&cpuidle_lock); + ret = __cpuidle_device_init(dev); + if (ret) + goto out_unlock; + ret = __cpuidle_register_device(dev); if (ret) goto out_unlock; From c878a52d3c7cabab5b24460825c24eafd8be7058 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 12 Jun 2013 15:08:55 +0200 Subject: [PATCH 0255/6183] cpuidle: Check if device is already registered Make __cpuidle_register_device() check whether or not the device has been registered already and return -EBUSY immediately if that's the case. [rjw: Changelog] Signed-off-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 5b63185da59b..d75040ddd2b3 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -400,13 +400,16 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) */ int cpuidle_register_device(struct cpuidle_device *dev) { - int ret; + int ret = -EBUSY; if (!dev) return -EINVAL; mutex_lock(&cpuidle_lock); + if (dev->registered) + goto out_unlock; + ret = __cpuidle_device_init(dev); if (ret) goto out_unlock; From 6e8b8726ad503214ba66e34aed69aff41de33489 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:19:32 +0930 Subject: [PATCH 0256/6183] PTR_RET is now PTR_ERR_OR_ZERO True, it's often used in return statements, but after much bikeshedding it's probably better to have an explicit name. (I tried just putting the IS_ERR check inside PTR_ERR itself and gcc usually generated no more code. But that clashes current expectations of how PTR_ERR behaves, so having a separate function is better). Suggested-by: Julia Lawall Suggested-by: "Michael S. Tsirkin" Cc: Julia Lawall Cc: "Michael S. Tsirkin" Signed-off-by: Rusty Russell --- include/linux/err.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/err.h b/include/linux/err.h index 221fcfb676c4..15f92e072450 100644 --- a/include/linux/err.h +++ b/include/linux/err.h @@ -52,7 +52,7 @@ static inline void * __must_check ERR_CAST(__force const void *ptr) return (void *) ptr; } -static inline int __must_check PTR_RET(__force const void *ptr) +static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr) { if (IS_ERR(ptr)) return PTR_ERR(ptr); @@ -60,6 +60,9 @@ static inline int __must_check PTR_RET(__force const void *ptr) return 0; } +/* Deprecated */ +#define PTR_RET(p) PTR_ERR_OR_ZERO(p) + #endif #endif /* _LINUX_ERR_H */ From 8c6ffba0eddc8c110dbf444f51354ce42069abfc Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:20:32 +0930 Subject: [PATCH 0257/6183] PTR_RET is now PTR_ERR_OR_ZERO(): Replace most. Sweep of the simple cases. Cc: netdev@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-arm-kernel@lists.infradead.org Cc: Julia Lawall Signed-off-by: Rusty Russell Acked-by: David S. Miller Acked-by: Benjamin Herrenschmidt --- arch/arm/mach-omap2/i2c.c | 2 +- arch/m68k/amiga/platform.c | 2 +- arch/m68k/kernel/time.c | 2 +- arch/m68k/q40/config.c | 2 +- arch/powerpc/kernel/iommu.c | 2 +- arch/powerpc/kernel/time.c | 2 +- arch/powerpc/platforms/ps3/time.c | 2 +- arch/powerpc/sysdev/rtc_cmos_setup.c | 2 +- arch/s390/hypfs/hypfs_dbfs.c | 2 +- drivers/char/tile-srom.c | 2 +- drivers/infiniband/core/cma.c | 2 +- drivers/net/appletalk/cops.c | 2 +- drivers/net/appletalk/ltpc.c | 2 +- drivers/net/ethernet/amd/atarilance.c | 2 +- drivers/net/ethernet/amd/mvme147.c | 2 +- drivers/net/ethernet/amd/ni65.c | 2 +- drivers/net/ethernet/amd/sun3lance.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c | 2 +- drivers/net/wireless/brcm80211/brcmsmac/debug.c | 2 +- drivers/platform/x86/samsung-q10.c | 2 +- drivers/regulator/fan53555.c | 2 +- drivers/spi/spi-fsl-spi.c | 2 +- drivers/spi/spidev.c | 2 +- drivers/video/omap2/dss/core.c | 2 +- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/inode.c | 2 +- net/bluetooth/hci_sysfs.c | 2 +- net/bridge/netfilter/ebtable_broute.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 2 +- net/bridge/netfilter/ebtable_nat.c | 2 +- net/ipv4/netfilter/arptable_filter.c | 2 +- net/ipv4/netfilter/iptable_filter.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 2 +- net/ipv4/netfilter/iptable_nat.c | 2 +- net/ipv4/netfilter/iptable_raw.c | 2 +- net/ipv4/netfilter/iptable_security.c | 2 +- net/ipv6/netfilter/ip6table_filter.c | 2 +- net/ipv6/netfilter/ip6table_mangle.c | 2 +- net/ipv6/netfilter/ip6table_nat.c | 2 +- net/ipv6/netfilter/ip6table_raw.c | 2 +- net/ipv6/netfilter/ip6table_security.c | 2 +- scripts/coccinelle/api/ptr_ret.cocci | 10 +++++----- sound/soc/soc-io.c | 2 +- 43 files changed, 47 insertions(+), 47 deletions(-) diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c index d940e53dd9f2..b456b4471f35 100644 --- a/arch/arm/mach-omap2/i2c.c +++ b/arch/arm/mach-omap2/i2c.c @@ -181,7 +181,7 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata, sizeof(struct omap_i2c_bus_platform_data)); WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name); - return PTR_RET(pdev); + return PTR_ERR_OR_ZERO(pdev); } static int __init omap_i2c_cmdline(void) diff --git a/arch/m68k/amiga/platform.c b/arch/m68k/amiga/platform.c index 6083088c0cca..dacd9f911f71 100644 --- a/arch/m68k/amiga/platform.c +++ b/arch/m68k/amiga/platform.c @@ -56,7 +56,7 @@ static int __init amiga_init_bus(void) n = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2; pdev = platform_device_register_simple("amiga-zorro", -1, zorro_resources, n); - return PTR_RET(pdev); + return PTR_ERR_OR_ZERO(pdev); } subsys_initcall(amiga_init_bus); diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index bea6bcf8f9b8..7eb9792009f8 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -90,7 +90,7 @@ static int __init rtc_init(void) return -ENODEV; pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); - return PTR_RET(pdev); + return PTR_ERR_OR_ZERO(pdev); } module_init(rtc_init); diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 658542b914fc..078bb744b5fe 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c @@ -338,6 +338,6 @@ static __init int q40_add_kbd_device(void) return -ENODEV; pdev = platform_device_register_simple("q40kbd", -1, NULL, 0); - return PTR_RET(pdev); + return PTR_ERR_OR_ZERO(pdev); } arch_initcall(q40_add_kbd_device); diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index b20ff173a671..0adab06ce5c0 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -105,7 +105,7 @@ static int __init fail_iommu_debugfs(void) struct dentry *dir = fault_create_debugfs_attr("fail_iommu", NULL, &fail_iommu); - return PTR_RET(dir); + return PTR_ERR_OR_ZERO(dir); } late_initcall(fail_iommu_debugfs); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 65ab9e909377..cdcc156865ef 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -1049,7 +1049,7 @@ static int __init rtc_init(void) pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); - return PTR_RET(pdev); + return PTR_ERR_OR_ZERO(pdev); } module_init(rtc_init); diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c index cba1e6be68e5..ce73ce865613 100644 --- a/arch/powerpc/platforms/ps3/time.c +++ b/arch/powerpc/platforms/ps3/time.c @@ -90,7 +90,7 @@ static int __init ps3_rtc_init(void) pdev = platform_device_register_simple("rtc-ps3", -1, NULL, 0); - return PTR_RET(pdev); + return PTR_ERR_OR_ZERO(pdev); } module_init(ps3_rtc_init); diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c index af79e1ea74b6..af0f9beddca9 100644 --- a/arch/powerpc/sysdev/rtc_cmos_setup.c +++ b/arch/powerpc/sysdev/rtc_cmos_setup.c @@ -62,7 +62,7 @@ static int __init add_rtc(void) pd = platform_device_register_simple("rtc_cmos", -1, &res[0], num_res); - return PTR_RET(pd); + return PTR_ERR_OR_ZERO(pd); } fs_initcall(add_rtc); diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index bb5dd496614f..17ab8b7b53cc 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -105,7 +105,7 @@ void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) int hypfs_dbfs_init(void) { dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); - return PTR_RET(dbfs_dir); + return PTR_ERR_OR_ZERO(dbfs_dir); } void hypfs_dbfs_exit(void) diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c index 7faeb1cde97d..ce04d6eb23d4 100644 --- a/drivers/char/tile-srom.c +++ b/drivers/char/tile-srom.c @@ -349,7 +349,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index) dev = device_create(srom_class, &platform_bus, MKDEV(srom_major, index), srom, "%d", index); - return PTR_RET(dev); + return PTR_ERR_OR_ZERO(dev); } /** srom_init() - Initialize the driver's module. */ diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index f1c279fabe64..4df360bede81 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -3205,7 +3205,7 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv, id_priv->id.port_num, &rec, comp_mask, GFP_KERNEL, cma_ib_mc_handler, mc); - return PTR_RET(mc->multicast.ib); + return PTR_ERR_OR_ZERO(mc->multicast.ib); } static void iboe_mcast_work_handler(struct work_struct *work) diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index cff6f023c03a..7f2a032c354c 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -996,7 +996,7 @@ static int __init cops_module_init(void) printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", cardname); cops_dev = cops_probe(-1); - return PTR_RET(cops_dev); + return PTR_ERR_OR_ZERO(cops_dev); } static void __exit cops_module_exit(void) diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index b5782cdf0bca..01e2ac55c137 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -1243,7 +1243,7 @@ static int __init ltpc_module_init(void) "ltpc: Autoprobing is not recommended for modules\n"); dev_ltpc = ltpc_probe(); - return PTR_RET(dev_ltpc); + return PTR_ERR_OR_ZERO(dev_ltpc); } module_init(ltpc_module_init); #endif diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c index e8d0ef508f48..10ceca523fc0 100644 --- a/drivers/net/ethernet/amd/atarilance.c +++ b/drivers/net/ethernet/amd/atarilance.c @@ -1147,7 +1147,7 @@ static struct net_device *atarilance_dev; static int __init atarilance_module_init(void) { atarilance_dev = atarilance_probe(-1); - return PTR_RET(atarilance_dev); + return PTR_ERR_OR_ZERO(atarilance_dev); } static void __exit atarilance_module_exit(void) diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c index a51497c9d2af..e108e911da05 100644 --- a/drivers/net/ethernet/amd/mvme147.c +++ b/drivers/net/ethernet/amd/mvme147.c @@ -188,7 +188,7 @@ static struct net_device *dev_mvme147_lance; int __init init_module(void) { dev_mvme147_lance = mvme147lance_probe(-1); - return PTR_RET(dev_mvme147_lance); + return PTR_ERR_OR_ZERO(dev_mvme147_lance); } void __exit cleanup_module(void) diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c index 26fc0ce0faa3..1cf33addd15e 100644 --- a/drivers/net/ethernet/amd/ni65.c +++ b/drivers/net/ethernet/amd/ni65.c @@ -1238,7 +1238,7 @@ MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)"); int __init init_module(void) { dev_ni65 = ni65_probe(-1); - return PTR_RET(dev_ni65); + return PTR_ERR_OR_ZERO(dev_ni65); } void __exit cleanup_module(void) diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c index 4375abe61da1..d6b20296b8e4 100644 --- a/drivers/net/ethernet/amd/sun3lance.c +++ b/drivers/net/ethernet/amd/sun3lance.c @@ -940,7 +940,7 @@ static struct net_device *sun3lance_dev; int __init init_module(void) { sun3lance_dev = sun3lance_probe(-1); - return PTR_RET(sun3lance_dev); + return PTR_ERR_OR_ZERO(sun3lance_dev); } void __exit cleanup_module(void) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index c37b9d68e458..0f9e9057e7dd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -50,7 +50,7 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr) return -ENODEV; drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); - return PTR_RET(drvr->dbgfs_dir); + return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); } void brcmf_debugfs_detach(struct brcmf_pub *drvr) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c index 9761deb46204..a5d4add26f41 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c @@ -56,7 +56,7 @@ int brcms_debugfs_attach(struct brcms_pub *drvr) drvr->dbgfs_dir = debugfs_create_dir( dev_name(&drvr->wlc->hw->d11core->dev), root_folder); - return PTR_RET(drvr->dbgfs_dir); + return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); } void brcms_debugfs_detach(struct brcms_pub *drvr) diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c index 1a90b62a71c6..4430b8c1369d 100644 --- a/drivers/platform/x86/samsung-q10.c +++ b/drivers/platform/x86/samsung-q10.c @@ -176,7 +176,7 @@ static int __init samsungq10_init(void) samsungq10_probe, NULL, 0, NULL, 0); - return PTR_RET(samsungq10_device); + return PTR_ERR_OR_ZERO(samsungq10_device); } static void __exit samsungq10_exit(void) diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index f0e1ae52bb05..192444a8dab0 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -219,7 +219,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->owner = THIS_MODULE; di->rdev = regulator_register(&di->desc, config); - return PTR_RET(di->rdev); + return PTR_ERR_OR_ZERO(di->rdev); } diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 41e89c3e3edc..ca0ddb8cef5c 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -901,7 +901,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) return -EINVAL; master = fsl_spi_probe(&pdev->dev, mem, irq); - return PTR_RET(master); + return PTR_ERR_OR_ZERO(master); } static int plat_mpc8xxx_spi_remove(struct platform_device *pdev) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 911e9e0711d2..ca5bcfe874d0 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -603,7 +603,7 @@ static int spidev_probe(struct spi_device *spi) dev = device_create(spidev_class, &spi->dev, spidev->devt, spidev, "spidev%d.%d", spi->master->bus_num, spi->chip_select); - status = PTR_RET(dev); + status = PTR_ERR_OR_ZERO(dev); } else { dev_dbg(&spi->dev, "no minor number available!\n"); status = -ENODEV; diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 1aeb274e30fc..a7ce26c090dd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -189,7 +189,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, write, &dss_debug_fops); - return PTR_RET(d); + return PTR_ERR_OR_ZERO(d); } #else /* CONFIG_OMAP2_DSS_DEBUGFS */ static inline int dss_initialize_debugfs(void) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 4253ad580e39..5f8f3341c099 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -747,7 +747,7 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info) WARN_ON(atomic_xchg( &fs_info->mutually_exclusive_operation_running, 1)); task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl"); - return PTR_RET(task); + return PTR_ERR_OR_ZERO(task); } static int btrfs_dev_replace_kthread(void *data) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6d1b93c8aafb..2987e1755d60 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3166,7 +3166,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) found_key.type = BTRFS_INODE_ITEM_KEY; found_key.offset = 0; inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); - ret = PTR_RET(inode); + ret = PTR_ERR_OR_ZERO(inode); if (ret && ret != -ESTALE) goto out; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 7ad6ecf36f20..edf623a29043 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -590,7 +590,7 @@ int __init bt_sysfs_init(void) bt_class = class_create(THIS_MODULE, "bluetooth"); - return PTR_RET(bt_class); + return PTR_ERR_OR_ZERO(bt_class); } void bt_sysfs_cleanup(void) diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 70f656ce0f4a..dbd1c783431b 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -64,7 +64,7 @@ static int ebt_broute(struct sk_buff *skb) static int __net_init broute_net_init(struct net *net) { net->xt.broute_table = ebt_register_table(net, &broute_table); - return PTR_RET(net->xt.broute_table); + return PTR_ERR_OR_ZERO(net->xt.broute_table); } static void __net_exit broute_net_exit(struct net *net) diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 3c2e9dced9e0..94b2b700cff8 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -100,7 +100,7 @@ static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { static int __net_init frame_filter_net_init(struct net *net) { net->xt.frame_filter = ebt_register_table(net, &frame_filter); - return PTR_RET(net->xt.frame_filter); + return PTR_ERR_OR_ZERO(net->xt.frame_filter); } static void __net_exit frame_filter_net_exit(struct net *net) diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index 10871bc77908..322555acdd40 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -100,7 +100,7 @@ static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { static int __net_init frame_nat_net_init(struct net *net) { net->xt.frame_nat = ebt_register_table(net, &frame_nat); - return PTR_RET(net->xt.frame_nat); + return PTR_ERR_OR_ZERO(net->xt.frame_nat); } static void __net_exit frame_nat_net_exit(struct net *net) diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index eadab1ed6500..a865f6f94013 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -48,7 +48,7 @@ static int __net_init arptable_filter_net_init(struct net *net) net->ipv4.arptable_filter = arpt_register_table(net, &packet_filter, repl); kfree(repl); - return PTR_RET(net->ipv4.arptable_filter); + return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter); } static void __net_exit arptable_filter_net_exit(struct net *net) diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 6b3da5cf54e9..50af5b45c050 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -69,7 +69,7 @@ static int __net_init iptable_filter_net_init(struct net *net) net->ipv4.iptable_filter = ipt_register_table(net, &packet_filter, repl); kfree(repl); - return PTR_RET(net->ipv4.iptable_filter); + return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter); } static void __net_exit iptable_filter_net_exit(struct net *net) diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index cba5658ec82c..0d8cd82e0fad 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -107,7 +107,7 @@ static int __net_init iptable_mangle_net_init(struct net *net) net->ipv4.iptable_mangle = ipt_register_table(net, &packet_mangler, repl); kfree(repl); - return PTR_RET(net->ipv4.iptable_mangle); + return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle); } static void __net_exit iptable_mangle_net_exit(struct net *net) diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index 6383273d54e1..683bfaffed65 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -292,7 +292,7 @@ static int __net_init iptable_nat_net_init(struct net *net) return -ENOMEM; net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl); kfree(repl); - return PTR_RET(net->ipv4.nat_table); + return PTR_ERR_OR_ZERO(net->ipv4.nat_table); } static void __net_exit iptable_nat_net_exit(struct net *net) diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 03d9696d3c6e..1f82aea11df6 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -48,7 +48,7 @@ static int __net_init iptable_raw_net_init(struct net *net) net->ipv4.iptable_raw = ipt_register_table(net, &packet_raw, repl); kfree(repl); - return PTR_RET(net->ipv4.iptable_raw); + return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw); } static void __net_exit iptable_raw_net_exit(struct net *net) diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index b283d8e2601a..f867a8d38bf7 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -66,7 +66,7 @@ static int __net_init iptable_security_net_init(struct net *net) net->ipv4.iptable_security = ipt_register_table(net, &security_table, repl); kfree(repl); - return PTR_RET(net->ipv4.iptable_security); + return PTR_ERR_OR_ZERO(net->ipv4.iptable_security); } static void __net_exit iptable_security_net_exit(struct net *net) diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index beb5777d2043..29b44b14c5ea 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -61,7 +61,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) net->ipv6.ip6table_filter = ip6t_register_table(net, &packet_filter, repl); kfree(repl); - return PTR_RET(net->ipv6.ip6table_filter); + return PTR_ERR_OR_ZERO(net->ipv6.ip6table_filter); } static void __net_exit ip6table_filter_net_exit(struct net *net) diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index e075399d8b72..c705907ae6ab 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -101,7 +101,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net) net->ipv6.ip6table_mangle = ip6t_register_table(net, &packet_mangler, repl); kfree(repl); - return PTR_RET(net->ipv6.ip6table_mangle); + return PTR_ERR_OR_ZERO(net->ipv6.ip6table_mangle); } static void __net_exit ip6table_mangle_net_exit(struct net *net) diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index 6383f90efda8..9b076d2d3a7b 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c @@ -293,7 +293,7 @@ static int __net_init ip6table_nat_net_init(struct net *net) return -ENOMEM; net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); kfree(repl); - return PTR_RET(net->ipv6.ip6table_nat); + return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat); } static void __net_exit ip6table_nat_net_exit(struct net *net) diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 60d1bddff7a0..9a626d86720f 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -40,7 +40,7 @@ static int __net_init ip6table_raw_net_init(struct net *net) net->ipv6.ip6table_raw = ip6t_register_table(net, &packet_raw, repl); kfree(repl); - return PTR_RET(net->ipv6.ip6table_raw); + return PTR_ERR_OR_ZERO(net->ipv6.ip6table_raw); } static void __net_exit ip6table_raw_net_exit(struct net *net) diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index db155351339c..ce88d1d7e525 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -58,7 +58,7 @@ static int __net_init ip6table_security_net_init(struct net *net) net->ipv6.ip6table_security = ip6t_register_table(net, &security_table, repl); kfree(repl); - return PTR_RET(net->ipv6.ip6table_security); + return PTR_ERR_OR_ZERO(net->ipv6.ip6table_security); } static void __net_exit ip6table_security_net_exit(struct net *net) diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci index 2274638d005b..e18f8402e37c 100644 --- a/scripts/coccinelle/api/ptr_ret.cocci +++ b/scripts/coccinelle/api/ptr_ret.cocci @@ -1,5 +1,5 @@ /// -/// Use PTR_RET rather than if(IS_ERR(...)) + PTR_ERR +/// Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR /// // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. @@ -7,7 +7,7 @@ // URL: http://coccinelle.lip6.fr/ // Options: --no-includes --include-headers // -// Keywords: ERR_PTR, PTR_ERR, PTR_RET +// Keywords: ERR_PTR, PTR_ERR, PTR_RET, PTR_ERR_OR_ZERO // Version min: 2.6.39 // @@ -21,21 +21,21 @@ expression ptr; @@ - if (IS_ERR(ptr)) return PTR_ERR(ptr); else return 0; -+ return PTR_RET(ptr); ++ return PTR_ERR_OR_ZERO(ptr); @depends on patch@ expression ptr; @@ - if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0; -+ return PTR_RET(ptr); ++ return PTR_ERR_OR_ZERO(ptr); @depends on patch@ expression ptr; @@ - (IS_ERR(ptr) ? PTR_ERR(ptr) : 0) -+ PTR_RET(ptr) ++ PTR_ERR_OR_ZERO(ptr) @r1 depends on !patch@ expression ptr; diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 8ca9ecc5ac57..122c0c18b9dd 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -158,7 +158,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, return -EINVAL; } - return PTR_RET(codec->control_data); + return PTR_ERR_OR_ZERO(codec->control_data); } EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); #else From 228b82211b47b597fa75dff2ac146b40eaaddf18 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:21:32 +0930 Subject: [PATCH 0258/6183] s390: Replace weird use of PTR_RET. Saves repeating "(void __force *)__uptr" but it's less clear. Using the output of PTR_RET() to determine the error rather than just testing IS_ERR() is odd. For example, I *assume* __gptr_to_uptr() never returns NULL? Because the __ret would be 0 for the old code. The new version is clearer, IMHO: it would try to get_user() on that address. If you hate this variant, I can just s/PTR_RET/PTR_ERR_OR_ZERO/ instead. Cc: Christian Borntraeger Cc: Martin Schwidefsky Signed-off-by: Rusty Russell Acked-by: Heiko Carstens --- arch/s390/kvm/gaccess.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h index 302e0e52b009..99d789e8a018 100644 --- a/arch/s390/kvm/gaccess.h +++ b/arch/s390/kvm/gaccess.h @@ -42,9 +42,11 @@ static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu, ({ \ __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\ int __mask = sizeof(__typeof__(*(gptr))) - 1; \ - int __ret = PTR_RET((void __force *)__uptr); \ + int __ret; \ \ - if (!__ret) { \ + if (IS_ERR((void __force *)__uptr)) { \ + __ret = PTR_ERR((void __force *)__uptr); \ + } else { \ BUG_ON((unsigned long)__uptr & __mask); \ __ret = get_user(x, __uptr); \ } \ @@ -55,9 +57,11 @@ static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu, ({ \ __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\ int __mask = sizeof(__typeof__(*(gptr))) - 1; \ - int __ret = PTR_RET((void __force *)__uptr); \ + int __ret; \ \ - if (!__ret) { \ + if (IS_ERR((void __force *)__uptr)) { \ + __ret = PTR_ERR((void __force *)__uptr); \ + } else { \ BUG_ON((unsigned long)__uptr & __mask); \ __ret = put_user(x, __uptr); \ } \ From 5d7e438629413586ab78779751caa6e713c2234c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:22:32 +0930 Subject: [PATCH 0259/6183] acpi: Replace weird use of PTR_RET. This functions is really weird. It sets rc to -ENOMEM, then overrides it. It was converted to PTR_RET in a1458187 when it should have simply been rewritten. This version makes it more explicit, with a single IS_ERR() test. Cc: Alexandru Gheorghiu Signed-off-by: Rusty Russell Acked-by: Rafael J. Wysocki --- drivers/acpi/acpi_pad.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 27bb6a91de5f..46e0b3ca4aba 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -231,16 +231,19 @@ static struct task_struct *ps_tsks[NR_CPUS]; static unsigned int ps_tsk_num; static int create_power_saving_task(void) { - int rc = -ENOMEM; + int rc; ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread, (void *)(unsigned long)ps_tsk_num, "acpi_pad/%d", ps_tsk_num); - rc = PTR_RET(ps_tsks[ps_tsk_num]); - if (!rc) - ps_tsk_num++; - else + + if (IS_ERR(ps_tsks[ps_tsk_num])) { + rc = PTR_ERR(ps_tsks[ps_tsk_num]); ps_tsks[ps_tsk_num] = NULL; + } else { + rc = 0; + ps_tsk_num++; + } return rc; } From 5795c6ac7c77dc2363c41948cf828916c17cf78f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:23:32 +0930 Subject: [PATCH 0260/6183] pinctrl: don't use PTR_RET(). We've already tested that it's an error. Cc: Sebastian Hesselbarth Signed-off-by: Rusty Russell --- drivers/pinctrl/mvebu/pinctrl-dove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index 048ae80adabd..29f7e4fc7ca5 100644 --- a/drivers/pinctrl/mvebu/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c @@ -785,7 +785,7 @@ static int dove_pinctrl_probe(struct platform_device *pdev) clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to get pdma clock"); - return PTR_RET(clk); + return PTR_ERR(clk); } clk_prepare_enable(clk); From 60d676c007964576e83d791fc0908af8d133519f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:24:08 +0930 Subject: [PATCH 0261/6183] remoteproc: don't use PTR_RET(). We've already tested that it's an error. Cc: Robert Tivy Signed-off-by: Rusty Russell Acked-by: Ohad Ben-Cohen --- drivers/remoteproc/da8xx_remoteproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 9b2e60afa1a6..129f7b997866 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -165,7 +165,7 @@ static int reset_assert(struct device *dev) dsp_clk = clk_get(dev, NULL); if (IS_ERR(dsp_clk)) { dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); - return PTR_RET(dsp_clk); + return PTR_ERR(dsp_clk); } davinci_clk_reset_assert(dsp_clk); From 8a1d41cfeaf59a07acc7b1b3620ad6aa5cf47dc2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:24:08 +0930 Subject: [PATCH 0262/6183] staging/zcache: don't use PTR_RET(). We've already tested that it's an error. Cc: Dan Magenheimer Signed-off-by: Rusty Russell --- drivers/staging/zcache/zcache-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index dcceed29d31a..88e7fe7fe183 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -1908,7 +1908,7 @@ static int zcache_init(void) #endif if (IS_ERR(old_ops) || old_ops) { if (IS_ERR(old_ops)) - return PTR_RET(old_ops); + return PTR_ERR(old_ops); pr_warn("%s: frontswap_ops overridden\n", namestr); } } From 6b4f2b56a48c8ea9775bd2b29681725d4474367a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 15 Jul 2013 11:24:08 +0930 Subject: [PATCH 0263/6183] mm/oom_kill: remove weird use of ERR_PTR()/PTR_ERR(). The normal expectation for ERR_PTR() is to put a negative errno into a pointer. oom_kill puts the magic -1 in the result (and has since pre-git), which is probably clearer with an explicit cast. Cc: Andrew Morton Signed-off-by: Rusty Russell --- mm/oom_kill.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 79e451a78c9e..98e75f2ac7bc 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -288,7 +288,7 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, /* * Simple selection loop. We chose the process with the highest - * number of 'points'. + * number of 'points'. Returns -1 on scan abort. * * (not docbooked, we don't want this one cluttering up the manual) */ @@ -314,7 +314,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, continue; case OOM_SCAN_ABORT: rcu_read_unlock(); - return ERR_PTR(-1UL); + return (struct task_struct *)(-1UL); case OOM_SCAN_OK: break; }; @@ -657,7 +657,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, dump_header(NULL, gfp_mask, order, NULL, mpol_mask); panic("Out of memory and no killable processes...\n"); } - if (PTR_ERR(p) != -1UL) { + if (p != (void *)-1UL) { oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, nodemask, "Out of memory"); killed = 1; From 170ab436bff98f765ce365532d780d07aa1a576d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Sun, 7 Jul 2013 18:31:56 -0300 Subject: [PATCH 0264/6183] ARM: sun5i: dt: Add I2C muxings for sun5i A10S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The information has been extracted from the A10S-OLinuXino-Micro schematics, as we do not have a user manual for A10S yet. Signed-off-by: Emilio López Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun5i-a10s.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index 2307ce827ae0..7c9f88f701bc 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -229,6 +229,27 @@ allwinner,drive = <0>; allwinner,pull = <0>; }; + + i2c0_pins_a: i2c0@0 { + allwinner,pins = "PB0", "PB1"; + allwinner,function = "i2c0"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + i2c1_pins_a: i2c1@0 { + allwinner,pins = "PB15", "PB16"; + allwinner,function = "i2c1"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + i2c2_pins_a: i2c2@0 { + allwinner,pins = "PB17", "PB18"; + allwinner,function = "i2c2"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; }; timer@01c20c00 { From ca3d4ed5914b7e367a9079ce765bbe26332eb780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Sun, 7 Jul 2013 18:31:57 -0300 Subject: [PATCH 0265/6183] ARM: sun5i: dt: Add I2C controller nodes to the A10S dtsi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allwinner A10S has 3 I2C controllers embedded on it. Add them to the corresponding dtsi. Signed-off-by: Emilio López Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun5i-a10s.dtsi | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index 7c9f88f701bc..0f0881a7ac8e 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -303,5 +303,38 @@ clocks = <&apb1_gates 19>; status = "disabled"; }; + + i2c0: i2c@01c2ac00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "allwinner,sun4i-i2c"; + reg = <0x01c2ac00 0x400>; + interrupts = <7>; + clocks = <&apb1_gates 0>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@01c2b000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "allwinner,sun4i-i2c"; + reg = <0x01c2b000 0x400>; + interrupts = <8>; + clocks = <&apb1_gates 1>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c2: i2c@01c2b400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "allwinner,sun4i-i2c"; + reg = <0x01c2b400 0x400>; + interrupts = <9>; + clocks = <&apb1_gates 2>; + clock-frequency = <100000>; + status = "disabled"; + }; }; }; From d6c451dd2c388cb32d3a20e3c74c11cc84999ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Sun, 7 Jul 2013 18:31:58 -0300 Subject: [PATCH 0266/6183] ARM: sun5i: dt: Enable I2C controllers on A10S-OLinuXino-Micro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This board from OLIMEX is using the three I2C controllers present on A10S: * I2C-0 connects to the AXP152 PMU * I2C-1 holds an AT24C16BN-SH EEPROM with the MAC address for ethernet * I2C-2 is used for UEXT modules. Signed-off-by: Emilio López Signed-off-by: Maxime Ripard --- .../boot/dts/sun5i-a10s-olinuxino-micro.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts index 64dc0c42c43a..2a69ddffb657 100644 --- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts @@ -60,6 +60,24 @@ pinctrl-0 = <&uart3_pins_a>; status = "okay"; }; + + i2c0: i2c@01c2ac00 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + }; + + i2c1: i2c@01c2b000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins_a>; + status = "okay"; + }; + + i2c2: i2c@01c2b400 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins_a>; + status = "okay"; + }; }; leds { From bdbfd8e0bb86dcd59f6cfa3278e361c56933fec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Sun, 7 Jul 2013 18:31:59 -0300 Subject: [PATCH 0267/6183] ARM: sun5i: dt: Add AT24 device on A10S-OLinuXino-Micro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This OLIMEX board has a AT24C16BN-SH EEPROM holding the MAC address. This patch adds the corresponding device tree node to reflect this. Signed-off-by: Emilio López Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts index 2a69ddffb657..24dd8bb7df8a 100644 --- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts +++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts @@ -71,6 +71,13 @@ pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins_a>; status = "okay"; + + at24@50 { + compatible = "at,24c16"; + pagesize = <16>; + reg = <0x50>; + read-only; + }; }; i2c2: i2c@01c2b400 { From 0adb9c2c5ed42f199cb2a630c37d18dee385fae2 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 15 Jul 2013 10:12:18 +0200 Subject: [PATCH 0268/6183] HID: kye: Add report fixup for Genius Gx Imperator Keyboard Genius Gx Imperator Keyboard presents the same problem in its report descriptors than Genius Gila Gaming Mouse. Use the same fixup for both. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=928561 Reported-and-tested-by: Honza Brazdil Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-kye.c | 45 ++++++++++++++++++++++++++---------------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8de5cb8319b9..b0f2f459f59b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1594,6 +1594,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c5aea29f164f..02885319c10a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -479,6 +479,7 @@ #define USB_VENDOR_ID_KYE 0x0458 #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 #define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138 +#define USB_DEVICE_ID_GENIUS_GX_IMPERATOR 0x4018 #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 #define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011 diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index 1e2ee2aa84a0..73845120295e 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -268,6 +268,26 @@ static __u8 easypen_m610x_rdesc_fixed[] = { 0xC0 /* End Collection */ }; +static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize, int offset, const char *device_name) { + /* + * the fixup that need to be done: + * - change Usage Maximum in the Comsumer Control + * (report ID 3) to a reasonable value + */ + if (*rsize >= offset + 31 && + /* Usage Page (Consumer Devices) */ + rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c && + /* Usage (Consumer Control) */ + rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 && + /* Usage Maximum > 12287 */ + rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) { + hid_info(hdev, "fixing up %s report descriptor\n", device_name); + rdesc[offset + 12] = 0x2f; + } + return rdesc; +} + static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -315,23 +335,12 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, } break; case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE: - /* - * the fixup that need to be done: - * - change Usage Maximum in the Comsumer Control - * (report ID 3) to a reasonable value - */ - if (*rsize >= 135 && - /* Usage Page (Consumer Devices) */ - rdesc[104] == 0x05 && rdesc[105] == 0x0c && - /* Usage (Consumer Control) */ - rdesc[106] == 0x09 && rdesc[107] == 0x01 && - /* Usage Maximum > 12287 */ - rdesc[114] == 0x2a && rdesc[116] > 0x2f) { - hid_info(hdev, - "fixing up Genius Gila Gaming Mouse " - "report descriptor\n"); - rdesc[116] = 0x2f; - } + rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104, + "Genius Gila Gaming Mouse"); + break; + case USB_DEVICE_ID_GENIUS_GX_IMPERATOR: + rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83, + "Genius Gx Imperator Keyboard"); break; } return rdesc; @@ -428,6 +437,8 @@ static const struct hid_device_id kye_devices[] = { USB_DEVICE_ID_KYE_EASYPEN_M610X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, + USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, { } }; MODULE_DEVICE_TABLE(hid, kye_devices); From e394fe55f7cf5a4f6c20fbd02ab37b1d5c3dd364 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 1 Jul 2013 16:49:04 +0800 Subject: [PATCH 0269/6183] ASoC: adav80x: Add module device table for adav801 This driver can be built as module, thus add module device table for adav801 to support module auto loading. To make the naming consistent, also rename adav80x_id to adav80x_i2c_id. Signed-off-by: Axel Lin Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adav80x.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 3c839cc4e00e..15b012d0f226 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -868,6 +868,12 @@ static int adav80x_bus_remove(struct device *dev) } #if defined(CONFIG_SPI_MASTER) +static const struct spi_device_id adav80x_spi_id[] = { + { "adav801", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, adav80x_spi_id); + static int adav80x_spi_probe(struct spi_device *spi) { return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); @@ -885,15 +891,16 @@ static struct spi_driver adav80x_spi_driver = { }, .probe = adav80x_spi_probe, .remove = adav80x_spi_remove, + .id_table = adav80x_spi_id, }; #endif #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static const struct i2c_device_id adav80x_id[] = { +static const struct i2c_device_id adav80x_i2c_id[] = { { "adav803", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, adav80x_id); +MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); static int adav80x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -913,7 +920,7 @@ static struct i2c_driver adav80x_i2c_driver = { }, .probe = adav80x_i2c_probe, .remove = adav80x_i2c_remove, - .id_table = adav80x_id, + .id_table = adav80x_i2c_id, }; #endif From a2911cdb1fd09de7c0da3938ffab1bc5cedda4f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 3 Jul 2013 21:15:13 -0700 Subject: [PATCH 0270/6183] ASoC: add ak4554 driver ak4554 is very simple DA/AD converter which has no setting register. Note that it has hard coded asymmetric data format playback : SND_SOC_DAIFMT_RIGHT_J capture : SND_SOC_DAIFMT_LEFT_J This driver has single DAI and doesn't have set_fmt. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ak4554.c | 79 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 sound/soc/codecs/ak4554.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index badb6fbacaa6..ffb9adb18647 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -198,6 +198,9 @@ config SND_SOC_AK4104 config SND_SOC_AK4535 tristate +config SND_SOC_AK4554 + tristate + config SND_SOC_AK4641 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 70fd8066f546..fab4086796a0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -11,6 +11,7 @@ snd-soc-adav80x-objs := adav80x.o snd-soc-ads117x-objs := ads117x.o snd-soc-ak4104-objs := ak4104.o snd-soc-ak4535-objs := ak4535.o +snd-soc-ak4554-objs := ak4554.o snd-soc-ak4641-objs := ak4641.o snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o @@ -138,6 +139,7 @@ obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o +obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c new file mode 100644 index 000000000000..c1a1733f8a35 --- /dev/null +++ b/sound/soc/codecs/ak4554.c @@ -0,0 +1,79 @@ +/* + * ak4554.c + * + * Copyright (C) 2013 Renesas Solutions Corp. + * Kuninori Morimoto + * + * 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 +#include + +/* + * ak4554 is very simple DA/AD converter which has no setting register. + * + * CAUTION + * + * ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J, + * and, capture format is SND_SOC_DAIFMT_LEFT_J + * on same bit clock, LR clock. + * But, this driver doesn't have snd_soc_dai_ops :: set_fmt + * + * CPU/Codec DAI image + * + * CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554 + * | + * CPU-DAI2 (capture only fmt = LEFT_J) ---+ + */ + +static struct snd_soc_dai_driver ak4554_dai = { + .name = "ak4554-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .symmetric_rates = 1, +}; + +static struct snd_soc_codec_driver soc_codec_dev_ak4554 = { +}; + +static int ak4554_soc_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_ak4554, + &ak4554_dai, 1); +} + +static int ak4554_soc_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver ak4554_driver = { + .driver = { + .name = "ak4554-adc-dac", + .owner = THIS_MODULE, + }, + .probe = ak4554_soc_probe, + .remove = ak4554_soc_remove, +}; +module_platform_driver(ak4554_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SoC AK4554 driver"); +MODULE_AUTHOR("Kuninori Morimoto "); From b25f77815021ec6e7400a82c4984b9c80699ce80 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 4 Jul 2013 19:42:49 -0700 Subject: [PATCH 0271/6183] ASoC: ak4554: add DT support Support for loading the ak4554 codec module via devicetree. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak4554.c | 11 +++++++++++ sound/soc/codecs/ak4554.c | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ak4554.c diff --git a/Documentation/devicetree/bindings/sound/ak4554.c b/Documentation/devicetree/bindings/sound/ak4554.c new file mode 100644 index 000000000000..934fa02754b3 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ak4554.c @@ -0,0 +1,11 @@ +AK4554 ADC/DAC + +Required properties: + + - compatible : "asahi-kasei,ak4554" + +Example: + +ak4554-adc-dac { + compatible = "asahi-kasei,ak4554"; +}; diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c index c1a1733f8a35..6aed9c4d06d6 100644 --- a/sound/soc/codecs/ak4554.c +++ b/sound/soc/codecs/ak4554.c @@ -64,10 +64,17 @@ static int ak4554_soc_remove(struct platform_device *pdev) return 0; } +static struct of_device_id ak4554_of_match[] = { + { .compatible = "asahi-kasei,ak4554" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ak4554_of_match); + static struct platform_driver ak4554_driver = { .driver = { .name = "ak4554-adc-dac", .owner = THIS_MODULE, + .of_match_table = ak4554_of_match, }, .probe = ak4554_soc_probe, .remove = ak4554_soc_remove, From 326c29b6bedb7440b4232631686027af84a62cf5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 4 Jul 2013 08:56:27 +0100 Subject: [PATCH 0272/6183] mfd: arizona: Add GPIO control register bit definitions Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/linux/mfd/arizona/gpio.h | 96 ++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 include/linux/mfd/arizona/gpio.h diff --git a/include/linux/mfd/arizona/gpio.h b/include/linux/mfd/arizona/gpio.h new file mode 100644 index 000000000000..d2146bb74f89 --- /dev/null +++ b/include/linux/mfd/arizona/gpio.h @@ -0,0 +1,96 @@ +/* + * GPIO configuration for Arizona devices + * + * Copyright 2013 Wolfson Microelectronics. PLC. + * + * Author: Charles Keepax + * + * 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. + */ + +#ifndef _ARIZONA_GPIO_H +#define _ARIZONA_GPIO_H + +#define ARIZONA_GP_FN_TXLRCLK 0x00 +#define ARIZONA_GP_FN_GPIO 0x01 +#define ARIZONA_GP_FN_IRQ1 0x02 +#define ARIZONA_GP_FN_IRQ2 0x03 +#define ARIZONA_GP_FN_OPCLK 0x04 +#define ARIZONA_GP_FN_FLL1_OUT 0x05 +#define ARIZONA_GP_FN_FLL2_OUT 0x06 +#define ARIZONA_GP_FN_PWM1 0x08 +#define ARIZONA_GP_FN_PWM2 0x09 +#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED 0x0A +#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED 0x0B +#define ARIZONA_GP_FN_FLL1_LOCK 0x0C +#define ARIZONA_GP_FN_FLL2_LOCK 0x0D +#define ARIZONA_GP_FN_FLL1_CLOCK_OK 0x0F +#define ARIZONA_GP_FN_FLL2_CLOCK_OK 0x10 +#define ARIZONA_GP_FN_HEADPHONE_DET 0x12 +#define ARIZONA_GP_FN_MIC_DET 0x13 +#define ARIZONA_GP_FN_WSEQ_STATUS 0x15 +#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR 0x16 +#define ARIZONA_GP_FN_ASRC1_LOCK 0x1A +#define ARIZONA_GP_FN_ASRC2_LOCK 0x1B +#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR 0x1C +#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT 0x1D +#define ARIZONA_GP_FN_DRC1_ANTICLIP 0x1E +#define ARIZONA_GP_FN_DRC1_DECAY 0x1F +#define ARIZONA_GP_FN_DRC1_NOISE 0x20 +#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE 0x21 +#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT 0x22 +#define ARIZONA_GP_FN_DRC2_ANTICLIP 0x23 +#define ARIZONA_GP_FN_DRC2_DECAY 0x24 +#define ARIZONA_GP_FN_DRC2_NOISE 0x25 +#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE 0x26 +#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE 0x27 +#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR 0x28 +#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR 0x29 +#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR 0x2A +#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN 0x2B +#define ARIZONA_GP_FN_SPK_TEMP_WARNING 0x2C +#define ARIZONA_GP_FN_UNDERCLOCKED 0x2D +#define ARIZONA_GP_FN_OVERCLOCKED 0x2E +#define ARIZONA_GP_FN_DSP_IRQ1 0x35 +#define ARIZONA_GP_FN_DSP_IRQ2 0x36 +#define ARIZONA_GP_FN_ASYNC_OPCLK 0x3D +#define ARIZONA_GP_FN_BOOT_DONE 0x44 +#define ARIZONA_GP_FN_DSP1_RAM_READY 0x45 +#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS 0x4B +#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS 0x4C + +#define ARIZONA_GPN_DIR 0x8000 /* GPN_DIR */ +#define ARIZONA_GPN_DIR_MASK 0x8000 /* GPN_DIR */ +#define ARIZONA_GPN_DIR_SHIFT 15 /* GPN_DIR */ +#define ARIZONA_GPN_DIR_WIDTH 1 /* GPN_DIR */ +#define ARIZONA_GPN_PU 0x4000 /* GPN_PU */ +#define ARIZONA_GPN_PU_MASK 0x4000 /* GPN_PU */ +#define ARIZONA_GPN_PU_SHIFT 14 /* GPN_PU */ +#define ARIZONA_GPN_PU_WIDTH 1 /* GPN_PU */ +#define ARIZONA_GPN_PD 0x2000 /* GPN_PD */ +#define ARIZONA_GPN_PD_MASK 0x2000 /* GPN_PD */ +#define ARIZONA_GPN_PD_SHIFT 13 /* GPN_PD */ +#define ARIZONA_GPN_PD_WIDTH 1 /* GPN_PD */ +#define ARIZONA_GPN_LVL 0x0800 /* GPN_LVL */ +#define ARIZONA_GPN_LVL_MASK 0x0800 /* GPN_LVL */ +#define ARIZONA_GPN_LVL_SHIFT 11 /* GPN_LVL */ +#define ARIZONA_GPN_LVL_WIDTH 1 /* GPN_LVL */ +#define ARIZONA_GPN_POL 0x0400 /* GPN_POL */ +#define ARIZONA_GPN_POL_MASK 0x0400 /* GPN_POL */ +#define ARIZONA_GPN_POL_SHIFT 10 /* GPN_POL */ +#define ARIZONA_GPN_POL_WIDTH 1 /* GPN_POL */ +#define ARIZONA_GPN_OP_CFG 0x0200 /* GPN_OP_CFG */ +#define ARIZONA_GPN_OP_CFG_MASK 0x0200 /* GPN_OP_CFG */ +#define ARIZONA_GPN_OP_CFG_SHIFT 9 /* GPN_OP_CFG */ +#define ARIZONA_GPN_OP_CFG_WIDTH 1 /* GPN_OP_CFG */ +#define ARIZONA_GPN_DB 0x0100 /* GPN_DB */ +#define ARIZONA_GPN_DB_MASK 0x0100 /* GPN_DB */ +#define ARIZONA_GPN_DB_SHIFT 8 /* GPN_DB */ +#define ARIZONA_GPN_DB_WIDTH 1 /* GPN_DB */ +#define ARIZONA_GPN_FN_MASK 0x007F /* GPN_DB */ +#define ARIZONA_GPN_FN_SHIFT 0 /* GPN_DB */ +#define ARIZONA_GPN_FN_WIDTH 7 /* GPN_DB */ + +#endif From b63144e6c6097486e7678f9ecc2769b68d2ec83e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 4 Jul 2013 08:56:28 +0100 Subject: [PATCH 0273/6183] ASoC: arizona: Add signal activity output for DRC When doing signal activity detection, the only output from the DRC will often be a GPIO pin. This patch adds a signal activity output that is activated when a GPIO is configured to output the DRC signal activity detection. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 33 +++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 1 + sound/soc/codecs/wm5102.c | 6 ++++++ sound/soc/codecs/wm5110.c | 9 +++++++++ 4 files changed, 49 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index de625813c0e6..c9116ac0d4a7 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "arizona.h" @@ -223,6 +224,38 @@ int arizona_init_spk(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(arizona_init_spk); +int arizona_init_gpio(struct snd_soc_codec *codec) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int i; + + switch (arizona->type) { + case WM5110: + snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity"); + } + + snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity"); + + for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { + switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { + case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: + snd_soc_dapm_enable_pin(&codec->dapm, + "DRC1 Signal Activity"); + break; + case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: + snd_soc_dapm_enable_pin(&codec->dapm, + "DRC2 Signal Activity"); + break; + default: + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_gpio); + const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index b60b08ccc1d0..fe1b794bd5f0 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -242,6 +242,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); extern int arizona_init_spk(struct snd_soc_codec *codec); +extern int arizona_init_gpio(struct snd_soc_codec *codec); extern int arizona_init_dai(struct arizona_priv *priv, int dai); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 282fd232cdf7..a6cbdb4b5c0f 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -998,6 +998,8 @@ SND_SOC_DAPM_INPUT("IN2R"), SND_SOC_DAPM_INPUT("IN3L"), SND_SOC_DAPM_INPUT("IN3R"), +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), + SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | @@ -1614,6 +1616,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "SPKDAT1R", NULL, "OUT5R" }, { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1L" }, + { "DRC1 Signal Activity", NULL, "DRC1R" }, }; static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, @@ -1781,6 +1786,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) return ret; arizona_init_spk(codec); + arizona_init_gpio(codec); snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2e7cb4ba161a..fc410377277f 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -432,6 +432,9 @@ SND_SOC_DAPM_INPUT("IN3R"), SND_SOC_DAPM_INPUT("IN4L"), SND_SOC_DAPM_INPUT("IN4R"), +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, 0, NULL, 0, arizona_in_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | @@ -1006,6 +1009,11 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "SPKDAT2R", NULL, "OUT6R" }, { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1L" }, + { "DRC1 Signal Activity", NULL, "DRC1R" }, + { "DRC2 Signal Activity", NULL, "DRC2L" }, + { "DRC2 Signal Activity", NULL, "DRC2R" }, }; static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, @@ -1170,6 +1178,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) return ret; arizona_init_spk(codec); + arizona_init_gpio(codec); snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS"); From b79fae606c921522577f3000b6b9a807cd733d2e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 4 Jul 2013 16:53:03 +0100 Subject: [PATCH 0274/6183] ASoC: arizona: Add default case to silence build warning Reported-by: Fengguang Wu Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index c9116ac0d4a7..8dc6881496de 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -233,6 +233,9 @@ int arizona_init_gpio(struct snd_soc_codec *codec) switch (arizona->type) { case WM5110: snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity"); + break; + default: + break; } snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity"); From 01f00d55a7f21b966417fece78214154f01590ed Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 3 Jul 2013 16:37:56 +0800 Subject: [PATCH 0275/6183] ASoC: atmel_ssc_dai: move set dma data to startup callback move set dma data to startup callback function, if the set dma data exist in hw_params callback, so the dma data only usable when call hw_params, if want use it before hw_params callback, it will cause NULL pointer access oops Signed-off-by: Bo Shen Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index f3fdfa07fcb9..6cf9cf1238cc 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -196,15 +196,27 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; - int dir_mask; + struct atmel_pcm_dma_params *dma_params; + int dir, dir_mask; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dir = 0; dir_mask = SSC_DIR_MASK_PLAYBACK; - else + } else { + dir = 1; dir_mask = SSC_DIR_MASK_CAPTURE; + } + + dma_params = &ssc_dma_params[dai->id][dir]; + dma_params->ssc = ssc_p->ssc; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + + snd_soc_dai_set_dma_data(dai, substream, dma_params); spin_lock_irq(&ssc_p->lock); if (ssc_p->dir_mask & dir_mask) { @@ -325,7 +337,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); int id = dai->id; struct atmel_ssc_info *ssc_p = &ssc_info[id]; struct atmel_pcm_dma_params *dma_params; @@ -344,19 +355,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, else dir = 1; - dma_params = &ssc_dma_params[id][dir]; - dma_params->ssc = ssc_p->ssc; - dma_params->substream = substream; - - ssc_p->dma_params[dir] = dma_params; - - /* - * The snd_soc_pcm_stream->dma_data field is only used to communicate - * the appropriate DMA parameters to the pcm driver hw_params() - * function. It should not be used for other purposes - * as it is common to all substreams. - */ - snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params); + dma_params = ssc_p->dma_params[dir]; channels = params_channels(params); From f1b0dd8b9377590b387fd21ba67081ed0e7111e3 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 3 Jul 2013 16:37:57 +0800 Subject: [PATCH 0276/6183] ASoC: atmel_ssc_dai: add error mask define add error mask define, which will be used when execute DMA transfer Signed-off-by: Bo Shen Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 6cf9cf1238cc..1ab47639f11c 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -73,6 +73,7 @@ static struct atmel_ssc_mask ssc_tx_mask = { .ssc_disable = SSC_BIT(CR_TXDIS), .ssc_endx = SSC_BIT(SR_ENDTX), .ssc_endbuf = SSC_BIT(SR_TXBUFE), + .ssc_error = SSC_BIT(SR_OVRUN), .pdc_enable = ATMEL_PDC_TXTEN, .pdc_disable = ATMEL_PDC_TXTDIS, }; @@ -82,6 +83,7 @@ static struct atmel_ssc_mask ssc_rx_mask = { .ssc_disable = SSC_BIT(CR_RXDIS), .ssc_endx = SSC_BIT(SR_ENDRX), .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .ssc_error = SSC_BIT(SR_OVRUN), .pdc_enable = ATMEL_PDC_RXTEN, .pdc_disable = ATMEL_PDC_RXTDIS, }; From cede8d7aaa60bd7c03b9ec5eb43b09714710b8ba Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 3 Jul 2013 16:37:58 +0800 Subject: [PATCH 0277/6183] ASoC: atmel-pcm-dma: move prepare for dma to dai prepare as prepare callback for dma is acctually access ssc register which better done in dai driver, so move it to dai prepare callback function Signed-off-by: Bo Shen Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm-dma.c | 14 -------------- sound/soc/atmel/atmel_ssc_dai.c | 1 + 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index 1d38fd0bc4e2..5a57803cb180 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -175,19 +175,6 @@ err: return ret; } -static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct atmel_pcm_dma_params *prtd; - - prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); - ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); - - return 0; -} - static int atmel_pcm_open(struct snd_pcm_substream *substream) { snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware); @@ -200,7 +187,6 @@ static struct snd_pcm_ops atmel_pcm_ops = { .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_pcm_hw_params, - .prepare = atmel_pcm_dma_prepare, .trigger = snd_dmaengine_pcm_trigger, .pointer = snd_dmaengine_pcm_pointer_no_residue, .mmap = atmel_pcm_mmap, diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 1ab47639f11c..0ecf356027f6 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -649,6 +649,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, dma_params = ssc_p->dma_params[dir]; ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); + ssc_writel(ssc_p->ssc->regs, IER, dma_params->mask->ssc_error); pr_debug("%s enabled SSC_SR=0x%08x\n", dir ? "receive" : "transmit", From 10175b3b2fdd287515db4c103d96b323bb4cd690 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 3 Jul 2013 16:37:59 +0800 Subject: [PATCH 0278/6183] ARM: atmel-ssc: change phybase type to dma_addr_t as the phybase paramter only used for DMA operation, change it's type from resource_size_t to dma_addr_t Signed-off-by: Bo Shen Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/linux/atmel-ssc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index deb0ae58b99b..66a0e5384edd 100644 --- a/include/linux/atmel-ssc.h +++ b/include/linux/atmel-ssc.h @@ -11,7 +11,7 @@ struct atmel_ssc_platform_data { struct ssc_device { struct list_head list; - resource_size_t phybase; + dma_addr_t phybase; void __iomem *regs; struct platform_device *pdev; struct atmel_ssc_platform_data *pdata; From 95e0e07e710e24a240f2c9645ecaad3559d6040d Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 3 Jul 2013 16:38:00 +0800 Subject: [PATCH 0279/6183] ASoC: atmel-pcm: use generic dmaengine framework Align atmel pcm to use ASoC generic dmaengine framework DMA is fully device tree based Signed-off-by: Bo Shen Reviewed-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 1 + sound/soc/atmel/atmel-pcm-dma.c | 104 +++++--------------------------- 2 files changed, 17 insertions(+), 88 deletions(-) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 3fdd87fa18a9..1c0b1858638c 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -13,6 +13,7 @@ config SND_ATMEL_SOC_PDC config SND_ATMEL_SOC_DMA tristate depends on SND_ATMEL_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM config SND_ATMEL_SOC_SSC tristate diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index 5a57803cb180..3ff5601eef10 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -89,124 +89,52 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, } } -/*--------------------------------------------------------------------------*\ - * DMAENGINE operations -\*--------------------------------------------------------------------------*/ -static bool filter(struct dma_chan *chan, void *slave) -{ - struct at_dma_slave *sl = slave; - - if (sl->dma_dev == chan->device->dev) { - chan->private = sl; - return true; - } else { - return false; - } -} - static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd) + struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pcm_dma_params *prtd; struct ssc_device *ssc; - struct dma_chan *dma_chan; - struct dma_slave_config slave_config; int ret; + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ssc = prtd->ssc; - ret = snd_hwparams_to_dma_slave_config(substream, params, - &slave_config); + ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); if (ret) { pr_err("atmel-pcm: hwparams to dma slave configure failed\n"); return ret; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR; - slave_config.dst_maxburst = 1; + slave_config->dst_addr = ssc->phybase + SSC_THR; + slave_config->dst_maxburst = 1; } else { - slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR; - slave_config.src_maxburst = 1; - } - - dma_chan = snd_dmaengine_pcm_get_chan(substream); - if (dmaengine_slave_config(dma_chan, &slave_config)) { - pr_err("atmel-pcm: failed to configure dma channel\n"); - ret = -EBUSY; - return ret; - } - - return 0; -} - -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct atmel_pcm_dma_params *prtd; - struct ssc_device *ssc; - struct at_dma_slave *sdata = NULL; - int ret; - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - - prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - ssc = prtd->ssc; - if (ssc->pdev) - sdata = ssc->pdev->dev.platform_data; - - ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata); - if (ret) { - pr_err("atmel-pcm: dmaengine pcm open failed\n"); - return -EINVAL; - } - - ret = atmel_pcm_configure_dma(substream, params, prtd); - if (ret) { - pr_err("atmel-pcm: failed to configure dmai\n"); - goto err; + slave_config->src_addr = ssc->phybase + SSC_RHR; + slave_config->src_maxburst = 1; } prtd->dma_intr_handler = atmel_pcm_dma_irq; return 0; -err: - snd_dmaengine_pcm_close_release_chan(substream); - return ret; } -static int atmel_pcm_open(struct snd_pcm_substream *substream) -{ - snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware); - - return 0; -} - -static struct snd_pcm_ops atmel_pcm_ops = { - .open = atmel_pcm_open, - .close = snd_dmaengine_pcm_close_release_chan, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = atmel_pcm_hw_params, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer_no_residue, - .mmap = atmel_pcm_mmap, -}; - -static struct snd_soc_platform_driver atmel_soc_platform = { - .ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free, +static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = { + .prepare_slave_config = atmel_pcm_configure_dma, + .pcm_hardware = &atmel_pcm_dma_hardware, + .prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE, }; int atmel_pcm_dma_platform_register(struct device *dev) { - return snd_soc_register_platform(dev, &atmel_soc_platform); + return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); } EXPORT_SYMBOL(atmel_pcm_dma_platform_register); void atmel_pcm_dma_platform_unregister(struct device *dev) { - snd_soc_unregister_platform(dev); + snd_dmaengine_pcm_unregister(dev); } EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister); From 35261edca31b0084bb615e6b50dfa5757b26db76 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Jul 2013 17:19:25 +0800 Subject: [PATCH 0280/6183] ASoC: db1200: add .owner to struct snd_soc_card Add missing .owner of struct snd_soc_card. This prevents the module from being removed from underneath its users. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/au1x/db1200.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index a497a0cfeba1..decba87a074c 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -73,12 +73,14 @@ static struct snd_soc_dai_link db1300_ac97_dai = { static struct snd_soc_card db1300_ac97_machine = { .name = "DB1300_AC97", + .owner = THIS_MODULE, .dai_link = &db1300_ac97_dai, .num_links = 1, }; static struct snd_soc_card db1550_ac97_machine = { .name = "DB1550_AC97", + .owner = THIS_MODULE, .dai_link = &db1200_ac97_dai, .num_links = 1, }; @@ -145,6 +147,7 @@ static struct snd_soc_dai_link db1300_i2s_dai = { static struct snd_soc_card db1300_i2s_machine = { .name = "DB1300_I2S", + .owner = THIS_MODULE, .dai_link = &db1300_i2s_dai, .num_links = 1, }; @@ -161,6 +164,7 @@ static struct snd_soc_dai_link db1550_i2s_dai = { static struct snd_soc_card db1550_i2s_machine = { .name = "DB1550_I2S", + .owner = THIS_MODULE, .dai_link = &db1550_i2s_dai, .num_links = 1, }; From 64b0c282e87948bc0c5a1b94ca3d4dd9f6415c6f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 25 Jun 2013 11:00:06 +0100 Subject: [PATCH 0281/6183] ASoC: codecs: Make ALL_CODECS depend on COMPILE_TEST The main function of the option is to enable compile testing. There is still an option since COMPILE_TEST is intended to enable selection of extra drivers rather than forcing them on. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index badb6fbacaa6..01d112b48e7e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" + depends on COMPILE_TEST select SND_SOC_88PM860X if MFD_88PM860X select SND_SOC_L3 select SND_SOC_AB8500_CODEC if ABX500_CORE From 7464dcd061045e664723acbf6be49e3ff53d97d8 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Jul 2013 17:26:00 +0800 Subject: [PATCH 0282/6183] ASoC: imx_mc13783: add .owner to struct snd_soc_card Add missing .owner of struct snd_soc_card. This prevents the module from being removed from underneath its users. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/fsl/imx-mc13783.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 9df173c091a6..a3d60d4bea4c 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -90,6 +90,7 @@ static const struct snd_soc_dapm_route imx_mc13783_routes[] = { static struct snd_soc_card imx_mc13783 = { .name = "imx_mc13783", + .owner = THIS_MODULE, .dai_link = imx_mc13783_dai_mc13783, .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783), .dapm_widgets = imx_mc13783_widget, From c364796a473db467b9201ea31a096bc0cf23547a Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Thu, 20 Jun 2013 15:20:20 +0200 Subject: [PATCH 0283/6183] ASoC: imx-pcm-dma: DT support This patch removes the NO_DT flag. The pdev pointer may have a proper of_node with the dmas property, so we can use it to request DMA channels. Signed-off-by: Markus Pargmann Tested-by: Shawn Guo Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index fde4d2ea68c8..f323ce09f881 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -64,7 +64,6 @@ int imx_pcm_dma_init(struct platform_device *pdev) { return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config, SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | - SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_COMPAT); } EXPORT_SYMBOL_GPL(imx_pcm_dma_init); From 9051cba110000985c1a50374fea16f1493955b6e Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Thu, 20 Jun 2013 15:20:21 +0200 Subject: [PATCH 0284/6183] ASoC: imx-pcm-fiq: Introduce pcm-fiq-params Cleaner parameter passing for imx-pcm-fiq. Create a seperated fiq-params struct to pass all arguments. Signed-off-by: Markus Pargmann Tested-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/imx-pcm-fiq.c | 18 ++++++++++-------- sound/soc/fsl/imx-pcm.h | 15 +++++++++++++-- sound/soc/fsl/imx-ssi.c | 7 ++++++- sound/soc/fsl/imx-ssi.h | 1 + 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 310d90290320..3b2ba994beee 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include "imx-ssi.h" +#include "imx-pcm.h" struct imx_pcm_runtime_data { unsigned int period; @@ -366,9 +368,9 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = { .pcm_free = imx_pcm_fiq_free, }; -int imx_pcm_fiq_init(struct platform_device *pdev) +int imx_pcm_fiq_init(struct platform_device *pdev, + struct imx_pcm_fiq_params *params) { - struct imx_ssi *ssi = platform_get_drvdata(pdev); int ret; ret = claim_fiq(&fh); @@ -377,15 +379,15 @@ int imx_pcm_fiq_init(struct platform_device *pdev) return ret; } - mxc_set_irq_fiq(ssi->irq, 1); - ssi_irq = ssi->irq; + mxc_set_irq_fiq(params->irq, 1); + ssi_irq = params->irq; - imx_pcm_fiq = ssi->irq; + imx_pcm_fiq = params->irq; - imx_ssi_fiq_base = (unsigned long)ssi->base; + imx_ssi_fiq_base = (unsigned long)params->base; - ssi->dma_params_tx.maxburst = 4; - ssi->dma_params_rx.maxburst = 6; + params->dma_params_tx->maxburst = 4; + params->dma_params_rx->maxburst = 6; ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq); if (ret) diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index 67f656c7c320..fd56cad43cd6 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -32,6 +32,15 @@ imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, dma_data->peripheral_type = IMX_DMATYPE_SSI; } +struct imx_pcm_fiq_params { + int irq; + void __iomem *base; + + /* Pointer to original ssi driver to setup tx rx sizes */ + struct snd_dmaengine_dai_dma_data *dma_params_rx; + struct snd_dmaengine_dai_dma_data *dma_params_tx; +}; + #ifdef CONFIG_SND_SOC_IMX_PCM_DMA int imx_pcm_dma_init(struct platform_device *pdev); void imx_pcm_dma_exit(struct platform_device *pdev); @@ -47,10 +56,12 @@ static inline void imx_pcm_dma_exit(struct platform_device *pdev) #endif #ifdef CONFIG_SND_SOC_IMX_PCM_FIQ -int imx_pcm_fiq_init(struct platform_device *pdev); +int imx_pcm_fiq_init(struct platform_device *pdev, + struct imx_pcm_fiq_params *params); void imx_pcm_fiq_exit(struct platform_device *pdev); #else -static inline int imx_pcm_fiq_init(struct platform_device *pdev) +static inline int imx_pcm_fiq_init(struct platform_device *pdev, + struct imx_pcm_fiq_params *params) { return -ENODEV; } diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 51be3772cba9..f029e27366de 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -595,7 +595,12 @@ static int imx_ssi_probe(struct platform_device *pdev) goto failed_register; } - ret = imx_pcm_fiq_init(pdev); + ssi->fiq_params.irq = ssi->irq; + ssi->fiq_params.base = ssi->base; + ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx; + ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; + + ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params); if (ret) goto failed_pcm_fiq; diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h index d5003cefca8d..fb1616ba8c59 100644 --- a/sound/soc/fsl/imx-ssi.h +++ b/sound/soc/fsl/imx-ssi.h @@ -209,6 +209,7 @@ struct imx_ssi { struct snd_dmaengine_dai_dma_data dma_params_tx; struct imx_dma_data filter_data_tx; struct imx_dma_data filter_data_rx; + struct imx_pcm_fiq_params fiq_params; int enabled; }; From 624dcbdea24b599484895ed5b6a18e869e08d2a5 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Thu, 20 Jun 2013 15:20:28 +0200 Subject: [PATCH 0285/6183] ASoC: fsl: Move fsl-ssi binding doc to sound/ fsl-ssi was located in powerpc/fsl/ssi.txt. This is no powerpc specific device, so it should be moved to sound/ as it connects to differen audio codecs. Signed-off-by: Markus Pargmann Tested-by: Shawn Guo Signed-off-by: Mark Brown --- .../bindings/{powerpc/fsl/ssi.txt => sound/fsl,ssi.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/{powerpc/fsl/ssi.txt => sound/fsl,ssi.txt} (100%) diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt b/Documentation/devicetree/bindings/sound/fsl,ssi.txt similarity index 100% rename from Documentation/devicetree/bindings/powerpc/fsl/ssi.txt rename to Documentation/devicetree/bindings/sound/fsl,ssi.txt From b2c119b0bba808608c48a8f7c9d727956d56561a Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 10 Jul 2013 18:43:54 +0800 Subject: [PATCH 0286/6183] ASoC: fsl: Disable SSI in trigger() if RE/TE are both cleared The code enabled SSIEN when triggered by SNDRV_PCM_TRIGGER_START, so move the disable code to SNDRV_PCM_TRIGGER_STOP for symmetric. This also allows us to use the SSI driver more flexible so that it can support some use cases like "aplay S16_LE.wav S24_LE.wav" which would call the driver in sequence like: startup()->hw_params(S16_LE)->trigger(START)->tirgger(STOP)-> hw_params(S24_LE)->trigger(START)->tirgger(STOP)->shutdown() If we disable SSIEN in shutdown(), the second hw_params() would bypass the sample bits setting while using symmetric_rate. Signed-off-by: Nicolin Chen Acked-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2f2d837df07f..b6ab341a875c 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -510,6 +510,9 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0); else write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0); + + if ((read_ssi(&ssi->scr) & (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) + write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); break; default: @@ -534,15 +537,6 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, ssi_private->first_stream = ssi_private->second_stream; ssi_private->second_stream = NULL; - - /* - * If this is the last active substream, disable the SSI. - */ - if (!ssi_private->first_stream) { - struct ccsr_ssi __iomem *ssi = ssi_private->ssi; - - write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); - } } static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) From b641edfbf253a67a87698df275e3a35a7deac5d4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:31:58 +0100 Subject: [PATCH 0287/6183] ASoC: pcm3008: Remove noisy version print The version number has never been updated and the printk isn't based on any interaction with the device. Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3008.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index f2a6282b41f4..32e5a591f921 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -28,8 +28,6 @@ #include "pcm3008.h" -#define PCM3008_VERSION "0.2" - #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000) @@ -64,8 +62,6 @@ static int pcm3008_soc_probe(struct snd_soc_codec *codec) struct pcm3008_setup_data *setup = codec->dev->platform_data; int ret = 0; - printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); - /* DEM1 DEM0 DE-EMPHASIS_MODE * Low Low De-emphasis 44.1 kHz ON * Low High De-emphasis OFF From d7f184958e5292280c1048df951932bbfcd95f60 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:48:24 +0100 Subject: [PATCH 0288/6183] ASoC: pcm3008: Move gpio allocation to probe This is better from a device model point of view since we don't try to do things like instantiate the card until the required resources appear. Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3008.c | 89 +++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 32e5a591f921..8ab1c03d26bd 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -57,10 +57,40 @@ static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) gpio_free(setup->pdda_pin); } -static int pcm3008_soc_probe(struct snd_soc_codec *codec) +#ifdef CONFIG_PM +static int pcm3008_soc_suspend(struct snd_soc_codec *codec) { struct pcm3008_setup_data *setup = codec->dev->platform_data; - int ret = 0; + + gpio_set_value(setup->pdad_pin, 0); + gpio_set_value(setup->pdda_pin, 0); + + return 0; +} + +static int pcm3008_soc_resume(struct snd_soc_codec *codec) +{ + struct pcm3008_setup_data *setup = codec->dev->platform_data; + + gpio_set_value(setup->pdad_pin, 1); + gpio_set_value(setup->pdda_pin, 1); + + return 0; +} +#else +#define pcm3008_soc_suspend NULL +#define pcm3008_soc_resume NULL +#endif + +static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { + .suspend = pcm3008_soc_suspend, + .resume = pcm3008_soc_resume, +}; + +static int pcm3008_codec_probe(struct platform_device *pdev) +{ + struct pcm3008_setup_data *setup = pdev->dev.platform_data; + int ret; /* DEM1 DEM0 DE-EMPHASIS_MODE * Low Low De-emphasis 44.1 kHz ON @@ -97,63 +127,22 @@ static int pcm3008_soc_probe(struct snd_soc_codec *codec) if (ret != 0) goto gpio_err; - return ret; + return snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_pcm3008, &pcm3008_dai, 1); gpio_err: pcm3008_gpio_free(setup); - return ret; } -static int pcm3008_soc_remove(struct snd_soc_codec *codec) -{ - struct pcm3008_setup_data *setup = codec->dev->platform_data; - - pcm3008_gpio_free(setup); - return 0; -} - -#ifdef CONFIG_PM -static int pcm3008_soc_suspend(struct snd_soc_codec *codec) -{ - struct pcm3008_setup_data *setup = codec->dev->platform_data; - - gpio_set_value(setup->pdad_pin, 0); - gpio_set_value(setup->pdda_pin, 0); - - return 0; -} - -static int pcm3008_soc_resume(struct snd_soc_codec *codec) -{ - struct pcm3008_setup_data *setup = codec->dev->platform_data; - - gpio_set_value(setup->pdad_pin, 1); - gpio_set_value(setup->pdda_pin, 1); - - return 0; -} -#else -#define pcm3008_soc_suspend NULL -#define pcm3008_soc_resume NULL -#endif - -static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = { - .probe = pcm3008_soc_probe, - .remove = pcm3008_soc_remove, - .suspend = pcm3008_soc_suspend, - .resume = pcm3008_soc_resume, -}; - -static int pcm3008_codec_probe(struct platform_device *pdev) -{ - return snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_pcm3008, &pcm3008_dai, 1); -} - static int pcm3008_codec_remove(struct platform_device *pdev) { + struct pcm3008_setup_data *setup = pdev->dev.platform_data; + snd_soc_unregister_codec(&pdev->dev); + + pcm3008_gpio_free(setup); + return 0; } From 33319a2fcc4482a97a8924e777bc0036d1d96696 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:49:16 +0100 Subject: [PATCH 0289/6183] ASoC: pcm3008: Check for platform data The driver will crash if none is provided. Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3008.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 8ab1c03d26bd..4fa4ded30407 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -92,6 +92,9 @@ static int pcm3008_codec_probe(struct platform_device *pdev) struct pcm3008_setup_data *setup = pdev->dev.platform_data; int ret; + if (!setup) + return -EINVAL; + /* DEM1 DEM0 DE-EMPHASIS_MODE * Low Low De-emphasis 44.1 kHz ON * Low High De-emphasis OFF From d57a79acc77160089e191b6c78e9d42bed517a62 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:53:55 +0100 Subject: [PATCH 0290/6183] ASoC: pcm3008: Convert to devm_gpio_request_one() Signed-off-by: Mark Brown --- sound/soc/codecs/pcm3008.c | 44 +++++++++++--------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 4fa4ded30407..b883f99d6f9f 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -49,14 +49,6 @@ static struct snd_soc_dai_driver pcm3008_dai = { }, }; -static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) -{ - gpio_free(setup->dem0_pin); - gpio_free(setup->dem1_pin); - gpio_free(setup->pdad_pin); - gpio_free(setup->pdda_pin); -} - #ifdef CONFIG_PM static int pcm3008_soc_suspend(struct snd_soc_codec *codec) { @@ -103,49 +95,37 @@ static int pcm3008_codec_probe(struct platform_device *pdev) */ /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ - ret = gpio_request(setup->dem0_pin, "codec_dem0"); - if (ret == 0) - ret = gpio_direction_output(setup->dem0_pin, 1); + ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin, + GPIOF_OUT_INIT_HIGH, "codec_dem0"); if (ret != 0) - goto gpio_err; + return ret; /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ - ret = gpio_request(setup->dem1_pin, "codec_dem1"); - if (ret == 0) - ret = gpio_direction_output(setup->dem1_pin, 0); + ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin, + GPIOF_OUT_INIT_LOW, "codec_dem1"); if (ret != 0) - goto gpio_err; + return ret; /* Configure PDAD GPIO. */ - ret = gpio_request(setup->pdad_pin, "codec_pdad"); - if (ret == 0) - ret = gpio_direction_output(setup->pdad_pin, 1); + ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin, + GPIOF_OUT_INIT_HIGH, "codec_pdad"); if (ret != 0) - goto gpio_err; + return ret; /* Configure PDDA GPIO. */ - ret = gpio_request(setup->pdda_pin, "codec_pdda"); - if (ret == 0) - ret = gpio_direction_output(setup->pdda_pin, 1); + ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin, + GPIOF_OUT_INIT_HIGH, "codec_pdda"); if (ret != 0) - goto gpio_err; + return ret; return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm3008, &pcm3008_dai, 1); - -gpio_err: - pcm3008_gpio_free(setup); - return ret; } static int pcm3008_codec_remove(struct platform_device *pdev) { - struct pcm3008_setup_data *setup = pdev->dev.platform_data; - snd_soc_unregister_codec(&pdev->dev); - pcm3008_gpio_free(setup); - return 0; } From 0d6178662cf3dde6829ace63408f25cab42e21c3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Jul 2013 17:26:21 +0800 Subject: [PATCH 0291/6183] ASoC: brownstone: add .owner to struct snd_soc_card Add missing .owner of struct snd_soc_card. This prevents the module from being removed from underneath its users. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/pxa/brownstone.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 4ad76099dd43..5b7d969f89a9 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -129,6 +129,7 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = { /* audio machine driver */ static struct snd_soc_card brownstone = { .name = "brownstone", + .owner = THIS_MODULE, .dai_link = brownstone_wm8994_dai, .num_links = ARRAY_SIZE(brownstone_wm8994_dai), From 3986b9829f638c8a7864e81cdb066aa3d79f05a5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Jul 2013 17:26:40 +0800 Subject: [PATCH 0292/6183] ASoC: ttc_dkb: add .owner to struct snd_soc_card Add missing .owner of struct snd_soc_card. This prevents the module from being removed from underneath its users. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/pxa/ttc-dkb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c index f4ea4f6663a2..13c9ee0cb83b 100644 --- a/sound/soc/pxa/ttc-dkb.c +++ b/sound/soc/pxa/ttc-dkb.c @@ -122,6 +122,7 @@ static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = { /* ttc/td audio machine driver */ static struct snd_soc_card ttc_dkb_card = { .name = "ttc-dkb-hifi", + .owner = THIS_MODULE, .dai_link = ttc_pm860x_hifi_dai, .num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai), From e7c8c589bb640a86685ee040e683b1ec93339f13 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Jul 2013 17:25:37 +0800 Subject: [PATCH 0293/6183] ASoC: mop500: add .owner to struct snd_soc_card Add missing .owner of struct snd_soc_card. This prevents the module from being removed from underneath its users. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/ux500/mop500.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 8f5cd00a6e46..178d1bad6259 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -52,6 +52,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = { static struct snd_soc_card mop500_card = { .name = "MOP500-card", + .owner = THIS_MODULE, .probe = NULL, .dai_link = mop500_dai_links, .num_links = ARRAY_SIZE(mop500_dai_links), From 57e265c8d71fb94c130bfb31f589cc9e97fb3928 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Jul 2013 20:46:34 +0100 Subject: [PATCH 0294/6183] ASoC: wm8994: Move runtime PM init to platform device init As well as being better style this allows the device to idle when there is no audio card instantaited which is probably what we want. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1d4b1ec66e36..02c320f71cdf 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -4014,9 +4014,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->micdet_irq = control->pdata.micdet_irq; - pm_runtime_enable(codec->dev); - pm_runtime_idle(codec->dev); - /* By default use idle_bias_off, will override for WM8994 */ codec->dapm.idle_bias_off = 1; @@ -4389,8 +4386,6 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); - pm_runtime_disable(codec->dev); - for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i, &wm8994->fll_locked[i]); @@ -4449,6 +4444,9 @@ static int wm8994_probe(struct platform_device *pdev) wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994, wm8994_dai, ARRAY_SIZE(wm8994_dai)); } @@ -4456,6 +4454,8 @@ static int wm8994_probe(struct platform_device *pdev) static int wm8994_remove(struct platform_device *pdev) { snd_soc_unregister_codec(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return 0; } From cb23e852aabb50f5083fb734c2067220d087d26e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 4 Jul 2013 20:01:01 -0300 Subject: [PATCH 0295/6183] ASoC: sglt5000: Provide the reg_stride field sgtl5000 has 16-bit registers, and only even numbers are valid for its registers addresses. Let regmap knows about this feature by specifying the 'reg_stride' field, so that it can access only the valid registers. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index d441559dc92c..7c99f3ccb1c6 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1470,6 +1470,7 @@ static struct snd_soc_codec_driver sgtl5000_driver = { static const struct regmap_config sgtl5000_regmap = { .reg_bits = 16, .val_bits = 16, + .reg_stride = 2, .max_register = SGTL5000_MAX_REG_OFFSET, .volatile_reg = sgtl5000_volatile, From dc9ceed6a12aff627c81e01ada191e8a23fcbe3e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Jul 2013 17:27:14 +0100 Subject: [PATCH 0296/6183] regulator: core: Make set_voltage_tol() try for mid-range first The expected semantic for something expressed as a tolerance is that it should deliver the specified value with some deviation allowed but this is not what set_voltage_tol() currently does. Instead it just passes the maximum possible range to set_voltage() which will typically result in a voltage aimed at lower than the target voltage. Instead first try to set a voltage between the target voltage and the upper limit, then fall back on the full range. This will be much more robust against physical variation in systems and makes the API behave more like users would expect. Signed-off-by: Mark Brown --- include/linux/regulator/consumer.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 3a76389c6aaa..3610df8dd229 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -369,8 +369,11 @@ static inline int regulator_count_voltages(struct regulator *regulator) static inline int regulator_set_voltage_tol(struct regulator *regulator, int new_uV, int tol_uV) { - return regulator_set_voltage(regulator, - new_uV - tol_uV, new_uV + tol_uV); + if (regulator_set_voltage(regulator, new_uV, new_uV + tol_uV) == 0) + return 0; + else + return regulator_set_voltage(regulator, + new_uV - tol_uV, new_uV + tol_uV); } static inline int regulator_is_supported_voltage_tol(struct regulator *regulator, From 891636ea27ef42d92a420185d2ccbe190ba00a23 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 8 Jul 2013 09:14:45 +0100 Subject: [PATCH 0297/6183] regulator: core: Drop references on supply regulator when unregistering Signed-off-by: Mark Brown --- drivers/regulator/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 288c75abc190..1510333bcf0d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3740,8 +3740,11 @@ void regulator_unregister(struct regulator_dev *rdev) if (rdev == NULL) return; - if (rdev->supply) + if (rdev->supply) { + while (rdev->use_count--) + regulator_disable(rdev->supply); regulator_put(rdev->supply); + } mutex_lock(®ulator_list_mutex); debugfs_remove_recursive(rdev->debugfs); flush_work(&rdev->disable_work.work); From 94d33c02c7186b69849c292e1216a08ad1c0d99d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 22:52:41 +0100 Subject: [PATCH 0298/6183] regulator: core: Add helpers for multiple linear ranges Many regulators have several linear ranges of selector with different step sizes, for example offering better resolution at lower voltages. Provide regulator_{map,list}_voltage_linear_range() allowing these regulators to use generic code. To do so a table of regulator_linear_range structs needs to be pointed to from the descriptor. This was inspired by similar code included in a driver submission from Chao Xie and Yi Zhang at Marvell. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 87 ++++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 25 +++++++++ 2 files changed, 112 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 288c75abc190..e8604be4c66d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2078,6 +2078,43 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); +/** + * regulator_list_voltage_linear_range - List voltages for linear ranges + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with a series of simple linear mappings between voltages + * and selectors can set linear_ranges in the regulator descriptor and + * then use this function as their list_voltage() operation, + */ +int regulator_list_voltage_linear_range(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct regulator_linear_range *range; + int i; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + range = &rdev->desc->linear_ranges[i]; + + if (!(selector >= range->min_sel && + selector <= range->max_sel)) + continue; + + selector -= range->min_sel; + + return range->min_uV + (range->uV_step * selector); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range); + /** * regulator_list_voltage_table - List voltages with table based mapping * @@ -2368,6 +2405,56 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_map_voltage_linear); +/** + * regulator_map_voltage_linear - map_voltage() for multiple linear ranges + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers providing linear_ranges in their descriptor can use this as + * their map_voltage() callback. + */ +int regulator_map_voltage_linear_range(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + const struct regulator_linear_range *range; + int ret = -EINVAL; + int voltage, i; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + range = &rdev->desc->linear_ranges[i]; + + if (!(min_uV <= range->max_uV && max_uV >= range->min_uV)) + continue; + + if (min_uV <= range->min_uV) + min_uV = range->min_uV; + + ret = DIV_ROUND_UP(min_uV - range->min_uV, range->uV_step); + if (ret < 0) + return ret; + + break; + } + + if (i == rdev->desc->n_linear_ranges) + return -EINVAL; + + /* Map back into a voltage to verify we're still in bounds */ + voltage = rdev->desc->ops->list_voltage(rdev, ret); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); + static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 6700cc94bdd1..67e13aa5a478 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -39,6 +39,24 @@ enum regulator_status { REGULATOR_STATUS_UNDEFINED, }; +/** + * Specify a range of voltages for regulator_map_linar_range() and + * regulator_list_linear_range(). + * + * @min_uV: Lowest voltage in range + * @max_uV: Highest voltage in range + * @min_sel: Lowest selector for range + * @max_sel: Highest selector for range + * @uV_step: Step size + */ +struct regulator_linear_range { + unsigned int min_uV; + unsigned int max_uV; + unsigned int min_sel; + unsigned int max_sel; + unsigned int uV_step; +}; + /** * struct regulator_ops - regulator operations. * @@ -223,6 +241,9 @@ struct regulator_desc { unsigned int linear_min_sel; unsigned int ramp_delay; + const struct regulator_linear_range *linear_ranges; + int n_linear_ranges; + const unsigned int *volt_table; unsigned int vsel_reg; @@ -326,10 +347,14 @@ int regulator_mode_to_status(unsigned int); int regulator_list_voltage_linear(struct regulator_dev *rdev, unsigned int selector); +int regulator_list_voltage_linear_range(struct regulator_dev *rdev, + unsigned int selector); int regulator_list_voltage_table(struct regulator_dev *rdev, unsigned int selector); int regulator_map_voltage_linear(struct regulator_dev *rdev, int min_uV, int max_uV); +int regulator_map_voltage_linear_range(struct regulator_dev *rdev, + int min_uV, int max_uV); int regulator_map_voltage_iterate(struct regulator_dev *rdev, int min_uV, int max_uV); int regulator_map_voltage_ascend(struct regulator_dev *rdev, From 6692e432a9d59b55edbfdb4ed388e03c7f17e43c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:26:36 +0100 Subject: [PATCH 0299/6183] regulator: wm8400: Use linear ranges Signed-off-by: Mark Brown --- drivers/regulator/wm8400-regulator.c | 50 +++++++++------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index a09f03ee5506..2ac7e1aceb05 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -19,47 +19,21 @@ #include #include -static int wm8400_ldo_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - if (selector > WM8400_LDO1_VSEL_MASK) - return -EINVAL; - - if (selector < 15) - return 900000 + (selector * 50000); - else - return 1700000 + ((selector - 15) * 100000); -} - -static int wm8400_ldo_map_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) -{ - u16 val; - int volt; - - if (min_uV < 900000 || min_uV > 3300000) - return -EINVAL; - - if (min_uV < 1700000) /* Steps of 50mV from 900mV; */ - val = DIV_ROUND_UP(min_uV - 900000, 50000); - else /* Steps of 100mV from 1700mV */ - val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15; - - volt = wm8400_ldo_list_voltage(dev, val); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return val; -} +static const struct regulator_linear_range wm8400_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, + .uV_step = 100000 }, +}; static struct regulator_ops wm8400_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .list_voltage = wm8400_ldo_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .map_voltage = wm8400_ldo_map_voltage, + .map_voltage = regulator_map_voltage_linear_range, }; static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev) @@ -155,6 +129,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO1_CONTROL, .enable_mask = WM8400_LDO1_ENA, .n_voltages = WM8400_LDO1_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO1_CONTROL, .vsel_mask = WM8400_LDO1_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -167,6 +143,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO2_CONTROL, .enable_mask = WM8400_LDO2_ENA, .n_voltages = WM8400_LDO2_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .type = REGULATOR_VOLTAGE, .vsel_reg = WM8400_LDO2_CONTROL, .vsel_mask = WM8400_LDO2_VSEL_MASK, @@ -179,6 +157,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO3_CONTROL, .enable_mask = WM8400_LDO3_ENA, .n_voltages = WM8400_LDO3_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO3_CONTROL, .vsel_mask = WM8400_LDO3_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -191,6 +171,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO4_CONTROL, .enable_mask = WM8400_LDO4_ENA, .n_voltages = WM8400_LDO4_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO4_CONTROL, .vsel_mask = WM8400_LDO4_VSEL_MASK, .type = REGULATOR_VOLTAGE, From 5ff26a14c333113967f3abe5fcb81c8e49d282c0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:35:22 +0100 Subject: [PATCH 0300/6183] regulator: wm831x-ldo: Convert to use linear ranges Signed-off-by: Mark Brown --- drivers/regulator/wm831x-ldo.c | 104 ++++++++------------------------- 1 file changed, 24 insertions(+), 80 deletions(-) diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9ff883f80878..76792c7d86f3 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -62,41 +62,12 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data) * General purpose LDOs */ -#define WM831X_GP_LDO_SELECTOR_LOW 0xe -#define WM831X_GP_LDO_MAX_SELECTOR 0x1f - -static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 0.9-1.6V in 50mV steps */ - if (selector <= WM831X_GP_LDO_SELECTOR_LOW) - return 900000 + (selector * 50000); - /* 1.7-3.3V in 100mV steps */ - if (selector <= WM831X_GP_LDO_MAX_SELECTOR) - return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW) - * 100000); - return -EINVAL; -} - -static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int volt, vsel; - - if (min_uV < 900000) - vsel = 0; - else if (min_uV < 1700000) - vsel = ((min_uV - 900000) / 50000); - else - vsel = ((min_uV - 1700000) / 100000) - + WM831X_GP_LDO_SELECTOR_LOW + 1; - - volt = wm831x_gp_ldo_list_voltage(rdev, vsel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return vsel; -} +static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1650000, .min_sel = 0, .max_sel = 14, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -105,7 +76,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, struct wm831x *wm831x = ldo->wm831x; int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return sel; @@ -230,8 +201,8 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { - .list_voltage = wm831x_gp_ldo_list_voltage, - .map_voltage = wm831x_gp_ldo_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, @@ -290,7 +261,7 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; - ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1; + ldo->desc.n_voltages = 32; ldo->desc.ops = &wm831x_gp_ldo_ops; ldo->desc.owner = THIS_MODULE; ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; @@ -299,6 +270,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.enable_mask = 1 << id; ldo->desc.bypass_reg = ldo->base; ldo->desc.bypass_mask = WM831X_LDO1_SWI; + ldo->desc.linear_ranges = wm831x_gp_ldo_ranges; + ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges); config.dev = pdev->dev.parent; if (pdata) @@ -358,43 +331,12 @@ static struct platform_driver wm831x_gp_ldo_driver = { * Analogue LDOs */ - -#define WM831X_ALDO_SELECTOR_LOW 0xc -#define WM831X_ALDO_MAX_SELECTOR 0x1f - -static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 1-1.6V in 50mV steps */ - if (selector <= WM831X_ALDO_SELECTOR_LOW) - return 1000000 + (selector * 50000); - /* 1.7-3.5V in 100mV steps */ - if (selector <= WM831X_ALDO_MAX_SELECTOR) - return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW) - * 100000); - return -EINVAL; -} - -static int wm831x_aldo_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int volt, vsel; - - if (min_uV < 1000000) - vsel = 0; - else if (min_uV < 1700000) - vsel = ((min_uV - 1000000) / 50000); - else - vsel = ((min_uV - 1700000) / 100000) - + WM831X_ALDO_SELECTOR_LOW + 1; - - volt = wm831x_aldo_list_voltage(rdev, vsel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return vsel; - -} +static const struct regulator_linear_range wm831x_aldo_ranges[] = { + { .min_uV = 1000000, .max_uV = 1650000, .min_sel = 0, .max_sel = 12, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -403,7 +345,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, struct wm831x *wm831x = ldo->wm831x; int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - sel = wm831x_aldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return sel; @@ -486,8 +428,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) } static struct regulator_ops wm831x_aldo_ops = { - .list_voltage = wm831x_aldo_list_voltage, - .map_voltage = wm831x_aldo_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, @@ -545,7 +487,9 @@ static int wm831x_aldo_probe(struct platform_device *pdev) ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; - ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1; + ldo->desc.n_voltages = 32; + ldo->desc.linear_ranges = wm831x_aldo_ranges; + ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges); ldo->desc.ops = &wm831x_aldo_ops; ldo->desc.owner = THIS_MODULE; ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; From c36a1cdf96dd3a4e6b612d6847bff6c7086e358b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 23:35:42 +0100 Subject: [PATCH 0301/6183] regulator: wm8350: Convert to use linear ranges Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 55 +++++++++------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7f0fa22ef2aa..5453dd0105ed 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -542,41 +542,12 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev, return 0; } -static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector > WM8350_LDO1_VSEL_MASK) - return -EINVAL; - - if (selector < 16) - return (selector * 50000) + 900000; - else - return ((selector - 16) * 100000) + 1800000; -} - -static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) -{ - int volt, sel; - int min_mV = min_uV / 1000; - int max_mV = max_uV / 1000; - - if (min_mV < 900 || min_mV > 3300) - return -EINVAL; - if (max_mV < 900 || max_mV > 3300) - return -EINVAL; - - if (min_mV < 1800) /* step size is 50mV < 1800mV */ - sel = DIV_ROUND_UP(min_uV - 900, 50); - else /* step size is 100mV > 1800mV */ - sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16; - - volt = wm8350_ldo_list_voltage(rdev, sel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return sel; -} +static const struct regulator_linear_range wm8350_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1750000, .min_sel = 0, .max_sel = 15, + .uV_step = 50000 }, + { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { @@ -603,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) return -EINVAL; } - sel = wm8350_ldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return -EINVAL; @@ -998,10 +969,10 @@ static struct regulator_ops wm8350_dcdc2_5_ops = { }; static struct regulator_ops wm8350_ldo_ops = { - .map_voltage = wm8350_ldo_map_voltage, + .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .list_voltage = wm8350_ldo_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -1108,6 +1079,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO1, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO1_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO1_CONTROL, .vsel_mask = WM8350_LDO1_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1121,6 +1094,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO2, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO2_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO2_CONTROL, .vsel_mask = WM8350_LDO2_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1134,6 +1109,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO3, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO3_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO3_CONTROL, .vsel_mask = WM8350_LDO3_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1147,6 +1124,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO4, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO4_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO4_CONTROL, .vsel_mask = WM8350_LDO4_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, From 37a6f43dd1924013cbf2eb91b74b3cc9818b3af8 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Wed, 3 Jul 2013 10:30:57 +0900 Subject: [PATCH 0302/6183] regulator: lp872x: fix a build waring and coding styles Fix a warning below. drivers/regulator/lp872x.c:910:33: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] And checkpatch warnings are fixed. WARNING: space prohibited before semicolon Signed-off-by: Milo Kim Signed-off-by: Mark Brown --- drivers/regulator/lp872x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index b16336bcd4d4..1018fb2020a9 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -373,7 +373,7 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, return -EINVAL; } - for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) { + for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) { if (lp8725_buck_uA[i] >= min_uA && lp8725_buck_uA[i] <= max_uA) return lp872x_update_bits(lp, addr, @@ -787,7 +787,7 @@ static int lp872x_regulator_register(struct lp872x *lp) struct regulator_dev *rdev; int i, ret; - for (i = 0 ; i < lp->num_regulators ; i++) { + for (i = 0; i < lp->num_regulators; i++) { desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : &lp8725_regulator_desc[i]; @@ -820,7 +820,7 @@ static void lp872x_regulator_unregister(struct lp872x *lp) struct regulator_dev *rdev; int i; - for (i = 0 ; i < lp->num_regulators ; i++) { + for (i = 0; i < lp->num_regulators; i++) { rdev = *(lp->regulators + i); regulator_unregister(rdev); } @@ -907,7 +907,8 @@ static struct lp872x_platform_data goto out; for (i = 0; i < num_matches; i++) { - pdata->regulator_data[i].id = (int)match[i].driver_data; + pdata->regulator_data[i].id = + (enum lp872x_regulator_id)match[i].driver_data; pdata->regulator_data[i].init_data = match[i].init_data; /* Operation mode configuration for buck/buck1/buck2 */ From 1653ccf4c52df6a4abe8ec2f33f2cb2896d129ea Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sat, 29 Jun 2013 18:21:15 +0530 Subject: [PATCH 0303/6183] regulator: core: Add support for disabling ramp delay Some hardwares support disabling ramp delay, so adding ramp_disable flag to constraints. It will be used to figure out whether ramp_delay in constraints is explicitly set to zero or its unintialized (zero by default). And we don't need to call set_voltage_time_sel() for regulators for whom ramp delay is disabled in constraints. Signed-off-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/regulator.txt | 2 ++ drivers/regulator/core.c | 6 ++++-- drivers/regulator/of_regulator.c | 12 +++++++++--- include/linux/regulator/machine.h | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 48a3b8e5d6bd..2bd8f0978765 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -12,6 +12,8 @@ Optional properties: - regulator-allow-bypass: allow the regulator to go into bypass mode - -supply: phandle to the parent supply/regulator node - regulator-ramp-delay: ramp delay for regulator(in uV/uS) + For hardwares which support disabling ramp rate, it should be explicitly + intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 288c75abc190..6e6371c2346c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -984,7 +984,8 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } - if (rdev->constraints->ramp_delay && ops->set_ramp_delay) { + if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable) + && ops->set_ramp_delay) { ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay); if (ret < 0) { rdev_err(rdev, "failed to set ramp_delay\n"); @@ -2438,7 +2439,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 && + if (ret == 0 && !rdev->constraints->ramp_disable && + _regulator_is_enabled(rdev) && old_selector >= 0 && old_selector != selector && rdev->desc->ops->set_voltage_time_sel) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index f3c8f8f9dc39..7827384680d6 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -21,6 +21,7 @@ static void of_get_regulation_constraints(struct device_node *np, { const __be32 *min_uV, *max_uV, *uV_offset; const __be32 *min_uA, *max_uA, *ramp_delay; + struct property *prop; struct regulation_constraints *constraints = &(*init_data)->constraints; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -64,9 +65,14 @@ static void of_get_regulation_constraints(struct device_node *np, if (of_property_read_bool(np, "regulator-allow-bypass")) constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS; - ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL); - if (ramp_delay) - constraints->ramp_delay = be32_to_cpu(*ramp_delay); + prop = of_find_property(np, "regulator-ramp-delay", NULL); + if (prop && prop->value) { + ramp_delay = prop->value; + if (*ramp_delay) + constraints->ramp_delay = be32_to_cpu(*ramp_delay); + else + constraints->ramp_disable = true; + } } /** diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 36adbc82de6a..999b20ce06cf 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -134,6 +134,7 @@ struct regulation_constraints { unsigned always_on:1; /* regulator never off when system is on */ unsigned boot_on:1; /* bootloader/firmware enabled regulator */ unsigned apply_uV:1; /* apply uV constraint if min == max */ + unsigned ramp_disable:1; /* disable ramp delay */ }; /** From 5b175952011adae30b531ab89cc24acb173b2ce4 Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sat, 29 Jun 2013 18:21:19 +0530 Subject: [PATCH 0304/6183] regulator: core: Remove redundant checks In function _regulator_do_set_voltage(), old_selector gets intialised only if (_regulator_is_enabled(rdev) && rdev->desc->ops->set_voltage_time_sel && rdev->desc->ops->get_voltage_sel)) is true. Before calling set_voltage_time_sel() we checks if (old_selector >= 0) and it will true if it got intialised properly. so we don't need to check again _regulator_is_enabled(rdev) && rdev->desc->ops->set_voltage_time_sel before calling set_voltage_time_sel(). Signed-off-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6e6371c2346c..15368f35bbdf 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2439,9 +2439,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (ret == 0 && !rdev->constraints->ramp_disable && - _regulator_is_enabled(rdev) && old_selector >= 0 && - old_selector != selector && rdev->desc->ops->set_voltage_time_sel) { + if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0 + && old_selector != selector) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, old_selector, selector); From 1e1598ed04d831f5bb42a197b4045e6780365217 Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Mon, 24 Jun 2013 16:50:56 +0530 Subject: [PATCH 0305/6183] regulator: s2mps11: Implement set_voltage_time_sel() ops for bucks Currently driver uses local struct s2mps11_info to store ramp rate for bucks whic its getting through platform data, so instead of using regulator constraints it should use s2mps11_info to calculate ramp delay. Signed-off-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 53 ++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 2f62564ca936..a671eb63a4e5 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -53,6 +53,57 @@ static int get_ramp_delay(int ramp_delay) return cnt; } +static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + unsigned int ramp_delay = 0; + int old_volt, new_volt; + + switch (rdev->desc->id) { + case S2MPS11_BUCK2: + if (!s2mps11->buck2_ramp) + return 0; + ramp_delay = s2mps11->ramp_delay2; + break; + case S2MPS11_BUCK3: + if (!s2mps11->buck3_ramp) + return 0; + ramp_delay = s2mps11->ramp_delay34; + break; + case S2MPS11_BUCK4: + if (!s2mps11->buck4_ramp) + return 0; + ramp_delay = s2mps11->ramp_delay34; + break; + case S2MPS11_BUCK5: + ramp_delay = s2mps11->ramp_delay5; + break; + case S2MPS11_BUCK6: + if (!s2mps11->buck6_ramp) + return 0; + case S2MPS11_BUCK1: + ramp_delay = s2mps11->ramp_delay16; + break; + case S2MPS11_BUCK7: + case S2MPS11_BUCK8: + case S2MPS11_BUCK10: + ramp_delay = s2mps11->ramp_delay7810; + break; + case S2MPS11_BUCK9: + ramp_delay = s2mps11->ramp_delay9; + } + + if (ramp_delay == 0) + ramp_delay = rdev->desc->ramp_delay; + + old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector); + new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector); + + return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); +} + static struct regulator_ops s2mps11_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -72,7 +123,7 @@ static struct regulator_ops s2mps11_buck_ops = { .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel, }; #define regulator_desc_ldo1(num) { \ From 874b31585650afa6745de5133849365e7e6af418 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 11:44:49 +0100 Subject: [PATCH 0306/6183] spi/bitbang: Unexport spi_bitbang_transfer() Currently no drivers use the ability to override spi_bitbang_transfer() and if any started this would make it harder to convert the bitbang code to use transfer_one_message() so remove the export in order to prevent anyone starting. Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 3 +-- include/linux/spi/spi_bitbang.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a63d7da3bfe2..495ce0a51d2f 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -376,7 +376,7 @@ static void bitbang_work(struct work_struct *work) /** * spi_bitbang_transfer - default submit to transfer queue */ -int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) +static int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) { struct spi_bitbang *bitbang; unsigned long flags; @@ -398,7 +398,6 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) return status; } -EXPORT_SYMBOL_GPL(spi_bitbang_transfer); /*----------------------------------------------------------------------*/ diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index f987a2bee16a..b5aa215493f6 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -41,7 +41,6 @@ struct spi_bitbang { */ extern int spi_bitbang_setup(struct spi_device *spi); extern void spi_bitbang_cleanup(struct spi_device *spi); -extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); extern int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t); From 91b308586793b48c590c9ac3528bbacb8ef53e15 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 12:06:44 +0100 Subject: [PATCH 0307/6183] spi/bitbang: Factor out message transfer from message pump loop In order to make it easier to convert to transfer_one_message() lift the code that does the actual message transfer out of the work function that implements the message pump. This should have no functional impact, it's just a simple code motion patch. Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 205 ++++++++++++++++++++------------------ 1 file changed, 107 insertions(+), 98 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 495ce0a51d2f..8b8487c9694e 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -255,6 +255,112 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */ +static int spi_bitbang_transfer_one(struct spi_device *spi, + struct spi_message *m) +{ + struct spi_bitbang *bitbang; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned tmp; + unsigned cs_change; + int status; + int do_setup = -1; + + bitbang = spi_master_get_devdata(spi->master); + + /* FIXME this is made-up ... the correct value is known to + * word-at-a-time bitbang code, and presumably chipselect() + * should enforce these requirements too? + */ + nsecs = 100; + + tmp = 0; + cs_change = 1; + status = 0; + + list_for_each_entry (t, &m->transfers, transfer_list) { + + /* override speed or wordsize? */ + if (t->speed_hz || t->bits_per_word) + do_setup = 1; + + /* init (-1) or override (1) transfer params */ + if (do_setup != 0) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) + break; + if (do_setup == -1) + do_setup = 0; + } + + /* set up default clock polarity, and activate chip; + * this implicitly updates clock and spi modes as + * previously recorded for this device via setup(). + * (and also deselects any other chip that might be + * selected ...) + */ + if (cs_change) { + bitbang->chipselect(spi, BITBANG_CS_ACTIVE); + ndelay(nsecs); + } + cs_change = t->cs_change; + if (!t->tx_buf && !t->rx_buf && t->len) { + status = -EINVAL; + break; + } + + /* transfer data. the lower level code handles any + * new dma mappings it needs. our caller always gave + * us dma-safe buffers. + */ + if (t->len) { + /* REVISIT dma API still needs a designated + * DMA_ADDR_INVALID; ~0 might be better. + */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; + status = bitbang->txrx_bufs(spi, t); + } + if (status > 0) + m->actual_length += status; + if (status != t->len) { + /* always report some kind of error */ + if (status >= 0) + status = -EREMOTEIO; + break; + } + status = 0; + + /* protocol tweaks before next transfer */ + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { + /* sometimes a short mid-message deselect of the chip + * may be needed to terminate a mode or command + */ + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); + } + } + + m->status = status; + m->complete(m->context); + + /* normally deactivate chipselect ... unless no error and + * cs_change has hinted that the next message will probably + * be for this chip too. + */ + if (!(status == 0 && cs_change)) { + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); + } + + return status; +} + static void bitbang_work(struct work_struct *work) { struct spi_bitbang *bitbang = @@ -265,107 +371,10 @@ static void bitbang_work(struct work_struct *work) spin_lock_irqsave(&bitbang->lock, flags); bitbang->busy = 1; list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { - struct spi_device *spi; - unsigned nsecs; - struct spi_transfer *t = NULL; - unsigned tmp; - unsigned cs_change; - int status; - int do_setup = -1; - list_del(&m->queue); spin_unlock_irqrestore(&bitbang->lock, flags); - /* FIXME this is made-up ... the correct value is known to - * word-at-a-time bitbang code, and presumably chipselect() - * should enforce these requirements too? - */ - nsecs = 100; - - spi = m->spi; - tmp = 0; - cs_change = 1; - status = 0; - - list_for_each_entry (t, &m->transfers, transfer_list) { - - /* override speed or wordsize? */ - if (t->speed_hz || t->bits_per_word) - do_setup = 1; - - /* init (-1) or override (1) transfer params */ - if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; - if (do_setup == -1) - do_setup = 0; - } - - /* set up default clock polarity, and activate chip; - * this implicitly updates clock and spi modes as - * previously recorded for this device via setup(). - * (and also deselects any other chip that might be - * selected ...) - */ - if (cs_change) { - bitbang->chipselect(spi, BITBANG_CS_ACTIVE); - ndelay(nsecs); - } - cs_change = t->cs_change; - if (!t->tx_buf && !t->rx_buf && t->len) { - status = -EINVAL; - break; - } - - /* transfer data. the lower level code handles any - * new dma mappings it needs. our caller always gave - * us dma-safe buffers. - */ - if (t->len) { - /* REVISIT dma API still needs a designated - * DMA_ADDR_INVALID; ~0 might be better. - */ - if (!m->is_dma_mapped) - t->rx_dma = t->tx_dma = 0; - status = bitbang->txrx_bufs(spi, t); - } - if (status > 0) - m->actual_length += status; - if (status != t->len) { - /* always report some kind of error */ - if (status >= 0) - status = -EREMOTEIO; - break; - } - status = 0; - - /* protocol tweaks before next transfer */ - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command - */ - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } - } - - m->status = status; - m->complete(m->context); - - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. - */ - if (!(status == 0 && cs_change)) { - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } + spi_bitbang_transfer_one(m->spi, m); spin_lock_irqsave(&bitbang->lock, flags); } From fa4bd4f1ade784d9cbed67ab228d0ad5edb3830d Mon Sep 17 00:00:00 2001 From: Scott Jiang Date: Wed, 26 Jun 2013 18:07:40 -0400 Subject: [PATCH 0308/6183] spi: add spi controller v3 master driver for Blackfin New spi controller(version 3) is integrated into Blackfin 60x processor. Comparing to bf5xx spi controller, we support 32 bits word size and independent receive and transmit DMA channels now. Also mode 0 and 2 (CPHA = 0) can get fully supported becasue cs line may be controlled by the software. Signed-off-by: Scott Jiang Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 9 +- drivers/spi/Makefile | 1 + drivers/spi/spi-bfin-v3.c | 973 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 982 insertions(+), 1 deletion(-) create mode 100644 drivers/spi/spi-bfin-v3.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 89cbbabaff44..e31bf77ab259 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -88,10 +88,17 @@ config SPI_BCM2835 config SPI_BFIN5XX tristate "SPI controller driver for ADI Blackfin5xx" - depends on BLACKFIN + depends on BLACKFIN && !BF60x help This is the SPI controller master driver for Blackfin 5xx processor. +config SPI_BFIN_V3 + tristate "SPI controller v3 for Blackfin" + depends on BF60x + help + This is the SPI controller v3 master driver + found on Blackfin 60x processor. + config SPI_BFIN_SPORT tristate "SPI bus via Blackfin SPORT" depends on BLACKFIN diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 33f9c09561e7..7c4170263cd8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o +obj-$(CONFIG_SPI_BFIN_V3) += spi-bfin-v3.o obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c new file mode 100644 index 000000000000..603d7e91085b --- /dev/null +++ b/drivers/spi/spi-bfin-v3.c @@ -0,0 +1,973 @@ +/* + * Analog Devices SPI3 controller driver + * + * Copyright (c) 2013 Analog Devices Inc. + * + * 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. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum bfin_spi_state { + START_STATE, + RUNNING_STATE, + DONE_STATE, + ERROR_STATE +}; + +struct bfin_spi_master; + +struct bfin_spi_transfer_ops { + void (*write) (struct bfin_spi_master *); + void (*read) (struct bfin_spi_master *); + void (*duplex) (struct bfin_spi_master *); +}; + +/* runtime info for spi master */ +struct bfin_spi_master { + /* SPI framework hookup */ + struct spi_master *master; + + /* Regs base of SPI controller */ + struct bfin_spi_regs __iomem *regs; + + /* Pin request list */ + u16 *pin_req; + + /* Message Transfer pump */ + struct tasklet_struct pump_transfers; + + /* Current message transfer state info */ + struct spi_message *cur_msg; + struct spi_transfer *cur_transfer; + struct bfin_spi_device *cur_chip; + unsigned transfer_len; + + /* transfer buffer */ + void *tx; + void *tx_end; + void *rx; + void *rx_end; + + /* dma info */ + unsigned int tx_dma; + unsigned int rx_dma; + dma_addr_t tx_dma_addr; + dma_addr_t rx_dma_addr; + unsigned long dummy_buffer; /* used in unidirectional transfer */ + unsigned long tx_dma_size; + unsigned long rx_dma_size; + int tx_num; + int rx_num; + + /* store register value for suspend/resume */ + u32 control; + u32 ssel; + + unsigned long sclk; + enum bfin_spi_state state; + + const struct bfin_spi_transfer_ops *ops; +}; + +struct bfin_spi_device { + u32 control; + u32 clock; + u32 ssel; + + u8 cs; + u16 cs_chg_udelay; /* Some devices require > 255usec delay */ + u32 cs_gpio; + u32 tx_dummy_val; /* tx value for rx only transfer */ + bool enable_dma; + const struct bfin_spi_transfer_ops *ops; +}; + +static void bfin_spi_enable(struct bfin_spi_master *drv_data) +{ + bfin_write_or(&drv_data->regs->control, SPI_CTL_EN); +} + +static void bfin_spi_disable(struct bfin_spi_master *drv_data) +{ + bfin_write_and(&drv_data->regs->control, ~SPI_CTL_EN); +} + +/* Caculate the SPI_CLOCK register value based on input HZ */ +static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz) +{ + u32 spi_clock = sclk / speed_hz; + + if (spi_clock) + spi_clock--; + return spi_clock; +} + +static int bfin_spi_flush(struct bfin_spi_master *drv_data) +{ + unsigned long limit = loops_per_jiffy << 1; + + /* wait for stop and clear stat */ + while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit) + cpu_relax(); + + bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + + return limit; +} + +/* Chip select operation functions for cs_change flag */ +static void bfin_spi_cs_active(struct bfin_spi_master *drv_data, struct bfin_spi_device *chip) +{ + if (likely(chip->cs < MAX_CTRL_CS)) + bfin_write_and(&drv_data->regs->ssel, ~chip->ssel); + else + gpio_set_value(chip->cs_gpio, 0); +} + +static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data, + struct bfin_spi_device *chip) +{ + if (likely(chip->cs < MAX_CTRL_CS)) + bfin_write_or(&drv_data->regs->ssel, chip->ssel); + else + gpio_set_value(chip->cs_gpio, 1); + + /* Move delay here for consistency */ + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); +} + +/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ +static inline void bfin_spi_cs_enable(struct bfin_spi_master *drv_data, + struct bfin_spi_device *chip) +{ + if (chip->cs < MAX_CTRL_CS) + bfin_write_or(&drv_data->regs->ssel, chip->ssel >> 8); +} + +static inline void bfin_spi_cs_disable(struct bfin_spi_master *drv_data, + struct bfin_spi_device *chip) +{ + if (chip->cs < MAX_CTRL_CS) + bfin_write_and(&drv_data->regs->ssel, ~(chip->ssel >> 8)); +} + +/* stop controller and re-config current chip*/ +static void bfin_spi_restore_state(struct bfin_spi_master *drv_data) +{ + struct bfin_spi_device *chip = drv_data->cur_chip; + + /* Clear status and disable clock */ + bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + bfin_write(&drv_data->regs->rx_control, 0x0); + bfin_write(&drv_data->regs->tx_control, 0x0); + bfin_spi_disable(drv_data); + + SSYNC(); + + /* Load the registers */ + bfin_write(&drv_data->regs->control, chip->control); + bfin_write(&drv_data->regs->clock, chip->clock); + + bfin_spi_enable(drv_data); + drv_data->tx_num = drv_data->rx_num = 0; + /* we always choose tx transfer initiate */ + bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN); + bfin_write(&drv_data->regs->tx_control, + SPI_TXCTL_TEN | SPI_TXCTL_TTI); + bfin_spi_cs_active(drv_data, chip); +} + +/* discard invalid rx data and empty rfifo */ +static inline void dummy_read(struct bfin_spi_master *drv_data) +{ + while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)) + bfin_read(&drv_data->regs->rfifo); +} + +static void bfin_spi_u8_write(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->tx < drv_data->tx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++))); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u8_read(struct bfin_spi_master *drv_data) +{ + u32 tx_val = drv_data->cur_chip->tx_dummy_val; + + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, tx_val); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u8_duplex(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++))); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo); + } +} + +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = { + .write = bfin_spi_u8_write, + .read = bfin_spi_u8_read, + .duplex = bfin_spi_u8_duplex, +}; + +static void bfin_spi_u16_write(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->tx < drv_data->tx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx)); + drv_data->tx += 2; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u16_read(struct bfin_spi_master *drv_data) +{ + u32 tx_val = drv_data->cur_chip->tx_dummy_val; + + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, tx_val); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 2; + } +} + +static void bfin_spi_u16_duplex(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx)); + drv_data->tx += 2; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 2; + } +} + +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = { + .write = bfin_spi_u16_write, + .read = bfin_spi_u16_read, + .duplex = bfin_spi_u16_duplex, +}; + +static void bfin_spi_u32_write(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->tx < drv_data->tx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx)); + drv_data->tx += 4; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u32_read(struct bfin_spi_master *drv_data) +{ + u32 tx_val = drv_data->cur_chip->tx_dummy_val; + + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, tx_val); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 4; + } +} + +static void bfin_spi_u32_duplex(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx)); + drv_data->tx += 4; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 4; + } +} + +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u32 = { + .write = bfin_spi_u32_write, + .read = bfin_spi_u32_read, + .duplex = bfin_spi_u32_duplex, +}; + + +/* test if there is more transfer to be done */ +static void bfin_spi_next_transfer(struct bfin_spi_master *drv) +{ + struct spi_message *msg = drv->cur_msg; + struct spi_transfer *t = drv->cur_transfer; + + /* Move to next transfer */ + if (t->transfer_list.next != &msg->transfers) { + drv->cur_transfer = list_entry(t->transfer_list.next, + struct spi_transfer, transfer_list); + drv->state = RUNNING_STATE; + } else { + drv->state = DONE_STATE; + drv->cur_transfer = NULL; + } +} + +static void bfin_spi_giveback(struct bfin_spi_master *drv_data) +{ + struct bfin_spi_device *chip = drv_data->cur_chip; + + bfin_spi_cs_deactive(drv_data, chip); + spi_finalize_current_message(drv_data->master); +} + +static int bfin_spi_setup_transfer(struct bfin_spi_master *drv) +{ + struct spi_transfer *t = drv->cur_transfer; + u32 cr, cr_width; + + if (t->tx_buf) { + drv->tx = (void *)t->tx_buf; + drv->tx_end = drv->tx + t->len; + } else { + drv->tx = NULL; + } + + if (t->rx_buf) { + drv->rx = t->rx_buf; + drv->rx_end = drv->rx + t->len; + } else { + drv->rx = NULL; + } + + drv->transfer_len = t->len; + + /* bits per word setup */ + switch (t->bits_per_word) { + case 8: + cr_width = SPI_CTL_SIZE08; + drv->ops = &bfin_bfin_spi_transfer_ops_u8; + break; + case 16: + cr_width = SPI_CTL_SIZE16; + drv->ops = &bfin_bfin_spi_transfer_ops_u16; + break; + case 32: + cr_width = SPI_CTL_SIZE32; + drv->ops = &bfin_bfin_spi_transfer_ops_u32; + break; + default: + return -EINVAL; + } + cr = bfin_read(&drv->regs->control) & ~SPI_CTL_SIZE; + cr |= cr_width; + bfin_write(&drv->regs->control, cr); + + /* speed setup */ + bfin_write(&drv->regs->clock, + hz_to_spi_clock(drv->sclk, t->speed_hz)); + return 0; +} + +static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data) +{ + struct spi_transfer *t = drv_data->cur_transfer; + struct spi_message *msg = drv_data->cur_msg; + struct bfin_spi_device *chip = drv_data->cur_chip; + u32 dma_config; + unsigned long word_count, word_size; + void *tx_buf, *rx_buf; + + switch (t->bits_per_word) { + case 8: + dma_config = WDSIZE_8 | PSIZE_8; + word_count = drv_data->transfer_len; + word_size = 1; + break; + case 16: + dma_config = WDSIZE_16 | PSIZE_16; + word_count = drv_data->transfer_len / 2; + word_size = 2; + break; + default: + dma_config = WDSIZE_32 | PSIZE_32; + word_count = drv_data->transfer_len / 4; + word_size = 4; + break; + } + + if (!drv_data->rx) { + tx_buf = drv_data->tx; + rx_buf = &drv_data->dummy_buffer; + drv_data->tx_dma_size = drv_data->transfer_len; + drv_data->rx_dma_size = sizeof(drv_data->dummy_buffer); + set_dma_x_modify(drv_data->tx_dma, word_size); + set_dma_x_modify(drv_data->rx_dma, 0); + } else if (!drv_data->tx) { + drv_data->dummy_buffer = chip->tx_dummy_val; + tx_buf = &drv_data->dummy_buffer; + rx_buf = drv_data->rx; + drv_data->tx_dma_size = sizeof(drv_data->dummy_buffer); + drv_data->rx_dma_size = drv_data->transfer_len; + set_dma_x_modify(drv_data->tx_dma, 0); + set_dma_x_modify(drv_data->rx_dma, word_size); + } else { + tx_buf = drv_data->tx; + rx_buf = drv_data->rx; + drv_data->tx_dma_size = drv_data->rx_dma_size + = drv_data->transfer_len; + set_dma_x_modify(drv_data->tx_dma, word_size); + set_dma_x_modify(drv_data->rx_dma, word_size); + } + + drv_data->tx_dma_addr = dma_map_single(&msg->spi->dev, + (void *)tx_buf, + drv_data->tx_dma_size, + DMA_TO_DEVICE); + if (dma_mapping_error(&msg->spi->dev, + drv_data->tx_dma_addr)) + return -ENOMEM; + + drv_data->rx_dma_addr = dma_map_single(&msg->spi->dev, + (void *)rx_buf, + drv_data->rx_dma_size, + DMA_FROM_DEVICE); + if (dma_mapping_error(&msg->spi->dev, + drv_data->rx_dma_addr)) { + dma_unmap_single(&msg->spi->dev, + drv_data->tx_dma_addr, + drv_data->tx_dma_size, + DMA_TO_DEVICE); + return -ENOMEM; + } + + dummy_read(drv_data); + set_dma_x_count(drv_data->tx_dma, word_count); + set_dma_x_count(drv_data->rx_dma, word_count); + set_dma_start_addr(drv_data->tx_dma, drv_data->tx_dma_addr); + set_dma_start_addr(drv_data->rx_dma, drv_data->rx_dma_addr); + dma_config |= DMAFLOW_STOP | RESTART | DI_EN; + set_dma_config(drv_data->tx_dma, dma_config); + set_dma_config(drv_data->rx_dma, dma_config | WNR); + enable_dma(drv_data->tx_dma); + enable_dma(drv_data->rx_dma); + SSYNC(); + + bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN | SPI_RXCTL_RDR_NE); + SSYNC(); + bfin_write(&drv_data->regs->tx_control, + SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF); + + return 0; +} + +static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + + if (!drv_data->rx) { + /* write only half duplex */ + drv_data->ops->write(drv_data); + if (drv_data->tx != drv_data->tx_end) + return -EIO; + } else if (!drv_data->tx) { + /* read only half duplex */ + drv_data->ops->read(drv_data); + if (drv_data->rx != drv_data->rx_end) + return -EIO; + } else { + /* full duplex mode */ + drv_data->ops->duplex(drv_data); + if (drv_data->tx != drv_data->tx_end) + return -EIO; + } + + if (!bfin_spi_flush(drv_data)) + return -EIO; + msg->actual_length += drv_data->transfer_len; + tasklet_schedule(&drv_data->pump_transfers); + return 0; +} + +static void bfin_spi_pump_transfers(unsigned long data) +{ + struct bfin_spi_master *drv_data = (struct bfin_spi_master *)data; + struct spi_message *msg = NULL; + struct spi_transfer *t = NULL; + struct bfin_spi_device *chip = NULL; + int ret; + + /* Get current state information */ + msg = drv_data->cur_msg; + t = drv_data->cur_transfer; + chip = drv_data->cur_chip; + + /* Handle for abort */ + if (drv_data->state == ERROR_STATE) { + msg->status = -EIO; + bfin_spi_giveback(drv_data); + return; + } + + if (drv_data->state == RUNNING_STATE) { + if (t->delay_usecs) + udelay(t->delay_usecs); + if (t->cs_change) + bfin_spi_cs_deactive(drv_data, chip); + bfin_spi_next_transfer(drv_data); + t = drv_data->cur_transfer; + } + /* Handle end of message */ + if (drv_data->state == DONE_STATE) { + msg->status = 0; + bfin_spi_giveback(drv_data); + return; + } + + if ((t->len == 0) || (t->tx_buf == NULL && t->rx_buf == NULL)) { + /* Schedule next transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + return; + } + + ret = bfin_spi_setup_transfer(drv_data); + if (ret) { + msg->status = ret; + bfin_spi_giveback(drv_data); + } + + bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + bfin_spi_cs_active(drv_data, chip); + drv_data->state = RUNNING_STATE; + + if (chip->enable_dma) + ret = bfin_spi_dma_xfer(drv_data); + else + ret = bfin_spi_pio_xfer(drv_data); + if (ret) { + msg->status = ret; + bfin_spi_giveback(drv_data); + } +} + +static int bfin_spi_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + + drv_data->cur_msg = m; + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + bfin_spi_restore_state(drv_data); + + drv_data->state = START_STATE; + drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + struct spi_transfer, transfer_list); + + tasklet_schedule(&drv_data->pump_transfers); + return 0; +} + +#define MAX_SPI_SSEL 7 + +static const u16 ssel[][MAX_SPI_SSEL] = { + {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3, + P_SPI0_SSEL4, P_SPI0_SSEL5, + P_SPI0_SSEL6, P_SPI0_SSEL7}, + + {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3, + P_SPI1_SSEL4, P_SPI1_SSEL5, + P_SPI1_SSEL6, P_SPI1_SSEL7}, + + {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3, + P_SPI2_SSEL4, P_SPI2_SSEL5, + P_SPI2_SSEL6, P_SPI2_SSEL7}, +}; + +static int bfin_spi_setup(struct spi_device *spi) +{ + struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master); + struct bfin_spi_device *chip = spi_get_ctldata(spi); + u32 bfin_ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE; + int ret = -EINVAL; + + if (!chip) { + struct bfin_spi3_chip *chip_info = spi->controller_data; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, "can not allocate chip data\n"); + return -ENOMEM; + } + if (chip_info) { + if (chip_info->control & ~bfin_ctl_reg) { + dev_err(&spi->dev, + "do not set bits that the SPI framework manages\n"); + goto error; + } + chip->control = chip_info->control; + chip->cs_chg_udelay = chip_info->cs_chg_udelay; + chip->tx_dummy_val = chip_info->tx_dummy_val; + chip->enable_dma = chip_info->enable_dma; + } + chip->cs = spi->chip_select; + if (chip->cs < MAX_CTRL_CS) { + chip->ssel = (1 << chip->cs) << 8; + ret = peripheral_request(ssel[spi->master->bus_num] + [chip->cs-1], dev_name(&spi->dev)); + if (ret) { + dev_err(&spi->dev, "peripheral_request() error\n"); + goto error; + } + } else { + chip->cs_gpio = chip->cs - MAX_CTRL_CS; + ret = gpio_request_one(chip->cs_gpio, GPIOF_OUT_INIT_HIGH, + dev_name(&spi->dev)); + if (ret) { + dev_err(&spi->dev, "gpio_request_one() error\n"); + goto error; + } + } + spi_set_ctldata(spi, chip); + } + + /* force a default base state */ + chip->control &= bfin_ctl_reg; + + if (spi->mode & SPI_CPOL) + chip->control |= SPI_CTL_CPOL; + if (spi->mode & SPI_CPHA) + chip->control |= SPI_CTL_CPHA; + if (spi->mode & SPI_LSB_FIRST) + chip->control |= SPI_CTL_LSBF; + chip->control |= SPI_CTL_MSTR; + /* we choose software to controll cs */ + chip->control &= ~SPI_CTL_ASSEL; + + chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz); + + bfin_spi_cs_enable(drv_data, chip); + bfin_spi_cs_deactive(drv_data, chip); + + return 0; +error: + if (chip) { + kfree(chip); + spi_set_ctldata(spi, NULL); + } + + return ret; +} + +static void bfin_spi_cleanup(struct spi_device *spi) +{ + struct bfin_spi_device *chip = spi_get_ctldata(spi); + struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master); + + if (!chip) + return; + + if (chip->cs < MAX_CTRL_CS) { + peripheral_free(ssel[spi->master->bus_num] + [chip->cs-1]); + bfin_spi_cs_disable(drv_data, chip); + } else { + gpio_free(chip->cs_gpio); + } + + kfree(chip); + spi_set_ctldata(spi, NULL); +} + +static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id) +{ + struct bfin_spi_master *drv_data = dev_id; + u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma); + + clear_dma_irqstat(drv_data->tx_dma); + if (dma_stat & DMA_DONE) { + drv_data->tx_num++; + } else { + dev_err(&drv_data->master->dev, + "spi tx dma error: %d\n", dma_stat); + if (drv_data->tx) + drv_data->state = ERROR_STATE; + } + bfin_write_and(&drv_data->regs->tx_control, ~SPI_TXCTL_TDR_NF); + return IRQ_HANDLED; +} + +static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id) +{ + struct bfin_spi_master *drv_data = dev_id; + struct spi_message *msg = drv_data->cur_msg; + u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma); + + clear_dma_irqstat(drv_data->rx_dma); + if (dma_stat & DMA_DONE) { + drv_data->rx_num++; + /* we may fail on tx dma */ + if (drv_data->state != ERROR_STATE) + msg->actual_length += drv_data->transfer_len; + } else { + drv_data->state = ERROR_STATE; + dev_err(&drv_data->master->dev, + "spi rx dma error: %d\n", dma_stat); + } + bfin_write(&drv_data->regs->tx_control, 0); + bfin_write(&drv_data->regs->rx_control, 0); + if (drv_data->rx_num != drv_data->tx_num) + dev_dbg(&drv_data->master->dev, + "dma interrupt missing: tx=%d,rx=%d\n", + drv_data->tx_num, drv_data->rx_num); + tasklet_schedule(&drv_data->pump_transfers); + return IRQ_HANDLED; +} + +static int bfin_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bfin_spi3_master *info = dev->platform_data; + struct spi_master *master; + struct bfin_spi_master *drv_data; + struct resource *mem, *res; + unsigned int tx_dma, rx_dma; + unsigned long sclk; + int ret; + + if (!info) { + dev_err(dev, "platform data missing!\n"); + return -ENODEV; + } + + sclk = get_sclk1(); + if (!sclk) { + dev_err(dev, "can not get sclk1\n"); + return -ENXIO; + } + + /* get register base and tx/rx dma */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "can not get register base\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(dev, "can not get tx dma resource\n"); + return -ENXIO; + } + tx_dma = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(dev, "can not get rx dma resource\n"); + return -ENXIO; + } + rx_dma = res->start; + + /* allocate master with space for drv_data */ + master = spi_alloc_master(dev, sizeof(*drv_data)); + if (!master) { + dev_err(dev, "can not alloc spi_master\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, master); + + /* the mode bits supported by this driver */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + + master->bus_num = pdev->id; + master->num_chipselect = info->num_chipselect; + master->cleanup = bfin_spi_cleanup; + master->setup = bfin_spi_setup; + master->transfer_one_message = bfin_spi_transfer_one_message; + master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + drv_data->tx_dma = tx_dma; + drv_data->rx_dma = rx_dma; + drv_data->pin_req = info->pin_req; + drv_data->sclk = sclk; + + drv_data->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(drv_data->regs)) { + ret = PTR_ERR(drv_data->regs); + goto err_put_master; + } + + /* request tx and rx dma */ + ret = request_dma(tx_dma, "SPI_TX_DMA"); + if (ret) { + dev_err(dev, "can not request SPI TX DMA channel\n"); + goto err_put_master; + } + set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data); + + ret = request_dma(rx_dma, "SPI_RX_DMA"); + if (ret) { + dev_err(dev, "can not request SPI RX DMA channel\n"); + goto err_free_tx_dma; + } + set_dma_callback(drv_data->rx_dma, bfin_spi_rx_dma_isr, drv_data); + + /* request CLK, MOSI and MISO */ + ret = peripheral_request_list(drv_data->pin_req, "bfin-spi3"); + if (ret < 0) { + dev_err(dev, "can not request spi pins\n"); + goto err_free_rx_dma; + } + + bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA); + bfin_write(&drv_data->regs->ssel, 0x0000FE00); + bfin_write(&drv_data->regs->delay, 0x0); + + tasklet_init(&drv_data->pump_transfers, + bfin_spi_pump_transfers, (unsigned long)drv_data); + /* register with the SPI framework */ + ret = spi_register_master(master); + if (ret) { + dev_err(dev, "can not register spi master\n"); + goto err_free_peripheral; + } + + return ret; + +err_free_peripheral: + peripheral_free_list(drv_data->pin_req); +err_free_rx_dma: + free_dma(rx_dma); +err_free_tx_dma: + free_dma(tx_dma); +err_put_master: + platform_set_drvdata(pdev, NULL); + spi_master_put(master); + + return ret; +} + +static int bfin_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + + bfin_spi_disable(drv_data); + + peripheral_free_list(drv_data->pin_req); + free_dma(drv_data->rx_dma); + free_dma(drv_data->tx_dma); + + platform_set_drvdata(pdev, NULL); + spi_unregister_master(drv_data->master); + return 0; +} + +#ifdef CONFIG_PM +static int bfin_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + + spi_master_suspend(master); + + drv_data->control = bfin_read(&drv_data->regs->control); + drv_data->ssel = bfin_read(&drv_data->regs->ssel); + + bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA); + bfin_write(&drv_data->regs->ssel, 0x0000FE00); + dma_disable_irq(drv_data->rx_dma); + dma_disable_irq(drv_data->tx_dma); + + return 0; +} + +static int bfin_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + int ret = 0; + + /* bootrom may modify spi and dma status when resume in spi boot mode */ + disable_dma(drv_data->rx_dma); + + dma_enable_irq(drv_data->rx_dma); + dma_enable_irq(drv_data->tx_dma); + bfin_write(&drv_data->regs->control, drv_data->control); + bfin_write(&drv_data->regs->ssel, drv_data->ssel); + + ret = spi_master_resume(master); + if (ret) { + free_dma(drv_data->rx_dma); + free_dma(drv_data->tx_dma); + } + + return ret; +} +#endif +static const struct dev_pm_ops bfin_spi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(bfin_spi_suspend, bfin_spi_resume) +}; + +MODULE_ALIAS("platform:bfin-spi3"); +static struct platform_driver bfin_spi_driver = { + .driver = { + .name = "bfin-spi3", + .owner = THIS_MODULE, + .pm = &bfin_spi_pm_ops, + }, + .remove = bfin_spi_remove, +}; + +module_platform_driver_probe(bfin_spi_driver, bfin_spi_probe); + +MODULE_DESCRIPTION("Analog Devices SPI3 controller driver"); +MODULE_AUTHOR("Scott Jiang "); +MODULE_LICENSE("GPL v2"); From 838af505843ca6277b47816e284001dbe7875386 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 19:37:51 +0100 Subject: [PATCH 0309/6183] spi/rspi: Add missing dependency on DMAE The filter function used by the rspi driver is part of the DMAE controller driver so if the DMA controller driver is somehow disabled then the rspi driver will fail to build. Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 89cbbabaff44..175491f2bb39 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -341,7 +341,7 @@ config SPI_PXA2XX_PCI config SPI_RSPI tristate "Renesas RSPI controller" - depends on SUPERH + depends on SUPERH && SH_DMAE_BASE help SPI driver for Renesas RSPI blocks. From a2fd4f9fa3b9f051550b36c4dfa74bc32bda24ee Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 14:57:26 +0100 Subject: [PATCH 0310/6183] spi: Support transfer speed checking in the core Allow drivers to avoid implementing their own checks for simple rates by specifying the limits in the master structure. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 7 +++++++ include/linux/spi/spi.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 978dda2c5239..a52f16685d6a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1387,6 +1387,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) BIT(xfer->bits_per_word - 1))) return -EINVAL; } + + if (xfer->speed_hz && master->min_speed_hz && + xfer->speed_hz < master->min_speed_hz) + return -EINVAL; + if (xfer->speed_hz && master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + return -EINVAL; } message->spi = spi; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 28e440be1c07..cdf668156154 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -233,6 +233,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * suported. If set, the SPI core will reject any transfer with an * unsupported bits_per_word. If not set, this value is simply ignored, * and it's up to the individual driver to perform any validation. + * @min_speed_hz: Lowest supported transfer speed + * @max_speed_hz: Highest supported transfer speed * @flags: other constraints relevant to this driver * @bus_lock_spinlock: spinlock for SPI bus locking * @bus_lock_mutex: mutex for SPI bus locking @@ -312,6 +314,10 @@ struct spi_master { #define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1)) #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1)) + /* limits on transfer speed */ + u32 min_speed_hz; + u32 max_speed_hz; + /* other constraints relevant to this driver */ u16 flags; #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ From 24a0013a04e81e95198daab98edf4df02e191568 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 15:05:40 +0100 Subject: [PATCH 0311/6183] spi: More sanity checks for transfers Check that transfers are non-empty and that there is a completion for them. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a52f16685d6a..c2899161ccac 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1351,6 +1351,11 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) struct spi_master *master = spi->master; struct spi_transfer *xfer; + if (list_empty(&message->transfers)) + return -EINVAL; + if (!message->complete) + return -EINVAL; + /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where * either MOSI or MISO is missing. They can also be caused by From c8b94d8492e6e3f938519517ae859f94820f9422 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 19:26:52 +0100 Subject: [PATCH 0312/6183] spi/clps711x: Remove unneeded devm_ deallocations The whole point of devm is that it'll do these automatically. Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 17965fe225cc..5655acf55bfe 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -239,11 +239,8 @@ static int spi_clps711x_probe(struct platform_device *pdev) } dev_err(&pdev->dev, "Failed to register master\n"); - devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw); clk_out: - devm_clk_put(&pdev->dev, hw->spi_clk); - err_out: while (--i >= 0) if (gpio_is_valid(hw->chipselect[i])) @@ -261,13 +258,10 @@ static int spi_clps711x_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct spi_clps711x_data *hw = spi_master_get_devdata(master); - devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw); - for (i = 0; i < master->num_chipselect; i++) if (gpio_is_valid(hw->chipselect[i])) gpio_free(hw->chipselect[i]); - devm_clk_put(&pdev->dev, hw->spi_clk); spi_unregister_master(master); kfree(master); From 4870c2170d91f33a1a90bd5b1d7c5534332f30f2 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 28 Jun 2013 11:43:34 -0700 Subject: [PATCH 0313/6183] spi: spi-ep93xx: always handle transfer specific settings __spi_async(), which starts every SPI message transfer, initializes the bits_per_word and max speed for every transfer in the message. Since the conditional test in ep93xx_spi_process_transfer() will always succeed just remove it and always call ep93xx_spi_chip_setup() to configure the hardware for each transfer in the message. Remove the redundant ep93xx_spi_chp_setup() in ep93xx_spi_process_transfer() which just initializes the hardware to the "default" based on the SPI device. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 45 ++++++++++------------------------------ 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index cad30b8a1d71..11e2b999cce2 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -708,39 +708,21 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, struct spi_transfer *t) { struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi); + int err; msg->state = t; - /* - * Handle any transfer specific settings if needed. We use - * temporary chip settings here and restore original later when - * the transfer is finished. - */ - if (t->speed_hz || t->bits_per_word) { - struct ep93xx_spi_chip tmp_chip = *chip; - - if (t->speed_hz) { - int err; - - err = ep93xx_spi_calc_divisors(espi, &tmp_chip, - t->speed_hz); - if (err) { - dev_err(&espi->pdev->dev, - "failed to adjust speed\n"); - msg->status = err; - return; - } - } - - if (t->bits_per_word) - tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word); - - /* - * Set up temporary new hw settings for this transfer. - */ - ep93xx_spi_chip_setup(espi, &tmp_chip); + err = ep93xx_spi_calc_divisors(espi, chip, t->speed_hz); + if (err) { + dev_err(&espi->pdev->dev, "failed to adjust speed\n"); + msg->status = err; + return; } + chip->dss = bits_per_word_to_dss(t->bits_per_word); + + ep93xx_spi_chip_setup(espi, chip); + espi->rx = 0; espi->tx = 0; @@ -783,9 +765,6 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, ep93xx_spi_cs_control(msg->spi, true); } } - - if (t->speed_hz || t->bits_per_word) - ep93xx_spi_chip_setup(espi, chip); } /* @@ -838,10 +817,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, espi->fifo_level = 0; /* - * Update SPI controller registers according to spi device and assert - * the chipselect. + * Assert the chipselect. */ - ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi)); ep93xx_spi_cs_control(msg->spi, true); list_for_each_entry(t, &msg->transfers, transfer_list) { From 8d7586bda032748ceec44416fa32a711a62e4954 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:06:26 -0700 Subject: [PATCH 0314/6183] spi: spi-ep93xx: use read,write instead of __raw_* variants The memory resource used by this driver is ioremap()'d and the normal read,write calls can be used instead of the __raw_* variants. Also, remove the inline tag on the helper functions and let the compiler decide if they are inlined. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 11e2b999cce2..d7eccfc40ac9 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -158,28 +158,26 @@ struct ep93xx_spi_chip { /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) -static inline void -ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value) +static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi, + u16 reg, u8 value) { - __raw_writeb(value, espi->regs_base + reg); + writeb(value, espi->regs_base + reg); } -static inline u8 -ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg) +static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg) { - return __raw_readb(spi->regs_base + reg); + return readb(spi->regs_base + reg); } -static inline void -ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value) +static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi, + u16 reg, u16 value) { - __raw_writew(value, espi->regs_base + reg); + writew(value, espi->regs_base + reg); } -static inline u16 -ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg) +static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg) { - return __raw_readw(spi->regs_base + reg); + return readw(spi->regs_base + reg); } static int ep93xx_spi_enable(const struct ep93xx_spi *espi) From 701c3587ee38ed53719187b0f1b059e113ac534f Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:07:01 -0700 Subject: [PATCH 0315/6183] spi: spi-ep93xx: remove bits_per_word() helper Check t->bits_per_word directly and remove the inline helper function. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index d7eccfc40ac9..d5e64201cdd3 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -429,17 +429,9 @@ static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, ep93xx_spi_write_u16(espi, SSPCR0, cr0); } -static inline int bits_per_word(const struct ep93xx_spi *espi) -{ - struct spi_message *msg = espi->current_msg; - struct spi_transfer *t = msg->state; - - return t->bits_per_word; -} - static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) { - if (bits_per_word(espi) > 8) { + if (t->bits_per_word > 8) { u16 tx_val = 0; if (t->tx_buf) @@ -458,7 +450,7 @@ static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) { - if (bits_per_word(espi) > 8) { + if (t->bits_per_word > 8) { u16 rx_val; rx_val = ep93xx_spi_read_u16(espi, SSPDR); @@ -544,7 +536,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) size_t len = t->len; int i, ret, nents; - if (bits_per_word(espi) > 8) + if (t->bits_per_word > 8) buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; else buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; From 48a7776e981fdf780728e45de4ae4f2b522c9c4d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:07:53 -0700 Subject: [PATCH 0316/6183] spi: spi-ep93xx: get platform resources early in (*probe) Get the platform resources early in the (*probe) to minimize the number of goto's in the error path. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index d5e64201cdd3..c2660c24c0ab 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -991,6 +991,18 @@ static int ep93xx_spi_probe(struct platform_device *pdev) info = pdev->dev.platform_data; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq resources\n"); + return -EBUSY; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "unable to get iomem resource\n"); + return -ENODEV; + } + master = spi_alloc_master(&pdev->dev, sizeof(*espi)); if (!master) { dev_err(&pdev->dev, "failed to allocate spi master\n"); @@ -1027,20 +1039,6 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi->min_rate = clk_get_rate(espi->clk) / (254 * 256); espi->pdev = pdev; - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - error = -EBUSY; - dev_err(&pdev->dev, "failed to get irq resources\n"); - goto fail_put_clock; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "unable to get iomem resource\n"); - error = -ENODEV; - goto fail_put_clock; - } - espi->sspdr_phys = res->start + SSPDR; espi->regs_base = devm_ioremap_resource(&pdev->dev, res); From b2d185edbac9c40adb1d390ad966e6900992e69d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:08:59 -0700 Subject: [PATCH 0317/6183] spi: spi-ep93xx: remove dev_err() for kzalloc() failure The kzalloc() failure will have already output a message. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index c2660c24c0ab..7a44163ace50 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -1004,10 +1004,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) } master = spi_alloc_master(&pdev->dev, sizeof(*espi)); - if (!master) { - dev_err(&pdev->dev, "failed to allocate spi master\n"); + if (!master) return -ENOMEM; - } master->setup = ep93xx_spi_setup; master->transfer = ep93xx_spi_transfer; From d9b65dfd44fdade5c0fde5f7b8a0f267e99f990d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:09:29 -0700 Subject: [PATCH 0318/6183] spi: spi-ep93xx: remove 'dss' from per chip private data This value is only needed to set the bits per word for each transfer of a message. There is no reason to set the value in ep93xx_spi_enable() because ep93xx_spi_process_transfer() sets it again for each transfer. Just pass the t->bits_per_word directly to ep93xx_spi_chip_setup() in ep93xx_spi_process_transfer() and remove 'dss' from the per chip private data. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 7a44163ace50..8d562526abe5 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -139,7 +139,6 @@ struct ep93xx_spi { * @rate: max rate in hz this chip supports * @div_cpsr: cpsr (pre-scaler) divider * @div_scr: scr divider - * @dss: bits per word (4 - 16 bits) * @ops: private chip operations * * This structure is used to store hardware register specific settings for each @@ -151,7 +150,6 @@ struct ep93xx_spi_chip { unsigned long rate; u8 div_cpsr; u8 div_scr; - u8 dss; struct ep93xx_spi_chip_ops *ops; }; @@ -329,8 +327,6 @@ static int ep93xx_spi_setup(struct spi_device *spi) chip->rate = spi->max_speed_hz; } - chip->dss = bits_per_word_to_dss(spi->bits_per_word); - ep93xx_spi_cs_control(spi, false); return 0; } @@ -407,22 +403,25 @@ static void ep93xx_spi_cleanup(struct spi_device *spi) * ep93xx_spi_chip_setup() - configures hardware according to given @chip * @espi: ep93xx SPI controller struct * @chip: chip specific settings + * @bits_per_word: transfer bits_per_word * * This function sets up the actual hardware registers with settings given in * @chip. Note that no validation is done so make sure that callers validate * settings before calling this. */ static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, - const struct ep93xx_spi_chip *chip) + const struct ep93xx_spi_chip *chip, + u8 bits_per_word) { + u8 dss = bits_per_word_to_dss(bits_per_word); u16 cr0; cr0 = chip->div_scr << SSPCR0_SCR_SHIFT; cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT; - cr0 |= chip->dss; + cr0 |= dss; dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", - chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss); + chip->spi->mode, chip->div_cpsr, chip->div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0); ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr); @@ -709,9 +708,7 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, return; } - chip->dss = bits_per_word_to_dss(t->bits_per_word); - - ep93xx_spi_chip_setup(espi, chip); + ep93xx_spi_chip_setup(espi, chip, t->bits_per_word); espi->rx = 0; espi->tx = 0; From e6eb8d9bb7b9c144ae63a5e97a686dd8a3377443 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:08:21 -0700 Subject: [PATCH 0319/6183] spi: spi-ep93xx: use devm_clk_get() Use devm_clk_get() so that the clk_put() happens automatically when the last reference to this driver is dropped. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 8d562526abe5..cc2a2405bd1d 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -1016,7 +1016,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi = spi_master_get_devdata(master); - espi->clk = clk_get(&pdev->dev, NULL); + espi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(espi->clk)) { dev_err(&pdev->dev, "unable to get spi clock\n"); error = PTR_ERR(espi->clk); @@ -1039,14 +1039,14 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi->regs_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(espi->regs_base)) { error = PTR_ERR(espi->regs_base); - goto fail_put_clock; + goto fail_release_master; } error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt, 0, "ep93xx-spi", espi); if (error) { dev_err(&pdev->dev, "failed to request irq\n"); - goto fail_put_clock; + goto fail_release_master; } if (info->use_dma && ep93xx_spi_setup_dma(espi)) @@ -1080,8 +1080,6 @@ fail_free_queue: destroy_workqueue(espi->wq); fail_free_dma: ep93xx_spi_release_dma(espi); -fail_put_clock: - clk_put(espi->clk); fail_release_master: spi_master_put(master); @@ -1117,7 +1115,6 @@ static int ep93xx_spi_remove(struct platform_device *pdev) spin_unlock_irq(&espi->lock); ep93xx_spi_release_dma(espi); - clk_put(espi->clk); spi_unregister_master(master); return 0; From 22c1b69ea833de84a9505135303ff443e62b3b15 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:10:00 -0700 Subject: [PATCH 0320/6183] spi: spi-ep93xx: don't bother calculating the divisors in ep93xx_spi_setup() The divisors needed to generate the SPI clock are calculated per transfer based on the t->speed_hz. There is no reason to calculate them in ep93xx_spi_setup(). Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index cc2a2405bd1d..6cdfc4036b75 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -136,7 +136,6 @@ struct ep93xx_spi { /** * struct ep93xx_spi_chip - SPI device hardware settings * @spi: back pointer to the SPI device - * @rate: max rate in hz this chip supports * @div_cpsr: cpsr (pre-scaler) divider * @div_scr: scr divider * @ops: private chip operations @@ -147,7 +146,6 @@ struct ep93xx_spi { */ struct ep93xx_spi_chip { const struct spi_device *spi; - unsigned long rate; u8 div_cpsr; u8 div_scr; struct ep93xx_spi_chip_ops *ops; @@ -315,18 +313,6 @@ static int ep93xx_spi_setup(struct spi_device *spi) spi_set_ctldata(spi, chip); } - if (spi->max_speed_hz != chip->rate) { - int err; - - err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz); - if (err != 0) { - spi_set_ctldata(spi, NULL); - kfree(chip); - return err; - } - chip->rate = spi->max_speed_hz; - } - ep93xx_spi_cs_control(spi, false); return 0; } From f7ef1da9e22ce390333645fc0ea70ff279eecd55 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 2 Jul 2013 10:10:29 -0700 Subject: [PATCH 0321/6183] spi: spi-ep93xx: move the clock divider calcs into ep93xx_spi_chip_setup() The divider values stored in the per chip data are only used to set the registers in the hardware to generate the desired SPI clock. Since these are calculated per transfer based on the t->speed_hz there is no reason keep them in the per chip data. Move the ep93xx_spi_calc_divisors() call into ep93xx_spi_chip_setup() and return the dividers thru pointers. Remove the divider values from the per chip data structure. Signed-off-by: H Hartley Sweeten Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 57 ++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 6cdfc4036b75..2e64806b40af 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -136,18 +136,10 @@ struct ep93xx_spi { /** * struct ep93xx_spi_chip - SPI device hardware settings * @spi: back pointer to the SPI device - * @div_cpsr: cpsr (pre-scaler) divider - * @div_scr: scr divider * @ops: private chip operations - * - * This structure is used to store hardware register specific settings for each - * SPI device. Settings are written to hardware by function - * ep93xx_spi_chip_setup(). */ struct ep93xx_spi_chip { const struct spi_device *spi; - u8 div_cpsr; - u8 div_scr; struct ep93xx_spi_chip_ops *ops; }; @@ -224,17 +216,13 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) /** * ep93xx_spi_calc_divisors() - calculates SPI clock divisors * @espi: ep93xx SPI controller struct - * @chip: divisors are calculated for this chip * @rate: desired SPI output clock rate - * - * Function calculates cpsr (clock pre-scaler) and scr divisors based on - * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If, - * for some reason, divisors cannot be calculated nothing is stored and - * %-EINVAL is returned. + * @div_cpsr: pointer to return the cpsr (pre-scaler) divider + * @div_scr: pointer to return the scr divider */ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, - struct ep93xx_spi_chip *chip, - unsigned long rate) + unsigned long rate, + u8 *div_cpsr, u8 *div_scr) { unsigned long spi_clk_rate = clk_get_rate(espi->clk); int cpsr, scr; @@ -257,8 +245,8 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, for (cpsr = 2; cpsr <= 254; cpsr += 2) { for (scr = 0; scr <= 255; scr++) { if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) { - chip->div_scr = (u8)scr; - chip->div_cpsr = (u8)cpsr; + *div_scr = (u8)scr; + *div_cpsr = (u8)cpsr; return 0; } } @@ -389,29 +377,35 @@ static void ep93xx_spi_cleanup(struct spi_device *spi) * ep93xx_spi_chip_setup() - configures hardware according to given @chip * @espi: ep93xx SPI controller struct * @chip: chip specific settings + * @speed_hz: transfer speed * @bits_per_word: transfer bits_per_word - * - * This function sets up the actual hardware registers with settings given in - * @chip. Note that no validation is done so make sure that callers validate - * settings before calling this. */ -static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, - const struct ep93xx_spi_chip *chip, - u8 bits_per_word) +static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, + const struct ep93xx_spi_chip *chip, + u32 speed_hz, u8 bits_per_word) { u8 dss = bits_per_word_to_dss(bits_per_word); + u8 div_cpsr = 0; + u8 div_scr = 0; u16 cr0; + int err; - cr0 = chip->div_scr << SSPCR0_SCR_SHIFT; + err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr); + if (err) + return err; + + cr0 = div_scr << SSPCR0_SCR_SHIFT; cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT; cr0 |= dss; dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", - chip->spi->mode, chip->div_cpsr, chip->div_scr, dss); + chip->spi->mode, div_cpsr, div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0); - ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr); + ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); ep93xx_spi_write_u16(espi, SSPCR0, cr0); + + return 0; } static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) @@ -687,15 +681,14 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, msg->state = t; - err = ep93xx_spi_calc_divisors(espi, chip, t->speed_hz); + err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word); if (err) { - dev_err(&espi->pdev->dev, "failed to adjust speed\n"); + dev_err(&espi->pdev->dev, + "failed to setup chip for transfer\n"); msg->status = err; return; } - ep93xx_spi_chip_setup(espi, chip, t->bits_per_word); - espi->rx = 0; espi->tx = 0; From 130b82c047675cf398ac49b7d230288f1b9ac9ad Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 11 Jul 2013 01:26:48 -0300 Subject: [PATCH 0322/6183] spi: spi-imx: Use devm functions Using devm functions can make the code smaller and cleaner. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 61 +++++++++++-------------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 7db4f43ee4d8..756cd466cfaf 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -796,10 +796,11 @@ static int spi_imx_probe(struct platform_device *pdev) if (!gpio_is_valid(cs_gpio)) continue; - ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); + ret = devm_gpio_request(&pdev->dev, spi_imx->chipselect[i], + DRIVER_NAME); if (ret) { dev_err(&pdev->dev, "can't get cs gpios\n"); - goto out_gpio_free; + goto out_master_put; } } @@ -816,46 +817,35 @@ static int spi_imx_probe(struct platform_device *pdev) (struct spi_imx_devtype_data *) pdev->id_entry->driver_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "can't get platform resource\n"); - ret = -ENOMEM; - goto out_gpio_free; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto out_gpio_free; - } - - spi_imx->base = ioremap(res->start, resource_size(res)); - if (!spi_imx->base) { - ret = -EINVAL; - goto out_release_mem; + spi_imx->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(spi_imx->base)) { + ret = PTR_ERR(spi_imx->base); + goto out_master_put; } spi_imx->irq = platform_get_irq(pdev, 0); if (spi_imx->irq < 0) { ret = -EINVAL; - goto out_iounmap; + goto out_master_put; } - ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx); + ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, + DRIVER_NAME, spi_imx); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); - goto out_iounmap; + goto out_master_put; } spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(spi_imx->clk_ipg)) { ret = PTR_ERR(spi_imx->clk_ipg); - goto out_free_irq; + goto out_master_put; } spi_imx->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(spi_imx->clk_per)) { ret = PTR_ERR(spi_imx->clk_per); - goto out_free_irq; + goto out_master_put; } clk_prepare_enable(spi_imx->clk_per); @@ -881,45 +871,24 @@ static int spi_imx_probe(struct platform_device *pdev) out_clk_put: clk_disable_unprepare(spi_imx->clk_per); clk_disable_unprepare(spi_imx->clk_ipg); -out_free_irq: - free_irq(spi_imx->irq, spi_imx); -out_iounmap: - iounmap(spi_imx->base); -out_release_mem: - release_mem_region(res->start, resource_size(res)); -out_gpio_free: - while (--i >= 0) { - if (gpio_is_valid(spi_imx->chipselect[i])) - gpio_free(spi_imx->chipselect[i]); - } +out_master_put: spi_master_put(master); - kfree(master); + return ret; } static int spi_imx_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - int i; spi_bitbang_stop(&spi_imx->bitbang); writel(0, spi_imx->base + MXC_CSPICTRL); clk_disable_unprepare(spi_imx->clk_per); clk_disable_unprepare(spi_imx->clk_ipg); - free_irq(spi_imx->irq, spi_imx); - iounmap(spi_imx->base); - - for (i = 0; i < master->num_chipselect; i++) - if (gpio_is_valid(spi_imx->chipselect[i])) - gpio_free(spi_imx->chipselect[i]); - spi_master_put(master); - release_mem_region(res->start, resource_size(res)); - return 0; } From 83174626ccf897827d2c49f26d9b0b7f74af85cc Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 11 Jul 2013 01:26:49 -0300 Subject: [PATCH 0323/6183] spi: spi-imx: Check the return value from clk_prepare_enable() clk_prepare_enable() may fail, so let's check its return value and propagate it in the case of error. While at it, fix the order of clk_disable_unprepare calls: clk_ipg should be disabled first, followed by clk_per. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 756cd466cfaf..81c7dd2228f9 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -848,8 +848,13 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_master_put; } - clk_prepare_enable(spi_imx->clk_per); - clk_prepare_enable(spi_imx->clk_ipg); + ret = clk_prepare_enable(spi_imx->clk_per); + if (ret) + goto out_master_put; + + ret = clk_prepare_enable(spi_imx->clk_ipg); + if (ret) + goto out_put_per; spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); @@ -869,8 +874,9 @@ static int spi_imx_probe(struct platform_device *pdev) return ret; out_clk_put: - clk_disable_unprepare(spi_imx->clk_per); clk_disable_unprepare(spi_imx->clk_ipg); +out_put_per: + clk_disable_unprepare(spi_imx->clk_per); out_master_put: spi_master_put(master); @@ -885,8 +891,8 @@ static int spi_imx_remove(struct platform_device *pdev) spi_bitbang_stop(&spi_imx->bitbang); writel(0, spi_imx->base + MXC_CSPICTRL); - clk_disable_unprepare(spi_imx->clk_per); clk_disable_unprepare(spi_imx->clk_ipg); + clk_disable_unprepare(spi_imx->clk_per); spi_master_put(master); return 0; From e11933f626c0a1333ec118d35a0c6c90d576b707 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 10 Jul 2013 00:16:27 -0300 Subject: [PATCH 0324/6183] spi: spi-mxs: Fix the error path sequence On mxs_spi_probe() the dma channels are requested prior to enabling the SSP clock, so in the error path we should disable the SSP clock first and release the DMA channels later. Same logic applies in mxs_spi_remove(). Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 424d38e59421..92254a1672e7 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -580,8 +580,8 @@ static int mxs_spi_probe(struct platform_device *pdev) return 0; out_free_dma: - dma_release_channel(ssp->dmach); clk_disable_unprepare(ssp->clk); + dma_release_channel(ssp->dmach); out_master_free: spi_master_put(master); return ret; @@ -598,11 +598,8 @@ static int mxs_spi_remove(struct platform_device *pdev) ssp = &spi->ssp; spi_unregister_master(master); - - dma_release_channel(ssp->dmach); - clk_disable_unprepare(ssp->clk); - + dma_release_channel(ssp->dmach); spi_master_put(master); return 0; From 9c4a39afaa2ef8f96b7bda1ffb5deef0e98ad189 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 10 Jul 2013 00:16:28 -0300 Subject: [PATCH 0325/6183] spi: spi-mxs: Check the return value from clk_prepare_enable() clk_prepare_enable() may fail, so let's check its return value and propagate it in the case of error. While at it, rename 'out_free_dma' to 'out_disable_clk' so that it can properly describe its purpose. Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 92254a1672e7..ecc59444875c 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -563,7 +563,10 @@ static int mxs_spi_probe(struct platform_device *pdev) goto out_master_free; } - clk_prepare_enable(ssp->clk); + ret = clk_prepare_enable(ssp->clk); + if (ret) + goto out_dma_release; + clk_set_rate(ssp->clk, clk_freq); ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; @@ -574,13 +577,14 @@ static int mxs_spi_probe(struct platform_device *pdev) ret = spi_register_master(master); if (ret) { dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret); - goto out_free_dma; + goto out_disable_clk; } return 0; -out_free_dma: +out_disable_clk: clk_disable_unprepare(ssp->clk); +out_dma_release: dma_release_channel(ssp->dmach); out_master_free: spi_master_put(master); From 8498bce934b864d609dab15a342bc47bb637c7f6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 10 Jul 2013 00:16:29 -0300 Subject: [PATCH 0326/6183] spi: spi-mxs: Check the return value from stmp_reset_block() stmp_reset_block() may fail, so let's check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index ecc59444875c..5b0a8e309197 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -570,7 +570,9 @@ static int mxs_spi_probe(struct platform_device *pdev) clk_set_rate(ssp->clk, clk_freq); ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; - stmp_reset_block(ssp->base); + ret = stmp_reset_block(ssp->base); + if (ret) + goto out_disable_clk; platform_set_drvdata(pdev, master); From 407d600f1fb99978bde36b79403f6177865697b6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 14:34:55 +0100 Subject: [PATCH 0327/6183] spi/omap-100k: Remove empty reset function Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index ee25670f8cfd..18bcaf3bcf17 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -472,11 +472,6 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) return 0; } -static int omap1_spi100k_reset(struct omap1_spi100k *spi100k) -{ - return 0; -} - static int omap1_spi100k_probe(struct platform_device *pdev) { struct spi_master *master; @@ -532,9 +527,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) goto err2; } - if (omap1_spi100k_reset(spi100k) < 0) - goto err3; - status = spi_register_master(master); if (status < 0) goto err3; From 69ea672a13a9b702ea3dc84de0cd9e1f4a088217 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 15:06:46 +0100 Subject: [PATCH 0328/6183] spi/omap-100k: Use core functionality to check validity of transfers Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 18bcaf3bcf17..3b42a4ba8fa2 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -424,7 +424,6 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) { struct omap1_spi100k *spi100k; unsigned long flags; - struct spi_transfer *t; m->actual_length = 0; m->status = -EINPROGRESS; @@ -435,35 +434,6 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) if (spi100k->state == SPI_SHUTDOWN) return -ESHUTDOWN; - /* reject invalid messages and transfers */ - if (list_empty(&m->transfers) || !m->complete) - return -EINVAL; - - list_for_each_entry(t, &m->transfers, transfer_list) { - const void *tx_buf = t->tx_buf; - void *rx_buf = t->rx_buf; - unsigned len = t->len; - - if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ - || (len && !(rx_buf || tx_buf))) { - dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", - t->speed_hz, - len, - tx_buf ? "tx" : "", - rx_buf ? "rx" : "", - t->bits_per_word); - return -EINVAL; - } - - if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) { - dev_dbg(&spi->dev, "%d Hz max exceeds %d\n", - t->speed_hz, - OMAP1_SPI100K_MAX_FREQ/(1<<16)); - return -EINVAL; - } - - } - spin_lock_irqsave(&spi100k->lock, flags); list_add_tail(&m->queue, &spi100k->msg_queue); queue_work(omap1_spi100k_wq, &spi100k->work); @@ -496,6 +466,8 @@ static int omap1_spi100k_probe(struct platform_device *pdev) master->num_chipselect = 2; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16); + master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ; platform_set_drvdata(pdev, master); From e8153ab3d7ab33aad872fd36f91a22a1071ceabf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 15:40:19 +0100 Subject: [PATCH 0329/6183] spi/omap-100k: Factor message transfer function out of work queue In preparation for removing the custom workqueue. Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 133 ++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 3b42a4ba8fa2..5999285f4cbd 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -321,10 +321,76 @@ static int omap1_spi100k_setup(struct spi_device *spi) return ret; } +static int omap1_spi100k_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct omap1_spi100k *spi100k = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t = NULL; + int cs_active = 0; + int par_override = 0; + int status = 0; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { + status = -EINVAL; + break; + } + if (par_override || t->speed_hz || t->bits_per_word) { + par_override = 1; + status = omap1_spi100k_setup_transfer(spi, t); + if (status < 0) + break; + if (!t->speed_hz && !t->bits_per_word) + par_override = 0; + } + + if (!cs_active) { + omap1_spi100k_force_cs(spi100k, 1); + cs_active = 1; + } + + if (t->len) { + unsigned count; + + count = omap1_spi100k_txrx_pio(spi, t); + m->actual_length += count; + + if (count != t->len) { + status = -EIO; + break; + } + } + + if (t->delay_usecs) + udelay(t->delay_usecs); + + /* ignore the "leave it on after last xfer" hint */ + + if (t->cs_change) { + omap1_spi100k_force_cs(spi100k, 0); + cs_active = 0; + } + } + + /* Restore defaults if they were overriden */ + if (par_override) { + par_override = 0; + status = omap1_spi100k_setup_transfer(spi, NULL); + } + + if (cs_active) + omap1_spi100k_force_cs(spi100k, 0); + + m->status = status; + m->complete(m->context); + + return status; +} + static void omap1_spi100k_work(struct work_struct *work) { struct omap1_spi100k *spi100k; - int status = 0; spi100k = container_of(work, struct omap1_spi100k, work); spin_lock_irq(&spi100k->lock); @@ -340,11 +406,6 @@ static void omap1_spi100k_work(struct work_struct *work) */ while (!list_empty(&spi100k->msg_queue)) { struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - int cs_active = 0; - struct omap1_spi100k_cs *cs; - int par_override = 0; m = container_of(spi100k->msg_queue.next, struct spi_message, queue); @@ -352,62 +413,7 @@ static void omap1_spi100k_work(struct work_struct *work) list_del_init(&m->queue); spin_unlock_irq(&spi100k->lock); - spi = m->spi; - cs = spi->controller_state; - - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - status = -EINVAL; - break; - } - if (par_override || t->speed_hz || t->bits_per_word) { - par_override = 1; - status = omap1_spi100k_setup_transfer(spi, t); - if (status < 0) - break; - if (!t->speed_hz && !t->bits_per_word) - par_override = 0; - } - - if (!cs_active) { - omap1_spi100k_force_cs(spi100k, 1); - cs_active = 1; - } - - if (t->len) { - unsigned count; - - count = omap1_spi100k_txrx_pio(spi, t); - m->actual_length += count; - - if (count != t->len) { - status = -EIO; - break; - } - } - - if (t->delay_usecs) - udelay(t->delay_usecs); - - /* ignore the "leave it on after last xfer" hint */ - - if (t->cs_change) { - omap1_spi100k_force_cs(spi100k, 0); - cs_active = 0; - } - } - - /* Restore defaults if they were overriden */ - if (par_override) { - par_override = 0; - status = omap1_spi100k_setup_transfer(spi, NULL); - } - - if (cs_active) - omap1_spi100k_force_cs(spi100k, 0); - - m->status = status; - m->complete(m->context); + omap1_spi100k_transfer_one_message(m->spi->master, m); spin_lock_irq(&spi100k->lock); } @@ -415,9 +421,6 @@ static void omap1_spi100k_work(struct work_struct *work) clk_disable(spi100k->ick); clk_disable(spi100k->fck); spin_unlock_irq(&spi100k->lock); - - if (status < 0) - printk(KERN_WARNING "spi transfer failed with %d\n", status); } static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) From da60b85506861b71db345f93bae72cbd8b51dcdd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 15:52:11 +0100 Subject: [PATCH 0330/6183] spi/omap-100k: Convert to use core message queue implementation Saves some code duplication and gets us the benefits of any improvements in the core code. Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 103 ++++++------------------------------ 1 file changed, 17 insertions(+), 86 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 5999285f4cbd..d4fcca9dc8e5 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -83,11 +83,6 @@ #define SPI_SHUTDOWN 1 struct omap1_spi100k { - struct work_struct work; - - /* lock protects queue and registers */ - spinlock_t lock; - struct list_head msg_queue; struct spi_master *master; struct clk *ick; struct clk *fck; @@ -104,8 +99,6 @@ struct omap1_spi100k_cs { int word_len; }; -static struct workqueue_struct *omap1_spi100k_wq; - #define MOD_REG_BIT(val, mask, set) do { \ if (set) \ val |= mask; \ @@ -321,6 +314,16 @@ static int omap1_spi100k_setup(struct spi_device *spi) return ret; } +static int omap1_spi100k_prepare_hardware(struct spi_master *master) +{ + struct omap1_spi100k *spi100k = spi_master_get_devdata(master); + + clk_enable(spi100k->ick); + clk_enable(spi100k->fck); + + return 0; +} + static int omap1_spi100k_transfer_one_message(struct spi_master *master, struct spi_message *m) { @@ -383,64 +386,18 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master, omap1_spi100k_force_cs(spi100k, 0); m->status = status; - m->complete(m->context); + + spi_finalize_current_message(master); return status; } -static void omap1_spi100k_work(struct work_struct *work) +static int omap1_spi100k_unprepare_hardware(struct spi_master *master) { - struct omap1_spi100k *spi100k; - - spi100k = container_of(work, struct omap1_spi100k, work); - spin_lock_irq(&spi100k->lock); - - clk_enable(spi100k->ick); - clk_enable(spi100k->fck); - - /* We only enable one channel at a time -- the one whose message is - * at the head of the queue -- although this controller would gladly - * arbitrate among multiple channels. This corresponds to "single - * channel" master mode. As a side effect, we need to manage the - * chipselect with the FORCE bit ... CS != channel enable. - */ - while (!list_empty(&spi100k->msg_queue)) { - struct spi_message *m; - - m = container_of(spi100k->msg_queue.next, struct spi_message, - queue); - - list_del_init(&m->queue); - spin_unlock_irq(&spi100k->lock); - - omap1_spi100k_transfer_one_message(m->spi->master, m); - - spin_lock_irq(&spi100k->lock); - } + struct omap1_spi100k *spi100k = spi_master_get_devdata(master); clk_disable(spi100k->ick); clk_disable(spi100k->fck); - spin_unlock_irq(&spi100k->lock); -} - -static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct omap1_spi100k *spi100k; - unsigned long flags; - - m->actual_length = 0; - m->status = -EINPROGRESS; - - spi100k = spi_master_get_devdata(spi->master); - - /* Don't accept new work if we're shutting down */ - if (spi100k->state == SPI_SHUTDOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&spi100k->lock, flags); - list_add_tail(&m->queue, &spi100k->msg_queue); - queue_work(omap1_spi100k_wq, &spi100k->work); - spin_unlock_irqrestore(&spi100k->lock, flags); return 0; } @@ -464,7 +421,9 @@ static int omap1_spi100k_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->setup = omap1_spi100k_setup; - master->transfer = omap1_spi100k_transfer; + master->transfer_one_message = omap1_spi100k_transfer_one_message; + master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware; + master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware; master->cleanup = NULL; master->num_chipselect = 2; master->mode_bits = MODEBITS; @@ -484,10 +443,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) */ spi100k->base = (void __iomem *) pdev->dev.platform_data; - INIT_WORK(&spi100k->work, omap1_spi100k_work); - - spin_lock_init(&spi100k->lock); - INIT_LIST_HEAD(&spi100k->msg_queue); spi100k->ick = clk_get(&pdev->dev, "ick"); if (IS_ERR(spi100k->ick)) { dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); @@ -524,27 +479,11 @@ static int omap1_spi100k_remove(struct platform_device *pdev) struct spi_master *master; struct omap1_spi100k *spi100k; struct resource *r; - unsigned limit = 500; - unsigned long flags; int status = 0; master = platform_get_drvdata(pdev); spi100k = spi_master_get_devdata(master); - spin_lock_irqsave(&spi100k->lock, flags); - - spi100k->state = SPI_SHUTDOWN; - while (!list_empty(&spi100k->msg_queue) && limit--) { - spin_unlock_irqrestore(&spi100k->lock, flags); - msleep(10); - spin_lock_irqsave(&spi100k->lock, flags); - } - - if (!list_empty(&spi100k->msg_queue)) - status = -EBUSY; - - spin_unlock_irqrestore(&spi100k->lock, flags); - if (status != 0) return status; @@ -569,20 +508,12 @@ static struct platform_driver omap1_spi100k_driver = { static int __init omap1_spi100k_init(void) { - omap1_spi100k_wq = create_singlethread_workqueue( - omap1_spi100k_driver.driver.name); - - if (omap1_spi100k_wq == NULL) - return -1; - return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe); } static void __exit omap1_spi100k_exit(void) { platform_driver_unregister(&omap1_spi100k_driver); - - destroy_workqueue(omap1_spi100k_wq); } module_init(omap1_spi100k_init); From 022a9412ec056026739c15df90e947b67d1b8222 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:07:51 +0100 Subject: [PATCH 0331/6183] spi/omap-100k: Convert to devm_clk_get() Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index d4fcca9dc8e5..691ef3f199ff 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -443,33 +443,29 @@ static int omap1_spi100k_probe(struct platform_device *pdev) */ spi100k->base = (void __iomem *) pdev->dev.platform_data; - spi100k->ick = clk_get(&pdev->dev, "ick"); + spi100k->ick = devm_clk_get(&pdev->dev, "ick"); if (IS_ERR(spi100k->ick)) { dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); status = PTR_ERR(spi100k->ick); - goto err1; + goto err; } - spi100k->fck = clk_get(&pdev->dev, "fck"); + spi100k->fck = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(spi100k->fck)) { dev_dbg(&pdev->dev, "can't get spi100k_fck\n"); status = PTR_ERR(spi100k->fck); - goto err2; + goto err; } status = spi_register_master(master); if (status < 0) - goto err3; + goto err; spi100k->state = SPI_RUNNING; return status; -err3: - clk_put(spi100k->fck); -err2: - clk_put(spi100k->ick); -err1: +err: spi_master_put(master); return status; } @@ -487,9 +483,6 @@ static int omap1_spi100k_remove(struct platform_device *pdev) if (status != 0) return status; - clk_put(spi100k->fck); - clk_put(spi100k->ick); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi_unregister_master(master); From 13cd19e855437254fe38b8522584f3a0738b0884 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:09:22 +0100 Subject: [PATCH 0332/6183] spi/omap-100k: Prepare and unprepare clocks Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 691ef3f199ff..3590dd43837b 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -303,13 +303,13 @@ static int omap1_spi100k_setup(struct spi_device *spi) spi100k_open(spi->master); - clk_enable(spi100k->ick); - clk_enable(spi100k->fck); + clk_prepare_enable(spi100k->ick); + clk_prepare_enable(spi100k->fck); ret = omap1_spi100k_setup_transfer(spi, NULL); - clk_disable(spi100k->ick); - clk_disable(spi100k->fck); + clk_disable_unprepare(spi100k->ick); + clk_disable_unprepare(spi100k->fck); return ret; } @@ -318,8 +318,8 @@ static int omap1_spi100k_prepare_hardware(struct spi_master *master) { struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - clk_enable(spi100k->ick); - clk_enable(spi100k->fck); + clk_prepare_enable(spi100k->ick); + clk_prepare_enable(spi100k->fck); return 0; } @@ -396,8 +396,8 @@ static int omap1_spi100k_unprepare_hardware(struct spi_master *master) { struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - clk_disable(spi100k->ick); - clk_disable(spi100k->fck); + clk_disable_unprepare(spi100k->ick); + clk_disable_unprepare(spi100k->fck); return 0; } From 2d0c6148e381b81f8e6783d24b724963a86364cc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 16:10:33 +0100 Subject: [PATCH 0333/6183] spi/omap-100k: Convert to module_platform_driver() Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 3590dd43837b..cdcc72c5d380 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -495,22 +495,11 @@ static struct platform_driver omap1_spi100k_driver = { .name = "omap1_spi100k", .owner = THIS_MODULE, }, + .probe = omap1_spi100k_probe, .remove = omap1_spi100k_remove, }; - -static int __init omap1_spi100k_init(void) -{ - return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe); -} - -static void __exit omap1_spi100k_exit(void) -{ - platform_driver_unregister(&omap1_spi100k_driver); -} - -module_init(omap1_spi100k_init); -module_exit(omap1_spi100k_exit); +module_platform_driver(omap1_spi100k_driver); MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver"); MODULE_AUTHOR("Fabrice Crohas "); From 1de7061253a2742c743f3883f0e73480c9bceee0 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 3 Jul 2013 13:25:06 +0300 Subject: [PATCH 0334/6183] spi/pxa2xx: enable DMA on newer Intel LPSS silicon There is an additional bit in the Intel LPSS SPI private registers that needs to be set in order to be able to use DMA with the SPI controller. Enable this as well. Signed-off-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f440dcee852b..e0fd6f63c93e 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -69,6 +69,8 @@ MODULE_ALIAS("platform:pxa2xx-spi"); #define LPSS_TX_HITHRESH_DFLT 224 /* Offset from drv_data->lpss_base */ +#define GENERAL_REG 0x08 +#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define SSP_REG 0x0c #define SPI_CS_CONTROL 0x18 #define SPI_CS_CONTROL_SW_MODE BIT(0) @@ -142,8 +144,13 @@ detection_done: __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); /* Enable multiblock DMA transfers */ - if (drv_data->master_info->enable_dma) + if (drv_data->master_info->enable_dma) { __lpss_ssp_write_priv(drv_data, SSP_REG, 1); + + value = __lpss_ssp_read_priv(drv_data, GENERAL_REG); + value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE; + __lpss_ssp_write_priv(drv_data, GENERAL_REG, value); + } } static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) From 9f4b323803ff18d87dcc042723b527ee646dddfc Mon Sep 17 00:00:00 2001 From: Girish K S Date: Thu, 27 Jun 2013 12:26:53 +0530 Subject: [PATCH 0335/6183] spi: s3c64xx: add missing check for polling mode Due to changes in mainline prior to submission the spi device detection in polling mode breaks. This revealed the missing check for polling during dma prepare. This patch adds the missing check. Signed-off-by: Girish K S Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index eb53df27e7ea..63e2070c6c14 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -434,6 +434,9 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) dma_cap_mask_t mask; int ret; + if (is_polling(sdd)) + return 0; + dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); From 94b1f0dfa6dd8a3ed303cc7b0034b17e9cc34824 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Tue, 25 Jun 2013 19:45:29 +0800 Subject: [PATCH 0336/6183] spi: sirf: add missed spi mode_bits that SiRFSoC hardware supports Missing this will cause some user cases fail when they want to change spi transfer mode. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index fc20bcfd90c3..96087169296e 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -538,6 +538,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer; sspi->bitbang.master->setup = spi_sirfsoc_setup; master->bus_num = pdev->id; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) | SPI_BPW_MASK(16) | SPI_BPW_MASK(32); sspi->bitbang.master->dev.of_node = pdev->dev.of_node; From 86562d04fc8212e2453d9714064a741a7d400da0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Jul 2013 08:37:44 +0800 Subject: [PATCH 0337/6183] spi: tegra114: remove redundant dev_err call in tegra_spi_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e8f542ab8935..8c99c00515c4 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1068,7 +1068,6 @@ static int tegra_spi_probe(struct platform_device *pdev) tspi->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(tspi->base)) { ret = PTR_ERR(tspi->base); - dev_err(&pdev->dev, "ioremap failed: err = %d\n", ret); goto exit_free_master; } From cd4c424463b6051b0d3cac49a96389788c39bb35 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Jul 2013 17:34:43 +0300 Subject: [PATCH 0338/6183] spi: tle62x0: dump small buffers using %*ph We have nice specifier in kernel for that. It changes separator from ',' (comma) to space, though it's not a big deal since it's just a debug message. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-tle62x0.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 6b0874d782ed..3e528c0396e7 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -52,8 +52,7 @@ static inline int tle62x0_write(struct tle62x0_state *st) buff[1] = gpio_state; } - dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n", - buff[0], buff[1], buff[2]); + dev_dbg(&st->us->dev, "buff %3ph\n", buff); return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2); } From c40537d008ab1b4fe2f12641cca1462de10a95f7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Jul 2013 20:33:01 +0100 Subject: [PATCH 0339/6183] spi/xilinx: Convert to devm_ioremap_resource() Saves code and reduces the possibility of error. Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index fb56fcfdf65e..ad48710b2859 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -362,14 +362,10 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; init_completion(&xspi->done); - if (!request_mem_region(mem->start, resource_size(mem), - XILINX_SPI_NAME)) + xspi->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); goto put_master; - - xspi->regs = ioremap(mem->start, resource_size(mem)); - if (xspi->regs == NULL) { - dev_warn(dev, "ioremap failure\n"); - goto map_failed; } master->bus_num = bus_num; @@ -408,7 +404,7 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, xspi->tx_fn = xspi_tx32; xspi->rx_fn = xspi_rx32; } else - goto unmap_io; + goto put_master; /* SPI controller initializations */ @@ -417,7 +413,7 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, /* Register for SPI Interrupt */ ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi); if (ret) - goto unmap_io; + goto put_master; ret = spi_bitbang_start(&xspi->bitbang); if (ret) { @@ -431,10 +427,6 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, free_irq: free_irq(xspi->irq, xspi); -unmap_io: - iounmap(xspi->regs); -map_failed: - release_mem_region(mem->start, resource_size(mem)); put_master: spi_master_put(master); return NULL; @@ -449,9 +441,7 @@ void xilinx_spi_deinit(struct spi_master *master) spi_bitbang_stop(&xspi->bitbang); free_irq(xspi->irq, xspi); - iounmap(xspi->regs); - release_mem_region(xspi->mem.start, resource_size(&xspi->mem)); spi_master_put(xspi->bitbang.master); } EXPORT_SYMBOL(xilinx_spi_deinit); From d81c0bbbf84086568b559bee59e4a93aba4a6e0f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Jul 2013 12:05:42 +0100 Subject: [PATCH 0340/6183] spi/xilinx: Remove remains of of_platform device registration In the past there used to be a separate platform device type for device tree systems so the probe and removal functions were split into generic and bus sections. Since this is no longer the case simplify the code (and remove some unprototyped exports) by factoring everything into the bus probe() and remove(). Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 147 +++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 83 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index ad48710b2859..038e59a8bf0a 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -340,17 +340,51 @@ static const struct of_device_id xilinx_spi_of_match[] = { }; MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); -struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, - u32 irq, s16 bus_num, int num_cs, int bits_per_word) +static int xilinx_spi_probe(struct platform_device *dev) { - struct spi_master *master; struct xilinx_spi *xspi; - int ret; + struct xspi_platform_data *pdata; + struct resource *r; + int ret, irq, num_cs = 0, bits_per_word = 8; + struct spi_master *master; u32 tmp; + u8 i; - master = spi_alloc_master(dev, sizeof(struct xilinx_spi)); + pdata = dev->dev.platform_data; + if (pdata) { + num_cs = pdata->num_chipselect; + bits_per_word = pdata->bits_per_word; + } + +#ifdef CONFIG_OF + if (dev->dev.of_node) { + const __be32 *prop; + int len; + + /* number of slave select bits is required */ + prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits", + &len); + if (prop && len >= sizeof(*prop)) + num_cs = __be32_to_cpup(prop); + } +#endif + + if (!num_cs) { + dev_err(&dev->dev, "Missing slave select configuration data\n"); + return -EINVAL; + } + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!r) + return -ENODEV; + + irq = platform_get_irq(dev, 0); + if (irq < 0) + return -ENXIO; + + master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi)); if (!master) - return NULL; + return -ENODEV; /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA; @@ -362,17 +396,17 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; init_completion(&xspi->done); - xspi->regs = devm_ioremap_resource(dev, mem); + xspi->regs = devm_ioremap_resource(&dev->dev, r); if (IS_ERR(xspi->regs)) { ret = PTR_ERR(xspi->regs); goto put_master; } - master->bus_num = bus_num; + master->bus_num = dev->dev.id; master->num_chipselect = num_cs; - master->dev.of_node = dev->of_node; + master->dev.of_node = dev->dev.of_node; - xspi->mem = *mem; + xspi->mem = *r; xspi->irq = irq; /* @@ -403,8 +437,10 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, } else if (xspi->bits_per_word == 32) { xspi->tx_fn = xspi_tx32; xspi->rx_fn = xspi_rx32; - } else + } else { + ret = -EINVAL; goto put_master; + } /* SPI controller initializations */ @@ -417,80 +453,12 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, ret = spi_bitbang_start(&xspi->bitbang); if (ret) { - dev_err(dev, "spi_bitbang_start FAILED\n"); + dev_err(&dev->dev, "spi_bitbang_start FAILED\n"); goto free_irq; } - dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", - (unsigned long long)mem->start, xspi->regs, xspi->irq); - return master; - -free_irq: - free_irq(xspi->irq, xspi); -put_master: - spi_master_put(master); - return NULL; -} -EXPORT_SYMBOL(xilinx_spi_init); - -void xilinx_spi_deinit(struct spi_master *master) -{ - struct xilinx_spi *xspi; - - xspi = spi_master_get_devdata(master); - - spi_bitbang_stop(&xspi->bitbang); - free_irq(xspi->irq, xspi); - - spi_master_put(xspi->bitbang.master); -} -EXPORT_SYMBOL(xilinx_spi_deinit); - -static int xilinx_spi_probe(struct platform_device *dev) -{ - struct xspi_platform_data *pdata; - struct resource *r; - int irq, num_cs = 0, bits_per_word = 8; - struct spi_master *master; - u8 i; - - pdata = dev->dev.platform_data; - if (pdata) { - num_cs = pdata->num_chipselect; - bits_per_word = pdata->bits_per_word; - } - -#ifdef CONFIG_OF - if (dev->dev.of_node) { - const __be32 *prop; - int len; - - /* number of slave select bits is required */ - prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits", - &len); - if (prop && len >= sizeof(*prop)) - num_cs = __be32_to_cpup(prop); - } -#endif - - if (!num_cs) { - dev_err(&dev->dev, "Missing slave select configuration data\n"); - return -EINVAL; - } - - - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!r) - return -ENODEV; - - irq = platform_get_irq(dev, 0); - if (irq < 0) - return -ENXIO; - - master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs, - bits_per_word); - if (!master) - return -ENODEV; + dev_info(&dev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", + (unsigned long long)r->start, xspi->regs, xspi->irq); if (pdata) { for (i = 0; i < pdata->num_devices; i++) @@ -499,11 +467,24 @@ static int xilinx_spi_probe(struct platform_device *dev) platform_set_drvdata(dev, master); return 0; + +free_irq: + free_irq(xspi->irq, xspi); +put_master: + spi_master_put(master); + + return ret; } static int xilinx_spi_remove(struct platform_device *dev) { - xilinx_spi_deinit(platform_get_drvdata(dev)); + struct spi_master *master = platform_get_drvdata(dev); + struct xilinx_spi *xspi = spi_master_get_devdata(master); + + spi_bitbang_stop(&xspi->bitbang); + free_irq(xspi->irq, xspi); + + spi_master_put(xspi->bitbang.master); return 0; } From 7cb2abd05fe1f9aea70b8ee38004b60bc882ffb5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 5 Jul 2013 11:24:26 +0100 Subject: [PATCH 0341/6183] spi/xilinx: Refer to platform device as pdev in probe() and remove() This is a more traditional name and makes things a bit clearer when referring to actual struct devices as we do frequently during probe(). Signed-off-by: Mark Brown Acked-by: Michal Simek --- drivers/spi/spi-xilinx.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 038e59a8bf0a..3026efa5a59f 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -340,7 +340,7 @@ static const struct of_device_id xilinx_spi_of_match[] = { }; MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); -static int xilinx_spi_probe(struct platform_device *dev) +static int xilinx_spi_probe(struct platform_device *pdev) { struct xilinx_spi *xspi; struct xspi_platform_data *pdata; @@ -350,19 +350,19 @@ static int xilinx_spi_probe(struct platform_device *dev) u32 tmp; u8 i; - pdata = dev->dev.platform_data; + pdata = pdev->dev.platform_data; if (pdata) { num_cs = pdata->num_chipselect; bits_per_word = pdata->bits_per_word; } #ifdef CONFIG_OF - if (dev->dev.of_node) { + if (pdev->dev.of_node) { const __be32 *prop; int len; /* number of slave select bits is required */ - prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits", + prop = of_get_property(pdev->dev.of_node, "xlnx,num-ss-bits", &len); if (prop && len >= sizeof(*prop)) num_cs = __be32_to_cpup(prop); @@ -370,19 +370,20 @@ static int xilinx_spi_probe(struct platform_device *dev) #endif if (!num_cs) { - dev_err(&dev->dev, "Missing slave select configuration data\n"); + dev_err(&pdev->dev, + "Missing slave select configuration data\n"); return -EINVAL; } - r = platform_get_resource(dev, IORESOURCE_MEM, 0); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) return -ENODEV; - irq = platform_get_irq(dev, 0); + irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENXIO; - master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi)); + master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); if (!master) return -ENODEV; @@ -396,15 +397,15 @@ static int xilinx_spi_probe(struct platform_device *dev) xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; init_completion(&xspi->done); - xspi->regs = devm_ioremap_resource(&dev->dev, r); + xspi->regs = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(xspi->regs)) { ret = PTR_ERR(xspi->regs); goto put_master; } - master->bus_num = dev->dev.id; + master->bus_num = pdev->dev.id; master->num_chipselect = num_cs; - master->dev.of_node = dev->dev.of_node; + master->dev.of_node = pdev->dev.of_node; xspi->mem = *r; xspi->irq = irq; @@ -453,11 +454,11 @@ static int xilinx_spi_probe(struct platform_device *dev) ret = spi_bitbang_start(&xspi->bitbang); if (ret) { - dev_err(&dev->dev, "spi_bitbang_start FAILED\n"); + dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); goto free_irq; } - dev_info(&dev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", + dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", (unsigned long long)r->start, xspi->regs, xspi->irq); if (pdata) { @@ -465,7 +466,7 @@ static int xilinx_spi_probe(struct platform_device *dev) spi_new_device(master, pdata->devices + i); } - platform_set_drvdata(dev, master); + platform_set_drvdata(pdev, master); return 0; free_irq: @@ -476,9 +477,9 @@ put_master: return ret; } -static int xilinx_spi_remove(struct platform_device *dev) +static int xilinx_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(dev); + struct spi_master *master = platform_get_drvdata(pdev); struct xilinx_spi *xspi = spi_master_get_devdata(master); spi_bitbang_stop(&xspi->bitbang); From 5586c09e19b0dea5c1b4fd9838ca73575def223f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 Jul 2013 15:29:14 +0200 Subject: [PATCH 0342/6183] spi/xilinx: Remove CONFIG_OF from the driver dev.of_node is in struct device all the time. Signed-off-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 3026efa5a59f..2e1d8a4ac375 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -356,7 +356,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) bits_per_word = pdata->bits_per_word; } -#ifdef CONFIG_OF if (pdev->dev.of_node) { const __be32 *prop; int len; @@ -367,7 +366,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) if (prop && len >= sizeof(*prop)) num_cs = __be32_to_cpup(prop); } -#endif if (!num_cs) { dev_err(&pdev->dev, From ad3fdbcaf98dc1258f7ee1503703e7fcbc0d8d8e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 Jul 2013 15:29:15 +0200 Subject: [PATCH 0343/6183] spi/xilinx: Clean ioremap calling devm_ioremap_resource() automatically checks that struct resource is initialized. Also group platform_get_resource() and devm_ioremap_resource() together. And remove mem resource from struct xilinx_spi. Signed-off-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 2e1d8a4ac375..a9b99a997f91 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -80,7 +80,6 @@ struct xilinx_spi { /* bitbang has to be first */ struct spi_bitbang bitbang; struct completion done; - struct resource mem; /* phys mem */ void __iomem *regs; /* virt. address of the control registers */ u32 irq; @@ -344,7 +343,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) { struct xilinx_spi *xspi; struct xspi_platform_data *pdata; - struct resource *r; + struct resource *res; int ret, irq, num_cs = 0, bits_per_word = 8; struct spi_master *master; u32 tmp; @@ -373,10 +372,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -EINVAL; } - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENODEV; - irq = platform_get_irq(pdev, 0); if (irq < 0) return -ENXIO; @@ -395,7 +390,8 @@ static int xilinx_spi_probe(struct platform_device *pdev) xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; init_completion(&xspi->done); - xspi->regs = devm_ioremap_resource(&pdev->dev, r); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xspi->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(xspi->regs)) { ret = PTR_ERR(xspi->regs); goto put_master; @@ -405,7 +401,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) master->num_chipselect = num_cs; master->dev.of_node = pdev->dev.of_node; - xspi->mem = *r; xspi->irq = irq; /* @@ -457,7 +452,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", - (unsigned long long)r->start, xspi->regs, xspi->irq); + (unsigned long long)res->start, xspi->regs, xspi->irq); if (pdata) { for (i = 0; i < pdata->num_devices; i++) From be3acdff943f46c32e9b2f453f0033bbae01a804 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 Jul 2013 15:29:17 +0200 Subject: [PATCH 0344/6183] spi/xilinx: Use of_property_read_u32 for reading value from node It simplifies driver probing. Signed-off-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index a9b99a997f91..0b23408d357c 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -353,17 +353,9 @@ static int xilinx_spi_probe(struct platform_device *pdev) if (pdata) { num_cs = pdata->num_chipselect; bits_per_word = pdata->bits_per_word; - } - - if (pdev->dev.of_node) { - const __be32 *prop; - int len; - - /* number of slave select bits is required */ - prop = of_get_property(pdev->dev.of_node, "xlnx,num-ss-bits", - &len); - if (prop && len >= sizeof(*prop)) - num_cs = __be32_to_cpup(prop); + } else { + of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits", + &num_cs); } if (!num_cs) { From 7b3b7432ae7848a269671921393148ff1aae3881 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 9 Jul 2013 18:05:16 +0200 Subject: [PATCH 0345/6183] spi/xilinx: Simplify irq allocation Use devm_request_irq() for irq allocation which simplify driver code. Signed-off-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 0b23408d357c..e5d3716da21a 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -344,7 +344,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) struct xilinx_spi *xspi; struct xspi_platform_data *pdata; struct resource *res; - int ret, irq, num_cs = 0, bits_per_word = 8; + int ret, num_cs = 0, bits_per_word = 8; struct spi_master *master; u32 tmp; u8 i; @@ -364,10 +364,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) return -EINVAL; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; - master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); if (!master) return -ENODEV; @@ -393,8 +389,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) master->num_chipselect = num_cs; master->dev.of_node = pdev->dev.of_node; - xspi->irq = irq; - /* * Detect endianess on the IP via loop bit in CR. Detection * must be done before reset is sent because incorrect reset @@ -428,19 +422,25 @@ static int xilinx_spi_probe(struct platform_device *pdev) goto put_master; } - /* SPI controller initializations */ xspi_init_hw(xspi); + xspi->irq = platform_get_irq(pdev, 0); + if (xspi->irq < 0) { + ret = xspi->irq; + goto put_master; + } + /* Register for SPI Interrupt */ - ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi); + ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, + dev_name(&pdev->dev), xspi); if (ret) goto put_master; ret = spi_bitbang_start(&xspi->bitbang); if (ret) { dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); - goto free_irq; + goto put_master; } dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", @@ -454,8 +454,6 @@ static int xilinx_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); return 0; -free_irq: - free_irq(xspi->irq, xspi); put_master: spi_master_put(master); @@ -466,9 +464,14 @@ static int xilinx_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct xilinx_spi *xspi = spi_master_get_devdata(master); + void __iomem *regs_base = xspi->regs; spi_bitbang_stop(&xspi->bitbang); - free_irq(xspi->irq, xspi); + + /* Disable all the interrupts just in case */ + xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); + /* Disable the global IPIF interrupt */ + xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); spi_master_put(xspi->bitbang.master); From 1696d9dc57e062ce5200f6a42a6aaada15b434bb Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 15 Jul 2013 10:15:09 +0200 Subject: [PATCH 0346/6183] ACPI: Remove the old /proc/acpi/event interface It is quite some time that this one has been deprecated. Get rid of it. Should some really important user be overseen, it may be reverted and the userspace program worked on first, but it is time to do something to get rid of this old stuff... Signed-off-by: Thomas Renninger Acked-by: Matthew Garrett Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki --- Documentation/laptops/asus-laptop.txt | 8 +- Documentation/laptops/sony-laptop.txt | 8 +- drivers/acpi/Kconfig | 18 ---- drivers/acpi/ac.c | 1 - drivers/acpi/acpi_pad.c | 1 - drivers/acpi/battery.c | 2 - drivers/acpi/bus.c | 98 ---------------------- drivers/acpi/button.c | 2 - drivers/acpi/event.c | 106 ------------------------ drivers/acpi/processor_driver.c | 4 - drivers/acpi/sbs.c | 15 +--- drivers/acpi/thermal.c | 3 - drivers/acpi/video.c | 10 --- drivers/char/sonypi.c | 5 -- drivers/pci/hotplug/acpiphp_ibm.c | 1 - drivers/platform/x86/asus-laptop.c | 1 - drivers/platform/x86/eeepc-laptop.c | 1 - drivers/platform/x86/fujitsu-laptop.c | 4 - drivers/platform/x86/panasonic-laptop.c | 3 - drivers/platform/x86/sony-laptop.c | 4 - drivers/platform/x86/thinkpad_acpi.c | 11 --- include/acpi/acpi_bus.h | 9 -- 22 files changed, 10 insertions(+), 305 deletions(-) diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt index 69f9fb3701e0..79a1bc675a8d 100644 --- a/Documentation/laptops/asus-laptop.txt +++ b/Documentation/laptops/asus-laptop.txt @@ -8,8 +8,8 @@ http://acpi4asus.sf.net/ This driver provides support for extra features of ACPI-compatible ASUS laptops. It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or - VICTOR XP7210 for example). It makes all the extra buttons generate standard - ACPI events that go through /proc/acpi/events and input events (like keyboards). + VICTOR XP7210 for example). It makes all the extra buttons generate input + events (like keyboards). On some models adds support for changing the display brightness and output, switching the LCD backlight on and off, and most importantly, allows you to blink those fancy LEDs intended for reporting mail and wireless status. @@ -55,8 +55,8 @@ Usage DSDT) to me. That's all, now, all the events generated by the hotkeys of your laptop - should be reported in your /proc/acpi/event entry. You can check with - "acpi_listen". + should be reported via netlink events. You can check with + "acpi_genl monitor" (part of the acpica project). Hotkeys are also reported as input keys (like keyboards) you can check which key are supported using "xev" under X11. diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt index 0d5ac7f5287e..978b1e615155 100644 --- a/Documentation/laptops/sony-laptop.txt +++ b/Documentation/laptops/sony-laptop.txt @@ -12,10 +12,10 @@ Fn keys (hotkeys): ------------------ Some models report hotkeys through the SNC or SPIC devices, such events are reported both through the ACPI subsystem as acpi events and through the INPUT -subsystem. See the logs of acpid or /proc/acpi/event and -/proc/bus/input/devices to find out what those events are and which input -devices are created by the driver. Additionally, loading the driver with the -debug option will report all events in the kernel log. +subsystem. See the logs of /proc/bus/input/devices to find out what those +events are and which input devices are created by the driver. +Additionally, loading the driver with the debug option will report all events +in the kernel log. The "scancodes" passed to the input system (that can be remapped with udev) are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 100bd724f648..3278a210c435 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -91,24 +91,6 @@ config ACPI_EC_DEBUGFS Thus this option is a debug option that helps to write ACPI drivers and can be used to identify ACPI code or EC firmware bugs. -config ACPI_PROC_EVENT - bool "Deprecated /proc/acpi/event support" - depends on PROC_FS - default y - help - A user-space daemon, acpid, typically reads /proc/acpi/event - and handles all ACPI-generated events. - - These events are now delivered to user-space either - via the input layer or as netlink events. - - This build option enables the old code for legacy - user-space implementation. After some time, this will - be moved under CONFIG_ACPI_PROCFS, and then deleted. - - Say Y here to retain the old behaviour. Say N if your - user-space is newer than kernel 2.6.23 (September 2007). - config ACPI_AC tristate "AC Adapter" depends on X86 diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 4f4e741d34b2..f37beaa32750 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -267,7 +267,6 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event) msleep(ac_sleep_before_get_state_ms); acpi_ac_get_state(ac); - acpi_bus_generate_proc_event(device, event, (u32) ac->state); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, (u32) ac->state); diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 27bb6a91de5f..6230637054c6 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -452,7 +452,6 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, switch (event) { case ACPI_PROCESSOR_AGGREGATOR_NOTIFY: acpi_pad_handle_notify(handle); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd252a8..33dfa851899d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1034,8 +1034,6 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) if (event == ACPI_BATTERY_NOTIFY_INFO) acpi_battery_refresh(battery); acpi_battery_update(battery); - acpi_bus_generate_proc_event(device, event, - acpi_battery_present(battery)); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, acpi_battery_present(battery)); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a5bb33bab448..b6e9a3786e2d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -345,104 +345,6 @@ static void acpi_bus_osc_support(void) /* do we need to check other returned cap? Sounds no */ } -/* -------------------------------------------------------------------------- - Event Management - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_PROC_EVENT -static DEFINE_SPINLOCK(acpi_bus_event_lock); - -LIST_HEAD(acpi_bus_event_list); -DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); - -extern int event_is_open; - -int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data) -{ - struct acpi_bus_event *event; - unsigned long flags; - - /* drop event on the floor if no one's listening */ - if (!event_is_open) - return 0; - - event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC); - if (!event) - return -ENOMEM; - - strcpy(event->device_class, device_class); - strcpy(event->bus_id, bus_id); - event->type = type; - event->data = data; - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - list_add_tail(&event->node, &acpi_bus_event_list); - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - wake_up_interruptible(&acpi_bus_event_queue); - - return 0; - -} - -EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4); - -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) -{ - if (!device) - return -EINVAL; - return acpi_bus_generate_proc_event4(device->pnp.device_class, - device->pnp.bus_id, type, data); -} - -EXPORT_SYMBOL(acpi_bus_generate_proc_event); - -int acpi_bus_receive_event(struct acpi_bus_event *event) -{ - unsigned long flags; - struct acpi_bus_event *entry = NULL; - - DECLARE_WAITQUEUE(wait, current); - - - if (!event) - return -EINVAL; - - if (list_empty(&acpi_bus_event_list)) { - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&acpi_bus_event_queue, &wait); - - if (list_empty(&acpi_bus_event_list)) - schedule(); - - remove_wait_queue(&acpi_bus_event_queue, &wait); - set_current_state(TASK_RUNNING); - - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&acpi_bus_event_lock, flags); - if (!list_empty(&acpi_bus_event_list)) { - entry = list_entry(acpi_bus_event_list.next, - struct acpi_bus_event, node); - list_del(&entry->node); - } - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - - if (!entry) - return -ENODEV; - - memcpy(event, entry, sizeof(struct acpi_bus_event)); - - kfree(entry); - - return 0; -} - -#endif /* CONFIG_ACPI_PROC_EVENT */ - /* -------------------------------------------------------------------------- Notification Handling -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index d2e617b5b3f6..a55773801c5f 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -303,8 +303,6 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) pm_wakeup_event(&device->dev, 0); } - - acpi_bus_generate_proc_event(device, event, ++button->pushed); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 1442737cedec..8247fcdde079 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -21,100 +21,6 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event"); -#ifdef CONFIG_ACPI_PROC_EVENT -/* Global vars for handling event proc entry */ -static DEFINE_SPINLOCK(acpi_system_event_lock); -int event_is_open = 0; -extern struct list_head acpi_bus_event_list; -extern wait_queue_head_t acpi_bus_event_queue; - -static int acpi_system_open_event(struct inode *inode, struct file *file) -{ - spin_lock_irq(&acpi_system_event_lock); - - if (event_is_open) - goto out_busy; - - event_is_open = 1; - - spin_unlock_irq(&acpi_system_event_lock); - return 0; - - out_busy: - spin_unlock_irq(&acpi_system_event_lock); - return -EBUSY; -} - -static ssize_t -acpi_system_read_event(struct file *file, char __user * buffer, size_t count, - loff_t * ppos) -{ - int result = 0; - struct acpi_bus_event event; - static char str[ACPI_MAX_STRING]; - static int chars_remaining = 0; - static char *ptr; - - if (!chars_remaining) { - memset(&event, 0, sizeof(struct acpi_bus_event)); - - if ((file->f_flags & O_NONBLOCK) - && (list_empty(&acpi_bus_event_list))) - return -EAGAIN; - - result = acpi_bus_receive_event(&event); - if (result) - return result; - - chars_remaining = sprintf(str, "%s %s %08x %08x\n", - event.device_class ? event. - device_class : "", - event.bus_id ? event. - bus_id : "", event.type, - event.data); - ptr = str; - } - - if (chars_remaining < count) { - count = chars_remaining; - } - - if (copy_to_user(buffer, ptr, count)) - return -EFAULT; - - *ppos += count; - chars_remaining -= count; - ptr += count; - - return count; -} - -static int acpi_system_close_event(struct inode *inode, struct file *file) -{ - spin_lock_irq(&acpi_system_event_lock); - event_is_open = 0; - spin_unlock_irq(&acpi_system_event_lock); - return 0; -} - -static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) -{ - poll_wait(file, &acpi_bus_event_queue, wait); - if (!list_empty(&acpi_bus_event_list)) - return POLLIN | POLLRDNORM; - return 0; -} - -static const struct file_operations acpi_system_event_ops = { - .owner = THIS_MODULE, - .open = acpi_system_open_event, - .read = acpi_system_read_event, - .release = acpi_system_close_event, - .poll = acpi_system_poll_event, - .llseek = default_llseek, -}; -#endif /* CONFIG_ACPI_PROC_EVENT */ - /* ACPI notifier chain */ static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); @@ -280,9 +186,6 @@ static int acpi_event_genetlink_init(void) static int __init acpi_event_init(void) { -#ifdef CONFIG_ACPI_PROC_EVENT - struct proc_dir_entry *entry; -#endif int error = 0; if (acpi_disabled) @@ -293,15 +196,6 @@ static int __init acpi_event_init(void) if (error) printk(KERN_WARNING PREFIX "Failed to create genetlink family for ACPI event\n"); - -#ifdef CONFIG_ACPI_PROC_EVENT - /* 'event' [R] */ - entry = proc_create("event", S_IRUSR, acpi_root_dir, - &acpi_system_event_ops); - if (!entry) - return -ENODEV; -#endif - return 0; } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 823be116619e..94b7b3b5559e 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -91,21 +91,17 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) acpi_processor_ppc_has_changed(pr, 1); if (saved == pr->performance_platform_limit) break; - acpi_bus_generate_proc_event(device, event, - pr->performance_platform_limit); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, pr->performance_platform_limit); break; case ACPI_PROCESSOR_NOTIFY_POWER: acpi_processor_cst_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_PROCESSOR_NOTIFY_THROTTLING: acpi_processor_tstate_has_changed(pr); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index b6241eeb1132..aef7e1cd1e5d 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -873,14 +873,9 @@ static void acpi_sbs_callback(void *context) u8 saved_charger_state = sbs->charger_present; u8 saved_battery_state; acpi_ac_get_present(sbs); - if (sbs->charger_present != saved_charger_state) { -#ifdef CONFIG_ACPI_PROC_EVENT - acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, - ACPI_SBS_NOTIFY_STATUS, - sbs->charger_present); -#endif + if (sbs->charger_present != saved_charger_state) kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE); - } + if (sbs->manager_present) { for (id = 0; id < MAX_SBS_BAT; ++id) { if (!(sbs->batteries_supported & (1 << id))) @@ -890,12 +885,6 @@ static void acpi_sbs_callback(void *context) acpi_battery_read(bat); if (saved_battery_state == bat->present) continue; -#ifdef CONFIG_ACPI_PROC_EVENT - acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, - bat->name, - ACPI_SBS_NOTIFY_STATUS, - bat->present); -#endif kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE); } } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a33821ca3895..547a906a7662 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -769,7 +769,6 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip, else return 0; - acpi_bus_generate_proc_event(tz->device, type, 1); acpi_bus_generate_netlink_event(tz->device->pnp.device_class, dev_name(&tz->device->dev), type, 1); @@ -980,14 +979,12 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) case ACPI_THERMAL_NOTIFY_THRESHOLDS: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_THERMAL_NOTIFY_DEVICES: acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES); acpi_thermal_check(tz); - acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5d7075d25700..8f91a3783191 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1556,7 +1556,6 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) switch (event) { case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, * most likely via hotkey. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; @@ -1564,20 +1563,16 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) * connector. */ acpi_video_device_enumerate(video); acpi_video_device_rebind(video); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_SWITCHVIDEOMODE; break; case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_VIDEO_NEXT; break; case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_VIDEO_PREV; break; @@ -1620,31 +1615,26 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_CYCLE; break; case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSUP; break; case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESSDOWN; break; case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_BRIGHTNESS_ZERO; break; case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ if (brightness_switch_enabled) acpi_video_switch_brightness(video_device, event); - acpi_bus_generate_proc_event(device, event, 0); keycode = KEY_DISPLAY_OFF; break; default: diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index bf2349dbbf7f..7cc1fe2241fd 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -876,11 +876,6 @@ found: if (useinput) sonypi_report_input_event(event); -#ifdef CONFIG_ACPI - if (sonypi_acpi_device) - acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event); -#endif - kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event, sizeof(event), &sonypi_device.fifo_lock); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index c35e8ad6db01..5394fffdf167 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -270,7 +270,6 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context) if (subevent == 0x80) { dbg("%s: generationg bus event\n", __func__); - acpi_bus_generate_proc_event(note->device, note->event, detail); acpi_bus_generate_netlink_event(note->device->pnp.device_class, dev_name(¬e->device->dev), note->event, detail); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8e268da6fdbd..0e9c169b42f8 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1543,7 +1543,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) /* TODO Find a better way to handle events count. */ count = asus->event_count[event % 128]++; - acpi_bus_generate_proc_event(asus->device, event, count); acpi_bus_generate_netlink_event(asus->device->pnp.device_class, dev_name(&asus->device->dev), event, count); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5d26e70bed6c..a6afd4108beb 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1269,7 +1269,6 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event) if (event > ACPI_MAX_SYS_NOTIFY) return; count = eeepc->event_count[event % 128]++; - acpi_bus_generate_proc_event(device, event, count); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, count); diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1c9386e7c58c..52b8a97efde1 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -773,8 +773,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) else set_lcd_level(newb); } - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); keycode = KEY_BRIGHTNESSUP; } else if (oldb > newb) { if (disable_brightness_adjust != 1) { @@ -783,8 +781,6 @@ static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) else set_lcd_level(newb); } - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); keycode = KEY_BRIGHTNESSDOWN; } break; diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 4add9a31bf60..984253da365d 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -464,9 +464,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) "error getting hotkey status\n")); return; } - - acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); - if (!sparse_keymap_report_event(hotk_input_dev, result & 0xf, result & 0x80, false)) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 2ac045f27f10..069821b1fc22 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1275,9 +1275,6 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) ev_type = HOTKEY; sony_laptop_report_input_event(real_ev); } - - acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev); - acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); } @@ -4243,7 +4240,6 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) found: sony_laptop_report_input_event(device_event); - acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); sonypi_compat_report_event(device_event); return IRQ_HANDLED; } diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 54d31c0a9840..e946c0d58a97 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2282,10 +2282,6 @@ static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; static void tpacpi_hotkey_send_key(unsigned int scancode) { tpacpi_input_send_key_masked(scancode); - if (hotkey_report_mode < 2) { - acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, - 0x80, TP_HKEY_EV_HOTKEY_BASE + scancode); - } } static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) @@ -3737,13 +3733,6 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) "event happened to %s\n", TPACPI_MAIL); } - /* Legacy events */ - if (!ignore_acpi_ev && - (send_acpi_ev || hotkey_report_mode < 2)) { - acpi_bus_generate_proc_event(ibm->acpi->device, - event, hkey); - } - /* netlink events */ if (!ignore_acpi_ev && send_acpi_ev) { acpi_bus_generate_netlink_event( diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 56e6b68c8d2f..2650d1f19e43 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -383,15 +383,6 @@ bool acpi_bus_can_wakeup(acpi_handle handle); static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; } #endif -#ifdef CONFIG_ACPI_PROC_EVENT -int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data); -int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data); -int acpi_bus_receive_event(struct acpi_bus_event *event); -#else -static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data) - { return 0; } -#endif - void acpi_scan_lock_acquire(void); void acpi_scan_lock_release(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); From 8b5301c5ff2568236c6e3b3d0c93a3e4194ec3f5 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 3 Jul 2013 14:48:39 +0200 Subject: [PATCH 0347/6183] platform / thinkpad: Remove deprecated hotkey_report_mode parameter It is somewhat strange that the default value to support the depracated interface is set (1). Anyway this has existed for years. The previous patch already removed the functionality to still export events through /proc. Now this param is useless and should vanish too. Signed-off-by: Thomas Renninger Acked-by: Matthew Garrett Acked-by: Henrique de Moraes Holschuh Signed-off-by: Rafael J. Wysocki --- Documentation/laptops/thinkpad-acpi.txt | 73 ++----------------------- drivers/platform/x86/thinkpad_acpi.c | 29 ---------- 2 files changed, 6 insertions(+), 96 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index cf7bc6cb9719..86c52360ffe7 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -329,20 +329,6 @@ sysfs notes: This attribute has poll()/select() support. - hotkey_report_mode: - Returns the state of the procfs ACPI event report mode - filter for hot keys. If it is set to 1 (the default), - all hot key presses are reported both through the input - layer and also as ACPI events through procfs (but not - through netlink). If it is set to 2, hot key presses - are reported only through the input layer. - - This attribute is read-only in kernels 2.6.23 or later, - and read-write on earlier kernels. - - May return -EPERM (write access locked out by module - parameter) or -EACCES (read-only). - wakeup_reason: Set to 1 if the system is waking up because the user requested a bay ejection. Set to 2 if the system is @@ -518,24 +504,21 @@ SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A Non hotkey ACPI HKEY event map: ------------------------------- -Events that are not propagated by the driver, except for legacy -compatibility purposes when hotkey_report_mode is set to 1: - -0x5001 Lid closed -0x5002 Lid opened -0x5009 Tablet swivel: switched to tablet mode -0x500A Tablet swivel: switched to normal mode -0x7000 Radio Switch may have changed state - Events that are never propagated by the driver: 0x2304 System is waking up from suspend to undock 0x2305 System is waking up from suspend to eject bay 0x2404 System is waking up from hibernation to undock 0x2405 System is waking up from hibernation to eject bay +0x5001 Lid closed +0x5002 Lid opened +0x5009 Tablet swivel: switched to tablet mode +0x500A Tablet swivel: switched to normal mode 0x5010 Brightness level changed/control event 0x6000 KEYBOARD: Numlock key pressed 0x6005 KEYBOARD: Fn key pressed (TO BE VERIFIED) +0x7000 Radio Switch may have changed state + Events that are propagated by the driver to userspace: @@ -574,50 +557,6 @@ operating system is to force either an immediate suspend or hibernate cycle, or a system shutdown. Obviously, something is very wrong if this happens. -Compatibility notes: - -ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never -supported the input layer, and sent events over the procfs ACPI event -interface. - -To avoid sending duplicate events over the input layer and the ACPI -event interface, thinkpad-acpi 0.16 implements a module parameter -(hotkey_report_mode), and also a sysfs device attribute with the same -name. - -Make no mistake here: userspace is expected to switch to using the input -layer interface of thinkpad-acpi, together with the ACPI netlink event -interface in kernels 2.6.23 and later, or with the ACPI procfs event -interface in kernels 2.6.22 and earlier. - -If no hotkey_report_mode module parameter is specified (or it is set to -zero), the driver defaults to mode 1 (see below), and on kernels 2.6.22 -and earlier, also allows one to change the hotkey_report_mode through -sysfs. In kernels 2.6.23 and later, where the netlink ACPI event -interface is available, hotkey_report_mode cannot be changed through -sysfs (it is read-only). - -If the hotkey_report_mode module parameter is set to 1 or 2, it cannot -be changed later through sysfs (any writes will return -EPERM to signal -that hotkey_report_mode was locked. On 2.6.23 and later, where -hotkey_report_mode cannot be changed at all, writes will return -EACCES). - -hotkey_report_mode set to 1 makes the driver export through the procfs -ACPI event interface all hot key presses (which are *also* sent to the -input layer). This is a legacy compatibility behaviour, and it is also -the default mode of operation for the driver. - -hotkey_report_mode set to 2 makes the driver filter out the hot key -presses from the procfs ACPI event interface, so these events will only -be sent through the input layer. Userspace that has been updated to use -the thinkpad-acpi input layer interface should set hotkey_report_mode to -2. - -Hot key press events are never sent to the ACPI netlink event interface. -Really up-to-date userspace under kernel 2.6.23 and later is to use the -netlink interface and the input layer interface, and don't bother at all -with hotkey_report_mode. - Brightness hotkey notes: diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e946c0d58a97..be67e5e28d18 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2022,8 +2022,6 @@ static u32 hotkey_driver_mask; /* events needed by the driver */ static u32 hotkey_user_mask; /* events visible to userspace */ static u32 hotkey_acpi_mask; /* events enabled in firmware */ -static unsigned int hotkey_report_mode; - static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; @@ -2878,18 +2876,6 @@ static void hotkey_tablet_mode_notify_change(void) "hotkey_tablet_mode"); } -/* sysfs hotkey report_mode -------------------------------------------- */ -static ssize_t hotkey_report_mode_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - (hotkey_report_mode != 0) ? hotkey_report_mode : 1); -} - -static struct device_attribute dev_attr_hotkey_report_mode = - __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); - /* sysfs wakeup reason (pollable) -------------------------------------- */ static ssize_t hotkey_wakeup_reason_show(struct device *dev, struct device_attribute *attr, @@ -2931,7 +2917,6 @@ static struct attribute *hotkey_attributes[] __initdata = { &dev_attr_hotkey_enable.attr, &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, - &dev_attr_hotkey_report_mode.attr, &dev_attr_hotkey_wakeup_reason.attr, &dev_attr_hotkey_wakeup_hotunplug_complete.attr, &dev_attr_hotkey_mask.attr, @@ -3435,11 +3420,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n", hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask); - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "legacy ibm/hotkey event reporting over procfs %s\n", - (hotkey_report_mode < 2) ? - "enabled" : "disabled"); - tpacpi_inputdev->open = &hotkey_inputdev_open; tpacpi_inputdev->close = &hotkey_inputdev_close; @@ -8829,11 +8809,6 @@ module_param(brightness_enable, uint, 0444); MODULE_PARM_DESC(brightness_enable, "Enables backlight control when 1, disables when 0"); -module_param(hotkey_report_mode, uint, 0444); -MODULE_PARM_DESC(hotkey_report_mode, - "used for backwards compatibility with userspace, " - "see documentation"); - #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT module_param_named(volume_mode, volume_mode, uint, 0444); MODULE_PARM_DESC(volume_mode, @@ -8964,10 +8939,6 @@ static int __init thinkpad_acpi_module_init(void) tpacpi_lifecycle = TPACPI_LIFE_INIT; - /* Parameter checking */ - if (hotkey_report_mode > 2) - return -EINVAL; - /* Driver-level probe */ ret = get_thinkpad_model_data(&thinkpad_id); From 68593c9340847662ac1d337b3c5621a1f4ca05db Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Mon, 15 Jul 2013 21:41:32 +0800 Subject: [PATCH 0348/6183] ALSA: hdspm - remove unneeded semicolon sound/pci/rme9652/hdspm.c:1110:2-3: Unneeded semicolon Generated by: coccinelle/misc/semicolon.cocci Reported-by: Fengguang Wu Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a3a71ac513f1..ec6335e2fda0 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1250,7 +1250,7 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) else if (hdspm->control_register & HDSPM_DoubleSpeed) return rate * 2; - }; + } return rate; } From c50c2f7af1fe503b1c3b8cb0fa0e3c9b4bba9e92 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Jul 2013 16:39:09 +0100 Subject: [PATCH 0349/6183] ASoC: kirkwood: Remove unused headers Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-openrd.c | 2 -- sound/soc/kirkwood/kirkwood-t5325.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c index b979c7154715..addbebc2b3fa 100644 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ b/sound/soc/kirkwood/kirkwood-openrd.c @@ -16,9 +16,7 @@ #include #include #include -#include #include -#include #include "../codecs/cs42l51.h" static int openrd_client_hw_params(struct snd_pcm_substream *substream, diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c index 1d0ed6f8add7..4f4cb56f765a 100644 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ b/sound/soc/kirkwood/kirkwood-t5325.c @@ -15,9 +15,7 @@ #include #include #include -#include #include -#include #include "../codecs/alc5623.h" static int t5325_hw_params(struct snd_pcm_substream *substream, From 30d3924852c7b07df4e015610aca1cafa5c15cab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Jul 2013 16:40:18 +0100 Subject: [PATCH 0350/6183] ASoC: kirkwood: Enable build on non-Kirkwood platforms Improve build coverage by enabling build on other platforms if COMPILE_TEST is enabled. Signed-off-by: Mark Brown --- sound/soc/kirkwood/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index c62d715235e2..59085ad6c41a 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig @@ -1,6 +1,6 @@ config SND_KIRKWOOD_SOC tristate "SoC Audio for the Marvell Kirkwood chip" - depends on ARCH_KIRKWOOD + depends on ARCH_KIRKWOOD || COMPILE_TEST help Say Y or M if you want to add support for codecs attached to the Kirkwood I2S interface. You will also need to select the @@ -11,7 +11,7 @@ config SND_KIRKWOOD_SOC_I2S config SND_KIRKWOOD_SOC_OPENRD tristate "SoC Audio support for Kirkwood Openrd Client" - depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE) + depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST) depends on I2C select SND_KIRKWOOD_SOC_I2S select SND_SOC_CS42L51 @@ -21,7 +21,7 @@ config SND_KIRKWOOD_SOC_OPENRD config SND_KIRKWOOD_SOC_T5325 tristate "SoC Audio support for HP t5325" - depends on SND_KIRKWOOD_SOC && MACH_T5325 && I2C + depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C select SND_KIRKWOOD_SOC_I2S select SND_SOC_ALC5623 help From 4734dc96ea50109ae08603af10804f989ff35437 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Jul 2013 16:41:14 +0100 Subject: [PATCH 0351/6183] ASoC: kirkwood-i2s: Use devm_clk_get() for extclk Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 4c9dad3263c5..44412eaf6e81 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -498,10 +498,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) if (err < 0) return err; - priv->extclk = clk_get(&pdev->dev, "extclk"); + priv->extclk = devm_clk_get(&pdev->dev, "extclk"); if (!IS_ERR(priv->extclk)) { if (priv->extclk == priv->clk) { - clk_put(priv->extclk); priv->extclk = ERR_PTR(-EINVAL); } else { dev_info(&pdev->dev, "found external clock\n"); @@ -529,10 +528,8 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev) return 0; dev_err(&pdev->dev, "snd_soc_register_component failed\n"); - if (!IS_ERR(priv->extclk)) { + if (!IS_ERR(priv->extclk)) clk_disable_unprepare(priv->extclk); - clk_put(priv->extclk); - } clk_disable_unprepare(priv->clk); return err; @@ -544,10 +541,8 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - if (!IS_ERR(priv->extclk)) { + if (!IS_ERR(priv->extclk)) clk_disable_unprepare(priv->extclk); - clk_put(priv->extclk); - } clk_disable_unprepare(priv->clk); return 0; From 21b341cac2cdc52d59db5bd936a5c6b325286c2d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 10 Jul 2013 12:30:43 +0530 Subject: [PATCH 0352/6183] ARM: tegra: enable gpio-keys on Dalmore Dalmore have the keys mounted on board which are connected to different pins of Tegra. Add the keys entry in DTS file to enable key functionality. This will enable KEY_POWER, KEY_HOME, KEY_VOLUMEUP and KEY_VOLUMEDOWN. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra114-dalmore.dts | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts index cb640eb6c932..a42bfa4211a9 100644 --- a/arch/arm/boot/dts/tegra114-dalmore.dts +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -883,6 +883,35 @@ }; }; + gpio-keys { + compatible = "gpio-keys"; + + home { + label = "Home"; + gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>; + linux,code = <102>; /* KEY_HOME */ + }; + + power { + label = "Power"; + gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; + linux,code = <116>; /* KEY_POWER */ + gpio-key,wakeup; + }; + + volume_down { + label = "Volume Down"; + gpios = <&gpio TEGRA_GPIO(R, 1) GPIO_ACTIVE_LOW>; + linux,code = <114>; /* KEY_VOLUMEDOWN */ + }; + + volume_up { + label = "Volume Up"; + gpios = <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_LOW>; + linux,code = <115>; /* KEY_VOLUMEUP */ + }; + }; + regulators { compatible = "simple-bus"; #address-cells = <1>; From 74ecab275dfbd00bf3f1daa7f0be0c0288fbeac4 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Fri, 12 Jul 2013 15:49:23 +0800 Subject: [PATCH 0353/6183] ARM: tegra: add DT entry for nct1008 to Cardhu Enable thermal sensor nct1008 for Tegra30 Cardhu. Signed-off-by: Wei Ni Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra30-cardhu.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index f65b53d32416..e5759caae770 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -286,6 +286,13 @@ }; }; }; + + nct1008 { + compatible = "onnn,nct1008"; + reg = <0x4c>; + interrupt-parent = <&gpio>; + interrupts = ; + }; }; spi@7000da00 { From 2b8584d5d2f4ba5b4eb49e500c1dd8f7a9784132 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 15 Jul 2013 10:33:53 -0600 Subject: [PATCH 0354/6183] ARM: tegra: fix DT node ordering in Tegra30 Cardhu Nodes should be sorted by reg. Fix location of the tps62361 node. Signed-off-by: Stephen Warren --- arch/arm/boot/dts/tegra30-cardhu.dtsi | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index e5759caae770..c011b6797648 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -173,19 +173,6 @@ gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>; }; - tps62361 { - compatible = "ti,tps62361"; - reg = <0x60>; - - regulator-name = "tps62361-vout"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1500000>; - regulator-boot-on; - regulator-always-on; - ti,vsel0-state-high; - ti,vsel1-state-high; - }; - pmic: tps65911@2d { compatible = "ti,tps65911"; reg = <0x2d>; @@ -293,6 +280,19 @@ interrupt-parent = <&gpio>; interrupts = ; }; + + tps62361 { + compatible = "ti,tps62361"; + reg = <0x60>; + + regulator-name = "tps62361-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + ti,vsel0-state-high; + ti,vsel1-state-high; + }; }; spi@7000da00 { From 939c02777a27ea7915764ecca5263dbb60c664f3 Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sat, 29 Jun 2013 18:21:16 +0530 Subject: [PATCH 0355/6183] regulator: s2mps11: Implement set_ramp_rate callback for bucks Implementing set_ramp_rate() and using standard constraints for getting ramp_delay and ramp_disable, instead of getting it as s2mps11 specific data through platform data, makes driver more compliant with framework and reduces the complexity for adding DT support. Signed-off-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 117 ++++++++++++++++++++++++++++ include/linux/mfd/samsung/s2mps11.h | 11 +++ 2 files changed, 128 insertions(+) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index a671eb63a4e5..4b84e7660637 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,121 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); } +static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK; + unsigned int ramp_enable = 1, enable_shift = 0; + int ret; + + switch (rdev->desc->id) { + case S2MPS11_BUCK1: + if (ramp_delay > s2mps11->ramp_delay16) + s2mps11->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay16; + + ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT; + break; + case S2MPS11_BUCK2: + enable_shift = S2MPS11_BUCK2_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + s2mps11->ramp_delay2 = ramp_delay; + ramp_shift = S2MPS11_BUCK2_RAMP_SHIFT; + ramp_reg = S2MPS11_REG_RAMP; + break; + case S2MPS11_BUCK3: + enable_shift = S2MPS11_BUCK3_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mps11->ramp_delay34) + s2mps11->ramp_delay34 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay34; + + ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT; + ramp_reg = S2MPS11_REG_RAMP; + break; + case S2MPS11_BUCK4: + enable_shift = S2MPS11_BUCK4_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mps11->ramp_delay34) + s2mps11->ramp_delay34 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay34; + + ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT; + ramp_reg = S2MPS11_REG_RAMP; + break; + case S2MPS11_BUCK5: + s2mps11->ramp_delay5 = ramp_delay; + ramp_shift = S2MPS11_BUCK5_RAMP_SHIFT; + break; + case S2MPS11_BUCK6: + enable_shift = S2MPS11_BUCK6_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mps11->ramp_delay16) + s2mps11->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay16; + + ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT; + break; + case S2MPS11_BUCK7: + case S2MPS11_BUCK8: + case S2MPS11_BUCK10: + if (ramp_delay > s2mps11->ramp_delay7810) + s2mps11->ramp_delay7810 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay7810; + + ramp_shift = S2MPS11_BUCK7810_RAMP_SHIFT; + break; + case S2MPS11_BUCK9: + s2mps11->ramp_delay9 = ramp_delay; + ramp_shift = S2MPS11_BUCK9_RAMP_SHIFT; + break; + default: + return 0; + } + + if (!ramp_enable) + goto ramp_disable; + + if (enable_shift) { + ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, + 1 << enable_shift, 1 << enable_shift); + if (ret) { + dev_err(&rdev->dev, "failed to enable ramp rate\n"); + return ret; + } + } + + ramp_val = get_ramp_delay(ramp_delay); + + return regmap_update_bits(rdev->regmap, ramp_reg, + ramp_val << ramp_shift, 1 << ramp_shift); + +ramp_disable: + return regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, 0, + 1 << enable_shift); +} + static struct regulator_ops s2mps11_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -124,6 +240,7 @@ static struct regulator_ops s2mps11_buck_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel, + .set_ramp_delay = s2mps11_set_ramp_delay, }; #define regulator_desc_ldo1(num) { \ diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h index 4e94dc65f987..d0d52ea60074 100644 --- a/include/linux/mfd/samsung/s2mps11.h +++ b/include/linux/mfd/samsung/s2mps11.h @@ -191,6 +191,17 @@ enum s2mps11_regulators { #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1) #define S2MPS11_RAMP_DELAY 25000 /* uV/us */ + +#define S2MPS11_BUCK2_RAMP_SHIFT 6 +#define S2MPS11_BUCK34_RAMP_SHIFT 4 +#define S2MPS11_BUCK5_RAMP_SHIFT 6 +#define S2MPS11_BUCK16_RAMP_SHIFT 4 +#define S2MPS11_BUCK7810_RAMP_SHIFT 2 +#define S2MPS11_BUCK9_RAMP_SHIFT 0 +#define S2MPS11_BUCK2_RAMP_EN_SHIFT 3 +#define S2MPS11_BUCK3_RAMP_EN_SHIFT 2 +#define S2MPS11_BUCK4_RAMP_EN_SHIFT 1 +#define S2MPS11_BUCK6_RAMP_EN_SHIFT 0 #define S2MPS11_PMIC_EN_SHIFT 6 #define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3) From a50c6b3255b819c9e18c1cc350ed46698b346c1a Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sat, 29 Jun 2013 18:21:17 +0530 Subject: [PATCH 0356/6183] regulator: s2mps11: Add DT support This patch adds DT support for parsing regulators constraints for parent(mfd) node and moves some common intialising code out of loop while registering. Signed-off-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 49 ++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 4b84e7660637..b316d40c8e14 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -16,13 +16,17 @@ #include #include #include +#include #include #include #include #include +#include #include #include +#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) + struct s2mps11_info { struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; @@ -407,22 +411,38 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); + struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX]; + struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; int i, ret; unsigned char ramp_enable, ramp_reg = 0; - if (!pdata) { - dev_err(pdev->dev.parent, "Platform data not supplied\n"); - return -ENODEV; - } - s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; - platform_set_drvdata(pdev, s2mps11); + if (!iodev->dev->of_node) + goto p_data; + + for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) + rdata[i].name = regulators[i].name; + + reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); + if (!reg_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); + + goto common_reg; +p_data: + if (!pdata) { + dev_err(pdev->dev.parent, "Platform data not supplied\n"); + return -ENODEV; + } s2mps11->ramp_delay2 = pdata->buck2_ramp_delay; s2mps11->ramp_delay34 = pdata->buck34_ramp_delay; @@ -454,12 +474,19 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9); sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg); - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { +common_reg: + platform_set_drvdata(pdev, s2mps11); - config.dev = &pdev->dev; - config.regmap = iodev->regmap; - config.init_data = pdata->regulators[i].initdata; - config.driver_data = s2mps11; + config.dev = &pdev->dev; + config.regmap = iodev->regmap; + config.driver_data = s2mps11; + for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + if (!reg_np) { + config.init_data = pdata->regulators[i].initdata; + } else { + config.init_data = rdata[i].init_data; + config.of_node = rdata[i].of_node; + } s2mps11->rdev[i] = regulator_register(®ulators[i], &config); if (IS_ERR(s2mps11->rdev[i])) { From 6c683c929977b90795939e1e862271c112e7d10f Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sat, 29 Jun 2013 18:21:18 +0530 Subject: [PATCH 0357/6183] regulator: s2mps11: Convert driver completely to use set_ramp_delay callback Since now we have ramp_delay and ramp_disable as standard regulator constraints and DT part using it so this patch removes legacy part i.e. getting ramp_delayxx and ramp_enable from pdata since it can be passed as standard regulator constraints. Signed-off-by: Yadwinder Singh Brar Signed-off-by: Mark Brown --- drivers/regulator/s2mps11.c | 62 ++++++------------------------------- 1 file changed, 9 insertions(+), 53 deletions(-) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index b316d40c8e14..f047d36f6027 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -36,11 +36,6 @@ struct s2mps11_info { int ramp_delay16; int ramp_delay7810; int ramp_delay9; - - bool buck6_ramp; - bool buck2_ramp; - bool buck3_ramp; - bool buck4_ramp; }; static int get_ramp_delay(int ramp_delay) @@ -68,26 +63,18 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, switch (rdev->desc->id) { case S2MPS11_BUCK2: - if (!s2mps11->buck2_ramp) - return 0; ramp_delay = s2mps11->ramp_delay2; break; case S2MPS11_BUCK3: - if (!s2mps11->buck3_ramp) - return 0; ramp_delay = s2mps11->ramp_delay34; break; case S2MPS11_BUCK4: - if (!s2mps11->buck4_ramp) - return 0; ramp_delay = s2mps11->ramp_delay34; break; case S2MPS11_BUCK5: ramp_delay = s2mps11->ramp_delay5; break; case S2MPS11_BUCK6: - if (!s2mps11->buck6_ramp) - return 0; case S2MPS11_BUCK1: ramp_delay = s2mps11->ramp_delay16; break; @@ -416,15 +403,21 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) struct regulator_config config = { }; struct s2mps11_info *s2mps11; int i, ret; - unsigned char ramp_enable, ramp_reg = 0; s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; - if (!iodev->dev->of_node) - goto p_data; + if (!iodev->dev->of_node) { + if (pdata) { + goto common_reg; + } else { + dev_err(pdev->dev.parent, + "Platform data or DT node not supplied\n"); + return -ENODEV; + } + } for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) rdata[i].name = regulators[i].name; @@ -437,43 +430,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); - goto common_reg; -p_data: - if (!pdata) { - dev_err(pdev->dev.parent, "Platform data not supplied\n"); - return -ENODEV; - } - - s2mps11->ramp_delay2 = pdata->buck2_ramp_delay; - s2mps11->ramp_delay34 = pdata->buck34_ramp_delay; - s2mps11->ramp_delay5 = pdata->buck5_ramp_delay; - s2mps11->ramp_delay16 = pdata->buck16_ramp_delay; - s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay; - s2mps11->ramp_delay9 = pdata->buck9_ramp_delay; - - s2mps11->buck6_ramp = pdata->buck6_ramp_enable; - s2mps11->buck2_ramp = pdata->buck2_ramp_enable; - s2mps11->buck3_ramp = pdata->buck3_ramp_enable; - s2mps11->buck4_ramp = pdata->buck4_ramp_enable; - - ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) | - (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ; - - if (ramp_enable) { - if (s2mps11->buck2_ramp) - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) << 6; - if (s2mps11->buck3_ramp || s2mps11->buck4_ramp) - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) << 4; - sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable); - } - - ramp_reg &= 0x00; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) << 6; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) << 4; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) << 2; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9); - sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg); - common_reg: platform_set_drvdata(pdev, s2mps11); From f2bd77c8f3b8c108bc460e779585854fbd2d8c59 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Wed, 3 Jul 2013 17:55:48 +0800 Subject: [PATCH 0358/6183] ARM: tegra: enable Cortex-A15 erratum 798181 The commit 93dc688 (ARM: 7684/1: errata: Workaround for Cortex-A15 erratum 798181 (TLBI/DSB operations)) introduced a workaround for Cortex-A15 erratum 798181. Enable it for Tegra114. Signed-off-by: Joseph Lo Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index ef3a8da49b2d..add345e6a6bb 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -59,6 +59,7 @@ config ARCH_TEGRA_3x_SOC config ARCH_TEGRA_114_SOC bool "Enable support for Tegra114 family" select HAVE_ARM_ARCH_TIMER + select ARM_ERRATA_798181 select ARM_GIC select ARM_L1_CACHE_SHIFT_6 select CPU_V7 From c85cffa5894fad8ad7c8051ccf7dd73a3a3f92b6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 11 Jul 2013 17:28:29 +0200 Subject: [PATCH 0359/6183] perf timechart: Use traceevent lib event-parse.h include Adding traceevent lib event-parse.h include to timechart command and removing duplicated local 'enum trace_flag_type' definition. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Renninger Link: http://lkml.kernel.org/r/1373556513-3000-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-timechart.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4536a92b18f3..a5120095978e 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -12,6 +12,8 @@ * of the License. */ +#include + #include "builtin.h" #include "util/util.h" @@ -328,25 +330,6 @@ struct wakeup_entry { int success; }; -/* - * trace_flag_type is an enumeration that holds different - * states when a trace occurs. These are: - * IRQS_OFF - interrupts were disabled - * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags - * NEED_RESCED - reschedule is requested - * HARDIRQ - inside an interrupt handler - * SOFTIRQ - inside a softirq handler - */ -enum trace_flag_type { - TRACE_FLAG_IRQS_OFF = 0x01, - TRACE_FLAG_IRQS_NOSUPPORT = 0x02, - TRACE_FLAG_NEED_RESCHED = 0x04, - TRACE_FLAG_HARDIRQ = 0x08, - TRACE_FLAG_SOFTIRQ = 0x10, -}; - - - struct sched_switch { struct trace_entry te; char prev_comm[TASK_COMM_LEN]; From 5936678e7da5f8d2944a2ad45d66c88b4a7ccb67 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 11 Jul 2013 17:28:30 +0200 Subject: [PATCH 0360/6183] perf timechart: Remove event types framework only user The only user of the event types data is 'perf timechart' command and uses this info to identify proper tracepoints based on its name. Switching this code to use tracepoint callbacks handlers same as another commands like builtin-{kmem,lock,sched}.c using the perf_session__set_tracepoints_handlers function. This way we get rid of the only event types user and can remove them completely in next patches. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Renninger Link: http://lkml.kernel.org/r/1373556513-3000-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-timechart.c | 159 ++++++++++++++++++++------------- 1 file changed, 99 insertions(+), 60 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index a5120095978e..c2e02319347a 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -21,6 +21,7 @@ #include "util/color.h" #include #include "util/cache.h" +#include "util/evlist.h" #include "util/evsel.h" #include #include "util/symbol.h" @@ -462,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) } } +typedef int (*tracepoint_handler)(struct perf_evsel *evsel, + struct perf_sample *sample); static int process_sample_event(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, @@ -469,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, struct perf_evsel *evsel, struct machine *machine __maybe_unused) { - struct trace_entry *te; - if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { if (!first_time || first_time > sample->time) first_time = sample->time; @@ -478,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, last_time = sample->time; } - te = (void *)sample->raw_data; - if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { - char *event_str; -#ifdef SUPPORT_OLD_POWER_EVENTS - struct power_entry_old *peo; - peo = (void *)te; -#endif - /* - * FIXME: use evsel, its already mapped from id to perf_evsel, - * remove perf_header__find_event infrastructure bits. - * Mapping all these "power:cpu_idle" strings to the tracepoint - * ID and then just comparing against evsel->attr.config. - * - * e.g.: - * - * if (evsel->attr.config == power_cpu_idle_id) - */ - event_str = perf_header__find_event(te->type); + if (sample->cpu > numcpus) + numcpus = sample->cpu; - if (!event_str) - return 0; - - if (sample->cpu > numcpus) - numcpus = sample->cpu; - - if (strcmp(event_str, "power:cpu_idle") == 0) { - struct power_processor_entry *ppe = (void *)te; - if (ppe->state == (u32)PWR_EVENT_EXIT) - c_state_end(ppe->cpu_id, sample->time); - else - c_state_start(ppe->cpu_id, sample->time, - ppe->state); - } - else if (strcmp(event_str, "power:cpu_frequency") == 0) { - struct power_processor_entry *ppe = (void *)te; - p_state_change(ppe->cpu_id, sample->time, ppe->state); - } - - else if (strcmp(event_str, "sched:sched_wakeup") == 0) - sched_wakeup(sample->cpu, sample->time, sample->pid, te); - - else if (strcmp(event_str, "sched:sched_switch") == 0) - sched_switch(sample->cpu, sample->time, te); - -#ifdef SUPPORT_OLD_POWER_EVENTS - if (use_old_power_events) { - if (strcmp(event_str, "power:power_start") == 0) - c_state_start(peo->cpu_id, sample->time, - peo->value); - - else if (strcmp(event_str, "power:power_end") == 0) - c_state_end(sample->cpu, sample->time); - - else if (strcmp(event_str, - "power:power_frequency") == 0) - p_state_change(peo->cpu_id, sample->time, - peo->value); - } -#endif + if (evsel->handler.func != NULL) { + tracepoint_handler f = evsel->handler.func; + return f(evsel, sample); } + return 0; } +static int +process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + struct power_processor_entry *ppe = sample->raw_data; + + if (ppe->state == (u32) PWR_EVENT_EXIT) + c_state_end(ppe->cpu_id, sample->time); + else + c_state_start(ppe->cpu_id, sample->time, ppe->state); + return 0; +} + +static int +process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + struct power_processor_entry *ppe = sample->raw_data; + + p_state_change(ppe->cpu_id, sample->time, ppe->state); + return 0; +} + +static int +process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + struct trace_entry *te = sample->raw_data; + + sched_wakeup(sample->cpu, sample->time, sample->pid, te); + return 0; +} + +static int +process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + struct trace_entry *te = sample->raw_data; + + sched_switch(sample->cpu, sample->time, te); + return 0; +} + +#ifdef SUPPORT_OLD_POWER_EVENTS +static int +process_sample_power_start(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + struct power_entry_old *peo = sample->raw_data; + + c_state_start(peo->cpu_id, sample->time, peo->value); + return 0; +} + +static int +process_sample_power_end(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + c_state_end(sample->cpu, sample->time); + return 0; +} + +static int +process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused, + struct perf_sample *sample) +{ + struct power_entry_old *peo = sample->raw_data; + + p_state_change(peo->cpu_id, sample->time, peo->value); + return 0; +} +#endif /* SUPPORT_OLD_POWER_EVENTS */ + /* * After the last sample we need to wrap up the current C/P state * and close out each CPU for these. @@ -957,6 +979,17 @@ static int __cmd_timechart(const char *output_name) .sample = process_sample_event, .ordered_samples = true, }; + const struct perf_evsel_str_handler power_tracepoints[] = { + { "power:cpu_idle", process_sample_cpu_idle }, + { "power:cpu_frequency", process_sample_cpu_frequency }, + { "sched:sched_wakeup", process_sample_sched_wakeup }, + { "sched:sched_switch", process_sample_sched_switch }, +#ifdef SUPPORT_OLD_POWER_EVENTS + { "power:power_start", process_sample_power_start }, + { "power:power_end", process_sample_power_end }, + { "power:power_frequency", process_sample_power_frequency }, +#endif + }; struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_timechart); int ret = -EINVAL; @@ -967,6 +1000,12 @@ static int __cmd_timechart(const char *output_name) if (!perf_session__has_traces(session, "timechart record")) goto out_delete; + if (perf_session__set_tracepoints_handlers(session, + power_tracepoints)) { + pr_err("Initializing session tracepoint handlers failed\n"); + goto out_delete; + } + ret = perf_session__process_events(session, &perf_timechart); if (ret) goto out_delete; From 44b3c57802b7557d0e2d8c3bd39bce942e9324cc Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 11 Jul 2013 17:28:31 +0200 Subject: [PATCH 0361/6183] perf tools: Remove event types from perf data file Removing event types data storing/reading to/from perf data file as it's no longer needed. The only user of this data 'perf timechart' was switched to use tracepoints handler callbacks. The event_types offset and size stay in the perf data file header but are ignored from now on. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1373556513-3000-4-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 28 +--------------------------- tools/perf/util/header.h | 3 +-- 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d12d79cf8d32..88626678bfc4 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2334,16 +2334,6 @@ int perf_session__write_header(struct perf_session *session, } } - header->event_offset = lseek(fd, 0, SEEK_CUR); - header->event_size = trace_event_count * sizeof(struct perf_trace_event_type); - if (trace_events) { - err = do_write(fd, trace_events, header->event_size); - if (err < 0) { - pr_debug("failed to write perf header events\n"); - return err; - } - } - header->data_offset = lseek(fd, 0, SEEK_CUR); if (at_exit) { @@ -2364,10 +2354,7 @@ int perf_session__write_header(struct perf_session *session, .offset = header->data_offset, .size = header->data_size, }, - .event_types = { - .offset = header->event_offset, - .size = header->event_size, - }, + /* event_types is ignored, store zeros */ }; memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); @@ -2614,8 +2601,6 @@ int perf_file_header__read(struct perf_file_header *header, memcpy(&ph->adds_features, &header->adds_features, sizeof(ph->adds_features)); - ph->event_offset = header->event_types.offset; - ph->event_size = header->event_types.size; ph->data_offset = header->data.offset; ph->data_size = header->data.size; return 0; @@ -2839,17 +2824,6 @@ int perf_session__read_header(struct perf_session *session, int fd) symbol_conf.nr_events = nr_attrs; - if (f_header.event_types.size) { - lseek(fd, f_header.event_types.offset, SEEK_SET); - trace_events = malloc(f_header.event_types.size); - if (trace_events == NULL) - return -ENOMEM; - if (perf_header__getbuffer64(header, fd, trace_events, - f_header.event_types.size)) - goto out_errno; - trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); - } - perf_header__process_sections(header, fd, &session->pevent, perf_file_section__process); diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 2d1ca7d3ca9c..298982fb195b 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -45,6 +45,7 @@ struct perf_file_header { u64 attr_size; struct perf_file_section attrs; struct perf_file_section data; + /* event_types is ignored */ struct perf_file_section event_types; DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); }; @@ -88,8 +89,6 @@ struct perf_header { s64 attr_offset; u64 data_offset; u64 data_size; - u64 event_offset; - u64 event_size; DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); struct perf_session_env env; }; From 30d350795e8e57c17eabaab454932889f1ae8159 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 11 Jul 2013 17:28:32 +0200 Subject: [PATCH 0362/6183] perf record: Remove event types pushing Removing event types data pushing from record command. It's no longer needed, because this data is ignored. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1373556513-3000-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ecca62e27b28..1f5243c1c477 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -904,7 +904,6 @@ const struct option record_options[] = { int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) { int err = -ENOMEM; - struct perf_evsel *pos; struct perf_evlist *evsel_list; struct perf_record *rec = &record; char errbuf[BUFSIZ]; @@ -968,11 +967,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) usage_with_options(record_usage, record_options); - list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos))) - goto out_free_fd; - } - if (rec->opts.user_interval != ULLONG_MAX) rec->opts.default_interval = rec->opts.user_interval; if (rec->opts.user_freq != UINT_MAX) From 6065210db932fd183cbc8bc77558fee275360e71 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 11 Jul 2013 17:28:33 +0200 Subject: [PATCH 0363/6183] perf tools: Remove event types framework completely Removing event types framework completely. The only remainder (apart from few comments) is following enum: enum perf_user_event_type { ... PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */ ... } It's kept as deprecated, resulting in error when processed in perf_session__process_user_event function. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1373556513-3000-6-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 7 --- tools/perf/builtin-record.c | 7 --- tools/perf/builtin-report.c | 1 - tools/perf/builtin-script.c | 1 - tools/perf/util/event.h | 2 +- tools/perf/util/header.c | 90 ------------------------------------- tools/perf/util/header.h | 13 ------ tools/perf/util/session.c | 11 ----- tools/perf/util/tool.h | 3 -- 9 files changed, 1 insertion(+), 134 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index ad1296c6f88c..1d8de2e4a407 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -67,12 +67,6 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool, return perf_event__repipe_synth(tool, event); } -static int perf_event__repipe_event_type_synth(struct perf_tool *tool, - union perf_event *event) -{ - return perf_event__repipe_synth(tool, event); -} - static int perf_event__repipe_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist) @@ -402,7 +396,6 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, .attr = perf_event__repipe_attr, - .event_type = perf_event__repipe_event_type_synth, .tracing_data = perf_event__repipe_op2_synth, .finished_round = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth, diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1f5243c1c477..a41ac41546c9 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) goto out_delete_session; } - err = perf_event__synthesize_event_types(tool, process_synthesized_event, - machine); - if (err < 0) { - pr_err("Couldn't synthesize event_types.\n"); - goto out_delete_session; - } - if (have_tracepoints(&evsel_list->entries)) { /* * FIXME err <= 0 here actually means that diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 188c265751c8..a34c587900c7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -741,7 +741,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) .lost = perf_event__process_lost, .read = process_read_event, .attr = perf_event__process_attr, - .event_type = perf_event__process_event_type, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, .ordered_samples = true, diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3de8979fe87d..ecb697998d3b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -524,7 +524,6 @@ static struct perf_tool perf_script = { .exit = perf_event__process_exit, .fork = perf_event__process_fork, .attr = perf_event__process_attr, - .event_type = perf_event__process_event_type, .tracing_data = perf_event__process_tracing_data, .build_id = perf_event__process_build_id, .ordered_samples = true, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 181389535c0c..1ebb8fb0178c 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -116,7 +116,7 @@ struct build_id_event { enum perf_user_event_type { /* above any possible kernel type */ PERF_RECORD_USER_TYPE_START = 64, PERF_RECORD_HEADER_ATTR = 64, - PERF_RECORD_HEADER_EVENT_TYPE = 65, + PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */ PERF_RECORD_HEADER_TRACING_DATA = 66, PERF_RECORD_HEADER_BUILD_ID = 67, PERF_RECORD_FINISHED_ROUND = 68, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 88626678bfc4..b28a65ecd61b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -25,41 +25,9 @@ static bool no_buildid_cache = false; -static int trace_event_count; -static struct perf_trace_event_type *trace_events; - static u32 header_argc; static const char **header_argv; -int perf_header__push_event(u64 id, const char *name) -{ - struct perf_trace_event_type *nevents; - - if (strlen(name) > MAX_EVENT_NAME) - pr_warning("Event %s will be truncated\n", name); - - nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events)); - if (nevents == NULL) - return -ENOMEM; - trace_events = nevents; - - memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type)); - trace_events[trace_event_count].event_id = id; - strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1); - trace_event_count++; - return 0; -} - -char *perf_header__find_event(u64 id) -{ - int i; - for (i = 0 ; i < trace_event_count; i++) { - if (trace_events[i].event_id == id) - return trace_events[i].name; - } - return NULL; -} - /* * magic2 = "PERFILE2" * must be a numerical value to let the endianness @@ -2936,64 +2904,6 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, return 0; } -int perf_event__synthesize_event_type(struct perf_tool *tool, - u64 event_id, char *name, - perf_event__handler_t process, - struct machine *machine) -{ - union perf_event ev; - size_t size = 0; - int err = 0; - - memset(&ev, 0, sizeof(ev)); - - ev.event_type.event_type.event_id = event_id; - memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME); - strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); - - ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; - size = strlen(ev.event_type.event_type.name); - size = PERF_ALIGN(size, sizeof(u64)); - ev.event_type.header.size = sizeof(ev.event_type) - - (sizeof(ev.event_type.event_type.name) - size); - - err = process(tool, &ev, NULL, machine); - - return err; -} - -int perf_event__synthesize_event_types(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) -{ - struct perf_trace_event_type *type; - int i, err = 0; - - for (i = 0; i < trace_event_count; i++) { - type = &trace_events[i]; - - err = perf_event__synthesize_event_type(tool, type->event_id, - type->name, process, - machine); - if (err) { - pr_debug("failed to create perf header event type\n"); - return err; - } - } - - return err; -} - -int perf_event__process_event_type(struct perf_tool *tool __maybe_unused, - union perf_event *event) -{ - if (perf_header__push_event(event->event_type.event_type.event_id, - event->event_type.event_type.name) < 0) - return -ENOMEM; - - return 0; -} - int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 298982fb195b..669fda531da6 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -102,9 +102,6 @@ int perf_session__write_header(struct perf_session *session, int fd, bool at_exit); int perf_header__write_pipe(int fd); -int perf_header__push_event(u64 id, const char *name); -char *perf_header__find_event(u64 id); - void perf_header__set_feat(struct perf_header *header, int feat); void perf_header__clear_feat(struct perf_header *header, int feat); bool perf_header__has_feat(const struct perf_header *header, int feat); @@ -132,16 +129,6 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); -int perf_event__synthesize_event_type(struct perf_tool *tool, - u64 event_id, char *name, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_event_types(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); -int perf_event__process_event_type(struct perf_tool *tool, - union perf_event *event); - int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct perf_evlist *evlist, perf_event__handler_t process); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1eb58eedcac1..d0d9f946a1b1 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -241,13 +241,6 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, return 0; } -static int process_event_type_stub(struct perf_tool *tool __maybe_unused, - union perf_event *event __maybe_unused) -{ - dump_printf(": unhandled!\n"); - return 0; -} - static int process_finished_round(struct perf_tool *tool, union perf_event *event, struct perf_session *session); @@ -274,8 +267,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool) tool->unthrottle = process_event_stub; if (tool->attr == NULL) tool->attr = process_event_synth_attr_stub; - if (tool->event_type == NULL) - tool->event_type = process_event_type_stub; if (tool->tracing_data == NULL) tool->tracing_data = process_event_synth_tracing_data_stub; if (tool->build_id == NULL) @@ -928,8 +919,6 @@ static int perf_session__process_user_event(struct perf_session *session, union if (err == 0) perf_session__set_id_hdr_size(session); return err; - case PERF_RECORD_HEADER_EVENT_TYPE: - return tool->event_type(tool, event); case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(session->fd, file_offset, SEEK_SET); diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 88f8cbdb8a34..62b16b6165ba 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -22,8 +22,6 @@ typedef int (*event_attr_op)(struct perf_tool *tool, union perf_event *event, struct perf_evlist **pevlist); -typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event); - typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, struct perf_session *session); @@ -39,7 +37,6 @@ struct perf_tool { unthrottle; event_attr_op attr; event_op2 tracing_data; - event_simple_op event_type; event_op2 finished_round, build_id; bool ordered_samples; From bcfed2a8a61a0f6ee7769f5093a8279a9e50c526 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 6 Jun 2013 17:38:11 +0200 Subject: [PATCH 0364/6183] ARM: shmobile: armadillo800eva: remove left-overs A comment and a #define in board-armadillo800eva.c have been left over after recent changes and are no longer relevant or needed, remove them. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-armadillo800eva.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e115f6742107..66cfd5686578 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -679,15 +679,6 @@ static struct platform_device vcc_sdhi1 = { }; /* SDHI0 */ -/* - * FIXME - * - * It use polling mode here, since - * CD (= Card Detect) pin is not connected to SDHI0_CD. - * We can use IRQ31 as card detect irq, - * but it needs chattering removal operation - */ -#define IRQ31 irq_pin(31) static struct sh_mobile_sdhi_info sdhi0_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, From 0f5615117b812ce171469bd7e5d00037aaab4845 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 16 Jul 2013 12:18:19 +0900 Subject: [PATCH 0365/6183] irqchip: exynos: cleanup non-DT stuff in exynos-combiner For EXYNOS SoCs, only can support for DT so removes non-DT stuff in exynos-combiner. Cc: Thomas Gleixner Signed-off-by: Kukjin Kim --- drivers/irqchip/exynos-combiner.c | 44 +------------------------------ 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 4c6826513901..868ed40cb6bf 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -19,10 +19,6 @@ #include #include -#ifdef CONFIG_EXYNOS_ATAGS -#include -#endif - #include "irqchip.h" #define COMBINER_ENABLE_SET 0x0 @@ -138,7 +134,6 @@ static void __init combiner_init_one(struct combiner_chip_data *combiner_data, __raw_writel(combiner_data->irq_mask, base + COMBINER_ENABLE_CLEAR); } -#ifdef CONFIG_OF static int combiner_irq_domain_xlate(struct irq_domain *d, struct device_node *controller, const u32 *intspec, unsigned int intsize, @@ -156,16 +151,6 @@ static int combiner_irq_domain_xlate(struct irq_domain *d, return 0; } -#else -static int combiner_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) -{ - return -EINVAL; -} -#endif static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) @@ -184,26 +169,6 @@ static struct irq_domain_ops combiner_irq_domain_ops = { .map = combiner_irq_domain_map, }; -static unsigned int combiner_lookup_irq(int group) -{ -#ifdef CONFIG_EXYNOS_ATAGS - if (group < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250()) - return IRQ_SPI(group); - - switch (group) { - case 16: - return IRQ_SPI(107); - case 17: - return IRQ_SPI(108); - case 18: - return IRQ_SPI(48); - case 19: - return IRQ_SPI(42); - } -#endif - return 0; -} - static void __init combiner_init(void __iomem *combiner_base, struct device_node *np, unsigned int max_nr, @@ -229,12 +194,7 @@ static void __init combiner_init(void __iomem *combiner_base, } for (i = 0; i < max_nr; i++) { -#ifdef CONFIG_OF - if (np) - irq = irq_of_parse_and_map(np, i); - else -#endif - irq = combiner_lookup_irq(i); + irq = irq_of_parse_and_map(np, i); combiner_init_one(&combiner_data[i], i, combiner_base + (i >> 2) * 0x10, irq); @@ -242,7 +202,6 @@ static void __init combiner_init(void __iomem *combiner_base, } } -#ifdef CONFIG_OF static int __init combiner_of_init(struct device_node *np, struct device_node *parent) { @@ -275,4 +234,3 @@ static int __init combiner_of_init(struct device_node *np, } IRQCHIP_DECLARE(exynos4210_combiner, "samsung,exynos4210-combiner", combiner_of_init); -#endif From 8b770e3c9824c98eafe67950ad6e41e09ec9c98a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 4 Jul 2013 21:13:24 +0200 Subject: [PATCH 0366/6183] backlight: Add GPIO-based backlight driver The GPIO backlight driver controls the backlight in on/off mode through a single GPIO. Signed-off-by: Laurent Pinchart Acked-by: Jingoo Han Signed-off-by: Simon Horman --- drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/gpio_backlight.c | 133 +++++++++++++++++++ include/linux/platform_data/gpio_backlight.h | 21 +++ 4 files changed, 162 insertions(+) create mode 100644 drivers/video/backlight/gpio_backlight.c create mode 100644 include/linux/platform_data/gpio_backlight.h diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index d5ab6583f440..5ab64237c972 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -425,6 +425,13 @@ config BACKLIGHT_AS3711 If you have an Austrian Microsystems AS3711 say Y to enable the backlight driver. +config BACKLIGHT_GPIO + tristate "Generic GPIO based Backlight Driver" + depends on GPIOLIB + help + If you have a LCD backlight adjustable by GPIO, say Y to enable + this driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 92711fe60464..65698a882c2f 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o +obj-$(CONFIG_BACKLIGHT_GPIO) += gpio_backlight.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c new file mode 100644 index 000000000000..5fa217f9f445 --- /dev/null +++ b/drivers/video/backlight/gpio_backlight.c @@ -0,0 +1,133 @@ +/* + * gpio_backlight.c - Simple GPIO-controlled backlight + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct gpio_backlight { + struct device *dev; + struct device *fbdev; + + int gpio; + int active; +}; + +static int gpio_backlight_update_status(struct backlight_device *bl) +{ + struct gpio_backlight *gbl = bl_get_data(bl); + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + gpio_set_value(gbl->gpio, brightness ? gbl->active : !gbl->active); + + return 0; +} + +static int gpio_backlight_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static int gpio_backlight_check_fb(struct backlight_device *bl, + struct fb_info *info) +{ + struct gpio_backlight *gbl = bl_get_data(bl); + + return gbl->fbdev == NULL || gbl->fbdev == info->dev; +} + +static const struct backlight_ops gpio_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = gpio_backlight_update_status, + .get_brightness = gpio_backlight_get_brightness, + .check_fb = gpio_backlight_check_fb, +}; + +static int gpio_backlight_probe(struct platform_device *pdev) +{ + struct gpio_backlight_platform_data *pdata = pdev->dev.platform_data; + struct backlight_properties props; + struct backlight_device *bl; + struct gpio_backlight *gbl; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "failed to find platform data\n"); + return -ENODEV; + } + + gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL); + if (gbl == NULL) + return -ENOMEM; + + gbl->dev = &pdev->dev; + gbl->fbdev = pdata->fbdev; + gbl->gpio = pdata->gpio; + gbl->active = pdata->active_low ? 0 : 1; + + ret = devm_gpio_request_one(gbl->dev, gbl->gpio, GPIOF_DIR_OUT | + (gbl->active ? GPIOF_INIT_LOW + : GPIOF_INIT_HIGH), + pdata->name); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request GPIO\n"); + return ret; + } + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 1; + bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, gbl, + &gpio_backlight_ops, &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } + + bl->props.brightness = pdata->def_value; + backlight_update_status(bl); + + platform_set_drvdata(pdev, bl); + return 0; +} + +static int gpio_backlight_remove(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + + backlight_device_unregister(bl); + return 0; +} + +static struct platform_driver gpio_backlight_driver = { + .driver = { + .name = "gpio-backlight", + .owner = THIS_MODULE, + }, + .probe = gpio_backlight_probe, + .remove = gpio_backlight_remove, +}; + +module_platform_driver(gpio_backlight_driver); + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("GPIO-based Backlight Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-backlight"); diff --git a/include/linux/platform_data/gpio_backlight.h b/include/linux/platform_data/gpio_backlight.h new file mode 100644 index 000000000000..5ae0d9c80d4d --- /dev/null +++ b/include/linux/platform_data/gpio_backlight.h @@ -0,0 +1,21 @@ +/* + * gpio_backlight.h - Simple GPIO-controlled backlight + * + * 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. + */ +#ifndef __GPIO_BACKLIGHT_H__ +#define __GPIO_BACKLIGHT_H__ + +struct device; + +struct gpio_backlight_platform_data { + struct device *fbdev; + int gpio; + int def_value; + bool active_low; + const char *name; +}; + +#endif From 82e5c40d88f928afffe7bd4027719d3184433908 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 4 Jul 2013 21:13:25 +0200 Subject: [PATCH 0367/6183] backlight: Add Sanyo LV5207LP backlight driver The LV5207LP is a multi-purpose 7 LEDs driver for the mobile market. Only the main LED is supported by this driver. Signed-off-by: Laurent Pinchart Acked-by: Jingoo Han Signed-off-by: Simon Horman --- drivers/video/backlight/Kconfig | 6 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/lv5207lp.c | 171 +++++++++++++++++++++++++ include/linux/platform_data/lv5207lp.h | 19 +++ 4 files changed, 197 insertions(+) create mode 100644 drivers/video/backlight/lv5207lp.c create mode 100644 include/linux/platform_data/lv5207lp.h diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 5ab64237c972..b304e075cf3a 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -432,6 +432,12 @@ config BACKLIGHT_GPIO If you have a LCD backlight adjustable by GPIO, say Y to enable this driver. +config BACKLIGHT_LV5207LP + tristate "Sanyo LV5207LP Backlight" + depends on I2C + help + If you have a Sanyo LV5207LP say Y to enable the backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 65698a882c2f..4e5e8116c8c4 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o +obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o diff --git a/drivers/video/backlight/lv5207lp.c b/drivers/video/backlight/lv5207lp.c new file mode 100644 index 000000000000..498fd73d59b9 --- /dev/null +++ b/drivers/video/backlight/lv5207lp.c @@ -0,0 +1,171 @@ +/* + * Sanyo LV5207LP LED Driver + * + * Copyright (C) 2013 Ideas on board SPRL + * + * Contact: Laurent Pinchart + * + * 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 +#include +#include +#include +#include +#include +#include + +#define LV5207LP_CTRL1 0x00 +#define LV5207LP_CPSW (1 << 7) +#define LV5207LP_SCTEN (1 << 6) +#define LV5207LP_C10 (1 << 5) +#define LV5207LP_CKSW (1 << 4) +#define LV5207LP_RSW (1 << 3) +#define LV5207LP_GSW (1 << 2) +#define LV5207LP_BSW (1 << 1) +#define LV5207LP_CTRL2 0x01 +#define LV5207LP_MSW (1 << 7) +#define LV5207LP_MLED4 (1 << 6) +#define LV5207LP_RED 0x02 +#define LV5207LP_GREEN 0x03 +#define LV5207LP_BLUE 0x04 + +#define LV5207LP_MAX_BRIGHTNESS 32 + +struct lv5207lp { + struct i2c_client *client; + struct backlight_device *backlight; + struct lv5207lp_platform_data *pdata; +}; + +static int lv5207lp_write(struct lv5207lp *lv, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(lv->client, reg, data); +} + +static int lv5207lp_backlight_update_status(struct backlight_device *backlight) +{ + struct lv5207lp *lv = bl_get_data(backlight); + int brightness = backlight->props.brightness; + + if (backlight->props.power != FB_BLANK_UNBLANK || + backlight->props.fb_blank != FB_BLANK_UNBLANK || + backlight->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + if (brightness) { + lv5207lp_write(lv, LV5207LP_CTRL1, + LV5207LP_CPSW | LV5207LP_C10 | LV5207LP_CKSW); + lv5207lp_write(lv, LV5207LP_CTRL2, + LV5207LP_MSW | LV5207LP_MLED4 | + (brightness - 1)); + } else { + lv5207lp_write(lv, LV5207LP_CTRL1, 0); + lv5207lp_write(lv, LV5207LP_CTRL2, 0); + } + + return 0; +} + +static int lv5207lp_backlight_get_brightness(struct backlight_device *backlight) +{ + return backlight->props.brightness; +} + +static int lv5207lp_backlight_check_fb(struct backlight_device *backlight, + struct fb_info *info) +{ + struct lv5207lp *lv = bl_get_data(backlight); + + return lv->pdata->fbdev == NULL || lv->pdata->fbdev == info->dev; +} + +static const struct backlight_ops lv5207lp_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lv5207lp_backlight_update_status, + .get_brightness = lv5207lp_backlight_get_brightness, + .check_fb = lv5207lp_backlight_check_fb, +}; + +static int lv5207lp_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lv5207lp_platform_data *pdata = client->dev.platform_data; + struct backlight_device *backlight; + struct backlight_properties props; + struct lv5207lp *lv; + + if (pdata == NULL) { + dev_err(&client->dev, "No platform data supplied\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&client->dev, + "I2C adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + lv = devm_kzalloc(&client->dev, sizeof(*lv), GFP_KERNEL); + if (!lv) + return -ENOMEM; + + lv->client = client; + lv->pdata = pdata; + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = min_t(unsigned int, pdata->max_value, + LV5207LP_MAX_BRIGHTNESS); + props.brightness = clamp_t(unsigned int, pdata->def_value, 0, + props.max_brightness); + + backlight = backlight_device_register(dev_name(&client->dev), + &lv->client->dev, lv, + &lv5207lp_backlight_ops, &props); + if (IS_ERR(backlight)) { + dev_err(&client->dev, "failed to register backlight\n"); + return PTR_ERR(backlight); + } + + backlight_update_status(backlight); + i2c_set_clientdata(client, backlight); + + return 0; +} + +static int lv5207lp_remove(struct i2c_client *client) +{ + struct backlight_device *backlight = i2c_get_clientdata(client); + + backlight->props.brightness = 0; + backlight_update_status(backlight); + backlight_device_unregister(backlight); + + return 0; +} + +static const struct i2c_device_id lv5207lp_ids[] = { + { "lv5207lp", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lv5207lp_ids); + +static struct i2c_driver lv5207lp_driver = { + .driver = { + .name = "lv5207lp", + }, + .probe = lv5207lp_probe, + .remove = lv5207lp_remove, + .id_table = lv5207lp_ids, +}; + +module_i2c_driver(lv5207lp_driver); + +MODULE_DESCRIPTION("Sanyo LV5207LP Backlight Driver"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/lv5207lp.h b/include/linux/platform_data/lv5207lp.h new file mode 100644 index 000000000000..7dc4d9a219a6 --- /dev/null +++ b/include/linux/platform_data/lv5207lp.h @@ -0,0 +1,19 @@ +/* + * lv5207lp.h - Sanyo LV5207LP LEDs Driver + * + * 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. + */ +#ifndef __LV5207LP_H__ +#define __LV5207LP_H__ + +struct device; + +struct lv5207lp_platform_data { + struct device *fbdev; + unsigned int max_value; + unsigned int def_value; +}; + +#endif From 67b43e590415866649e5ba8a6421bb84ecb74f72 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 4 Jul 2013 21:13:26 +0200 Subject: [PATCH 0368/6183] backlight: Add ROHM BD6107 backlight driver The BD6107 is a multi-purpose 10 channels LED driver for the mobile market. Only the main channel is supported by this driver. Signed-off-by: Laurent Pinchart Acked-by: Jingoo Han Signed-off-by: Simon Horman --- drivers/video/backlight/Kconfig | 6 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/bd6107.c | 213 +++++++++++++++++++++++++++ include/linux/platform_data/bd6107.h | 19 +++ 4 files changed, 239 insertions(+) create mode 100644 drivers/video/backlight/bd6107.c create mode 100644 include/linux/platform_data/bd6107.h diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index b304e075cf3a..d4a7a351d67c 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -438,6 +438,12 @@ config BACKLIGHT_LV5207LP help If you have a Sanyo LV5207LP say Y to enable the backlight driver. +config BACKLIGHT_BD6107 + tristate "Rohm BD6107 Backlight" + depends on I2C + help + If you have a Rohm BD6107 say Y to enable the backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 4e5e8116c8c4..38e1babb1946 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o +obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c new file mode 100644 index 000000000000..15e3294b29fe --- /dev/null +++ b/drivers/video/backlight/bd6107.c @@ -0,0 +1,213 @@ +/* + * ROHM Semiconductor BD6107 LED Driver + * + * Copyright (C) 2013 Ideas on board SPRL + * + * Contact: Laurent Pinchart + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define BD6107_PSCNT1 0x00 +#define BD6107_PSCNT1_PSCNTREG2 (1 << 2) +#define BD6107_PSCNT1_PSCNTREG1 (1 << 0) +#define BD6107_REGVSET 0x02 +#define BD6107_REGVSET_REG1VSET_2_85V (1 << 2) +#define BD6107_REGVSET_REG1VSET_2_80V (0 << 2) +#define BD6107_LEDCNT1 0x03 +#define BD6107_LEDCNT1_LEDONOFF2 (1 << 1) +#define BD6107_LEDCNT1_LEDONOFF1 (1 << 0) +#define BD6107_PORTSEL 0x04 +#define BD6107_PORTSEL_LEDM(n) (1 << (n)) +#define BD6107_RGB1CNT1 0x05 +#define BD6107_RGB1CNT2 0x06 +#define BD6107_RGB1CNT3 0x07 +#define BD6107_RGB1CNT4 0x08 +#define BD6107_RGB1CNT5 0x09 +#define BD6107_RGB1FLM 0x0a +#define BD6107_RGB2CNT1 0x0b +#define BD6107_RGB2CNT2 0x0c +#define BD6107_RGB2CNT3 0x0d +#define BD6107_RGB2CNT4 0x0e +#define BD6107_RGB2CNT5 0x0f +#define BD6107_RGB2FLM 0x10 +#define BD6107_PSCONT3 0x11 +#define BD6107_SMMONCNT 0x12 +#define BD6107_DCDCCNT 0x13 +#define BD6107_IOSEL 0x14 +#define BD6107_OUT1 0x15 +#define BD6107_OUT2 0x16 +#define BD6107_MASK1 0x17 +#define BD6107_MASK2 0x18 +#define BD6107_FACTOR1 0x19 +#define BD6107_FACTOR2 0x1a +#define BD6107_CLRFACT1 0x1b +#define BD6107_CLRFACT2 0x1c +#define BD6107_STATE1 0x1d +#define BD6107_LSIVER 0x1e +#define BD6107_GRPSEL 0x1f +#define BD6107_LEDCNT2 0x20 +#define BD6107_LEDCNT3 0x21 +#define BD6107_MCURRENT 0x22 +#define BD6107_MAINCNT1 0x23 +#define BD6107_MAINCNT2 0x24 +#define BD6107_SLOPECNT 0x25 +#define BD6107_MSLOPE 0x26 +#define BD6107_RGBSLOPE 0x27 +#define BD6107_TEST 0x29 +#define BD6107_SFTRST 0x2a +#define BD6107_SFTRSTGD 0x2b + +struct bd6107 { + struct i2c_client *client; + struct backlight_device *backlight; + struct bd6107_platform_data *pdata; +}; + +static int bd6107_write(struct bd6107 *bd, u8 reg, u8 data) +{ + return i2c_smbus_write_byte_data(bd->client, reg, data); +} + +static int bd6107_backlight_update_status(struct backlight_device *backlight) +{ + struct bd6107 *bd = bl_get_data(backlight); + int brightness = backlight->props.brightness; + + if (backlight->props.power != FB_BLANK_UNBLANK || + backlight->props.fb_blank != FB_BLANK_UNBLANK || + backlight->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + if (brightness) { + bd6107_write(bd, BD6107_PORTSEL, BD6107_PORTSEL_LEDM(2) | + BD6107_PORTSEL_LEDM(1) | BD6107_PORTSEL_LEDM(0)); + bd6107_write(bd, BD6107_MAINCNT1, brightness); + bd6107_write(bd, BD6107_LEDCNT1, BD6107_LEDCNT1_LEDONOFF1); + } else { + gpio_set_value(bd->pdata->reset, 0); + msleep(24); + gpio_set_value(bd->pdata->reset, 1); + } + + return 0; +} + +static int bd6107_backlight_get_brightness(struct backlight_device *backlight) +{ + return backlight->props.brightness; +} + +static int bd6107_backlight_check_fb(struct backlight_device *backlight, + struct fb_info *info) +{ + struct bd6107 *bd = bl_get_data(backlight); + + return bd->pdata->fbdev == NULL || bd->pdata->fbdev == info->dev; +} + +static const struct backlight_ops bd6107_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = bd6107_backlight_update_status, + .get_brightness = bd6107_backlight_get_brightness, + .check_fb = bd6107_backlight_check_fb, +}; + +static int bd6107_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bd6107_platform_data *pdata = client->dev.platform_data; + struct backlight_device *backlight; + struct backlight_properties props; + struct bd6107 *bd; + int ret; + + if (pdata == NULL || !pdata->reset) { + dev_err(&client->dev, "No reset GPIO in platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_warn(&client->dev, + "I2C adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); + return -EIO; + } + + bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL); + if (!bd) + return -ENOMEM; + + bd->client = client; + bd->pdata = pdata; + + ret = devm_gpio_request_one(&client->dev, pdata->reset, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, "reset"); + if (ret < 0) { + dev_err(&client->dev, "unable to request reset GPIO\n"); + return ret; + } + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 128; + props.brightness = clamp_t(unsigned int, pdata->def_value, 0, + props.max_brightness); + + backlight = backlight_device_register(dev_name(&client->dev), + &bd->client->dev, bd, + &bd6107_backlight_ops, &props); + if (IS_ERR(backlight)) { + dev_err(&client->dev, "failed to register backlight\n"); + return PTR_ERR(backlight); + } + + backlight_update_status(backlight); + i2c_set_clientdata(client, backlight); + + return 0; +} + +static int bd6107_remove(struct i2c_client *client) +{ + struct backlight_device *backlight = i2c_get_clientdata(client); + + backlight->props.brightness = 0; + backlight_update_status(backlight); + backlight_device_unregister(backlight); + + return 0; +} + +static const struct i2c_device_id bd6107_ids[] = { + { "bd6107", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bd6107_ids); + +static struct i2c_driver bd6107_driver = { + .driver = { + .name = "bd6107", + }, + .probe = bd6107_probe, + .remove = bd6107_remove, + .id_table = bd6107_ids, +}; + +module_i2c_driver(bd6107_driver); + +MODULE_DESCRIPTION("Rohm BD6107 Backlight Driver"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/bd6107.h b/include/linux/platform_data/bd6107.h new file mode 100644 index 000000000000..671d6502d241 --- /dev/null +++ b/include/linux/platform_data/bd6107.h @@ -0,0 +1,19 @@ +/* + * bd6107.h - Rohm BD6107 LEDs Driver + * + * 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. + */ +#ifndef __BD6107_H__ +#define __BD6107_H__ + +struct device; + +struct bd6107_platform_data { + struct device *fbdev; + int reset; /* Reset GPIO */ + unsigned int def_value; +}; + +#endif From 0d8ff15e9a15f2b393e53337a107b7a1e5919b6d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 4 Jul 2013 11:02:03 -0700 Subject: [PATCH 0369/6183] drm/i915/hsw: Set correct Haswell PTE encodings. The cacheability controls have changed, and the bits have been rearranged in general. Note that age 0 is the oldest (most likely to get evicted) and age 3 is the youngest (most likely to stick around for a bit). We've picked 0 for no reason, but atm it shouldn't matter anyway (since we don't yet try to differentiate between different objects). v2: Remove comments for snb/ivb cache leves, that's a separate change. v3: Resolve conflicts due to patch series reordering. v4: Rebased on top of Kenneth Graunke's ->pte_encode refactoring. v5: Removed eLLC bits for separate patch. In the internal repository this was: Signed-off-by: Ben Widawsky Signed-off-by: Kenneth Graunke Reviewed-by: Damien Lespiau [danvet: Add comment about cache ages as requested by Ben provoked due to a question from Damien.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 242d0f9bb9e4..5534dd5cea58 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -33,6 +33,7 @@ /* PPGTT stuff */ #define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) +#define HSW_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0x7f0)) #define GEN6_PDE_VALID (1 << 0) /* gen6+ has bit 11-4 for physical addr bit 39-32 */ @@ -44,6 +45,14 @@ #define GEN6_PTE_CACHE_LLC (2 << 1) #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) +#define HSW_PTE_ADDR_ENCODE(addr) HSW_GTT_ADDR_ENCODE(addr) + +/* Cacheability Control is a 4-bit value. The low three bits are stored in * + * bits 3:1 of the PTE, while the fourth bit is stored in bit 11 of the PTE. + */ +#define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \ + (((bits) & 0x8) << (11 - 3))) +#define HSW_WB_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x3) static gen6_gtt_pte_t gen6_pte_encode(dma_addr_t addr, enum i915_cache_level level) @@ -92,10 +101,10 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr, enum i915_cache_level level) { gen6_gtt_pte_t pte = GEN6_PTE_VALID; - pte |= GEN6_PTE_ADDR_ENCODE(addr); + pte |= HSW_PTE_ADDR_ENCODE(addr); if (level != I915_CACHE_NONE) - pte |= GEN6_PTE_CACHE_LLC; + pte |= HSW_WB_LLC_AGE0; return pte; } From 05e21cc43da5a1a58b34a2cfad13d22bcfeb1f2b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 4 Jul 2013 11:02:04 -0700 Subject: [PATCH 0370/6183] drm/i915: Define some of the eLLC magic The EDRAM present register isn't really defined in the docs. It just says check to see if it's set to 1. So I haven't defined the 1 value not knowing what it actually means. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 20b10a0fa452..1246dfd5ff92 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4147,8 +4147,8 @@ i915_gem_init_hw(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) return -EIO; - if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) - I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); + if (IS_HASWELL(dev) && (I915_READ(HSW_EDRAM_PRESENT) == 1)) + I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf)); if (HAS_PCH_NOP(dev)) { u32 temp = I915_READ(GEN7_MSG_CTL); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dc3d6a74f391..5e58a44c5fe3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4472,6 +4472,10 @@ #define GT_FIFO_FREE_ENTRIES 0x120008 #define GT_FIFO_NUM_RESERVED_ENTRIES 20 +#define HSW_IDICR 0x9008 +#define IDIHASHMSK(x) (((x) & 0x3f) << 16) +#define HSW_EDRAM_PRESENT 0x120010 + #define GEN6_UCGCTL1 0x9400 # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) # define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) From 59124506ba5297e48410e410c3bce83784fddf58 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 4 Jul 2013 11:02:05 -0700 Subject: [PATCH 0371/6183] drm/i915: store eLLC size The eLLC cannot be determined by PCIID because as far as we know, even machines supporting eLLC may not have it enabled, or fused off or whatever. It's possible this isn't actually true, and at that point we can switch to a DEV_INFO flag instead. I've defined everything where the docs are clear, and left the rest as magic. But we need it before we set the pte_encode function pointers, which happens really early, in gtt_init. The problem with just doing the normal sequence earlier is we don't have the ability to use forcewake until after the pte functions have been set up. Since all solutions are somewhat ugly (barring rewriting all the init ordering), I've opted to do the detection really early, and the enabling later - since the register to detect doesn't require forcewake. Signed-off-by: Ben Widawsky [danvet: Move dev_priv->ellc_size away from the dri1 dungeon to a nice place right next to the l3 parity stuff. Also squash in the follow-up commit to read out the eLLC size a bit earlier.] Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ++++++++++ drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem.c | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6ce903306320..a1d04b23e576 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1519,6 +1519,16 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_early_sanitize_regs(dev); + if (IS_HASWELL(dev) && (I915_READ(HSW_EDRAM_PRESENT) == 1)) { + /* The docs do not explain exactly how the calculation can be + * made. It is somewhat guessable, but for now, it's always + * 128MB. + * NB: We can't write IDICR yet because we do not have gt funcs + * set up */ + dev_priv->ellc_size = 128; + DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size); + } + ret = i915_gem_gtt_init(dev); if (ret) goto put_bridge; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 65d54edae176..5d4491e74871 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1151,6 +1151,9 @@ typedef struct drm_i915_private { struct intel_l3_parity l3_parity; + /* Cannot be determined by PCIID. You must always read a register. */ + size_t ellc_size; + /* gen6+ rps state */ struct intel_gen6_power_mgmt rps; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1246dfd5ff92..53c39bcf8e0e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4147,7 +4147,7 @@ i915_gem_init_hw(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) return -EIO; - if (IS_HASWELL(dev) && (I915_READ(HSW_EDRAM_PRESENT) == 1)) + if (dev_priv->ellc_size) I915_WRITE(HSW_IDICR, I915_READ(HSW_IDICR) | IDIHASHMSK(0xf)); if (HAS_PCH_NOP(dev)) { From 4d15c145a6234d999c0452eec0d275c1fbf0688c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 4 Jul 2013 11:02:06 -0700 Subject: [PATCH 0372/6183] drm/i915: Use eLLC/LLC by default when available DRI clients really should be using MOCS to get fine grained streaming cache controls. With that note, I *hope* that this patch doesn't improve performance overwhelmingly, because if it does - it means there is a problem elsewhere. In any case, the kernel, and old userspace should get some benefit from this, so let's do it. eLLC is always a good default, and really not using it is the special case for MOCS. References: http://www.intel.com/newsroom/kits/restricted/ha$well!/pdfs/4th_Gen_Intel_Core_PressBriefing_5-29.pdf (page 57) Signed-off-by: Ben Widawsky Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5534dd5cea58..422273328302 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -53,6 +53,7 @@ #define HSW_CACHEABILITY_CONTROL(bits) ((((bits) & 0x7) << 1) | \ (((bits) & 0x8) << (11 - 3))) #define HSW_WB_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x3) +#define HSW_WB_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0xb) static gen6_gtt_pte_t gen6_pte_encode(dma_addr_t addr, enum i915_cache_level level) @@ -109,6 +110,18 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr, return pte; } +static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr, + enum i915_cache_level level) +{ + gen6_gtt_pte_t pte = GEN6_PTE_VALID; + pte |= HSW_PTE_ADDR_ENCODE(addr); + + if (level != I915_CACHE_NONE) + pte |= HSW_WB_ELLC_LLC_AGE0; + + return pte; +} + static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = ppgtt->dev->dev_private; @@ -861,7 +874,9 @@ int i915_gem_gtt_init(struct drm_device *dev) } else { gtt->gtt_probe = gen6_gmch_probe; gtt->gtt_remove = gen6_gmch_remove; - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev) && dev_priv->ellc_size) + gtt->pte_encode = iris_pte_encode; + else if (IS_HASWELL(dev)) gtt->pte_encode = hsw_pte_encode; else if (IS_VALLEYVIEW(dev)) gtt->pte_encode = byt_pte_encode; From 63573eb7ba3d1bdc1db25fe79314609a4189a306 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 4 Jul 2013 11:02:07 -0700 Subject: [PATCH 0373/6183] drm/i915: debugfs entries for [e]LLC To make users life a little easier figuring out what they have on their system. Ideally, I'd really like to report LLC size, but it turned out to be a bit of a pain. Maybe I'll revisit it in the future. Signed-off-by: Ben Widawsky Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 86379799dab8..8819f851e996 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1530,6 +1530,19 @@ static int i915_dpio_info(struct seq_file *m, void *data) return 0; } +static int i915_llc(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Size calculation for LLC is a bit of a pain. Ignore for now. */ + seq_printf(m, "LLC: %s\n", yesno(HAS_LLC(dev))); + seq_printf(m, "eLLC: %zuMB\n", dev_priv->ellc_size); + + return 0; +} + static int i915_wedged_get(void *data, u64 *val) { @@ -1959,6 +1972,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_swizzle_info", i915_swizzle_info, 0}, {"i915_ppgtt_info", i915_ppgtt_info, 0}, {"i915_dpio", i915_dpio_info, 0}, + {"i915_llc", i915_llc, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) From d18ea1b58a5003eb6fca03aff03c4c01321e6cb1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Jul 2013 22:43:25 +0200 Subject: [PATCH 0374/6183] drm/i915: unify PM interrupt preinstall sequence Since the addition of VECS we have a slightly different enable sequence for PM interrupts on ivb/hsw vs snb and vlv. Usually that will end up in hard to track down surprises. Hence unifiy things and since we have copies of this code in 3 places now, extract it into its own little helper. Note that this changes the irq preinstall sequence a bit for snb and vlv: We now also clear the PM registers in the preinstall hook, in addition to the PM register clearing/setup already done when actually enabling rps. So this doesn't fix a bug but simply unifies the code across all platforms. After the postinstall hook is similarly unified we can rip out the then redundant PM interrupt setup from the rps code. v3: Rebase on top of the retained double-GTIIR clearing. Also resurrect the masking/disabling of the gen6+ PM interrupts as spotted by Ben Widaswky. v4: Move the DE interrupt reset code out of gen5_gt_irq_preinstall back to ironlake_irq_preinstall where it really belongs. Spotted by Paulo. v3: Improve the commit message to more clearly spell out why we want to unify the code and what exactly changes. Cc: Paulo Zanoni Reviewed-by: Ben Widawsky [danvet: s/GT/PM/ to fix up a comment which Ben spotted while reviewing.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 39 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 64db680fb7a4..0d54a550ec6d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2054,6 +2054,23 @@ static void ibx_irq_preinstall(struct drm_device *dev) POSTING_READ(SDEIER); } +static void gen5_gt_irq_preinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* and GT */ + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + POSTING_READ(GTIER); + + if (INTEL_INFO(dev)->gen >= 6) { + /* and PM */ + I915_WRITE(GEN6_PMIMR, 0xffffffff); + I915_WRITE(GEN6_PMIER, 0x0); + POSTING_READ(GEN6_PMIER); + } +} + /* drm_dma.h hooks */ static void ironlake_irq_preinstall(struct drm_device *dev) @@ -2064,16 +2081,11 @@ static void ironlake_irq_preinstall(struct drm_device *dev) I915_WRITE(HWSTAM, 0xeffe); - /* XXX hotplug from PCH */ - I915_WRITE(DEIMR, 0xffffffff); I915_WRITE(DEIER, 0x0); POSTING_READ(DEIER); - /* and GT */ - I915_WRITE(GTIMR, 0xffffffff); - I915_WRITE(GTIER, 0x0); - POSTING_READ(GTIER); + gen5_gt_irq_preinstall(dev); ibx_irq_preinstall(dev); } @@ -2092,15 +2104,7 @@ static void ivybridge_irq_preinstall(struct drm_device *dev) I915_WRITE(DEIER, 0x0); POSTING_READ(DEIER); - /* and GT */ - I915_WRITE(GTIMR, 0xffffffff); - I915_WRITE(GTIER, 0x0); - POSTING_READ(GTIER); - - /* Power management */ - I915_WRITE(GEN6_PMIMR, 0xffffffff); - I915_WRITE(GEN6_PMIER, 0x0); - POSTING_READ(GEN6_PMIER); + gen5_gt_irq_preinstall(dev); ibx_irq_preinstall(dev); } @@ -2121,9 +2125,8 @@ static void valleyview_irq_preinstall(struct drm_device *dev) /* and GT */ I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIMR, 0xffffffff); - I915_WRITE(GTIER, 0x0); - POSTING_READ(GTIER); + + gen5_gt_irq_preinstall(dev); I915_WRITE(DPINVGTT, 0xff); From dac30a9843f8a6007e9d25cad2b5735679041397 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 15 Jul 2013 15:43:32 +0530 Subject: [PATCH 0375/6183] drivers/rtc: Replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is now deprecated. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Sachin Kamat Signed-off-by: Rusty Russell --- drivers/rtc/rtc-da9052.c | 2 +- drivers/rtc/rtc-isl12022.c | 2 +- drivers/rtc/rtc-m48t35.c | 2 +- drivers/rtc/rtc-pcf8563.c | 2 +- drivers/rtc/rtc-pcf8583.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 9c8c19441cc6..4385ca4503da 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -250,7 +250,7 @@ static int da9052_rtc_probe(struct platform_device *pdev) rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &da9052_rtc_ops, THIS_MODULE); - return PTR_RET(rtc->rtc); + return PTR_ERR_OR_ZERO(rtc->rtc); } static struct platform_driver da9052_rtc_driver = { diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 5dbdc4405718..03b891129428 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -268,7 +268,7 @@ static int isl12022_probe(struct i2c_client *client, isl12022->rtc = devm_rtc_device_register(&client->dev, isl12022_driver.driver.name, &isl12022_rtc_ops, THIS_MODULE); - return PTR_RET(isl12022->rtc); + return PTR_ERR_OR_ZERO(isl12022->rtc); } static const struct i2c_device_id isl12022_id[] = { diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 23c3779a5f2b..411adb3f86a1 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -175,7 +175,7 @@ static int m48t35_probe(struct platform_device *pdev) priv->rtc = devm_rtc_device_register(&pdev->dev, "m48t35", &m48t35_ops, THIS_MODULE); - return PTR_RET(priv->rtc); + return PTR_ERR_OR_ZERO(priv->rtc); } static struct platform_driver m48t35_platform_driver = { diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 710c3a5aa6ff..63b558c48196 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -264,7 +264,7 @@ static int pcf8563_probe(struct i2c_client *client, pcf8563_driver.driver.name, &pcf8563_rtc_ops, THIS_MODULE); - return PTR_RET(pcf8563->rtc); + return PTR_ERR_OR_ZERO(pcf8563->rtc); } static const struct i2c_device_id pcf8563_id[] = { diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 843a745c42f3..c2639845186b 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -285,7 +285,7 @@ static int pcf8583_probe(struct i2c_client *client, pcf8583_driver.driver.name, &pcf8583_rtc_ops, THIS_MODULE); - return PTR_RET(pcf8583->rtc); + return PTR_ERR_OR_ZERO(pcf8583->rtc); } static const struct i2c_device_id pcf8583_id[] = { From 28ce42013c55339a35c669e534fc1200f42253d7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 15 Jul 2013 15:51:22 +0530 Subject: [PATCH 0376/6183] dma-buf: Replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is now deprecated. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Sachin Kamat Signed-off-by: Rusty Russell --- drivers/base/dma-buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 6687ba741879..1219ab7c3107 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -680,7 +680,7 @@ int dma_buf_debugfs_create_file(const char *name, d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir, write, &dma_buf_debug_fops); - return PTR_RET(d); + return PTR_ERR_OR_ZERO(d); } #else static inline int dma_buf_init_debugfs(void) From 627df4bc9537b13e17086deef1c92326d2b92fd4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 15 Jul 2013 15:57:07 +0530 Subject: [PATCH 0377/6183] sh_veu: Replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is now deprecated. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Sachin Kamat Signed-off-by: Rusty Russell --- drivers/media/platform/sh_veu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index aa4cca371cbf..744e43b480bc 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -359,7 +359,7 @@ static int sh_veu_context_init(struct sh_veu_dev *veu) veu->m2m_ctx = v4l2_m2m_ctx_init(veu->m2m_dev, veu, sh_veu_queue_init); - return PTR_RET(veu->m2m_ctx); + return PTR_ERR_OR_ZERO(veu->m2m_ctx); } static int sh_veu_querycap(struct file *file, void *priv, From b03cda5145f39b19aef1152350c04f4e3412cd20 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 15 Jul 2013 16:04:46 +0530 Subject: [PATCH 0378/6183] drm/cma: Replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is now deprecated. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Sachin Kamat Signed-off-by: Rusty Russell --- drivers/gpu/drm/drm_gem_cma_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index ece72a8ac245..61c1d17f870c 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -215,7 +215,7 @@ int drm_gem_cma_dumb_create(struct drm_file *file_priv, cma_obj = drm_gem_cma_create_with_handle(file_priv, dev, args->size, &args->handle); - return PTR_RET(cma_obj); + return PTR_ERR_OR_ZERO(cma_obj); } EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create); From cd633972e120003bd4cecc7dae560d2e32da5360 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 15 Jul 2013 16:52:18 +0530 Subject: [PATCH 0379/6183] Btrfs: volume: Replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is now deprecated. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Sachin Kamat Signed-off-by: Rusty Russell --- fs/btrfs/volumes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 78b871753cb6..67a085381845 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3302,7 +3302,7 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) } tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); - return PTR_RET(tsk); + return PTR_ERR_OR_ZERO(tsk); } int btrfs_recover_balance(struct btrfs_fs_info *fs_info) From 0a9a8c91a5f9617d6fa319fe052de38691fb29cb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Jul 2013 22:43:26 +0200 Subject: [PATCH 0380/6183] drm/i915: unify GT/PM irq postinstall code Again extract a common helper. For the postinstall hook things are a bit more complicated since we have more cases on ilk-hsw/vlv here. But since vlv was clearly broken by failing to initialize dev_priv->gt_irq_mask correctly the shared code is clearly justified. Also kill the PMIER setting in the async rps enable work. I should have been save, but also clearly looked rather fragile. PMIER setup is now all down in the irq pre/postinstall hooks. With this we now have the usual interrupt register sequence for GT/PM irq registers: - IER is setup once with all the interrupts we ever need in the postinstall hook and never touched again. Exceptions are SDEIER, which is touched in the preinstall hook (when the irq handler isn't enabled) and then only from the irq handler. And DEIER/VLV_IER with is used in the irq handler but also written to once in the postinstall hook. But since that write is essentially what enables the interrupt and we should always have MSI interrupts we should be save. In case we ever have non-MSI interrupts we'd be screwed. - IIR is cleared in the postinstall hook before we enable/unmask the respective interrupt sources. Hence we can't steal an interrupt event an accidentally trigger the spurious interrupt logic in the core kernel. Note that after some discussion with Ben Widawsky we think that we actually should clear the IIR registers in the preinstall hook. But doing that is a much larger patch series. - IMR regs are (usually) all masked off. Those are the only regs changed at runtime, which is all protected by dev_priv->irq_lock. This unification also kills the cargo-culted read-modify-write PM register setup for VECS. Interrupt setup is done without userspace being able to interfere, so we better know what values we want to put into those registers. RMW cycles otoh are really good at papering over races, until stuff magically blows up and no one has a clue why. v2: Touch the gen6+ PM interrupt registers only on gen6+. v3: Improve the commit message to more clearly spell out why we want to unify the code and what exactly changes. Cc: Ben Widawsky Cc: Paulo Zanoni Reviewed-by: Ben Widawsky [danvet: Add a comment to explain why the l3 parity interrupt is special.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 93 +++++++++++++++------------------ drivers/gpu/drm/i915/intel_pm.c | 4 -- 2 files changed, 43 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0d54a550ec6d..b388641e0606 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2196,6 +2196,46 @@ static void ibx_irq_postinstall(struct drm_device *dev) I915_WRITE(SDEIMR, ~mask); } +static void gen5_gt_irq_postinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pm_irqs, gt_irqs; + + pm_irqs = gt_irqs = 0; + + dev_priv->gt_irq_mask = ~0; + if (HAS_L3_GPU_CACHE(dev)) { + /* L3 parity interrupt is always unmasked. */ + dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; + gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; + } + + gt_irqs |= GT_RENDER_USER_INTERRUPT; + if (IS_GEN5(dev)) { + gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT | + ILK_BSD_USER_INTERRUPT; + } else { + gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; + } + + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + I915_WRITE(GTIER, gt_irqs); + POSTING_READ(GTIER); + + if (INTEL_INFO(dev)->gen >= 6) { + pm_irqs |= GEN6_PM_RPS_EVENTS; + + if (HAS_VEBOX(dev)) + pm_irqs |= PM_VEBOX_USER_INTERRUPT; + + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); + I915_WRITE(GEN6_PMIMR, 0xffffffff); + I915_WRITE(GEN6_PMIER, pm_irqs); + POSTING_READ(GEN6_PMIER); + } +} + static int ironlake_irq_postinstall(struct drm_device *dev) { unsigned long irqflags; @@ -2206,7 +2246,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | DE_POISON; - u32 gt_irqs; dev_priv->irq_mask = ~display_mask; @@ -2217,21 +2256,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT); POSTING_READ(DEIER); - dev_priv->gt_irq_mask = ~0; - - I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - - gt_irqs = GT_RENDER_USER_INTERRUPT; - - if (IS_GEN6(dev)) - gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; - else - gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT | - ILK_BSD_USER_INTERRUPT; - - I915_WRITE(GTIER, gt_irqs); - POSTING_READ(GTIER); + gen5_gt_irq_postinstall(dev); ibx_irq_postinstall(dev); @@ -2260,8 +2285,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB | DE_ERR_INT_IVB; - u32 pm_irqs = GEN6_PM_RPS_EVENTS; - u32 gt_irqs; dev_priv->irq_mask = ~display_mask; @@ -2276,30 +2299,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PIPEA_VBLANK_IVB); POSTING_READ(DEIER); - dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; - - I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - - gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT | - GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT; - I915_WRITE(GTIER, gt_irqs); - POSTING_READ(GTIER); - - I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); - if (HAS_VEBOX(dev)) - pm_irqs |= PM_VEBOX_USER_INTERRUPT; - - /* Our enable/disable rps functions may touch these registers so - * make sure to set a known state for only the non-RPS bits. - * The RMW is extra paranoia since this should be called after being set - * to a known state in preinstall. - * */ - I915_WRITE(GEN6_PMIMR, - (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs); - I915_WRITE(GEN6_PMIER, - (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs); - POSTING_READ(GEN6_PMIER); + gen5_gt_irq_postinstall(dev); ibx_irq_postinstall(dev); @@ -2309,7 +2309,6 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) static int valleyview_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 gt_irqs; u32 enable_mask; u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; unsigned long irqflags; @@ -2349,13 +2348,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(VLV_IIR, 0xffffffff); I915_WRITE(VLV_IIR, 0xffffffff); - I915_WRITE(GTIIR, I915_READ(GTIIR)); - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - - gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT | - GT_BLT_USER_INTERRUPT; - I915_WRITE(GTIER, gt_irqs); - POSTING_READ(GTIER); + gen5_gt_irq_postinstall(dev); /* ack & enable invalid PTE error interrupts */ #if 0 /* FIXME: add support to irq handler for checking these bits */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a9be0d1c173d..96f08724e491 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3319,8 +3319,6 @@ static void gen6_enable_rps(struct drm_device *dev) gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8); - /* requires MSI enabled */ - I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS); spin_lock_irq(&dev_priv->irq_lock); /* FIXME: Our interrupt enabling sequence is bonghits. * dev_priv->rps.pm_iir really should be 0 here. */ @@ -3599,8 +3597,6 @@ static void valleyview_enable_rps(struct drm_device *dev) valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); - /* requires MSI enabled */ - I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); spin_lock_irq(&dev_priv->irq_lock); WARN_ON(dev_priv->rps.pm_iir != 0); I915_WRITE(GEN6_PMIMR, 0); From 44fc7d5cf30723563558715f0794c8389a5c15ba Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Jul 2013 22:43:27 +0200 Subject: [PATCH 0381/6183] drm/i915: extract rps interrupt enable/disable helpers The VECS enabling required some changes to how rps interrupts are enabled/disabled since VECS interrupts are handling with the PM interrupt registers. But now that the pre/postinstall sequences is identical for all platforms with rps support (snb, ivb, hsw, vlv) we can also use the exact same sequence to actually enable the rps interrupts. Strictly speaking using spinlocks is overkill on snb/ivb & vlv since they have no VECS ring, but imo that's more than made up by the common code. Hence this just unifies the vlv code with the snb-hsw code which matched exactly before the VECS enabling. See commit eda63ffb906c2fb3b609a0e87aeb63c0f25b9e6b Author: Ben Widawsky Date: Tue May 28 19:22:26 2013 -0700 drm/i915: Add PM regs to pre/post install and commit 4848405cced3b46f4ec7d404b8ed5873171ae10a Author: Ben Widawsky Date: Tue May 28 19:22:27 2013 -0700 drm/i915: make PM interrupt writes non-destructive for why the gen6 code (shared between snb, ivb and hsw) needed to be changed originally. v3: Improve the commit message to more clearly spell out why we want to unify the code and what exactly changes. Cc: Paulo Zanoni Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 59 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 96f08724e491..787a528e7200 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3121,13 +3121,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); } - -static void gen6_disable_rps(struct drm_device *dev) +static void gen6_disable_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - I915_WRITE(GEN6_RC_CONTROL, 0); - I915_WRITE(GEN6_RPNSWREQ, 1 << 31); I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS); /* Complete PM interrupt masking here doesn't race with the rps work @@ -3142,23 +3139,23 @@ static void gen6_disable_rps(struct drm_device *dev) I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); } +static void gen6_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_RC_CONTROL, 0); + I915_WRITE(GEN6_RPNSWREQ, 1 << 31); + + gen6_disable_rps_interrupts(dev); +} + static void valleyview_disable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(GEN6_RC_CONTROL, 0); - I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); - I915_WRITE(GEN6_PMIER, 0); - /* Complete PM interrupt masking here doesn't race with the rps work - * item again unmasking PM interrupts because that is using a different - * register (PMIMR) to mask PM interrupts. The only risk is in leaving - * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ - spin_lock_irq(&dev_priv->irq_lock); - dev_priv->rps.pm_iir = 0; - spin_unlock_irq(&dev_priv->irq_lock); - - I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); + gen6_disable_rps_interrupts(dev); if (dev_priv->vlv_pctx) { drm_gem_object_unreference(&dev_priv->vlv_pctx->base); @@ -3191,6 +3188,21 @@ int intel_enable_rc6(const struct drm_device *dev) return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); } +static void gen6_enable_rps_interrupts(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + spin_lock_irq(&dev_priv->irq_lock); + /* FIXME: Our interrupt enabling sequence is bonghits. + * dev_priv->rps.pm_iir really should be 0 here. */ + dev_priv->rps.pm_iir = 0; + I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); + I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); + spin_unlock_irq(&dev_priv->irq_lock); + /* unmask all PM interrupts */ + I915_WRITE(GEN6_PMINTRMSK, 0); +} + static void gen6_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3319,15 +3331,7 @@ static void gen6_enable_rps(struct drm_device *dev) gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8); - spin_lock_irq(&dev_priv->irq_lock); - /* FIXME: Our interrupt enabling sequence is bonghits. - * dev_priv->rps.pm_iir really should be 0 here. */ - dev_priv->rps.pm_iir = 0; - I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); - I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); - spin_unlock_irq(&dev_priv->irq_lock); - /* unmask all PM interrupts */ - I915_WRITE(GEN6_PMINTRMSK, 0); + gen6_enable_rps_interrupts(dev); rc6vids = 0; ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); @@ -3597,12 +3601,7 @@ static void valleyview_enable_rps(struct drm_device *dev) valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); - spin_lock_irq(&dev_priv->irq_lock); - WARN_ON(dev_priv->rps.pm_iir != 0); - I915_WRITE(GEN6_PMIMR, 0); - spin_unlock_irq(&dev_priv->irq_lock); - /* enable all PM interrupts */ - I915_WRITE(GEN6_PMINTRMSK, 0); + gen6_enable_rps_interrupts(dev); gen6_gt_force_wake_put(dev_priv); } From a0b3335a2141aadb8f2398ade97fe574f2ddc875 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Jul 2013 23:35:34 +0200 Subject: [PATCH 0382/6183] drm/i915: simplify rps interrupt enabling/disabling sequence At the moment we have the following interrupt enabling sequence: 1. irq preinstall hook 2. enabling the interrupt handler and calling irq postinstall hook 3. enable rps interrupts from the async work And the folliwing disable sequence: 1. disabling the interrupt handler and calling the uninstall hook 2. disabling the rps interrupt Since the postinstall hook now always sets up PMIIR, PMIER and PMIMR to known-good states there no way for an interrupt to sneak in in the enable sequence, so we can reinstate the WARN lost in commit eda63ffb906c2fb3b609a0e87aeb63c0f25b9e6b Author: Ben Widawsky Date: Tue May 28 19:22:26 2013 -0700 drm/i915: Add PM regs to pre/post install Note that there's some room for future cleanups since most of the interrupt register clearing in the disable function is rather redundant. But that's better done in follow-up patches, if at all. Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 787a528e7200..bc5aae088550 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3193,9 +3193,7 @@ static void gen6_enable_rps_interrupts(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; spin_lock_irq(&dev_priv->irq_lock); - /* FIXME: Our interrupt enabling sequence is bonghits. - * dev_priv->rps.pm_iir really should be 0 here. */ - dev_priv->rps.pm_iir = 0; + WARN_ON(dev_priv->rps.pm_iir); I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); spin_unlock_irq(&dev_priv->irq_lock); From 7457d61748f7939dea49849db442cb3df4c7c3fe Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 7 Jun 2013 17:41:07 +0100 Subject: [PATCH 0383/6183] drm/i915: We implement WaFbcWaitForVBlankBeforeEnable for ilk and snb We also wait for that blank on other platforms but the w/a doesn't apply there. Not an issue at all. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bc5aae088550..cae89fe9b84f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -404,6 +404,8 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) * following the termination of the page-flipping sequence * and indeed performing the enable as a co-routine and not * waiting synchronously upon the vblank. + * + * WaFbcWaitForVBlankBeforeEnable:ilk,snb */ schedule_delayed_work(&work->work, msecs_to_jiffies(50)); } From 4bb353343dcc2486a1deda87f4c069153dc353c3 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 14 Jun 2013 15:23:24 +0100 Subject: [PATCH 0384/6183] drm/i915: We implement WaFbcAsynchFlipDisableFbcQueue on ilk and snb v2: Put the comment a bit closer to the actual write (Paulo Zanoni) Reviewed-by: Paulo Zanoni Signed-off-by: Damien Lespiau [danvet: Fix space before tab.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cae89fe9b84f..d212e42638d9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4453,6 +4453,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev) * The bit 7,8,9 of 0x42020. */ if (IS_IRONLAKE_M(dev)) { + /* WaFbcAsynchFlipDisableFbcQueue:ilk */ I915_WRITE(ILK_DISPLAY_CHICKEN1, I915_READ(ILK_DISPLAY_CHICKEN1) | ILK_FBCQ_DIS); @@ -4589,6 +4590,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) * The bit5 and bit7 of 0x42020 * The bit14 of 0x70180 * The bit14 of 0x71180 + * + * WaFbcAsynchFlipDisableFbcQueue:snb */ I915_WRITE(ILK_DISPLAY_CHICKEN1, I915_READ(ILK_DISPLAY_CHICKEN1) | From f1e8fa56fd650e0a23f64afdf59f3907d9a89615 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 7 Jun 2013 17:41:09 +0100 Subject: [PATCH 0385/6183] drm/i915: We implement WaFbcDisableDpfcClockGating on ilk Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d212e42638d9..9b95f78d352a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4416,7 +4416,10 @@ static void ironlake_init_clock_gating(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; - /* Required for FBC */ + /* + * Required for FBC + * WaFbcDisableDpfcClockGating:ilk + */ dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE | ILK_DPFCUNIT_CLOCK_GATE_DISABLE | ILK_DPFDUNIT_CLOCK_GATE_ENABLE; From 19bc678a6066d4ecca938c50ac2f9e9ccfb0ddbe Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 7 Jun 2013 17:41:10 +0100 Subject: [PATCH 0386/6183] drm/i915: We implement WaMPhyProgramming on Haswell Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ae3dc5d1ff52..3cda57d7b3f0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5166,7 +5166,10 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) BUG_ON(val != final); } -/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */ +/* + * Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. + * WaMPhyProgramming:hsw + */ static void lpt_init_pch_refclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; From eb4926e4a6e3922398fd6880f07a84db95aa3741 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 7 Jun 2013 17:41:14 +0100 Subject: [PATCH 0387/6183] drm/i915: Don't try to calculate RC6 residency on GEN4 and before intel_enable_rc6() is used to check if we can compute the RC6 residency in the sysfs code. Disable this for platforms older than Ironlake. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9b95f78d352a..e81d37667bc9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3167,6 +3167,10 @@ static void valleyview_disable_rps(struct drm_device *dev) int intel_enable_rc6(const struct drm_device *dev) { + /* No RC6 before Ironlake */ + if (INTEL_INFO(dev)->gen < 5) + return 0; + /* Respect the kernel parameter if it is set */ if (i915_enable_rc6 >= 0) return i915_enable_rc6; From 11fa3384042f5578e0f6179eef70cbcb2892be92 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 3 Jul 2013 17:22:06 +0300 Subject: [PATCH 0388/6183] drm/i915: Fix retrieval of hangcheck stats The default context is always supported (as it contains the global hangcheck stats) and the contexts for hangcheck are not limited to any ring. References: https://bugs.freedesktop.org/show_bug.cgi?id=65845 Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 23 ++++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5d4491e74871..700db059427b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1860,7 +1860,7 @@ static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) } struct i915_ctx_hang_stats * __must_check -i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring, +i915_gem_context_get_hang_stats(struct drm_device *dev, struct drm_file *file, u32 id); int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 2074544682cf..2470206a4d07 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -304,31 +304,24 @@ static int context_idr_cleanup(int id, void *p, void *data) } struct i915_ctx_hang_stats * -i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring, +i915_gem_context_get_hang_stats(struct drm_device *dev, struct drm_file *file, u32 id) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_file_private *file_priv = file->driver_priv; - struct i915_hw_context *to; - - if (dev_priv->hw_contexts_disabled) - return ERR_PTR(-ENOENT); - - if (ring->id != RCS) - return ERR_PTR(-EINVAL); - - if (file == NULL) - return ERR_PTR(-EINVAL); + struct i915_hw_context *ctx; if (id == DEFAULT_CONTEXT_ID) return &file_priv->hang_stats; - to = i915_gem_context_get(file->driver_priv, id); - if (to == NULL) + ctx = NULL; + if (!dev_priv->hw_contexts_disabled) + ctx = i915_gem_context_get(file->driver_priv, id); + if (ctx == NULL) return ERR_PTR(-ENOENT); - return &to->hang_stats; + return &ctx->hang_stats; } void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) From e85209698649be30cb1389966f29107d63f16940 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 3 Jul 2013 17:22:07 +0300 Subject: [PATCH 0389/6183] drm/i915: Replace open-coding of DEFAULT_CONTEXT_ID The intent of the check is made more clear if we use the proper name for 0 here. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 64eda4463b70..1b58694d7be7 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -873,7 +873,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, break; case I915_EXEC_BSD: ring = &dev_priv->ring[VCS]; - if (ctx_id != 0) { + if (ctx_id != DEFAULT_CONTEXT_ID) { DRM_DEBUG("Ring %s doesn't support contexts\n", ring->name); return -EPERM; @@ -881,7 +881,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, break; case I915_EXEC_BLT: ring = &dev_priv->ring[BCS]; - if (ctx_id != 0) { + if (ctx_id != DEFAULT_CONTEXT_ID) { DRM_DEBUG("Ring %s doesn't support contexts\n", ring->name); return -EPERM; @@ -889,7 +889,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, break; case I915_EXEC_VEBOX: ring = &dev_priv->ring[VECS]; - if (ctx_id != 0) { + if (ctx_id != DEFAULT_CONTEXT_ID) { DRM_DEBUG("Ring %s doesn't support contexts\n", ring->name); return -EPERM; From 6ad74047f47e1c48223237a0032c5e000f01193f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Jul 2013 10:46:16 +0100 Subject: [PATCH 0390/6183] ASoC: kirkwood-i2s: Remove empty remove() Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 44412eaf6e81..becc082e7ee3 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -398,11 +398,6 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai) } -static int kirkwood_i2s_remove(struct snd_soc_dai *dai) -{ - return 0; -} - static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { .startup = kirkwood_i2s_startup, .trigger = kirkwood_i2s_trigger, @@ -413,7 +408,6 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { static struct snd_soc_dai_driver kirkwood_i2s_dai = { .probe = kirkwood_i2s_probe, - .remove = kirkwood_i2s_remove, .playback = { .channels_min = 1, .channels_max = 2, @@ -431,7 +425,6 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = { .probe = kirkwood_i2s_probe, - .remove = kirkwood_i2s_remove, .playback = { .channels_min = 1, .channels_max = 2, From 9e12cbd93232c20544d16aa33c587786a6cb726d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Jul 2013 10:47:10 +0100 Subject: [PATCH 0391/6183] ASoC: kirkwood-i2s: Inline KIRKWOOD_I2S_RATES The addition of extclk support makes this misleading as it's only the rates used when there is no extclk so put it in the specific DAI it applies to. Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index becc082e7ee3..e6027fd5b29c 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -26,9 +26,6 @@ #define DRV_NAME "kirkwood-i2s" -#define KIRKWOOD_I2S_RATES \ - (SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) #define KIRKWOOD_I2S_FORMATS \ (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ @@ -411,13 +408,15 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = { .playback = { .channels_min = 1, .channels_max = 2, - .rates = KIRKWOOD_I2S_RATES, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, .formats = KIRKWOOD_I2S_FORMATS, }, .capture = { .channels_min = 1, .channels_max = 2, - .rates = KIRKWOOD_I2S_RATES, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, .formats = KIRKWOOD_I2S_FORMATS, }, .ops = &kirkwood_i2s_dai_ops, From e4c3bce26de240457370d00ce396602cc98bb3cc Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 16 Jul 2013 11:48:10 +0200 Subject: [PATCH 0392/6183] ALSA: hda - Headphone mic support for an Asus/Conexant device This Conexant codec has a single jack that can be used as either headphone or mic (but not headset). The existing hp_mic functionality does not apply here, because the mic and the HP are on separate pins. Hence make a lighter version of what has been earlier done for Realtek codecs. BugLink: https://bugs.launchpad.net/bugs/1198030 Tested-by: Franz Hsieh Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 79 +++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index de00ce166470..4edd2d0f9a3c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -66,6 +66,8 @@ struct conexant_spec { hda_nid_t eapds[4]; bool dynamic_eapd; + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + #ifdef ENABLE_CXT_STATIC_QUIRKS const struct snd_kcontrol_new *mixers[5]; int num_mixers; @@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec) snd_hda_gen_init(codec); if (!spec->dynamic_eapd) cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); + return 0; } @@ -3224,6 +3229,8 @@ enum { CXT_PINCFG_LEMOTE_A1205, CXT_FIXUP_STEREO_DMIC, CXT_FIXUP_INC_MIC_BOOST, + CXT_FIXUP_HEADPHONE_MIC_PIN, + CXT_FIXUP_HEADPHONE_MIC, }; static void cxt_fixup_stereo_dmic(struct hda_codec *codec, @@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec, (0 << AC_AMPCAP_MUTE_SHIFT)); } +static void cxt_update_headset_mode(struct hda_codec *codec) +{ + /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ + int i; + bool mic_mode = false; + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + + hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; + + for (i = 0; i < cfg->num_inputs; i++) + if (cfg->inputs[i].pin == mux_pin) { + mic_mode = !!cfg->inputs[i].is_headphone_mic; + break; + } + + if (mic_mode) { + snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ + spec->gen.hp_jack_present = false; + } else { + snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ + spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); + } + + snd_hda_gen_update_outputs(codec); +} + +static void cxt_update_headset_mode_hook(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol) +{ + cxt_update_headset_mode(codec); +} + +static void cxt_fixup_headphone_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct conexant_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; + spec->gen.automute_hook = cxt_update_headset_mode; + break; + case HDA_FIXUP_ACT_INIT: + cxt_update_headset_mode(codec); + break; + } +} + + /* ThinkPad X200 & co with cxt5051 */ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ @@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cxt5066_increase_mic_boost, }, + [CXT_FIXUP_HEADPHONE_MIC_PIN] = { + .type = HDA_FIXUP_PINS, + .chained = true, + .chain_id = CXT_FIXUP_HEADPHONE_MIC, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { } + } + }, + [CXT_FIXUP_HEADPHONE_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_headphone_mic, + }, }; static const struct snd_pci_quirk cxt5051_fixups[] = { @@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), @@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, + spec->parse_flags); if (err < 0) goto error; @@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->bus->allow_bus_reset = 1; } + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; error: From 8a537f85e9db8a43b323b0ffcf358c51448491de Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 16 Jul 2013 08:47:47 +0200 Subject: [PATCH 0393/6183] ASoC: kirkwood-i2s: fix a compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the function kirkwood_set_rate, when the rate cannot be satisfied by the internal nor by an external clock, the clock source in undefined: warning: ‘clks_ctrl’ may be used uninitialized in this function The ALSA subsystem should never gives such a rate because: - the rates with the internal clock are limited to 44.1, 48 and 96 kHz as specified by the kirkwood_i2s_dai structure, - the other rates are proposed in the structure kirkwood_i2s_dai_extclk only when the external clock is present. In case of programming error (bad rate for internal clock and no external clock), the function will simply cause a backtrace. Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-i2s.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index e6027fd5b29c..ba7203995369 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c @@ -102,14 +102,16 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai, uint32_t clks_ctrl; if (rate == 44100 || rate == 48000 || rate == 96000) { - /* use internal dco for supported rates */ + /* use internal dco for the supported rates + * defined in kirkwood_i2s_dai */ dev_dbg(dai->dev, "%s: dco set rate = %lu\n", __func__, rate); kirkwood_set_dco(priv->io, rate); clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO; - } else if (!IS_ERR(priv->extclk)) { - /* use optional external clk for other rates */ + } else { + /* use the external clock for the other rates + * defined in kirkwood_i2s_dai_extclk */ dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n", __func__, rate, 256 * rate); clk_set_rate(priv->extclk, 256 * rate); From b4519c71c45b31f5acd6db984c8830e52120323a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 16 Jul 2013 02:10:11 -0300 Subject: [PATCH 0394/6183] regmap: Provide __acquires/__releases annotations Fix the following sparse warnings: drivers/base/regmap/regmap.c:305:13: warning: context imbalance in 'regmap_lock_spinlock' - wrong count at exit drivers/base/regmap/regmap.c:314:13: warning: context imbalance in 'regmap_unlock_spinlock' - unexpected unlock Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 95920583e31e..bf8a81c930ac 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -303,6 +303,7 @@ static void regmap_unlock_mutex(void *__map) } static void regmap_lock_spinlock(void *__map) +__acquires(&map->spinlock) { struct regmap *map = __map; unsigned long flags; @@ -312,6 +313,7 @@ static void regmap_lock_spinlock(void *__map) } static void regmap_unlock_spinlock(void *__map) +__releases(&map->spinlock) { struct regmap *map = __map; spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags); From 10cd45b6e8ac1d1a99f6bdf0e0c80f2a1351f3f5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 3 Jul 2013 17:22:08 +0300 Subject: [PATCH 0395/6183] drm/i915: introduce i915_queue_hangcheck To run hangcheck in near future. Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 6 ++---- drivers/gpu/drm/i915/i915_irq.c | 21 ++++++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 700db059427b..c93ab68e4da9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1622,6 +1622,7 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); extern void intel_console_resume(struct work_struct *work); /* i915_irq.c */ +void i915_queue_hangcheck(struct drm_device *dev); void i915_hangcheck_elapsed(unsigned long data); void i915_handle_error(struct drm_device *dev, bool wedged); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 53c39bcf8e0e..df6ba10bf3a0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2083,10 +2083,8 @@ int __i915_add_request(struct intel_ring_buffer *ring, ring->outstanding_lazy_request = 0; if (!dev_priv->ums.mm_suspended) { - if (i915_enable_hangcheck) { - mod_timer(&dev_priv->gpu_error.hangcheck_timer, - round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); - } + i915_queue_hangcheck(ring->dev); + if (was_empty) { queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b388641e0606..99106990a326 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -698,18 +698,13 @@ static void ironlake_rps_change_irq_handler(struct drm_device *dev) static void notify_ring(struct drm_device *dev, struct intel_ring_buffer *ring) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (ring->obj == NULL) return; trace_i915_gem_request_complete(ring, ring->get_seqno(ring, false)); wake_up_all(&ring->irq_queue); - if (i915_enable_hangcheck) { - mod_timer(&dev_priv->gpu_error.hangcheck_timer, - round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); - } + i915_queue_hangcheck(dev); } static void gen6_pm_rps_work(struct work_struct *work) @@ -2030,9 +2025,17 @@ void i915_hangcheck_elapsed(unsigned long data) if (busy_count) /* Reset timer case chip hangs without another request * being added */ - mod_timer(&dev_priv->gpu_error.hangcheck_timer, - round_jiffies_up(jiffies + - DRM_I915_HANGCHECK_JIFFIES)); + i915_queue_hangcheck(dev); +} + +void i915_queue_hangcheck(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (!i915_enable_hangcheck) + return; + + mod_timer(&dev_priv->gpu_error.hangcheck_timer, + round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } static void ibx_irq_preinstall(struct drm_device *dev) From 1d5be6b287c8efc879fbe578e2b7bc8f7a38f313 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 12 Jul 2013 13:38:17 -0700 Subject: [PATCH 0396/6183] cgroup: move module ref handling into rebind_subsystems() Module ref handling in cgroup is rather weird. parse_cgroupfs_options() grabs all the modules for the specified subsystems. A module ref is kept if the specified subsystem is newly bound to the hierarchy. If not, or the operation fails, the refs are dropped. This scatters module ref handling across multiple functions making it difficult to track. It also make the function nasty to use for dynamic subsystem binding which is necessary for the planned unified hierarchy. There's nothing which requires the subsystem modules to be pinned between parse_cgroupfs_options() and rebind_subsystems() in both mount and remount paths. parse_cgroupfs_options() can just parse and rebind_subsystems() can handle pinning the subsystems that it wants to bind, which is a natural part of its task - binding - anyway. Move module ref handling into rebind_subsystems() which makes the code a lot simpler - modules are gotten iff it's gonna be bound and put iff unbound or binding fails. v2: Li pointed out that if a controller module is unloaded between parsing and binding, rebind_subsystems() won't notice the missing controller as it only iterates through existing controllers. Fix it by updating rebind_subsystems() to compare @added_mask to @pinned and fail with -ENOENT if they don't match. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 93 +++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 65 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index c108d3d1ea30..2a8cf1a7d2f4 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1003,6 +1003,7 @@ static int rebind_subsystems(struct cgroupfs_root *root, { struct cgroup *cgrp = &root->top_cgroup; struct cgroup_subsys *ss; + unsigned long pinned = 0; int i, ret; BUG_ON(!mutex_is_locked(&cgroup_mutex)); @@ -1010,20 +1011,32 @@ static int rebind_subsystems(struct cgroupfs_root *root, /* Check that any added subsystems are currently free */ for_each_subsys(ss, i) { - unsigned long bit = 1UL << i; - - if (!(bit & added_mask)) + if (!(added_mask & (1 << i))) continue; + /* is the subsystem mounted elsewhere? */ if (ss->root != &cgroup_dummy_root) { - /* Subsystem isn't free */ - return -EBUSY; + ret = -EBUSY; + goto out_put; } + + /* pin the module */ + if (!try_module_get(ss->module)) { + ret = -ENOENT; + goto out_put; + } + pinned |= 1 << i; + } + + /* subsys could be missing if unloaded between parsing and here */ + if (added_mask != pinned) { + ret = -ENOENT; + goto out_put; } ret = cgroup_populate_dir(cgrp, added_mask); if (ret) - return ret; + goto out_put; /* * Nothing can fail from this point on. Remove files for the @@ -1067,11 +1080,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, } else if (bit & root->subsys_mask) { /* Subsystem state should already exist */ BUG_ON(!cgrp->subsys[i]); - /* - * a refcount was taken, but we already had one, so - * drop the extra reference. - */ - module_put(ss->module); #ifdef CONFIG_MODULE_UNLOAD BUG_ON(ss->module && !module_refcount(ss->module)); #endif @@ -1088,6 +1096,12 @@ static int rebind_subsystems(struct cgroupfs_root *root, root->flags |= CGRP_ROOT_SUBSYS_BOUND; return 0; + +out_put: + for_each_subsys(ss, i) + if (pinned & (1 << i)) + module_put(ss->module); + return ret; } static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) @@ -1138,7 +1152,6 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) char *token, *o = data; bool all_ss = false, one_ss = false; unsigned long mask = (unsigned long)-1; - bool module_pin_failed = false; struct cgroup_subsys *ss; int i; @@ -1281,52 +1294,9 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) if (!opts->subsys_mask && !opts->name) return -EINVAL; - /* - * Grab references on all the modules we'll need, so the subsystems - * don't dance around before rebind_subsystems attaches them. This may - * take duplicate reference counts on a subsystem that's already used, - * but rebind_subsystems handles this case. - */ - for_each_subsys(ss, i) { - if (!(opts->subsys_mask & (1UL << i))) - continue; - if (!try_module_get(cgroup_subsys[i]->module)) { - module_pin_failed = true; - break; - } - } - if (module_pin_failed) { - /* - * oops, one of the modules was going away. this means that we - * raced with a module_delete call, and to the user this is - * essentially a "subsystem doesn't exist" case. - */ - for (i--; i >= 0; i--) { - /* drop refcounts only on the ones we took */ - unsigned long bit = 1UL << i; - - if (!(bit & opts->subsys_mask)) - continue; - module_put(cgroup_subsys[i]->module); - } - return -ENOENT; - } - return 0; } -static void drop_parsed_module_refcounts(unsigned long subsys_mask) -{ - struct cgroup_subsys *ss; - int i; - - mutex_lock(&cgroup_mutex); - for_each_subsys(ss, i) - if (subsys_mask & (1UL << i)) - module_put(cgroup_subsys[i]->module); - mutex_unlock(&cgroup_mutex); -} - static int cgroup_remount(struct super_block *sb, int *flags, char *data) { int ret = 0; @@ -1384,8 +1354,6 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) mutex_unlock(&cgroup_root_mutex); mutex_unlock(&cgroup_mutex); mutex_unlock(&cgrp->dentry->d_inode->i_mutex); - if (ret) - drop_parsed_module_refcounts(opts.subsys_mask); return ret; } @@ -1591,7 +1559,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, new_root = cgroup_root_from_opts(&opts); if (IS_ERR(new_root)) { ret = PTR_ERR(new_root); - goto drop_modules; + goto out_err; } opts.new_root = new_root; @@ -1600,7 +1568,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, if (IS_ERR(sb)) { ret = PTR_ERR(sb); cgroup_free_root(opts.new_root); - goto drop_modules; + goto out_err; } root = sb->s_fs_info; @@ -1708,9 +1676,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n"); } } - - /* no subsys rebinding, so refcounts don't change */ - drop_parsed_module_refcounts(opts.subsys_mask); } kfree(opts.release_agent); @@ -1728,8 +1693,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, mutex_unlock(&inode->i_mutex); drop_new_super: deactivate_locked_super(sb); - drop_modules: - drop_parsed_module_refcounts(opts.subsys_mask); out_err: kfree(opts.release_agent); kfree(opts.name); @@ -4837,7 +4800,7 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) /* * we shouldn't be called if the subsystem is in use, and the use of - * try_module_get in parse_cgroupfs_options should ensure that it + * try_module_get() in rebind_subsystems() should ensure that it * doesn't start being used while we're killing it off. */ BUG_ON(ss->root != &cgroup_dummy_root); From a698b4488ab98deef6c3beeba3e27fea17650132 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 28 Jun 2013 21:08:27 -0700 Subject: [PATCH 0397/6183] cgroup: remove gratuituous BUG_ON()s from rebind_subsystems() rebind_subsystems() performs santiy checks even on subsystems which aren't specified to be added or removed and the checks aren't all that useful given that these are in a very cold path while the violations they check would trip up in much hotter paths. Let's remove these from rebind_subsystems(). Signed-off-by: Tejun Heo Acked-by: Li Zefan --- kernel/cgroup.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 2a8cf1a7d2f4..345fac8e4fba 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1077,15 +1077,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, /* subsystem is now free - drop reference on module */ module_put(ss->module); root->subsys_mask &= ~bit; - } else if (bit & root->subsys_mask) { - /* Subsystem state should already exist */ - BUG_ON(!cgrp->subsys[i]); -#ifdef CONFIG_MODULE_UNLOAD - BUG_ON(ss->module && !module_refcount(ss->module)); -#endif - } else { - /* Subsystem state shouldn't exist */ - BUG_ON(cgrp->subsys[i]); } } From dc34e7e1a701134c2639dc7af78dc91055616477 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 1 Jul 2013 00:01:32 +0400 Subject: [PATCH 0398/6183] libata: move 'struct ata_taskfile' and friends from ata.h to libata.h Move 'struct ata_taskfile', ata_prot_flags() and their friends from to . They were misplaced from the beginning, as should cover ATA/ATAPI and related standards only -- to which the aforementioned structure and function have only remote relation. I would have moved 'enum ata_tf_protocols' closely related to 'struct ata_taskfile' but it unfortunately gets used by 'drivers/ide/ide-ioctls.c'... Signed-off-by: Sergei Shtylyov Signed-off-by: Tejun Heo --- include/linux/ata.h | 102 ----------------------------------------- include/linux/libata.h | 102 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/include/linux/ata.h b/include/linux/ata.h index ee0bd9524055..f63fb1afc5cc 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -446,22 +446,6 @@ enum { SERR_TRANS_ST_ERROR = (1 << 24), /* Transport state trans. error */ SERR_UNRECOG_FIS = (1 << 25), /* Unrecognized FIS */ SERR_DEV_XCHG = (1 << 26), /* device exchanged */ - - /* struct ata_taskfile flags */ - ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */ - ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ - ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ - ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ - ATA_TFLAG_LBA = (1 << 4), /* enable LBA */ - ATA_TFLAG_FUA = (1 << 5), /* enable FUA */ - ATA_TFLAG_POLLING = (1 << 6), /* set nIEN to 1 and use polling */ - - /* protocol flags */ - ATA_PROT_FLAG_PIO = (1 << 0), /* is PIO */ - ATA_PROT_FLAG_DMA = (1 << 1), /* is DMA */ - ATA_PROT_FLAG_DATA = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA, - ATA_PROT_FLAG_NCQ = (1 << 2), /* is NCQ */ - ATA_PROT_FLAG_ATAPI = (1 << 3), /* is ATAPI */ }; enum ata_tf_protocols { @@ -488,83 +472,6 @@ struct ata_bmdma_prd { __le32 flags_len; }; -struct ata_taskfile { - unsigned long flags; /* ATA_TFLAG_xxx */ - u8 protocol; /* ATA_PROT_xxx */ - - u8 ctl; /* control reg */ - - u8 hob_feature; /* additional data */ - u8 hob_nsect; /* to support LBA48 */ - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; - - u8 feature; - u8 nsect; - u8 lbal; - u8 lbam; - u8 lbah; - - u8 device; - - u8 command; /* IO operation */ -}; - -/* - * protocol tests - */ -static inline unsigned int ata_prot_flags(u8 prot) -{ - switch (prot) { - case ATA_PROT_NODATA: - return 0; - case ATA_PROT_PIO: - return ATA_PROT_FLAG_PIO; - case ATA_PROT_DMA: - return ATA_PROT_FLAG_DMA; - case ATA_PROT_NCQ: - return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ; - case ATAPI_PROT_NODATA: - return ATA_PROT_FLAG_ATAPI; - case ATAPI_PROT_PIO: - return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO; - case ATAPI_PROT_DMA: - return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA; - } - return 0; -} - -static inline int ata_is_atapi(u8 prot) -{ - return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI; -} - -static inline int ata_is_nodata(u8 prot) -{ - return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA); -} - -static inline int ata_is_pio(u8 prot) -{ - return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO; -} - -static inline int ata_is_dma(u8 prot) -{ - return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA; -} - -static inline int ata_is_ncq(u8 prot) -{ - return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ; -} - -static inline int ata_is_data(u8 prot) -{ - return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA; -} - /* * id tests */ @@ -1060,15 +967,6 @@ static inline unsigned ata_set_lba_range_entries(void *_buffer, return used_bytes; } -static inline int is_multi_taskfile(struct ata_taskfile *tf) -{ - return (tf->command == ATA_CMD_READ_MULTI) || - (tf->command == ATA_CMD_WRITE_MULTI) || - (tf->command == ATA_CMD_READ_MULTI_EXT) || - (tf->command == ATA_CMD_WRITE_MULTI_EXT) || - (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT); -} - static inline bool ata_ok(u8 status) { return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) diff --git a/include/linux/libata.h b/include/linux/libata.h index 4ea55bb45deb..283d66bc603c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -138,6 +138,22 @@ enum { ATA_SHT_THIS_ID = -1, ATA_SHT_USE_CLUSTERING = 1, + /* struct ata_taskfile flags */ + ATA_TFLAG_LBA48 = (1 << 0), /* enable 48-bit LBA and "HOB" */ + ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ + ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ + ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ + ATA_TFLAG_LBA = (1 << 4), /* enable LBA */ + ATA_TFLAG_FUA = (1 << 5), /* enable FUA */ + ATA_TFLAG_POLLING = (1 << 6), /* set nIEN to 1 and use polling */ + + /* protocol flags */ + ATA_PROT_FLAG_PIO = (1 << 0), /* is PIO */ + ATA_PROT_FLAG_DMA = (1 << 1), /* is DMA */ + ATA_PROT_FLAG_DATA = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA, + ATA_PROT_FLAG_NCQ = (1 << 2), /* is NCQ */ + ATA_PROT_FLAG_ATAPI = (1 << 3), /* is ATAPI */ + /* struct ata_device stuff */ ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */ ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */ @@ -518,6 +534,29 @@ enum sw_activity { BLINK_OFF, }; +struct ata_taskfile { + unsigned long flags; /* ATA_TFLAG_xxx */ + u8 protocol; /* ATA_PROT_xxx */ + + u8 ctl; /* control reg */ + + u8 hob_feature; /* additional data */ + u8 hob_nsect; /* to support LBA48 */ + u8 hob_lbal; + u8 hob_lbam; + u8 hob_lbah; + + u8 feature; + u8 nsect; + u8 lbal; + u8 lbam; + u8 lbah; + + u8 device; + + u8 command; /* IO operation */ +}; + #ifdef CONFIG_ATA_SFF struct ata_ioports { void __iomem *cmd_addr; @@ -959,6 +998,69 @@ extern const unsigned long sata_deb_timing_long[]; extern struct ata_port_operations ata_dummy_port_ops; extern const struct ata_port_info ata_dummy_port_info; +/* + * protocol tests + */ +static inline unsigned int ata_prot_flags(u8 prot) +{ + switch (prot) { + case ATA_PROT_NODATA: + return 0; + case ATA_PROT_PIO: + return ATA_PROT_FLAG_PIO; + case ATA_PROT_DMA: + return ATA_PROT_FLAG_DMA; + case ATA_PROT_NCQ: + return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ; + case ATAPI_PROT_NODATA: + return ATA_PROT_FLAG_ATAPI; + case ATAPI_PROT_PIO: + return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO; + case ATAPI_PROT_DMA: + return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA; + } + return 0; +} + +static inline int ata_is_atapi(u8 prot) +{ + return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI; +} + +static inline int ata_is_nodata(u8 prot) +{ + return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA); +} + +static inline int ata_is_pio(u8 prot) +{ + return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO; +} + +static inline int ata_is_dma(u8 prot) +{ + return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA; +} + +static inline int ata_is_ncq(u8 prot) +{ + return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ; +} + +static inline int ata_is_data(u8 prot) +{ + return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA; +} + +static inline int is_multi_taskfile(struct ata_taskfile *tf) +{ + return (tf->command == ATA_CMD_READ_MULTI) || + (tf->command == ATA_CMD_WRITE_MULTI) || + (tf->command == ATA_CMD_READ_MULTI_EXT) || + (tf->command == ATA_CMD_WRITE_MULTI_EXT) || + (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT); +} + static inline const unsigned long * sata_ehc_deb_timing(struct ata_eh_context *ehc) { From f2c4fa655f7139a181a6d6db99a49cab96ed0337 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Jul 2013 13:36:05 +0100 Subject: [PATCH 0399/6183] ASoC: tlv320aic3x: Add compatible strings for specific devices The driver supports a range of devices but currently doesn't allow those device names to be used for enumeration on DT. Add the currently listed I2C IDs as compatible strings. Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tlv320aic3x.txt | 8 +++++++- sound/soc/codecs/tlv320aic3x.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index f47c3f589fd0..26f65f92f42d 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -3,7 +3,13 @@ Texas Instruments - tlv320aic3x Codec module The tlv320aic3x serial control bus communicates through I2C protocols Required properties: -- compatible - "string" - "ti,tlv320aic3x" + +- compatible - "string" - One of: + "ti,tlv320aic3x" - Generic TLV320AIC3x device + "ti,tlv320aic33" - TLV320AIC33 + "ti,tlv320aic3007" - TLV320AIC3007 + + - reg - - I2C slave address diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index e5b926883131..c9bb760f405f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1582,6 +1582,8 @@ static int aic3x_i2c_remove(struct i2c_client *client) #if defined(CONFIG_OF) static const struct of_device_id tlv320aic3x_of_match[] = { { .compatible = "ti,tlv320aic3x", }, + { .compatible = "ti,tlv320aic33" }, + { .compatible = "ti,tlv320aic3007" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); From cbaa56896146cbb5ab54bd65f98d020af282e6c6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Jul 2013 13:39:52 +0100 Subject: [PATCH 0400/6183] ASoC: tlv320aic3x: List tlv320aic3106 as a supported device Currently there is no specific handling for it but the tlv320aic3106 is supported using this driver. Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tlv320aic3x.txt | 1 + sound/soc/codecs/tlv320aic3x.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 26f65f92f42d..705a6b156c6c 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -8,6 +8,7 @@ Required properties: "ti,tlv320aic3x" - Generic TLV320AIC3x device "ti,tlv320aic33" - TLV320AIC33 "ti,tlv320aic3007" - TLV320AIC3007 + "ti,tlv320aic3106" - TLV320AIC3106 - reg - - I2C slave address diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index c9bb760f405f..cad4fb17a933 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1492,6 +1492,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { { "tlv320aic3x", AIC3X_MODEL_3X }, { "tlv320aic33", AIC3X_MODEL_33 }, { "tlv320aic3007", AIC3X_MODEL_3007 }, + { "tlv320aic3106", AIC3X_MODEL_3X }, { } }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); @@ -1584,6 +1585,7 @@ static const struct of_device_id tlv320aic3x_of_match[] = { { .compatible = "ti,tlv320aic3x", }, { .compatible = "ti,tlv320aic33" }, { .compatible = "ti,tlv320aic3007" }, + { .compatible = "ti,tlv320aic3106" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); From a1df5c2b310ff88cad66de6d55c06d4ad3b9684b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Jul 2013 17:03:18 +0100 Subject: [PATCH 0401/6183] ASoC: imx: Enable COMPILE_TEST builds Since DT based boards don't have any dependency on arch/arm enable them if COMPILE_TEST is enabled. Signed-off-by: Mark Brown Acked-by: Shawn Guo --- sound/soc/fsl/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index aa438546c912..87e28bcf7a83 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -98,7 +98,7 @@ endif # SND_POWERPC_SOC menuconfig SND_IMX_SOC tristate "SoC Audio for Freescale i.MX CPUs" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST help Say Y or M if you want to add support for codecs attached to the i.MX CPUs. From 7497185f8c5a3e0dc92765bfc723900b492cd8a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Jul 2013 18:13:35 +0100 Subject: [PATCH 0402/6183] ASoC: samsung-spdif: Convert to devm_clk_get() Signed-off-by: Mark Brown --- sound/soc/samsung/spdif.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 2e5ebb2f1982..5ea70ab0ecb5 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -395,7 +395,7 @@ static int spdif_probe(struct platform_device *pdev) spin_lock_init(&spdif->lock); - spdif->pclk = clk_get(&pdev->dev, "spdif"); + spdif->pclk = devm_clk_get(&pdev->dev, "spdif"); if (IS_ERR(spdif->pclk)) { dev_err(&pdev->dev, "failed to get peri-clock\n"); ret = -ENOENT; @@ -403,7 +403,7 @@ static int spdif_probe(struct platform_device *pdev) } clk_prepare_enable(spdif->pclk); - spdif->sclk = clk_get(&pdev->dev, "sclk_spdif"); + spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif"); if (IS_ERR(spdif->sclk)) { dev_err(&pdev->dev, "failed to get internal source clock\n"); ret = -ENOENT; @@ -457,10 +457,8 @@ err3: release_mem_region(mem_res->start, resource_size(mem_res)); err2: clk_disable_unprepare(spdif->sclk); - clk_put(spdif->sclk); err1: clk_disable_unprepare(spdif->pclk); - clk_put(spdif->pclk); err0: return ret; } @@ -480,9 +478,7 @@ static int spdif_remove(struct platform_device *pdev) release_mem_region(mem_res->start, resource_size(mem_res)); clk_disable_unprepare(spdif->sclk); - clk_put(spdif->sclk); clk_disable_unprepare(spdif->pclk); - clk_put(spdif->pclk); return 0; } From f1269ae41f2e2846031cb361b59ebc36d5f9528a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 16 Jul 2013 20:05:07 +0800 Subject: [PATCH 0403/6183] ASoC: imx-sgtl5000: fix error return code in imx_sgtl5000_probe() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Acked-by: Shawn Guo Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 3f726e4f88db..389cbfa6dca7 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -129,8 +129,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) } data->codec_clk = devm_clk_get(&codec_dev->dev, NULL); - if (IS_ERR(data->codec_clk)) + if (IS_ERR(data->codec_clk)) { + ret = PTR_ERR(data->codec_clk); goto fail; + } data->clk_frequency = clk_get_rate(data->codec_clk); From eb2cabd7cfa25c0ec4a099bf632ad9bae3be79f1 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 15 Jul 2013 12:52:52 -0600 Subject: [PATCH 0404/6183] ARM: tegra: remove tegra114-pluto.dts Early upstream work on Tegra114 was performed on the Pluto board. However, it's not used any more, and the DT doesn't contain anything beyond a serial port, so the file isn't useful either. Remove it. Signed-off-by: Stephen Warren --- arch/arm/boot/dts/Makefile | 3 +-- arch/arm/boot/dts/tegra114-pluto.dts | 33 ---------------------------- 2 files changed, 1 insertion(+), 35 deletions(-) delete mode 100644 arch/arm/boot/dts/tegra114-pluto.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 641b3c9a7028..de39162a7c0f 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -224,8 +224,7 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ tegra30-beaver.dtb \ tegra30-cardhu-a02.dtb \ tegra30-cardhu-a04.dtb \ - tegra114-dalmore.dtb \ - tegra114-pluto.dtb + tegra114-dalmore.dtb dtb-$(CONFIG_ARCH_VERSATILE) += versatile-ab.dtb \ versatile-pb.dtb dtb-$(CONFIG_ARCH_U300) += ste-u300.dtb diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts deleted file mode 100644 index d5f8d3e0bde2..000000000000 --- a/arch/arm/boot/dts/tegra114-pluto.dts +++ /dev/null @@ -1,33 +0,0 @@ -/dts-v1/; - -#include "tegra114.dtsi" - -/ { - model = "NVIDIA Tegra114 Pluto evaluation board"; - compatible = "nvidia,pluto", "nvidia,tegra114"; - - memory { - reg = <0x80000000 0x40000000>; - }; - - serial@70006300 { - status = "okay"; - }; - - pmc { - nvidia,invert-interrupt; - }; - - clocks { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - clk32k_in: clock { - compatible = "fixed-clock"; - reg=<0>; - #clock-cells = <0>; - clock-frequency = <32768>; - }; - }; -}; From 9b710506a03b01a9fdd83962912bc9d8237b82e8 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 16 Jul 2013 15:20:14 -0700 Subject: [PATCH 0405/6183] x86, bitops: Change bitops to be native operand size Change the bitops operation to be naturally "long", i.e. 63 bits on the 64-bit kernel. Additional bugs are likely to crop up in the future. We already have bugs which machines with > 16 TiB of memory in a single node, as can happen if memory is interleaved. The x86 bitop operations take a signed index, so using an unsigned type is not an option. Jim Kukunas measured the effect of this patch on kernel size: it adds 2779 bytes to the allyesconfig kernel. Some of that probably could be elided by replacing the inline functions with macros which select the 32-bit type if the index is a 32-bit value, something like: In that case we could also use "Jr" constraints for the 64-bit version. However, this would more than double the amount of code for a relatively small gain. Note that we can't use ilog2() for _BITOPS_LONG_SHIFT, as that causes a recursive header inclusion problem. The change to constant_test_bit() should both generate better code and give correct result for negative bit indicies. As previously written the compiler had to generate extra code to create the proper wrong result for negative values. Signed-off-by: H. Peter Anvin Cc: Jim Kukunas Link: http://lkml.kernel.org/n/tip-z61ofiwe90xeyb461o72h8ya@git.kernel.org --- arch/x86/include/asm/bitops.h | 46 ++++++++++++++++++------------ arch/x86/include/asm/sync_bitops.h | 24 ++++++++-------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h index 6dfd0195bb55..41639ce8fd63 100644 --- a/arch/x86/include/asm/bitops.h +++ b/arch/x86/include/asm/bitops.h @@ -15,6 +15,14 @@ #include #include +#if BITS_PER_LONG == 32 +# define _BITOPS_LONG_SHIFT 5 +#elif BITS_PER_LONG == 64 +# define _BITOPS_LONG_SHIFT 6 +#else +# error "Unexpected BITS_PER_LONG" +#endif + #define BIT_64(n) (U64_C(1) << (n)) /* @@ -59,7 +67,7 @@ * restricted to acting on a single-word quantity. */ static __always_inline void -set_bit(unsigned int nr, volatile unsigned long *addr) +set_bit(long nr, volatile unsigned long *addr) { if (IS_IMMEDIATE(nr)) { asm volatile(LOCK_PREFIX "orb %1,%0" @@ -81,7 +89,7 @@ set_bit(unsigned int nr, volatile unsigned long *addr) * If it's called on the same region of memory simultaneously, the effect * may be that only one operation succeeds. */ -static inline void __set_bit(int nr, volatile unsigned long *addr) +static inline void __set_bit(long nr, volatile unsigned long *addr) { asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory"); } @@ -97,7 +105,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr) * in order to ensure changes are visible on other processors. */ static __always_inline void -clear_bit(int nr, volatile unsigned long *addr) +clear_bit(long nr, volatile unsigned long *addr) { if (IS_IMMEDIATE(nr)) { asm volatile(LOCK_PREFIX "andb %1,%0" @@ -118,13 +126,13 @@ clear_bit(int nr, volatile unsigned long *addr) * clear_bit() is atomic and implies release semantics before the memory * operation. It can be used for an unlock. */ -static inline void clear_bit_unlock(unsigned nr, volatile unsigned long *addr) +static inline void clear_bit_unlock(long nr, volatile unsigned long *addr) { barrier(); clear_bit(nr, addr); } -static inline void __clear_bit(int nr, volatile unsigned long *addr) +static inline void __clear_bit(long nr, volatile unsigned long *addr) { asm volatile("btr %1,%0" : ADDR : "Ir" (nr)); } @@ -141,7 +149,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr) * No memory barrier is required here, because x86 cannot reorder stores past * older loads. Same principle as spin_unlock. */ -static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr) +static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr) { barrier(); __clear_bit(nr, addr); @@ -159,7 +167,7 @@ static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr) * If it's called on the same region of memory simultaneously, the effect * may be that only one operation succeeds. */ -static inline void __change_bit(int nr, volatile unsigned long *addr) +static inline void __change_bit(long nr, volatile unsigned long *addr) { asm volatile("btc %1,%0" : ADDR : "Ir" (nr)); } @@ -173,7 +181,7 @@ static inline void __change_bit(int nr, volatile unsigned long *addr) * Note that @nr may be almost arbitrarily large; this function is not * restricted to acting on a single-word quantity. */ -static inline void change_bit(int nr, volatile unsigned long *addr) +static inline void change_bit(long nr, volatile unsigned long *addr) { if (IS_IMMEDIATE(nr)) { asm volatile(LOCK_PREFIX "xorb %1,%0" @@ -194,7 +202,7 @@ static inline void change_bit(int nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int test_and_set_bit(long nr, volatile unsigned long *addr) { int oldbit; @@ -212,7 +220,7 @@ static inline int test_and_set_bit(int nr, volatile unsigned long *addr) * This is the same as test_and_set_bit on x86. */ static __always_inline int -test_and_set_bit_lock(int nr, volatile unsigned long *addr) +test_and_set_bit_lock(long nr, volatile unsigned long *addr) { return test_and_set_bit(nr, addr); } @@ -226,7 +234,7 @@ test_and_set_bit_lock(int nr, volatile unsigned long *addr) * If two examples of this operation race, one can appear to succeed * but actually fail. You must protect multiple accesses with a lock. */ -static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_set_bit(long nr, volatile unsigned long *addr) { int oldbit; @@ -245,7 +253,7 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int test_and_clear_bit(long nr, volatile unsigned long *addr) { int oldbit; @@ -272,7 +280,7 @@ static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) * accessed from a hypervisor on the same CPU if running in a VM: don't change * this without also updating arch/x86/kernel/kvm.c */ -static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_clear_bit(long nr, volatile unsigned long *addr) { int oldbit; @@ -284,7 +292,7 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) } /* WARNING: non atomic and it can be reordered! */ -static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_change_bit(long nr, volatile unsigned long *addr) { int oldbit; @@ -304,7 +312,7 @@ static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int test_and_change_bit(long nr, volatile unsigned long *addr) { int oldbit; @@ -315,13 +323,13 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) return oldbit; } -static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr) +static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr) { - return ((1UL << (nr % BITS_PER_LONG)) & - (addr[nr / BITS_PER_LONG])) != 0; + return ((1UL << (nr & (BITS_PER_LONG-1))) & + (addr[nr >> _BITOPS_LONG_SHIFT])) != 0; } -static inline int variable_test_bit(int nr, volatile const unsigned long *addr) +static inline int variable_test_bit(long nr, volatile const unsigned long *addr) { int oldbit; diff --git a/arch/x86/include/asm/sync_bitops.h b/arch/x86/include/asm/sync_bitops.h index 9d09b4073b60..05af3b31d522 100644 --- a/arch/x86/include/asm/sync_bitops.h +++ b/arch/x86/include/asm/sync_bitops.h @@ -26,9 +26,9 @@ * Note that @nr may be almost arbitrarily large; this function is not * restricted to acting on a single-word quantity. */ -static inline void sync_set_bit(int nr, volatile unsigned long *addr) +static inline void sync_set_bit(long nr, volatile unsigned long *addr) { - asm volatile("lock; btsl %1,%0" + asm volatile("lock; bts %1,%0" : "+m" (ADDR) : "Ir" (nr) : "memory"); @@ -44,9 +44,9 @@ static inline void sync_set_bit(int nr, volatile unsigned long *addr) * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() * in order to ensure changes are visible on other processors. */ -static inline void sync_clear_bit(int nr, volatile unsigned long *addr) +static inline void sync_clear_bit(long nr, volatile unsigned long *addr) { - asm volatile("lock; btrl %1,%0" + asm volatile("lock; btr %1,%0" : "+m" (ADDR) : "Ir" (nr) : "memory"); @@ -61,9 +61,9 @@ static inline void sync_clear_bit(int nr, volatile unsigned long *addr) * Note that @nr may be almost arbitrarily large; this function is not * restricted to acting on a single-word quantity. */ -static inline void sync_change_bit(int nr, volatile unsigned long *addr) +static inline void sync_change_bit(long nr, volatile unsigned long *addr) { - asm volatile("lock; btcl %1,%0" + asm volatile("lock; btc %1,%0" : "+m" (ADDR) : "Ir" (nr) : "memory"); @@ -77,11 +77,11 @@ static inline void sync_change_bit(int nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr) { int oldbit; - asm volatile("lock; btsl %2,%1\n\tsbbl %0,%0" + asm volatile("lock; bts %2,%1\n\tsbbl %0,%0" : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); return oldbit; @@ -95,11 +95,11 @@ static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr) { int oldbit; - asm volatile("lock; btrl %2,%1\n\tsbbl %0,%0" + asm volatile("lock; btr %2,%1\n\tsbbl %0,%0" : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); return oldbit; @@ -113,11 +113,11 @@ static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr) * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int sync_test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr) { int oldbit; - asm volatile("lock; btcl %2,%1\n\tsbbl %0,%0" + asm volatile("lock; btc %2,%1\n\tsbbl %0,%0" : "=r" (oldbit), "+m" (ADDR) : "Ir" (nr) : "memory"); return oldbit; From fd4363fff3d96795d3feb1b3fb48ce590f186bdd Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 12 Jul 2013 11:21:48 +0200 Subject: [PATCH 0406/6183] x86: Introduce int3 (breakpoint)-based instruction patching Introduce a method for run-time instruction patching on a live SMP kernel based on int3 breakpoint, completely avoiding the need for stop_machine(). The way this is achieved: - add a int3 trap to the address that will be patched - sync cores - update all but the first byte of the patched range - sync cores - replace the first byte (int3) by the first byte of replacing opcode - sync cores According to http://lkml.indiana.edu/hypermail/linux/kernel/1001.1/01530.html synchronization after replacing "all but first" instructions should not be necessary (on Intel hardware), as the syncing after the subsequent patching of the first byte provides enough safety. But there's not only Intel HW out there, and we'd rather be on a safe side. If any CPU instruction execution would collide with the patching, it'd be trapped by the int3 breakpoint and redirected to the provided "handler" (which would typically mean just skipping over the patched region, acting as "nop" has been there, in case we are doing nop -> jump and jump -> nop transitions). Ftrace has been using this very technique since 08d636b ("ftrace/x86: Have arch x86_64 use breakpoints instead of stop machine") for ages already, and jump labels are another obvious potential user of this. Based on activities of Masami Hiramatsu a few years ago. Reviewed-by: Steven Rostedt Reviewed-by: Masami Hiramatsu Signed-off-by: Jiri Kosina Link: http://lkml.kernel.org/r/alpine.LNX.2.00.1307121102440.29788@pobox.suse.cz Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/alternative.h | 1 + arch/x86/kernel/alternative.c | 106 +++++++++++++++++++++++++++++ kernel/kprobes.c | 2 +- 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 58ed6d96a6ac..3abf8dd6f44f 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -233,6 +233,7 @@ struct text_poke_param { }; extern void *text_poke(void *addr, const void *opcode, size_t len); +extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler); extern void *text_poke_smp(void *addr, const void *opcode, size_t len); extern void text_poke_smp_batch(struct text_poke_param *params, int n); diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index c15cf9a25e27..0ab49366a7a6 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -596,6 +597,111 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len) return addr; } +static void do_sync_core(void *info) +{ + sync_core(); +} + +static bool bp_patching_in_progress; +static void *bp_int3_handler, *bp_int3_addr; + +static int int3_notify(struct notifier_block *self, unsigned long val, void *data) +{ + struct die_args *args = data; + + /* bp_patching_in_progress */ + smp_rmb(); + + if (likely(!bp_patching_in_progress)) + return NOTIFY_DONE; + + /* we are not interested in non-int3 faults and ring > 0 faults */ + if (val != DIE_INT3 || !args->regs || user_mode_vm(args->regs) + || args->regs->ip != (unsigned long)bp_int3_addr) + return NOTIFY_DONE; + + /* set up the specified breakpoint handler */ + args->regs->ip = (unsigned long) bp_int3_handler; + + return NOTIFY_STOP; +} +/** + * text_poke_bp() -- update instructions on live kernel on SMP + * @addr: address to patch + * @opcode: opcode of new instruction + * @len: length to copy + * @handler: address to jump to when the temporary breakpoint is hit + * + * Modify multi-byte instruction by using int3 breakpoint on SMP. + * In contrary to text_poke_smp(), we completely avoid stop_machine() here, + * and achieve the synchronization using int3 breakpoint. + * + * The way it is done: + * - add a int3 trap to the address that will be patched + * - sync cores + * - update all but the first byte of the patched range + * - sync cores + * - replace the first byte (int3) by the first byte of + * replacing opcode + * - sync cores + * + * Note: must be called under text_mutex. + */ +void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler) +{ + unsigned char int3 = 0xcc; + + bp_int3_handler = handler; + bp_int3_addr = (u8 *)addr + sizeof(int3); + bp_patching_in_progress = true; + /* + * Corresponding read barrier in int3 notifier for + * making sure the in_progress flags is correctly ordered wrt. + * patching + */ + smp_wmb(); + + text_poke(addr, &int3, sizeof(int3)); + + on_each_cpu(do_sync_core, NULL, 1); + + if (len - sizeof(int3) > 0) { + /* patch all but the first byte */ + text_poke((char *)addr + sizeof(int3), + (const char *) opcode + sizeof(int3), + len - sizeof(int3)); + /* + * According to Intel, this core syncing is very likely + * not necessary and we'd be safe even without it. But + * better safe than sorry (plus there's not only Intel). + */ + on_each_cpu(do_sync_core, NULL, 1); + } + + /* patch the first byte */ + text_poke(addr, opcode, sizeof(int3)); + + on_each_cpu(do_sync_core, NULL, 1); + + bp_patching_in_progress = false; + smp_wmb(); + + return addr; +} + +/* this one needs to run before anything else handles it as a + * regular exception */ +static struct notifier_block int3_nb = { + .priority = 0x7fffffff, + .notifier_call = int3_notify +}; + +static int __init int3_init(void) +{ + return register_die_notifier(&int3_nb); +} + +arch_initcall(int3_init); /* * Cross-modifying kernel text with stop_machine(). * This code originally comes from immediate value. diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 6e33498d665c..b58b490fa439 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1709,7 +1709,7 @@ EXPORT_SYMBOL_GPL(unregister_kprobes); static struct notifier_block kprobe_exceptions_nb = { .notifier_call = kprobe_exceptions_notify, - .priority = 0x7fffffff /* we need to be notified first */ + .priority = 0x7ffffff0 /* High priority, but not first. */ }; unsigned long __weak arch_deref_entry_point(void *entry) From 51b2c07b22261f19188d9a9071943d60a067481c Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 12 Jul 2013 11:22:09 +0200 Subject: [PATCH 0407/6183] x86: Make jump_label use int3-based patching Make jump labels use text_poke_bp() for text patching instead of text_poke_smp(), avoiding the need for stop_machine(). Reviewed-by: Steven Rostedt Reviewed-by: Masami Hiramatsu Signed-off-by: Jiri Kosina Link: http://lkml.kernel.org/r/alpine.LNX.2.00.1307121120250.29788@pobox.suse.cz Signed-off-by: H. Peter Anvin --- arch/x86/kernel/jump_label.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c index 2889b3d43882..460f5d9ceebb 100644 --- a/arch/x86/kernel/jump_label.c +++ b/arch/x86/kernel/jump_label.c @@ -37,7 +37,19 @@ static void __jump_label_transform(struct jump_entry *entry, } else memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); - (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); + /* + * Make text_poke_bp() a default fallback poker. + * + * At the time the change is being done, just ignore whether we + * are doing nop -> jump or jump -> nop transition, and assume + * always nop being the 'currently valid' instruction + * + */ + if (poker) + (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); + else + text_poke_bp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE, + (void *)entry->code + JUMP_LABEL_NOP_SIZE); } void arch_jump_label_transform(struct jump_entry *entry, @@ -45,7 +57,7 @@ void arch_jump_label_transform(struct jump_entry *entry, { get_online_cpus(); mutex_lock(&text_mutex); - __jump_label_transform(entry, type, text_poke_smp); + __jump_label_transform(entry, type, NULL); mutex_unlock(&text_mutex); put_online_cpus(); } From c9031fbb35bd44d99c5cfe7d3c97ec238d63643a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 26 May 2013 17:53:37 -0700 Subject: [PATCH 0408/6183] ARM: shmobile: r8a7778: add __initdata on resource and device data These data will be kmemdup()'ed on platform_device_add_resources() and platform_device_add_data() Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7778.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c index 80c20392ad7c..b70bfeef2f6c 100644 --- a/arch/arm/mach-shmobile/setup-r8a7778.c +++ b/arch/arm/mach-shmobile/setup-r8a7778.c @@ -53,7 +53,7 @@ .irqs = SCIx_IRQ_MUXED(irq), \ } -static struct plat_sci_port scif_platform_data[] = { +static struct plat_sci_port scif_platform_data[] __initdata = { SCIF_INFO(0xffe40000, gic_iid(0x66)), SCIF_INFO(0xffe41000, gic_iid(0x67)), SCIF_INFO(0xffe42000, gic_iid(0x68)), @@ -63,24 +63,24 @@ static struct plat_sci_port scif_platform_data[] = { }; /* TMU */ -static struct resource sh_tmu0_resources[] = { +static struct resource sh_tmu0_resources[] __initdata = { DEFINE_RES_MEM(0xffd80008, 12), DEFINE_RES_IRQ(gic_iid(0x40)), }; -static struct sh_timer_config sh_tmu0_platform_data = { +static struct sh_timer_config sh_tmu0_platform_data __initdata = { .name = "TMU00", .channel_offset = 0x4, .timer_bit = 0, .clockevent_rating = 200, }; -static struct resource sh_tmu1_resources[] = { +static struct resource sh_tmu1_resources[] __initdata = { DEFINE_RES_MEM(0xffd80014, 12), DEFINE_RES_IRQ(gic_iid(0x41)), }; -static struct sh_timer_config sh_tmu1_platform_data = { +static struct sh_timer_config sh_tmu1_platform_data __initdata = { .name = "TMU01", .channel_offset = 0x10, .timer_bit = 1, @@ -189,7 +189,7 @@ USB_PLATFORM_INFO(ehci); USB_PLATFORM_INFO(ohci); /* Ether */ -static struct resource ether_resources[] = { +static struct resource ether_resources[] __initdata = { DEFINE_RES_MEM(0xfde00000, 0x400), DEFINE_RES_IRQ(gic_iid(0x89)), }; @@ -203,17 +203,17 @@ void __init r8a7778_add_ether_device(struct sh_eth_plat_data *pdata) } /* PFC/GPIO */ -static struct resource pfc_resources[] = { +static struct resource pfc_resources[] __initdata = { DEFINE_RES_MEM(0xfffc0000, 0x118), }; #define R8A7778_GPIO(idx) \ -static struct resource r8a7778_gpio##idx##_resources[] = { \ +static struct resource r8a7778_gpio##idx##_resources[] __initdata = { \ DEFINE_RES_MEM(0xffc40000 + 0x1000 * (idx), 0x30), \ DEFINE_RES_IRQ(gic_iid(0x87)), \ }; \ \ -static struct gpio_rcar_config r8a7778_gpio##idx##_platform_data = { \ +static struct gpio_rcar_config r8a7778_gpio##idx##_platform_data __initdata = { \ .gpio_base = 32 * (idx), \ .irq_base = GPIO_IRQ_BASE(idx), \ .number_of_pins = 32, \ @@ -249,7 +249,7 @@ void __init r8a7778_pinmux_init(void) }; /* SDHI */ -static struct resource sdhi_resources[] = { +static struct resource sdhi_resources[] __initdata = { /* SDHI0 */ DEFINE_RES_MEM(0xFFE4C000, 0x100), DEFINE_RES_IRQ(gic_iid(0x77)), @@ -365,12 +365,12 @@ void __init r8a7778_init_late(void) platform_device_register_full(&ohci_info); } -static struct renesas_intc_irqpin_config irqpin_platform_data = { +static struct renesas_intc_irqpin_config irqpin_platform_data __initdata = { .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */ .sense_bitfield_width = 2, }; -static struct resource irqpin_resources[] = { +static struct resource irqpin_resources[] __initdata = { DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */ DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */ DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */ From 474f67587345bf7b32bbd9d2b5621e85500103c5 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 27 Jun 2013 17:09:01 +0900 Subject: [PATCH 0409/6183] ARM: shmobile: sh73a0 pinmux platform device cleanup Use DEFINE_RES_MEM() and platform_device_register_simple() to save a couple of lines of code. Signed-off-by: Magnus Damm Acked-by: Laurent Pinchart [ remove const from resource pfc_resources to avoid section miss-match reported by 4.4.5 ] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-sh73a0.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 96e7ca1e4e11..79a6040774a4 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -61,29 +61,16 @@ void __init sh73a0_map_io(void) iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc)); } -static struct resource sh73a0_pfc_resources[] = { - [0] = { - .start = 0xe6050000, - .end = 0xe6057fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 0xe605801c, - .end = 0xe6058027, - .flags = IORESOURCE_MEM, - } -}; - -static struct platform_device sh73a0_pfc_device = { - .name = "pfc-sh73a0", - .id = -1, - .resource = sh73a0_pfc_resources, - .num_resources = ARRAY_SIZE(sh73a0_pfc_resources), +/* PFC */ +static struct resource pfc_resources[] __initdata = { + DEFINE_RES_MEM(0xe6050000, 0x8000), + DEFINE_RES_MEM(0xe605801c, 0x000c), }; void __init sh73a0_pinmux_init(void) { - platform_device_register(&sh73a0_pfc_device); + platform_device_register_simple("pfc-sh73a0", -1, pfc_resources, + ARRAY_SIZE(pfc_resources)); } static struct plat_sci_port scif0_platform_data = { From 34dd9fc04a028edad7658006764c4d18ac3dca73 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sun, 26 May 2013 22:05:23 +0900 Subject: [PATCH 0410/6183] ARM: shmobile: emev2: Remove init_irq declaration in machine description Commit ebafed7a ("ARM: irq: Call irqchip_init if no init_irq function is specified") removed the need to explictly setup the init_irq field in the machine description when using only irqchip_init. Remove that declaration for shmobile as well. Signed-off-by: Maxime Ripard Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-emev2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index 1ccddd228112..6e8b6ac3c6b2 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -454,7 +453,6 @@ DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") .smp = smp_ops(emev2_smp_ops), .init_early = emev2_init_delay, .nr_irqs = NR_IRQS_LEGACY, - .init_irq = irqchip_init, .init_machine = emev2_add_standard_devices_dt, .dt_compat = emev2_boards_compat_dt, MACHINE_END From 0bdbe04db005e025d3522ad3ae9797a4954528e9 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sun, 26 May 2013 22:05:56 +0900 Subject: [PATCH 0411/6183] ARM: shmobile: r8a73a4: Remove init_irq declaration in machine description Commit ebafed7a ("ARM: irq: Call irqchip_init if no init_irq function is specified") removed the need to explictly setup the init_irq field in the machine description when using only irqchip_init. Remove that declaration for shmobile as well. Signed-off-by: Maxime Ripard Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a73a4.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a73a4.c b/arch/arm/mach-shmobile/setup-r8a73a4.c index 7f45c2edbca9..a8c4e41bf27a 100644 --- a/arch/arm/mach-shmobile/setup-r8a73a4.c +++ b/arch/arm/mach-shmobile/setup-r8a73a4.c @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include -#include #include #include #include @@ -194,7 +193,6 @@ static const char *r8a73a4_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(R8A73A4_DT, "Generic R8A73A4 (Flattened Device Tree)") - .init_irq = irqchip_init, .init_machine = r8a73a4_add_standard_devices_dt, .init_time = shmobile_timer_init, .dt_compat = r8a73a4_boards_compat_dt, From c7f6085f6ea7b7cf155f470431cf1b12cd999450 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 15:01:21 +0900 Subject: [PATCH 0412/6183] ARM: shmobile: ape6evm: Remove init_irq declaration in machine description Remove redundant irqchip_init() callback. The default case of NULL will result in invoking irqchip_init() anyway. Signed-off-by: Magnus Damm [ horms+renesas@verge.net.au: Trimmed patch to remove portion that updates the r8a73a4 SoC and altered the subject to use the same format as the patch that updates the r8a73a4. ] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-ape6evm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c index 5eb0caa6a7d0..1fbc39a14e25 100644 --- a/arch/arm/mach-shmobile/board-ape6evm.c +++ b/arch/arm/mach-shmobile/board-ape6evm.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -102,7 +101,6 @@ static const char *ape6evm_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(APE6EVM_DT, "ape6evm") - .init_irq = irqchip_init, .init_time = shmobile_timer_init, .init_machine = ape6evm_add_standard_devices, .dt_compat = ape6evm_boards_compat_dt, From 125332daf2e4119614c561bc8cbf1f49cd243023 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 May 2013 18:00:22 +0900 Subject: [PATCH 0413/6183] ARM: shmobile: r8a7790: Remove init_irq declaration in machine description Commit ebafed7a ("ARM: irq: Call irqchip_init if no init_irq function is specified") removed the need to explictly setup the init_irq field in the machine description when using only irqchip_init. Remove that declaration for shmobile as well. Signed-off-by: Maxime Ripard Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7790.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index 28f94752b8ff..d405dbd44b07 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include @@ -188,7 +187,6 @@ static const char *r8a7790_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(R8A7790_DT, "Generic R8A7790 (Flattened Device Tree)") - .init_irq = irqchip_init, .init_machine = r8a7790_add_standard_devices_dt, .init_time = r8a7790_timer_init, .dt_compat = r8a7790_boards_compat_dt, From 5f85052c606e38c98de28170a2df72f78931aa30 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 15:01:31 +0900 Subject: [PATCH 0414/6183] ARM: shmobile: lager: Remove init_irq declaration in machine description Remove redundant irqchip_init() callback. The default case of NULL will result in invoking irqchip_init() anyway. Signed-off-by: Magnus Damm [ horms+renesas@verge.net.au: Trimmed patch to remove portion that updates the r8a7790 SoC and altered the subject to use the same format as the patch that updates the r8a7790. ] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-lager.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index d73e21d3ea8a..1e99b17767bb 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -103,7 +102,6 @@ static const char *lager_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(LAGER_DT, "lager") - .init_irq = irqchip_init, .init_time = r8a7790_timer_init, .init_machine = lager_add_standard_devices, .dt_compat = lager_boards_compat_dt, From 7d6b8883547feacc705c476cdb7f272e309d9fb0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 May 2013 18:00:49 +0900 Subject: [PATCH 0415/6183] ARM: shmobile: sh73a0: Remove init_irq declaration in machine description Commit ebafed7a ("ARM: irq: Call irqchip_init if no init_irq function is specified") removed the need to explictly setup the init_irq field in the machine description when using only irqchip_init. Remove that declaration for shmobile as well. Signed-off-by: Maxime Ripard Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-sh73a0.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 79a6040774a4..bd9370f26978 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -975,7 +974,6 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") .map_io = sh73a0_map_io, .init_early = sh73a0_init_delay, .nr_irqs = NR_IRQS_LEGACY, - .init_irq = irqchip_init, .init_machine = sh73a0_add_standard_devices_dt, .dt_compat = sh73a0_boards_compat_dt, MACHINE_END From fc492ba58aa6642f34eba716daf6ec4d2715e492 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 15:01:40 +0900 Subject: [PATCH 0416/6183] ARM: shmobile: kzm9g: Remove init_irq declaration in machine description Remove redundant irqchip_init() callback. The default case of NULL will result in invoking irqchip_init() anyway. Signed-off-by: Magnus Damm [ horms+renesas@verge.net.au: Trimmed patch to remove portion that updates the sh73a0 SoC and altered the subject to use the same format as the patch that updates the sh73a0. ] Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-kzm9g-reference.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c index 44055fe8a45c..41092bb01ee5 100644 --- a/arch/arm/mach-shmobile/board-kzm9g-reference.c +++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -99,7 +98,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference") .map_io = sh73a0_map_io, .init_early = sh73a0_init_delay, .nr_irqs = NR_IRQS_LEGACY, - .init_irq = irqchip_init, .init_machine = kzm_init, .init_time = shmobile_timer_init, .dt_compat = kzm9g_boards_compat_dt, From a597d8df88143f7a409b260b1e89735eb0bdca05 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:41:15 +0900 Subject: [PATCH 0417/6183] ARM: shmobile: Remove unused EMEV2 auxdata and callback Replace the SoC-specific callback init_machine() with a NULL to use the default code. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-emev2.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index 6e8b6ac3c6b2..b0564ce116e5 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -434,15 +434,6 @@ void __init emev2_init_irq(void) } #ifdef CONFIG_USE_OF -static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = { - { } -}; - -static void __init emev2_add_standard_devices_dt(void) -{ - of_platform_populate(NULL, of_default_bus_match_table, - emev2_auxdata_lookup, NULL); -} static const char *emev2_boards_compat_dt[] __initdata = { "renesas,emev2", @@ -453,7 +444,6 @@ DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)") .smp = smp_ops(emev2_smp_ops), .init_early = emev2_init_delay, .nr_irqs = NR_IRQS_LEGACY, - .init_machine = emev2_add_standard_devices_dt, .dt_compat = emev2_boards_compat_dt, MACHINE_END From 88378837780166d67a11142cd6f76596c0a2d8c3 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:41:24 +0900 Subject: [PATCH 0418/6183] ARM: shmobile: Remove unused r8a7740 auxdata table Pass NULL to of_platform_populate instead of passing an empty list. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7740.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 00c5a707238b..ac29c2ee011f 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -986,16 +986,22 @@ void __init r8a7740_add_early_devices(void) #ifdef CONFIG_USE_OF -static const struct of_dev_auxdata r8a7740_auxdata_lookup[] __initconst = { - { } -}; +void __init r8a7740_add_early_devices_dt(void) +{ + shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */ + + early_platform_add_devices(r8a7740_early_devices, + ARRAY_SIZE(r8a7740_early_devices)); + + /* setup early console here as well */ + shmobile_setup_console(); +} void __init r8a7740_add_standard_devices_dt(void) { platform_add_devices(r8a7740_devices_dt, ARRAY_SIZE(r8a7740_devices_dt)); - of_platform_populate(NULL, of_default_bus_match_table, - r8a7740_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } void __init r8a7740_init_delay(void) From 40216263d3d0b9b46688a28a96daf66fe75caa28 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:41:33 +0900 Subject: [PATCH 0419/6183] ARM: shmobile: Remove unused r8a7778 auxdata and callback Replace the SoC-specific callback init_machine() with a NULL to use the default code. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7778.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c index b70bfeef2f6c..2a101ebdedf4 100644 --- a/arch/arm/mach-shmobile/setup-r8a7778.c +++ b/arch/arm/mach-shmobile/setup-r8a7778.c @@ -457,16 +457,6 @@ void __init r8a7778_init_irq_dt(void) r8a7778_init_irq_common(); } -static const struct of_dev_auxdata r8a7778_auxdata_lookup[] __initconst = { - {}, -}; - -void __init r8a7778_add_standard_devices_dt(void) -{ - of_platform_populate(NULL, of_default_bus_match_table, - r8a7778_auxdata_lookup, NULL); -} - static const char *r8a7778_compat_dt[] __initdata = { "renesas,r8a7778", NULL, @@ -475,7 +465,6 @@ static const char *r8a7778_compat_dt[] __initdata = { DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)") .init_early = r8a7778_init_delay, .init_irq = r8a7778_init_irq_dt, - .init_machine = r8a7778_add_standard_devices_dt, .init_time = shmobile_timer_init, .dt_compat = r8a7778_compat_dt, .init_late = r8a7778_init_late, From 41b0156ca5a1460f8f6dde7e57baf1b80d6a7030 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:41:46 +0900 Subject: [PATCH 0420/6183] ARM: shmobile: Remove unused r8a7779 auxdata table Pass NULL to of_platform_populate instead of passing an empty list. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7779.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 398687761f50..66d38261ecaa 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -665,10 +665,6 @@ void __init r8a7779_init_delay(void) shmobile_setup_delay(1000, 2, 4); /* Cortex-A9 @ 1000MHz */ } -static const struct of_dev_auxdata r8a7779_auxdata_lookup[] __initconst = { - {}, -}; - void __init r8a7779_add_standard_devices_dt(void) { /* clocks are setup late during boot in the case of DT */ @@ -676,8 +672,7 @@ void __init r8a7779_add_standard_devices_dt(void) platform_add_devices(r8a7779_devices_dt, ARRAY_SIZE(r8a7779_devices_dt)); - of_platform_populate(NULL, of_default_bus_match_table, - r8a7779_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static const char *r8a7779_compat_dt[] __initdata = { From 975e5af958916f8b76a8926cd4d50c04936d7079 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:41:55 +0900 Subject: [PATCH 0421/6183] ARM: shmobile: Remove unused sh7372 auxdata table Pass NULL to of_platform_populate instead of passing an empty list. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-sh7372.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 5502d624aca6..13e6fdbde0a5 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1147,10 +1147,6 @@ void __init sh7372_add_early_devices_dt(void) shmobile_setup_console(); } -static const struct of_dev_auxdata sh7372_auxdata_lookup[] __initconst = { - { } -}; - void __init sh7372_add_standard_devices_dt(void) { /* clocks are setup late during boot in the case of DT */ @@ -1159,8 +1155,7 @@ void __init sh7372_add_standard_devices_dt(void) platform_add_devices(sh7372_early_devices, ARRAY_SIZE(sh7372_early_devices)); - of_platform_populate(NULL, of_default_bus_match_table, - sh7372_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } static const char *sh7372_boards_compat_dt[] __initdata = { From ea31597fe72245985e9d2521ea7e87acf2f14252 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:42:04 +0900 Subject: [PATCH 0422/6183] ARM: shmobile: Remove unused sh73a0 auxdata table Pass NULL to of_platform_populate instead of passing an empty list. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-sh73a0.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index bd9370f26978..516c2391b47a 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -944,10 +944,6 @@ void __init sh73a0_add_early_devices(void) #ifdef CONFIG_USE_OF -static const struct of_dev_auxdata sh73a0_auxdata_lookup[] __initconst = { - {}, -}; - void __init sh73a0_add_standard_devices_dt(void) { struct platform_device_info devinfo = { .name = "cpufreq-cpu0", .id = -1, }; @@ -957,8 +953,7 @@ void __init sh73a0_add_standard_devices_dt(void) platform_add_devices(sh73a0_devices_dt, ARRAY_SIZE(sh73a0_devices_dt)); - of_platform_populate(NULL, of_default_bus_match_table, - sh73a0_auxdata_lookup, NULL); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); /* Instantiate cpufreq-cpu0 */ platform_device_register_full(&devinfo); From fdbc45dbbe5a69a2c665630ab577726e01eadf23 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 1 Jul 2013 14:42:13 +0900 Subject: [PATCH 0423/6183] ARM: shmobile: Remove redundant r8a7790 callback Replace the SoC-specific callback init_machine() with a NULL to use the default code. This cleans up the code and reduces the number of lines. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7790.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index d405dbd44b07..b7e78b9a7fdf 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -176,10 +176,6 @@ void __init r8a7790_timer_init(void) } #ifdef CONFIG_USE_OF -void __init r8a7790_add_standard_devices_dt(void) -{ - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} static const char *r8a7790_boards_compat_dt[] __initdata = { "renesas,r8a7790", @@ -187,7 +183,6 @@ static const char *r8a7790_boards_compat_dt[] __initdata = { }; DT_MACHINE_START(R8A7790_DT, "Generic R8A7790 (Flattened Device Tree)") - .init_machine = r8a7790_add_standard_devices_dt, .init_time = r8a7790_timer_init, .dt_compat = r8a7790_boards_compat_dt, MACHINE_END From 4146fa8861419ac0d2c3607168339621586f6c03 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 2 Jul 2013 18:27:33 +0900 Subject: [PATCH 0424/6183] ARM: shmobile: Remove unused EMEV2/KZM9D early console Remove EMEV2 early console code from KZM9D and instead rely on console setup during regular platform device probe time. This makes the DT code and the KZM9D board support behave the same. Signed-off-by: Magnus Damm Acked-by: Arnd Bergmann Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-kzm9d.c | 2 +- arch/arm/mach-shmobile/include/mach/emev2.h | 2 +- arch/arm/mach-shmobile/setup-emev2.c | 24 +++------------------ 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c index 4368000e1127..15900f1f8af7 100644 --- a/arch/arm/mach-shmobile/board-kzm9d.c +++ b/arch/arm/mach-shmobile/board-kzm9d.c @@ -85,7 +85,7 @@ static const char *kzm9d_boards_compat_dt[] __initdata = { DT_MACHINE_START(KZM9D_DT, "kzm9d") .smp = smp_ops(emev2_smp_ops), .map_io = emev2_map_io, - .init_early = emev2_add_early_devices, + .init_early = emev2_init_delay, .nr_irqs = NR_IRQS_LEGACY, .init_irq = emev2_init_irq, .init_machine = kzm9d_add_standard_devices, diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h index ac3751705cab..3e0c0441c782 100644 --- a/arch/arm/mach-shmobile/include/mach/emev2.h +++ b/arch/arm/mach-shmobile/include/mach/emev2.h @@ -3,7 +3,7 @@ extern void emev2_map_io(void); extern void emev2_init_irq(void); -extern void emev2_add_early_devices(void); +extern void emev2_init_delay(void); extern void emev2_add_standard_devices(void); extern void emev2_clock_init(void); extern void emev2_set_boot_vector(unsigned long value); diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index b0564ce116e5..f6edd190a6b4 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -375,14 +375,11 @@ static struct platform_device pmu_device = { .resource = pmu_resources, }; -static struct platform_device *emev2_early_devices[] __initdata = { +static struct platform_device *emev2_devices[] __initdata = { &uart0_device, &uart1_device, &uart2_device, &uart3_device, -}; - -static struct platform_device *emev2_late_devices[] __initdata = { &sti_device, &gio0_device, &gio1_device, @@ -396,29 +393,14 @@ void __init emev2_add_standard_devices(void) { emev2_clock_init(); - platform_add_devices(emev2_early_devices, - ARRAY_SIZE(emev2_early_devices)); - - platform_add_devices(emev2_late_devices, - ARRAY_SIZE(emev2_late_devices)); + platform_add_devices(emev2_devices, ARRAY_SIZE(emev2_devices)); } -static void __init emev2_init_delay(void) +void __init emev2_init_delay(void) { shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */ } -void __init emev2_add_early_devices(void) -{ - emev2_init_delay(); - - early_platform_add_devices(emev2_early_devices, - ARRAY_SIZE(emev2_early_devices)); - - /* setup early console here as well */ - shmobile_setup_console(); -} - void __init emev2_init_irq(void) { void __iomem *gic_dist_base; From 210e179da2e39c965872b941a36e55ab78328e49 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 2 Jul 2013 18:27:49 +0900 Subject: [PATCH 0425/6183] ARM: shmobile: Make EMEV2 platform devices more compact Convert the EMEV2 SoC device setup code from using very verbose resources and static platform devices to the same style as more recent boards. This reduces the size of the code. Signed-off-by: Magnus Damm Acked-by: Arnd Bergmann Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-emev2.c | 321 +++++---------------------- 1 file changed, 61 insertions(+), 260 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index f6edd190a6b4..e4b46930db52 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -62,102 +62,40 @@ void __init emev2_map_io(void) /* UART */ static struct resource uart0_resources[] = { - [0] = { - .start = 0xe1020000, - .end = 0xe1020037, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 40, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device uart0_device = { - .name = "serial8250-em", - .id = 0, - .num_resources = ARRAY_SIZE(uart0_resources), - .resource = uart0_resources, + DEFINE_RES_MEM(0xe1020000, 0x38), + DEFINE_RES_IRQ(40), }; static struct resource uart1_resources[] = { - [0] = { - .start = 0xe1030000, - .end = 0xe1030037, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 41, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device uart1_device = { - .name = "serial8250-em", - .id = 1, - .num_resources = ARRAY_SIZE(uart1_resources), - .resource = uart1_resources, + DEFINE_RES_MEM(0xe1030000, 0x38), + DEFINE_RES_IRQ(41), }; static struct resource uart2_resources[] = { - [0] = { - .start = 0xe1040000, - .end = 0xe1040037, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 42, - .flags = IORESOURCE_IRQ, - } -}; - -static struct platform_device uart2_device = { - .name = "serial8250-em", - .id = 2, - .num_resources = ARRAY_SIZE(uart2_resources), - .resource = uart2_resources, + DEFINE_RES_MEM(0xe1040000, 0x38), + DEFINE_RES_IRQ(42), }; static struct resource uart3_resources[] = { - [0] = { - .start = 0xe1050000, - .end = 0xe1050037, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 43, - .flags = IORESOURCE_IRQ, - } + DEFINE_RES_MEM(0xe1050000, 0x38), + DEFINE_RES_IRQ(43), }; -static struct platform_device uart3_device = { - .name = "serial8250-em", - .id = 3, - .num_resources = ARRAY_SIZE(uart3_resources), - .resource = uart3_resources, -}; +#define emev2_register_uart(idx) \ + platform_device_register_simple("serial8250-em", idx, \ + uart##idx##_resources, \ + ARRAY_SIZE(uart##idx##_resources)) /* STI */ static struct resource sti_resources[] = { - [0] = { - .name = "STI", - .start = 0xe0180000, - .end = 0xe0180053, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 157, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device sti_device = { - .name = "em_sti", - .id = 0, - .resource = sti_resources, - .num_resources = ARRAY_SIZE(sti_resources), + DEFINE_RES_MEM(0xe0180000, 0x54), + DEFINE_RES_IRQ(157), }; +#define emev2_register_sti() \ + platform_device_register_simple("em_sti", 0, \ + sti_resources, \ + ARRAY_SIZE(sti_resources)) /* GIO */ static struct gpio_em_config gio0_config = { @@ -167,36 +105,10 @@ static struct gpio_em_config gio0_config = { }; static struct resource gio0_resources[] = { - [0] = { - .name = "GIO_000", - .start = 0xe0050000, - .end = 0xe005002b, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "GIO_000", - .start = 0xe0050040, - .end = 0xe005005f, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = 99, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = 100, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device gio0_device = { - .name = "em_gio", - .id = 0, - .resource = gio0_resources, - .num_resources = ARRAY_SIZE(gio0_resources), - .dev = { - .platform_data = &gio0_config, - }, + DEFINE_RES_MEM(0xe0050000, 0x2c), + DEFINE_RES_MEM(0xe0050040, 0x20), + DEFINE_RES_IRQ(99), + DEFINE_RES_IRQ(100), }; static struct gpio_em_config gio1_config = { @@ -206,36 +118,10 @@ static struct gpio_em_config gio1_config = { }; static struct resource gio1_resources[] = { - [0] = { - .name = "GIO_032", - .start = 0xe0050080, - .end = 0xe00500ab, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "GIO_032", - .start = 0xe00500c0, - .end = 0xe00500df, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = 101, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = 102, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device gio1_device = { - .name = "em_gio", - .id = 1, - .resource = gio1_resources, - .num_resources = ARRAY_SIZE(gio1_resources), - .dev = { - .platform_data = &gio1_config, - }, + DEFINE_RES_MEM(0xe0050080, 0x2c), + DEFINE_RES_MEM(0xe00500c0, 0x20), + DEFINE_RES_IRQ(101), + DEFINE_RES_IRQ(102), }; static struct gpio_em_config gio2_config = { @@ -245,36 +131,10 @@ static struct gpio_em_config gio2_config = { }; static struct resource gio2_resources[] = { - [0] = { - .name = "GIO_064", - .start = 0xe0050100, - .end = 0xe005012b, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "GIO_064", - .start = 0xe0050140, - .end = 0xe005015f, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = 103, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = 104, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device gio2_device = { - .name = "em_gio", - .id = 2, - .resource = gio2_resources, - .num_resources = ARRAY_SIZE(gio2_resources), - .dev = { - .platform_data = &gio2_config, - }, + DEFINE_RES_MEM(0xe0050100, 0x2c), + DEFINE_RES_MEM(0xe0050140, 0x20), + DEFINE_RES_IRQ(103), + DEFINE_RES_IRQ(104), }; static struct gpio_em_config gio3_config = { @@ -284,36 +144,10 @@ static struct gpio_em_config gio3_config = { }; static struct resource gio3_resources[] = { - [0] = { - .name = "GIO_096", - .start = 0xe0050180, - .end = 0xe00501ab, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "GIO_096", - .start = 0xe00501c0, - .end = 0xe00501df, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = 105, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = 106, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device gio3_device = { - .name = "em_gio", - .id = 3, - .resource = gio3_resources, - .num_resources = ARRAY_SIZE(gio3_resources), - .dev = { - .platform_data = &gio3_config, - }, + DEFINE_RES_MEM(0xe0050180, 0x2c), + DEFINE_RES_MEM(0xe00501c0, 0x20), + DEFINE_RES_IRQ(105), + DEFINE_RES_IRQ(106), }; static struct gpio_em_config gio4_config = { @@ -323,77 +157,44 @@ static struct gpio_em_config gio4_config = { }; static struct resource gio4_resources[] = { - [0] = { - .name = "GIO_128", - .start = 0xe0050200, - .end = 0xe005022b, - .flags = IORESOURCE_MEM, - }, - [1] = { - .name = "GIO_128", - .start = 0xe0050240, - .end = 0xe005025f, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = 107, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = 108, - .flags = IORESOURCE_IRQ, - }, + DEFINE_RES_MEM(0xe0050200, 0x2c), + DEFINE_RES_MEM(0xe0050240, 0x20), + DEFINE_RES_IRQ(107), + DEFINE_RES_IRQ(108), }; -static struct platform_device gio4_device = { - .name = "em_gio", - .id = 4, - .resource = gio4_resources, - .num_resources = ARRAY_SIZE(gio4_resources), - .dev = { - .platform_data = &gio4_config, - }, -}; +#define emev2_register_gio(idx) \ + platform_device_register_resndata(&platform_bus, "em_gio", \ + idx, gio##idx##_resources, \ + ARRAY_SIZE(gio##idx##_resources), \ + &gio##idx##_config, \ + sizeof(struct gpio_em_config)) static struct resource pmu_resources[] = { - [0] = { - .start = 152, - .end = 152, - .flags = IORESOURCE_IRQ, - }, - [1] = { - .start = 153, - .end = 153, - .flags = IORESOURCE_IRQ, - }, + DEFINE_RES_IRQ(152), + DEFINE_RES_IRQ(153), }; -static struct platform_device pmu_device = { - .name = "arm-pmu", - .id = -1, - .num_resources = ARRAY_SIZE(pmu_resources), - .resource = pmu_resources, -}; - -static struct platform_device *emev2_devices[] __initdata = { - &uart0_device, - &uart1_device, - &uart2_device, - &uart3_device, - &sti_device, - &gio0_device, - &gio1_device, - &gio2_device, - &gio3_device, - &gio4_device, - &pmu_device, -}; +#define emev2_register_pmu() \ + platform_device_register_simple("arm-pmu", -1, \ + pmu_resources, \ + ARRAY_SIZE(pmu_resources)) void __init emev2_add_standard_devices(void) { emev2_clock_init(); - platform_add_devices(emev2_devices, ARRAY_SIZE(emev2_devices)); + emev2_register_uart(0); + emev2_register_uart(1); + emev2_register_uart(2); + emev2_register_uart(3); + emev2_register_sti(); + emev2_register_gio(0); + emev2_register_gio(1); + emev2_register_gio(2); + emev2_register_gio(3); + emev2_register_gio(4); + emev2_register_pmu(); } void __init emev2_init_delay(void) From 09cb2e366737ac70f1d7c6c0a3747a75c8f90f1e Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 8 Jul 2013 15:20:05 +0900 Subject: [PATCH 0426/6183] ARM: shmobile: Fix EMEV2 clock comment typo Update the STI timer frequency comment to 32.768 kHz to fix 37 kHz typo. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/clock-emev2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c index 4710f1847bb7..56dd0cfcddc7 100644 --- a/arch/arm/mach-shmobile/clock-emev2.c +++ b/arch/arm/mach-shmobile/clock-emev2.c @@ -221,7 +221,7 @@ void __init emev2_clock_init(void) smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE); BUG_ON(!smu_base); - /* setup STI timer to run on 37.768 kHz and deassert reset */ + /* setup STI timer to run on 32.768 kHz and deassert reset */ emev2_smu_write(0, STI_CLKSEL); emev2_smu_write(1, STI_RSTCTRL); From 54aa4c48bc0d364565e7d1c722b07314efdc2a10 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Jul 2013 01:48:34 -0700 Subject: [PATCH 0427/6183] ARM: shmobile: r8a7778: remove r8a7778_init_irq() This patch removes r8a7778_init_irq(), since no-one is using it. And now, there is no reason to have r8a7778_init_irq_common(). r8a7778_init_irq_dt() includes it. Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/include/mach/r8a7778.h | 1 - arch/arm/mach-shmobile/setup-r8a7778.c | 37 +++++-------------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/arch/arm/mach-shmobile/include/mach/r8a7778.h b/arch/arm/mach-shmobile/include/mach/r8a7778.h index 851d027a2f06..9b561bf4229f 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7778.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7778.h @@ -33,7 +33,6 @@ extern void r8a7778_add_mmc_device(struct sh_mmcif_plat_data *info); extern void r8a7778_init_late(void); extern void r8a7778_init_delay(void); -extern void r8a7778_init_irq(void); extern void r8a7778_init_irq_dt(void); extern void r8a7778_clock_init(void); extern void r8a7778_init_irq_extpin(int irlm); diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c index 2a101ebdedf4..a3a2e37b03f3 100644 --- a/arch/arm/mach-shmobile/setup-r8a7778.c +++ b/arch/arm/mach-shmobile/setup-r8a7778.c @@ -408,17 +408,25 @@ void __init r8a7778_init_irq_extpin(int irlm) &irqpin_platform_data, sizeof(irqpin_platform_data)); } +void __init r8a7778_init_delay(void) +{ + shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */ +} + +#ifdef CONFIG_USE_OF #define INT2SMSKCR0 0x82288 /* 0xfe782288 */ #define INT2SMSKCR1 0x8228c /* 0xfe78228c */ #define INT2NTSR0 0x00018 /* 0xfe700018 */ #define INT2NTSR1 0x0002c /* 0xfe70002c */ -static void __init r8a7778_init_irq_common(void) +void __init r8a7778_init_irq_dt(void) { void __iomem *base = ioremap_nocache(0xfe700000, 0x00100000); BUG_ON(!base); + irqchip_init(); + /* route all interrupts to ARM */ __raw_writel(0x73ffffff, base + INT2NTSR0); __raw_writel(0xffffffff, base + INT2NTSR1); @@ -430,33 +438,6 @@ static void __init r8a7778_init_irq_common(void) iounmap(base); } -void __init r8a7778_init_irq(void) -{ - void __iomem *gic_dist_base; - void __iomem *gic_cpu_base; - - gic_dist_base = ioremap_nocache(0xfe438000, PAGE_SIZE); - gic_cpu_base = ioremap_nocache(0xfe430000, PAGE_SIZE); - BUG_ON(!gic_dist_base || !gic_cpu_base); - - /* use GIC to handle interrupts */ - gic_init(0, 29, gic_dist_base, gic_cpu_base); - - r8a7778_init_irq_common(); -} - -void __init r8a7778_init_delay(void) -{ - shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */ -} - -#ifdef CONFIG_USE_OF -void __init r8a7778_init_irq_dt(void) -{ - irqchip_init(); - r8a7778_init_irq_common(); -} - static const char *r8a7778_compat_dt[] __initdata = { "renesas,r8a7778", NULL, From ebd9616f439a8a46b9dca9a272b342f34c5f3614 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 9 Jul 2013 19:40:16 +0900 Subject: [PATCH 0428/6183] ARM: shmobile: Remove unused mach/dma.h Remove mach-shmobile mach/dma.h since it only seems to be used on non-mach-shmobile platforms. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/include/mach/dma.h | 1 - 1 file changed, 1 deletion(-) delete mode 100644 arch/arm/mach-shmobile/include/mach/dma.h diff --git a/arch/arm/mach-shmobile/include/mach/dma.h b/arch/arm/mach-shmobile/include/mach/dma.h deleted file mode 100644 index 40a8c178f10d..000000000000 --- a/arch/arm/mach-shmobile/include/mach/dma.h +++ /dev/null @@ -1 +0,0 @@ -/* empty */ From 2c408d149299e99c89fc4be80fb4fe00a7016f02 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Thu, 27 Jun 2013 08:48:07 +0900 Subject: [PATCH 0429/6183] ARM: shmobile: Update romImage to relocate appended DTB Instead of relying of MACH_TYPE for board identification, update the romImage code to relocate an appended DTB to the beginning of RAM. This implementation is independent of ARM_APPENDED_DTB, this because it is necessary to copy the DTB to memory so the kernel can access it. Without this patch Mackerel does not boot via the Mask ROM over USB (r_usb_boot) - this since non-DT boot was broken ages ago in commit: 0ce53cd ARM: mach-shmobile: Use DT_MACHINE for mackerel Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/boot/compressed/head-shmobile.S | 43 +++++++++++++++++++-- arch/arm/mach-shmobile/include/mach/zboot.h | 2 - 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/compressed/head-shmobile.S b/arch/arm/boot/compressed/head-shmobile.S index e2d636336b7c..e7f80928949c 100644 --- a/arch/arm/boot/compressed/head-shmobile.S +++ b/arch/arm/boot/compressed/head-shmobile.S @@ -55,12 +55,47 @@ __tmp_stack: __continue: #endif /* CONFIG_ZBOOT_ROM_MMC || CONFIG_ZBOOT_ROM_SH_MOBILE_SDHI */ - /* Set board ID necessary for boot */ - ldr r7, 1f @ Set machine type register - mov r8, #0 @ pass null pointer as atag + adr r0, dtb_info + ldmia r0, {r1, r3, r4, r5, r7} + + sub r0, r0, r1 @ calculate the delta offset + add r5, r5, r0 @ _edata + + ldr lr, [r5, #0] @ check if valid DTB is present + cmp lr, r3 + bne 0f + + add r9, r7, #31 @ rounded up to a multiple + bic r9, r9, #31 @ ... of 32 bytes + + add r6, r9, r5 @ copy from _edata + add r9, r9, r4 @ to MEMORY_START + +1: ldmdb r6!, {r0 - r3, r10 - r12, lr} + cmp r6, r5 + stmdb r9!, {r0 - r3, r10 - r12, lr} + bhi 1b + + /* Success: Zero board ID, pointer to start of memory for atag/dtb */ + mov r7, #0 + mov r8, r4 b 2f -1 : .long MACH_TYPE + .align 2 +dtb_info: + .word dtb_info +#ifndef __ARMEB__ + .word 0xedfe0dd0 @ sig is 0xd00dfeed big endian +#else + .word 0xd00dfeed +#endif + .word MEMORY_START + .word _edata + .word 0x4000 @ maximum DTB size +0: + /* Failure: Zero board ID, NULL atag/dtb */ + mov r7, #0 + mov r8, #0 @ pass null pointer as atag 2 : #endif /* CONFIG_ZBOOT_ROM */ diff --git a/arch/arm/mach-shmobile/include/mach/zboot.h b/arch/arm/mach-shmobile/include/mach/zboot.h index f2d8744c1f14..c3c4669a2d72 100644 --- a/arch/arm/mach-shmobile/include/mach/zboot.h +++ b/arch/arm/mach-shmobile/include/mach/zboot.h @@ -1,7 +1,6 @@ #ifndef ZBOOT_H #define ZBOOT_H -#include #include /************************************************** @@ -11,7 +10,6 @@ **************************************************/ #ifdef CONFIG_MACH_MACKEREL -#define MACH_TYPE MACH_TYPE_MACKEREL #define MEMORY_START 0x40000000 #include "mach/head-mackerel.txt" #else From 14bd03e08831a52035e601ae85b05a4849214ec4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 4 Jul 2013 21:13:27 +0200 Subject: [PATCH 0430/6183] ARM: mach-shmobile: mackerel: Use gpio-backlight Replace the backlight callback with a gpio-backlight platform device. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-mackerel.c | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 85f51a849a50..af06753eb809 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,6 @@ #include #include #include - #include