X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finfiniband%2Fcore%2Fmad.c;fp=drivers%2Finfiniband%2Fcore%2Fmad.c;h=c82f47a66e48f8ee4d1f48bb80c9eec220bc37c8;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=1c3cfbbe6a97fcf3e7e5ce71060ad9b302a53833;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 1c3cfbbe6..c82f47a66 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -31,10 +31,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * - * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $ + * $Id: mad.c 2817 2005-07-07 11:29:26Z halr $ */ #include -#include #include "mad_priv.h" #include "mad_rmpp.h" @@ -46,7 +45,8 @@ MODULE_DESCRIPTION("kernel IB MAD API"); MODULE_AUTHOR("Hal Rosenstock"); MODULE_AUTHOR("Sean Hefty"); -static kmem_cache_t *ib_mad_cache; + +kmem_cache_t *ib_mad_cache; static struct list_head ib_mad_port_list; static u32 ib_mad_client_id = 0; @@ -167,15 +167,6 @@ static int is_vendor_method_in_use( return 0; } -int ib_response_mad(struct ib_mad *mad) -{ - return ((mad->mad_hdr.method & IB_MGMT_METHOD_RESP) || - (mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) || - ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_BM) && - (mad->mad_hdr.attr_mod & IB_BM_ATTR_MOD_RESP))); -} -EXPORT_SYMBOL(ib_response_mad); - /* * ib_register_mad_agent - Register to send/receive MADs */ @@ -236,11 +227,6 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, if (!is_vendor_oui(mad_reg_req->oui)) goto error1; } - /* Make sure class supplied is consistent with RMPP */ - if (!ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) { - if (rmpp_version) - goto error1; - } /* Make sure class supplied is consistent with QP type */ if (qp_type == IB_QPT_SMI) { if ((mad_reg_req->mgmt_class != @@ -361,7 +347,7 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, INIT_WORK(&mad_agent_priv->local_work, local_completions, mad_agent_priv); atomic_set(&mad_agent_priv->refcount, 1); - init_completion(&mad_agent_priv->comp); + init_waitqueue_head(&mad_agent_priv->wait); return &mad_agent_priv->agent; @@ -476,7 +462,7 @@ struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; mad_snoop_priv->agent.port_num = port_num; mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; - init_completion(&mad_snoop_priv->comp); + init_waitqueue_head(&mad_snoop_priv->wait); mad_snoop_priv->snoop_index = register_snoop_agent( &port_priv->qp_info[qpn], mad_snoop_priv); @@ -495,18 +481,6 @@ error1: } EXPORT_SYMBOL(ib_register_mad_snoop); -static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv) -{ - if (atomic_dec_and_test(&mad_agent_priv->refcount)) - complete(&mad_agent_priv->comp); -} - -static inline void deref_snoop_agent(struct ib_mad_snoop_private *mad_snoop_priv) -{ - if (atomic_dec_and_test(&mad_snoop_priv->refcount)) - complete(&mad_snoop_priv->comp); -} - static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) { struct ib_mad_port_private *port_priv; @@ -530,8 +504,9 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) flush_workqueue(port_priv->wq); ib_cancel_rmpp_recvs(mad_agent_priv); - deref_mad_agent(mad_agent_priv); - wait_for_completion(&mad_agent_priv->comp); + atomic_dec(&mad_agent_priv->refcount); + wait_event(mad_agent_priv->wait, + !atomic_read(&mad_agent_priv->refcount)); kfree(mad_agent_priv->reg_req); ib_dereg_mr(mad_agent_priv->agent.mr); @@ -549,8 +524,9 @@ static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) atomic_dec(&qp_info->snoop_count); spin_unlock_irqrestore(&qp_info->snoop_lock, flags); - deref_snoop_agent(mad_snoop_priv); - wait_for_completion(&mad_snoop_priv->comp); + atomic_dec(&mad_snoop_priv->refcount); + wait_event(mad_snoop_priv->wait, + !atomic_read(&mad_snoop_priv->refcount)); kfree(mad_snoop_priv); } @@ -579,6 +555,13 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent) } EXPORT_SYMBOL(ib_unregister_mad_agent); +static inline int response_mad(struct ib_mad *mad) +{ + /* Trap represses are responses although response bit is reset */ + return ((mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) || + (mad->mad_hdr.method & IB_MGMT_METHOD_RESP)); +} + static void dequeue_mad(struct ib_mad_list_head *mad_list) { struct ib_mad_queue *mad_queue; @@ -612,7 +595,8 @@ static void snoop_send(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, send_buf, mad_send_wc); - deref_snoop_agent(mad_snoop_priv); + if (atomic_dec_and_test(&mad_snoop_priv->refcount)) + wake_up(&mad_snoop_priv->wait); spin_lock_irqsave(&qp_info->snoop_lock, flags); } spin_unlock_irqrestore(&qp_info->snoop_lock, flags); @@ -637,7 +621,8 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, mad_recv_wc); - deref_snoop_agent(mad_snoop_priv); + if (atomic_dec_and_test(&mad_snoop_priv->refcount)) + wake_up(&mad_snoop_priv->wait); spin_lock_irqsave(&qp_info->snoop_lock, flags); } spin_unlock_irqrestore(&qp_info->snoop_lock, flags); @@ -694,8 +679,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, goto out; } /* Check to post send on QP or process locally */ - ret = smi_check_local_smp(smp, device); - if (!ret) + ret = smi_check_local_dr_smp(smp, device, port_num); + if (!ret || !device->process_mad) goto out; local = kmalloc(sizeof *local, GFP_ATOMIC); @@ -725,7 +710,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, switch (ret) { case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY: - if (ib_response_mad(&mad_priv->mad.mad) && + if (response_mad(&mad_priv->mad.mad) && mad_agent_priv->agent.recv_handler) { local->mad_priv = mad_priv; local->recv_mad_agent = mad_agent_priv; @@ -780,67 +765,18 @@ out: return ret; } -static int get_pad_size(int hdr_len, int data_len) +static int get_buf_length(int hdr_len, int data_len) { int seg_size, pad; seg_size = sizeof(struct ib_mad) - hdr_len; if (data_len && seg_size) { pad = seg_size - data_len % seg_size; - return pad == seg_size ? 0 : pad; + if (pad == seg_size) + pad = 0; } else - return seg_size; -} - -static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr) -{ - struct ib_rmpp_segment *s, *t; - - list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) { - list_del(&s->list); - kfree(s); - } -} - -static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr, - gfp_t gfp_mask) -{ - struct ib_mad_send_buf *send_buf = &send_wr->send_buf; - struct ib_rmpp_mad *rmpp_mad = send_buf->mad; - struct ib_rmpp_segment *seg = NULL; - int left, seg_size, pad; - - send_buf->seg_size = sizeof (struct ib_mad) - send_buf->hdr_len; - seg_size = send_buf->seg_size; - pad = send_wr->pad; - - /* Allocate data segments. */ - for (left = send_buf->data_len + pad; left > 0; left -= seg_size) { - seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask); - if (!seg) { - printk(KERN_ERR "alloc_send_rmpp_segs: RMPP mem " - "alloc failed for len %zd, gfp %#x\n", - sizeof (*seg) + seg_size, gfp_mask); - free_send_rmpp_list(send_wr); - return -ENOMEM; - } - seg->num = ++send_buf->seg_count; - list_add_tail(&seg->list, &send_wr->rmpp_list); - } - - /* Zero any padding */ - if (pad) - memset(seg->data + seg_size - pad, 0, pad); - - rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv-> - agent.rmpp_version; - rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; - ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); - - send_wr->cur_seg = container_of(send_wr->rmpp_list.next, - struct ib_rmpp_segment, list); - send_wr->last_ack_seg = send_wr->cur_seg; - return 0; + pad = seg_size; + return hdr_len + data_len + pad; } struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, @@ -851,40 +787,32 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, { struct ib_mad_agent_private *mad_agent_priv; struct ib_mad_send_wr_private *mad_send_wr; - int pad, message_size, ret, size; + int buf_size; void *buf; mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, agent); - pad = get_pad_size(hdr_len, data_len); - message_size = hdr_len + data_len + pad; + buf_size = get_buf_length(hdr_len, data_len); if ((!mad_agent->rmpp_version && - (rmpp_active || message_size > sizeof(struct ib_mad))) || - (!rmpp_active && message_size > sizeof(struct ib_mad))) + (rmpp_active || buf_size > sizeof(struct ib_mad))) || + (!rmpp_active && buf_size > sizeof(struct ib_mad))) return ERR_PTR(-EINVAL); - size = rmpp_active ? hdr_len : sizeof(struct ib_mad); - buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask); + buf = kzalloc(sizeof *mad_send_wr + buf_size, gfp_mask); if (!buf) return ERR_PTR(-ENOMEM); - mad_send_wr = buf + size; - INIT_LIST_HEAD(&mad_send_wr->rmpp_list); + mad_send_wr = buf + buf_size; mad_send_wr->send_buf.mad = buf; - mad_send_wr->send_buf.hdr_len = hdr_len; - mad_send_wr->send_buf.data_len = data_len; - mad_send_wr->pad = pad; mad_send_wr->mad_agent_priv = mad_agent_priv; - mad_send_wr->sg_list[0].length = hdr_len; + mad_send_wr->sg_list[0].length = buf_size; mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; - mad_send_wr->sg_list[1].length = sizeof(struct ib_mad) - hdr_len; - mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey; mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; - mad_send_wr->send_wr.num_sge = 2; + mad_send_wr->send_wr.num_sge = 1; mad_send_wr->send_wr.opcode = IB_WR_SEND; mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED; mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn; @@ -892,11 +820,13 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index; if (rmpp_active) { - ret = alloc_send_rmpp_list(mad_send_wr, gfp_mask); - if (ret) { - kfree(buf); - return ERR_PTR(ret); - } + struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad; + rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len - + IB_MGMT_RMPP_HDR + data_len); + rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version; + rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; + ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, + IB_MGMT_RMPP_FLAG_ACTIVE); } mad_send_wr->send_buf.mad_agent = mad_agent; @@ -905,80 +835,16 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, } EXPORT_SYMBOL(ib_create_send_mad); -int ib_get_mad_data_offset(u8 mgmt_class) -{ - if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) - return IB_MGMT_SA_HDR; - else if ((mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) || - (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) || - (mgmt_class == IB_MGMT_CLASS_BIS)) - return IB_MGMT_DEVICE_HDR; - else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && - (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) - return IB_MGMT_VENDOR_HDR; - else - return IB_MGMT_MAD_HDR; -} -EXPORT_SYMBOL(ib_get_mad_data_offset); - -int ib_is_mad_class_rmpp(u8 mgmt_class) -{ - if ((mgmt_class == IB_MGMT_CLASS_SUBN_ADM) || - (mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) || - (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) || - (mgmt_class == IB_MGMT_CLASS_BIS) || - ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && - (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))) - return 1; - return 0; -} -EXPORT_SYMBOL(ib_is_mad_class_rmpp); - -void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num) -{ - struct ib_mad_send_wr_private *mad_send_wr; - struct list_head *list; - - mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private, - send_buf); - list = &mad_send_wr->cur_seg->list; - - if (mad_send_wr->cur_seg->num < seg_num) { - list_for_each_entry(mad_send_wr->cur_seg, list, list) - if (mad_send_wr->cur_seg->num == seg_num) - break; - } else if (mad_send_wr->cur_seg->num > seg_num) { - list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list) - if (mad_send_wr->cur_seg->num == seg_num) - break; - } - return mad_send_wr->cur_seg->data; -} -EXPORT_SYMBOL(ib_get_rmpp_segment); - -static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr) -{ - if (mad_send_wr->send_buf.seg_count) - return ib_get_rmpp_segment(&mad_send_wr->send_buf, - mad_send_wr->seg_num); - else - return mad_send_wr->send_buf.mad + - mad_send_wr->send_buf.hdr_len; -} - void ib_free_send_mad(struct ib_mad_send_buf *send_buf) { struct ib_mad_agent_private *mad_agent_priv; - struct ib_mad_send_wr_private *mad_send_wr; mad_agent_priv = container_of(send_buf->mad_agent, struct ib_mad_agent_private, agent); - mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private, - send_buf); - - free_send_rmpp_list(mad_send_wr); kfree(send_buf->mad); - deref_mad_agent(mad_agent_priv); + + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + wake_up(&mad_agent_priv->wait); } EXPORT_SYMBOL(ib_free_send_mad); @@ -999,17 +865,10 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) mad_agent = mad_send_wr->send_buf.mad_agent; sge = mad_send_wr->sg_list; - sge[0].addr = dma_map_single(mad_agent->device->dma_device, - mad_send_wr->send_buf.mad, - sge[0].length, - DMA_TO_DEVICE); - pci_unmap_addr_set(mad_send_wr, header_mapping, sge[0].addr); - - sge[1].addr = dma_map_single(mad_agent->device->dma_device, - ib_get_payload(mad_send_wr), - sge[1].length, - DMA_TO_DEVICE); - pci_unmap_addr_set(mad_send_wr, payload_mapping, sge[1].addr); + sge->addr = dma_map_single(mad_agent->device->dma_device, + mad_send_wr->send_buf.mad, sge->length, + DMA_TO_DEVICE); + pci_unmap_addr_set(mad_send_wr, mapping, sge->addr); spin_lock_irqsave(&qp_info->send_queue.lock, flags); if (qp_info->send_queue.count < qp_info->send_queue.max_active) { @@ -1026,14 +885,11 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) list_add_tail(&mad_send_wr->mad_list.list, list); } spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); - if (ret) { - dma_unmap_single(mad_agent->device->dma_device, - pci_unmap_addr(mad_send_wr, header_mapping), - sge[0].length, DMA_TO_DEVICE); + if (ret) dma_unmap_single(mad_agent->device->dma_device, - pci_unmap_addr(mad_send_wr, payload_mapping), - sge[1].length, DMA_TO_DEVICE); - } + pci_unmap_addr(mad_send_wr, mapping), + sge->length, DMA_TO_DEVICE); + return ret; } @@ -1065,13 +921,6 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf, goto error; } - if (!ib_is_mad_class_rmpp(((struct ib_mad_hdr *) send_buf->mad)->mgmt_class)) { - if (mad_agent_priv->agent.rmpp_version) { - ret = -EINVAL; - goto error; - } - } - /* * Save pointer to next work request to post in case the * current one completes, and the user modifies the work @@ -1553,7 +1402,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv, unsigned long flags; spin_lock_irqsave(&port_priv->reg_lock, flags); - if (ib_response_mad(mad)) { + if (response_mad(mad)) { u32 hi_tid; struct ib_mad_agent_private *entry; @@ -1668,108 +1517,29 @@ static int is_data_mad(struct ib_mad_agent_private *mad_agent_priv, (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA); } -static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr, - struct ib_mad_recv_wc *rwc) -{ - return ((struct ib_mad *)(wr->send_buf.mad))->mad_hdr.mgmt_class == - rwc->recv_buf.mad->mad_hdr.mgmt_class; -} - -static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv, - struct ib_mad_send_wr_private *wr, - struct ib_mad_recv_wc *rwc ) -{ - struct ib_ah_attr attr; - u8 send_resp, rcv_resp; - union ib_gid sgid; - struct ib_device *device = mad_agent_priv->agent.device; - u8 port_num = mad_agent_priv->agent.port_num; - u8 lmc; - - send_resp = ((struct ib_mad *)(wr->send_buf.mad))-> - mad_hdr.method & IB_MGMT_METHOD_RESP; - rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP; - - if (send_resp == rcv_resp) - /* both requests, or both responses. GIDs different */ - return 0; - - if (ib_query_ah(wr->send_buf.ah, &attr)) - /* Assume not equal, to avoid false positives. */ - return 0; - - if (!!(attr.ah_flags & IB_AH_GRH) != - !!(rwc->wc->wc_flags & IB_WC_GRH)) - /* one has GID, other does not. Assume different */ - return 0; - - if (!send_resp && rcv_resp) { - /* is request/response. */ - if (!(attr.ah_flags & IB_AH_GRH)) { - if (ib_get_cached_lmc(device, port_num, &lmc)) - return 0; - return (!lmc || !((attr.src_path_bits ^ - rwc->wc->dlid_path_bits) & - ((1 << lmc) - 1))); - } else { - if (ib_get_cached_gid(device, port_num, - attr.grh.sgid_index, &sgid)) - return 0; - return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw, - 16); - } - } - - if (!(attr.ah_flags & IB_AH_GRH)) - return attr.dlid == rwc->wc->slid; - else - return !memcmp(attr.grh.dgid.raw, rwc->recv_buf.grh->sgid.raw, - 16); -} - -static inline int is_direct(u8 class) -{ - return (class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE); -} - struct ib_mad_send_wr_private* -ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, - struct ib_mad_recv_wc *wc) +ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) { - struct ib_mad_send_wr_private *wr; - struct ib_mad *mad; - - mad = (struct ib_mad *)wc->recv_buf.mad; + struct ib_mad_send_wr_private *mad_send_wr; - list_for_each_entry(wr, &mad_agent_priv->wait_list, agent_list) { - if ((wr->tid == mad->mad_hdr.tid) && - rcv_has_same_class(wr, wc) && - /* - * Don't check GID for direct routed MADs. - * These might have permissive LIDs. - */ - (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || - rcv_has_same_gid(mad_agent_priv, wr, wc))) - return wr; + list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, + agent_list) { + if (mad_send_wr->tid == tid) + return mad_send_wr; } /* * It's possible to receive the response before we've * been notified that the send has completed */ - list_for_each_entry(wr, &mad_agent_priv->send_list, agent_list) { - if (is_data_mad(mad_agent_priv, wr->send_buf.mad) && - wr->tid == mad->mad_hdr.tid && - wr->timeout && - rcv_has_same_class(wr, wc) && - /* - * Don't check GID for direct routed MADs. - * These might have permissive LIDs. - */ - (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || - rcv_has_same_gid(mad_agent_priv, wr, wc))) + list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, + agent_list) { + if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && + mad_send_wr->tid == tid && mad_send_wr->timeout) { /* Verify request has not been canceled */ - return (wr->status == IB_WC_SUCCESS) ? wr : NULL; + return (mad_send_wr->status == IB_WC_SUCCESS) ? + mad_send_wr : NULL; + } } return NULL; } @@ -1777,9 +1547,11 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) { mad_send_wr->timeout = 0; - if (mad_send_wr->refcount == 1) - list_move_tail(&mad_send_wr->agent_list, + if (mad_send_wr->refcount == 1) { + list_del(&mad_send_wr->agent_list); + list_add_tail(&mad_send_wr->agent_list, &mad_send_wr->mad_agent_priv->done_list); + } } static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, @@ -1788,6 +1560,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, struct ib_mad_send_wr_private *mad_send_wr; struct ib_mad_send_wc mad_send_wc; unsigned long flags; + __be64 tid; INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); @@ -1795,19 +1568,22 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, mad_recv_wc); if (!mad_recv_wc) { - deref_mad_agent(mad_agent_priv); + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + wake_up(&mad_agent_priv->wait); return; } } /* Complete corresponding request */ - if (ib_response_mad(mad_recv_wc->recv_buf.mad)) { + if (response_mad(mad_recv_wc->recv_buf.mad)) { + tid = mad_recv_wc->recv_buf.mad->mad_hdr.tid; spin_lock_irqsave(&mad_agent_priv->lock, flags); - mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); + mad_send_wr = ib_find_send_mad(mad_agent_priv, tid); if (!mad_send_wr) { spin_unlock_irqrestore(&mad_agent_priv->lock, flags); ib_free_recv_mad(mad_recv_wc); - deref_mad_agent(mad_agent_priv); + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + wake_up(&mad_agent_priv->wait); return; } ib_mark_mad_done(mad_send_wr); @@ -1826,7 +1602,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, } else { mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, mad_recv_wc); - deref_mad_agent(mad_agent_priv); + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + wake_up(&mad_agent_priv->wait); } } @@ -1884,7 +1661,9 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, port_priv->device->node_type, port_priv->port_num)) goto out; - if (!smi_check_local_smp(&recv->mad.smp, port_priv->device)) + if (!smi_check_local_dr_smp(&recv->mad.smp, + port_priv->device, + port_priv->port_num)) goto out; } @@ -2056,7 +1835,8 @@ void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, mad_send_wc); /* Release reference on agent taken when sending */ - deref_mad_agent(mad_agent_priv); + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + wake_up(&mad_agent_priv->wait); return; done: spin_unlock_irqrestore(&mad_agent_priv->lock, flags); @@ -2082,11 +1862,8 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, retry: dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, - pci_unmap_addr(mad_send_wr, header_mapping), + pci_unmap_addr(mad_send_wr, mapping), mad_send_wr->sg_list[0].length, DMA_TO_DEVICE); - dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, - pci_unmap_addr(mad_send_wr, payload_mapping), - mad_send_wr->sg_list[1].length, DMA_TO_DEVICE); queued_send_wr = NULL; spin_lock_irqsave(&send_queue->lock, flags); list_del(&mad_list->list); @@ -2098,7 +1875,8 @@ retry: queued_send_wr = container_of(mad_list, struct ib_mad_send_wr_private, mad_list); - list_move_tail(&mad_list->list, &send_queue->list); + list_del(&mad_list->list); + list_add_tail(&mad_list->list, &send_queue->list); } spin_unlock_irqrestore(&send_queue->lock, flags); @@ -2341,7 +2119,6 @@ static void local_completions(void *data) local = list_entry(mad_agent_priv->local_list.next, struct ib_mad_local_private, completion_list); - list_del(&local->completion_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); if (local->mad_priv) { recv_mad_agent = local->recv_mad_agent; @@ -2393,6 +2170,7 @@ local_send_completion: &mad_send_wc); spin_lock_irqsave(&mad_agent_priv->lock, flags); + list_del(&local->completion_list); atomic_dec(&mad_agent_priv->refcount); if (!recv) kmem_cache_free(ib_mad_cache, local->mad_priv); @@ -2484,12 +2262,8 @@ static void timeout_sends(void *data) static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg) { struct ib_mad_port_private *port_priv = cq->cq_context; - unsigned long flags; - spin_lock_irqsave(&ib_mad_port_list_lock, flags); - if (!list_empty(&port_priv->port_list)) - queue_work(port_priv->wq, &port_priv->work); - spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + queue_work(port_priv->wq, &port_priv->work); } /* @@ -2528,11 +2302,11 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, } } sg_list.addr = dma_map_single(qp_info->port_priv-> - device->dma_device, - &mad_priv->grh, - sizeof *mad_priv - - sizeof mad_priv->header, - DMA_FROM_DEVICE); + device->dma_device, + &mad_priv->grh, + sizeof *mad_priv - + sizeof mad_priv->header, + DMA_FROM_DEVICE); pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr); recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list; mad_priv->header.mad_list.mad_queue = recv_queue; @@ -2801,23 +2575,18 @@ static int ib_mad_port_open(struct ib_device *device, } INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv); - spin_lock_irqsave(&ib_mad_port_list_lock, flags); - list_add_tail(&port_priv->port_list, &ib_mad_port_list); - spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); - ret = ib_mad_port_start(port_priv); if (ret) { printk(KERN_ERR PFX "Couldn't start port\n"); goto error9; } - return 0; - -error9: spin_lock_irqsave(&ib_mad_port_list_lock, flags); - list_del_init(&port_priv->port_list); + list_add_tail(&port_priv->port_list, &ib_mad_port_list); spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + return 0; +error9: destroy_workqueue(port_priv->wq); error8: destroy_mad_qp(&port_priv->qp_info[1]); @@ -2854,9 +2623,11 @@ static int ib_mad_port_close(struct ib_device *device, int port_num) printk(KERN_ERR PFX "Port %d not found\n", port_num); return -ENODEV; } - list_del_init(&port_priv->port_list); + list_del(&port_priv->port_list); spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + /* Stop processing completions. */ + flush_workqueue(port_priv->wq); destroy_workqueue(port_priv->wq); destroy_mad_qp(&port_priv->qp_info[1]); destroy_mad_qp(&port_priv->qp_info[0]);