From b7c2a75725dee9b5643a0aae3a4cb47f52e00a49 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 22 Jul 2008 22:34:29 -0700 Subject: sparc64: Fix lockdep issues in LDC protocol layer. We're calling request_irq() with a IRQs disabled. No straightforward fix exists because we want to enable these IRQs and setup state atomically before getting into the IRQ handler the first time. What happens now is that we mark the VIRQ to not be automatically enabled by request_irq(). Then we make explicit enable_irq() calls when we grab the LDC channel. This way we don't need to call request_irq() illegally under the LDC channel lock any more. Bump LDC version and release date. Signed-off-by: David S. Miller --- arch/sparc64/kernel/irq.c | 10 +++++++++- arch/sparc64/kernel/ldc.c | 38 +++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 20 deletions(-) (limited to 'arch/sparc64') diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index b441a26b..c481673 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -621,8 +621,9 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) { struct irq_handler_data *data; - struct ino_bucket *bucket; unsigned long hv_err, cookie; + struct ino_bucket *bucket; + struct irq_desc *desc; unsigned int virt_irq; bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); @@ -643,6 +644,13 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) if (unlikely(!data)) return 0; + /* In order to make the LDC channel startup sequence easier, + * especially wrt. locking, we do not let request_irq() enable + * the interrupt. + */ + desc = irq_desc + virt_irq; + desc->status |= IRQ_NOAUTOEN; + set_irq_chip_data(virt_irq, data); /* Catch accidental accesses to these things. IMAP/ICLR handling diff --git a/arch/sparc64/kernel/ldc.c b/arch/sparc64/kernel/ldc.c index 63969f6..d6898233 100644 --- a/arch/sparc64/kernel/ldc.c +++ b/arch/sparc64/kernel/ldc.c @@ -1,6 +1,6 @@ /* ldc.c: Logical Domain Channel link-layer protocol driver. * - * Copyright (C) 2007 David S. Miller + * Copyright (C) 2007, 2008 David S. Miller */ #include @@ -23,8 +23,8 @@ #define DRV_MODULE_NAME "ldc" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.0" -#define DRV_MODULE_RELDATE "June 25, 2007" +#define DRV_MODULE_VERSION "1.1" +#define DRV_MODULE_RELDATE "July 22, 2008" static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; @@ -1235,13 +1235,9 @@ int ldc_bind(struct ldc_channel *lp, const char *name) unsigned long hv_err, flags; int err = -EINVAL; - spin_lock_irqsave(&lp->lock, flags); - - if (!name) - goto out_err; - - if (lp->state != LDC_STATE_INIT) - goto out_err; + if (!name || + (lp->state != LDC_STATE_INIT)) + return -EINVAL; snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name); snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name); @@ -1250,25 +1246,32 @@ int ldc_bind(struct ldc_channel *lp, const char *name) IRQF_SAMPLE_RANDOM | IRQF_SHARED, lp->rx_irq_name, lp); if (err) - goto out_err; + return err; err = request_irq(lp->cfg.tx_irq, ldc_tx, IRQF_SAMPLE_RANDOM | IRQF_SHARED, lp->tx_irq_name, lp); - if (err) - goto out_free_rx_irq; + if (err) { + free_irq(lp->cfg.rx_irq, lp); + return err; + } + + spin_lock_irqsave(&lp->lock, flags); + + enable_irq(lp->cfg.rx_irq); + enable_irq(lp->cfg.tx_irq); lp->flags |= LDC_FLAG_REGISTERED_IRQS; err = -ENODEV; hv_err = sun4v_ldc_tx_qconf(lp->id, 0, 0); if (hv_err) - goto out_free_tx_irq; + goto out_free_irqs; hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries); if (hv_err) - goto out_free_tx_irq; + goto out_free_irqs; hv_err = sun4v_ldc_rx_qconf(lp->id, 0, 0); if (hv_err) @@ -1304,14 +1307,11 @@ out_unmap_rx: out_unmap_tx: sun4v_ldc_tx_qconf(lp->id, 0, 0); -out_free_tx_irq: +out_free_irqs: lp->flags &= ~LDC_FLAG_REGISTERED_IRQS; free_irq(lp->cfg.tx_irq, lp); - -out_free_rx_irq: free_irq(lp->cfg.rx_irq, lp); -out_err: spin_unlock_irqrestore(&lp->lock, flags); return err; -- cgit v1.1 From 7ae93f51d7fa8b9130d47e0b7d17979a165c5bc3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 23 Jul 2008 16:21:07 -0700 Subject: sparc64: Fix cpufreq notifier registry. Based upon a report by Daniel Smolik. We do it too early, which triggers a BUG in cpufreq_register_notifier(). Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'arch/sparc64') diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index bedc4c1..a0c6a97 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -884,6 +884,16 @@ static struct notifier_block sparc64_cpufreq_notifier_block = { .notifier_call = sparc64_cpufreq_notifier }; +static int __init register_sparc64_cpufreq_notifier(void) +{ + + cpufreq_register_notifier(&sparc64_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + return 0; +} + +core_initcall(register_sparc64_cpufreq_notifier); + #endif /* CONFIG_CPU_FREQ */ static int sparc64_next_event(unsigned long delta, @@ -1050,11 +1060,6 @@ void __init time_init(void) sparc64_clockevent.mult, sparc64_clockevent.shift); setup_sparc64_timer(); - -#ifdef CONFIG_CPU_FREQ - cpufreq_register_notifier(&sparc64_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); -#endif } unsigned long long sched_clock(void) -- cgit v1.1