From 3ad2f3fbb961429d2aa627465ae4829758bc7e07 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Feb 2010 08:01:28 +0800 Subject: tree-wide: Assorted spelling fixes In particular, several occurances of funny versions of 'success', 'unknown', 'therefore', 'acknowledge', 'argument', 'achieve', 'address', 'beginning', 'desirable', 'separate' and 'necessary' are fixed. Signed-off-by: Daniel Mack Cc: Joe Perches Cc: Junio C Hamano Signed-off-by: Jiri Kosina --- drivers/infiniband/hw/ehca/ehca_qes.h | 4 ++-- drivers/infiniband/hw/ehca/ehca_reqs.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h index 5d28e3e98a20..90c4efa67586 100644 --- a/drivers/infiniband/hw/ehca/ehca_qes.h +++ b/drivers/infiniband/hw/ehca/ehca_qes.h @@ -46,7 +46,7 @@ #include "ehca_tools.h" -/* virtual scatter gather entry to specify remote adresses with length */ +/* virtual scatter gather entry to specify remote addresses with length */ struct ehca_vsgentry { u64 vaddr; u32 lkey; @@ -148,7 +148,7 @@ struct ehca_wqe { u32 immediate_data; union { struct { - u64 remote_virtual_adress; + u64 remote_virtual_address; u32 rkey; u32 reserved; u64 atomic_1st_op_dma_len; diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index e3ec7fdd67bd..9a3fbfca9b41 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -269,7 +269,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, /* no break is intentional here */ case IB_QPT_RC: /* TODO: atomic not implemented */ - wqe_p->u.nud.remote_virtual_adress = + wqe_p->u.nud.remote_virtual_address = send_wr->wr.rdma.remote_addr; wqe_p->u.nud.rkey = send_wr->wr.rdma.rkey; -- cgit v1.2.3-59-g8ed1b From 2542322485be45853cc72d542d8ed84fae82c981 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Thu, 11 Feb 2010 15:40:29 -0800 Subject: RDMA/cxgb3: Remove BUG_ON() on CQ rearm failure Failure to rearm a CQ means the cxgb3 device is wedged, but we shouldn't kill the whole system with a BUG_ON() if this happens. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 0677fc7dfd51..8837d56f9c92 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -109,7 +109,6 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq, while (!CQ_VLD_ENTRY(rptr, cq->size_log2, cqe)) { udelay(1); if (i++ > 1000000) { - BUG_ON(1); printk(KERN_ERR "%s: stalled rnic\n", rdev_p->dev_name); return -EIO; -- cgit v1.2.3-59-g8ed1b From 757bebb3f989f10acc6f105e89305b0d19aa7c55 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 11 Feb 2010 15:40:40 -0800 Subject: IPoIB: Remove TX moderation settings from ethtool support As of commit f56bcd8 ("IPoIB: Use separate CQ for UD send completions"), there are no TX interrupts. Change the ethtool code not to report TX moderation settings, so users will not be misled to think they can control TX interrupt moderation. Pointed out by Alex Vainman Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_ethtool.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index e9795f60e5d6..d10b4ec68d28 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -55,9 +55,7 @@ static int ipoib_get_coalesce(struct net_device *dev, struct ipoib_dev_priv *priv = netdev_priv(dev); coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs; - coal->tx_coalesce_usecs = priv->ethtool.coalesce_usecs; coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames; - coal->tx_max_coalesced_frames = priv->ethtool.max_coalesced_frames; return 0; } @@ -69,10 +67,8 @@ static int ipoib_set_coalesce(struct net_device *dev, int ret; /* - * Since IPoIB uses a single CQ for both rx and tx, we assume - * that rx params dictate the configuration. These values are - * saved in the private data and returned when ipoib_get_coalesce() - * is called. + * These values are saved in the private data and returned + * when ipoib_get_coalesce() is called */ if (coal->rx_coalesce_usecs > 0xffff || coal->rx_max_coalesced_frames > 0xffff) @@ -85,8 +81,6 @@ static int ipoib_set_coalesce(struct net_device *dev, return ret; } - coal->tx_coalesce_usecs = coal->rx_coalesce_usecs; - coal->tx_max_coalesced_frames = coal->rx_max_coalesced_frames; priv->ethtool.coalesce_usecs = coal->rx_coalesce_usecs; priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames; -- cgit v1.2.3-59-g8ed1b From ccbe9f0b11b137c9453771a7ca3bf417dc7ce152 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 11 Feb 2010 15:40:48 -0800 Subject: RDMA: Use rlimit helpers Make sure compiler won't do weird things with limits by using the rlimit helpers added in 3e10e716 ("resource: add helpers for fetching rlimits"). E.g. fetching them twice may return 2 different values after writable limits are implemented. Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Roland Dreier --- drivers/infiniband/core/umem.c | 2 +- drivers/infiniband/hw/ipath/ipath_user_pages.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 6f7c096abf13..4f906f0614f0 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -136,7 +136,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, down_write(¤t->mm->mmap_sem); locked = npages + current->mm->locked_vm; - lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; + lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { ret = -ENOMEM; diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c index 82878e348627..eb7d59abd12d 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_pages.c +++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c @@ -59,8 +59,7 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages, size_t got; int ret; - lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> - PAGE_SHIFT; + lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; if (num_pages > lock_limit) { ret = -ENOMEM; -- cgit v1.2.3-59-g8ed1b From a478868a1b891da8f3c67c1b933e870df89dca80 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 27 Jan 2010 13:57:03 +0000 Subject: IB/mlx4: Simplify retrieval of ib_device struct ib_qp already holds a pointer to the ib device. No need to dive to the hw device object to retrieve it. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx4/qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 2a97c964b9ef..b377671264e9 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1214,7 +1214,7 @@ out: static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, void *wqe, unsigned *mlx_seg_len) { - struct ib_device *ib_dev = &to_mdev(sqp->qp.ibqp.device)->ib_dev; + struct ib_device *ib_dev = sqp->qp.ibqp.device; struct mlx4_wqe_mlx_seg *mlx = wqe; struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); -- cgit v1.2.3-59-g8ed1b From 25ef756385ce01834504977c22bcce8d8f000e5b Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 27 Jan 2010 17:01:56 +0000 Subject: IB/ehca: Do not turn off irqs in tasklet context The irq_spinlock is only taken in tasklet context, so it is safe not to disable hardware interrupts. Signed-off-by: Alexander Schmidt Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 42be0b15084b..b2b6fea2b141 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -548,11 +548,10 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) struct ehca_eq *eq = &shca->eq; struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache; u64 eqe_value, ret; - unsigned long flags; int eqe_cnt, i; int eq_empty = 0; - spin_lock_irqsave(&eq->irq_spinlock, flags); + spin_lock(&eq->irq_spinlock); if (is_irq) { const int max_query_cnt = 100; int query_cnt = 0; @@ -643,7 +642,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) } while (1); unlock_irq_spinlock: - spin_unlock_irqrestore(&eq->irq_spinlock, flags); + spin_unlock(&eq->irq_spinlock); } void ehca_tasklet_eq(unsigned long data) -- cgit v1.2.3-59-g8ed1b From fa55e30bc35bf4ec5a7304a537c0ce5438e908e2 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Wed, 27 Jan 2010 17:03:08 +0000 Subject: IB/ehca: Allow access for ib_query_qp() The max_dest_rd_atomic and max_qp_rd_atomic values are properly returned by query_qp(), so there should not be an error returned when they are queried. Signed-off-by: Alexander Schmidt Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_qp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 0338f1fabe8a..b105f664d3ef 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -55,9 +55,7 @@ static struct kmem_cache *qp_cache; /* * attributes not supported by query qp */ -#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \ - IB_QP_MAX_QP_RD_ATOMIC | \ - IB_QP_ACCESS_FLAGS | \ +#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_ACCESS_FLAGS | \ IB_QP_EN_SQD_ASYNC_NOTIFY) /* -- cgit v1.2.3-59-g8ed1b From 45e354e3f235ecb51e16576d6668c43cddbb6e68 Mon Sep 17 00:00:00 2001 From: Alexander Schmidt Date: Tue, 16 Feb 2010 08:59:50 +0000 Subject: IB/ehca: Require in_wc in process_mad() If the caller does not pass a valid in_wc to process_mad(), return MAD failure status, as it is not possible to generate a valid MAD redirect response (and redirects are the only MAD responses ehca generates). Signed-off-by: Alexander Schmidt Signed-off-by: Roland Dreier --- drivers/infiniband/hw/ehca/ehca_sqp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c index 8c1213f8916a..dba8f9f8b996 100644 --- a/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -222,7 +222,7 @@ int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, { int ret; - if (!port_num || port_num > ibdev->phys_port_cnt) + if (!port_num || port_num > ibdev->phys_port_cnt || !in_wc) return IB_MAD_RESULT_FAILURE; /* accept only pma request */ -- cgit v1.2.3-59-g8ed1b From 6e10d2e407542605b2bdca43dc88c35fa8bd24b2 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Fri, 12 Feb 2010 19:55:03 +0000 Subject: RDMA/nes: Use atomic counters for CM listener create and destroy After running long iterative MPI tests, sometimes ethtool reports a "CM Destroy Listener" count more than the "CM Create Listener" count. This inconsistency is fixed by making counter variables atomic. Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes.h | 4 ++-- drivers/infiniband/hw/nes/nes_cm.c | 8 ++++---- drivers/infiniband/hw/nes/nes_nic.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index 98840564bb2f..cffdac4a899f 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -193,8 +193,8 @@ extern u32 cm_packets_created; extern u32 cm_packets_received; extern u32 cm_packets_dropped; extern u32 cm_packets_retrans; -extern u32 cm_listens_created; -extern u32 cm_listens_destroyed; +extern atomic_t cm_listens_created; +extern atomic_t cm_listens_destroyed; extern u32 cm_backlog_drops; extern atomic_t cm_loopbacks; extern atomic_t cm_nodes_created; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 39468c277036..debd92c53d89 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -67,8 +67,8 @@ u32 cm_packets_dropped; u32 cm_packets_retrans; u32 cm_packets_created; u32 cm_packets_received; -u32 cm_listens_created; -u32 cm_listens_destroyed; +atomic_t cm_listens_created; +atomic_t cm_listens_destroyed; u32 cm_backlog_drops; atomic_t cm_loopbacks; atomic_t cm_nodes_created; @@ -1042,7 +1042,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, kfree(listener); listener = NULL; ret = 0; - cm_listens_destroyed++; + atomic_inc(&cm_listens_destroyed); } else { spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); } @@ -3172,7 +3172,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog) g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node); return err; } - cm_listens_created++; + atomic_inc(&cm_listens_created); } cm_id->add_ref(cm_id); diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index ab1102780186..3d550dc77d0d 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1230,8 +1230,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, target_stat_values[++index] = cm_packets_received; target_stat_values[++index] = cm_packets_dropped; target_stat_values[++index] = cm_packets_retrans; - target_stat_values[++index] = cm_listens_created; - target_stat_values[++index] = cm_listens_destroyed; + target_stat_values[++index] = atomic_read(&cm_listens_created); + target_stat_values[++index] = atomic_read(&cm_listens_destroyed); target_stat_values[++index] = cm_backlog_drops; target_stat_values[++index] = atomic_read(&cm_loopbacks); target_stat_values[++index] = atomic_read(&cm_nodes_created); -- cgit v1.2.3-59-g8ed1b From 43093b941283b1b0c30213fe0f4f6f65c94d2d63 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Fri, 12 Feb 2010 19:57:04 +0000 Subject: RDMA/nes: Fix crash when listener destroyed during loopback setup When a listener is destroyed and there is an MPA response pending for loopback connection, the active side cm_node gets destroyed twice: once in cm_event_connect_error() and again in nes_accept()/nes_reject(). Increment the cm_node's refcount so it's not destroyed by cm_event_connect_error(). Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index debd92c53d89..2a49ee40b520 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1011,9 +1011,10 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, event.cm_info.loc_port = loopback->loc_port; event.cm_info.cm_id = loopback->cm_id; + add_ref_cm_node(loopback); + loopback->state = NES_CM_STATE_CLOSED; cm_event_connect_error(&event); cm_node->state = NES_CM_STATE_LISTENER_DESTROYED; - loopback->state = NES_CM_STATE_CLOSED; rem_ref_cm_node(cm_node->cm_core, cm_node); -- cgit v1.2.3-59-g8ed1b From 30b172ff8eb025525ad7b32d1935554930cc5625 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Fri, 12 Feb 2010 19:58:05 +0000 Subject: RDMA/nes: Multiple disconnects cause crash during AE handling There is a double disconnect during AE processing, causing crashes. While fixing the crash, also simplify the AE handling code. Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 88 ++++++++++++-------------------------- 1 file changed, 28 insertions(+), 60 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index b1c2cbb88f09..310cc7cab396 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -3352,8 +3352,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, u16 async_event_id; u8 tcp_state; u8 iwarp_state; - int must_disconn = 1; - int must_terminate = 0; struct ib_event ibevent; nes_debug(NES_DBG_AEQ, "\n"); @@ -3367,6 +3365,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, BUG_ON(!context); } + /* context is nesqp unless async_event_id == CQ ERROR */ + nesqp = (struct nes_qp *)(unsigned long)context; async_event_id = (u16)aeq_info; tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; @@ -3378,8 +3378,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, switch (async_event_id) { case NES_AEQE_AEID_LLP_FIN_RECEIVED: - nesqp = (struct nes_qp *)(unsigned long)context; - if (nesqp->term_flags) return; /* Ignore it, wait for close complete */ @@ -3394,79 +3392,48 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, async_event_id, nesqp->last_aeq, tcp_state); } - if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) || - (nesqp->ibqp_state != IB_QPS_RTS)) { - /* FIN Received but tcp state or IB state moved on, - should expect a close complete */ - return; - } - + break; case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: - nesqp = (struct nes_qp *)(unsigned long)context; if (nesqp->term_flags) { nes_terminate_done(nesqp, 0); return; } + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; + spin_unlock_irqrestore(&nesqp->lock, flags); + nes_hw_modify_qp(nesdev, nesqp, NES_CQP_QP_IWARP_STATE_CLOSING, 0, 0); + nes_cm_disconn(nesqp); + break; - case NES_AEQE_AEID_LLP_CONNECTION_RESET: case NES_AEQE_AEID_RESET_SENT: - nesqp = (struct nes_qp *)(unsigned long)context; - if (async_event_id == NES_AEQE_AEID_RESET_SENT) { - tcp_state = NES_AEQE_TCP_STATE_CLOSED; - } + tcp_state = NES_AEQE_TCP_STATE_CLOSED; spin_lock_irqsave(&nesqp->lock, flags); nesqp->hw_iwarp_state = iwarp_state; nesqp->hw_tcp_state = tcp_state; nesqp->last_aeq = async_event_id; - - if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) || - (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) { - nesqp->hte_added = 0; - next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE; - } - - if ((nesqp->ibqp_state == IB_QPS_RTS) && - ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || - (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { - switch (nesqp->hw_iwarp_state) { - case NES_AEQE_IWARP_STATE_RTS: - next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING; - nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; - break; - case NES_AEQE_IWARP_STATE_TERMINATE: - must_disconn = 0; /* terminate path takes care of disconn */ - if (nesqp->term_flags == 0) - must_terminate = 1; - break; - } - } else { - if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) { - /* FIN Received but ib state not RTS, - close complete will be on its way */ - must_disconn = 0; - } - } + nesqp->hte_added = 0; spin_unlock_irqrestore(&nesqp->lock, flags); + next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE; + nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); + nes_cm_disconn(nesqp); + break; - if (must_terminate) - nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); - else if (must_disconn) { - if (next_iwarp_state) { - nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X\n", - nesqp->hwqp.qp_id, next_iwarp_state); - nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); - } - nes_cm_disconn(nesqp); - } + case NES_AEQE_AEID_LLP_CONNECTION_RESET: + if (atomic_read(&nesqp->close_timer_started)) + return; + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = iwarp_state; + nesqp->hw_tcp_state = tcp_state; + nesqp->last_aeq = async_event_id; + spin_unlock_irqrestore(&nesqp->lock, flags); + nes_cm_disconn(nesqp); break; case NES_AEQE_AEID_TERMINATE_SENT: - nesqp = (struct nes_qp *)(unsigned long)context; nes_terminate_send_fin(nesdev, nesqp, aeqe); break; case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED: - nesqp = (struct nes_qp *)(unsigned long)context; nes_terminate_received(nesdev, nesqp, aeqe); break; @@ -3480,7 +3447,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER: case NES_AEQE_AEID_AMP_BOUNDS_VIOLATION: case NES_AEQE_AEID_AMP_TO_WRAP: - nesqp = (struct nes_qp *)(unsigned long)context; + printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_ACCESS_ERR\n", + nesqp->hwqp.qp_id, async_event_id); nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_ACCESS_ERR); break; @@ -3488,7 +3456,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, case NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL: case NES_AEQE_AEID_DDP_UBE_INVALID_MO: case NES_AEQE_AEID_DDP_UBE_INVALID_QN: - nesqp = (struct nes_qp *)(unsigned long)context; if (iwarp_opcode(nesqp, aeq_info) > IWARP_OPCODE_TERM) { aeq_info &= 0xffff0000; aeq_info |= NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE; @@ -3530,7 +3497,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, case NES_AEQE_AEID_STAG_ZERO_INVALID: case NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST: case NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP: - nesqp = (struct nes_qp *)(unsigned long)context; + printk(KERN_ERR PFX "QP[%u] async_event_id=0x%04X IB_EVENT_QP_FATAL\n", + nesqp->hwqp.qp_id, async_event_id); nes_terminate_connection(nesdev, nesqp, aeqe, IB_EVENT_QP_FATAL); break; -- cgit v1.2.3-59-g8ed1b From 831d06cf5b036a1ed14e412e9311c5e23075ed8d Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 4 Feb 2010 11:25:07 +0000 Subject: RDMA/nes: Change WQ overflow return code Change the nes driver to return -ENOMEM on SQ/RQ overflow to match the return code of other RDMA HW drivers (e.g cxgb3, ehca, mlx4, mthca). Signed-off-by: Or Gerlitz Acked-by: Chien Tung Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 64d3136e3747..815725f886c4 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -228,7 +228,7 @@ static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw, /* Check for SQ overflow */ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { spin_unlock_irqrestore(&nesqp->lock, flags); - return -EINVAL; + return -ENOMEM; } wqe = &nesqp->hwqp.sq_vbase[head]; @@ -3294,7 +3294,7 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, /* Check for SQ overflow */ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) { - err = -EINVAL; + err = -ENOMEM; break; } @@ -3577,7 +3577,7 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr, } /* Check for RQ overflow */ if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) { - err = -EINVAL; + err = -ENOMEM; break; } -- cgit v1.2.3-59-g8ed1b From 1cef4659850eeb862c248c7670e404d7a1711ed1 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:17:11 +0000 Subject: IB/iser: Revert commit bba7ebb "avoid recv buffer exhaustion" We will make a major change in the recv buffer posting logic, after which the problem commit bba7ebb "avoid recv buffer exhaustion caused by unexpected PDUs" comes to solve doesn't exist any more, so revert it. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 3 - drivers/infiniband/ulp/iser/iser_initiator.c | 132 +++++++++------------------ drivers/infiniband/ulp/iser/iser_verbs.c | 1 - 3 files changed, 41 insertions(+), 95 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 9d529cae1f0d..e8dfdcfa1daf 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -252,9 +252,6 @@ struct iser_conn { wait_queue_head_t wait; /* waitq for conn/disconn */ atomic_t post_recv_buf_count; /* posted rx count */ atomic_t post_send_buf_count; /* posted tx count */ - atomic_t unexpected_pdu_count;/* count of received * - * unexpected pdus * - * not yet retired */ char name[ISER_OBJECT_NAME_SIZE]; struct iser_page_vec *page_vec; /* represents SG to fmr maps* * maps serialized as tx is*/ diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 9de640200ad3..5f42fbe3080c 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -183,8 +183,14 @@ static int iser_post_receive_control(struct iscsi_conn *conn) struct iser_regd_buf *regd_data; struct iser_dto *recv_dto = NULL; struct iser_device *device = iser_conn->ib_conn->device; - int rx_data_size, err; - int posts, outstanding_unexp_pdus; + int rx_data_size, err = 0; + + rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); + if (rx_desc == NULL) { + iser_err("Failed to alloc desc for post recv\n"); + return -ENOMEM; + } + rx_desc->type = ISCSI_RX; /* for the login sequence we must support rx of upto 8K; login is done * after conn create/bind (connect) and conn stop/bind (reconnect), @@ -195,80 +201,46 @@ static int iser_post_receive_control(struct iscsi_conn *conn) else /* FIXME till user space sets conn->max_recv_dlength correctly */ rx_data_size = 128; - outstanding_unexp_pdus = - atomic_xchg(&iser_conn->ib_conn->unexpected_pdu_count, 0); - - /* - * in addition to the response buffer, replace those consumed by - * unexpected pdus. - */ - for (posts = 0; posts < 1 + outstanding_unexp_pdus; posts++) { - rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); - if (rx_desc == NULL) { - iser_err("Failed to alloc desc for post recv %d\n", - posts); - err = -ENOMEM; - goto post_rx_cache_alloc_failure; - } - rx_desc->type = ISCSI_RX; - rx_desc->data = kmalloc(rx_data_size, GFP_NOIO); - if (rx_desc->data == NULL) { - iser_err("Failed to alloc data buf for post recv %d\n", - posts); - err = -ENOMEM; - goto post_rx_kmalloc_failure; - } + rx_desc->data = kmalloc(rx_data_size, GFP_NOIO); + if (rx_desc->data == NULL) { + iser_err("Failed to alloc data buf for post recv\n"); + err = -ENOMEM; + goto post_rx_kmalloc_failure; + } - recv_dto = &rx_desc->dto; - recv_dto->ib_conn = iser_conn->ib_conn; - recv_dto->regd_vector_len = 0; + recv_dto = &rx_desc->dto; + recv_dto->ib_conn = iser_conn->ib_conn; + recv_dto->regd_vector_len = 0; - regd_hdr = &rx_desc->hdr_regd_buf; - memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); - regd_hdr->device = device; - regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */ - regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN; + regd_hdr = &rx_desc->hdr_regd_buf; + memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); + regd_hdr->device = device; + regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */ + regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN; - iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE); + iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE); - iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0); + iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0); - regd_data = &rx_desc->data_regd_buf; - memset(regd_data, 0, sizeof(struct iser_regd_buf)); - regd_data->device = device; - regd_data->virt_addr = rx_desc->data; - regd_data->data_size = rx_data_size; + regd_data = &rx_desc->data_regd_buf; + memset(regd_data, 0, sizeof(struct iser_regd_buf)); + regd_data->device = device; + regd_data->virt_addr = rx_desc->data; + regd_data->data_size = rx_data_size; - iser_reg_single(device, regd_data, DMA_FROM_DEVICE); + iser_reg_single(device, regd_data, DMA_FROM_DEVICE); - iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0); + iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0); - err = iser_post_recv(rx_desc); - if (err) { - iser_err("Failed iser_post_recv for post %d\n", posts); - goto post_rx_post_recv_failure; - } - } - /* all posts successful */ - return 0; + err = iser_post_recv(rx_desc); + if (!err) + return 0; -post_rx_post_recv_failure: + /* iser_post_recv failed */ iser_dto_buffs_release(recv_dto); kfree(rx_desc->data); post_rx_kmalloc_failure: kmem_cache_free(ig.desc_cache, rx_desc); -post_rx_cache_alloc_failure: - if (posts > 0) { - /* - * response buffer posted, but did not replace all unexpected - * pdu recv bufs. Ignore error, retry occurs next send - */ - outstanding_unexp_pdus -= (posts - 1); - err = 0; - } - atomic_add(outstanding_unexp_pdus, - &iser_conn->ib_conn->unexpected_pdu_count); - return err; } @@ -302,10 +274,8 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) struct iscsi_iser_conn *iser_conn = conn->dd_data; int i; - /* - * FIXME this value should be declared to the target during login with - * the MaxOutstandingUnexpectedPDUs key when supported - */ + /* no need to keep it in a var, we are after login so if this should + * be negotiated, by now the result should be available here */ int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS; iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num); @@ -507,7 +477,6 @@ int iser_send_control(struct iscsi_conn *conn, int err = 0; struct iser_regd_buf *regd_buf; struct iser_device *device; - unsigned char opcode; if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); @@ -542,15 +511,10 @@ int iser_send_control(struct iscsi_conn *conn, data_seg_len); } - opcode = task->hdr->opcode & ISCSI_OPCODE_MASK; - - /* post recv buffer for response if one is expected */ - if (!(opcode == ISCSI_OP_NOOP_OUT && task->hdr->itt == RESERVED_ITT)) { - if (iser_post_receive_control(conn) != 0) { - iser_err("post_rcv_buff failed!\n"); - err = -ENOMEM; - goto send_control_error; - } + if (iser_post_receive_control(conn) != 0) { + iser_err("post_rcv_buff failed!\n"); + err = -ENOMEM; + goto send_control_error; } err = iser_post_send(mdesc); @@ -621,20 +585,6 @@ void iser_rcv_completion(struct iser_desc *rx_desc, * parallel to the execution of iser_conn_term. So the code that waits * * for the posted rx bufs refcount to become zero handles everything */ atomic_dec(&conn->ib_conn->post_recv_buf_count); - - /* - * if an unexpected PDU was received then the recv wr consumed must - * be replaced, this is done in the next send of a control-type PDU - */ - if (opcode == ISCSI_OP_NOOP_IN && hdr->itt == RESERVED_ITT) { - /* nop-in with itt = 0xffffffff */ - atomic_inc(&conn->ib_conn->unexpected_pdu_count); - } - else if (opcode == ISCSI_OP_ASYNC_EVENT) { - /* asyncronous message */ - atomic_inc(&conn->ib_conn->unexpected_pdu_count); - } - /* a reject PDU consumes the recv buf posted for the response */ } void iser_snd_completion(struct iser_desc *tx_desc) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 8579f32ce38e..7092503a10e3 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -491,7 +491,6 @@ void iser_conn_init(struct iser_conn *ib_conn) init_waitqueue_head(&ib_conn->wait); atomic_set(&ib_conn->post_recv_buf_count, 0); atomic_set(&ib_conn->post_send_buf_count, 0); - atomic_set(&ib_conn->unexpected_pdu_count, 0); atomic_set(&ib_conn->refcount, 1); INIT_LIST_HEAD(&ib_conn->conn_list); spin_lock_init(&ib_conn->lock); -- cgit v1.2.3-59-g8ed1b From bcc60c381d857ced653e912cbe6121294773e147 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:17:42 +0000 Subject: IB/iser: New receive buffer posting logic Currently, the recv buffer posting logic is based on the transactional nature of iSER which allows for posting a buffer before sending a PDU. Change this to post only when the number of outstanding recv buffers is below a water mark and in a batched manner, thus simplifying and optimizing the data path. Use a pre-allocated ring of recv buffers instead of allocating from kmem cache. A special treatment is given to the login response buffer whose size must be 8K unlike the size of buffers used for any other purpose which is 128 bytes. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/infiniband/ulp/iser/iscsi_iser.h | 40 ++++- drivers/infiniband/ulp/iser/iser_initiator.c | 235 +++++++++++++-------------- drivers/infiniband/ulp/iser/iser_verbs.c | 134 +++++++++------ 4 files changed, 235 insertions(+), 176 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 5f7a6fca0a4d..355470e7e904 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -283,7 +283,7 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) * due to issues with the login code re iser sematics * this not set in iscsi_conn_setup - FIXME */ - conn->max_recv_dlength = 128; + conn->max_recv_dlength = ISER_RECV_DATA_SEG_LEN; iser_conn = conn->dd_data; conn->dd_data = iser_conn; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index e8dfdcfa1daf..83effb610594 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -102,9 +102,9 @@ #define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), * * SCSI_TMFUNC(2), LOGOUT(1) */ -#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX + \ - ISER_MAX_RX_MISC_PDUS + \ - ISER_MAX_TX_MISC_PDUS) +#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX) + +#define ISER_MIN_POSTED_RX (ISCSI_DEF_XMIT_CMDS_MAX >> 2) /* the max TX (send) WR supported by the iSER QP is defined by * * max_send_wr = T * (1 + D) + C ; D is how many inflight dataouts we expect * @@ -132,6 +132,12 @@ struct iser_hdr { __be64 read_va; } __attribute__((packed)); +/* Constant PDU lengths calculations */ +#define ISER_HEADERS_LEN (sizeof(struct iser_hdr) + sizeof(struct iscsi_hdr)) + +#define ISER_RECV_DATA_SEG_LEN 128 +#define ISER_RX_PAYLOAD_SIZE (ISER_HEADERS_LEN + ISER_RECV_DATA_SEG_LEN) +#define ISER_RX_LOGIN_SIZE (ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN) /* Length of an object name string */ #define ISER_OBJECT_NAME_SIZE 64 @@ -212,7 +218,6 @@ struct iser_dto { }; enum iser_desc_type { - ISCSI_RX, ISCSI_TX_CONTROL , ISCSI_TX_SCSI_COMMAND, ISCSI_TX_DATAOUT @@ -228,6 +233,17 @@ struct iser_desc { struct iser_dto dto; }; +#define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \ + sizeof(u64) + sizeof(struct ib_sge))) +struct iser_rx_desc { + struct iser_hdr iser_header; + struct iscsi_hdr iscsi_header; + char data[ISER_RECV_DATA_SEG_LEN]; + u64 dma_addr; + struct ib_sge rx_sg; + char pad[ISER_RX_PAD_SIZE]; +} __attribute__((packed)); + struct iser_device { struct ib_device *ib_device; struct ib_pd *pd; @@ -256,6 +272,12 @@ struct iser_conn { struct iser_page_vec *page_vec; /* represents SG to fmr maps* * maps serialized as tx is*/ struct list_head conn_list; /* entry in ig conn list */ + + char *login_buf; + u64 login_dma; + unsigned int rx_desc_head; + struct iser_rx_desc *rx_descs; + struct ib_recv_wr rx_wr[ISER_MIN_POSTED_RX]; }; struct iscsi_iser_conn { @@ -319,8 +341,9 @@ void iser_conn_put(struct iser_conn *ib_conn); void iser_conn_terminate(struct iser_conn *ib_conn); -void iser_rcv_completion(struct iser_desc *desc, - unsigned long dto_xfer_len); +void iser_rcv_completion(struct iser_rx_desc *desc, + unsigned long dto_xfer_len, + struct iser_conn *ib_conn); void iser_snd_completion(struct iser_desc *desc); @@ -332,6 +355,8 @@ void iser_dto_buffs_release(struct iser_dto *dto); int iser_regd_buff_release(struct iser_regd_buf *regd_buf); +void iser_free_rx_descriptors(struct iser_conn *ib_conn); + void iser_reg_single(struct iser_device *device, struct iser_regd_buf *regd_buf, enum dma_data_direction direction); @@ -353,7 +378,8 @@ int iser_reg_page_vec(struct iser_conn *ib_conn, void iser_unreg_mem(struct iser_mem_reg *mem_reg); -int iser_post_recv(struct iser_desc *rx_desc); +int iser_post_recvl(struct iser_conn *ib_conn); +int iser_post_recvm(struct iser_conn *ib_conn, int count); int iser_post_send(struct iser_desc *tx_desc); int iser_conn_state_comp(struct iser_conn *ib_conn, diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 5f42fbe3080c..6d9bbe6363ee 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -39,9 +39,6 @@ #include "iscsi_iser.h" -/* Constant PDU lengths calculations */ -#define ISER_TOTAL_HEADERS_LEN (sizeof (struct iser_hdr) + \ - sizeof (struct iscsi_hdr)) /* iser_dto_add_regd_buff - increments the reference count for * * the registered buffer & adds it to the DTO object */ @@ -172,78 +169,6 @@ iser_prepare_write_cmd(struct iscsi_task *task, return 0; } -/** - * iser_post_receive_control - allocates, initializes and posts receive DTO. - */ -static int iser_post_receive_control(struct iscsi_conn *conn) -{ - struct iscsi_iser_conn *iser_conn = conn->dd_data; - struct iser_desc *rx_desc; - struct iser_regd_buf *regd_hdr; - struct iser_regd_buf *regd_data; - struct iser_dto *recv_dto = NULL; - struct iser_device *device = iser_conn->ib_conn->device; - int rx_data_size, err = 0; - - rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); - if (rx_desc == NULL) { - iser_err("Failed to alloc desc for post recv\n"); - return -ENOMEM; - } - rx_desc->type = ISCSI_RX; - - /* for the login sequence we must support rx of upto 8K; login is done - * after conn create/bind (connect) and conn stop/bind (reconnect), - * what's common for both schemes is that the connection is not started - */ - if (conn->c_stage != ISCSI_CONN_STARTED) - rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN; - else /* FIXME till user space sets conn->max_recv_dlength correctly */ - rx_data_size = 128; - - rx_desc->data = kmalloc(rx_data_size, GFP_NOIO); - if (rx_desc->data == NULL) { - iser_err("Failed to alloc data buf for post recv\n"); - err = -ENOMEM; - goto post_rx_kmalloc_failure; - } - - recv_dto = &rx_desc->dto; - recv_dto->ib_conn = iser_conn->ib_conn; - recv_dto->regd_vector_len = 0; - - regd_hdr = &rx_desc->hdr_regd_buf; - memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); - regd_hdr->device = device; - regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */ - regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN; - - iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE); - - iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0); - - regd_data = &rx_desc->data_regd_buf; - memset(regd_data, 0, sizeof(struct iser_regd_buf)); - regd_data->device = device; - regd_data->virt_addr = rx_desc->data; - regd_data->data_size = rx_data_size; - - iser_reg_single(device, regd_data, DMA_FROM_DEVICE); - - iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0); - - err = iser_post_recv(rx_desc); - if (!err) - return 0; - - /* iser_post_recv failed */ - iser_dto_buffs_release(recv_dto); - kfree(rx_desc->data); -post_rx_kmalloc_failure: - kmem_cache_free(ig.desc_cache, rx_desc); - return err; -} - /* creates a new tx descriptor and adds header regd buffer */ static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn, struct iser_desc *tx_desc) @@ -254,7 +179,7 @@ static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn, memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); regd_hdr->device = iser_conn->ib_conn->device; regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */ - regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN; + regd_hdr->data_size = ISER_HEADERS_LEN; send_dto->ib_conn = iser_conn->ib_conn; send_dto->notify_enable = 1; @@ -266,6 +191,72 @@ static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn, iser_dto_add_regd_buff(send_dto, regd_hdr, 0, 0); } +int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) +{ + int i, j; + u64 dma_addr; + struct iser_rx_desc *rx_desc; + struct ib_sge *rx_sg; + struct iser_device *device = ib_conn->device; + + ib_conn->rx_descs = kmalloc(ISER_QP_MAX_RECV_DTOS * + sizeof(struct iser_rx_desc), GFP_KERNEL); + if (!ib_conn->rx_descs) + goto rx_desc_alloc_fail; + + rx_desc = ib_conn->rx_descs; + + for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++) { + dma_addr = ib_dma_map_single(device->ib_device, (void *)rx_desc, + ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); + if (ib_dma_mapping_error(device->ib_device, dma_addr)) + goto rx_desc_dma_map_failed; + + rx_desc->dma_addr = dma_addr; + + rx_sg = &rx_desc->rx_sg; + rx_sg->addr = rx_desc->dma_addr; + rx_sg->length = ISER_RX_PAYLOAD_SIZE; + rx_sg->lkey = device->mr->lkey; + } + + ib_conn->rx_desc_head = 0; + return 0; + +rx_desc_dma_map_failed: + rx_desc = ib_conn->rx_descs; + for (j = 0; j < i; j++, rx_desc++) + ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr, + ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); + kfree(ib_conn->rx_descs); + ib_conn->rx_descs = NULL; +rx_desc_alloc_fail: + iser_err("failed allocating rx descriptors / data buffers\n"); + return -ENOMEM; +} + +void iser_free_rx_descriptors(struct iser_conn *ib_conn) +{ + int i; + struct iser_rx_desc *rx_desc; + struct iser_device *device = ib_conn->device; + + if (ib_conn->login_buf) { + ib_dma_unmap_single(device->ib_device, ib_conn->login_dma, + ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); + kfree(ib_conn->login_buf); + } + + if (!ib_conn->rx_descs) + return; + + rx_desc = ib_conn->rx_descs; + for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++) + ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr, + ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); + kfree(ib_conn->rx_descs); +} + /** * iser_conn_set_full_featured_mode - (iSER API) */ @@ -273,27 +264,20 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) { struct iscsi_iser_conn *iser_conn = conn->dd_data; - int i; - /* no need to keep it in a var, we are after login so if this should - * be negotiated, by now the result should be available here */ - int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS; - - iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num); + iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX); /* Check that there is no posted recv or send buffers left - */ /* they must be consumed during the login phase */ BUG_ON(atomic_read(&iser_conn->ib_conn->post_recv_buf_count) != 0); BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); + if (iser_alloc_rx_descriptors(iser_conn->ib_conn)) + return -ENOMEM; + /* Initial post receive buffers */ - for (i = 0; i < initial_post_recv_bufs_num; i++) { - if (iser_post_receive_control(conn) != 0) { - iser_err("Failed to post recv bufs at:%d conn:0x%p\n", - i, conn); - return -ENOMEM; - } - } - iser_dbg("Posted %d post recv bufs, conn:0x%p\n", i, conn); + if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX)) + return -ENOMEM; + return 0; } @@ -321,7 +305,7 @@ int iser_send_command(struct iscsi_conn *conn, struct iscsi_iser_task *iser_task = task->dd_data; struct iser_dto *send_dto = NULL; unsigned long edtl; - int err = 0; + int err; struct iser_data_buf *data_buf; struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr; struct scsi_cmnd *sc = task->sc; @@ -371,12 +355,6 @@ int iser_send_command(struct iscsi_conn *conn, iser_reg_single(iser_conn->ib_conn->device, send_dto->regd[0], DMA_TO_DEVICE); - if (iser_post_receive_control(conn) != 0) { - iser_err("post_recv failed!\n"); - err = -ENOMEM; - goto send_command_error; - } - iser_task->status = ISER_TASK_STATUS_STARTED; err = iser_post_send(&iser_task->desc); @@ -474,7 +452,7 @@ int iser_send_control(struct iscsi_conn *conn, struct iser_desc *mdesc = &iser_task->desc; struct iser_dto *send_dto = NULL; unsigned long data_seg_len; - int err = 0; + int err; struct iser_regd_buf *regd_buf; struct iser_device *device; @@ -511,10 +489,10 @@ int iser_send_control(struct iscsi_conn *conn, data_seg_len); } - if (iser_post_receive_control(conn) != 0) { - iser_err("post_rcv_buff failed!\n"); - err = -ENOMEM; - goto send_control_error; + if (task == conn->login_task) { + err = iser_post_recvl(iser_conn->ib_conn); + if (err) + goto send_control_error; } err = iser_post_send(mdesc); @@ -530,27 +508,34 @@ send_control_error: /** * iser_rcv_dto_completion - recv DTO completion */ -void iser_rcv_completion(struct iser_desc *rx_desc, - unsigned long dto_xfer_len) +void iser_rcv_completion(struct iser_rx_desc *rx_desc, + unsigned long rx_xfer_len, + struct iser_conn *ib_conn) { - struct iser_dto *dto = &rx_desc->dto; - struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn; + struct iscsi_iser_conn *conn = ib_conn->iser_conn; struct iscsi_task *task; struct iscsi_iser_task *iser_task; struct iscsi_hdr *hdr; - char *rx_data = NULL; - int rx_data_len = 0; unsigned char opcode; + u64 rx_dma; + int rx_buflen, outstanding, count, err; + + /* differentiate between login to all other PDUs */ + if ((char *)rx_desc == ib_conn->login_buf) { + rx_dma = ib_conn->login_dma; + rx_buflen = ISER_RX_LOGIN_SIZE; + } else { + rx_dma = rx_desc->dma_addr; + rx_buflen = ISER_RX_PAYLOAD_SIZE; + } - hdr = &rx_desc->iscsi_header; + ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, rx_dma, + rx_buflen, DMA_FROM_DEVICE); - iser_dbg("op 0x%x itt 0x%x\n", hdr->opcode,hdr->itt); + hdr = &rx_desc->iscsi_header; - if (dto_xfer_len > ISER_TOTAL_HEADERS_LEN) { /* we have data */ - rx_data_len = dto_xfer_len - ISER_TOTAL_HEADERS_LEN; - rx_data = dto->regd[1]->virt_addr; - rx_data += dto->offset[1]; - } + iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode, + hdr->itt, (int)(rx_xfer_len - ISER_HEADERS_LEN)); opcode = hdr->opcode & ISCSI_OPCODE_MASK; @@ -573,18 +558,30 @@ void iser_rcv_completion(struct iser_desc *rx_desc, iscsi_put_task(task); } } - iser_dto_buffs_release(dto); - iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len); + iscsi_iser_recv(conn->iscsi_conn, hdr, + rx_desc->data, rx_xfer_len - ISER_HEADERS_LEN); - kfree(rx_desc->data); - kmem_cache_free(ig.desc_cache, rx_desc); + ib_dma_sync_single_for_device(ib_conn->device->ib_device, rx_dma, + rx_buflen, DMA_FROM_DEVICE); /* decrementing conn->post_recv_buf_count only --after-- freeing the * * task eliminates the need to worry on tasks which are completed in * * parallel to the execution of iser_conn_term. So the code that waits * * for the posted rx bufs refcount to become zero handles everything */ atomic_dec(&conn->ib_conn->post_recv_buf_count); + + if (rx_dma == ib_conn->login_dma) + return; + + outstanding = atomic_read(&ib_conn->post_recv_buf_count); + if (outstanding + ISER_MIN_POSTED_RX <= ISER_QP_MAX_RECV_DTOS) { + count = min(ISER_QP_MAX_RECV_DTOS - outstanding, + ISER_MIN_POSTED_RX); + err = iser_post_recvm(ib_conn, count); + if (err) + iser_err("posting %d rx bufs err %d\n", count, err); + } } void iser_snd_completion(struct iser_desc *tx_desc) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 7092503a10e3..89b956044060 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -129,13 +129,23 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) { struct iser_device *device; struct ib_qp_init_attr init_attr; - int ret; + int ret = -ENOMEM; struct ib_fmr_pool_param params; BUG_ON(ib_conn->device == NULL); device = ib_conn->device; + ib_conn->login_buf = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL); + if (!ib_conn->login_buf) { + goto alloc_err; + ret = -ENOMEM; + } + + ib_conn->login_dma = ib_dma_map_single(ib_conn->device->ib_device, + (void *)ib_conn->login_buf, ISER_RX_LOGIN_SIZE, + DMA_FROM_DEVICE); + ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) + (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)), GFP_KERNEL); @@ -174,7 +184,7 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS; init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS; init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN; - init_attr.cap.max_recv_sge = 2; + init_attr.cap.max_recv_sge = 1; init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; init_attr.qp_type = IB_QPT_RC; @@ -192,6 +202,7 @@ qp_err: (void)ib_destroy_fmr_pool(ib_conn->fmr_pool); fmr_pool_err: kfree(ib_conn->page_vec); + kfree(ib_conn->login_buf); alloc_err: iser_err("unable to alloc mem or create resource, err %d\n", ret); return ret; @@ -314,7 +325,7 @@ static void iser_conn_release(struct iser_conn *ib_conn) mutex_lock(&ig.connlist_mutex); list_del(&ib_conn->conn_list); mutex_unlock(&ig.connlist_mutex); - + iser_free_rx_descriptors(ib_conn); iser_free_ib_conn_res(ib_conn); ib_conn->device = NULL; /* on EVENT_ADDR_ERROR there's no device yet for this conn */ @@ -625,6 +636,60 @@ void iser_unreg_mem(struct iser_mem_reg *reg) reg->mem_h = NULL; } +int iser_post_recvl(struct iser_conn *ib_conn) +{ + struct ib_recv_wr rx_wr, *rx_wr_failed; + struct ib_sge sge; + int ib_ret; + + sge.addr = ib_conn->login_dma; + sge.length = ISER_RX_LOGIN_SIZE; + sge.lkey = ib_conn->device->mr->lkey; + + rx_wr.wr_id = (unsigned long)ib_conn->login_buf; + rx_wr.sg_list = &sge; + rx_wr.num_sge = 1; + rx_wr.next = NULL; + + atomic_inc(&ib_conn->post_recv_buf_count); + ib_ret = ib_post_recv(ib_conn->qp, &rx_wr, &rx_wr_failed); + if (ib_ret) { + iser_err("ib_post_recv failed ret=%d\n", ib_ret); + atomic_dec(&ib_conn->post_recv_buf_count); + } + return ib_ret; +} + +int iser_post_recvm(struct iser_conn *ib_conn, int count) +{ + struct ib_recv_wr *rx_wr, *rx_wr_failed; + int i, ib_ret; + unsigned int my_rx_head = ib_conn->rx_desc_head; + struct iser_rx_desc *rx_desc; + + for (rx_wr = ib_conn->rx_wr, i = 0; i < count; i++, rx_wr++) { + rx_desc = &ib_conn->rx_descs[my_rx_head]; + rx_wr->wr_id = (unsigned long)rx_desc; + rx_wr->sg_list = &rx_desc->rx_sg; + rx_wr->num_sge = 1; + rx_wr->next = rx_wr + 1; + my_rx_head = (my_rx_head + 1) & (ISER_QP_MAX_RECV_DTOS - 1); + } + + rx_wr--; + rx_wr->next = NULL; /* mark end of work requests list */ + + atomic_add(count, &ib_conn->post_recv_buf_count); + ib_ret = ib_post_recv(ib_conn->qp, ib_conn->rx_wr, &rx_wr_failed); + if (ib_ret) { + iser_err("ib_post_recv failed ret=%d\n", ib_ret); + atomic_sub(count, &ib_conn->post_recv_buf_count); + } else + ib_conn->rx_desc_head = my_rx_head; + return ib_ret; +} + + /** * iser_dto_to_iov - builds IOV from a dto descriptor */ @@ -665,39 +730,6 @@ static void iser_dto_to_iov(struct iser_dto *dto, struct ib_sge *iov, int iov_le } } -/** - * iser_post_recv - Posts a receive buffer. - * - * returns 0 on success, -1 on failure - */ -int iser_post_recv(struct iser_desc *rx_desc) -{ - int ib_ret, ret_val = 0; - struct ib_recv_wr recv_wr, *recv_wr_failed; - struct ib_sge iov[2]; - struct iser_conn *ib_conn; - struct iser_dto *recv_dto = &rx_desc->dto; - - /* Retrieve conn */ - ib_conn = recv_dto->ib_conn; - - iser_dto_to_iov(recv_dto, iov, 2); - - recv_wr.next = NULL; - recv_wr.sg_list = iov; - recv_wr.num_sge = recv_dto->regd_vector_len; - recv_wr.wr_id = (unsigned long)rx_desc; - - atomic_inc(&ib_conn->post_recv_buf_count); - ib_ret = ib_post_recv(ib_conn->qp, &recv_wr, &recv_wr_failed); - if (ib_ret) { - iser_err("ib_post_recv failed ret=%d\n", ib_ret); - atomic_dec(&ib_conn->post_recv_buf_count); - ret_val = -1; - } - - return ret_val; -} /** * iser_start_send - Initiate a Send DTO operation @@ -737,18 +769,17 @@ int iser_post_send(struct iser_desc *tx_desc) return ret_val; } -static void iser_handle_comp_error(struct iser_desc *desc) +static void iser_handle_comp_error(struct iser_desc *desc, + struct iser_conn *ib_conn) { - struct iser_dto *dto = &desc->dto; - struct iser_conn *ib_conn = dto->ib_conn; - - iser_dto_buffs_release(dto); + struct iser_rx_desc *rx = (struct iser_rx_desc *)desc; + struct iser_rx_desc *rx_first = ib_conn->rx_descs; + struct iser_rx_desc *rx_last = rx_first + (ISER_QP_MAX_RECV_DTOS - 1); - if (desc->type == ISCSI_RX) { - kfree(desc->data); - kmem_cache_free(ig.desc_cache, desc); + if ((char *)desc == ib_conn->login_buf || + (rx_first <= rx && rx <= rx_last)) atomic_dec(&ib_conn->post_recv_buf_count); - } else { /* type is TX control/command/dataout */ + else { /* type is TX control/command/dataout */ if (desc->type == ISCSI_TX_DATAOUT) kmem_cache_free(ig.desc_cache, desc); atomic_dec(&ib_conn->post_send_buf_count); @@ -780,20 +811,25 @@ static void iser_cq_tasklet_fn(unsigned long data) struct ib_wc wc; struct iser_desc *desc; unsigned long xfer_len; + struct iser_conn *ib_conn; while (ib_poll_cq(cq, 1, &wc) == 1) { desc = (struct iser_desc *) (unsigned long) wc.wr_id; BUG_ON(desc == NULL); + ib_conn = wc.qp->qp_context; if (wc.status == IB_WC_SUCCESS) { - if (desc->type == ISCSI_RX) { + if (wc.opcode == IB_WC_RECV) { xfer_len = (unsigned long)wc.byte_len; - iser_rcv_completion(desc, xfer_len); + iser_rcv_completion((struct iser_rx_desc *)desc, + xfer_len, ib_conn); } else /* type == ISCSI_TX_CONTROL/SCSI_CMD/DOUT */ iser_snd_completion(desc); } else { - iser_err("comp w. error op %d status %d\n",desc->type,wc.status); - iser_handle_comp_error(desc); + if (wc.status != IB_WC_WR_FLUSH_ERR) + iser_err("id %llx status %d vend_err %x\n", + wc.wr_id, wc.status, wc.vendor_err); + iser_handle_comp_error(desc, ib_conn); } } /* #warning "it is assumed here that arming CQ only once its empty" * -- cgit v1.2.3-59-g8ed1b From 704315f082d473b34047817f0a6a01924f38501e Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:18:39 +0000 Subject: IB/iser: Remove atomic counter for posted receive buffers Now that both the posting and reaping of receive buffers is done in the completion path, the counter of outstanding buffers not be atomic. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 2 +- drivers/infiniband/ulp/iser/iser_initiator.c | 6 +++--- drivers/infiniband/ulp/iser/iser_verbs.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 83effb610594..4491235340de 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -266,7 +266,7 @@ struct iser_conn { struct ib_fmr_pool *fmr_pool; /* pool of IB FMRs */ int disc_evt_flag; /* disconn event delivered */ wait_queue_head_t wait; /* waitq for conn/disconn */ - atomic_t post_recv_buf_count; /* posted rx count */ + int post_recv_buf_count; /* posted rx count */ atomic_t post_send_buf_count; /* posted tx count */ char name[ISER_OBJECT_NAME_SIZE]; struct iser_page_vec *page_vec; /* represents SG to fmr maps* diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 6d9bbe6363ee..3e65a43d2154 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -268,7 +268,7 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) /* Check that there is no posted recv or send buffers left - */ /* they must be consumed during the login phase */ - BUG_ON(atomic_read(&iser_conn->ib_conn->post_recv_buf_count) != 0); + BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0); BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); if (iser_alloc_rx_descriptors(iser_conn->ib_conn)) @@ -569,12 +569,12 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, * task eliminates the need to worry on tasks which are completed in * * parallel to the execution of iser_conn_term. So the code that waits * * for the posted rx bufs refcount to become zero handles everything */ - atomic_dec(&conn->ib_conn->post_recv_buf_count); + conn->ib_conn->post_recv_buf_count--; if (rx_dma == ib_conn->login_dma) return; - outstanding = atomic_read(&ib_conn->post_recv_buf_count); + outstanding = ib_conn->post_recv_buf_count; if (outstanding + ISER_MIN_POSTED_RX <= ISER_QP_MAX_RECV_DTOS) { count = min(ISER_QP_MAX_RECV_DTOS - outstanding, ISER_MIN_POSTED_RX); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 89b956044060..202c00dc6a76 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -453,7 +453,7 @@ static void iser_disconnected_handler(struct rdma_cm_id *cma_id) ISCSI_ERR_CONN_FAILED); /* Complete the termination process if no posts are pending */ - if ((atomic_read(&ib_conn->post_recv_buf_count) == 0) && + if (ib_conn->post_recv_buf_count == 0 && (atomic_read(&ib_conn->post_send_buf_count) == 0)) { ib_conn->state = ISER_CONN_DOWN; wake_up_interruptible(&ib_conn->wait); @@ -500,7 +500,7 @@ void iser_conn_init(struct iser_conn *ib_conn) { ib_conn->state = ISER_CONN_INIT; init_waitqueue_head(&ib_conn->wait); - atomic_set(&ib_conn->post_recv_buf_count, 0); + ib_conn->post_recv_buf_count = 0; atomic_set(&ib_conn->post_send_buf_count, 0); atomic_set(&ib_conn->refcount, 1); INIT_LIST_HEAD(&ib_conn->conn_list); @@ -651,11 +651,11 @@ int iser_post_recvl(struct iser_conn *ib_conn) rx_wr.num_sge = 1; rx_wr.next = NULL; - atomic_inc(&ib_conn->post_recv_buf_count); + ib_conn->post_recv_buf_count++; ib_ret = ib_post_recv(ib_conn->qp, &rx_wr, &rx_wr_failed); if (ib_ret) { iser_err("ib_post_recv failed ret=%d\n", ib_ret); - atomic_dec(&ib_conn->post_recv_buf_count); + ib_conn->post_recv_buf_count--; } return ib_ret; } @@ -679,11 +679,11 @@ int iser_post_recvm(struct iser_conn *ib_conn, int count) rx_wr--; rx_wr->next = NULL; /* mark end of work requests list */ - atomic_add(count, &ib_conn->post_recv_buf_count); + ib_conn->post_recv_buf_count += count; ib_ret = ib_post_recv(ib_conn->qp, ib_conn->rx_wr, &rx_wr_failed); if (ib_ret) { iser_err("ib_post_recv failed ret=%d\n", ib_ret); - atomic_sub(count, &ib_conn->post_recv_buf_count); + ib_conn->post_recv_buf_count -= count; } else ib_conn->rx_desc_head = my_rx_head; return ib_ret; @@ -778,14 +778,14 @@ static void iser_handle_comp_error(struct iser_desc *desc, if ((char *)desc == ib_conn->login_buf || (rx_first <= rx && rx <= rx_last)) - atomic_dec(&ib_conn->post_recv_buf_count); + ib_conn->post_recv_buf_count--; else { /* type is TX control/command/dataout */ if (desc->type == ISCSI_TX_DATAOUT) kmem_cache_free(ig.desc_cache, desc); atomic_dec(&ib_conn->post_send_buf_count); } - if (atomic_read(&ib_conn->post_recv_buf_count) == 0 && + if (ib_conn->post_recv_buf_count == 0 && atomic_read(&ib_conn->post_send_buf_count) == 0) { /* getting here when the state is UP means that the conn is * * being terminated asynchronously from the iSCSI layer's * -- cgit v1.2.3-59-g8ed1b From 78ad0a34dc138047529058c5f2265664cb70a052 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:19:21 +0000 Subject: IB/iser: Use different CQ for send completions Use a different CQ for send completions, where send completions are polled by the interrupt-driven receive completion handler. Therefore, interrupts aren't used for the send CQ. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 3 +- drivers/infiniband/ulp/iser/iser_verbs.c | 110 +++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 37 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 4491235340de..a314576be4bf 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -247,7 +247,8 @@ struct iser_rx_desc { struct iser_device { struct ib_device *ib_device; struct ib_pd *pd; - struct ib_cq *cq; + struct ib_cq *rx_cq; + struct ib_cq *tx_cq; struct ib_mr *mr; struct tasklet_struct cq_tasklet; struct list_head ig_list; /* entry in ig devices list */ diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 202c00dc6a76..218aa10939a0 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -37,9 +37,8 @@ #include "iscsi_iser.h" #define ISCSI_ISER_MAX_CONN 8 -#define ISER_MAX_CQ_LEN ((ISER_QP_MAX_RECV_DTOS + \ - ISER_QP_MAX_REQ_DTOS) * \ - ISCSI_ISER_MAX_CONN) +#define ISER_MAX_RX_CQ_LEN (ISER_QP_MAX_RECV_DTOS * ISCSI_ISER_MAX_CONN) +#define ISER_MAX_TX_CQ_LEN (ISER_QP_MAX_REQ_DTOS * ISCSI_ISER_MAX_CONN) static void iser_cq_tasklet_fn(unsigned long data); static void iser_cq_callback(struct ib_cq *cq, void *cq_context); @@ -67,15 +66,23 @@ static int iser_create_device_ib_res(struct iser_device *device) if (IS_ERR(device->pd)) goto pd_err; - device->cq = ib_create_cq(device->ib_device, + device->rx_cq = ib_create_cq(device->ib_device, iser_cq_callback, iser_cq_event_callback, (void *)device, - ISER_MAX_CQ_LEN, 0); - if (IS_ERR(device->cq)) - goto cq_err; + ISER_MAX_RX_CQ_LEN, 0); + if (IS_ERR(device->rx_cq)) + goto rx_cq_err; - if (ib_req_notify_cq(device->cq, IB_CQ_NEXT_COMP)) + device->tx_cq = ib_create_cq(device->ib_device, + NULL, iser_cq_event_callback, + (void *)device, + ISER_MAX_TX_CQ_LEN, 0); + + if (IS_ERR(device->tx_cq)) + goto tx_cq_err; + + if (ib_req_notify_cq(device->rx_cq, IB_CQ_NEXT_COMP)) goto cq_arm_err; tasklet_init(&device->cq_tasklet, @@ -93,8 +100,10 @@ static int iser_create_device_ib_res(struct iser_device *device) dma_mr_err: tasklet_kill(&device->cq_tasklet); cq_arm_err: - ib_destroy_cq(device->cq); -cq_err: + ib_destroy_cq(device->tx_cq); +tx_cq_err: + ib_destroy_cq(device->rx_cq); +rx_cq_err: ib_dealloc_pd(device->pd); pd_err: iser_err("failed to allocate an IB resource\n"); @@ -112,11 +121,13 @@ static void iser_free_device_ib_res(struct iser_device *device) tasklet_kill(&device->cq_tasklet); (void)ib_dereg_mr(device->mr); - (void)ib_destroy_cq(device->cq); + (void)ib_destroy_cq(device->tx_cq); + (void)ib_destroy_cq(device->rx_cq); (void)ib_dealloc_pd(device->pd); device->mr = NULL; - device->cq = NULL; + device->tx_cq = NULL; + device->rx_cq = NULL; device->pd = NULL; } @@ -179,8 +190,8 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) init_attr.event_handler = iser_qp_event_callback; init_attr.qp_context = (void *)ib_conn; - init_attr.send_cq = device->cq; - init_attr.recv_cq = device->cq; + init_attr.send_cq = device->tx_cq; + init_attr.recv_cq = device->rx_cq; init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS; init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS; init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN; @@ -772,18 +783,8 @@ int iser_post_send(struct iser_desc *tx_desc) static void iser_handle_comp_error(struct iser_desc *desc, struct iser_conn *ib_conn) { - struct iser_rx_desc *rx = (struct iser_rx_desc *)desc; - struct iser_rx_desc *rx_first = ib_conn->rx_descs; - struct iser_rx_desc *rx_last = rx_first + (ISER_QP_MAX_RECV_DTOS - 1); - - if ((char *)desc == ib_conn->login_buf || - (rx_first <= rx && rx <= rx_last)) - ib_conn->post_recv_buf_count--; - else { /* type is TX control/command/dataout */ - if (desc->type == ISCSI_TX_DATAOUT) - kmem_cache_free(ig.desc_cache, desc); - atomic_dec(&ib_conn->post_send_buf_count); - } + if (desc && desc->type == ISCSI_TX_DATAOUT) + kmem_cache_free(ig.desc_cache, desc); if (ib_conn->post_recv_buf_count == 0 && atomic_read(&ib_conn->post_send_buf_count) == 0) { @@ -804,37 +805,74 @@ static void iser_handle_comp_error(struct iser_desc *desc, } } +static int iser_drain_tx_cq(struct iser_device *device) +{ + struct ib_cq *cq = device->tx_cq; + struct ib_wc wc; + struct iser_desc *tx_desc; + struct iser_conn *ib_conn; + int completed_tx = 0; + + while (ib_poll_cq(cq, 1, &wc) == 1) { + tx_desc = (struct iser_desc *) (unsigned long) wc.wr_id; + ib_conn = wc.qp->qp_context; + if (wc.status == IB_WC_SUCCESS) { + if (wc.opcode == IB_WC_SEND) + iser_snd_completion(tx_desc); + else + iser_err("expected opcode %d got %d\n", + IB_WC_SEND, wc.opcode); + } else { + iser_err("tx id %llx status %d vend_err %x\n", + wc.wr_id, wc.status, wc.vendor_err); + atomic_dec(&ib_conn->post_send_buf_count); + iser_handle_comp_error(tx_desc, ib_conn); + } + completed_tx++; + } + return completed_tx; +} + + static void iser_cq_tasklet_fn(unsigned long data) { struct iser_device *device = (struct iser_device *)data; - struct ib_cq *cq = device->cq; + struct ib_cq *cq = device->rx_cq; struct ib_wc wc; - struct iser_desc *desc; + struct iser_rx_desc *desc; unsigned long xfer_len; struct iser_conn *ib_conn; + int completed_tx, completed_rx; + completed_tx = completed_rx = 0; while (ib_poll_cq(cq, 1, &wc) == 1) { - desc = (struct iser_desc *) (unsigned long) wc.wr_id; + desc = (struct iser_rx_desc *) (unsigned long) wc.wr_id; BUG_ON(desc == NULL); ib_conn = wc.qp->qp_context; - if (wc.status == IB_WC_SUCCESS) { if (wc.opcode == IB_WC_RECV) { xfer_len = (unsigned long)wc.byte_len; - iser_rcv_completion((struct iser_rx_desc *)desc, - xfer_len, ib_conn); - } else /* type == ISCSI_TX_CONTROL/SCSI_CMD/DOUT */ - iser_snd_completion(desc); + iser_rcv_completion(desc, xfer_len, ib_conn); + } else + iser_err("expected opcode %d got %d\n", + IB_WC_RECV, wc.opcode); } else { if (wc.status != IB_WC_WR_FLUSH_ERR) - iser_err("id %llx status %d vend_err %x\n", + iser_err("rx id %llx status %d vend_err %x\n", wc.wr_id, wc.status, wc.vendor_err); - iser_handle_comp_error(desc, ib_conn); + ib_conn->post_recv_buf_count--; + iser_handle_comp_error(NULL, ib_conn); } + completed_rx++; + if (!(completed_rx & 63)) + completed_tx += iser_drain_tx_cq(device); } /* #warning "it is assumed here that arming CQ only once its empty" * * " would not cause interrupts to be missed" */ ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); + + completed_tx += iser_drain_tx_cq(device); + iser_dbg("got %d rx %d tx completions\n", completed_rx, completed_tx); } static void iser_cq_callback(struct ib_cq *cq, void *cq_context) -- cgit v1.2.3-59-g8ed1b From f19624aa92003969ba822cd3c552800965aa530b Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:19:56 +0000 Subject: IB/iser: Simplify send flow/descriptors Simplify and shrink the logic/code used for the send descriptors. Changes include removing struct iser_dto (an unnecessary abstraction), using struct iser_regd_buf only for handling SCSI commands, using dma_sync instead of dma_map/unmap, etc. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 34 +++++- drivers/infiniband/ulp/iser/iscsi_iser.h | 48 ++------ drivers/infiniband/ulp/iser/iser_initiator.c | 176 ++++++++++----------------- drivers/infiniband/ulp/iser/iser_memory.c | 60 --------- drivers/infiniband/ulp/iser/iser_verbs.c | 75 ++---------- 5 files changed, 115 insertions(+), 278 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 355470e7e904..331147b71a91 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -128,6 +128,28 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode) return 0; } +int iser_initialize_task_headers(struct iscsi_task *task, + struct iser_tx_desc *tx_desc) +{ + struct iscsi_iser_conn *iser_conn = task->conn->dd_data; + struct iser_device *device = iser_conn->ib_conn->device; + struct iscsi_iser_task *iser_task = task->dd_data; + u64 dma_addr; + + dma_addr = ib_dma_map_single(device->ib_device, (void *)tx_desc, + ISER_HEADERS_LEN, DMA_TO_DEVICE); + if (ib_dma_mapping_error(device->ib_device, dma_addr)) + return -ENOMEM; + + tx_desc->dma_addr = dma_addr; + tx_desc->tx_sg[0].addr = tx_desc->dma_addr; + tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; + tx_desc->tx_sg[0].lkey = device->mr->lkey; + + iser_task->headers_initialized = 1; + iser_task->iser_conn = iser_conn; + return 0; +} /** * iscsi_iser_task_init - Initialize task * @task: iscsi task @@ -137,17 +159,17 @@ static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode) static int iscsi_iser_task_init(struct iscsi_task *task) { - struct iscsi_iser_conn *iser_conn = task->conn->dd_data; struct iscsi_iser_task *iser_task = task->dd_data; + if (!iser_task->headers_initialized) + if (iser_initialize_task_headers(task, &iser_task->desc)) + return -ENOMEM; + /* mgmt task */ - if (!task->sc) { - iser_task->desc.data = task->data; + if (!task->sc) return 0; - } iser_task->command_sent = 0; - iser_task->iser_conn = iser_conn; iser_task_rdma_init(iser_task); return 0; } @@ -675,7 +697,7 @@ static int __init iser_init(void) memset(&ig, 0, sizeof(struct iser_global)); ig.desc_cache = kmem_cache_create("iser_descriptors", - sizeof (struct iser_desc), + sizeof(struct iser_tx_desc), 0, SLAB_HWCACHE_ALIGN, NULL); if (ig.desc_cache == NULL) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index a314576be4bf..269f23f1b6d1 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -193,28 +193,8 @@ struct iser_regd_buf { struct iser_mem_reg reg; /* memory registration info */ void *virt_addr; struct iser_device *device; /* device->device for dma_unmap */ - u64 dma_addr; /* if non zero, addr for dma_unmap */ enum dma_data_direction direction; /* direction for dma_unmap */ unsigned int data_size; - atomic_t ref_count; /* refcount, freed when dec to 0 */ -}; - -#define MAX_REGD_BUF_VECTOR_LEN 2 - -struct iser_dto { - struct iscsi_iser_task *task; - struct iser_conn *ib_conn; - int notify_enable; - - /* vector of registered buffers */ - unsigned int regd_vector_len; - struct iser_regd_buf *regd[MAX_REGD_BUF_VECTOR_LEN]; - - /* offset into the registered buffer may be specified */ - unsigned int offset[MAX_REGD_BUF_VECTOR_LEN]; - - /* a smaller size may be specified, if 0, then full size is used */ - unsigned int used_sz[MAX_REGD_BUF_VECTOR_LEN]; }; enum iser_desc_type { @@ -223,14 +203,15 @@ enum iser_desc_type { ISCSI_TX_DATAOUT }; -struct iser_desc { +struct iser_tx_desc { struct iser_hdr iser_header; struct iscsi_hdr iscsi_header; - struct iser_regd_buf hdr_regd_buf; - void *data; /* used by RX & TX_CONTROL */ - struct iser_regd_buf data_regd_buf; /* used by RX & TX_CONTROL */ enum iser_desc_type type; - struct iser_dto dto; + u64 dma_addr; + /* sg[0] points to iser/iscsi headers, sg[1] optionally points to either + of immediate data, unsolicited data-out or control (login,text) */ + struct ib_sge tx_sg[2]; + int num_sge; }; #define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \ @@ -287,7 +268,7 @@ struct iscsi_iser_conn { }; struct iscsi_iser_task { - struct iser_desc desc; + struct iser_tx_desc desc; struct iscsi_iser_conn *iser_conn; enum iser_task_status status; int command_sent; /* set if command sent */ @@ -295,6 +276,7 @@ struct iscsi_iser_task { struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */ struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/ struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */ + int headers_initialized; }; struct iser_page_vec { @@ -346,22 +328,14 @@ void iser_rcv_completion(struct iser_rx_desc *desc, unsigned long dto_xfer_len, struct iser_conn *ib_conn); -void iser_snd_completion(struct iser_desc *desc); +void iser_snd_completion(struct iser_tx_desc *desc, struct iser_conn *ib_conn); void iser_task_rdma_init(struct iscsi_iser_task *task); void iser_task_rdma_finalize(struct iscsi_iser_task *task); -void iser_dto_buffs_release(struct iser_dto *dto); - -int iser_regd_buff_release(struct iser_regd_buf *regd_buf); - void iser_free_rx_descriptors(struct iser_conn *ib_conn); -void iser_reg_single(struct iser_device *device, - struct iser_regd_buf *regd_buf, - enum dma_data_direction direction); - void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task, enum iser_data_dir cmd_dir); @@ -381,7 +355,7 @@ void iser_unreg_mem(struct iser_mem_reg *mem_reg); int iser_post_recvl(struct iser_conn *ib_conn); int iser_post_recvm(struct iser_conn *ib_conn, int count); -int iser_post_send(struct iser_desc *tx_desc); +int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc); int iser_conn_state_comp(struct iser_conn *ib_conn, enum iser_ib_conn_state comp); @@ -392,4 +366,6 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, enum dma_data_direction dma_dir); void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); +int iser_initialize_task_headers(struct iscsi_task *task, + struct iser_tx_desc *tx_desc); #endif diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 3e65a43d2154..3be3a13b5e30 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -39,26 +39,6 @@ #include "iscsi_iser.h" - -/* iser_dto_add_regd_buff - increments the reference count for * - * the registered buffer & adds it to the DTO object */ -static void iser_dto_add_regd_buff(struct iser_dto *dto, - struct iser_regd_buf *regd_buf, - unsigned long use_offset, - unsigned long use_size) -{ - int add_idx; - - atomic_inc(®d_buf->ref_count); - - add_idx = dto->regd_vector_len; - dto->regd[add_idx] = regd_buf; - dto->used_sz[add_idx] = use_size; - dto->offset[add_idx] = use_offset; - - dto->regd_vector_len++; -} - /* Register user buffer memory and initialize passive rdma * dto descriptor. Total data size is stored in * iser_task->data[ISER_DIR_IN].data_len @@ -119,9 +99,9 @@ iser_prepare_write_cmd(struct iscsi_task *task, struct iscsi_iser_task *iser_task = task->dd_data; struct iser_regd_buf *regd_buf; int err; - struct iser_dto *send_dto = &iser_task->desc.dto; struct iser_hdr *hdr = &iser_task->desc.iser_header; struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT]; + struct ib_sge *tx_dsg = &iser_task->desc.tx_sg[1]; err = iser_dma_map_task_data(iser_task, buf_out, @@ -160,37 +140,36 @@ iser_prepare_write_cmd(struct iscsi_task *task, if (imm_sz > 0) { iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n", task->itt, imm_sz); - iser_dto_add_regd_buff(send_dto, - regd_buf, - 0, - imm_sz); + tx_dsg->addr = regd_buf->reg.va; + tx_dsg->length = imm_sz; + tx_dsg->lkey = regd_buf->reg.lkey; + iser_task->desc.num_sge = 2; } return 0; } /* creates a new tx descriptor and adds header regd buffer */ -static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn, - struct iser_desc *tx_desc) +static void iser_create_send_desc(struct iser_conn *ib_conn, + struct iser_tx_desc *tx_desc) { - struct iser_regd_buf *regd_hdr = &tx_desc->hdr_regd_buf; - struct iser_dto *send_dto = &tx_desc->dto; - - memset(regd_hdr, 0, sizeof(struct iser_regd_buf)); - regd_hdr->device = iser_conn->ib_conn->device; - regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */ - regd_hdr->data_size = ISER_HEADERS_LEN; + struct iser_device *device = ib_conn->device; - send_dto->ib_conn = iser_conn->ib_conn; - send_dto->notify_enable = 1; - send_dto->regd_vector_len = 0; + ib_dma_sync_single_for_cpu(device->ib_device, + tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr)); tx_desc->iser_header.flags = ISER_VER; - iser_dto_add_regd_buff(send_dto, regd_hdr, 0, 0); + tx_desc->num_sge = 1; + + if (tx_desc->tx_sg[0].lkey != device->mr->lkey) { + tx_desc->tx_sg[0].lkey = device->mr->lkey; + iser_dbg("sdesc %p lkey mismatch, fixing\n", tx_desc); + } } + int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) { int i, j; @@ -303,12 +282,12 @@ int iser_send_command(struct iscsi_conn *conn, { struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_task *iser_task = task->dd_data; - struct iser_dto *send_dto = NULL; unsigned long edtl; int err; struct iser_data_buf *data_buf; struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr; struct scsi_cmnd *sc = task->sc; + struct iser_tx_desc *tx_desc = &iser_task->desc; if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); @@ -320,10 +299,8 @@ int iser_send_command(struct iscsi_conn *conn, edtl = ntohl(hdr->data_length); /* build the tx desc regd header and add it to the tx desc dto */ - iser_task->desc.type = ISCSI_TX_SCSI_COMMAND; - send_dto = &iser_task->desc.dto; - send_dto->task = iser_task; - iser_create_send_desc(iser_conn, &iser_task->desc); + tx_desc->type = ISCSI_TX_SCSI_COMMAND; + iser_create_send_desc(iser_conn->ib_conn, tx_desc); if (hdr->flags & ISCSI_FLAG_CMD_READ) data_buf = &iser_task->data[ISER_DIR_IN]; @@ -352,17 +329,13 @@ int iser_send_command(struct iscsi_conn *conn, goto send_command_error; } - iser_reg_single(iser_conn->ib_conn->device, - send_dto->regd[0], DMA_TO_DEVICE); - iser_task->status = ISER_TASK_STATUS_STARTED; - err = iser_post_send(&iser_task->desc); + err = iser_post_send(iser_conn->ib_conn, tx_desc); if (!err) return 0; send_command_error: - iser_dto_buffs_release(send_dto); iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err); return err; } @@ -376,12 +349,14 @@ int iser_send_data_out(struct iscsi_conn *conn, { struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_task *iser_task = task->dd_data; - struct iser_desc *tx_desc = NULL; - struct iser_dto *send_dto = NULL; + struct iser_tx_desc *tx_desc = NULL; + struct iser_regd_buf *regd_buf; unsigned long buf_offset; unsigned long data_seg_len; uint32_t itt; int err = 0; + struct ib_sge *tx_dsg; + if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); @@ -398,28 +373,25 @@ int iser_send_data_out(struct iscsi_conn *conn, iser_dbg("%s itt %d dseg_len %d offset %d\n", __func__,(int)itt,(int)data_seg_len,(int)buf_offset); - tx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO); + tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_NOIO); if (tx_desc == NULL) { iser_err("Failed to alloc desc for post dataout\n"); return -ENOMEM; } tx_desc->type = ISCSI_TX_DATAOUT; + tx_desc->iser_header.flags = ISER_VER; memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr)); - /* build the tx desc regd header and add it to the tx desc dto */ - send_dto = &tx_desc->dto; - send_dto->task = iser_task; - iser_create_send_desc(iser_conn, tx_desc); - - iser_reg_single(iser_conn->ib_conn->device, - send_dto->regd[0], DMA_TO_DEVICE); + /* build the tx desc */ + iser_initialize_task_headers(task, tx_desc); - /* all data was registered for RDMA, we can use the lkey */ - iser_dto_add_regd_buff(send_dto, - &iser_task->rdma_regd[ISER_DIR_OUT], - buf_offset, - data_seg_len); + regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT]; + tx_dsg = &tx_desc->tx_sg[1]; + tx_dsg->addr = regd_buf->reg.va + buf_offset; + tx_dsg->length = data_seg_len; + tx_dsg->lkey = regd_buf->reg.lkey; + tx_desc->num_sge = 2; if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) { iser_err("Offset:%ld & DSL:%ld in Data-Out " @@ -433,12 +405,11 @@ int iser_send_data_out(struct iscsi_conn *conn, itt, buf_offset, data_seg_len); - err = iser_post_send(tx_desc); + err = iser_post_send(iser_conn->ib_conn, tx_desc); if (!err) return 0; send_data_out_error: - iser_dto_buffs_release(send_dto); kmem_cache_free(ig.desc_cache, tx_desc); iser_err("conn %p failed err %d\n",conn, err); return err; @@ -449,11 +420,9 @@ int iser_send_control(struct iscsi_conn *conn, { struct iscsi_iser_conn *iser_conn = conn->dd_data; struct iscsi_iser_task *iser_task = task->dd_data; - struct iser_desc *mdesc = &iser_task->desc; - struct iser_dto *send_dto = NULL; + struct iser_tx_desc *mdesc = &iser_task->desc; unsigned long data_seg_len; - int err; - struct iser_regd_buf *regd_buf; + int err = 0; struct iser_device *device; if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { @@ -466,27 +435,24 @@ int iser_send_control(struct iscsi_conn *conn, /* build the tx desc regd header and add it to the tx desc dto */ mdesc->type = ISCSI_TX_CONTROL; - send_dto = &mdesc->dto; - send_dto->task = NULL; - iser_create_send_desc(iser_conn, mdesc); + iser_create_send_desc(iser_conn->ib_conn, mdesc); device = iser_conn->ib_conn->device; - iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE); - data_seg_len = ntoh24(task->hdr->dlength); if (data_seg_len > 0) { - regd_buf = &mdesc->data_regd_buf; - memset(regd_buf, 0, sizeof(struct iser_regd_buf)); - regd_buf->device = device; - regd_buf->virt_addr = task->data; - regd_buf->data_size = task->data_count; - iser_reg_single(device, regd_buf, - DMA_TO_DEVICE); - iser_dto_add_regd_buff(send_dto, regd_buf, - 0, - data_seg_len); + struct ib_sge *tx_dsg = &mdesc->tx_sg[1]; + if (task != conn->login_task) { + iser_err("data present on non login task!!!\n"); + goto send_control_error; + } + memcpy(iser_conn->ib_conn->login_buf, task->data, + task->data_count); + tx_dsg->addr = iser_conn->ib_conn->login_dma; + tx_dsg->length = data_seg_len; + tx_dsg->lkey = device->mr->lkey; + mdesc->num_sge = 2; } if (task == conn->login_task) { @@ -495,12 +461,11 @@ int iser_send_control(struct iscsi_conn *conn, goto send_control_error; } - err = iser_post_send(mdesc); + err = iser_post_send(iser_conn->ib_conn, mdesc); if (!err) return 0; send_control_error: - iser_dto_buffs_release(send_dto); iser_err("conn %p failed err %d\n",conn, err); return err; } @@ -584,21 +549,20 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, } } -void iser_snd_completion(struct iser_desc *tx_desc) +void iser_snd_completion(struct iser_tx_desc *tx_desc, + struct iser_conn *ib_conn) { - struct iser_dto *dto = &tx_desc->dto; - struct iser_conn *ib_conn = dto->ib_conn; struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn; struct iscsi_conn *conn = iser_conn->iscsi_conn; struct iscsi_task *task; int resume_tx = 0; + struct iser_device *device = ib_conn->device; - iser_dbg("Initiator, Data sent dto=0x%p\n", dto); - - iser_dto_buffs_release(dto); - - if (tx_desc->type == ISCSI_TX_DATAOUT) + if (tx_desc->type == ISCSI_TX_DATAOUT) { + ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr, + ISER_HEADERS_LEN, DMA_TO_DEVICE); kmem_cache_free(ig.desc_cache, tx_desc); + } if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) == ISER_QP_MAX_REQ_DTOS) @@ -639,7 +603,6 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task) void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) { - int deferred; int is_rdma_aligned = 1; struct iser_regd_buf *regd; @@ -657,32 +620,17 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) if (iser_task->dir[ISER_DIR_IN]) { regd = &iser_task->rdma_regd[ISER_DIR_IN]; - deferred = iser_regd_buff_release(regd); - if (deferred) { - iser_err("%d references remain for BUF-IN rdma reg\n", - atomic_read(®d->ref_count)); - } + if (regd->reg.is_fmr) + iser_unreg_mem(®d->reg); } if (iser_task->dir[ISER_DIR_OUT]) { regd = &iser_task->rdma_regd[ISER_DIR_OUT]; - deferred = iser_regd_buff_release(regd); - if (deferred) { - iser_err("%d references remain for BUF-OUT rdma reg\n", - atomic_read(®d->ref_count)); - } + if (regd->reg.is_fmr) + iser_unreg_mem(®d->reg); } /* if the data was unaligned, it was already unmapped and then copied */ if (is_rdma_aligned) iser_dma_unmap_task_data(iser_task); } - -void iser_dto_buffs_release(struct iser_dto *dto) -{ - int i; - - for (i = 0; i < dto->regd_vector_len; i++) - iser_regd_buff_release(dto->regd[i]); -} - diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 274c883ef3ea..5e32e8f1edf5 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -40,62 +40,6 @@ #define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */ -/** - * Decrements the reference count for the - * registered buffer & releases it - * - * returns 0 if released, 1 if deferred - */ -int iser_regd_buff_release(struct iser_regd_buf *regd_buf) -{ - struct ib_device *dev; - - if ((atomic_read(®d_buf->ref_count) == 0) || - atomic_dec_and_test(®d_buf->ref_count)) { - /* if we used the dma mr, unreg is just NOP */ - if (regd_buf->reg.is_fmr) - iser_unreg_mem(®d_buf->reg); - - if (regd_buf->dma_addr) { - dev = regd_buf->device->ib_device; - ib_dma_unmap_single(dev, - regd_buf->dma_addr, - regd_buf->data_size, - regd_buf->direction); - } - /* else this regd buf is associated with task which we */ - /* dma_unmap_single/sg later */ - return 0; - } else { - iser_dbg("Release deferred, regd.buff: 0x%p\n", regd_buf); - return 1; - } -} - -/** - * iser_reg_single - fills registered buffer descriptor with - * registration information - */ -void iser_reg_single(struct iser_device *device, - struct iser_regd_buf *regd_buf, - enum dma_data_direction direction) -{ - u64 dma_addr; - - dma_addr = ib_dma_map_single(device->ib_device, - regd_buf->virt_addr, - regd_buf->data_size, direction); - BUG_ON(ib_dma_mapping_error(device->ib_device, dma_addr)); - - regd_buf->reg.lkey = device->mr->lkey; - regd_buf->reg.len = regd_buf->data_size; - regd_buf->reg.va = dma_addr; - regd_buf->reg.is_fmr = 0; - - regd_buf->dma_addr = dma_addr; - regd_buf->direction = direction; -} - /** * iser_start_rdma_unaligned_sg */ @@ -474,9 +418,5 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task, return err; } } - - /* take a reference on this regd buf such that it will not be released * - * (eg in send dto completion) before we get the scsi response */ - atomic_inc(®d_buf->ref_count); return 0; } diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 218aa10939a0..18cf65f092e8 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -194,7 +194,7 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn) init_attr.recv_cq = device->rx_cq; init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS; init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS; - init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN; + init_attr.cap.max_send_sge = 2; init_attr.cap.max_recv_sge = 1; init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; init_attr.qp_type = IB_QPT_RC; @@ -701,86 +701,37 @@ int iser_post_recvm(struct iser_conn *ib_conn, int count) } -/** - * iser_dto_to_iov - builds IOV from a dto descriptor - */ -static void iser_dto_to_iov(struct iser_dto *dto, struct ib_sge *iov, int iov_len) -{ - int i; - struct ib_sge *sge; - struct iser_regd_buf *regd_buf; - - if (dto->regd_vector_len > iov_len) { - iser_err("iov size %d too small for posting dto of len %d\n", - iov_len, dto->regd_vector_len); - BUG(); - } - - for (i = 0; i < dto->regd_vector_len; i++) { - sge = &iov[i]; - regd_buf = dto->regd[i]; - - sge->addr = regd_buf->reg.va; - sge->length = regd_buf->reg.len; - sge->lkey = regd_buf->reg.lkey; - - if (dto->used_sz[i] > 0) /* Adjust size */ - sge->length = dto->used_sz[i]; - - /* offset and length should not exceed the regd buf length */ - if (sge->length + dto->offset[i] > regd_buf->reg.len) { - iser_err("Used len:%ld + offset:%d, exceed reg.buf.len:" - "%ld in dto:0x%p [%d], va:0x%08lX\n", - (unsigned long)sge->length, dto->offset[i], - (unsigned long)regd_buf->reg.len, dto, i, - (unsigned long)sge->addr); - BUG(); - } - - sge->addr += dto->offset[i]; /* Adjust offset */ - } -} - - /** * iser_start_send - Initiate a Send DTO operation * * returns 0 on success, -1 on failure */ -int iser_post_send(struct iser_desc *tx_desc) +int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc) { - int ib_ret, ret_val = 0; + int ib_ret; struct ib_send_wr send_wr, *send_wr_failed; - struct ib_sge iov[MAX_REGD_BUF_VECTOR_LEN]; - struct iser_conn *ib_conn; - struct iser_dto *dto = &tx_desc->dto; - ib_conn = dto->ib_conn; - - iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN); + ib_dma_sync_single_for_device(ib_conn->device->ib_device, + tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); send_wr.next = NULL; send_wr.wr_id = (unsigned long)tx_desc; - send_wr.sg_list = iov; - send_wr.num_sge = dto->regd_vector_len; + send_wr.sg_list = tx_desc->tx_sg; + send_wr.num_sge = tx_desc->num_sge; send_wr.opcode = IB_WR_SEND; - send_wr.send_flags = dto->notify_enable ? IB_SEND_SIGNALED : 0; + send_wr.send_flags = IB_SEND_SIGNALED; atomic_inc(&ib_conn->post_send_buf_count); ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed); if (ib_ret) { - iser_err("Failed to start SEND DTO, dto: 0x%p, IOV len: %d\n", - dto, dto->regd_vector_len); iser_err("ib_post_send failed, ret:%d\n", ib_ret); atomic_dec(&ib_conn->post_send_buf_count); - ret_val = -1; } - - return ret_val; + return ib_ret; } -static void iser_handle_comp_error(struct iser_desc *desc, +static void iser_handle_comp_error(struct iser_tx_desc *desc, struct iser_conn *ib_conn) { if (desc && desc->type == ISCSI_TX_DATAOUT) @@ -809,16 +760,16 @@ static int iser_drain_tx_cq(struct iser_device *device) { struct ib_cq *cq = device->tx_cq; struct ib_wc wc; - struct iser_desc *tx_desc; + struct iser_tx_desc *tx_desc; struct iser_conn *ib_conn; int completed_tx = 0; while (ib_poll_cq(cq, 1, &wc) == 1) { - tx_desc = (struct iser_desc *) (unsigned long) wc.wr_id; + tx_desc = (struct iser_tx_desc *) (unsigned long) wc.wr_id; ib_conn = wc.qp->qp_context; if (wc.status == IB_WC_SUCCESS) { if (wc.opcode == IB_WC_SEND) - iser_snd_completion(tx_desc); + iser_snd_completion(tx_desc, ib_conn); else iser_err("expected opcode %d got %d\n", IB_WC_SEND, wc.opcode); -- cgit v1.2.3-59-g8ed1b From 528f4e8c8341706a354ff96daf615e678e9b296f Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:20:43 +0000 Subject: IB/iser: Use atomic allocations Two minor flows in iSER's data path still use allocations; move them to be atomic as a preperation step towards moving to use libiscsi passthrough mode. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_initiator.c | 2 +- drivers/infiniband/ulp/iser/iser_memory.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 3be3a13b5e30..e27eb8757650 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -373,7 +373,7 @@ int iser_send_data_out(struct iscsi_conn *conn, iser_dbg("%s itt %d dseg_len %d offset %d\n", __func__,(int)itt,(int)data_seg_len,(int)buf_offset); - tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_NOIO); + tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_ATOMIC); if (tx_desc == NULL) { iser_err("Failed to alloc desc for post dataout\n"); return -ENOMEM; diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 5e32e8f1edf5..fb88d6896b67 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -53,10 +53,10 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, unsigned long cmd_data_len = data->data_len; if (cmd_data_len > ISER_KMALLOC_THRESHOLD) - mem = (void *)__get_free_pages(GFP_NOIO, + mem = (void *)__get_free_pages(GFP_ATOMIC, ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT); else - mem = kmalloc(cmd_data_len, GFP_NOIO); + mem = kmalloc(cmd_data_len, GFP_ATOMIC); if (mem == NULL) { iser_err("Failed to allocate mem size %d %d for copying sglist\n", -- cgit v1.2.3-59-g8ed1b From aae3c995ff74a183d15207436d383942485b2edd Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:21:18 +0000 Subject: IB/iser: Remove unnecessary connection checks Remove unnecessary checks for the IB connection state and for QP overflow, as conn state changes are reported by iSER to libiscsi and handled there. QP overflow is theoretically possible only when unsolicited data-outs are used; anyway it's being checked and handled by HW drivers. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.h | 3 --- drivers/infiniband/ulp/iser/iser_initiator.c | 38 ---------------------------- drivers/infiniband/ulp/iser/iser_verbs.c | 11 -------- 3 files changed, 52 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 269f23f1b6d1..036934cdcb92 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -357,9 +357,6 @@ int iser_post_recvl(struct iser_conn *ib_conn); int iser_post_recvm(struct iser_conn *ib_conn, int count); int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc); -int iser_conn_state_comp(struct iser_conn *ib_conn, - enum iser_ib_conn_state comp); - int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, struct iser_data_buf *data, enum iser_data_dir iser_dir, diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index e27eb8757650..27450eebd1e4 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -260,20 +260,6 @@ int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) return 0; } -static int -iser_check_xmit(struct iscsi_conn *conn, void *task) -{ - struct iscsi_iser_conn *iser_conn = conn->dd_data; - - if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) == - ISER_QP_MAX_REQ_DTOS) { - iser_dbg("%ld can't xmit task %p\n",jiffies,task); - return -ENOBUFS; - } - return 0; -} - - /** * iser_send_command - send command PDU */ @@ -289,13 +275,6 @@ int iser_send_command(struct iscsi_conn *conn, struct scsi_cmnd *sc = task->sc; struct iser_tx_desc *tx_desc = &iser_task->desc; - if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { - iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); - return -EPERM; - } - if (iser_check_xmit(conn, task)) - return -ENOBUFS; - edtl = ntohl(hdr->data_length); /* build the tx desc regd header and add it to the tx desc dto */ @@ -357,15 +336,6 @@ int iser_send_data_out(struct iscsi_conn *conn, int err = 0; struct ib_sge *tx_dsg; - - if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { - iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); - return -EPERM; - } - - if (iser_check_xmit(conn, task)) - return -ENOBUFS; - itt = (__force uint32_t)hdr->itt; data_seg_len = ntoh24(hdr->dlength); buf_offset = ntohl(hdr->offset); @@ -425,14 +395,6 @@ int iser_send_control(struct iscsi_conn *conn, int err = 0; struct iser_device *device; - if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) { - iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn); - return -EPERM; - } - - if (iser_check_xmit(conn, task)) - return -ENOBUFS; - /* build the tx desc regd header and add it to the tx desc dto */ mdesc->type = ISCSI_TX_CONTROL; iser_create_send_desc(iser_conn->ib_conn, mdesc); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 18cf65f092e8..308d17bb5146 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -300,17 +300,6 @@ static void iser_device_try_release(struct iser_device *device) mutex_unlock(&ig.device_list_mutex); } -int iser_conn_state_comp(struct iser_conn *ib_conn, - enum iser_ib_conn_state comp) -{ - int ret; - - spin_lock_bh(&ib_conn->lock); - ret = (ib_conn->state == comp); - spin_unlock_bh(&ib_conn->lock); - return ret; -} - static int iser_conn_state_comp_exch(struct iser_conn *ib_conn, enum iser_ib_conn_state comp, enum iser_ib_conn_state exch) -- cgit v1.2.3-59-g8ed1b From 962b4b528ba87c8d837bb04794a1918c7de631cd Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:22:34 +0000 Subject: IB/iser: Use libiscsi passthrough mode libiscsi passthrough mode invokes the transport xmit calls directly without first going through an internal queue, unlike the other mode, which uses a queue and a xmitworker thread. Now that the "cant_sleep" prerequisite of iscsi_host_alloc is met, move to use it. Handling xmit errors is now done by the passthrough flow of libiscsi. Since the queue/worker aren't used in this mode, the code that schedules the xmitworker is removed. Signed-off-by: Or Gerlitz Reviewed-by: Mike Christie Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iscsi_iser.c | 11 +++-------- drivers/infiniband/ulp/iser/iser_initiator.c | 12 ------------ 2 files changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 331147b71a91..71237f8f78f7 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -190,7 +190,7 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) { int error = 0; - iser_dbg("task deq [cid %d itt 0x%x]\n", conn->id, task->itt); + iser_dbg("mtask xmit [cid %d itt 0x%x]\n", conn->id, task->itt); error = iser_send_control(conn, task); @@ -200,9 +200,6 @@ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) * - if yes, the task is recycled at iscsi_complete_pdu * - if no, the task is recycled at iser_snd_completion */ - if (error && error != -ENOBUFS) - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return error; } @@ -254,7 +251,7 @@ iscsi_iser_task_xmit(struct iscsi_task *task) task->imm_count, task->unsol_r2t.data_length); } - iser_dbg("task deq [cid %d itt 0x%x]\n", + iser_dbg("ctask xmit [cid %d itt 0x%x]\n", conn->id, task->itt); /* Send the cmd PDU */ @@ -270,8 +267,6 @@ iscsi_iser_task_xmit(struct iscsi_task *task) error = iscsi_iser_task_xmit_unsol_data(conn, task); iscsi_iser_task_xmit_exit: - if (error && error != -ENOBUFS) - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return error; } @@ -423,7 +418,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, struct Scsi_Host *shost; struct iser_conn *ib_conn; - shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 1); + shost = iscsi_host_alloc(&iscsi_iser_sht, 0, 0); if (!shost) return NULL; shost->transportt = iscsi_iser_scsi_transport; diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 27450eebd1e4..f447ace89cb1 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -514,10 +514,7 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, void iser_snd_completion(struct iser_tx_desc *tx_desc, struct iser_conn *ib_conn) { - struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn; - struct iscsi_conn *conn = iser_conn->iscsi_conn; struct iscsi_task *task; - int resume_tx = 0; struct iser_device *device = ib_conn->device; if (tx_desc->type == ISCSI_TX_DATAOUT) { @@ -526,17 +523,8 @@ void iser_snd_completion(struct iser_tx_desc *tx_desc, kmem_cache_free(ig.desc_cache, tx_desc); } - if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) == - ISER_QP_MAX_REQ_DTOS) - resume_tx = 1; - atomic_dec(&ib_conn->post_send_buf_count); - if (resume_tx) { - iser_dbg("%ld resuming tx\n",jiffies); - iscsi_conn_queue_work(conn); - } - if (tx_desc->type == ISCSI_TX_CONTROL) { /* this arithmetic is legal by libiscsi dd_data allocation */ task = (void *) ((long)(void *)tx_desc - -- cgit v1.2.3-59-g8ed1b From 88ec415772144f4fc4a50b123bb6200de686898d Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 8 Feb 2010 13:23:11 +0000 Subject: IB/iser: Remove redundant locking from iser scsi command response flow Currently the iSER receive completion flow takes the session lock twice. Optimize it to avoid the first one by letting iser_task_rdma_finalize() be called only from the cleanup_task callback invoked by iscsi_free_task, thus reducing the contention on the session lock between the scsi command submission to the scsi command completion flows. Signed-off-by: Or Gerlitz Reviewed-by: Mike Christie Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/iser/iser_initiator.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index f447ace89cb1..0b9ef0716588 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -440,10 +440,7 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, struct iser_conn *ib_conn) { struct iscsi_iser_conn *conn = ib_conn->iser_conn; - struct iscsi_task *task; - struct iscsi_iser_task *iser_task; struct iscsi_hdr *hdr; - unsigned char opcode; u64 rx_dma; int rx_buflen, outstanding, count, err; @@ -464,28 +461,6 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc, iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode, hdr->itt, (int)(rx_xfer_len - ISER_HEADERS_LEN)); - opcode = hdr->opcode & ISCSI_OPCODE_MASK; - - if (opcode == ISCSI_OP_SCSI_CMD_RSP) { - spin_lock(&conn->iscsi_conn->session->lock); - task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt); - if (task) - __iscsi_get_task(task); - spin_unlock(&conn->iscsi_conn->session->lock); - - if (!task) - iser_err("itt can't be matched to task!!! " - "conn %p opcode %d itt %d\n", - conn->iscsi_conn, opcode, hdr->itt); - else { - iser_task = task->dd_data; - iser_dbg("itt %d task %p\n",hdr->itt, task); - iser_task->status = ISER_TASK_STATUS_COMPLETED; - iser_task_rdma_finalize(iser_task); - iscsi_put_task(task); - } - } - iscsi_iser_recv(conn->iscsi_conn, hdr, rx_desc->data, rx_xfer_len - ISER_HEADERS_LEN); -- cgit v1.2.3-59-g8ed1b From 055422ddbb0a7610c5f57a056743d7336a39e90f Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:07:49 +0000 Subject: IB/uverbs: Convert *cdev to cdev in struct ib_uverbs_device Instead of storing a pointer to a cdev, embed the entire struct cdev. This change allows us to use the container_of() macro in ib_uverbs_open() in a future patch. This change increases the size of struct ib_uverbs_device to 168 bytes across 3 cachelines from 80 bytes in 2 cachelines. However, we rearrange the members so that everything fits into the first cacheline except for the struct cdev. Finally, we don't touch the cdev in any fastpaths, so this change shouldn't negatively affect performance. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 7 ++++--- drivers/infiniband/core/uverbs_main.c | 23 ++++++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index b3ea9587dc80..e695f65328a3 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -69,12 +70,12 @@ struct ib_uverbs_device { struct kref ref; + int num_comp_vectors; struct completion comp; - int devnum; - struct cdev *cdev; struct device *dev; struct ib_device *ib_dev; - int num_comp_vectors; + int devnum; + struct cdev cdev; }; struct ib_uverbs_event_file { diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 5f284ffd430e..5da9a734959a 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -43,7 +43,6 @@ #include #include #include -#include #include @@ -761,17 +760,15 @@ static void ib_uverbs_add_one(struct ib_device *device) uverbs_dev->ib_dev = device; uverbs_dev->num_comp_vectors = device->num_comp_vectors; - uverbs_dev->cdev = cdev_alloc(); - if (!uverbs_dev->cdev) - goto err; - uverbs_dev->cdev->owner = THIS_MODULE; - uverbs_dev->cdev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; - kobject_set_name(&uverbs_dev->cdev->kobj, "uverbs%d", uverbs_dev->devnum); - if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + cdev_init(&uverbs_dev->cdev, NULL); + uverbs_dev->cdev.owner = THIS_MODULE; + uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; + kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); + if (cdev_add(&uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) goto err_cdev; uverbs_dev->dev = device_create(uverbs_class, device->dma_device, - uverbs_dev->cdev->dev, uverbs_dev, + uverbs_dev->cdev.dev, uverbs_dev, "uverbs%d", uverbs_dev->devnum); if (IS_ERR(uverbs_dev->dev)) goto err_cdev; @@ -790,10 +787,10 @@ static void ib_uverbs_add_one(struct ib_device *device) return; err_class: - device_destroy(uverbs_class, uverbs_dev->cdev->dev); + device_destroy(uverbs_class, uverbs_dev->cdev.dev); err_cdev: - cdev_del(uverbs_dev->cdev); + cdev_del(&uverbs_dev->cdev); clear_bit(uverbs_dev->devnum, dev_map); err: @@ -811,8 +808,8 @@ static void ib_uverbs_remove_one(struct ib_device *device) return; dev_set_drvdata(uverbs_dev->dev, NULL); - device_destroy(uverbs_class, uverbs_dev->cdev->dev); - cdev_del(uverbs_dev->cdev); + device_destroy(uverbs_class, uverbs_dev->cdev.dev); + cdev_del(&uverbs_dev->cdev); spin_lock(&map_lock); dev_table[uverbs_dev->devnum] = NULL; -- cgit v1.2.3-59-g8ed1b From 2a72f212263701b927559f6850446421d5906c41 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:07:54 +0000 Subject: IB/uverbs: Remove dev_table dev_table's raison d'etre was to associate an inode back to a struct ib_uverbs_device. However, now that we've converted ib_uverbs_device to contain an embedded cdev (instead of a *cdev), we can use the container_of() macro and cast back to the containing device. There's no longer any need for dev_table, so get rid of it. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 5da9a734959a..3f11292dda13 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -74,7 +74,6 @@ DEFINE_IDR(ib_uverbs_qp_idr); DEFINE_IDR(ib_uverbs_srq_idr); static DEFINE_SPINLOCK(map_lock); -static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, @@ -616,14 +615,12 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) /* * ib_uverbs_open() does not need the BKL: * - * - dev_table[] accesses are protected by map_lock, the - * ib_uverbs_device structures are properly reference counted, and + * - the ib_uverbs_device structures are properly reference counted and * everything else is purely local to the file being created, so * races against other open calls are not a problem; * - there is no ioctl method to race against; - * - the device is added to dev_table[] as the last part of module - * initialization, the open method will either immediately run - * -ENXIO, or all required initialization will be done. + * - the open method will either immediately run -ENXIO, or all + * required initialization will be done. */ static int ib_uverbs_open(struct inode *inode, struct file *filp) { @@ -631,13 +628,10 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) struct ib_uverbs_file *file; int ret; - spin_lock(&map_lock); - dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR]; + dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev); if (dev) kref_get(&dev->ref); - spin_unlock(&map_lock); - - if (!dev) + else return -ENXIO; if (!try_module_get(dev->ib_dev->owner)) { @@ -778,10 +772,6 @@ static void ib_uverbs_add_one(struct ib_device *device) if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version)) goto err_class; - spin_lock(&map_lock); - dev_table[uverbs_dev->devnum] = uverbs_dev; - spin_unlock(&map_lock); - ib_set_client_data(device, &uverbs_client, uverbs_dev); return; @@ -811,10 +801,6 @@ static void ib_uverbs_remove_one(struct ib_device *device) device_destroy(uverbs_class, uverbs_dev->cdev.dev); cdev_del(&uverbs_dev->cdev); - spin_lock(&map_lock); - dev_table[uverbs_dev->devnum] = NULL; - spin_unlock(&map_lock); - clear_bit(uverbs_dev->devnum, dev_map); kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); -- cgit v1.2.3-59-g8ed1b From 38707980c42c58e2d00b34ecaa40cf5207bdd9d1 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:07:59 +0000 Subject: IB/uverbs: Use stack variable 'devnum' in ib_uverbs_add_one This change is not useful by itself, but it sets us up for a future change that allows us to dynamically allocate device numbers in case we have more than IB_UVERBS_MAX_DEVICES in the system. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 3f11292dda13..acae9ed05728 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -730,6 +730,7 @@ static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static void ib_uverbs_add_one(struct ib_device *device) { + int devnum; struct ib_uverbs_device *uverbs_dev; if (!device->alloc_ucontext) @@ -743,12 +744,13 @@ static void ib_uverbs_add_one(struct ib_device *device) init_completion(&uverbs_dev->comp); spin_lock(&map_lock); - uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); - if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { + devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); + if (devnum >= IB_UVERBS_MAX_DEVICES) { spin_unlock(&map_lock); goto err; } - set_bit(uverbs_dev->devnum, dev_map); + uverbs_dev->devnum = devnum; + set_bit(devnum, dev_map); spin_unlock(&map_lock); uverbs_dev->ib_dev = device; @@ -758,7 +760,7 @@ static void ib_uverbs_add_one(struct ib_device *device) uverbs_dev->cdev.owner = THIS_MODULE; uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); - if (cdev_add(&uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + if (cdev_add(&uverbs_dev->cdev, IB_UVERBS_BASE_DEV + devnum, 1)) goto err_cdev; uverbs_dev->dev = device_create(uverbs_class, device->dma_device, @@ -781,7 +783,7 @@ err_class: err_cdev: cdev_del(&uverbs_dev->cdev); - clear_bit(uverbs_dev->devnum, dev_map); + clear_bit(devnum, dev_map); err: kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); -- cgit v1.2.3-59-g8ed1b From ddbd6883013dcc9f9ca5c0b26f79d9334a95926c Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:04 +0000 Subject: IB/uverbs: use stack variable 'base' in ib_uverbs_add_one This change is not useful by itself, but sets us up for a future change that allows us to support more than IB_UVERBS_MAX_DEVICES in a system. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index acae9ed05728..8c594cde8a1d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -731,6 +731,7 @@ static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static void ib_uverbs_add_one(struct ib_device *device) { int devnum; + dev_t base; struct ib_uverbs_device *uverbs_dev; if (!device->alloc_ucontext) @@ -750,6 +751,7 @@ static void ib_uverbs_add_one(struct ib_device *device) goto err; } uverbs_dev->devnum = devnum; + base = devnum + IB_UVERBS_BASE_DEV; set_bit(devnum, dev_map); spin_unlock(&map_lock); @@ -760,7 +762,7 @@ static void ib_uverbs_add_one(struct ib_device *device) uverbs_dev->cdev.owner = THIS_MODULE; uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); - if (cdev_add(&uverbs_dev->cdev, IB_UVERBS_BASE_DEV + devnum, 1)) + if (cdev_add(&uverbs_dev->cdev, base, 1)) goto err_cdev; uverbs_dev->dev = device_create(uverbs_class, device->dma_device, -- cgit v1.2.3-59-g8ed1b From 6d6a0e71eec5886f2511632a38f28f1ed7794d70 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:09 +0000 Subject: IB/uverbs: Increase maximum devices supported Some large systems may support more than IB_UVERBS_MAX_DEVICES (currently 32). This change allows us to support more devices in a backwards-compatible manner. The first IB_UVERBS_MAX_DEVICES keep the same major/minor device numbers that they've always had. If there are more than IB_UVERBS_MAX_DEVICES, we then dynamically request a new major device number (new minors start at 0). This change increases the maximum number of HCAs to 64 (from 32). Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 56 +++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 8c594cde8a1d..7d42d550e87e 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -728,6 +728,34 @@ static ssize_t show_abi_version(struct class *class, char *buf) } static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); +static dev_t overflow_maj; +static DECLARE_BITMAP(overflow_map, IB_UVERBS_MAX_DEVICES); + +/* + * If we have more than IB_UVERBS_MAX_DEVICES, dynamically overflow by + * requesting a new major number and doubling the number of max devices we + * support. It's stupid, but simple. + */ +static int find_overflow_devnum(void) +{ + int ret; + + if (!overflow_maj) { + ret = alloc_chrdev_region(&overflow_maj, 0, IB_UVERBS_MAX_DEVICES, + "infiniband_verbs"); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register dynamic device number\n"); + return ret; + } + } + + ret = find_first_zero_bit(overflow_map, IB_UVERBS_MAX_DEVICES); + if (ret >= IB_UVERBS_MAX_DEVICES) + return -1; + + return ret; +} + static void ib_uverbs_add_one(struct ib_device *device) { int devnum; @@ -748,11 +776,19 @@ static void ib_uverbs_add_one(struct ib_device *device) devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); if (devnum >= IB_UVERBS_MAX_DEVICES) { spin_unlock(&map_lock); - goto err; + devnum = find_overflow_devnum(); + if (devnum < 0) + goto err; + + spin_lock(&map_lock); + uverbs_dev->devnum = devnum + IB_UVERBS_MAX_DEVICES; + base = devnum + overflow_maj; + set_bit(devnum, overflow_map); + } else { + uverbs_dev->devnum = devnum; + base = devnum + IB_UVERBS_BASE_DEV; + set_bit(devnum, dev_map); } - uverbs_dev->devnum = devnum; - base = devnum + IB_UVERBS_BASE_DEV; - set_bit(devnum, dev_map); spin_unlock(&map_lock); uverbs_dev->ib_dev = device; @@ -785,7 +821,10 @@ err_class: err_cdev: cdev_del(&uverbs_dev->cdev); - clear_bit(devnum, dev_map); + if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES) + clear_bit(devnum, dev_map); + else + clear_bit(devnum, overflow_map); err: kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); @@ -805,7 +844,10 @@ static void ib_uverbs_remove_one(struct ib_device *device) device_destroy(uverbs_class, uverbs_dev->cdev.dev); cdev_del(&uverbs_dev->cdev); - clear_bit(uverbs_dev->devnum, dev_map); + if (uverbs_dev->devnum < IB_UVERBS_MAX_DEVICES) + clear_bit(uverbs_dev->devnum, dev_map); + else + clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map); kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); wait_for_completion(&uverbs_dev->comp); @@ -895,6 +937,8 @@ static void __exit ib_uverbs_cleanup(void) unregister_filesystem(&uverbs_event_fs); class_destroy(uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); + if (overflow_maj) + unregister_chrdev_region(overflow_maj, IB_UVERBS_MAX_DEVICES); idr_destroy(&ib_uverbs_pd_idr); idr_destroy(&ib_uverbs_mr_idr); idr_destroy(&ib_uverbs_mw_idr); -- cgit v1.2.3-59-g8ed1b From 830a38713816fb1f0d05efc339bf41e91ac74379 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:14 +0000 Subject: IB/uverbs: Pack struct ib_uverbs_event_file tighter Eliminate some padding in the structure by rearranging the members. sizeof(struct ib_uverbs_event_file) is now 72 bytes (from 80) and more members now fit in the first cacheline. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index e695f65328a3..e54d9ac6d1ca 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -80,13 +80,13 @@ struct ib_uverbs_device { struct ib_uverbs_event_file { struct kref ref; + int is_async; struct ib_uverbs_file *uverbs_file; spinlock_t lock; + int is_closed; wait_queue_head_t poll_wait; struct fasync_struct *async_queue; struct list_head event_list; - int is_async; - int is_closed; }; struct ib_uverbs_file { -- cgit v1.2.3-59-g8ed1b From 9afed76d59749f1b95e5e1d7d5bc4c3041852aa9 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:19 +0000 Subject: IB/uverbs: Whitespace cleanup Clean up the errors as shown when 'let c_space_errors=1' is set in vim. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/uverbs_main.c | 68 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 7d42d550e87e..dbf04511cf0a 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -79,34 +79,34 @@ static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) = { - [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, - [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, - [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, - [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, - [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, - [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, - [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, + [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, + [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, + [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, + [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, + [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, + [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, + [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, - [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, - [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq, - [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq, - [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq, - [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, - [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, - [IB_USER_VERBS_CMD_QUERY_QP] = ib_uverbs_query_qp, - [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, - [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, - [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send, - [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv, - [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv, - [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah, - [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah, - [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, - [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, - [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, - [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, - [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq, - [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, + [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, + [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq, + [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq, + [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq, + [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, + [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, + [IB_USER_VERBS_CMD_QUERY_QP] = ib_uverbs_query_qp, + [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, + [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, + [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send, + [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv, + [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv, + [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah, + [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah, + [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, + [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, + [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, + [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, + [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq, + [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, }; static struct vfsmount *uverbs_event_mnt; @@ -368,7 +368,7 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp) static const struct file_operations uverbs_event_fops = { .owner = THIS_MODULE, - .read = ib_uverbs_event_read, + .read = ib_uverbs_event_read, .poll = ib_uverbs_event_poll, .release = ib_uverbs_event_close, .fasync = ib_uverbs_event_fasync @@ -678,17 +678,17 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp) } static const struct file_operations uverbs_fops = { - .owner = THIS_MODULE, - .write = ib_uverbs_write, - .open = ib_uverbs_open, + .owner = THIS_MODULE, + .write = ib_uverbs_write, + .open = ib_uverbs_open, .release = ib_uverbs_close }; static const struct file_operations uverbs_mmap_fops = { - .owner = THIS_MODULE, - .write = ib_uverbs_write, + .owner = THIS_MODULE, + .write = ib_uverbs_write, .mmap = ib_uverbs_mmap, - .open = ib_uverbs_open, + .open = ib_uverbs_open, .release = ib_uverbs_close }; -- cgit v1.2.3-59-g8ed1b From 2b937afcab34e4f739e2f7cd6062870fbe6b2ccf Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:25 +0000 Subject: IB/umad: Convert *cdev to cdev in struct ib_umad_port Instead of storing pointers to cdev and sm_cdev, embed the full structures instead. This change allows us to use the container_of() macro in ib_umad_open() and ib_umad_sm_open() in a future patch. This change increases the size of struct ib_umad_port to 320 bytes from 128. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 46 +++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 7de02969ed7d..40440ef1b31c 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -87,10 +87,10 @@ enum { */ struct ib_umad_port { - struct cdev *cdev; + struct cdev cdev; struct device *dev; - struct cdev *sm_cdev; + struct cdev sm_cdev; struct device *sm_dev; struct semaphore sm_sem; @@ -1008,17 +1008,14 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, mutex_init(&port->file_mutex); INIT_LIST_HEAD(&port->file_list); - port->cdev = cdev_alloc(); - if (!port->cdev) - return -1; - port->cdev->owner = THIS_MODULE; - port->cdev->ops = &umad_fops; - kobject_set_name(&port->cdev->kobj, "umad%d", port->dev_num); - if (cdev_add(port->cdev, base_dev + port->dev_num, 1)) + cdev_init(&port->cdev, &umad_fops); + port->cdev.owner = THIS_MODULE; + kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num); + if (cdev_add(&port->cdev, base_dev + port->dev_num, 1)) goto err_cdev; port->dev = device_create(umad_class, device->dma_device, - port->cdev->dev, port, + port->cdev.dev, port, "umad%d", port->dev_num); if (IS_ERR(port->dev)) goto err_cdev; @@ -1028,17 +1025,14 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (device_create_file(port->dev, &dev_attr_port)) goto err_dev; - port->sm_cdev = cdev_alloc(); - if (!port->sm_cdev) - goto err_dev; - port->sm_cdev->owner = THIS_MODULE; - port->sm_cdev->ops = &umad_sm_fops; - kobject_set_name(&port->sm_cdev->kobj, "issm%d", port->dev_num); - if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) + cdev_init(&port->sm_cdev, &umad_sm_fops); + port->sm_cdev.owner = THIS_MODULE; + kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num); + if (cdev_add(&port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) goto err_sm_cdev; port->sm_dev = device_create(umad_class, device->dma_device, - port->sm_cdev->dev, port, + port->sm_cdev.dev, port, "issm%d", port->dev_num); if (IS_ERR(port->sm_dev)) goto err_sm_cdev; @@ -1055,16 +1049,16 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, return 0; err_sm_dev: - device_destroy(umad_class, port->sm_cdev->dev); + device_destroy(umad_class, port->sm_cdev.dev); err_sm_cdev: - cdev_del(port->sm_cdev); + cdev_del(&port->sm_cdev); err_dev: - device_destroy(umad_class, port->cdev->dev); + device_destroy(umad_class, port->cdev.dev); err_cdev: - cdev_del(port->cdev); + cdev_del(&port->cdev); clear_bit(port->dev_num, dev_map); return -1; @@ -1079,11 +1073,11 @@ static void ib_umad_kill_port(struct ib_umad_port *port) dev_set_drvdata(port->dev, NULL); dev_set_drvdata(port->sm_dev, NULL); - device_destroy(umad_class, port->cdev->dev); - device_destroy(umad_class, port->sm_cdev->dev); + device_destroy(umad_class, port->cdev.dev); + device_destroy(umad_class, port->sm_cdev.dev); - cdev_del(port->cdev); - cdev_del(port->sm_cdev); + cdev_del(&port->cdev); + cdev_del(&port->sm_cdev); spin_lock(&port_lock); umad_port[port->dev_num] = NULL; -- cgit v1.2.3-59-g8ed1b From 6aa2a86ec430fb1ae739bd065d7ea6596997a2cf Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:30 +0000 Subject: IB/umad: Remove port_table[] We no longer need this data structure, as it was used to associate an inode back to a struct ib_umad_port during ->open(). But now that we're embedding a struct cdev in struct ib_umad_port, we can use the container_of() macro to go from the inode back to the device instead. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 45 ++++++++------------------------------ 1 file changed, 9 insertions(+), 36 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 40440ef1b31c..46c88795cc75 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -65,12 +65,9 @@ enum { }; /* - * Our lifetime rules for these structs are the following: each time a - * device special file is opened, we look up the corresponding struct - * ib_umad_port by minor in the umad_port[] table while holding the - * port_lock. If this lookup succeeds, we take a reference on the - * ib_umad_port's struct ib_umad_device while still holding the - * port_lock; if the lookup fails, we fail the open(). We drop these + * Our lifetime rules for these structs are the following: + * device special file is opened, we take a reference on the + * ib_umad_port's struct ib_umad_device. We drop these * references in the corresponding close(). * * In addition to references coming from open character devices, there @@ -78,12 +75,7 @@ enum { * module's reference taken when allocating the ib_umad_device in * ib_umad_add_one(). * - * When destroying an ib_umad_device, we clear all of its - * ib_umad_ports from umad_port[] while holding port_lock before - * dropping the module's reference to the ib_umad_device. This is - * always safe because any open() calls will either succeed and obtain - * a reference before we clear the umad_port[] entries, or fail after - * we clear the umad_port[] entries. + * When destroying an ib_umad_device, we drop the module's reference. */ struct ib_umad_port { @@ -136,7 +128,6 @@ static struct class *umad_class; static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); static DEFINE_SPINLOCK(port_lock); -static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS]; static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS); static void ib_umad_add_one(struct ib_device *device); @@ -779,15 +770,11 @@ static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd, /* * ib_umad_open() does not need the BKL: * - * - umad_port[] accesses are protected by port_lock, the - * ib_umad_port structures are properly reference counted, and + * - the ib_umad_port structures are properly reference counted, and * everything else is purely local to the file being created, so * races against other open calls are not a problem; * - the ioctl method does not affect any global state outside of the * file structure being operated on; - * - the port is added to umad_port[] as the last part of module - * initialization so the open method will either immediately run - * -ENXIO, or all required initialization will be done. */ static int ib_umad_open(struct inode *inode, struct file *filp) { @@ -795,13 +782,10 @@ static int ib_umad_open(struct inode *inode, struct file *filp) struct ib_umad_file *file; int ret = 0; - spin_lock(&port_lock); - port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE]; + port = container_of(inode->i_cdev, struct ib_umad_port, cdev); if (port) kref_get(&port->umad_dev->ref); - spin_unlock(&port_lock); - - if (!port) + else return -ENXIO; mutex_lock(&port->file_mutex); @@ -892,13 +876,10 @@ static int ib_umad_sm_open(struct inode *inode, struct file *filp) }; int ret; - spin_lock(&port_lock); - port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS]; + port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev); if (port) kref_get(&port->umad_dev->ref); - spin_unlock(&port_lock); - - if (!port) + else return -ENXIO; if (filp->f_flags & O_NONBLOCK) { @@ -1042,10 +1023,6 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (device_create_file(port->sm_dev, &dev_attr_port)) goto err_sm_dev; - spin_lock(&port_lock); - umad_port[port->dev_num] = port; - spin_unlock(&port_lock); - return 0; err_sm_dev: @@ -1079,10 +1056,6 @@ static void ib_umad_kill_port(struct ib_umad_port *port) cdev_del(&port->cdev); cdev_del(&port->sm_cdev); - spin_lock(&port_lock); - umad_port[port->dev_num] = NULL; - spin_unlock(&port_lock); - mutex_lock(&port->file_mutex); port->ib_dev = NULL; -- cgit v1.2.3-59-g8ed1b From d451b8df9f7e572ea77f976745f424dd1dae8aeb Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:35 +0000 Subject: IB/umad: Use stack variable 'devnum' in ib_umad_init_port This change is not useful by itself, but sets us up for a future change that allows us to dynamically allocate device numbers in case we have more than IB_UMAD_MAX_PORTS in the system. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 46c88795cc75..df403ec49d94 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -974,13 +974,16 @@ static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); static int ib_umad_init_port(struct ib_device *device, int port_num, struct ib_umad_port *port) { + int devnum; + spin_lock(&port_lock); - port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); - if (port->dev_num >= IB_UMAD_MAX_PORTS) { + devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); + if (devnum >= IB_UMAD_MAX_PORTS) { spin_unlock(&port_lock); return -1; } - set_bit(port->dev_num, dev_map); + port->dev_num = devnum; + set_bit(devnum, dev_map); spin_unlock(&port_lock); port->ib_dev = device; @@ -992,7 +995,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, cdev_init(&port->cdev, &umad_fops); port->cdev.owner = THIS_MODULE; kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num); - if (cdev_add(&port->cdev, base_dev + port->dev_num, 1)) + if (cdev_add(&port->cdev, base_dev + devnum, 1)) goto err_cdev; port->dev = device_create(umad_class, device->dma_device, @@ -1009,7 +1012,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, cdev_init(&port->sm_cdev, &umad_sm_fops); port->sm_cdev.owner = THIS_MODULE; kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num); - if (cdev_add(&port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) + if (cdev_add(&port->sm_cdev, base_dev + devnum + IB_UMAD_MAX_PORTS, 1)) goto err_sm_cdev; port->sm_dev = device_create(umad_class, device->dma_device, @@ -1036,7 +1039,7 @@ err_dev: err_cdev: cdev_del(&port->cdev); - clear_bit(port->dev_num, dev_map); + clear_bit(devnum, dev_map); return -1; } -- cgit v1.2.3-59-g8ed1b From dc2ed5e3c963490a4fe934b482537d1274961ecb Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:40 +0000 Subject: IB/umad: Use stack variable 'base' in ib_umad_init_port This change is not useful by itself, but sets us up for a future change that allows us to support more than IB_UMAD_MAX_PORTS in a system. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index df403ec49d94..5a66bd062389 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -975,6 +975,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, struct ib_umad_port *port) { int devnum; + dev_t base; spin_lock(&port_lock); devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); @@ -983,6 +984,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, return -1; } port->dev_num = devnum; + base = devnum + base_dev; set_bit(devnum, dev_map); spin_unlock(&port_lock); @@ -995,7 +997,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, cdev_init(&port->cdev, &umad_fops); port->cdev.owner = THIS_MODULE; kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num); - if (cdev_add(&port->cdev, base_dev + devnum, 1)) + if (cdev_add(&port->cdev, base, 1)) goto err_cdev; port->dev = device_create(umad_class, device->dma_device, @@ -1009,10 +1011,11 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, if (device_create_file(port->dev, &dev_attr_port)) goto err_dev; + base += IB_UMAD_MAX_PORTS; cdev_init(&port->sm_cdev, &umad_sm_fops); port->sm_cdev.owner = THIS_MODULE; kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num); - if (cdev_add(&port->sm_cdev, base_dev + devnum + IB_UMAD_MAX_PORTS, 1)) + if (cdev_add(&port->sm_cdev, base, 1)) goto err_sm_cdev; port->sm_dev = device_create(umad_class, device->dma_device, -- cgit v1.2.3-59-g8ed1b From 8698d3feccda66fcb52748e7c7690bd1003f7849 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:45 +0000 Subject: IB/umad: Increase maximum devices supported Some large systems may support more than IB_UMAD_MAX_PORTS (currently 64). This change allows us to support more ports in a backwards-compatible manner. The first IB_UMAD_MAX_PORTS keep the same major/minor device numbers they've always had. If there are more than IB_UMAD_MAX_PORTS, we then dynamically request a new major device number (new minors start at 0). Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 50 +++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 5a66bd062389..57818aea9967 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -971,6 +971,28 @@ static ssize_t show_abi_version(struct class *class, char *buf) } static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); +static dev_t overflow_maj; +static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS); +static int find_overflow_devnum(void) +{ + int ret; + + if (!overflow_maj) { + ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2, + "infiniband_mad"); + if (ret) { + printk(KERN_ERR "user_mad: couldn't register dynamic device number\n"); + return ret; + } + } + + ret = find_first_zero_bit(overflow_map, IB_UMAD_MAX_PORTS); + if (ret >= IB_UMAD_MAX_PORTS) + return -1; + + return ret; +} + static int ib_umad_init_port(struct ib_device *device, int port_num, struct ib_umad_port *port) { @@ -981,11 +1003,19 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); if (devnum >= IB_UMAD_MAX_PORTS) { spin_unlock(&port_lock); - return -1; + devnum = find_overflow_devnum(); + if (devnum < 0) + return -1; + + spin_lock(&port_lock); + port->dev_num = devnum + IB_UMAD_MAX_PORTS; + base = devnum + overflow_maj; + set_bit(devnum, overflow_map); + } else { + port->dev_num = devnum; + base = devnum + base_dev; + set_bit(devnum, dev_map); } - port->dev_num = devnum; - base = devnum + base_dev; - set_bit(devnum, dev_map); spin_unlock(&port_lock); port->ib_dev = device; @@ -1042,7 +1072,10 @@ err_dev: err_cdev: cdev_del(&port->cdev); - clear_bit(devnum, dev_map); + if (port->dev_num < IB_UMAD_MAX_PORTS) + clear_bit(devnum, dev_map); + else + clear_bit(devnum, overflow_map); return -1; } @@ -1079,7 +1112,10 @@ static void ib_umad_kill_port(struct ib_umad_port *port) mutex_unlock(&port->file_mutex); - clear_bit(port->dev_num, dev_map); + if (port->dev_num < IB_UMAD_MAX_PORTS) + clear_bit(port->dev_num, dev_map); + else + clear_bit(port->dev_num - IB_UMAD_MAX_PORTS, overflow_map); } static void ib_umad_add_one(struct ib_device *device) @@ -1187,6 +1223,8 @@ static void __exit ib_umad_cleanup(void) ib_unregister_client(&umad_client); class_destroy(umad_class); unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); + if (overflow_maj) + unregister_chrdev_region(overflow_maj, IB_UMAD_MAX_PORTS * 2); } module_init(ib_umad_init); -- cgit v1.2.3-59-g8ed1b From d3f2c67f2d10675f45b0d9257269420e9f59aa1a Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:50 +0000 Subject: IB/umad: Clean whitespace Clean errors as shown when 'let c_space_errors=1' is set in vim. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/user_mad.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 57818aea9967..02d360cfc2f7 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -487,8 +487,8 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ah_attr.ah_flags = IB_AH_GRH; memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16); ah_attr.grh.sgid_index = packet->mad.hdr.gid_index; - ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label); - ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit; + ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label); + ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit; ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class; } @@ -519,9 +519,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err_ah; } - packet->msg->ah = ah; + packet->msg->ah = ah; packet->msg->timeout_ms = packet->mad.hdr.timeout_ms; - packet->msg->retries = packet->mad.hdr.retries; + packet->msg->retries = packet->mad.hdr.retries; packet->msg->context[0] = packet; /* Copy MAD header. Any RMPP header is already in place. */ @@ -856,16 +856,16 @@ static int ib_umad_close(struct inode *inode, struct file *filp) } static const struct file_operations umad_fops = { - .owner = THIS_MODULE, - .read = ib_umad_read, - .write = ib_umad_write, - .poll = ib_umad_poll, + .owner = THIS_MODULE, + .read = ib_umad_read, + .write = ib_umad_write, + .poll = ib_umad_poll, .unlocked_ioctl = ib_umad_ioctl, #ifdef CONFIG_COMPAT - .compat_ioctl = ib_umad_compat_ioctl, + .compat_ioctl = ib_umad_compat_ioctl, #endif - .open = ib_umad_open, - .release = ib_umad_close + .open = ib_umad_open, + .release = ib_umad_close }; static int ib_umad_sm_open(struct inode *inode, struct file *filp) @@ -930,8 +930,8 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp) } static const struct file_operations umad_sm_fops = { - .owner = THIS_MODULE, - .open = ib_umad_sm_open, + .owner = THIS_MODULE, + .open = ib_umad_sm_open, .release = ib_umad_sm_close }; -- cgit v1.2.3-59-g8ed1b From dd08f702dd773004b81aeddcd120b052a42710c3 Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:08:55 +0000 Subject: IB/ucm: Use stack variable 'devnum' in ib_ucm_add_one This change is not useful by itself, but sets us up for a future change that allows us to dynamically allocate device numbers in case we have more than IB_UCM_MAX_DEVICES in the system. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index f504c9b00c1b..7ff3300a86ca 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1239,6 +1239,7 @@ static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); static void ib_ucm_add_one(struct ib_device *device) { + int devnum; struct ib_ucm_device *ucm_dev; if (!device->alloc_ucontext || @@ -1251,16 +1252,17 @@ static void ib_ucm_add_one(struct ib_device *device) ucm_dev->ib_dev = device; - ucm_dev->devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); - if (ucm_dev->devnum >= IB_UCM_MAX_DEVICES) + devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); + if (devnum >= IB_UCM_MAX_DEVICES) goto err; - set_bit(ucm_dev->devnum, dev_map); + ucm_dev->devnum = devnum; + set_bit(devnum, dev_map); cdev_init(&ucm_dev->cdev, &ucm_fops); ucm_dev->cdev.owner = THIS_MODULE; kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum); - if (cdev_add(&ucm_dev->cdev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) + if (cdev_add(&ucm_dev->cdev, IB_UCM_BASE_DEV + devnum, 1)) goto err; ucm_dev->dev.class = &cm_class; @@ -1281,7 +1283,7 @@ err_dev: device_unregister(&ucm_dev->dev); err_cdev: cdev_del(&ucm_dev->cdev); - clear_bit(ucm_dev->devnum, dev_map); + clear_bit(devnum, dev_map); err: kfree(ucm_dev); return; -- cgit v1.2.3-59-g8ed1b From 31d14b6e10657113f72d496121d52ca779156b2e Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:09:00 +0000 Subject: IB/ucm: Use stack variable 'base' in ib_ucm_add_one This change is not useful by itself, but sets us up for a future change that allows us to support more than IB_UCM_MAX_DEVICES. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 7ff3300a86ca..06c50d80f0d8 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1240,6 +1240,7 @@ static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); static void ib_ucm_add_one(struct ib_device *device) { int devnum; + dev_t base; struct ib_ucm_device *ucm_dev; if (!device->alloc_ucontext || @@ -1257,12 +1258,13 @@ static void ib_ucm_add_one(struct ib_device *device) goto err; ucm_dev->devnum = devnum; + base = devnum + IB_UCM_BASE_DEV; set_bit(devnum, dev_map); cdev_init(&ucm_dev->cdev, &ucm_fops); ucm_dev->cdev.owner = THIS_MODULE; kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum); - if (cdev_add(&ucm_dev->cdev, IB_UCM_BASE_DEV + devnum, 1)) + if (cdev_add(&ucm_dev->cdev, base, 1)) goto err; ucm_dev->dev.class = &cm_class; -- cgit v1.2.3-59-g8ed1b From daa913580e1a927aaf54f02ecfdf59c7b6bc2f6e Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:09:06 +0000 Subject: IB/ucm: Increase maximum devices supported Some large systems may support more than IB_UCM_MAX_DEVICES (currently 32). This change allows us to support more devices in a backwards-compatible manner. the first IB_UCM_MAX_DEVICES keep the same major/minor device numbers they've always had. If there are more than IB_UCM_MAX_DEVICES, then we dynamically request a new major device number (new minors start at 0). Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucm.c | 53 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 8 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 06c50d80f0d8..2e0d53eeec09 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1215,7 +1215,10 @@ static void ib_ucm_release_dev(struct device *dev) ucm_dev = container_of(dev, struct ib_ucm_device, dev); cdev_del(&ucm_dev->cdev); - clear_bit(ucm_dev->devnum, dev_map); + if (ucm_dev->devnum < IB_UCM_MAX_DEVICES) + clear_bit(ucm_dev->devnum, dev_map); + else + clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, dev_map); kfree(ucm_dev); } @@ -1237,6 +1240,28 @@ static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); +static dev_t overflow_maj; +static DECLARE_BITMAP(overflow_map, IB_UCM_MAX_DEVICES); +static int find_overflow_devnum(void) +{ + int ret; + + if (!overflow_maj) { + ret = alloc_chrdev_region(&overflow_maj, 0, IB_UCM_MAX_DEVICES, + "infiniband_cm"); + if (ret) { + printk(KERN_ERR "ucm: couldn't register dynamic device number\n"); + return ret; + } + } + + ret = find_first_zero_bit(overflow_map, IB_UCM_MAX_DEVICES); + if (ret >= IB_UCM_MAX_DEVICES) + return -1; + + return ret; +} + static void ib_ucm_add_one(struct ib_device *device) { int devnum; @@ -1254,12 +1279,19 @@ static void ib_ucm_add_one(struct ib_device *device) ucm_dev->ib_dev = device; devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); - if (devnum >= IB_UCM_MAX_DEVICES) - goto err; - - ucm_dev->devnum = devnum; - base = devnum + IB_UCM_BASE_DEV; - set_bit(devnum, dev_map); + if (devnum >= IB_UCM_MAX_DEVICES) { + devnum = find_overflow_devnum(); + if (devnum < 0) + goto err; + + ucm_dev->devnum = devnum + IB_UCM_MAX_DEVICES; + base = devnum + overflow_maj; + set_bit(devnum, overflow_map); + } else { + ucm_dev->devnum = devnum; + base = devnum + IB_UCM_BASE_DEV; + set_bit(devnum, dev_map); + } cdev_init(&ucm_dev->cdev, &ucm_fops); ucm_dev->cdev.owner = THIS_MODULE; @@ -1285,7 +1317,10 @@ err_dev: device_unregister(&ucm_dev->dev); err_cdev: cdev_del(&ucm_dev->cdev); - clear_bit(devnum, dev_map); + if (ucm_dev->devnum < IB_UCM_MAX_DEVICES) + clear_bit(devnum, dev_map); + else + clear_bit(devnum, overflow_map); err: kfree(ucm_dev); return; @@ -1344,6 +1379,8 @@ static void __exit ib_ucm_cleanup(void) ib_unregister_client(&ucm_client); class_remove_file(&cm_class, &class_attr_abi_version); unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); + if (overflow_maj) + unregister_chrdev_region(overflow_maj, IB_UCM_MAX_DEVICES); idr_destroy(&ctx_id_table); } -- cgit v1.2.3-59-g8ed1b From cdb8e43889a5d21ce706f5a93d3e1c9940cde1dc Mon Sep 17 00:00:00 2001 From: Alexander Chiang Date: Tue, 2 Feb 2010 19:09:11 +0000 Subject: IB/ucm: Clean whitespace errors As shown when 'let c_space_errors=1' is set in vim. Signed-off-by: Alex Chiang Signed-off-by: Roland Dreier --- drivers/infiniband/core/ucm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 2e0d53eeec09..1b09b735c5a8 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1223,10 +1223,10 @@ static void ib_ucm_release_dev(struct device *dev) } static const struct file_operations ucm_fops = { - .owner = THIS_MODULE, - .open = ib_ucm_open, + .owner = THIS_MODULE, + .open = ib_ucm_open, .release = ib_ucm_close, - .write = ib_ucm_write, + .write = ib_ucm_write, .poll = ib_ucm_poll, }; -- cgit v1.2.3-59-g8ed1b From e998f245c4b2d36ae2c35446e54ccbf1fb29d9de Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 27 Jan 2010 17:03:34 +0000 Subject: RDMA/cxgb3: Doorbell overflow avoidance and recovery T3 hardware doorbell FIFO overflows can cause application stalls due to lost doorbell ring events. This has been seen when running large NP IMB alltoall MPI jobs. The T3 hardware supports an xon/xoff-type flow control mechanism to help avoid overflowing the HW doorbell FIFO. This patch uses these interrupts to disable RDMA QP doorbell rings when we near an overflow condition, and then turn them back on (and ring all the active QP doorbells) when when the doorbell FIFO empties out. In addition if an doorbell ring is dropped by the hardware, the code will now recover. Design: cxgb3: - enable these DB interrupts - in the interrupt handler, schedule work tasks to call the ULPs event handlers with the new events. - ring all the qset txqs when an overflow is detected. iw_cxgb3: - disable db ringing on all active qps when we get the DB_FULL event - enable db ringing on all active qps and ring all active dbs when we get the DB_EMPTY event - On DB_DROP event: - disable db rings in the event handler - delay-schedule a work task which rings and enables the dbs on all active qps. - in post_send and post_recv logic, don't ring the db if it's disabled. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_wr.h | 17 +++++++- drivers/infiniband/hw/cxgb3/iwch.c | 79 +++++++++++++++++++++++++++++++++-- drivers/infiniband/hw/cxgb3/iwch.h | 2 + drivers/infiniband/hw/cxgb3/iwch_qp.c | 9 ++-- drivers/net/cxgb3/adapter.h | 5 +++ drivers/net/cxgb3/cxgb3_main.c | 57 ++++++++++++++++++++++++- drivers/net/cxgb3/cxgb3_offload.h | 5 ++- drivers/net/cxgb3/regs.h | 16 +++++++ drivers/net/cxgb3/sge.c | 10 ++++- drivers/net/cxgb3/t3_hw.c | 5 ++- 10 files changed, 192 insertions(+), 13 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index a197a5b7ac7f..15073b2da1c5 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -730,7 +730,22 @@ struct t3_cq { static inline void cxio_set_wq_in_error(struct t3_wq *wq) { - wq->queue->wq_in_err.err = 1; + wq->queue->wq_in_err.err |= 1; +} + +static inline void cxio_disable_wq_db(struct t3_wq *wq) +{ + wq->queue->wq_in_err.err |= 2; +} + +static inline void cxio_enable_wq_db(struct t3_wq *wq) +{ + wq->queue->wq_in_err.err &= ~2; +} + +static inline int cxio_wq_db_enabled(struct t3_wq *wq) +{ + return !(wq->queue->wq_in_err.err & 2); } static inline struct t3_cqe *cxio_next_hw_cqe(struct t3_cq *cq) diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index b0ea0105ddf6..d992543890ee 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -65,6 +65,46 @@ struct cxgb3_client t3c_client = { static LIST_HEAD(dev_list); static DEFINE_MUTEX(dev_mutex); +static int disable_qp_db(int id, void *p, void *data) +{ + struct iwch_qp *qhp = p; + + cxio_disable_wq_db(&qhp->wq); + return 0; +} + +static int enable_qp_db(int id, void *p, void *data) +{ + struct iwch_qp *qhp = p; + + if (data) + ring_doorbell(qhp->rhp->rdev.ctrl_qp.doorbell, qhp->wq.qpid); + cxio_enable_wq_db(&qhp->wq); + return 0; +} + +static void disable_dbs(struct iwch_dev *rnicp) +{ + spin_lock_irq(&rnicp->lock); + idr_for_each(&rnicp->qpidr, disable_qp_db, NULL); + spin_unlock_irq(&rnicp->lock); +} + +static void enable_dbs(struct iwch_dev *rnicp, int ring_db) +{ + spin_lock_irq(&rnicp->lock); + idr_for_each(&rnicp->qpidr, enable_qp_db, + (void *)(unsigned long)ring_db); + spin_unlock_irq(&rnicp->lock); +} + +static void iwch_db_drop_task(struct work_struct *work) +{ + struct iwch_dev *rnicp = container_of(work, struct iwch_dev, + db_drop_task.work); + enable_dbs(rnicp, 1); +} + static void rnic_init(struct iwch_dev *rnicp) { PDBG("%s iwch_dev %p\n", __func__, rnicp); @@ -72,6 +112,7 @@ static void rnic_init(struct iwch_dev *rnicp) idr_init(&rnicp->qpidr); idr_init(&rnicp->mmidr); spin_lock_init(&rnicp->lock); + INIT_DELAYED_WORK(&rnicp->db_drop_task, iwch_db_drop_task); rnicp->attr.max_qps = T3_MAX_NUM_QP - 32; rnicp->attr.max_wrs = T3_MAX_QP_DEPTH; @@ -147,6 +188,7 @@ static void close_rnic_dev(struct t3cdev *tdev) mutex_lock(&dev_mutex); list_for_each_entry_safe(dev, tmp, &dev_list, entry) { if (dev->rdev.t3cdev_p == tdev) { + cancel_delayed_work_sync(&dev->db_drop_task); list_del(&dev->entry); iwch_unregister_device(dev); cxio_rdev_close(&dev->rdev); @@ -165,7 +207,8 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) struct cxio_rdev *rdev = tdev->ulp; struct iwch_dev *rnicp; struct ib_event event; - u32 portnum = port_id + 1; + u32 portnum = port_id + 1; + int dispatch = 0; if (!rdev) return; @@ -174,21 +217,49 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) case OFFLOAD_STATUS_DOWN: { rdev->flags = CXIO_ERROR_FATAL; event.event = IB_EVENT_DEVICE_FATAL; + dispatch = 1; break; } case OFFLOAD_PORT_DOWN: { event.event = IB_EVENT_PORT_ERR; + dispatch = 1; break; } case OFFLOAD_PORT_UP: { event.event = IB_EVENT_PORT_ACTIVE; + dispatch = 1; + break; + } + case OFFLOAD_DB_FULL: { + disable_dbs(rnicp); + break; + } + case OFFLOAD_DB_EMPTY: { + enable_dbs(rnicp, 1); + break; + } + case OFFLOAD_DB_DROP: { + unsigned long delay = 1000; + unsigned short r; + + disable_dbs(rnicp); + get_random_bytes(&r, 2); + delay += r & 1023; + + /* + * delay is between 1000-2023 usecs. + */ + schedule_delayed_work(&rnicp->db_drop_task, + usecs_to_jiffies(delay)); break; } } - event.device = &rnicp->ibdev; - event.element.port_num = portnum; - ib_dispatch_event(&event); + if (dispatch) { + event.device = &rnicp->ibdev; + event.element.port_num = portnum; + ib_dispatch_event(&event); + } return; } diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h index 84735506333f..a1c44578e039 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.h +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -110,6 +111,7 @@ struct iwch_dev { struct idr mmidr; spinlock_t lock; struct list_head entry; + struct delayed_work db_drop_task; }; static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev) diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 3eb8cecf81d7..b4d893de3650 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -452,7 +452,8 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, ++(qhp->wq.sq_wptr); } spin_unlock_irqrestore(&qhp->lock, flag); - ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); + if (cxio_wq_db_enabled(&qhp->wq)) + ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); out: if (err) @@ -514,7 +515,8 @@ int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, num_wrs--; } spin_unlock_irqrestore(&qhp->lock, flag); - ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); + if (cxio_wq_db_enabled(&qhp->wq)) + ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); out: if (err) @@ -597,7 +599,8 @@ int iwch_bind_mw(struct ib_qp *qp, ++(qhp->wq.sq_wptr); spin_unlock_irqrestore(&qhp->lock, flag); - ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); + if (cxio_wq_db_enabled(&qhp->wq)) + ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid); return err; } diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 3e8618b4efbc..4cd7f420766a 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -264,6 +264,10 @@ struct adapter { struct work_struct fatal_error_handler_task; struct work_struct link_fault_handler_task; + struct work_struct db_full_task; + struct work_struct db_empty_task; + struct work_struct db_drop_task; + struct dentry *debugfs_root; struct mutex mdio_lock; @@ -335,6 +339,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); +extern struct workqueue_struct *cxgb3_wq; int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 89bec9c3c141..37945fce7fa5 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "common.h" @@ -140,7 +141,7 @@ MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not"); * will block keventd as it needs the rtnl lock, and we'll deadlock waiting * for our work to complete. Get our own work queue to solve this. */ -static struct workqueue_struct *cxgb3_wq; +struct workqueue_struct *cxgb3_wq; /** * link_report - show link status and link speed/duplex @@ -590,6 +591,19 @@ static void setup_rss(struct adapter *adap) V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map); } +static void ring_dbs(struct adapter *adap) +{ + int i, j; + + for (i = 0; i < SGE_QSETS; i++) { + struct sge_qset *qs = &adap->sge.qs[i]; + + if (qs->adap) + for (j = 0; j < SGE_TXQ_PER_SET; j++) + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id)); + } +} + static void init_napi(struct adapter *adap) { int i; @@ -2754,6 +2768,42 @@ static void t3_adap_check_task(struct work_struct *work) spin_unlock_irq(&adapter->work_lock); } +static void db_full_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_full_task); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0); +} + +static void db_empty_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_empty_task); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0); +} + +static void db_drop_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_drop_task); + unsigned long delay = 1000; + unsigned short r; + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0); + + /* + * Sleep a while before ringing the driver qset dbs. + * The delay is between 1000-2023 usecs. + */ + get_random_bytes(&r, 2); + delay += r & 1023; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(delay)); + ring_dbs(adapter); +} + /* * Processes external (PHY) interrupts in process context. */ @@ -3222,6 +3272,11 @@ static int __devinit init_one(struct pci_dev *pdev, INIT_LIST_HEAD(&adapter->adapter_list); INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); + + INIT_WORK(&adapter->db_full_task, db_full_task); + INIT_WORK(&adapter->db_empty_task, db_empty_task); + INIT_WORK(&adapter->db_drop_task, db_drop_task); + INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); for (i = 0; i < ai->nports0 + ai->nports1; ++i) { diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h index 670aa62042da..929c298115ca 100644 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -73,7 +73,10 @@ enum { OFFLOAD_STATUS_UP, OFFLOAD_STATUS_DOWN, OFFLOAD_PORT_DOWN, - OFFLOAD_PORT_UP + OFFLOAD_PORT_UP, + OFFLOAD_DB_FULL, + OFFLOAD_DB_EMPTY, + OFFLOAD_DB_DROP }; struct cxgb3_client { diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 1b5327b5a965..cb42353c9fdd 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -254,6 +254,22 @@ #define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) #define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) +#define S_HIPRIORITYDBFULL 7 +#define V_HIPRIORITYDBFULL(x) ((x) << S_HIPRIORITYDBFULL) +#define F_HIPRIORITYDBFULL V_HIPRIORITYDBFULL(1U) + +#define S_HIPRIORITYDBEMPTY 6 +#define V_HIPRIORITYDBEMPTY(x) ((x) << S_HIPRIORITYDBEMPTY) +#define F_HIPRIORITYDBEMPTY V_HIPRIORITYDBEMPTY(1U) + +#define S_LOPRIORITYDBFULL 5 +#define V_LOPRIORITYDBFULL(x) ((x) << S_LOPRIORITYDBFULL) +#define F_LOPRIORITYDBFULL V_LOPRIORITYDBFULL(1U) + +#define S_LOPRIORITYDBEMPTY 4 +#define V_LOPRIORITYDBEMPTY(x) ((x) << S_LOPRIORITYDBEMPTY) +#define F_LOPRIORITYDBEMPTY V_LOPRIORITYDBEMPTY(1U) + #define S_RSPQDISABLED 3 #define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) #define F_RSPQDISABLED V_RSPQDISABLED(1U) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 318a018ca7c5..9b434461c4f1 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -42,6 +42,7 @@ #include "sge_defs.h" #include "t3_cpl.h" #include "firmware_exports.h" +#include "cxgb3_offload.h" #define USE_GTS 0 @@ -2833,8 +2834,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter) } if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) - CH_ALERT(adapter, "SGE dropped %s priority doorbell\n", - status & F_HIPIODRBDROPERR ? "high" : "lo"); + queue_work(cxgb3_wq, &adapter->db_drop_task); + + if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL)) + queue_work(cxgb3_wq, &adapter->db_full_task); + + if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY)) + queue_work(cxgb3_wq, &adapter->db_empty_task); t3_write_reg(adapter, A_SG_INT_CAUSE, status); if (status & SGE_FATALERR) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 032cfe065570..c38fc717a0d1 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1432,7 +1432,10 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ - F_HIRCQPARITYERROR) + F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \ + F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \ + F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \ + F_LOPIODRBDROPERR) #define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ F_NFASRCHFAIL) -- cgit v1.2.3-59-g8ed1b From 9918b28d2bf733816c5d1612fe17ca380b601b10 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 29 Jan 2010 00:55:49 +0000 Subject: RDMA/cxgb3: Increase the max CQ depth Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index f3d440cc68f2..fc59cfcc99c3 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -53,7 +53,7 @@ #define T3_MAX_PBL_SIZE 256 #define T3_MAX_RQ_SIZE 1024 #define T3_MAX_QP_DEPTH (T3_MAX_RQ_SIZE-1) -#define T3_MAX_CQ_DEPTH 8192 +#define T3_MAX_CQ_DEPTH 262144 #define T3_MAX_NUM_STAG (1<<15) #define T3_MAX_MR_SIZE 0x100000000ULL #define T3_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */ -- cgit v1.2.3-59-g8ed1b From 5279d3ac2d9ca578d04c6f0c760485b0621eb393 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 27 Jan 2010 20:22:34 +0000 Subject: RDMA/cxgb3: Don't allocate the SW queue for user mode CQs Only kernel mode CQs need the SW queue memory allocated. The SW queue for user mode CQs is allocated in userspace by libcxgb3. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.c | 14 +++++++------- drivers/infiniband/hw/cxgb3/cxio_hal.h | 2 +- drivers/infiniband/hw/cxgb3/iwch_provider.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 8837d56f9c92..a28e862f2d68 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -154,7 +154,7 @@ static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid) return iwch_cxgb3_ofld_send(rdev_p->t3cdev_p, skb); } -int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) +int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel) { struct rdma_cq_setup setup; int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe); @@ -162,12 +162,12 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) cq->cqid = cxio_hal_get_cqid(rdev_p->rscp); if (!cq->cqid) return -ENOMEM; - cq->sw_queue = kzalloc(size, GFP_KERNEL); - if (!cq->sw_queue) - return -ENOMEM; - cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), - (1UL << (cq->size_log2)) * - sizeof(struct t3_cqe), + if (kernel) { + cq->sw_queue = kzalloc(size, GFP_KERNEL); + if (!cq->sw_queue) + return -ENOMEM; + } + cq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), size, &(cq->dma_addr), GFP_KERNEL); if (!cq->queue) { kfree(cq->sw_queue); diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index fc59cfcc99c3..073373c2c560 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -157,7 +157,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev); void cxio_rdev_close(struct cxio_rdev *rdev); int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq, enum t3_cq_opcode op, u32 credit); -int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq); +int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq, int kernel); int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq); int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq); void cxio_release_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx); diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index ed7175549ebd..47b35c6608d2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -187,7 +187,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve entries = roundup_pow_of_two(entries); chp->cq.size_log2 = ilog2(entries); - if (cxio_create_cq(&rhp->rdev, &chp->cq)) { + if (cxio_create_cq(&rhp->rdev, &chp->cq, !ucontext)) { kfree(chp); return ERR_PTR(-ENOMEM); } -- cgit v1.2.3-59-g8ed1b From 68baf495d8e559a82787f595fecc30a43bb89bb7 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 22 Feb 2010 22:07:22 +0000 Subject: RDMA/cxgb3: Mark RDMA device with CXIO_ERROR_FATAL when removing If cxgb3 calls the iw_cxgb3 t3cclient remove function due to a device removal event, then the iwch device must be marked with CXIO_ERROR_FATAL since the device below us is going away. Otherwise, we can get stuck in a deadlock as RDMA ULPs try and deallocate objects (like MRs, QPs, etc). So always mark the device with CXIO_ERROR_FATAL when removing. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index d992543890ee..ee1d8b4d4541 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -188,6 +188,7 @@ static void close_rnic_dev(struct t3cdev *tdev) mutex_lock(&dev_mutex); list_for_each_entry_safe(dev, tmp, &dev_list, entry) { if (dev->rdev.t3cdev_p == tdev) { + dev->rdev.flags = CXIO_ERROR_FATAL; cancel_delayed_work_sync(&dev->db_drop_task); list_del(&dev->entry); iwch_unregister_device(dev); -- cgit v1.2.3-59-g8ed1b From 920d706c892e8f8cfff95f46aeb95fc6344f0bd5 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Mon, 8 Feb 2010 11:40:37 +0000 Subject: IB/core: Fix and clean up ib_ud_header_init() ib_ud_header_init() first clears header and then fills up the various fields. Later on, it tests header->immediate_present, which it has already cleared, so the condition is always false. Fix this by adding an immediate_present parameter and setting header->immediate_present as is done with grh_present. Also remove unused calculation of header_len. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/core/ud_header.c | 14 ++++---------- drivers/infiniband/hw/mlx4/qp.c | 2 +- drivers/infiniband/hw/mthca/mthca_qp.c | 2 +- include/rdma/ib_pack.h | 1 + 4 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c index 8ec7876bedcf..650b501eb142 100644 --- a/drivers/infiniband/core/ud_header.c +++ b/drivers/infiniband/core/ud_header.c @@ -181,6 +181,7 @@ static const struct ib_field deth_table[] = { * ib_ud_header_init - Initialize UD header structure * @payload_bytes:Length of packet payload * @grh_present:GRH flag (if non-zero, GRH will be included) + * @immediate_present: specify if immediate data should be used * @header:Structure to initialize * * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header, @@ -191,21 +192,13 @@ static const struct ib_field deth_table[] = { */ void ib_ud_header_init(int payload_bytes, int grh_present, + int immediate_present, struct ib_ud_header *header) { - int header_len; u16 packet_length; memset(header, 0, sizeof *header); - header_len = - IB_LRH_BYTES + - IB_BTH_BYTES + - IB_DETH_BYTES; - if (grh_present) { - header_len += IB_GRH_BYTES; - } - header->lrh.link_version = 0; header->lrh.link_next_header = grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; @@ -231,7 +224,8 @@ void ib_ud_header_init(int payload_bytes, header->lrh.packet_length = cpu_to_be16(packet_length); - if (header->immediate_present) + header->immediate_present = immediate_present; + if (immediate_present) header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; else header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 2a97c964b9ef..a1823523d7a2 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1228,7 +1228,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, for (i = 0; i < wr->num_sge; ++i) send_size += wr->sg_list[i].length; - ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), &sqp->ud_header); + ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), 0, &sqp->ud_header); sqp->ud_header.lrh.service_level = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index c10576fa60c1..d2d172e6289c 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1494,7 +1494,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp, u16 pkey; ib_ud_header_init(256, /* assume a MAD */ - mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), + mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), 0, &sqp->ud_header); err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header); diff --git a/include/rdma/ib_pack.h b/include/rdma/ib_pack.h index d7fc45c4eba9..cbb50f4da3dd 100644 --- a/include/rdma/ib_pack.h +++ b/include/rdma/ib_pack.h @@ -232,6 +232,7 @@ void ib_unpack(const struct ib_field *desc, void ib_ud_header_init(int payload_bytes, int grh_present, + int immediate_present, struct ib_ud_header *header); int ib_ud_header_pack(struct ib_ud_header *header, -- cgit v1.2.3-59-g8ed1b From a265e5587f078618c1f17c3a83da65046f18746f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 24 Feb 2010 16:51:20 -0800 Subject: IB/uverbs: Use anon_inodes instead of private infinibandeventfs The anon_inodes interface has been split to allow creating a bare (non-installed) file pointer and also extended to allow specifying O_RDONLY in the flags. This makes it a suitable replacement for the private "infinibandeventfs" pseudo-filesystem used by uverbs, and this replacement saves a small chunk of boilerplate code. Signed-off-by: Roland Dreier --- drivers/infiniband/Kconfig | 1 + drivers/infiniband/core/uverbs_main.c | 60 +++-------------------------------- 2 files changed, 5 insertions(+), 56 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index dd0db67bf8d7..975adce5f40c 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -20,6 +20,7 @@ config INFINIBAND_USER_MAD config INFINIBAND_USER_ACCESS tristate "InfiniBand userspace access (verbs and CM)" + select ANON_INODES ---help--- Userspace InfiniBand access support. This enables the kernel side of userspace verbs and the userspace diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 5f284ffd430e..82b60c65dd4d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -42,8 +42,8 @@ #include #include #include -#include #include +#include #include @@ -53,8 +53,6 @@ MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand userspace verbs access"); MODULE_LICENSE("Dual BSD/GPL"); -#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */ - enum { IB_UVERBS_MAJOR = 231, IB_UVERBS_BASE_MINOR = 192, @@ -111,8 +109,6 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, }; -static struct vfsmount *uverbs_event_mnt; - static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device); @@ -492,7 +488,6 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, int is_async, int *fd) { struct ib_uverbs_event_file *ev_file; - struct path path; struct file *filp; int ret; @@ -515,27 +510,16 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, goto err; } - /* - * fops_get() can't fail here, because we're coming from a - * system call on a uverbs file, which will already have a - * module reference. - */ - path.mnt = uverbs_event_mnt; - path.dentry = uverbs_event_mnt->mnt_root; - path_get(&path); - filp = alloc_file(&path, FMODE_READ, fops_get(&uverbs_event_fops)); + filp = anon_inode_getfile("[uverbs-event]", &uverbs_event_fops, + ev_file, O_RDONLY); if (!filp) { ret = -ENFILE; goto err_fd; } - filp->private_data = ev_file; - return filp; err_fd: - fops_put(&uverbs_event_fops); - path_put(&path); put_unused_fd(*fd); err: @@ -825,21 +809,6 @@ static void ib_uverbs_remove_one(struct ib_device *device) kfree(uverbs_dev); } -static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) -{ - return get_sb_pseudo(fs_type, "infinibandevent:", NULL, - INFINIBANDEVENTFS_MAGIC, mnt); -} - -static struct file_system_type uverbs_event_fs = { - /* No owner field so module can be unloaded */ - .name = "infinibandeventfs", - .get_sb = uverbs_event_get_sb, - .kill_sb = kill_litter_super -}; - static int __init ib_uverbs_init(void) { int ret; @@ -864,33 +833,14 @@ static int __init ib_uverbs_init(void) goto out_class; } - ret = register_filesystem(&uverbs_event_fs); - if (ret) { - printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n"); - goto out_class; - } - - uverbs_event_mnt = kern_mount(&uverbs_event_fs); - if (IS_ERR(uverbs_event_mnt)) { - ret = PTR_ERR(uverbs_event_mnt); - printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n"); - goto out_fs; - } - ret = ib_register_client(&uverbs_client); if (ret) { printk(KERN_ERR "user_verbs: couldn't register client\n"); - goto out_mnt; + goto out_class; } return 0; -out_mnt: - mntput(uverbs_event_mnt); - -out_fs: - unregister_filesystem(&uverbs_event_fs); - out_class: class_destroy(uverbs_class); @@ -904,8 +854,6 @@ out: static void __exit ib_uverbs_cleanup(void) { ib_unregister_client(&uverbs_client); - mntput(uverbs_event_mnt); - unregister_filesystem(&uverbs_event_fs); class_destroy(uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); idr_destroy(&ib_uverbs_pd_idr); -- cgit v1.2.3-59-g8ed1b From 09124e1913cf2140941f60ab4fdf8576e1e8fd8d Mon Sep 17 00:00:00 2001 From: Chien Tung Date: Tue, 23 Feb 2010 17:52:10 +0000 Subject: RDMA/nes: Add support for KR device id 0x0110 Add support for KR device id 0x0110. While at it, cleanup nes_init_phy() by splitting it into nes_init_1g_phy() and nes_init_2025_phy(). Remove support for NES_PHY_TYPE_IRIS, which was used on an XFP board that was only manufactured in small quantities and given out for evals in even smaller quantities. Signed-off-by: Chien Tung Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes.c | 1 + drivers/infiniband/hw/nes/nes.h | 5 +- drivers/infiniband/hw/nes/nes_hw.c | 396 +++++++++++++++++++++--------------- drivers/infiniband/hw/nes/nes_hw.h | 2 +- drivers/infiniband/hw/nes/nes_nic.c | 57 +----- 5 files changed, 243 insertions(+), 218 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index b9d09bafd6c1..4272c52e38a4 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -110,6 +110,7 @@ static unsigned int sysfs_idx_addr; static struct pci_device_id nes_pci_table[] = { {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID}, + {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020_KR, PCI_ANY_ID, PCI_ANY_ID}, {0} }; diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index cffdac4a899f..cc78fee1dd51 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -64,8 +64,9 @@ * NetEffect PCI vendor id and NE010 PCI device id. */ #ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */ -#define PCI_VENDOR_ID_NETEFFECT 0x1678 -#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100 +#define PCI_VENDOR_ID_NETEFFECT 0x1678 +#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100 +#define PCI_DEVICE_ID_NETEFFECT_NE020_KR 0x0110 #endif #define NE020_REV 4 diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 310cc7cab396..ce7f53833577 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -748,16 +748,28 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, if (hw_rev != NE020_REV) { /* init serdes 0 */ - if (wide_ppm_offset && (nesadapter->phy_type[0] == NES_PHY_TYPE_CX4)) - nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA); - else + switch (nesadapter->phy_type[0]) { + case NES_PHY_TYPE_CX4: + if (wide_ppm_offset) + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000FFFAA); + else + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF); + break; + case NES_PHY_TYPE_KR: + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF); + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x00000000); + break; + case NES_PHY_TYPE_PUMA_1G: nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF); - - if (nesadapter->phy_type[0] == NES_PHY_TYPE_PUMA_1G) { sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0); sds |= 0x00000100; nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds); + break; + default: + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF); + break; } + if (!OneG_Mode) nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000); @@ -778,6 +790,9 @@ static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, if (wide_ppm_offset) nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000FFFAA); break; + case NES_PHY_TYPE_KR: + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x00000000); + break; case NES_PHY_TYPE_PUMA_1G: sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1); sds |= 0x000000100; @@ -1279,115 +1294,115 @@ int nes_destroy_cqp(struct nes_device *nesdev) /** - * nes_init_phy + * nes_init_1g_phy */ -int nes_init_phy(struct nes_device *nesdev) +int nes_init_1g_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index) { - struct nes_adapter *nesadapter = nesdev->nesadapter; u32 counter = 0; - u32 sds; - u32 mac_index = nesdev->mac_index; - u32 tx_config = 0; u16 phy_data; - u32 temp_phy_data = 0; - u32 temp_phy_data2 = 0; - u8 phy_type = nesadapter->phy_type[mac_index]; - u8 phy_index = nesadapter->phy_index[mac_index]; - - if ((nesadapter->OneG_Mode) && - (phy_type != NES_PHY_TYPE_PUMA_1G)) { - nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index); - if (phy_type == NES_PHY_TYPE_1G) { - tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); - tx_config &= 0xFFFFFFE3; - tx_config |= 0x04; - nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); - } - - nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data); - nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000); + int ret = 0; - /* Reset the PHY */ - nes_write_1G_phy_reg(nesdev, 0, phy_index, 0x8000); - udelay(100); - counter = 0; - do { - nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); - if (counter++ > 100) - break; - } while (phy_data & 0x8000); + nes_read_1G_phy_reg(nesdev, 1, phy_index, &phy_data); + nes_write_1G_phy_reg(nesdev, 23, phy_index, 0xb000); - /* Setting no phy loopback */ - phy_data &= 0xbfff; - phy_data |= 0x1140; - nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data); + /* Reset the PHY */ + nes_write_1G_phy_reg(nesdev, 0, phy_index, 0x8000); + udelay(100); + counter = 0; + do { nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); - nes_read_1G_phy_reg(nesdev, 0x17, phy_index, &phy_data); - nes_read_1G_phy_reg(nesdev, 0x1e, phy_index, &phy_data); - - /* Setting the interrupt mask */ - nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data); - nes_write_1G_phy_reg(nesdev, 0x19, phy_index, 0xffee); - nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data); + if (counter++ > 100) { + ret = -1; + break; + } + } while (phy_data & 0x8000); + + /* Setting no phy loopback */ + phy_data &= 0xbfff; + phy_data |= 0x1140; + nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data); + nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); + nes_read_1G_phy_reg(nesdev, 0x17, phy_index, &phy_data); + nes_read_1G_phy_reg(nesdev, 0x1e, phy_index, &phy_data); + + /* Setting the interrupt mask */ + nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data); + nes_write_1G_phy_reg(nesdev, 0x19, phy_index, 0xffee); + nes_read_1G_phy_reg(nesdev, 0x19, phy_index, &phy_data); + + /* turning on flow control */ + nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data); + nes_write_1G_phy_reg(nesdev, 4, phy_index, (phy_data & ~(0x03E0)) | 0xc00); + nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data); + + /* Clear Half duplex */ + nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data); + nes_write_1G_phy_reg(nesdev, 9, phy_index, phy_data & ~(0x0100)); + nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data); + + nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); + nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300); + + return ret; +} - /* turning on flow control */ - nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data); - nes_write_1G_phy_reg(nesdev, 4, phy_index, (phy_data & ~(0x03E0)) | 0xc00); - nes_read_1G_phy_reg(nesdev, 4, phy_index, &phy_data); - /* Clear Half duplex */ - nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data); - nes_write_1G_phy_reg(nesdev, 9, phy_index, phy_data & ~(0x0100)); - nes_read_1G_phy_reg(nesdev, 9, phy_index, &phy_data); +/** + * nes_init_2025_phy + */ +int nes_init_2025_phy(struct nes_device *nesdev, u8 phy_type, u8 phy_index) +{ + u32 temp_phy_data = 0; + u32 temp_phy_data2 = 0; + u32 counter = 0; + u32 sds; + u32 mac_index = nesdev->mac_index; + int ret = 0; + unsigned int first_attempt = 1; - nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); - nes_write_1G_phy_reg(nesdev, 0, phy_index, phy_data | 0x0300); + /* Check firmware heartbeat */ + nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + udelay(1500); + nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - return 0; + if (temp_phy_data != temp_phy_data2) { + nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((temp_phy_data & 0xff) > 0x20) + return 0; + printk(PFX "Reinitialize external PHY\n"); } - if ((phy_type == NES_PHY_TYPE_IRIS) || - (phy_type == NES_PHY_TYPE_ARGUS) || - (phy_type == NES_PHY_TYPE_SFP_D)) { - /* setup 10G MDIO operation */ - tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); - tx_config &= 0xFFFFFFE3; - tx_config |= 0x15; - nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); - } - if ((phy_type == NES_PHY_TYPE_ARGUS) || - (phy_type == NES_PHY_TYPE_SFP_D)) { - u32 first_time = 1; + /* no heartbeat, configure the PHY */ + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0x0000, 0x8000); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052); - /* Check firmware heartbeat */ - nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); - temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - udelay(1500); - nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); - temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + switch (phy_type) { + case NES_PHY_TYPE_ARGUS: + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00); - if (temp_phy_data != temp_phy_data2) { - nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd); - temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - if ((temp_phy_data & 0xff) > 0x20) - return 0; - printk(PFX "Reinitializing PHY\n"); - } + /* setup LEDs */ + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009); + break; - /* no heartbeat, configure the PHY */ - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0x0000, 0x8000); - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0000); + case NES_PHY_TYPE_SFP_D: nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052); - if (phy_type == NES_PHY_TYPE_ARGUS) { - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C); - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0008); - nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0001); - } else { - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004); - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038); - nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013); - } + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x0004); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0038); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0098); nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00); @@ -1395,71 +1410,136 @@ int nes_init_phy(struct nes_device *nesdev) nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x0007); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x000A); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0009); + break; - nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528); + case NES_PHY_TYPE_KR: + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc316, 0x000A); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc318, 0x0052); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc302, 0x000C); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc319, 0x0010); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0027, 0x0013); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc31a, 0x0080); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0026, 0x0E00); - /* Bring PHY out of reset */ - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0002); + /* setup LEDs */ + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd006, 0x000B); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd007, 0x0003); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd008, 0x0004); - /* Check for heartbeat */ - counter = 0; - mdelay(690); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0022, 0x406D); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0023, 0x0020); + break; + } + + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0x0028, 0xA528); + + /* Bring PHY out of reset */ + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc300, 0x0002); + + /* Check for heartbeat */ + counter = 0; + mdelay(690); + nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + do { + if (counter++ > 150) { + printk(PFX "No PHY heartbeat\n"); + break; + } + mdelay(1); nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + } while ((temp_phy_data2 == temp_phy_data)); + + /* wait for tracking */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - do { - if (counter++ > 150) { - printk(PFX "No PHY heartbeat\n"); + if (counter++ > 300) { + if (((temp_phy_data & 0xff) == 0x0) && first_attempt) { + first_attempt = 0; + counter = 0; + /* reset AMCC PHY and try again */ + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0); + nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040); + continue; + } else { + ret = 1; break; } - mdelay(1); - nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7ee); - temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - } while ((temp_phy_data2 == temp_phy_data)); - - /* wait for tracking */ - counter = 0; - do { - nes_read_10G_phy_reg(nesdev, phy_index, 0x3, 0xd7fd); - temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - if (counter++ > 300) { - if (((temp_phy_data & 0xff) == 0x0) && first_time) { - first_time = 0; - counter = 0; - /* reset AMCC PHY and try again */ - nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x00c0); - nes_write_10G_phy_reg(nesdev, phy_index, 0x3, 0xe854, 0x0040); - continue; - } else { - printk(PFX "PHY did not track\n"); - break; - } - } - mdelay(10); - } while ((temp_phy_data & 0xff) < 0x30); - - /* setup signal integrity */ - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000); - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE); - nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032); + } + mdelay(10); + } while ((temp_phy_data & 0xff) < 0x30); + + /* setup signal integrity */ + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xd003, 0x0000); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00D, 0x00FE); + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00E, 0x0032); + if (phy_type == NES_PHY_TYPE_KR) { + nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x000C); + } else { nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xF00F, 0x0002); nes_write_10G_phy_reg(nesdev, phy_index, 0x1, 0xc314, 0x0063); + } + + /* reset serdes */ + sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200); + sds |= 0x1; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds); + sds &= 0xfffffffe; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + mac_index * 0x200, sds); + + counter = 0; + while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) + && (counter++ < 5000)) + ; + + return ret; +} + + +/** + * nes_init_phy + */ +int nes_init_phy(struct nes_device *nesdev) +{ + struct nes_adapter *nesadapter = nesdev->nesadapter; + u32 mac_index = nesdev->mac_index; + u32 tx_config = 0; + unsigned long flags; + u8 phy_type = nesadapter->phy_type[mac_index]; + u8 phy_index = nesadapter->phy_index[mac_index]; + int ret = 0; + + tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); + if (phy_type == NES_PHY_TYPE_1G) { + /* setup 1G MDIO operation */ + tx_config &= 0xFFFFFFE3; + tx_config |= 0x04; + } else { + /* setup 10G MDIO operation */ + tx_config &= 0xFFFFFFE3; + tx_config |= 0x15; + } + nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); - /* reset serdes */ - sds = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + - mac_index * 0x200); - sds |= 0x1; - nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + - mac_index * 0x200, sds); - sds &= 0xfffffffe; - nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0 + - mac_index * 0x200, sds); - - counter = 0; - while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) - && (counter++ < 5000)) - ; + spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); + + switch (phy_type) { + case NES_PHY_TYPE_1G: + ret = nes_init_1g_phy(nesdev, phy_type, phy_index); + break; + case NES_PHY_TYPE_ARGUS: + case NES_PHY_TYPE_SFP_D: + case NES_PHY_TYPE_KR: + ret = nes_init_2025_phy(nesdev, phy_type, phy_index); + break; } - return 0; + + spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); + + return ret; } @@ -2460,23 +2540,9 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) } } else { switch (nesadapter->phy_type[mac_index]) { - case NES_PHY_TYPE_IRIS: - nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); - temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - u32temp = 20; - do { - nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); - phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - if ((phy_data == temp_phy_data) || (!(--u32temp))) - break; - temp_phy_data = phy_data; - } while (1); - nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", - __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); - break; - case NES_PHY_TYPE_ARGUS: case NES_PHY_TYPE_SFP_D: + case NES_PHY_TYPE_KR: /* clear the alarms */ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008); nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001); diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 084be0ee689b..9b1e7f869d83 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -37,12 +37,12 @@ #define NES_PHY_TYPE_CX4 1 #define NES_PHY_TYPE_1G 2 -#define NES_PHY_TYPE_IRIS 3 #define NES_PHY_TYPE_ARGUS 4 #define NES_PHY_TYPE_PUMA_1G 5 #define NES_PHY_TYPE_PUMA_10G 6 #define NES_PHY_TYPE_GLADIUS 7 #define NES_PHY_TYPE_SFP_D 8 +#define NES_PHY_TYPE_KR 9 #define NES_MULTICAST_PF_MAX 8 diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 3d550dc77d0d..7dd6ce6e7b99 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1461,9 +1461,9 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd } return 0; } - if ((phy_type == NES_PHY_TYPE_IRIS) || - (phy_type == NES_PHY_TYPE_ARGUS) || - (phy_type == NES_PHY_TYPE_SFP_D)) { + if ((phy_type == NES_PHY_TYPE_ARGUS) || + (phy_type == NES_PHY_TYPE_SFP_D) || + (phy_type == NES_PHY_TYPE_KR)) { et_cmd->transceiver = XCVR_EXTERNAL; et_cmd->port = PORT_FIBRE; et_cmd->supported = SUPPORTED_FIBRE; @@ -1583,8 +1583,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, struct net_device *netdev; struct nic_qp_map *curr_qp_map; u32 u32temp; - u16 phy_data; - u16 temp_phy_data; + u8 phy_type = nesdev->nesadapter->phy_type[nesdev->mac_index]; netdev = alloc_etherdev(sizeof(struct nes_vnic)); if (!netdev) { @@ -1692,65 +1691,23 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, if ((nesdev->netdev_count == 0) && ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) || - ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) && + ((phy_type == NES_PHY_TYPE_PUMA_1G) && (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { - /* - * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", - * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1))); - */ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1))); - if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) { + if (phy_type != NES_PHY_TYPE_PUMA_1G) { u32temp |= 0x00200000; nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1)), u32temp); } - u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200 * (nesdev->mac_index & 1))); - - if ((u32temp&0x0f1f0000) == 0x0f0f0000) { - if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) { - nes_init_phy(nesdev); - nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); - temp_phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - u32temp = 20; - do { - nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); - phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - if ((phy_data == temp_phy_data) || (!(--u32temp))) - break; - temp_phy_data = phy_data; - } while (1); - if (phy_data & 4) { - nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); - nesvnic->linkup = 1; - } else { - nes_debug(NES_DBG_INIT, "The Link is DOWN!!.\n"); - } - } else { - nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); - nesvnic->linkup = 1; - } - } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { - nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n", - nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn)); - if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) || - ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) { - nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); - nesvnic->linkup = 1; - } - } /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp); nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp); - if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_IRIS) - nes_init_phy(nesdev); + nes_init_phy(nesdev); } -- cgit v1.2.3-59-g8ed1b From 9c03dc9f19351edf25c1107e3cfd3cc538c7ab9e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 2 Feb 2010 19:23:54 +0000 Subject: IB/srp: Split send and recieve CQs to reduce number of interrupts We can reduce the number of IB interrupts from two interrupts per srp_queuecommand() call to one by using separate CQs for send and receive completions and processing send completions by polling every time a TX IU is allocated. Receive completion events still trigger an interrupt. Signed-off-by: Bart Van Assche Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 72 ++++++++++++++++++++++++++----------- drivers/infiniband/ulp/srp/ib_srp.h | 6 ++-- 2 files changed, 53 insertions(+), 25 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 54c8fe25c423..441ea7c2e7c4 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -80,7 +80,8 @@ MODULE_PARM_DESC(mellanox_workarounds, static void srp_add_one(struct ib_device *device); static void srp_remove_one(struct ib_device *device); -static void srp_completion(struct ib_cq *cq, void *target_ptr); +static void srp_recv_completion(struct ib_cq *cq, void *target_ptr); +static void srp_send_completion(struct ib_cq *cq, void *target_ptr); static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); static struct scsi_transport_template *ib_srp_transport_template; @@ -227,14 +228,22 @@ static int srp_create_target_ib(struct srp_target_port *target) if (!init_attr) return -ENOMEM; - target->cq = ib_create_cq(target->srp_host->srp_dev->dev, - srp_completion, NULL, target, SRP_CQ_SIZE, 0); - if (IS_ERR(target->cq)) { - ret = PTR_ERR(target->cq); + target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, + srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); + if (IS_ERR(target->recv_cq)) { + ret = PTR_ERR(target->recv_cq); goto out; } - ib_req_notify_cq(target->cq, IB_CQ_NEXT_COMP); + target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev, + srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); + if (IS_ERR(target->send_cq)) { + ret = PTR_ERR(target->send_cq); + ib_destroy_cq(target->recv_cq); + goto out; + } + + ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP); init_attr->event_handler = srp_qp_event; init_attr->cap.max_send_wr = SRP_SQ_SIZE; @@ -243,20 +252,22 @@ static int srp_create_target_ib(struct srp_target_port *target) init_attr->cap.max_send_sge = 1; init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; init_attr->qp_type = IB_QPT_RC; - init_attr->send_cq = target->cq; - init_attr->recv_cq = target->cq; + init_attr->send_cq = target->send_cq; + init_attr->recv_cq = target->recv_cq; target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); if (IS_ERR(target->qp)) { ret = PTR_ERR(target->qp); - ib_destroy_cq(target->cq); + ib_destroy_cq(target->send_cq); + ib_destroy_cq(target->recv_cq); goto out; } ret = srp_init_qp(target, target->qp); if (ret) { ib_destroy_qp(target->qp); - ib_destroy_cq(target->cq); + ib_destroy_cq(target->send_cq); + ib_destroy_cq(target->recv_cq); goto out; } @@ -270,7 +281,8 @@ static void srp_free_target_ib(struct srp_target_port *target) int i; ib_destroy_qp(target->qp); - ib_destroy_cq(target->cq); + ib_destroy_cq(target->send_cq); + ib_destroy_cq(target->recv_cq); for (i = 0; i < SRP_RQ_SIZE; ++i) srp_free_iu(target->srp_host, target->rx_ring[i]); @@ -568,7 +580,9 @@ static int srp_reconnect_target(struct srp_target_port *target) if (ret) goto err; - while (ib_poll_cq(target->cq, 1, &wc) > 0) + while (ib_poll_cq(target->recv_cq, 1, &wc) > 0) + ; /* nothing */ + while (ib_poll_cq(target->send_cq, 1, &wc) > 0) ; /* nothing */ spin_lock_irq(target->scsi_host->host_lock); @@ -851,7 +865,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) struct srp_iu *iu; u8 opcode; - iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV]; + iu = target->rx_ring[wc->wr_id]; dev = target->srp_host->srp_dev->dev; ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, @@ -898,7 +912,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) DMA_FROM_DEVICE); } -static void srp_completion(struct ib_cq *cq, void *target_ptr) +static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) { struct srp_target_port *target = target_ptr; struct ib_wc wc; @@ -907,17 +921,31 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr) while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { shost_printk(KERN_ERR, target->scsi_host, - PFX "failed %s status %d\n", - wc.wr_id & SRP_OP_RECV ? "receive" : "send", + PFX "failed receive status %d\n", wc.status); target->qp_in_error = 1; break; } - if (wc.wr_id & SRP_OP_RECV) - srp_handle_recv(target, &wc); - else - ++target->tx_tail; + srp_handle_recv(target, &wc); + } +} + +static void srp_send_completion(struct ib_cq *cq, void *target_ptr) +{ + struct srp_target_port *target = target_ptr; + struct ib_wc wc; + + while (ib_poll_cq(cq, 1, &wc) > 0) { + if (wc.status) { + shost_printk(KERN_ERR, target->scsi_host, + PFX "failed send status %d\n", + wc.status); + target->qp_in_error = 1; + break; + } + + ++target->tx_tail; } } @@ -930,7 +958,7 @@ static int __srp_post_recv(struct srp_target_port *target) int ret; next = target->rx_head & (SRP_RQ_SIZE - 1); - wr.wr_id = next | SRP_OP_RECV; + wr.wr_id = next; iu = target->rx_ring[next]; list.addr = iu->dma; @@ -970,6 +998,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, { s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2; + srp_send_completion(target->send_cq, target); + if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) return NULL; diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index e185b907fc12..5a80eac6fdaa 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -60,7 +60,6 @@ enum { SRP_RQ_SHIFT = 6, SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, SRP_SQ_SIZE = SRP_RQ_SIZE - 1, - SRP_CQ_SIZE = SRP_SQ_SIZE + SRP_RQ_SIZE, SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1), @@ -69,8 +68,6 @@ enum { SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4 }; -#define SRP_OP_RECV (1 << 31) - enum srp_target_state { SRP_TARGET_LIVE, SRP_TARGET_CONNECTING, @@ -133,7 +130,8 @@ struct srp_target_port { int path_query_id; struct ib_cm_id *cm_id; - struct ib_cq *cq; + struct ib_cq *recv_cq; + struct ib_cq *send_cq; struct ib_qp *qp; int max_ti_iu_len; -- cgit v1.2.3-59-g8ed1b From da9d2f07306fc29a2f10885c2b0a463f3863c365 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 24 Feb 2010 15:07:59 -0800 Subject: IB/srp: Clean up error path in srp_create_target_ib() Instead of repeating the error unwinding steps in each place an error can be detected, use the common idiom of gotos into an error flow. Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/srp/ib_srp.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 441ea7c2e7c4..ed3f9ebae882 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -232,15 +232,14 @@ static int srp_create_target_ib(struct srp_target_port *target) srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); if (IS_ERR(target->recv_cq)) { ret = PTR_ERR(target->recv_cq); - goto out; + goto err; } target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev, srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); if (IS_ERR(target->send_cq)) { ret = PTR_ERR(target->send_cq); - ib_destroy_cq(target->recv_cq); - goto out; + goto err_recv_cq; } ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP); @@ -258,20 +257,26 @@ static int srp_create_target_ib(struct srp_target_port *target) target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); if (IS_ERR(target->qp)) { ret = PTR_ERR(target->qp); - ib_destroy_cq(target->send_cq); - ib_destroy_cq(target->recv_cq); - goto out; + goto err_send_cq; } ret = srp_init_qp(target, target->qp); - if (ret) { - ib_destroy_qp(target->qp); - ib_destroy_cq(target->send_cq); - ib_destroy_cq(target->recv_cq); - goto out; - } + if (ret) + goto err_qp; -out: + kfree(init_attr); + return 0; + +err_qp: + ib_destroy_qp(target->qp); + +err_send_cq: + ib_destroy_cq(target->send_cq); + +err_recv_cq: + ib_destroy_cq(target->recv_cq); + +err: kfree(init_attr); return ret; } -- cgit v1.2.3-59-g8ed1b From 309ce156aa27f29338438011d292a8d6496623d3 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Sat, 20 Feb 2010 08:02:10 +0530 Subject: [SCSI] libiscsi: Make iscsi_eh_target_reset start with session reset The iscsi_eh_target_reset has been modified to attempt target reset only. If it fails, then iscsi_eh_session_reset will be called. Signed-off-by: Mike Christie Signed-off-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/scsi/be2iscsi/be_main.c | 2 +- drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- drivers/scsi/cxgb3i/cxgb3i_iscsi.c | 2 +- drivers/scsi/iscsi_tcp.c | 2 +- drivers/scsi/libiscsi.c | 23 +++++++++++++++++++---- include/scsi/libiscsi.h | 3 ++- 7 files changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 5f7a6fca0a4d..5472b7e9abdc 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -596,7 +596,7 @@ static struct scsi_host_template iscsi_iser_sht = { .cmd_per_lun = ISER_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, - .eh_target_reset_handler= iscsi_eh_target_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, .target_alloc = iscsi_target_alloc, .use_clustering = DISABLE_CLUSTERING, .proc_name = "iscsi_iser", diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7c22616ab141..4d269b434a78 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -79,7 +79,7 @@ static struct scsi_host_template beiscsi_sht = { .slave_configure = beiscsi_slave_configure, .target_alloc = iscsi_target_alloc, .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_target_reset, + .eh_target_reset_handler = iscsi_eh_session_reset, .sg_tablesize = BEISCSI_SGLIST_ELEMENTS, .can_queue = BE2_IO_DEPTH, .this_id = -1, diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 1c4d1215769d..cb71dc984797 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1989,7 +1989,7 @@ static struct scsi_host_template bnx2i_host_template = { .queuecommand = iscsi_queuecommand, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_target_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, .change_queue_depth = iscsi_change_queue_depth, .can_queue = 1024, .max_sectors = 127, diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index 412853c65372..b7c30585dadd 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c @@ -915,7 +915,7 @@ static struct scsi_host_template cxgb3i_host_template = { .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_target_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, .target_alloc = iscsi_target_alloc, .use_clustering = DISABLE_CLUSTERING, .this_id = -1, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8a89ba900588..249053a9d4fa 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -874,7 +874,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = { .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, - .eh_target_reset_handler= iscsi_eh_target_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, .use_clustering = DISABLE_CLUSTERING, .slave_alloc = iscsi_sw_tcp_slave_alloc, .slave_configure = iscsi_sw_tcp_slave_configure, diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 703eb6a88790..685eaec53218 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2338,7 +2338,7 @@ EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); * This function will wait for a relogin, session termination from * userspace, or a recovery/replacement timeout. */ -static int iscsi_eh_session_reset(struct scsi_cmnd *sc) +int iscsi_eh_session_reset(struct scsi_cmnd *sc) { struct iscsi_cls_session *cls_session; struct iscsi_session *session; @@ -2389,6 +2389,7 @@ failed: mutex_unlock(&session->eh_mutex); return SUCCESS; } +EXPORT_SYMBOL_GPL(iscsi_eh_session_reset); static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) { @@ -2403,8 +2404,7 @@ static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) * iscsi_eh_target_reset - reset target * @sc: scsi command * - * This will attempt to send a warm target reset. If that fails - * then we will drop the session and attempt ERL0 recovery. + * This will attempt to send a warm target reset. */ int iscsi_eh_target_reset(struct scsi_cmnd *sc) { @@ -2476,12 +2476,27 @@ done: ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname, rc == SUCCESS ? "SUCCESS" : "FAILED"); mutex_unlock(&session->eh_mutex); + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); +/** + * iscsi_eh_recover_target - reset target and possibly the session + * @sc: scsi command + * + * This will attempt to send a warm target reset. If that fails, + * we will escalate to ERL0 session recovery. + */ +int iscsi_eh_recover_target(struct scsi_cmnd *sc) +{ + int rc; + + rc = iscsi_eh_target_reset(sc); if (rc == FAILED) rc = iscsi_eh_session_reset(sc); return rc; } -EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); +EXPORT_SYMBOL_GPL(iscsi_eh_recover_target); /* * Pre-allocate a pool of @max items of @item_size. By default, the pool diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index ff92b46f5153..ae5196aae1a5 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -338,7 +338,8 @@ struct iscsi_host { extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason); extern int iscsi_eh_abort(struct scsi_cmnd *sc); -extern int iscsi_eh_target_reset(struct scsi_cmnd *sc); +extern int iscsi_eh_recover_target(struct scsi_cmnd *sc); +extern int iscsi_eh_session_reset(struct scsi_cmnd *sc); extern int iscsi_eh_device_reset(struct scsi_cmnd *sc); extern int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)); -- cgit v1.2.3-59-g8ed1b From b1e4594ba097634e9436cc4c6ba95f70a2d627ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 18 Jan 2010 01:38:00 -0500 Subject: switch infiniband uverbs to anon_inodes Signed-off-by: Al Viro --- drivers/infiniband/Kconfig | 1 + drivers/infiniband/core/uverbs.h | 2 +- drivers/infiniband/core/uverbs_cmd.c | 25 ++++++++--- drivers/infiniband/core/uverbs_main.c | 82 +++-------------------------------- 4 files changed, 29 insertions(+), 81 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index dd0db67bf8d7..975adce5f40c 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -20,6 +20,7 @@ config INFINIBAND_USER_MAD config INFINIBAND_USER_ACCESS tristate "InfiniBand userspace access (verbs and CM)" + select ANON_INODES ---help--- Userspace InfiniBand access support. This enables the kernel side of userspace verbs and the userspace diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index b3ea9587dc80..0b3862080c0f 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -145,7 +145,7 @@ extern struct idr ib_uverbs_srq_idr; void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, - int is_async, int *fd); + int is_async); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); void ib_uverbs_release_ucq(struct ib_uverbs_file *file, diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 112d3970222a..f71cf138d674 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -301,10 +301,15 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, resp.num_comp_vectors = file->device->num_comp_vectors; - filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); + ret = get_unused_fd(); + if (ret < 0) + goto err_free; + resp.async_fd = ret; + + filp = ib_uverbs_alloc_event_file(file, 1); if (IS_ERR(filp)) { ret = PTR_ERR(filp); - goto err_free; + goto err_fd; } if (copy_to_user((void __user *) (unsigned long) cmd.response, @@ -332,9 +337,11 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, return in_len; err_file: - put_unused_fd(resp.async_fd); fput(filp); +err_fd: + put_unused_fd(resp.async_fd); + err_free: ibdev->dealloc_ucontext(ucontext); @@ -715,6 +722,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, struct ib_uverbs_create_comp_channel cmd; struct ib_uverbs_create_comp_channel_resp resp; struct file *filp; + int ret; if (out_len < sizeof resp) return -ENOSPC; @@ -722,9 +730,16 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); - if (IS_ERR(filp)) + ret = get_unused_fd(); + if (ret < 0) + return ret; + resp.fd = ret; + + filp = ib_uverbs_alloc_event_file(file, 0); + if (IS_ERR(filp)) { + put_unused_fd(resp.fd); return PTR_ERR(filp); + } if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) { diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 5f284ffd430e..810f277739e2 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -41,8 +41,8 @@ #include #include #include +#include #include -#include #include #include @@ -53,8 +53,6 @@ MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand userspace verbs access"); MODULE_LICENSE("Dual BSD/GPL"); -#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */ - enum { IB_UVERBS_MAJOR = 231, IB_UVERBS_BASE_MINOR = 192, @@ -111,8 +109,6 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, }; -static struct vfsmount *uverbs_event_mnt; - static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device); @@ -489,12 +485,10 @@ void ib_uverbs_event_handler(struct ib_event_handler *handler, } struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, - int is_async, int *fd) + int is_async) { struct ib_uverbs_event_file *ev_file; - struct path path; struct file *filp; - int ret; ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL); if (!ev_file) @@ -509,38 +503,12 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, ev_file->is_async = is_async; ev_file->is_closed = 0; - *fd = get_unused_fd(); - if (*fd < 0) { - ret = *fd; - goto err; - } - - /* - * fops_get() can't fail here, because we're coming from a - * system call on a uverbs file, which will already have a - * module reference. - */ - path.mnt = uverbs_event_mnt; - path.dentry = uverbs_event_mnt->mnt_root; - path_get(&path); - filp = alloc_file(&path, FMODE_READ, fops_get(&uverbs_event_fops)); - if (!filp) { - ret = -ENFILE; - goto err_fd; - } - - filp->private_data = ev_file; + filp = anon_inode_getfile("[infinibandevent]", &uverbs_event_fops, + ev_file, O_RDONLY); + if (IS_ERR(filp)) + kfree(ev_file); return filp; - -err_fd: - fops_put(&uverbs_event_fops); - path_put(&path); - put_unused_fd(*fd); - -err: - kfree(ev_file); - return ERR_PTR(ret); } /* @@ -825,21 +793,6 @@ static void ib_uverbs_remove_one(struct ib_device *device) kfree(uverbs_dev); } -static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) -{ - return get_sb_pseudo(fs_type, "infinibandevent:", NULL, - INFINIBANDEVENTFS_MAGIC, mnt); -} - -static struct file_system_type uverbs_event_fs = { - /* No owner field so module can be unloaded */ - .name = "infinibandeventfs", - .get_sb = uverbs_event_get_sb, - .kill_sb = kill_litter_super -}; - static int __init ib_uverbs_init(void) { int ret; @@ -864,33 +817,14 @@ static int __init ib_uverbs_init(void) goto out_class; } - ret = register_filesystem(&uverbs_event_fs); - if (ret) { - printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n"); - goto out_class; - } - - uverbs_event_mnt = kern_mount(&uverbs_event_fs); - if (IS_ERR(uverbs_event_mnt)) { - ret = PTR_ERR(uverbs_event_mnt); - printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n"); - goto out_fs; - } - ret = ib_register_client(&uverbs_client); if (ret) { printk(KERN_ERR "user_verbs: couldn't register client\n"); - goto out_mnt; + goto out_class; } return 0; -out_mnt: - mntput(uverbs_event_mnt); - -out_fs: - unregister_filesystem(&uverbs_event_fs); - out_class: class_destroy(uverbs_class); @@ -904,8 +838,6 @@ out: static void __exit ib_uverbs_cleanup(void) { ib_unregister_client(&uverbs_client); - mntput(uverbs_event_mnt); - unregister_filesystem(&uverbs_event_fs); class_destroy(uverbs_class); unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); idr_destroy(&ib_uverbs_pd_idr); -- cgit v1.2.3-59-g8ed1b From 19b629f581320999ddb9f6597051b79cdb53459c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 5 Mar 2010 13:41:38 -0800 Subject: infiniband: use for_each_set_bit() Replace open-coded loop with for_each_set_bit(). Signed-off-by: Akinobu Mita Acked-by: Roland Dreier Cc: Sean Hefty Cc: Hal Rosenstock Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/core/mad.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 7522008fda86..58463da814d1 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1193,10 +1193,7 @@ static int method_in_use(struct ib_mad_mgmt_method_table **method, { int i; - for (i = find_first_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS); - i < IB_MGMT_MAX_METHODS; - i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, - 1+i)) { + for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS) { if ((*method)->agent[i]) { printk(KERN_ERR PFX "Method %d already in use\n", i); return -EINVAL; @@ -1330,13 +1327,9 @@ static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, goto error3; /* Finally, add in methods being registered */ - for (i = find_first_bit(mad_reg_req->method_mask, - IB_MGMT_MAX_METHODS); - i < IB_MGMT_MAX_METHODS; - i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, - 1+i)) { + for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS) (*method)->agent[i] = agent_priv; - } + return 0; error3: @@ -1429,13 +1422,9 @@ check_in_use: goto error4; /* Finally, add in methods being registered */ - for (i = find_first_bit(mad_reg_req->method_mask, - IB_MGMT_MAX_METHODS); - i < IB_MGMT_MAX_METHODS; - i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, - 1+i)) { + for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS) (*method)->agent[i] = agent_priv; - } + return 0; error4: -- cgit v1.2.3-59-g8ed1b From 28812fe11a21826ba4c97c6c7971a619987cd912 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 5 Jan 2010 12:48:07 +0100 Subject: driver-core: Add attribute argument to class_attribute show/store Passing the attribute to the low level IO functions allows all kinds of cleanups, by sharing low level IO code without requiring an own function for every piece of data. Also drivers can extend the attributes with own data fields and use that in the low level function. This makes the class attributes the same as sysdev_class attributes and plain attributes. This will allow further cleanups in drivers. Full tree sweep converting all users. Signed-off-by: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 4 ++-- drivers/base/cpu.c | 8 ++++++-- drivers/base/firmware_class.c | 8 ++++++-- drivers/base/memory.c | 11 ++++++++--- drivers/block/osdblk.c | 12 +++++++++--- drivers/block/pktcdvd.c | 12 +++++++++--- drivers/gpio/gpiolib.c | 8 ++++++-- drivers/gpu/drm/drm_sysfs.c | 3 ++- drivers/infiniband/core/ucm.c | 4 +++- drivers/infiniband/core/user_mad.c | 4 +++- drivers/infiniband/core/uverbs_main.c | 4 +++- drivers/misc/phantom.c | 2 +- drivers/mtd/ubi/build.c | 3 ++- drivers/net/bonding/bond_sysfs.c | 5 ++++- drivers/staging/asus_oled/asus_oled.c | 4 +++- drivers/uwb/driver.c | 5 ++++- include/linux/device.h | 6 ++++-- net/bluetooth/l2cap.c | 4 +++- net/bluetooth/rfcomm/core.c | 4 +++- net/bluetooth/rfcomm/sock.c | 4 +++- net/bluetooth/sco.c | 4 +++- 21 files changed, 87 insertions(+), 32 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/base/class.c b/drivers/base/class.c index 6e2c3b064f53..34a2de9c5385 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -31,7 +31,7 @@ static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, ssize_t ret = -EIO; if (class_attr->show) - ret = class_attr->show(cp->class, buf); + ret = class_attr->show(cp->class, class_attr, buf); return ret; } @@ -43,7 +43,7 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, ssize_t ret = -EIO; if (class_attr->store) - ret = class_attr->store(cp->class, buf, count); + ret = class_attr->store(cp->class, class_attr, buf, count); return ret; } diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index fb456b729803..9121c77b77fa 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -79,13 +79,17 @@ void unregister_cpu(struct cpu *cpu) } #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE -static ssize_t cpu_probe_store(struct class *class, const char *buf, +static ssize_t cpu_probe_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) { return arch_cpu_probe(buf, count); } -static ssize_t cpu_release_store(struct class *class, const char *buf, +static ssize_t cpu_release_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) { return arch_cpu_release(buf, count); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index a95024166b66..6604fb33d072 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -69,7 +69,9 @@ fw_load_abort(struct firmware_priv *fw_priv) } static ssize_t -firmware_timeout_show(struct class *class, char *buf) +firmware_timeout_show(struct class *class, + struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", loading_timeout); } @@ -87,7 +89,9 @@ firmware_timeout_show(struct class *class, char *buf) * Note: zero means 'wait forever'. **/ static ssize_t -firmware_timeout_store(struct class *class, const char *buf, size_t count) +firmware_timeout_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) { loading_timeout = simple_strtol(buf, NULL, 10); if (loading_timeout < 0) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 563656ad75a1..495f15e92d4c 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -331,7 +331,8 @@ static int block_size_init(void) */ #ifdef CONFIG_ARCH_MEMORY_PROBE static ssize_t -memory_probe_store(struct class *class, const char *buf, size_t count) +memory_probe_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) { u64 phys_addr; int nid; @@ -368,7 +369,9 @@ static inline int memory_probe_init(void) /* Soft offline a page */ static ssize_t -store_soft_offline_page(struct class *class, const char *buf, size_t count) +store_soft_offline_page(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) { int ret; u64 pfn; @@ -385,7 +388,9 @@ store_soft_offline_page(struct class *class, const char *buf, size_t count) /* Forcibly offline a page, including killing processes. */ static ssize_t -store_hard_offline_page(struct class *class, const char *buf, size_t count) +store_hard_offline_page(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) { int ret; u64 pfn; diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c index a808b1530b3b..eb2091aa1c19 100644 --- a/drivers/block/osdblk.c +++ b/drivers/block/osdblk.c @@ -476,7 +476,9 @@ static void class_osdblk_release(struct class *cls) kfree(cls); } -static ssize_t class_osdblk_list(struct class *c, char *data) +static ssize_t class_osdblk_list(struct class *c, + struct class_attribute *attr, + char *data) { int n = 0; struct list_head *tmp; @@ -500,7 +502,9 @@ static ssize_t class_osdblk_list(struct class *c, char *data) return n; } -static ssize_t class_osdblk_add(struct class *c, const char *buf, size_t count) +static ssize_t class_osdblk_add(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) { struct osdblk_device *osdev; ssize_t rc; @@ -592,7 +596,9 @@ err_out_mod: return rc; } -static ssize_t class_osdblk_remove(struct class *c, const char *buf, +static ssize_t class_osdblk_remove(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) { struct osdblk_device *osdev = NULL; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index b72935b8f203..73d815d3f1b2 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -337,7 +337,9 @@ static void class_pktcdvd_release(struct class *cls) { kfree(cls); } -static ssize_t class_pktcdvd_show_map(struct class *c, char *data) +static ssize_t class_pktcdvd_show_map(struct class *c, + struct class_attribute *attr, + char *data) { int n = 0; int idx; @@ -356,7 +358,9 @@ static ssize_t class_pktcdvd_show_map(struct class *c, char *data) return n; } -static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf, +static ssize_t class_pktcdvd_store_add(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) { unsigned int major, minor; @@ -376,7 +380,9 @@ static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf, return -EINVAL; } -static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf, +static ssize_t class_pktcdvd_store_remove(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) { unsigned int major, minor; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9006fdb26fea..6d1b86661e63 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -623,7 +623,9 @@ static const struct attribute_group gpiochip_attr_group = { * /sys/class/gpio/unexport ... write-only * integer N ... number of GPIO to unexport */ -static ssize_t export_store(struct class *class, const char *buf, size_t len) +static ssize_t export_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t len) { long gpio; int status; @@ -653,7 +655,9 @@ done: return status ? : len; } -static ssize_t unexport_store(struct class *class, const char *buf, size_t len) +static ssize_t unexport_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t len) { long gpio; int status; diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 7e42b7e9d43a..b95aaf23596e 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -71,7 +71,8 @@ static int drm_class_resume(struct device *dev) } /* Display the version of drm_core. This doesn't work right in current design */ -static ssize_t version_show(struct class *dev, char *buf) +static ssize_t version_show(struct class *dev, struct class_attribute *attr, + char *buf) { return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 1b09b735c5a8..02e209ff33fd 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1336,7 +1336,9 @@ static void ib_ucm_remove_one(struct ib_device *device) device_unregister(&ucm_dev->dev); } -static ssize_t show_abi_version(struct class *class, char *buf) +static ssize_t show_abi_version(struct class *class, + struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION); } diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 02d360cfc2f7..d0de8f265f45 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -965,7 +965,9 @@ static ssize_t show_port(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); -static ssize_t show_abi_version(struct class *class, char *buf) +static ssize_t show_abi_version(struct class *class, + struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION); } diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 4fa2e6516441..60879399207a 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -691,7 +691,9 @@ static ssize_t show_dev_abi_version(struct device *device, } static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); -static ssize_t show_abi_version(struct class *class, char *buf) +static ssize_t show_abi_version(struct class *class, + struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); } diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 04c27266f567..d30ae9560309 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -497,7 +497,7 @@ static struct pci_driver phantom_pci_driver = { .resume = phantom_resume }; -static ssize_t phantom_show_version(struct class *cls, char *buf) +static ssize_t phantom_show_version(struct class *cls, struct class_attribute *attr, char *buf) { return sprintf(buf, PHANTOM_VERSION "\n"); } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index bc45ef9af17d..fad40aa6f099 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -89,7 +89,8 @@ DEFINE_MUTEX(ubi_devices_mutex); static DEFINE_SPINLOCK(ubi_devices_lock); /* "Show" method for files in '//class/ubi/' */ -static ssize_t ubi_version_show(struct class *class, char *buf) +static ssize_t ubi_version_show(struct class *class, struct class_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", UBI_VERSION); } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 5acd557cea9b..b8bec086daa1 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -51,7 +51,9 @@ * "show" function for the bond_masters attribute. * The class parameter is ignored. */ -static ssize_t bonding_show_bonds(struct class *cls, char *buf) +static ssize_t bonding_show_bonds(struct class *cls, + struct class_attribute *attr, + char *buf) { struct net *net = current->nsproxy->net_ns; struct bond_net *bn = net_generic(net, bond_net_id); @@ -98,6 +100,7 @@ static struct net_device *bond_get_by_name(struct net *net, const char *ifname) */ static ssize_t bonding_store_bonds(struct class *cls, + struct class_attribute *attr, const char *buffer, size_t count) { struct net *net = current->nsproxy->net_ns; diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index cadb6f7321ad..7d93f50a0a64 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -770,7 +770,9 @@ static struct usb_driver oled_driver = { .id_table = id_table, }; -static ssize_t version_show(struct class *dev, char *buf) +static ssize_t version_show(struct class *dev, + struct class_attribute *attr, + char *buf) { return sprintf(buf, ASUS_OLED_UNDERSCORE_NAME " %s\n", ASUS_OLED_VERSION); diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c index da77e41de990..08bd6dbfd4a6 100644 --- a/drivers/uwb/driver.c +++ b/drivers/uwb/driver.c @@ -74,13 +74,16 @@ unsigned long beacon_timeout_ms = 500; static -ssize_t beacon_timeout_ms_show(struct class *class, char *buf) +ssize_t beacon_timeout_ms_show(struct class *class, + struct class_attribute *attr, + char *buf) { return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms); } static ssize_t beacon_timeout_ms_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t size) { unsigned long bt; diff --git a/include/linux/device.h b/include/linux/device.h index b30527db3ac0..190f8d30d1d3 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -251,8 +251,10 @@ extern struct device *class_find_device(struct class *class, struct class_attribute { struct attribute attr; - ssize_t (*show)(struct class *class, char *buf); - ssize_t (*store)(struct class *class, const char *buf, size_t count); + ssize_t (*show)(struct class *class, struct class_attribute *attr, + char *buf); + ssize_t (*store)(struct class *class, struct class_attribute *attr, + const char *buf, size_t count); }; #define CLASS_ATTR(_name, _mode, _show, _store) \ diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 400efa26ddba..4db7ae2fe07d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3937,7 +3937,9 @@ drop: return 0; } -static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) +static ssize_t l2cap_sysfs_show(struct class *dev, + struct class_attribute *attr, + char *buf) { struct sock *sk; struct hlist_node *node; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 89f4a59eb82b..db8a68e1a5ba 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2098,7 +2098,9 @@ static struct hci_cb rfcomm_cb = { .security_cfm = rfcomm_security_cfm }; -static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf) +static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, + struct class_attribute *attr, + char *buf) { struct rfcomm_session *s; struct list_head *pp, *p; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 4b5968dda673..ca87d6ac6a20 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -1061,7 +1061,9 @@ done: return result; } -static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf) +static ssize_t rfcomm_sock_sysfs_show(struct class *dev, + struct class_attribute *attr, + char *buf) { struct sock *sk; struct hlist_node *node; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index dd8f6ec57dce..f93b939539bc 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -953,7 +953,9 @@ drop: return 0; } -static ssize_t sco_sysfs_show(struct class *dev, char *buf) +static ssize_t sco_sysfs_show(struct class *dev, + struct class_attribute *attr, + char *buf) { struct sock *sk; struct hlist_node *node; -- cgit v1.2.3-59-g8ed1b From 0933e2d98d1b170ef62d48e18157f5dc43b58217 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 5 Jan 2010 12:48:09 +0100 Subject: driver core: Convert some drivers to CLASS_ATTR_STRING Convert some drivers who export a single string as class attribute to the new class_attr_string functions. This removes redundant code all over. Signed-off-by: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_sysfs.c | 19 ++++++++----------- drivers/infiniband/core/ucm.c | 15 +++++---------- drivers/infiniband/core/user_mad.c | 11 +++-------- drivers/infiniband/core/uverbs_main.c | 11 +++-------- drivers/misc/phantom.c | 13 ++++--------- drivers/staging/asus_oled/asus_oled.c | 15 ++++----------- 6 files changed, 27 insertions(+), 57 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index b95aaf23596e..014ce24761b9 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -70,20 +70,17 @@ static int drm_class_resume(struct device *dev) return 0; } -/* Display the version of drm_core. This doesn't work right in current design */ -static ssize_t version_show(struct class *dev, struct class_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR, - CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); -} - static char *drm_devnode(struct device *dev, mode_t *mode) { return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev)); } -static CLASS_ATTR(version, S_IRUGO, version_show, NULL); +static CLASS_ATTR_STRING(version, S_IRUGO, + CORE_NAME " " + __stringify(CORE_MAJOR) "." + __stringify(CORE_MINOR) "." + __stringify(CORE_PATCHLEVEL) " " + CORE_DATE); /** * drm_sysfs_create - create a struct drm_sysfs_class structure @@ -110,7 +107,7 @@ struct class *drm_sysfs_create(struct module *owner, char *name) class->suspend = drm_class_suspend; class->resume = drm_class_resume; - err = class_create_file(class, &class_attr_version); + err = class_create_file(class, &class_attr_version.attr); if (err) goto err_out_class; @@ -133,7 +130,7 @@ void drm_sysfs_destroy(void) { if ((drm_class == NULL) || (IS_ERR(drm_class))) return; - class_remove_file(drm_class, &class_attr_version); + class_remove_file(drm_class, &class_attr_version.attr); class_destroy(drm_class); } diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 02e209ff33fd..017d6e24448f 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1336,13 +1336,8 @@ static void ib_ucm_remove_one(struct ib_device *device) device_unregister(&ucm_dev->dev); } -static ssize_t show_abi_version(struct class *class, - struct class_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION); -} -static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); +static CLASS_ATTR_STRING(abi_version, S_IRUGO, + __stringify(IB_USER_CM_ABI_VERSION)); static int __init ib_ucm_init(void) { @@ -1355,7 +1350,7 @@ static int __init ib_ucm_init(void) goto error1; } - ret = class_create_file(&cm_class, &class_attr_abi_version); + ret = class_create_file(&cm_class, &class_attr_abi_version.attr); if (ret) { printk(KERN_ERR "ucm: couldn't create abi_version attribute\n"); goto error2; @@ -1369,7 +1364,7 @@ static int __init ib_ucm_init(void) return 0; error3: - class_remove_file(&cm_class, &class_attr_abi_version); + class_remove_file(&cm_class, &class_attr_abi_version.attr); error2: unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); error1: @@ -1379,7 +1374,7 @@ error1: static void __exit ib_ucm_cleanup(void) { ib_unregister_client(&ucm_client); - class_remove_file(&cm_class, &class_attr_abi_version); + class_remove_file(&cm_class, &class_attr_abi_version.attr); unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); if (overflow_maj) unregister_chrdev_region(overflow_maj, IB_UCM_MAX_DEVICES); diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index d0de8f265f45..04b585e86cb2 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -965,13 +965,8 @@ static ssize_t show_port(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); -static ssize_t show_abi_version(struct class *class, - struct class_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION); -} -static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); +static CLASS_ATTR_STRING(abi_version, S_IRUGO, + __stringify(IB_USER_MAD_ABI_VERSION)); static dev_t overflow_maj; static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS); @@ -1196,7 +1191,7 @@ static int __init ib_umad_init(void) goto out_chrdev; } - ret = class_create_file(umad_class, &class_attr_abi_version); + ret = class_create_file(umad_class, &class_attr_abi_version.attr); if (ret) { printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n"); goto out_class; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 60879399207a..d805cf365c8d 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -691,13 +691,8 @@ static ssize_t show_dev_abi_version(struct device *device, } static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); -static ssize_t show_abi_version(struct class *class, - struct class_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); -} -static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); +static CLASS_ATTR_STRING(abi_version, S_IRUGO, + __stringify(IB_USER_VERBS_ABI_VERSION)); static dev_t overflow_maj; static DECLARE_BITMAP(overflow_map, IB_UVERBS_MAX_DEVICES); @@ -843,7 +838,7 @@ static int __init ib_uverbs_init(void) goto out_chrdev; } - ret = class_create_file(uverbs_class, &class_attr_abi_version); + ret = class_create_file(uverbs_class, &class_attr_abi_version.attr); if (ret) { printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); goto out_class; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index d30ae9560309..779aa8ebe4cf 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -497,12 +497,7 @@ static struct pci_driver phantom_pci_driver = { .resume = phantom_resume }; -static ssize_t phantom_show_version(struct class *cls, struct class_attribute *attr, char *buf) -{ - return sprintf(buf, PHANTOM_VERSION "\n"); -} - -static CLASS_ATTR(version, 0444, phantom_show_version, NULL); +static CLASS_ATTR_STRING(version, 0444, PHANTOM_VERSION); static int __init phantom_init(void) { @@ -515,7 +510,7 @@ static int __init phantom_init(void) printk(KERN_ERR "phantom: can't register phantom class\n"); goto err; } - retval = class_create_file(phantom_class, &class_attr_version); + retval = class_create_file(phantom_class, &class_attr_version.attr); if (retval) { printk(KERN_ERR "phantom: can't create sysfs version file\n"); goto err_class; @@ -541,7 +536,7 @@ static int __init phantom_init(void) err_unchr: unregister_chrdev_region(dev, PHANTOM_MAX_MINORS); err_attr: - class_remove_file(phantom_class, &class_attr_version); + class_remove_file(phantom_class, &class_attr_version.attr); err_class: class_destroy(phantom_class); err: @@ -554,7 +549,7 @@ static void __exit phantom_exit(void) unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS); - class_remove_file(phantom_class, &class_attr_version); + class_remove_file(phantom_class, &class_attr_version.attr); class_destroy(phantom_class); pr_debug("phantom: module successfully removed\n"); diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 7d93f50a0a64..7ebecc92c61b 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -770,15 +770,8 @@ static struct usb_driver oled_driver = { .id_table = id_table, }; -static ssize_t version_show(struct class *dev, - struct class_attribute *attr, - char *buf) -{ - return sprintf(buf, ASUS_OLED_UNDERSCORE_NAME " %s\n", - ASUS_OLED_VERSION); -} - -static CLASS_ATTR(version, S_IRUGO, version_show, NULL); +static CLASS_ATTR_STRING(version, S_IRUGO, + ASUS_OLED_UNDERSCORE_NAME " " ASUS_OLED_VERSION); static int __init asus_oled_init(void) { @@ -790,7 +783,7 @@ static int __init asus_oled_init(void) return PTR_ERR(oled_class); } - retval = class_create_file(oled_class, &class_attr_version); + retval = class_create_file(oled_class, &class_attr_version.attr); if (retval) { err("Error creating class version file"); goto error; @@ -812,7 +805,7 @@ error: static void __exit asus_oled_exit(void) { - class_remove_file(oled_class, &class_attr_version); + class_remove_file(oled_class, &class_attr_version.attr); class_destroy(oled_class); usb_deregister(&oled_driver); -- cgit v1.2.3-59-g8ed1b From 52cf25d0ab7f78eeecc59ac652ed5090f69b619e Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Tue, 19 Jan 2010 02:58:23 +0100 Subject: Driver core: Constify struct sysfs_ops in struct kobj_type Constify struct sysfs_ops. This is part of the ops structure constification effort started by Arjan van de Ven et al. Benefits of this constification: * prevents modification of data that is shared (referenced) by many other structure instances at runtime * detects/prevents accidental (but not intentional) modification attempts on archs that enforce read-only kernel data at runtime * potentially better optimized code as the compiler can assume that the const data cannot be changed * the compiler/linker move const data into .rodata and therefore exclude them from false sharing Signed-off-by: Emese Revfy Acked-by: David Teigland Acked-by: Matt Domsch Acked-by: Maciej Sosnowski Acked-by: Hans J. Koch Acked-by: Pekka Enberg Acked-by: Jens Axboe Acked-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 2 +- arch/ia64/kernel/topology.c | 2 +- arch/powerpc/kernel/cacheinfo.c | 2 +- arch/sh/kernel/cpu/sh4/sq.c | 2 +- arch/x86/kernel/cpu/intel_cacheinfo.c | 2 +- arch/x86/kernel/cpu/mcheck/mce_amd.c | 2 +- block/blk-integrity.c | 2 +- block/blk-sysfs.c | 2 +- block/elevator.c | 2 +- drivers/base/bus.c | 4 ++-- drivers/base/class.c | 2 +- drivers/base/core.c | 2 +- drivers/base/sys.c | 4 ++-- drivers/block/pktcdvd.c | 2 +- drivers/cpufreq/cpufreq.c | 2 +- drivers/cpuidle/sysfs.c | 4 ++-- drivers/dma/ioat/dma.c | 2 +- drivers/dma/ioat/dma.h | 2 +- drivers/edac/edac_device_sysfs.c | 6 +++--- drivers/edac/edac_mc_sysfs.c | 4 ++-- drivers/edac/edac_pci_sysfs.c | 4 ++-- drivers/firmware/edd.c | 2 +- drivers/firmware/efivars.c | 2 +- drivers/firmware/iscsi_ibft.c | 2 +- drivers/firmware/memmap.c | 2 +- drivers/gpu/drm/ttm/ttm_bo.c | 2 +- drivers/gpu/drm/ttm/ttm_memory.c | 2 +- drivers/infiniband/core/cm.c | 2 +- drivers/infiniband/core/sysfs.c | 2 +- drivers/md/dm-sysfs.c | 2 +- drivers/md/md.c | 4 ++-- drivers/net/ibmveth.c | 2 +- drivers/net/iseries_veth.c | 4 ++-- drivers/parisc/pdc_stable.c | 2 +- drivers/pci/hotplug/fakephp.c | 2 +- drivers/pci/slot.c | 2 +- drivers/uio/uio.c | 4 ++-- drivers/uwb/wlp/sysfs.c | 3 +-- drivers/video/omap2/dss/manager.c | 2 +- drivers/video/omap2/dss/overlay.c | 2 +- drivers/xen/sys-hypervisor.c | 2 +- fs/btrfs/sysfs.c | 4 ++-- fs/dlm/lockspace.c | 2 +- fs/ext4/super.c | 2 +- fs/gfs2/sys.c | 2 +- fs/ocfs2/cluster/masklog.c | 2 +- fs/sysfs/file.c | 8 ++++---- include/linux/kobject.h | 4 ++-- kernel/params.c | 2 +- lib/kobject.c | 2 +- mm/slub.c | 2 +- net/bridge/br_private.h | 2 +- net/bridge/br_sysfs_if.c | 2 +- samples/kobject/kset-example.c | 2 +- 54 files changed, 69 insertions(+), 70 deletions(-) (limited to 'drivers/infiniband') diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index c79ab996dada..bdb13817e1e9 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -266,7 +266,7 @@ kobj_type: struct kobj_type { void (*release)(struct kobject *); - struct sysfs_ops *sysfs_ops; + const struct sysfs_ops *sysfs_ops; struct attribute **default_attrs; }; diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 8f060352e129..b3a5818088d9 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -282,7 +282,7 @@ static ssize_t cache_show(struct kobject * kobj, struct attribute * attr, char * return ret; } -static struct sysfs_ops cache_sysfs_ops = { +static const struct sysfs_ops cache_sysfs_ops = { .show = cache_show }; diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index bb37b1d19a58..01fe9ce28379 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -642,7 +642,7 @@ static struct kobj_attribute *cache_index_opt_attrs[] = { &cache_assoc_attr, }; -static struct sysfs_ops cache_index_ops = { +static const struct sysfs_ops cache_index_ops = { .show = cache_index_show, }; diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index fc065f9da6e5..14726eef1ce0 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -326,7 +326,7 @@ static struct attribute *sq_sysfs_attrs[] = { NULL, }; -static struct sysfs_ops sq_sysfs_ops = { +static const struct sysfs_ops sq_sysfs_ops = { .show = sq_sysfs_show, .store = sq_sysfs_store, }; diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index eddb1bdd1b8f..b3eeb66c0a51 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -903,7 +903,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops sysfs_ops = { +static const struct sysfs_ops sysfs_ops = { .show = show, .store = store, }; diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 83a3d1f4efca..cda932ca3ade 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -388,7 +388,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops threshold_ops = { +static const struct sysfs_ops threshold_ops = { .show = show, .store = store, }; diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 15c630813b1c..96e83c2bdb94 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -278,7 +278,7 @@ static struct attribute *integrity_attrs[] = { NULL, }; -static struct sysfs_ops integrity_ops = { +static const struct sysfs_ops integrity_ops = { .show = &integrity_attr_show, .store = &integrity_attr_store, }; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index e85442415db3..2ae2cb3f362f 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -450,7 +450,7 @@ static void blk_release_queue(struct kobject *kobj) kmem_cache_free(blk_requestq_cachep, q); } -static struct sysfs_ops queue_sysfs_ops = { +static const struct sysfs_ops queue_sysfs_ops = { .show = queue_attr_show, .store = queue_attr_store, }; diff --git a/block/elevator.c b/block/elevator.c index ee3a883840f2..df75676f6671 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -892,7 +892,7 @@ elv_attr_store(struct kobject *kobj, struct attribute *attr, return error; } -static struct sysfs_ops elv_sysfs_ops = { +static const struct sysfs_ops elv_sysfs_ops = { .show = elv_attr_show, .store = elv_attr_store, }; diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2afe599eb35d..cca1aa10054c 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -70,7 +70,7 @@ static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops driver_sysfs_ops = { +static const struct sysfs_ops driver_sysfs_ops = { .show = drv_attr_show, .store = drv_attr_store, }; @@ -115,7 +115,7 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops bus_sysfs_ops = { +static const struct sysfs_ops bus_sysfs_ops = { .show = bus_attr_show, .store = bus_attr_store, }; diff --git a/drivers/base/class.c b/drivers/base/class.c index 2e297cc4cd3d..0147f476b8a9 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -63,7 +63,7 @@ static void class_release(struct kobject *kobj) kfree(cp); } -static struct sysfs_ops class_sysfs_ops = { +static const struct sysfs_ops class_sysfs_ops = { .show = class_attr_show, .store = class_attr_store, }; diff --git a/drivers/base/core.c b/drivers/base/core.c index 58ec1069f4b0..b0d6646a2814 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -100,7 +100,7 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops dev_sysfs_ops = { +static const struct sysfs_ops dev_sysfs_ops = { .show = dev_attr_show, .store = dev_attr_store, }; diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 747c99e0568b..8980feec5d14 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -54,7 +54,7 @@ sysdev_store(struct kobject *kobj, struct attribute *attr, return -EIO; } -static struct sysfs_ops sysfs_ops = { +static const struct sysfs_ops sysfs_ops = { .show = sysdev_show, .store = sysdev_store, }; @@ -104,7 +104,7 @@ static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, return -EIO; } -static struct sysfs_ops sysfs_class_ops = { +static const struct sysfs_ops sysfs_class_ops = { .show = sysdev_class_show, .store = sysdev_class_store, }; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 73d815d3f1b2..39c8514442eb 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -284,7 +284,7 @@ static ssize_t kobj_pkt_store(struct kobject *kobj, return len; } -static struct sysfs_ops kobj_pkt_ops = { +static const struct sysfs_ops kobj_pkt_ops = { .show = kobj_pkt_show, .store = kobj_pkt_store }; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 67bc2ece7b4b..2d5d575e889d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -766,7 +766,7 @@ static void cpufreq_sysfs_release(struct kobject *kobj) complete(&policy->kobj_unregister); } -static struct sysfs_ops sysfs_ops = { +static const struct sysfs_ops sysfs_ops = { .show = show, .store = store, }; diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index c9cefacabf37..8719b36e1a4d 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -195,7 +195,7 @@ static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr, return ret; } -static struct sysfs_ops cpuidle_sysfs_ops = { +static const struct sysfs_ops cpuidle_sysfs_ops = { .show = cpuidle_show, .store = cpuidle_store, }; @@ -281,7 +281,7 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, return ret; } -static struct sysfs_ops cpuidle_state_sysfs_ops = { +static const struct sysfs_ops cpuidle_state_sysfs_ops = { .show = cpuidle_state_show, }; diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index af14c9a5b8d4..0099340b9616 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -1138,7 +1138,7 @@ ioat_attr_show(struct kobject *kobj, struct attribute *attr, char *page) return entry->show(&chan->common, page); } -struct sysfs_ops ioat_sysfs_ops = { +const struct sysfs_ops ioat_sysfs_ops = { .show = ioat_attr_show, }; diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index 4f747a254074..86b97ac8774e 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -346,7 +346,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan, unsigned long *phys_complete); void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type); void ioat_kobject_del(struct ioatdma_device *device); -extern struct sysfs_ops ioat_sysfs_ops; +extern const struct sysfs_ops ioat_sysfs_ops; extern struct ioat_sysfs_entry ioat_version_attr; extern struct ioat_sysfs_entry ioat_cap_attr; #endif /* IOATDMA_H */ diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 53764577035f..5fdedbc0f545 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -137,7 +137,7 @@ static ssize_t edac_dev_ctl_info_store(struct kobject *kobj, } /* edac_dev file operations for an 'ctl_info' */ -static struct sysfs_ops device_ctl_info_ops = { +static const struct sysfs_ops device_ctl_info_ops = { .show = edac_dev_ctl_info_show, .store = edac_dev_ctl_info_store }; @@ -373,7 +373,7 @@ static ssize_t edac_dev_instance_store(struct kobject *kobj, } /* edac_dev file operations for an 'instance' */ -static struct sysfs_ops device_instance_ops = { +static const struct sysfs_ops device_instance_ops = { .show = edac_dev_instance_show, .store = edac_dev_instance_store }; @@ -476,7 +476,7 @@ static ssize_t edac_dev_block_store(struct kobject *kobj, } /* edac_dev file operations for a 'block' */ -static struct sysfs_ops device_block_ops = { +static const struct sysfs_ops device_block_ops = { .show = edac_dev_block_show, .store = edac_dev_block_store }; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index e1d4ce083481..88840e9fa3e0 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -245,7 +245,7 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, return -EIO; } -static struct sysfs_ops csrowfs_ops = { +static const struct sysfs_ops csrowfs_ops = { .show = csrowdev_show, .store = csrowdev_store }; @@ -575,7 +575,7 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, } /* Intermediate show/store table */ -static struct sysfs_ops mci_ops = { +static const struct sysfs_ops mci_ops = { .show = mcidev_show, .store = mcidev_store }; diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index fb60a877d768..bef94e3d9944 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -121,7 +121,7 @@ static ssize_t edac_pci_instance_store(struct kobject *kobj, } /* fs_ops table */ -static struct sysfs_ops pci_instance_ops = { +static const struct sysfs_ops pci_instance_ops = { .show = edac_pci_instance_show, .store = edac_pci_instance_store }; @@ -261,7 +261,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj, return -EIO; } -static struct sysfs_ops edac_pci_sysfs_ops = { +static const struct sysfs_ops edac_pci_sysfs_ops = { .show = edac_pci_dev_show, .store = edac_pci_dev_store }; diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 9e4f59dc7f1e..110e24e50883 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -122,7 +122,7 @@ edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) return ret; } -static struct sysfs_ops edd_attr_ops = { +static const struct sysfs_ops edd_attr_ops = { .show = edd_attr_show, }; diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index f4f709d1370b..082f06ecd327 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -362,7 +362,7 @@ static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops efivar_attr_ops = { +static const struct sysfs_ops efivar_attr_ops = { .show = efivar_attr_show, .store = efivar_attr_store, }; diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index a3600e3ed0fa..ed2801c378de 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -519,7 +519,7 @@ static ssize_t ibft_show_attribute(struct kobject *kobj, return ret; } -static struct sysfs_ops ibft_attr_ops = { +static const struct sysfs_ops ibft_attr_ops = { .show = ibft_show_attribute, }; diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 20f645743ead..d59f7cad2269 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -74,7 +74,7 @@ static struct attribute *def_attrs[] = { NULL }; -static struct sysfs_ops memmap_attr_ops = { +static const struct sysfs_ops memmap_attr_ops = { .show = memmap_attr_show, }; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index c7320ce4567d..89c38c49066f 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -128,7 +128,7 @@ static struct attribute *ttm_bo_global_attrs[] = { NULL }; -static struct sysfs_ops ttm_bo_global_ops = { +static const struct sysfs_ops ttm_bo_global_ops = { .show = &ttm_bo_global_show }; diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c index f5245c02b8fd..eb143e04d402 100644 --- a/drivers/gpu/drm/ttm/ttm_memory.c +++ b/drivers/gpu/drm/ttm/ttm_memory.c @@ -152,7 +152,7 @@ static struct attribute *ttm_mem_zone_attrs[] = { NULL }; -static struct sysfs_ops ttm_mem_zone_ops = { +static const struct sysfs_ops ttm_mem_zone_ops = { .show = &ttm_mem_zone_show, .store = &ttm_mem_zone_store }; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 5130fc55b8e2..764787ebe8d8 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -3597,7 +3597,7 @@ static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr, atomic_long_read(&group->counter[cm_attr->index])); } -static struct sysfs_ops cm_counter_ops = { +static const struct sysfs_ops cm_counter_ops = { .show = cm_show_counter }; diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 158a214da2f7..1558bb7fc74d 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -79,7 +79,7 @@ static ssize_t port_attr_show(struct kobject *kobj, return port_attr->show(p, port_attr, buf); } -static struct sysfs_ops port_sysfs_ops = { +static const struct sysfs_ops port_sysfs_ops = { .show = port_attr_show }; diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index f91b40942e07..84d2b91e4efb 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c @@ -75,7 +75,7 @@ static struct attribute *dm_attrs[] = { NULL, }; -static struct sysfs_ops dm_sysfs_ops = { +static const struct sysfs_ops dm_sysfs_ops = { .show = dm_attr_show, }; diff --git a/drivers/md/md.c b/drivers/md/md.c index a20a71e5efd3..fdc1890b6ac5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2642,7 +2642,7 @@ static void rdev_free(struct kobject *ko) mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj); kfree(rdev); } -static struct sysfs_ops rdev_sysfs_ops = { +static const struct sysfs_ops rdev_sysfs_ops = { .show = rdev_attr_show, .store = rdev_attr_store, }; @@ -4059,7 +4059,7 @@ static void md_free(struct kobject *ko) kfree(mddev); } -static struct sysfs_ops md_sysfs_ops = { +static const struct sysfs_ops md_sysfs_ops = { .show = md_attr_show, .store = md_attr_store, }; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index f2b937966950..0bc777bac9b4 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1577,7 +1577,7 @@ static struct attribute * veth_pool_attrs[] = { NULL, }; -static struct sysfs_ops veth_pool_ops = { +static const struct sysfs_ops veth_pool_ops = { .show = veth_pool_show, .store = veth_pool_store, }; diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 966de5d69521..e6e972d9b7ca 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -384,7 +384,7 @@ static struct attribute *veth_cnx_default_attrs[] = { NULL }; -static struct sysfs_ops veth_cnx_sysfs_ops = { +static const struct sysfs_ops veth_cnx_sysfs_ops = { .show = veth_cnx_attribute_show }; @@ -441,7 +441,7 @@ static struct attribute *veth_port_default_attrs[] = { NULL }; -static struct sysfs_ops veth_port_sysfs_ops = { +static const struct sysfs_ops veth_port_sysfs_ops = { .show = veth_port_attribute_show }; diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 0bc5d474b168..1062b8ffe244 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -481,7 +481,7 @@ pdcspath_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static struct sysfs_ops pdcspath_attr_ops = { +static const struct sysfs_ops pdcspath_attr_ops = { .show = pdcspath_attr_show, .store = pdcspath_attr_store, }; diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 6151389fd903..0a894efd4b9b 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -73,7 +73,7 @@ static void legacy_release(struct kobject *kobj) } static struct kobj_type legacy_ktype = { - .sysfs_ops = &(struct sysfs_ops){ + .sysfs_ops = &(const struct sysfs_ops){ .store = legacy_store, .show = legacy_show }, .release = &legacy_release, diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 49c9e6c9779a..f75a44d37fbe 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -29,7 +29,7 @@ static ssize_t pci_slot_attr_store(struct kobject *kobj, return attribute->store ? attribute->store(slot, buf, len) : -EIO; } -static struct sysfs_ops pci_slot_sysfs_ops = { +static const struct sysfs_ops pci_slot_sysfs_ops = { .show = pci_slot_attr_show, .store = pci_slot_attr_store, }; diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index e941367dd28f..4de382acd8f2 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -129,7 +129,7 @@ static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr, return entry->show(mem, buf); } -static struct sysfs_ops map_sysfs_ops = { +static const struct sysfs_ops map_sysfs_ops = { .show = map_type_show, }; @@ -217,7 +217,7 @@ static ssize_t portio_type_show(struct kobject *kobj, struct attribute *attr, return entry->show(port, buf); } -static struct sysfs_ops portio_sysfs_ops = { +static const struct sysfs_ops portio_sysfs_ops = { .show = portio_type_show, }; diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c index 0370399ff4bb..6627c94cc854 100644 --- a/drivers/uwb/wlp/sysfs.c +++ b/drivers/uwb/wlp/sysfs.c @@ -615,8 +615,7 @@ ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -static -struct sysfs_ops wss_sysfs_ops = { +static const struct sysfs_ops wss_sysfs_ops = { .show = wlp_wss_attr_show, .store = wlp_wss_attr_store, }; diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 913142d4cab1..9acef00c47ea 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -341,7 +341,7 @@ static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, return manager_attr->store(manager, buf, size); } -static struct sysfs_ops manager_sysfs_ops = { +static const struct sysfs_ops manager_sysfs_ops = { .show = manager_attr_show, .store = manager_attr_store, }; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 0c5bea263ac6..aed3f3194347 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -320,7 +320,7 @@ static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, return overlay_attr->store(overlay, buf, size); } -static struct sysfs_ops overlay_sysfs_ops = { +static const struct sysfs_ops overlay_sysfs_ops = { .show = overlay_attr_show, .store = overlay_attr_store, }; diff --git a/drivers/xen/sys-hypervisor.c b/drivers/xen/sys-hypervisor.c index ae5cb05a1a1c..bb71ab2336c8 100644 --- a/drivers/xen/sys-hypervisor.c +++ b/drivers/xen/sys-hypervisor.c @@ -426,7 +426,7 @@ static ssize_t hyp_sysfs_store(struct kobject *kobj, return 0; } -static struct sysfs_ops hyp_sysfs_ops = { +static const struct sysfs_ops hyp_sysfs_ops = { .show = hyp_sysfs_show, .store = hyp_sysfs_store, }; diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index a240b6fa81df..4ce16ef702a3 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -164,12 +164,12 @@ static void btrfs_root_release(struct kobject *kobj) complete(&root->kobj_unregister); } -static struct sysfs_ops btrfs_super_attr_ops = { +static const struct sysfs_ops btrfs_super_attr_ops = { .show = btrfs_super_attr_show, .store = btrfs_super_attr_store, }; -static struct sysfs_ops btrfs_root_attr_ops = { +static const struct sysfs_ops btrfs_root_attr_ops = { .show = btrfs_root_attr_show, .store = btrfs_root_attr_store, }; diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 26a8bd40400a..f994a7dfda85 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -148,7 +148,7 @@ static void lockspace_kobj_release(struct kobject *k) kfree(ls); } -static struct sysfs_ops dlm_attr_ops = { +static const struct sysfs_ops dlm_attr_ops = { .show = dlm_attr_show, .store = dlm_attr_store, }; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2b83b96cb2eb..ce84a6ed4a48 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2358,7 +2358,7 @@ static void ext4_sb_release(struct kobject *kobj) } -static struct sysfs_ops ext4_attr_ops = { +static const struct sysfs_ops ext4_attr_ops = { .show = ext4_attr_show, .store = ext4_attr_store, }; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 543503010ed0..419042f7f0b6 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -49,7 +49,7 @@ static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr, return a->store ? a->store(sdp, buf, len) : len; } -static struct sysfs_ops gfs2_attr_ops = { +static const struct sysfs_ops gfs2_attr_ops = { .show = gfs2_attr_show, .store = gfs2_attr_store, }; diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index b39da877b12f..3bb928a2bf7d 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c @@ -136,7 +136,7 @@ static ssize_t mlog_store(struct kobject *obj, struct attribute *attr, return mlog_mask_store(mlog_attr->mask, buf, count); } -static struct sysfs_ops mlog_attr_ops = { +static const struct sysfs_ops mlog_attr_ops = { .show = mlog_show, .store = mlog_store, }; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 50b725bcc3f3..ced2299f1c9a 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -53,7 +53,7 @@ struct sysfs_buffer { size_t count; loff_t pos; char * page; - struct sysfs_ops * ops; + const struct sysfs_ops * ops; struct mutex mutex; int needs_read_fill; int event; @@ -75,7 +75,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer { struct sysfs_dirent *attr_sd = dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; - struct sysfs_ops * ops = buffer->ops; + const struct sysfs_ops * ops = buffer->ops; int ret = 0; ssize_t count; @@ -199,7 +199,7 @@ flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t { struct sysfs_dirent *attr_sd = dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; - struct sysfs_ops * ops = buffer->ops; + const struct sysfs_ops * ops = buffer->ops; int rc; /* need attr_sd for attr and ops, its parent for kobj */ @@ -335,7 +335,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; struct sysfs_buffer *buffer; - struct sysfs_ops *ops; + const struct sysfs_ops *ops; int error = -EACCES; char *p; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 57a1eaae9096..3950d3c2850d 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -106,7 +106,7 @@ extern char *kobject_get_path(struct kobject *kobj, gfp_t flag); struct kobj_type { void (*release)(struct kobject *kobj); - struct sysfs_ops *sysfs_ops; + const struct sysfs_ops *sysfs_ops; struct attribute **default_attrs; }; @@ -132,7 +132,7 @@ struct kobj_attribute { const char *buf, size_t count); }; -extern struct sysfs_ops kobj_sysfs_ops; +extern const struct sysfs_ops kobj_sysfs_ops; /** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. diff --git a/kernel/params.c b/kernel/params.c index 48370be3c0a1..68396d73c838 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -722,7 +722,7 @@ static ssize_t module_attr_store(struct kobject *kobj, return ret; } -static struct sysfs_ops module_sysfs_ops = { +static const struct sysfs_ops module_sysfs_ops = { .show = module_attr_show, .store = module_attr_store, }; diff --git a/lib/kobject.c b/lib/kobject.c index cecf5a0ef6e1..8115eb1bbf4d 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -700,7 +700,7 @@ static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -struct sysfs_ops kobj_sysfs_ops = { +const struct sysfs_ops kobj_sysfs_ops = { .show = kobj_attr_show, .store = kobj_attr_store, }; diff --git a/mm/slub.c b/mm/slub.c index a26753c12dcd..a2b8969ba6d0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -4390,7 +4390,7 @@ static void kmem_cache_release(struct kobject *kobj) kfree(s); } -static struct sysfs_ops slab_sysfs_ops = { +static const struct sysfs_ops slab_sysfs_ops = { .show = slab_attr_show, .store = slab_attr_store, }; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 1cf2cef78584..fef0384e3c0b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -423,7 +423,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port); #ifdef CONFIG_SYSFS /* br_sysfs_if.c */ -extern struct sysfs_ops brport_sysfs_ops; +extern const struct sysfs_ops brport_sysfs_ops; extern int br_sysfs_addif(struct net_bridge_port *p); /* br_sysfs_br.c */ diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 696596cd3384..0b9916489d6b 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -238,7 +238,7 @@ static ssize_t brport_store(struct kobject * kobj, return ret; } -struct sysfs_ops brport_sysfs_ops = { +const struct sysfs_ops brport_sysfs_ops = { .show = brport_show, .store = brport_store, }; diff --git a/samples/kobject/kset-example.c b/samples/kobject/kset-example.c index 7c6088140528..3b126d1f8599 100644 --- a/samples/kobject/kset-example.c +++ b/samples/kobject/kset-example.c @@ -87,7 +87,7 @@ static ssize_t foo_attr_store(struct kobject *kobj, } /* Our custom sysfs_ops that we will associate with our ktype later on */ -static struct sysfs_ops foo_sysfs_ops = { +static const struct sysfs_ops foo_sysfs_ops = { .show = foo_attr_show, .store = foo_attr_store, }; -- cgit v1.2.3-59-g8ed1b From f0dc117abdfa9a0e96c3d013d836460ef3cd08c7 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 3 Mar 2010 12:27:52 +0000 Subject: IPoIB: Fix TX queue lockup with mixed UD/CM traffic The IPoIB UD QP reports send completions to priv->send_cq, which is usually left unarmed; it only gets armed when the number of outstanding send requests reaches the size of the TX queue. This arming is done only in the send path for the UD QP. However, when sending CM packets, the net queue may be stopped for the same reasons but no measures are taken to recover the UD path from a lockup. Consider this scenario: a host sends high rate of both CM and UD packets, with a TX queue length of N. If at some time the number of outstanding UD packets is more than N/2 and the overall outstanding packets is N-1, and CM sends a packet (making the number of outstanding sends equal N), the TX queue will be stopped. When all the CM packets complete, the number of outstanding packets will still be higher than N/2 so the TX queue will not be restarted. Fix this by calling ib_req_notify_cq() when the queue is stopped in the CM path. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 83a7751c38d6..6e3cc865e369 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -752,6 +752,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", tx->qp->qp_num); + if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP)) + ipoib_warn(priv, "request notify on send CQ failed\n"); netif_stop_queue(dev); } } -- cgit v1.2.3-59-g8ed1b From a48f509b26cec53338f4b0abd52ecea35e3974b8 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 4 Mar 2010 13:17:37 +0000 Subject: IPoIB: Include return code in trace message for ib_post_send() failures Print the return code of ib_post_send() if it fails to make these debugging messages more useful. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 8 +++++--- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 6e3cc865e369..bc658373ad55 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -708,6 +708,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_cm_tx_buf *tx_req; u64 addr; + int rc; if (unlikely(skb->len > tx->mtu)) { ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", @@ -739,9 +740,10 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ tx_req->mapping = addr; - if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), - addr, skb->len))) { - ipoib_warn(priv, "post_send failed\n"); + rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), + addr, skb->len); + if (unlikely(rc)) { + ipoib_warn(priv, "post_send failed, error %d\n", rc); ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 8c91d9f37ada..5df40b128f81 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -529,7 +529,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_tx_buf *tx_req; - int hlen; + int hlen, rc; void *phead; if (skb_is_gso(skb)) { @@ -585,9 +585,10 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, netif_stop_queue(dev); } - if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), - address->ah, qpn, tx_req, phead, hlen))) { - ipoib_warn(priv, "post_send failed\n"); + rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), + address->ah, qpn, tx_req, phead, hlen); + if (unlikely(rc)) { + ipoib_warn(priv, "post_send failed, error %d\n", rc); ++dev->stats.tx_errors; --priv->tx_outstanding; ipoib_dma_unmap_tx(priv->ca, tx_req); -- cgit v1.2.3-59-g8ed1b From 070e140c4c536df33a9870318791b2ca8f7dbfcf Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Thu, 4 Mar 2010 18:18:18 +0000 Subject: IB/mad: Ignore iWARP devices on device removal When an iWARP device is unloaded, the ib_mad module logs errors. It should be ignoring iWARP devices on device removal just like it does on device add. Signed-off-by: Steve Wise Acked-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/mad.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 58463da814d1..e351b1548535 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2953,6 +2953,9 @@ static void ib_mad_remove_device(struct ib_device *device) { int i, num_ports, cur_port; + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + if (device->node_type == RDMA_NODE_IB_SWITCH) { num_ports = 1; cur_port = 0; -- cgit v1.2.3-59-g8ed1b From 69960a275efc9d82797bbbe2460a2d6c9cace314 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 3 Mar 2010 15:06:34 +0000 Subject: RDMA/cxgb3: Wait at least one schedule cycle during device removal During a hot-plug LLD removal event or an EEH error event, iw_cxgb3 must ensure that any/all threads that might be in a cxgb3 exported function must return from the function before iw_cxgb3 returns from its event processing. Do this by calling synchronize_net(). Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/iwch.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index ee1d8b4d4541..63f975f3e30f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -189,6 +189,7 @@ static void close_rnic_dev(struct t3cdev *tdev) list_for_each_entry_safe(dev, tmp, &dev_list, entry) { if (dev->rdev.t3cdev_p == tdev) { dev->rdev.flags = CXIO_ERROR_FATAL; + synchronize_net(); cancel_delayed_work_sync(&dev->db_drop_task); list_del(&dev->entry); iwch_unregister_device(dev); @@ -217,6 +218,7 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) switch (evt) { case OFFLOAD_STATUS_DOWN: { rdev->flags = CXIO_ERROR_FATAL; + synchronize_net(); event.event = IB_EVENT_DEVICE_FATAL; dispatch = 1; break; -- cgit v1.2.3-59-g8ed1b From 883c699241f48667ff59277d8c20790868fd4829 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Tue, 2 Mar 2010 17:22:51 -0600 Subject: RDMA/nes: Set assume_aligned_header bit Set assume_aligned_header bit in QP context as requested by hardware group. Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_verbs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 815725f886c4..69928296d74b 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1323,6 +1323,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, nesqp->nesqp_context->aeq_token_low = cpu_to_le32((u32)((unsigned long)(nesqp))); nesqp->nesqp_context->aeq_token_high = cpu_to_le32((u32)(upper_32_bits((unsigned long)(nesqp)))); nesqp->nesqp_context->ird_ord_sizes = cpu_to_le32(NES_QPCONTEXT_ORDIRD_ALSMM | + NES_QPCONTEXT_ORDIRD_AAH | ((((u32)nesadapter->max_irrq_wr) << NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT) & NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK)); if (disable_mpa_crc) { -- cgit v1.2.3-59-g8ed1b From 9f29006ae8c85746e5a52d557f689359149a0793 Mon Sep 17 00:00:00 2001 From: Chien Tung Date: Wed, 3 Mar 2010 19:13:28 +0000 Subject: RDMA/nes: Clear stall bit before destroying NIC QP Clear the stall bit to drop any incoming packets while destroying NIC QP. This will prevent a chip resource leak. Signed-off-by: Chien Tung Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 8 ++++++++ drivers/infiniband/hw/nes/nes_hw.h | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index ce7f53833577..925075557dc2 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -1899,9 +1899,14 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) u16 wqe_fragment_index; u64 wqe_frag; u32 cqp_head; + u32 wqm_cfg0; unsigned long flags; int ret; + /* clear wqe stall before destroying NIC QP */ + wqm_cfg0 = nes_read_indexed(nesdev, NES_IDX_WQM_CONFIG0); + nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0 & 0xFFFF7FFF); + /* Free remaining NIC receive buffers */ while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; @@ -2020,6 +2025,9 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase, nesvnic->nic_pbase); + + /* restore old wqm_cfg0 value */ + nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0); } /** diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 9b1e7f869d83..bbbfe9fc5a5a 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -160,6 +160,7 @@ enum indexed_regs { NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004, NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008, NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c, + NES_IDX_WQM_CONFIG0 = 0x5000, NES_IDX_WQM_CONFIG1 = 0x5004, NES_IDX_CM_CONFIG = 0x5100, NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000, -- cgit v1.2.3-59-g8ed1b From a72042c08a8ba3b685dc9cba62c57c48188ef2c8 Mon Sep 17 00:00:00 2001 From: Chien Tung Date: Wed, 3 Mar 2010 19:13:26 +0000 Subject: RDMA/nes: Fix CX4 link problem in back-to-back configuration Commit 09124e19 ("RDMA/nes: Add support for KR device id 0x0110") took out too much code and broke CX4 link detection in back-to-back configuration. Put back the code that does the link check. Signed-off-by: Chien Tung Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_nic.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index a1d79b6856ac..91fdde382e82 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1595,7 +1595,6 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, struct nes_vnic *nesvnic; struct net_device *netdev; struct nic_qp_map *curr_qp_map; - u32 u32temp; u8 phy_type = nesdev->nesadapter->phy_type[nesdev->mac_index]; netdev = alloc_etherdev(sizeof(struct nes_vnic)); @@ -1707,6 +1706,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, ((phy_type == NES_PHY_TYPE_PUMA_1G) && (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { + u32 u32temp; + u32 link_mask; + u32 link_val; + u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1))); if (phy_type != NES_PHY_TYPE_PUMA_1G) { @@ -1715,13 +1718,36 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, (0x200 * (nesdev->mac_index & 1)), u32temp); } + /* Check and set linkup here. This is for back to back */ + /* configuration where second port won't get link interrupt */ + switch (phy_type) { + case NES_PHY_TYPE_PUMA_1G: + if (nesdev->mac_index < 2) { + link_mask = 0x01010000; + link_val = 0x01010000; + } else { + link_mask = 0x02020000; + link_val = 0x02020000; + } + break; + default: + link_mask = 0x0f1f0000; + link_val = 0x0f0f0000; + break; + } + + u32temp = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1))); + if ((u32temp & link_mask) == link_val) + nesvnic->linkup = 1; + /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp); nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp); nes_init_phy(nesdev); - } return netdev; -- cgit v1.2.3-59-g8ed1b From 21e3bde964e873bb5d3b1dfef68294b1437fe678 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Mar 2010 14:01:25 -0700 Subject: sysfs: fix sysfs lockdep warning in infiniband code This fixes a sysfs lockdep warning in the infiniband code. Cc: Yinghai Lu Cc: Eric Biederman Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/sysfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/infiniband') diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 1558bb7fc74d..f901957abc8b 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -461,6 +461,7 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *, element->attr.attr.mode = S_IRUGO; element->attr.show = show; element->index = i; + sysfs_attr_init(&element->attr.attr); tab_attr[i] = &element->attr.attr; } -- cgit v1.2.3-59-g8ed1b