Commit 34816ad9 authored by Sean Hefty's avatar Sean Hefty Committed by Roland Dreier

[IB] Fix MAD layer DMA mappings to avoid touching data buffer once mapped

The MAD layer was violating the DMA API by touching data buffers used
for sends after the DMA mapping was done.  This causes problems on
non-cache-coherent architectures, because the device doing DMA won't
see updates to the payload buffers that exist only in the CPU cache.

Fix this by having all MAD consumers use ib_create_send_mad() to
allocate their send buffers, and moving the DMA mapping into the MAD
layer so it can be done just before calling send (and after any
modifications of the send buffer by the MAD layer).

Tested on a non-cache-coherent PowerPC 440SPe system.
Signed-off-by: default avatarSean Hefty <sean.hefty@intel.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent ae7971a7
This diff is collapsed.
......@@ -39,17 +39,14 @@
#ifndef __AGENT_H_
#define __AGENT_H_
extern spinlock_t ib_agent_port_list_lock;
#include <rdma/ib_mad.h>
extern int ib_agent_port_open(struct ib_device *device,
int port_num);
extern int ib_agent_port_open(struct ib_device *device, int port_num);
extern int ib_agent_port_close(struct ib_device *device, int port_num);
extern int agent_send(struct ib_mad_private *mad,
struct ib_grh *grh,
struct ib_wc *wc,
struct ib_device *device,
int port_num);
extern int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
struct ib_wc *wc, struct ib_device *device,
int port_num, int qpn);
#endif /* __AGENT_H_ */
/*
* Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved.
* Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* $Id: agent_priv.h 1640 2005-01-24 22:39:02Z halr $
*/
#ifndef __IB_AGENT_PRIV_H__
#define __IB_AGENT_PRIV_H__
#include <linux/pci.h>
#define SPFX "ib_agent: "
struct ib_agent_send_wr {
struct list_head send_list;
struct ib_ah *ah;
struct ib_mad_private *mad;
DECLARE_PCI_UNMAP_ADDR(mapping)
};
struct ib_agent_port_private {
struct list_head port_list;
struct list_head send_posted_list;
spinlock_t send_list_lock;
int port_num;
struct ib_mad_agent *smp_agent; /* SM class */
struct ib_mad_agent *perf_mgmt_agent; /* PerfMgmt class */
};
#endif /* __IB_AGENT_PRIV_H__ */
This diff is collapsed.
This diff is collapsed.
......@@ -118,9 +118,10 @@ struct ib_mad_send_wr_private {
struct ib_mad_list_head mad_list;
struct list_head agent_list;
struct ib_mad_agent_private *mad_agent_priv;
struct ib_mad_send_buf send_buf;
DECLARE_PCI_UNMAP_ADDR(mapping)
struct ib_send_wr send_wr;
struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
u64 wr_id; /* client WR ID */
__be64 tid;
unsigned long timeout;
int retries;
......@@ -141,10 +142,7 @@ struct ib_mad_local_private {
struct list_head completion_list;
struct ib_mad_private *mad_priv;
struct ib_mad_agent_private *recv_mad_agent;
struct ib_send_wr send_wr;
struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
u64 wr_id; /* client WR ID */
__be64 tid;
struct ib_mad_send_wr_private *mad_send_wr;
};
struct ib_mad_mgmt_method_table {
......
......@@ -103,12 +103,12 @@ void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent)
static int data_offset(u8 mgmt_class)
{
if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
return offsetof(struct ib_sa_mad, data);
return IB_MGMT_SA_HDR;
else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
(mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
return offsetof(struct ib_vendor_mad, data);
return IB_MGMT_VENDOR_HDR;
else
return offsetof(struct ib_rmpp_mad, data);
return IB_MGMT_RMPP_HDR;
}
static void format_ack(struct ib_rmpp_mad *ack,
......@@ -135,21 +135,18 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv,
struct ib_mad_recv_wc *recv_wc)
{
struct ib_mad_send_buf *msg;
struct ib_send_wr *bad_send_wr;
int hdr_len, ret;
int ret;
hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr);
msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp,
recv_wc->wc->pkey_index, rmpp_recv->ah, 1,
hdr_len, sizeof(struct ib_rmpp_mad) - hdr_len,
GFP_KERNEL);
recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR,
IB_MGMT_RMPP_DATA, GFP_KERNEL);
if (!msg)
return;
format_ack((struct ib_rmpp_mad *) msg->mad,
(struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv);
ret = ib_post_send_mad(&rmpp_recv->agent->agent, &msg->send_wr,
&bad_send_wr);
format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad,
rmpp_recv);
msg->ah = rmpp_recv->ah;
ret = ib_post_send_mad(msg, NULL);
if (ret)
ib_free_send_mad(msg);
}
......@@ -160,30 +157,31 @@ static int alloc_response_msg(struct ib_mad_agent *agent,
{
struct ib_mad_send_buf *m;
struct ib_ah *ah;
int hdr_len;
ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc,
recv_wc->recv_buf.grh, agent->port_num);
if (IS_ERR(ah))
return PTR_ERR(ah);
hdr_len = sizeof(struct ib_mad_hdr) + sizeof(struct ib_rmpp_hdr);
m = ib_create_send_mad(agent, recv_wc->wc->src_qp,
recv_wc->wc->pkey_index, ah, 1, hdr_len,
sizeof(struct ib_rmpp_mad) - hdr_len,
GFP_KERNEL);
recv_wc->wc->pkey_index, 1,
IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA, GFP_KERNEL);
if (IS_ERR(m)) {
ib_destroy_ah(ah);
return PTR_ERR(m);
}
m->ah = ah;
*msg = m;
return 0;
}
static void free_msg(struct ib_mad_send_buf *msg)
void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)
{
ib_destroy_ah(msg->send_wr.wr.ud.ah);
ib_free_send_mad(msg);
struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad;
if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_ACK)
ib_destroy_ah(mad_send_wc->send_buf->ah);
ib_free_send_mad(mad_send_wc->send_buf);
}
static void nack_recv(struct ib_mad_agent_private *agent,
......@@ -191,14 +189,13 @@ static void nack_recv(struct ib_mad_agent_private *agent,
{
struct ib_mad_send_buf *msg;
struct ib_rmpp_mad *rmpp_mad;
struct ib_send_wr *bad_send_wr;
int ret;
ret = alloc_response_msg(&agent->agent, recv_wc, &msg);
if (ret)
return;
rmpp_mad = (struct ib_rmpp_mad *) msg->mad;
rmpp_mad = msg->mad;
memcpy(rmpp_mad, recv_wc->recv_buf.mad,
data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class));
......@@ -210,9 +207,11 @@ static void nack_recv(struct ib_mad_agent_private *agent,
rmpp_mad->rmpp_hdr.seg_num = 0;
rmpp_mad->rmpp_hdr.paylen_newwin = 0;
ret = ib_post_send_mad(&agent->agent, &msg->send_wr, &bad_send_wr);
if (ret)
free_msg(msg);
ret = ib_post_send_mad(msg, NULL);
if (ret) {
ib_destroy_ah(msg->ah);
ib_free_send_mad(msg);
}
}
static void recv_timeout_handler(void *data)
......@@ -585,7 +584,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
int timeout;
u32 paylen;
rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr;
rmpp_mad = mad_send_wr->send_buf.mad;
ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num);
......@@ -612,7 +611,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr)
}
/* 2 seconds for an ACK until we can find the packet lifetime */
timeout = mad_send_wr->send_wr.wr.ud.timeout_ms;
timeout = mad_send_wr->send_buf.timeout_ms;
if (!timeout || timeout > 2000)
mad_send_wr->timeout = msecs_to_jiffies(2000);
mad_send_wr->seg_num++;
......@@ -640,7 +639,7 @@ static void abort_send(struct ib_mad_agent_private *agent, __be64 tid,
wc.status = IB_WC_REM_ABORT_ERR;
wc.vendor_err = rmpp_status;
wc.wr_id = mad_send_wr->wr_id;
wc.send_buf = &mad_send_wr->send_buf;
ib_mad_complete_send_wr(mad_send_wr, &wc);
return;
out:
......@@ -694,12 +693,12 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
if (seg_num > mad_send_wr->last_ack) {
mad_send_wr->last_ack = seg_num;
mad_send_wr->retries = mad_send_wr->send_wr.wr.ud.retries;
mad_send_wr->retries = mad_send_wr->send_buf.retries;
}
mad_send_wr->newwin = newwin;
if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
/* If no response is expected, the ACK completes the send */
if (!mad_send_wr->send_wr.wr.ud.timeout_ms) {
if (!mad_send_wr->send_buf.timeout_ms) {
struct ib_mad_send_wc wc;
ib_mark_mad_done(mad_send_wr);
......@@ -707,13 +706,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
wc.status = IB_WC_SUCCESS;
wc.vendor_err = 0;
wc.wr_id = mad_send_wr->wr_id;
wc.send_buf = &mad_send_wr->send_buf;
ib_mad_complete_send_wr(mad_send_wr, &wc);
return;
}
if (mad_send_wr->refcount == 1)
ib_reset_mad_timeout(mad_send_wr, mad_send_wr->
send_wr.wr.ud.timeout_ms);
ib_reset_mad_timeout(mad_send_wr,
mad_send_wr->send_buf.timeout_ms);
} else if (mad_send_wr->refcount == 1 &&
mad_send_wr->seg_num < mad_send_wr->newwin &&
mad_send_wr->seg_num <= mad_send_wr->total_seg) {
......@@ -842,7 +841,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
struct ib_rmpp_mad *rmpp_mad;
int i, total_len, ret;
rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr;
rmpp_mad = mad_send_wr->send_buf.mad;
if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
IB_MGMT_RMPP_FLAG_ACTIVE))
return IB_RMPP_RESULT_UNHANDLED;
......@@ -863,7 +862,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) /
(sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset);
mad_send_wr->pad = total_len - offsetof(struct ib_rmpp_mad, data) -
mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR -
be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin);
/* We need to wait for the final ACK even if there isn't a response */
......@@ -878,23 +877,15 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
struct ib_mad_send_wc *mad_send_wc)
{
struct ib_rmpp_mad *rmpp_mad;
struct ib_mad_send_buf *msg;
int ret;
rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr;
rmpp_mad = mad_send_wr->send_buf.mad;
if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
IB_MGMT_RMPP_FLAG_ACTIVE))
return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) {
msg = (struct ib_mad_send_buf *) (unsigned long)
mad_send_wc->wr_id;
if (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_ACK)
ib_free_send_mad(msg);
else
free_msg(msg);
if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
return IB_RMPP_RESULT_INTERNAL; /* ACK, STOP, or ABORT */
}
if (mad_send_wc->status != IB_WC_SUCCESS ||
mad_send_wr->status != IB_WC_SUCCESS)
......@@ -905,7 +896,7 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
if (mad_send_wr->last_ack == mad_send_wr->total_seg) {
mad_send_wr->timeout =
msecs_to_jiffies(mad_send_wr->send_wr.wr.ud.timeout_ms);
msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
return IB_RMPP_RESULT_PROCESSED; /* Send done */
}
......@@ -926,7 +917,7 @@ int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr)
struct ib_rmpp_mad *rmpp_mad;
int ret;
rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr;
rmpp_mad = mad_send_wr->send_buf.mad;
if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
IB_MGMT_RMPP_FLAG_ACTIVE))
return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */
......
......@@ -51,6 +51,8 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent,
int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr,
struct ib_mad_send_wc *mad_send_wc);
void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc);
void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent);
int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr);
......
This diff is collapsed.
......@@ -39,6 +39,8 @@
#ifndef __SMI_H_
#define __SMI_H_
#include <rdma/ib_smi.h>
int smi_handle_dr_smp_recv(struct ib_smp *smp,
u8 node_type,
int port_num,
......
......@@ -96,7 +96,6 @@ struct ib_umad_file {
};
struct ib_umad_packet {
struct ib_ah *ah;
struct ib_mad_send_buf *msg;
struct list_head list;
int length;
......@@ -139,10 +138,10 @@ static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *send_wc)
{
struct ib_umad_file *file = agent->context;
struct ib_umad_packet *timeout, *packet =
(void *) (unsigned long) send_wc->wr_id;
struct ib_umad_packet *timeout;
struct ib_umad_packet *packet = send_wc->send_buf->context[0];
ib_destroy_ah(packet->msg->send_wr.wr.ud.ah);
ib_destroy_ah(packet->msg->ah);
ib_free_send_mad(packet->msg);
if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
......@@ -268,11 +267,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
struct ib_umad_packet *packet;
struct ib_mad_agent *agent;
struct ib_ah_attr ah_attr;
struct ib_send_wr *bad_wr;
struct ib_ah *ah;
struct ib_rmpp_mad *rmpp_mad;
u8 method;
__be64 *tid;
int ret, length, hdr_len, data_len, rmpp_hdr_size;
int ret, length, hdr_len, rmpp_hdr_size;
int rmpp_active = 0;
if (count < sizeof (struct ib_user_mad))
......@@ -321,9 +320,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class;
}
packet->ah = ib_create_ah(agent->qp->pd, &ah_attr);
if (IS_ERR(packet->ah)) {
ret = PTR_ERR(packet->ah);
ah = ib_create_ah(agent->qp->pd, &ah_attr);
if (IS_ERR(ah)) {
ret = PTR_ERR(ah);
goto err_up;
}
......@@ -337,12 +336,10 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
/* Validate that the management class can support RMPP */
if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
hdr_len = offsetof(struct ib_sa_mad, data);
data_len = length - hdr_len;
hdr_len = IB_MGMT_SA_HDR;
} else if ((rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
(rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) {
hdr_len = offsetof(struct ib_vendor_mad, data);
data_len = length - hdr_len;
hdr_len = IB_MGMT_VENDOR_HDR;
} else {
ret = -EINVAL;
goto err_ah;
......@@ -353,25 +350,23 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
ret = -EINVAL;
goto err_ah;
}
hdr_len = offsetof(struct ib_mad, data);
data_len = length - hdr_len;
hdr_len = IB_MGMT_MAD_HDR;
}
packet->msg = ib_create_send_mad(agent,
be32_to_cpu(packet->mad.hdr.qpn),
0, packet->ah, rmpp_active,
hdr_len, data_len,
0, rmpp_active,
hdr_len, length - hdr_len,
GFP_KERNEL);
if (IS_ERR(packet->msg)) {
ret = PTR_ERR(packet->msg);
goto err_ah;
}
packet->msg->send_wr.wr.ud.timeout_ms = packet->mad.hdr.timeout_ms;
packet->msg->send_wr.wr.ud.retries = packet->mad.hdr.retries;
/* Override send WR WRID initialized in ib_create_send_mad */
packet->msg->send_wr.wr_id = (unsigned long) packet;
packet->msg->ah = ah;
packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;
packet->msg->retries = packet->mad.hdr.retries;
packet->msg->context[0] = packet;
if (!rmpp_active) {
/* Copy message from user into send buffer */
......@@ -403,17 +398,17 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
* transaction ID matches the agent being used to send the
* MAD.
*/
method = packet->msg->mad->mad_hdr.method;
method = ((struct ib_mad_hdr *) packet->msg)->method;
if (!(method & IB_MGMT_METHOD_RESP) &&
method != IB_MGMT_METHOD_TRAP_REPRESS &&
method != IB_MGMT_METHOD_SEND) {
tid = &packet->msg->mad->mad_hdr.tid;
tid = &((struct ib_mad_hdr *) packet->msg)->tid;
*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
(be64_to_cpup(tid) & 0xffffffff));
}
ret = ib_post_send_mad(agent, &packet->msg->send_wr, &bad_wr);
ret = ib_post_send_mad(packet->msg, NULL);
if (ret)
goto err_msg;
......@@ -425,7 +420,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
ib_free_send_mad(packet->msg);
err_ah:
ib_destroy_ah(packet->ah);
ib_destroy_ah(ah);
err_up:
up_read(&file->agent_mutex);
......
......@@ -46,11 +46,6 @@ enum {
MTHCA_VENDOR_CLASS2 = 0xa
};
struct mthca_trap_mad {
struct ib_mad *mad;
DECLARE_PCI_UNMAP_ADDR(mapping)
};
static void update_sm_ah(struct mthca_dev *dev,
u8 port_num, u16 lid, u8 sl)
{
......@@ -116,49 +111,14 @@ static void forward_trap(struct mthca_dev *dev,
struct ib_mad *mad)
{
int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
struct mthca_trap_mad *tmad;
struct ib_sge gather_list;
struct ib_send_wr *bad_wr, wr = {
.opcode = IB_WR_SEND,
.sg_list = &gather_list,
.num_sge = 1,
.send_flags = IB_SEND_SIGNALED,
.wr = {
.ud = {
.remote_qpn = qpn,
.remote_qkey = qpn ? IB_QP1_QKEY : 0,
.timeout_ms = 0
}
}
};
struct ib_mad_send_buf *send_buf;
struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
int ret;
unsigned long flags;
if (agent) {
tmad = kmalloc(sizeof *tmad, GFP_KERNEL);
if (!tmad)
return;
tmad->mad = kmalloc(sizeof *tmad->mad, GFP_KERNEL);
if (!tmad->mad) {
kfree(tmad);
return;
}
memcpy(tmad->mad, mad, sizeof *mad);
wr.wr.ud.mad_hdr = &tmad->mad->mad_hdr;
wr.wr_id = (unsigned long) tmad;
gather_list.addr = dma_map_single(agent->device->dma_device,
tmad->mad,
sizeof *tmad->mad,
DMA_TO_DEVICE);
gather_list.length = sizeof *tmad->mad;
gather_list.lkey = to_mpd(agent->qp->pd)->ntmr.ibmr.lkey;
pci_unmap_addr_set(tmad, mapping, gather_list.addr);
send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
IB_MGMT_MAD_DATA, GFP_ATOMIC);
/*
* We rely here on the fact that MLX QPs don't use the
* address handle after the send is posted (this is
......@@ -166,21 +126,15 @@ static void forward_trap(struct mthca_dev *dev,
* it's OK for our devices).
*/
spin_lock_irqsave(&dev->sm_lock, flags);
wr.wr.ud.ah = dev->sm_ah[port_num - 1];
if (wr.wr.ud.ah)
ret = ib_post_send_mad(agent, &wr, &bad_wr);
memcpy(send_buf->mad, mad, sizeof *mad);
if ((send_buf->ah = dev->sm_ah[port_num - 1]))
ret = ib_post_send_mad(send_buf, NULL);
else
ret = -EINVAL;
spin_unlock_irqrestore(&dev->sm_lock, flags);
if (ret) {
dma_unmap_single(agent->device->dma_device,
pci_unmap_addr(tmad, mapping),
sizeof *tmad->mad,
DMA_TO_DEVICE);
kfree(tmad->mad);
kfree(tmad);
}
if (ret)
ib_free_send_mad(send_buf);
}
}
......@@ -267,15 +221,7 @@ int mthca_process_mad(struct ib_device *ibdev,
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *mad_send_wc)
{
struct mthca_trap_mad *tmad =
(void *) (unsigned long) mad_send_wc->wr_id;
dma_unmap_single(agent->device->dma_device,
pci_unmap_addr(tmad, mapping),
sizeof *tmad->mad,
DMA_TO_DEVICE);
kfree(tmad->mad);
kfree(tmad);
ib_free_send_mad(mad_send_wc->send_buf);
}
int mthca_create_agents(struct mthca_dev *dev)
......
......@@ -109,10 +109,14 @@
#define IB_QP_SET_QKEY 0x80000000
enum {
IB_MGMT_MAD_HDR = 24,
IB_MGMT_MAD_DATA = 232,
IB_MGMT_RMPP_HDR = 36,
IB_MGMT_RMPP_DATA = 220,
IB_MGMT_VENDOR_HDR = 40,
IB_MGMT_VENDOR_DATA = 216,
IB_MGMT_SA_DATA = 200
IB_MGMT_SA_HDR = 56,
IB_MGMT_SA_DATA = 200,
};
struct ib_mad_hdr {
......@@ -203,26 +207,25 @@ struct ib_class_port_info
/**
* ib_mad_send_buf - MAD data buffer and work request for sends.
* @mad: References an allocated MAD data buffer. The size of the data
* buffer is specified in the @send_wr.length field.
* @mapping: DMA mapping information.
* @next: A pointer used to chain together MADs for posting.
* @mad: References an allocated MAD data buffer.
* @mad_agent: MAD agent that allocated the buffer.
* @ah: The address handle to use when sending the MAD.
* @context: User-controlled context fields.
* @send_wr: An initialized work request structure used when sending the MAD.
* The wr_id field of the work request is initialized to reference this
* data structure.
* @sge: A scatter-gather list referenced by the work request.
* @timeout_ms: Time to wait for a response.
* @retries: Number of times to retry a request for a response.
*
* Users are responsible for initializing the MAD buffer itself, with the
* exception of specifying the payload length field in any RMPP MAD.
*/
struct ib_mad_send_buf {
struct ib_mad *mad;
DECLARE_PCI_UNMAP_ADDR(mapping)
struct ib_mad_send_buf *next;
void *mad;
struct ib_mad_agent *mad_agent;
struct ib_ah *ah;
void *context[2];
struct ib_send_wr send_wr;
struct ib_sge sge;
int timeout_ms;
int retries;
};
/**
......@@ -287,7 +290,7 @@ typedef void (*ib_mad_send_handler)(struct ib_mad_agent *mad_agent,
* or @mad_send_wc.
*/
typedef void (*ib_mad_snoop_handler)(struct ib_mad_agent *mad_agent,
struct ib_send_wr *send_wr,
struct ib_mad_send_buf *send_buf,
struct ib_mad_send_wc *mad_send_wc);
/**
......@@ -334,13 +337,13 @@ struct ib_mad_agent {
/**
* ib_mad_send_wc - MAD send completion information.
* @wr_id: Work request identifier associated with the send MAD request.
* @send_buf: Send MAD data buffer associated with the send MAD request.
* @status: Completion status.
* @vendor_err: Optional vendor error information returned with a failed
* request.
*/
struct ib_mad_send_wc {
u64 wr_id;
struct ib_mad_send_buf *send_buf;
enum ib_wc_status status;
u32 vendor_err;
};
......@@ -366,7 +369,7 @@ struct ib_mad_recv_buf {
* @rmpp_list: Specifies a list of RMPP reassembled received MAD buffers.
* @mad_len: The length of the received MAD, without duplicated headers.
*
* For received response, the wr_id field of the wc is set to the wr_id
* For received response, the wr_id contains a pointer to the ib_mad_send_buf
* for the corresponding send request.
*/
struct ib_mad_recv_wc {
......@@ -463,9 +466,9 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent);
/**
* ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated
* with the registered client.
* @mad_agent: Specifies the associated registration to post the send to.
* @send_wr: Specifies the information needed to send the MAD(s).
* @bad_send_wr: Specifies the MAD on which an error was encountered.
* @send_buf: Specifies the information needed to send the MAD(s).
* @bad_send_buf: Specifies the MAD on which an error was encountered. This
* parameter is optional if only a single MAD is posted.
*
* Sent MADs are not guaranteed to complete in the order that they were posted.
*
......@@ -479,9 +482,8 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent);
* defined data being transferred. The paylen_newwin field should be
* specified in network-byte order.
*/
int ib_post_send_mad(struct ib_mad_agent *mad_agent,
struct ib_send_wr *send_wr,
struct ib_send_wr **bad_send_wr);
int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
struct ib_mad_send_buf **bad_send_buf);
/**
* ib_coalesce_recv_mad - Coalesces received MAD data into a single buffer.
......@@ -507,23 +509,25 @@ void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc);
/**
* ib_cancel_mad - Cancels an outstanding send MAD operation.
* @mad_agent: Specifies the registration associated with sent MAD.
* @wr_id: Indicates the work request identifier of the MAD to cancel.
* @send_buf: Indicates the MAD to cancel.
*
* MADs will be returned to the user through the corresponding
* ib_mad_send_handler.
*/
void ib_cancel_mad(struct ib_mad_agent *mad_agent, u64 wr_id);
void ib_cancel_mad(struct ib_mad_agent *mad_agent,
struct ib_mad_send_buf *send_buf);
/**
* ib_modify_mad - Modifies an outstanding send MAD operation.
* @mad_agent: Specifies the registration associated with sent MAD.
* @wr_id: Indicates the work request identifier of the MAD to modify.
* @send_buf: Indicates the MAD to modify.
* @timeout_ms: New timeout value for sent MAD.
*
* This call will reset the timeout value for a sent MAD to the specified
* value.
*/
int ib_modify_mad(struct ib_mad_agent *mad_agent, u64 wr_id, u32 timeout_ms);
int ib_modify_mad(struct ib_mad_agent *mad_agent,
struct ib_mad_send_buf *send_buf, u32 timeout_ms);
/**
* ib_redirect_mad_qp - Registers a QP for MAD services.
......@@ -572,7 +576,6 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent,
* @remote_qpn: Specifies the QPN of the receiving node.
* @pkey_index: Specifies which PKey the MAD will be sent using. This field
* is valid only if the remote_qpn is QP 1.
* @ah: References the address handle used to transfer to the remote node.
* @rmpp_active: Indicates if the send will enable RMPP.
* @hdr_len: Indicates the size of the data header of the MAD. This length
* should include the common MAD header, RMPP header, plus any class
......@@ -582,11 +585,10 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent,
* additional padding that may be necessary.
* @gfp_mask: GFP mask used for the memory allocation.
*
* This is a helper routine that may be used to allocate a MAD. Users are
* not required to allocate outbound MADs using this call. The returned
* MAD send buffer will reference a data buffer usable for sending a MAD, along
* This routine allocates a MAD for sending. The returned MAD send buffer
* will reference a data buffer usable for sending a MAD, along
* with an initialized work request structure. Users may modify the returned
* MAD data buffer or work request before posting the send.
* MAD data buffer before posting the send.
*
* The returned data buffer will be cleared. Users are responsible for
* initializing the common MAD and any class specific headers. If @rmpp_active
......@@ -594,7 +596,7 @@ int ib_process_mad_wc(struct ib_mad_agent *mad_agent,
*/
struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent,
u32 remote_qpn, u16 pkey_index,
struct ib_ah *ah, int rmpp_active,
int rmpp_active,
int hdr_len, int data_len,
gfp_t gfp_mask);
......
......@@ -595,11 +595,8 @@ struct ib_send_wr {
} atomic;
struct {
struct ib_ah *ah;
struct ib_mad_hdr *mad_hdr;
u32 remote_qpn;
u32 remote_qkey;
int timeout_ms; /* valid for MADs only */
int retries; /* valid for MADs only */
u16 pkey_index; /* valid for GSI only */
u8 port_num; /* valid for DR SMPs on switch only */
} ud;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment