提交 cb183a06 编写于 作者: H Hal Rosenstock 提交者: Linus Torvalds

[PATCH] IB: Implementation for RMPP support in user MAD

Implementation for RMPP support in user MAD
Signed-off-by: NHal Rosenstock <halr@voltaire.com>
Cc: Roland Dreier <rolandd@cisco.com>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 3f75dadd
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. 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
......@@ -29,7 +31,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* $Id: user_mad.c 1389 2004-12-27 22:56:47Z roland $
* $Id: user_mad.c 2814 2005-07-06 19:14:09Z halr $
*/
#include <linux/module.h>
......@@ -94,10 +96,12 @@ struct ib_umad_file {
};
struct ib_umad_packet {
struct ib_user_mad mad;
struct ib_ah *ah;
struct ib_mad_send_buf *msg;
struct list_head list;
int length;
DECLARE_PCI_UNMAP_ADDR(mapping)
struct ib_user_mad mad;
};
static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE);
......@@ -114,10 +118,10 @@ static int queue_packet(struct ib_umad_file *file,
int ret = 1;
down_read(&file->agent_mutex);
for (packet->mad.id = 0;
packet->mad.id < IB_UMAD_MAX_AGENTS;
packet->mad.id++)
if (agent == file->agent[packet->mad.id]) {
for (packet->mad.hdr.id = 0;
packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
packet->mad.hdr.id++)
if (agent == file->agent[packet->mad.hdr.id]) {
spin_lock_irq(&file->recv_lock);
list_add_tail(&packet->list, &file->recv_list);
spin_unlock_irq(&file->recv_lock);
......@@ -135,22 +139,30 @@ 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 *packet =
struct ib_umad_packet *timeout, *packet =
(void *) (unsigned long) send_wc->wr_id;
dma_unmap_single(agent->device->dma_device,
pci_unmap_addr(packet, mapping),
sizeof packet->mad.data,
DMA_TO_DEVICE);
ib_destroy_ah(packet->ah);
ib_destroy_ah(packet->msg->send_wr.wr.ud.ah);
ib_free_send_mad(packet->msg);
if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
packet->mad.status = ETIMEDOUT;
timeout = kmalloc(sizeof *timeout + sizeof (struct ib_mad_hdr),
GFP_KERNEL);
if (!timeout)
goto out;
if (!queue_packet(file, agent, packet))
return;
}
memset(timeout, 0, sizeof *timeout + sizeof (struct ib_mad_hdr));
timeout->length = sizeof (struct ib_mad_hdr);
timeout->mad.hdr.id = packet->mad.hdr.id;
timeout->mad.hdr.status = ETIMEDOUT;
memcpy(timeout->mad.data, packet->mad.data,
sizeof (struct ib_mad_hdr));
if (!queue_packet(file, agent, timeout))
return;
}
out:
kfree(packet);
}
......@@ -159,30 +171,35 @@ static void recv_handler(struct ib_mad_agent *agent,
{
struct ib_umad_file *file = agent->context;
struct ib_umad_packet *packet;
int length;
if (mad_recv_wc->wc->status != IB_WC_SUCCESS)
goto out;
packet = kmalloc(sizeof *packet, GFP_KERNEL);
length = mad_recv_wc->mad_len;
packet = kmalloc(sizeof *packet + length, GFP_KERNEL);
if (!packet)
goto out;
memset(packet, 0, sizeof *packet);
memset(packet, 0, sizeof *packet + length);
packet->length = length;
ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data);
memcpy(packet->mad.data, mad_recv_wc->recv_buf.mad, sizeof packet->mad.data);
packet->mad.status = 0;
packet->mad.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
packet->mad.lid = cpu_to_be16(mad_recv_wc->wc->slid);
packet->mad.sl = mad_recv_wc->wc->sl;
packet->mad.path_bits = mad_recv_wc->wc->dlid_path_bits;
packet->mad.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
if (packet->mad.grh_present) {
packet->mad.hdr.status = 0;
packet->mad.hdr.length = length + sizeof (struct ib_user_mad);
packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
packet->mad.hdr.sl = mad_recv_wc->wc->sl;
packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
if (packet->mad.hdr.grh_present) {
/* XXX parse GRH */
packet->mad.gid_index = 0;
packet->mad.hop_limit = 0;
packet->mad.traffic_class = 0;
memset(packet->mad.gid, 0, 16);
packet->mad.flow_label = 0;
packet->mad.hdr.gid_index = 0;
packet->mad.hdr.hop_limit = 0;
packet->mad.hdr.traffic_class = 0;
memset(packet->mad.hdr.gid, 0, 16);
packet->mad.hdr.flow_label = 0;
}
if (queue_packet(file, agent, packet))
......@@ -199,7 +216,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
struct ib_umad_packet *packet;
ssize_t ret;
if (count < sizeof (struct ib_user_mad))
if (count < sizeof (struct ib_user_mad) + sizeof (struct ib_mad))
return -EINVAL;
spin_lock_irq(&file->recv_lock);
......@@ -222,12 +239,25 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
spin_unlock_irq(&file->recv_lock);
if (copy_to_user(buf, &packet->mad, sizeof packet->mad))
if (count < packet->length + sizeof (struct ib_user_mad)) {
/* Return length needed (and first RMPP segment) if too small */
if (copy_to_user(buf, &packet->mad,
sizeof (struct ib_user_mad) + sizeof (struct ib_mad)))
ret = -EFAULT;
else
ret = -ENOSPC;
} else if (copy_to_user(buf, &packet->mad,
packet->length + sizeof (struct ib_user_mad)))
ret = -EFAULT;
else
ret = sizeof packet->mad;
kfree(packet);
ret = packet->length + sizeof (struct ib_user_mad);
if (ret < 0) {
/* Requeue packet */
spin_lock_irq(&file->recv_lock);
list_add(&packet->list, &file->recv_list);
spin_unlock_irq(&file->recv_lock);
} else
kfree(packet);
return ret;
}
......@@ -238,69 +268,57 @@ 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_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,
};
struct ib_send_wr *bad_wr;
struct ib_rmpp_mad *rmpp_mad;
u8 method;
u64 *tid;
int ret;
int ret, length, hdr_len, data_len, rmpp_hdr_size;
int rmpp_active = 0;
if (count < sizeof (struct ib_user_mad))
return -EINVAL;
packet = kmalloc(sizeof *packet, GFP_KERNEL);
length = count - sizeof (struct ib_user_mad);
packet = kmalloc(sizeof *packet + sizeof(struct ib_mad_hdr) +
sizeof(struct ib_rmpp_hdr), GFP_KERNEL);
if (!packet)
return -ENOMEM;
if (copy_from_user(&packet->mad, buf, sizeof packet->mad)) {
kfree(packet);
return -EFAULT;
if (copy_from_user(&packet->mad, buf,
sizeof (struct ib_user_mad) +
sizeof(struct ib_mad_hdr) +
sizeof(struct ib_rmpp_hdr))) {
ret = -EFAULT;
goto err;
}
if (packet->mad.id < 0 || packet->mad.id >= IB_UMAD_MAX_AGENTS) {
if (packet->mad.hdr.id < 0 ||
packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
ret = -EINVAL;
goto err;
}
packet->length = length;
down_read(&file->agent_mutex);
agent = file->agent[packet->mad.id];
agent = file->agent[packet->mad.hdr.id];
if (!agent) {
ret = -EINVAL;
goto err_up;
}
/*
* If userspace is generating a request that will generate a
* response, we need to make sure the high-order part of the
* transaction ID matches the agent being used to send the
* MAD.
*/
method = ((struct ib_mad_hdr *) packet->mad.data)->method;
if (!(method & IB_MGMT_METHOD_RESP) &&
method != IB_MGMT_METHOD_TRAP_REPRESS &&
method != IB_MGMT_METHOD_SEND) {
tid = &((struct ib_mad_hdr *) packet->mad.data)->tid;
*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
(be64_to_cpup(tid) & 0xffffffff));
}
memset(&ah_attr, 0, sizeof ah_attr);
ah_attr.dlid = be16_to_cpu(packet->mad.lid);
ah_attr.sl = packet->mad.sl;
ah_attr.src_path_bits = packet->mad.path_bits;
ah_attr.dlid = be16_to_cpu(packet->mad.hdr.lid);
ah_attr.sl = packet->mad.hdr.sl;
ah_attr.src_path_bits = packet->mad.hdr.path_bits;
ah_attr.port_num = file->port->port_num;
if (packet->mad.grh_present) {
if (packet->mad.hdr.grh_present) {
ah_attr.ah_flags = IB_AH_GRH;
memcpy(ah_attr.grh.dgid.raw, packet->mad.gid, 16);
ah_attr.grh.flow_label = packet->mad.flow_label;
ah_attr.grh.hop_limit = packet->mad.hop_limit;
ah_attr.grh.traffic_class = packet->mad.traffic_class;
memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);
ah_attr.grh.flow_label = 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;
}
packet->ah = ib_create_ah(agent->qp->pd, &ah_attr);
......@@ -309,35 +327,104 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err_up;
}
gather_list.addr = dma_map_single(agent->device->dma_device,
packet->mad.data,
sizeof packet->mad.data,
DMA_TO_DEVICE);
gather_list.length = sizeof packet->mad.data;
gather_list.lkey = file->mr[packet->mad.id]->lkey;
pci_unmap_addr_set(packet, mapping, gather_list.addr);
rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
if (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE) {
/* RMPP active */
if (!agent->rmpp_version) {
ret = -EINVAL;
goto err_ah;
}
/* Validate that 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;
} 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;
} else {
ret = -EINVAL;
goto err_ah;
}
rmpp_active = 1;
} else {
if (length > sizeof(struct ib_mad)) {
ret = -EINVAL;
goto err_ah;
}
hdr_len = offsetof(struct ib_mad, data);
data_len = length - hdr_len;
}
packet->msg = ib_create_send_mad(agent,
be32_to_cpu(packet->mad.hdr.qpn),
0, packet->ah, rmpp_active,
hdr_len, data_len,
GFP_KERNEL);
if (IS_ERR(packet->msg)) {
ret = PTR_ERR(packet->msg);
goto err_ah;
}
wr.wr.ud.mad_hdr = (struct ib_mad_hdr *) packet->mad.data;
wr.wr.ud.ah = packet->ah;
wr.wr.ud.remote_qpn = be32_to_cpu(packet->mad.qpn);
wr.wr.ud.remote_qkey = be32_to_cpu(packet->mad.qkey);
wr.wr.ud.timeout_ms = packet->mad.timeout_ms;
wr.wr.ud.retries = 0;
packet->msg->send_wr.wr.ud.timeout_ms = packet->mad.hdr.timeout_ms;
packet->msg->send_wr.wr.ud.retries = packet->mad.hdr.retries;
wr.wr_id = (unsigned long) packet;
/* Override send WR WRID initialized in ib_create_send_mad */
packet->msg->send_wr.wr_id = (unsigned long) packet;
ret = ib_post_send_mad(agent, &wr, &bad_wr);
if (ret) {
dma_unmap_single(agent->device->dma_device,
pci_unmap_addr(packet, mapping),
sizeof packet->mad.data,
DMA_TO_DEVICE);
goto err_up;
if (!rmpp_active) {
/* Copy message from user into send buffer */
if (copy_from_user(packet->msg->mad,
buf + sizeof(struct ib_user_mad), length)) {
ret = -EFAULT;
goto err_msg;
}
} else {
rmpp_hdr_size = sizeof(struct ib_mad_hdr) +
sizeof(struct ib_rmpp_hdr);
/* Only copy MAD headers (RMPP header in place) */
memcpy(packet->msg->mad, packet->mad.data,
sizeof(struct ib_mad_hdr));
/* Now, copy rest of message from user into send buffer */
if (copy_from_user(((struct ib_rmpp_mad *) packet->msg->mad)->data,
buf + sizeof (struct ib_user_mad) + rmpp_hdr_size,
length - rmpp_hdr_size)) {
ret = -EFAULT;
goto err_msg;
}
}
/*
* If userspace is generating a request that will generate a
* response, we need to make sure the high-order part of the
* transaction ID matches the agent being used to send the
* MAD.
*/
method = packet->msg->mad->mad_hdr.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 = 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);
if (ret)
goto err_msg;
up_read(&file->agent_mutex);
return sizeof packet->mad;
return sizeof (struct ib_user_mad_hdr) + packet->length;
err_msg:
ib_free_send_mad(packet->msg);
err_ah:
ib_destroy_ah(packet->ah);
err_up:
up_read(&file->agent_mutex);
......@@ -400,7 +487,8 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,
ureq.mgmt_class ? &req : NULL,
0, send_handler, recv_handler, file);
ureq.rmpp_version,
send_handler, recv_handler, file);
if (IS_ERR(agent)) {
ret = PTR_ERR(agent);
goto out;
......@@ -461,8 +549,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg)
return ret;
}
static long ib_umad_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case IB_USER_MAD_REGISTER_AGENT:
......@@ -518,14 +606,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
}
static 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,
.compat_ioctl = ib_umad_ioctl,
.open = ib_umad_open,
.release = ib_umad_close
.compat_ioctl = ib_umad_ioctl,
.open = ib_umad_open,
.release = ib_umad_close
};
static int ib_umad_sm_open(struct inode *inode, struct file *filp)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部