| From foo@baz Tue Oct 28 11:21:06 CST 2014 |
| From: Sowmini Varadhan <sowmini.varadhan@oracle.com> |
| Date: Tue, 16 Sep 2014 11:37:08 -0400 |
| Subject: sparc64: Move request_irq() from ldc_bind() to ldc_alloc() |
| |
| From: Sowmini Varadhan <sowmini.varadhan@oracle.com> |
| |
| [ Upstream commit c21c4ab0d6921f7160a43216fa6973b5924de561 ] |
| |
| The request_irq() needs to be done from ldc_alloc() |
| to avoid the following (caught by lockdep) |
| |
| [00000000004a0738] __might_sleep+0xf8/0x120 |
| [000000000058bea4] kmem_cache_alloc_trace+0x184/0x2c0 |
| [00000000004faf80] request_threaded_irq+0x80/0x160 |
| [000000000044f71c] ldc_bind+0x7c/0x220 |
| [0000000000452454] vio_port_up+0x54/0xe0 |
| [00000000101f6778] probe_disk+0x38/0x220 [sunvdc] |
| [00000000101f6b8c] vdc_port_probe+0x22c/0x300 [sunvdc] |
| [0000000000451a88] vio_device_probe+0x48/0x60 |
| [000000000074c56c] really_probe+0x6c/0x300 |
| [000000000074c83c] driver_probe_device+0x3c/0xa0 |
| [000000000074c92c] __driver_attach+0x8c/0xa0 |
| [000000000074a6ec] bus_for_each_dev+0x6c/0xa0 |
| [000000000074c1dc] driver_attach+0x1c/0x40 |
| [000000000074b0fc] bus_add_driver+0xbc/0x280 |
| |
| Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> |
| Acked-by: Dwight Engen <dwight.engen@oracle.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/sparc/include/asm/ldc.h | 5 +++-- |
| arch/sparc/kernel/ds.c | 4 ++-- |
| arch/sparc/kernel/ldc.c | 41 +++++++++++++++++++++-------------------- |
| arch/sparc/kernel/viohs.c | 4 ++-- |
| 4 files changed, 28 insertions(+), 26 deletions(-) |
| |
| --- a/arch/sparc/include/asm/ldc.h |
| +++ b/arch/sparc/include/asm/ldc.h |
| @@ -53,13 +53,14 @@ struct ldc_channel; |
| /* Allocate state for a channel. */ |
| struct ldc_channel *ldc_alloc(unsigned long id, |
| const struct ldc_channel_config *cfgp, |
| - void *event_arg); |
| + void *event_arg, |
| + const char *name); |
| |
| /* Shut down and free state for a channel. */ |
| void ldc_free(struct ldc_channel *lp); |
| |
| /* Register TX and RX queues of the link with the hypervisor. */ |
| -int ldc_bind(struct ldc_channel *lp, const char *name); |
| +int ldc_bind(struct ldc_channel *lp); |
| |
| /* For non-RAW protocols we need to complete a handshake before |
| * communication can proceed. ldc_connect() does that, if the |
| --- a/arch/sparc/kernel/ds.c |
| +++ b/arch/sparc/kernel/ds.c |
| @@ -1200,14 +1200,14 @@ static int ds_probe(struct vio_dev *vdev |
| ds_cfg.tx_irq = vdev->tx_irq; |
| ds_cfg.rx_irq = vdev->rx_irq; |
| |
| - lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp); |
| + lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp, "DS"); |
| if (IS_ERR(lp)) { |
| err = PTR_ERR(lp); |
| goto out_free_ds_states; |
| } |
| dp->lp = lp; |
| |
| - err = ldc_bind(lp, "DS"); |
| + err = ldc_bind(lp); |
| if (err) |
| goto out_free_ldc; |
| |
| --- a/arch/sparc/kernel/ldc.c |
| +++ b/arch/sparc/kernel/ldc.c |
| @@ -1078,7 +1078,8 @@ static void ldc_iommu_release(struct ldc |
| |
| struct ldc_channel *ldc_alloc(unsigned long id, |
| const struct ldc_channel_config *cfgp, |
| - void *event_arg) |
| + void *event_arg, |
| + const char *name) |
| { |
| struct ldc_channel *lp; |
| const struct ldc_mode_ops *mops; |
| @@ -1093,6 +1094,8 @@ struct ldc_channel *ldc_alloc(unsigned l |
| err = -EINVAL; |
| if (!cfgp) |
| goto out_err; |
| + if (!name) |
| + goto out_err; |
| |
| switch (cfgp->mode) { |
| case LDC_MODE_RAW: |
| @@ -1185,6 +1188,21 @@ struct ldc_channel *ldc_alloc(unsigned l |
| |
| INIT_HLIST_HEAD(&lp->mh_list); |
| |
| + snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name); |
| + snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name); |
| + |
| + err = request_irq(lp->cfg.rx_irq, ldc_rx, 0, |
| + lp->rx_irq_name, lp); |
| + if (err) |
| + goto out_free_txq; |
| + |
| + err = request_irq(lp->cfg.tx_irq, ldc_tx, 0, |
| + lp->tx_irq_name, lp); |
| + if (err) { |
| + free_irq(lp->cfg.rx_irq, lp); |
| + goto out_free_txq; |
| + } |
| + |
| return lp; |
| |
| out_free_txq: |
| @@ -1237,31 +1255,14 @@ EXPORT_SYMBOL(ldc_free); |
| * state. This does not initiate a handshake, ldc_connect() does |
| * that. |
| */ |
| -int ldc_bind(struct ldc_channel *lp, const char *name) |
| +int ldc_bind(struct ldc_channel *lp) |
| { |
| unsigned long hv_err, flags; |
| int err = -EINVAL; |
| |
| - if (!name || |
| - (lp->state != LDC_STATE_INIT)) |
| + if (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); |
| - |
| - err = request_irq(lp->cfg.rx_irq, ldc_rx, 0, |
| - lp->rx_irq_name, lp); |
| - if (err) |
| - return err; |
| - |
| - err = request_irq(lp->cfg.tx_irq, ldc_tx, 0, |
| - lp->tx_irq_name, lp); |
| - if (err) { |
| - free_irq(lp->cfg.rx_irq, lp); |
| - return err; |
| - } |
| - |
| - |
| spin_lock_irqsave(&lp->lock, flags); |
| |
| enable_irq(lp->cfg.rx_irq); |
| --- a/arch/sparc/kernel/viohs.c |
| +++ b/arch/sparc/kernel/viohs.c |
| @@ -714,7 +714,7 @@ int vio_ldc_alloc(struct vio_driver_stat |
| cfg.tx_irq = vio->vdev->tx_irq; |
| cfg.rx_irq = vio->vdev->rx_irq; |
| |
| - lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg); |
| + lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg, vio->name); |
| if (IS_ERR(lp)) |
| return PTR_ERR(lp); |
| |
| @@ -746,7 +746,7 @@ void vio_port_up(struct vio_driver_state |
| |
| err = 0; |
| if (state == LDC_STATE_INIT) { |
| - err = ldc_bind(vio->lp, vio->name); |
| + err = ldc_bind(vio->lp); |
| if (err) |
| printk(KERN_WARNING "%s: Port %lu bind failed, " |
| "err=%d\n", |