[openib-general] [PATCH v2 5/11] Implementation of Data path of the communication protocol
Ramachandra K
ramachandra.kuchimanchi at qlogic.com
Tue Nov 14 06:56:31 PST 2006
Adds the files that implement the data transfer part of the
communication protocol with the VEx. The RDMA of ethernet
packets is implemented in here.
Signed-off-by: Ramachandra K <ramachandra.kuchimanchi at qlogic.com>
---
drivers/infiniband/ulp/vnic/vnic_data.c | 1114 ++++++++++++++++++++++++++++
drivers/infiniband/ulp/vnic/vnic_data.h | 182 +++++
drivers/infiniband/ulp/vnic/vnic_trailer.h | 103 +++
3 files changed, 1399 insertions(+), 0 deletions(-)
diff --git a/drivers/infiniband/ulp/vnic/vnic_data.c b/drivers/infiniband/ulp/vnic/vnic_data.c
new file mode 100644
index 0000000..2579697
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_data.c
@@ -0,0 +1,1114 @@
+/*
+ * Copyright (c) 2006 QLogic, 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
+ * 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.
+ */
+
+#include <net/inet_sock.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+
+#include "vnic_util.h"
+#include "vnic_viport.h"
+#include "vnic_main.h"
+#include "vnic_config.h"
+#include "vnic_data.h"
+#include "vnic_trailer.h"
+#include "vnic_stats.h"
+
+static void data_received_kick(struct io *io);
+static void data_xmit_complete(struct io *io);
+
+u32 min_rcv_skb = 60;
+module_param(min_rcv_skb, int, 0444);
+MODULE_PARM_DESC(min_rcv_skb, "Packets of size (in bytes) less than"
+ " or equal this value will be copied during receive."
+ " Default 60");
+
+u32 min_xmt_skb = 60;
+module_param(min_xmt_skb, int, 0444);
+MODULE_PARM_DESC(min_xmit_skb, "Packets of size (in bytes) less than"
+ " or equal to this value will be copied during transmit."
+ "Default 60");
+
+int data_init(struct data * data, struct viport * viport,
+ struct data_config * config, struct ib_pd *pd)
+{
+ DATA_FUNCTION("data_init()\n");
+
+ data->parent = viport;
+ data->config = config;
+ data->ib_conn.viport = viport;
+ data->ib_conn.ib_config = &config->ib_config;
+ data->ib_conn.state = IB_CONN_UNINITTED;
+
+ if ((min_xmt_skb < 60) || (min_xmt_skb > 9000)) {
+ DATA_ERROR("min_xmt_skb (%d) must be between 60 and 9000\n",
+ min_xmt_skb);
+ goto failure;
+ }
+ if (vnic_ib_conn_init(&data->ib_conn, viport, pd,
+ &config->ib_config)) {
+ DATA_ERROR("Data IB connection initialization failed\n");
+ goto failure;
+ }
+ data->mr = ib_get_dma_mr(pd,
+ IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_READ |
+ IB_ACCESS_REMOTE_WRITE);
+ if (IS_ERR(data->mr)) {
+ DATA_ERROR("failed to register memory for"
+ " data connection\n");
+ goto destroy_conn;
+ }
+
+ data->ib_conn.cm_id = ib_create_cm_id(viport->config->ibdev,
+ vnic_ib_cm_handler,
+ &data->ib_conn);
+
+ if (IS_ERR(data->ib_conn.cm_id)) {
+ DATA_ERROR("creating data CM ID failed\n");
+ goto destroy_conn;
+ }
+
+ return 0;
+
+destroy_conn:
+ ib_destroy_qp(data->ib_conn.qp);
+ ib_destroy_cq(data->ib_conn.cq);
+failure:
+ return -1;
+}
+
+static void data_post_recvs(struct data *data)
+{
+ unsigned long flags;
+
+ DATA_FUNCTION("data_post_recvs()\n");
+ spin_lock_irqsave(&data->recv_ios_lock, flags);
+ while (!list_empty(&data->recv_ios)) {
+ struct io *io = list_entry(data->recv_ios.next,
+ struct io, list_ptrs);
+ struct recv_io *recv_io = (struct recv_io *)io;
+
+ list_del(&recv_io->io.list_ptrs);
+ spin_unlock_irqrestore(&data->recv_ios_lock, flags);
+ if (vnic_ib_post_recv(&data->ib_conn, &recv_io->io)) {
+ viport_failure(data->parent);
+ return;
+ }
+ spin_lock_irqsave(&data->recv_ios_lock, flags);
+ }
+ spin_unlock_irqrestore(&data->recv_ios_lock, flags);
+}
+
+static void data_init_pool_work_reqs(struct data * data,
+ struct recv_io * recv_io)
+{
+ struct recv_pool *recv_pool = &data->recv_pool;
+ struct xmit_pool *xmit_pool = &data->xmit_pool;
+ struct rdma_io *rdma_io;
+ struct rdma_dest *rdma_dest;
+ dma_addr_t xmit_dma;
+ u8 *xmit_data;
+ unsigned int i;
+
+ INIT_LIST_HEAD(&data->recv_ios);
+ spin_lock_init(&data->recv_ios_lock);
+ spin_lock_init(&data->xmit_buf_lock);
+ for (i = 0; i < data->config->num_recvs; i++) {
+ recv_io[i].io.viport = data->parent;
+ recv_io[i].io.routine = data_received_kick;
+ recv_io[i].list.addr = data->region_data_dma;
+ recv_io[i].list.length = 4;
+ recv_io[i].list.lkey = data->mr->lkey;
+
+ recv_io[i].io.rwr.wr_id = (u64)&recv_io[i].io;
+ recv_io[i].io.rwr.sg_list = &recv_io[i].list;
+ recv_io[i].io.rwr.num_sge = 1;
+
+ list_add(&recv_io[i].io.list_ptrs, &data->recv_ios);
+ }
+
+ INIT_LIST_HEAD(&recv_pool->avail_recv_bufs);
+ for (i = 0; i < recv_pool->pool_sz; i++) {
+ rdma_dest = &recv_pool->recv_bufs[i];
+ list_add(&rdma_dest->list_ptrs,
+ &recv_pool->avail_recv_bufs);
+ }
+
+ xmit_dma = xmit_pool->xmitdata_dma;
+ xmit_data = xmit_pool->xmit_data;
+
+ for (i = 0; i < xmit_pool->num_xmit_bufs; i++) {
+ rdma_io = &xmit_pool->xmit_bufs[i];
+ rdma_io->index = i;
+ rdma_io->io.viport = data->parent;
+ rdma_io->io.routine = data_xmit_complete;
+
+ rdma_io->list[0].lkey = data->mr->lkey;
+ rdma_io->list[1].lkey = data->mr->lkey;
+ rdma_io->io.swr.wr_id = (u64)rdma_io;
+ rdma_io->io.swr.sg_list = rdma_io->list;
+ rdma_io->io.swr.num_sge = 2;
+ rdma_io->io.swr.opcode = IB_WR_RDMA_WRITE;
+ rdma_io->io.swr.send_flags = IB_SEND_SIGNALED;
+ rdma_io->io.type = RDMA;
+
+ rdma_io->data = xmit_data;
+ rdma_io->data_dma = xmit_dma;
+
+ xmit_data += ALIGN(min_xmt_skb, VIPORT_TRAILER_ALIGNMENT);
+ xmit_dma += ALIGN(min_xmt_skb, VIPORT_TRAILER_ALIGNMENT);
+ rdma_io->trailer = (struct viport_trailer *)xmit_data;
+ rdma_io->trailer_dma = xmit_dma;
+ xmit_data += sizeof(struct viport_trailer);
+ xmit_dma += sizeof(struct viport_trailer);
+ }
+
+ xmit_pool->rdma_rkey = data->mr->rkey;
+ xmit_pool->rdma_addr = xmit_pool->buf_pool_dma;
+}
+
+static void data_init_free_bufs_swrs(struct data * data)
+{
+ struct rdma_io *rdma_io;
+ struct send_io *send_io;
+
+ rdma_io = &data->free_bufs_io;
+ rdma_io->io.viport = data->parent;
+ rdma_io->io.routine = NULL;
+
+ rdma_io->list[0].lkey = data->mr->lkey;
+
+ rdma_io->io.swr.wr_id = (u64)rdma_io;
+ rdma_io->io.swr.sg_list = rdma_io->list;
+ rdma_io->io.swr.num_sge = 1;
+ rdma_io->io.swr.opcode = IB_WR_RDMA_WRITE;
+ rdma_io->io.swr.send_flags = IB_SEND_SIGNALED;
+ rdma_io->io.type = RDMA;
+
+ send_io = &data->kick_io;
+ send_io->io.viport = data->parent;
+ send_io->io.routine = NULL;
+
+ send_io->list.addr = data->region_data_dma;
+ send_io->list.length = 0;
+ send_io->list.lkey = data->mr->lkey;
+
+ send_io->io.swr.wr_id = (u64)send_io;
+ send_io->io.swr.sg_list = &send_io->list;
+ send_io->io.swr.num_sge = 1;
+ send_io->io.swr.opcode = IB_WR_SEND;
+ send_io->io.swr.send_flags = IB_SEND_SIGNALED;
+ send_io->io.type = SEND;
+}
+
+static int data_init_buf_pools(struct data * data)
+{
+ struct recv_pool *recv_pool = &data->recv_pool;
+ struct xmit_pool *xmit_pool = &data->xmit_pool;
+ struct viport *viport = data->parent;
+
+ recv_pool->buf_pool_len =
+ sizeof(struct buff_pool_entry) * recv_pool->eioc_pool_sz;
+
+ recv_pool->buf_pool = kzalloc(recv_pool->buf_pool_len, GFP_KERNEL);
+
+ if (!recv_pool->buf_pool) {
+ DATA_ERROR("failed allocating %d bytes"
+ " for recv pool bufpool\n",
+ recv_pool->buf_pool_len);
+ goto failure;
+ }
+
+ recv_pool->buf_pool_dma =
+ dma_map_single(viport->config->ibdev->dma_device,
+ recv_pool->buf_pool, recv_pool->buf_pool_len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(recv_pool->buf_pool_dma)) {
+ DATA_ERROR("xmit buf_pool dma map error\n");
+ goto free_recv_pool;
+ }
+
+ xmit_pool->buf_pool_len =
+ sizeof(struct buff_pool_entry) * xmit_pool->pool_sz;
+ xmit_pool->buf_pool = kzalloc(xmit_pool->buf_pool_len, GFP_KERNEL);
+
+ if (!xmit_pool->buf_pool) {
+ DATA_ERROR("failed allocating %d bytes"
+ " for xmit pool bufpool\n",
+ xmit_pool->buf_pool_len);
+ goto unmap_recv_pool;
+ }
+
+ xmit_pool->buf_pool_dma =
+ dma_map_single(viport->config->ibdev->dma_device,
+ xmit_pool->buf_pool, xmit_pool->buf_pool_len,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(xmit_pool->buf_pool_dma)) {
+ DATA_ERROR("xmit buf_pool dma map error\n");
+ goto free_xmit_pool;
+ }
+
+ xmit_pool->xmit_data = kzalloc(xmit_pool->xmitdata_len, GFP_KERNEL);
+
+ if (!xmit_pool->xmit_data) {
+ DATA_ERROR("failed allocating %d bytes for xmit data\n",
+ xmit_pool->xmitdata_len);
+ goto unmap_xmit_pool;
+ }
+
+ xmit_pool->xmitdata_dma =
+ dma_map_single(viport->config->ibdev->dma_device,
+ xmit_pool->xmit_data, xmit_pool->xmitdata_len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(xmit_pool->xmitdata_dma)) {
+ DATA_ERROR("xmit data dma map error\n");
+ goto free_xmit_data;
+ }
+
+ return 0;
+
+free_xmit_data:
+ kfree(xmit_pool->xmit_data);
+unmap_xmit_pool:
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ xmit_pool->buf_pool_dma,
+ xmit_pool->buf_pool_len, DMA_FROM_DEVICE);
+free_xmit_pool:
+ kfree(xmit_pool->buf_pool);
+unmap_recv_pool:
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ recv_pool->buf_pool_dma,
+ recv_pool->buf_pool_len, DMA_TO_DEVICE);
+free_recv_pool:
+ kfree(recv_pool->buf_pool);
+failure:
+ return -1;
+}
+
+static void data_init_xmit_pool(struct data * data)
+{
+ struct xmit_pool *xmit_pool = &data->xmit_pool;
+
+ xmit_pool->pool_sz =
+ be32_to_cpu(data->eioc_pool_parms.num_recv_pool_entries);
+ xmit_pool->buffer_sz =
+ be32_to_cpu(data->eioc_pool_parms.size_recv_pool_entry);
+
+ xmit_pool->notify_count = 0;
+ xmit_pool->notify_bundle = data->config->notify_bundle;
+ xmit_pool->next_xmit_pool = 0;
+ xmit_pool->num_xmit_bufs = xmit_pool->notify_bundle * 2;
+ xmit_pool->next_xmit_buf = 0;
+ xmit_pool->last_comp_buf = xmit_pool->num_xmit_bufs - 1;
+
+ xmit_pool->kick_count = 0;
+ xmit_pool->kick_byte_count = 0;
+
+ xmit_pool->send_kicks =
+ be32_to_cpu(data->
+ eioc_pool_parms.num_recv_pool_entries_before_kick)
+ || be32_to_cpu(data->
+ eioc_pool_parms.num_recv_pool_bytes_before_kick);
+ xmit_pool->kick_bundle =
+ be32_to_cpu(data->
+ eioc_pool_parms.num_recv_pool_entries_before_kick);
+ xmit_pool->kick_byte_bundle =
+ be32_to_cpu(data->
+ eioc_pool_parms.num_recv_pool_bytes_before_kick);
+
+ xmit_pool->need_buffers = 1;
+
+ xmit_pool->xmitdata_len =
+ BUFFER_SIZE(min_xmt_skb) * xmit_pool->num_xmit_bufs;
+}
+
+static void data_init_recv_pool(struct data * data)
+{
+ struct recv_pool *recv_pool = &data->recv_pool;
+
+ recv_pool->pool_sz = data->config->host_recv_pool_entries;
+ recv_pool->eioc_pool_sz =
+ be32_to_cpu(data->host_pool_parms.num_recv_pool_entries);
+ if (recv_pool->pool_sz > recv_pool->eioc_pool_sz)
+ recv_pool->pool_sz =
+ be32_to_cpu(data->host_pool_parms.num_recv_pool_entries);
+
+ recv_pool->buffer_sz =
+ be32_to_cpu(data->host_pool_parms.size_recv_pool_entry);
+
+ recv_pool->sz_free_bundle =
+ be32_to_cpu(data->
+ host_pool_parms.free_recv_pool_entries_per_update);
+ recv_pool->num_free_bufs = 0;
+ recv_pool->num_posted_bufs = 0;
+
+ recv_pool->next_full_buf = 0;
+ recv_pool->next_free_buf = 0;
+ recv_pool->kick_on_free = 0;
+}
+
+int data_connect(struct data * data)
+{
+ struct xmit_pool *xmit_pool = &data->xmit_pool;
+ struct recv_pool *recv_pool = &data->recv_pool;
+ struct recv_io * recv_io;
+ unsigned int sz;
+ struct viport *viport = data->parent;
+
+ DATA_FUNCTION("data_connect()\n");
+
+ data_init_recv_pool(data);
+ data_init_xmit_pool(data);
+
+ sz = sizeof(struct rdma_dest) * recv_pool->pool_sz +
+ sizeof(struct recv_io) * data->config->num_recvs +
+ sizeof(struct rdma_io) * xmit_pool->num_xmit_bufs;
+
+ data->local_storage = vmalloc(sz);
+
+ if (!data->local_storage) {
+ DATA_ERROR("failed allocating %d bytes"
+ " local storage\n", sz);
+ goto out;
+ }
+
+ memset(data->local_storage, 0, sz);
+
+ recv_pool->recv_bufs = (struct rdma_dest *)data->local_storage;
+ sz = sizeof(struct rdma_dest) * recv_pool->pool_sz;
+
+ recv_io = (struct recv_io *)(data->local_storage + sz);
+ sz += sizeof(struct recv_io) * data->config->num_recvs;
+
+ xmit_pool->xmit_bufs = (struct rdma_io *)(data->local_storage + sz);
+ data->region_data = kzalloc(4, GFP_KERNEL);
+
+ if (!data->region_data) {
+ DATA_ERROR("failed to alloc memory for region data\n");
+ goto free_local_storage;
+ }
+
+ data->region_data_dma =
+ dma_map_single(viport->config->ibdev->dma_device,
+ data->region_data, 4, DMA_BIDIRECTIONAL);
+
+ if (dma_mapping_error(data->region_data_dma)) {
+ DATA_ERROR("region data dma map error\n");
+ goto free_region_data;
+ }
+
+ if (data_init_buf_pools(data))
+ goto unmap_region_data;
+
+ data_init_free_bufs_swrs(data);
+ data_init_pool_work_reqs(data, recv_io);
+
+ data_post_recvs(data);
+
+ if (vnic_ib_cm_connect(&data->ib_conn))
+ goto unmap_region_data;
+
+ return 0;
+
+unmap_region_data:
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ data->region_data_dma, 4, DMA_BIDIRECTIONAL);
+free_region_data:
+ kfree(data->region_data);
+free_local_storage:
+ vfree(data->local_storage);
+out:
+ return -1;
+}
+
+static void data_add_free_buffer(struct data *data, int index,
+ struct rdma_dest *rdma_dest)
+{
+ struct recv_pool *pool = &data->recv_pool;
+ struct buff_pool_entry *bpe;
+
+ DATA_FUNCTION("data_add_free_buffer()\n");
+ rdma_dest->trailer->connection_hash_and_valid = 0;
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ pool->buf_pool_dma, pool->buf_pool_len,
+ DMA_TO_DEVICE);
+
+ bpe = &pool->buf_pool[index];
+ bpe->rkey = cpu_to_be32(data->mr->rkey);
+
+ bpe->remote_addr = cpu_to_be64((unsigned long long)
+ virt_to_phys(rdma_dest->data));
+ bpe->valid = (u32) (rdma_dest - &pool->recv_bufs[0]) + 1;
+ ++pool->num_free_bufs;
+
+ dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+ pool->buf_pool_dma, pool->buf_pool_len,
+ DMA_TO_DEVICE);
+}
+
+/* NOTE: this routine is not reentrant */
+static void data_alloc_buffers(struct data *data, int initial_allocation)
+{
+ struct recv_pool *pool = &data->recv_pool;
+ struct rdma_dest *rdma_dest;
+ struct sk_buff *skb;
+ int index;
+
+ DATA_FUNCTION("data_alloc_buffers()\n");
+ index = ADD(pool->next_free_buf, pool->num_free_bufs,
+ pool->eioc_pool_sz);
+
+ while (!list_empty(&pool->avail_recv_bufs)) {
+ rdma_dest =
+ list_entry(pool->avail_recv_bufs.next,
+ struct rdma_dest, list_ptrs);
+ if (!rdma_dest->skb) {
+ if (initial_allocation)
+ skb = alloc_skb(pool->buffer_sz + 2,
+ GFP_KERNEL);
+ else
+ skb = dev_alloc_skb(pool->buffer_sz + 2);
+ if (!skb) {
+ DATA_ERROR("failed to alloc skb\n");
+ break;
+ }
+ skb_reserve(skb, 2);
+ skb_put(skb, pool->buffer_sz);
+ rdma_dest->skb = skb;
+ rdma_dest->data = skb->data;
+ rdma_dest->trailer =
+ (struct viport_trailer *)(rdma_dest->data +
+ pool->buffer_sz -
+ sizeof(struct
+ viport_trailer));
+ }
+ rdma_dest->trailer->connection_hash_and_valid = 0;
+
+ list_del_init(&rdma_dest->list_ptrs);
+
+ data_add_free_buffer(data, index, rdma_dest);
+ index = NEXT(index, pool->eioc_pool_sz);
+ }
+}
+
+static void data_send_kick_message(struct data *data)
+{
+ struct xmit_pool *pool = &data->xmit_pool;
+ DATA_FUNCTION("data_send_kick_message()\n");
+ /* stop timer for bundle_timeout */
+ if (data->kick_timer_on) {
+ del_timer(&data->kick_timer);
+ data->kick_timer_on = 0;
+ }
+ pool->kick_count = 0;
+ pool->kick_byte_count = 0;
+
+ /* TODO: keep track of when kick is outstanding, and
+ * don't reuse until complete
+ */
+ if (vnic_ib_post_send(&data->ib_conn, &data->free_bufs_io.io)) {
+ DATA_ERROR("failed to post send\n");
+ viport_failure(data->parent);
+ }
+}
+
+static void data_send_free_recv_buffers(struct data *data)
+{
+ struct recv_pool *pool = &data->recv_pool;
+ struct ib_send_wr *swr = &data->free_bufs_io.io.swr;
+
+ int bufs_sent = 0;
+ u64 rdma_addr;
+ u32 offset;
+ u32 sz;
+ unsigned int num_to_send, next_increment;
+
+ DATA_FUNCTION("data_send_free_recv_buffers()\n");
+
+ for (num_to_send = pool->sz_free_bundle;
+ num_to_send <= pool->num_free_bufs;
+ num_to_send += pool->sz_free_bundle) {
+ /* handle multiple bundles as one when possible. */
+ next_increment = num_to_send + pool->sz_free_bundle;
+ if ((next_increment <= pool->num_free_bufs)
+ && (pool->next_free_buf + next_increment <=
+ pool->eioc_pool_sz)) {
+ continue;
+ }
+
+ offset = pool->next_free_buf *
+ sizeof(struct buff_pool_entry);
+ sz = num_to_send * sizeof(struct buff_pool_entry);
+ rdma_addr = pool->eioc_rdma_addr + offset;
+ swr->sg_list->length = sz;
+ swr->sg_list->addr = pool->buf_pool_dma + offset;
+ swr->wr.rdma.remote_addr = rdma_addr;
+
+ if (vnic_ib_post_send(&data->ib_conn,
+ &data->free_bufs_io.io)) {
+ DATA_ERROR("failed to post send\n");
+ viport_failure(data->parent);
+ break;
+ }
+ INC(pool->next_free_buf, num_to_send, pool->eioc_pool_sz);
+ pool->num_free_bufs -= num_to_send;
+ pool->num_posted_bufs += num_to_send;
+ bufs_sent = 1;
+ }
+
+ if (bufs_sent) {
+ if (pool->kick_on_free)
+ data_send_kick_message(data);
+ }
+ if (pool->num_posted_bufs == 0) {
+ DATA_ERROR("%s: unable to allocate receive buffers\n",
+ config_viport_name(data->parent->config));
+ viport_failure(data->parent);
+ }
+}
+
+void data_connected(struct data *data)
+{
+ DATA_FUNCTION("data_connected()\n");
+ data->free_bufs_io.io.swr.wr.rdma.rkey =
+ data->recv_pool.eioc_rdma_rkey;
+ data_alloc_buffers(data, 1);
+ data_send_free_recv_buffers(data);
+ data->connected = 1;
+}
+
+void data_disconnect(struct data *data)
+{
+ struct xmit_pool *xmit_pool = &data->xmit_pool;
+ struct recv_pool *recv_pool = &data->recv_pool;
+ unsigned int i;
+
+ DATA_FUNCTION("data_disconnect()\n");
+
+ data->connected = 0;
+ if (data->kick_timer_on) {
+ del_timer_sync(&data->kick_timer);
+ data->kick_timer_on = 0;
+ }
+
+ for (i = 0; i < xmit_pool->num_xmit_bufs; i++) {
+ if (xmit_pool->xmit_bufs[i].skb)
+ dev_kfree_skb(xmit_pool->xmit_bufs[i].skb);
+ xmit_pool->xmit_bufs[i].skb = NULL;
+
+ }
+ for (i = 0; i < recv_pool->pool_sz; i++) {
+ if (data->recv_pool.recv_bufs[i].skb)
+ dev_kfree_skb(recv_pool->recv_bufs[i].skb);
+ recv_pool->recv_bufs[i].skb = NULL;
+ }
+ vfree(data->local_storage);
+ if (data->region_data) {
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ data->region_data_dma, 4,
+ DMA_BIDIRECTIONAL);
+ kfree(data->region_data);
+ }
+
+ if (recv_pool->buf_pool) {
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ recv_pool->buf_pool_dma,
+ recv_pool->buf_pool_len, DMA_TO_DEVICE);
+ kfree(recv_pool->buf_pool);
+ }
+
+ if (xmit_pool->buf_pool) {
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ xmit_pool->buf_pool_dma,
+ xmit_pool->buf_pool_len, DMA_FROM_DEVICE);
+ kfree(xmit_pool->buf_pool);
+ }
+
+ if (xmit_pool->xmit_data) {
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ xmit_pool->xmitdata_dma,
+ xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+ kfree(xmit_pool->xmit_data);
+ }
+}
+
+void data_cleanup(struct data *data)
+{
+ init_completion(&data->ib_conn.done);
+ if (ib_send_cm_dreq(data->ib_conn.cm_id, NULL, 0))
+ printk(KERN_DEBUG "data CM DREQ sending failed\n");
+ else
+ wait_for_completion(&data->ib_conn.done);
+
+ ib_destroy_cm_id(data->ib_conn.cm_id);
+ ib_destroy_qp(data->ib_conn.qp);
+ ib_destroy_cq(data->ib_conn.cq);
+ ib_dereg_mr(data->mr);
+
+}
+
+static int data_alloc_xmit_buffer(struct data *data, struct sk_buff *skb,
+ struct buff_pool_entry **pp_bpe,
+ struct rdma_io **pp_rdma_io,
+ int *last)
+{
+ struct xmit_pool *pool = &data->xmit_pool;
+ unsigned long flags;
+ int ret;
+
+ DATA_FUNCTION("data_alloc_xmit_buffer()\n");
+
+ spin_lock_irqsave(&data->xmit_buf_lock, flags);
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ pool->buf_pool_dma, pool->buf_pool_len,
+ DMA_TO_DEVICE);
+ *last = 0;
+ *pp_rdma_io = &pool->xmit_bufs[pool->next_xmit_buf];
+ *pp_bpe = &pool->buf_pool[pool->next_xmit_pool];
+
+ if ((*pp_bpe)->valid && pool->next_xmit_buf !=
+ pool->last_comp_buf) {
+ INC(pool->next_xmit_buf, 1, pool->num_xmit_bufs);
+ INC(pool->next_xmit_pool, 1, pool->pool_sz);
+ if (!pool->buf_pool[pool->next_xmit_pool].valid) {
+ DATA_INFO("just used the last EIOU"
+ " receive buffer\n");
+ *last = 1;
+ pool->need_buffers = 1;
+ vnic_stop_xmit(data->parent->vnic,
+ data->parent->parent);
+ data_kickreq_stats(data);
+ } else if (pool->next_xmit_buf == pool->last_comp_buf) {
+ DATA_INFO("just used our last xmit buffer\n");
+ pool->need_buffers = 1;
+ vnic_stop_xmit(data->parent->vnic,
+ data->parent->parent);
+ }
+ (*pp_rdma_io)->skb = skb;
+ (*pp_bpe)->valid = 0;
+ ret = 0;
+ } else {
+ data_no_xmitbuf_stats(data);
+ DATA_ERROR("Out of xmit buffers\n");
+ vnic_stop_xmit(data->parent->vnic,
+ data->parent->parent);
+ ret = -1;
+ }
+
+ dma_sync_single_for_device(data->parent->config->ibdev->
+ dma_device, pool->buf_pool_dma,
+ pool->buf_pool_len, DMA_TO_DEVICE);
+ spin_unlock_irqrestore(&data->xmit_buf_lock, flags);
+ return ret;
+}
+
+static void data_rdma_packet(struct data *data, struct buff_pool_entry *bpe,
+ struct rdma_io *rdma_io)
+{
+ struct ib_send_wr *swr;
+ struct sk_buff *skb;
+ dma_addr_t trailer_data_dma;
+ dma_addr_t skb_data_dma;
+ struct xmit_pool *xmit_pool = &data->xmit_pool;
+ struct viport *viport = data->parent;
+ u8 *d;
+ int len;
+ int fill_len;
+
+ DATA_FUNCTION("data_rdma_packet()\n");
+ swr = &rdma_io->io.swr;
+ skb = rdma_io->skb;
+ len = ALIGN(rdma_io->len, VIPORT_TRAILER_ALIGNMENT);
+ fill_len = len - skb->len;
+
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ xmit_pool->xmitdata_dma,
+ xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+
+ d = (u8 *) rdma_io->trailer - fill_len;
+ trailer_data_dma = rdma_io->trailer_dma - fill_len;
+ memset(d, 0, fill_len);
+
+ swr->sg_list[0].length = skb->len;
+ if (skb->len <= min_xmt_skb) {
+ memcpy(rdma_io->data, skb->data, skb->len);
+ swr->sg_list[0].lkey = data->mr->lkey;
+ swr->sg_list[0].addr = rdma_io->data_dma;
+ dev_kfree_skb_any(skb);
+ rdma_io->skb = NULL;
+ } else {
+ swr->sg_list[0].lkey = data->mr->lkey;
+
+ skb_data_dma = dma_map_single(viport->config->ibdev->dma_device,
+ skb->data, skb->len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(skb_data_dma)) {
+ DATA_ERROR("skb data dma map error\n");
+ goto failure;
+ }
+
+ rdma_io->skb_data_dma = skb_data_dma;
+
+ swr->sg_list[0].addr = skb_data_dma;
+ skb_orphan(skb);
+ }
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ xmit_pool->buf_pool_dma,
+ xmit_pool->buf_pool_len, DMA_TO_DEVICE);
+
+ swr->sg_list[1].addr = trailer_data_dma;
+ swr->sg_list[1].length = fill_len + sizeof(struct viport_trailer);
+ swr->sg_list[0].lkey = data->mr->lkey;
+ swr->wr.rdma.remote_addr = be64_to_cpu(bpe->remote_addr);
+ swr->wr.rdma.remote_addr += data->xmit_pool.buffer_sz;
+ swr->wr.rdma.remote_addr -= (sizeof(struct viport_trailer) + len);
+ swr->wr.rdma.rkey = be32_to_cpu(bpe->rkey);
+
+ dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+ xmit_pool->buf_pool_dma,
+ xmit_pool->buf_pool_len, DMA_TO_DEVICE);
+
+ data->xmit_pool.notify_count++;
+ if (data->xmit_pool.notify_count >= data->xmit_pool.notify_bundle) {
+ data->xmit_pool.notify_count = 0;
+ swr->send_flags = IB_SEND_SIGNALED;
+ } else {
+ swr->send_flags = 0;
+ }
+ dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+ xmit_pool->xmitdata_dma,
+ xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+ if (vnic_ib_post_send(&data->ib_conn, &rdma_io->io)) {
+ DATA_ERROR("failed to post send for data RDMA write\n");
+ viport_failure(data->parent);
+ goto failure;
+ }
+
+ data_xmits_stats(data);
+failure:
+ dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+ xmit_pool->xmitdata_dma,
+ xmit_pool->xmitdata_len, DMA_TO_DEVICE);
+}
+
+static void data_kick_timeout_handler(unsigned long arg)
+{
+ struct data *data = (struct data *)arg;
+
+ DATA_FUNCTION("data_kick_timeout_handler()\n");
+ data->kick_timer_on = 0;
+ data_send_kick_message(data);
+}
+
+int data_xmit_packet(struct data *data, struct sk_buff *skb)
+{
+ struct xmit_pool *pool = &data->xmit_pool;
+ struct rdma_io *rdma_io;
+ struct buff_pool_entry *bpe;
+ struct viport_trailer *trailer;
+ unsigned int sz = skb->len;
+ int last;
+
+ DATA_FUNCTION("data_xmit_packet()\n");
+ if (sz > pool->buffer_sz) {
+ DATA_ERROR("outbound packet too large, size = %d\n", sz);
+ return -1;
+ }
+
+ if (data_alloc_xmit_buffer(data, skb, &bpe, &rdma_io, &last)) {
+ DATA_ERROR("error in allocating data xmit buffer\n");
+ return -1;
+ }
+
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ pool->xmitdata_dma, pool->xmitdata_len,
+ DMA_TO_DEVICE);
+ trailer = rdma_io->trailer;
+
+ memset(trailer, 0, sizeof *trailer);
+ memcpy(trailer->dest_mac_addr, skb->data, ETH_ALEN);
+
+ if (skb->sk)
+ trailer->connection_hash_and_valid = 0x40 |
+ ((be16_to_cpu(inet_sk(skb->sk)->sport) +
+ be16_to_cpu( inet_sk(skb->sk)->dport)) & 0x3f);
+
+ trailer->connection_hash_and_valid |= CHV_VALID;
+
+ if ((sz > 16) && (*(__be16 *) (skb->data + 12) ==
+ __constant_cpu_to_be16(ETH_P_8021Q))) {
+ trailer->vlan = *(__be16 *) (skb->data + 14);
+ memmove(skb->data + 4, skb->data, 12);
+ skb_pull(skb, 4);
+ trailer->pkt_flags |= PF_VLAN_INSERT;
+ }
+ if (last)
+ trailer->pkt_flags |= PF_KICK;
+ if (sz < ETH_ZLEN) {
+ /* EIOU requires all packets to be
+ * of ethernet minimum packet size.
+ */
+ trailer->data_length = __constant_cpu_to_be16(ETH_ZLEN);
+ rdma_io->len = ETH_ZLEN;
+ } else {
+ trailer->data_length = cpu_to_be16(sz);
+ rdma_io->len = sz;
+ }
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ trailer->tx_chksum_flags = TX_CHKSUM_FLAGS_CHECKSUM_V4
+ | TX_CHKSUM_FLAGS_IP_CHECKSUM
+ | TX_CHKSUM_FLAGS_TCP_CHECKSUM
+ | TX_CHKSUM_FLAGS_UDP_CHECKSUM;
+ }
+
+ dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+ pool->xmitdata_dma, pool->xmitdata_len,
+ DMA_TO_DEVICE);
+
+ data_rdma_packet(data, bpe, rdma_io);
+
+ if (pool->send_kicks) {
+ /* EIOC needs kicks to inform it of sent packets */
+ pool->kick_count++;
+ pool->kick_byte_count += sz;
+ if ((pool->kick_count >= pool->kick_bundle)
+ || (pool->kick_byte_count >= pool->kick_byte_bundle)) {
+ data_send_kick_message(data);
+ } else if (pool->kick_count == 1) {
+ init_timer(&data->kick_timer);
+ /* timeout_before_kick is in usec */
+ data->kick_timer.expires =
+ msecs_to_jiffies(be32_to_cpu(data->
+ eioc_pool_parms.timeout_before_kick) * 1000)
+ + jiffies;
+ data->kick_timer.data = (unsigned long)data;
+ data->kick_timer.function = data_kick_timeout_handler;
+ add_timer(&data->kick_timer);
+ data->kick_timer_on = 1;
+ }
+ }
+ return 0;
+}
+
+void data_check_xmit_buffers(struct data *data)
+{
+ struct xmit_pool *pool = &data->xmit_pool;
+ unsigned long flags;
+
+ DATA_FUNCTION("data_check_xmit_buffers()\n");
+ spin_lock_irqsave(&data->xmit_buf_lock, flags);
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ pool->buf_pool_dma, pool->buf_pool_len,
+ DMA_TO_DEVICE);
+
+ if (data->xmit_pool.need_buffers
+ && pool->buf_pool[pool->next_xmit_pool].valid
+ && pool->next_xmit_buf != pool->last_comp_buf) {
+ data->xmit_pool.need_buffers = 0;
+ vnic_restart_xmit(data->parent->vnic,
+ data->parent->parent);
+ DATA_INFO("there are free xmit buffers\n");
+ }
+ dma_sync_single_for_device(data->parent->config->ibdev->dma_device,
+ pool->buf_pool_dma, pool->buf_pool_len,
+ DMA_TO_DEVICE);
+
+ spin_unlock_irqrestore(&data->xmit_buf_lock, flags);
+}
+
+static struct sk_buff *data_recv_to_skbuff(struct data *data,
+ struct rdma_dest *rdma_dest)
+{
+ struct viport_trailer *trailer;
+ struct sk_buff *skb = NULL;
+ int start;
+ unsigned int len;
+ u8 rx_chksum_flags;
+
+ DATA_FUNCTION("data_recv_to_skbuff()\n");
+ trailer = rdma_dest->trailer;
+ start = data_offset(data, trailer);
+ len = data_len(data, trailer);
+
+ if (len <= min_rcv_skb)
+ skb = dev_alloc_skb(len + VLAN_HLEN + 2);
+ /* leave room for VLAN header and alignment */
+ if (skb) {
+ skb_reserve(skb, VLAN_HLEN + 2);
+ memcpy(skb->data, rdma_dest->data + start, len);
+ skb_put(skb, len);
+ } else {
+ skb = rdma_dest->skb;
+ rdma_dest->skb = NULL;
+ rdma_dest->trailer = NULL;
+ rdma_dest->data = NULL;
+ skb_pull(skb, start);
+ skb_trim(skb, len);
+ }
+
+ rx_chksum_flags = trailer->rx_chksum_flags;
+ DATA_INFO("rx_chksum_flags = %d, LOOP = %c, IP = %c,"
+ " TCP = %c, UDP = %c\n",
+ rx_chksum_flags,
+ (rx_chksum_flags & RX_CHKSUM_FLAGS_LOOPBACK) ? 'Y' : 'N',
+ (rx_chksum_flags & RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED) ? 'Y'
+ : (rx_chksum_flags & RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED) ? 'N' :
+ '-',
+ (rx_chksum_flags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED) ? 'Y'
+ : (rx_chksum_flags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED) ? 'N' :
+ '-',
+ (rx_chksum_flags & RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED) ? 'Y'
+ : (rx_chksum_flags & RX_CHKSUM_FLAGS_UDP_CHECKSUM_FAILED) ? 'N' :
+ '-');
+
+ if ((rx_chksum_flags & RX_CHKSUM_FLAGS_LOOPBACK)
+ || ((rx_chksum_flags & RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED)
+ && ((rx_chksum_flags & RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED)
+ || (rx_chksum_flags &
+ RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED))))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (trailer->pkt_flags & PF_VLAN_INSERT) {
+ u8 *rv;
+
+ rv = skb_push(skb, 4);
+ memmove(rv, rv + 4, 12);
+ *(__be16 *) (rv + 12) = __constant_cpu_to_be16(ETH_P_8021Q);
+ if (trailer->pkt_flags & PF_PVID_OVERRIDDEN)
+ *(__be16 *) (rv + 14) = trailer->vlan &
+ __constant_cpu_to_be16(0xF000);
+ else
+ *(__be16 *) (rv + 14) = trailer->vlan;
+ }
+
+ return skb;
+}
+
+static int data_incoming_recv(struct data *data)
+{
+ struct recv_pool *pool = &data->recv_pool;
+ struct rdma_dest *rdma_dest;
+ struct viport_trailer *trailer;
+ struct buff_pool_entry *bpe;
+ struct sk_buff *skb;
+
+ DATA_FUNCTION("data_incoming_recv()\n");
+ if (pool->next_full_buf == pool->next_free_buf)
+ return -1;
+ bpe = &pool->buf_pool[pool->next_full_buf];
+ rdma_dest = &pool->recv_bufs[bpe->valid - 1];
+ trailer = rdma_dest->trailer;
+
+ if (!trailer
+ || !(trailer->connection_hash_and_valid & CHV_VALID))
+ return -1;
+
+ /* received a packet */
+ if (trailer->pkt_flags & PF_KICK)
+ pool->kick_on_free = 1;
+
+ skb = data_recv_to_skbuff(data, rdma_dest);
+
+ if (skb) {
+ vnic_recv_packet(data->parent->vnic,
+ data->parent->parent, skb);
+ list_add(&rdma_dest->list_ptrs, &pool->avail_recv_bufs);
+ }
+
+ dma_sync_single_for_cpu(data->parent->config->ibdev->dma_device,
+ pool->buf_pool_dma, pool->buf_pool_len,
+ DMA_TO_DEVICE);
+
+ bpe->valid = 0;
+ dma_sync_single_for_device(data->parent->config->ibdev->
+ dma_device, pool->buf_pool_dma,
+ pool->buf_pool_len, DMA_TO_DEVICE);
+
+ INC(pool->next_full_buf, 1, pool->eioc_pool_sz);
+ pool->num_posted_bufs--;
+ data_recvs_stats(data);
+ return 0;
+}
+
+static void data_received_kick(struct io *io)
+{
+ struct data *data = &io->viport->data;
+ unsigned long flags;
+
+ DATA_FUNCTION("data_received_kick()\n");
+ data_note_kickrcv_time();
+ spin_lock_irqsave(&data->recv_ios_lock, flags);
+ list_add(&io->list_ptrs, &data->recv_ios);
+ spin_unlock_irqrestore(&data->recv_ios_lock, flags);
+ data_post_recvs(data);
+ data_rcvkicks_stats(data);
+ data_check_xmit_buffers(data);
+
+ while (!data_incoming_recv(data));
+
+ if (data->connected) {
+ data_alloc_buffers(data, 0);
+ data_send_free_recv_buffers(data);
+ }
+}
+
+static void data_xmit_complete(struct io *io)
+{
+ struct rdma_io *rdma_io = (struct rdma_io *)io;
+ struct data *data = &io->viport->data;
+ struct xmit_pool *pool = &data->xmit_pool;
+ struct sk_buff *skb;
+
+ DATA_FUNCTION("data_xmit_complete()\n");
+
+ if (rdma_io->skb)
+ dma_unmap_single(data->parent->config->ibdev->dma_device,
+ rdma_io->skb_data_dma, rdma_io->skb->len,
+ DMA_TO_DEVICE);
+
+ while (pool->last_comp_buf != rdma_io->index) {
+ INC(pool->last_comp_buf, 1, pool->num_xmit_bufs);
+ skb = pool->xmit_bufs[pool->last_comp_buf].skb;
+ if (skb)
+ dev_kfree_skb_any(skb);
+ pool->xmit_bufs[pool->last_comp_buf].skb = NULL;
+ }
+
+ data_check_xmit_buffers(data);
+}
diff --git a/drivers/infiniband/ulp/vnic/vnic_data.h b/drivers/infiniband/ulp/vnic/vnic_data.h
new file mode 100644
index 0000000..379df14
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_data.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2006 QLogic, 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
+ * 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.
+ */
+
+#ifndef VNIC_DATA_H_INCLUDED
+#define VNIC_DATA_H_INCLUDED
+
+#include <linux/if_vlan.h>
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+#include <linux/timex.h>
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+
+#include "vnic_ib.h"
+#include "vnic_control_pkt.h"
+#include "vnic_trailer.h"
+
+struct rdma_dest {
+ struct list_head list_ptrs;
+ struct sk_buff *skb;
+ u8 *data;
+ struct viport_trailer *trailer;
+};
+
+struct buff_pool_entry {
+ __be64 remote_addr;
+ __be32 rkey;
+ u32 valid;
+};
+
+struct recv_pool {
+ u32 buffer_sz;
+ u32 pool_sz;
+ u32 eioc_pool_sz;
+ u32 eioc_rdma_rkey;
+ u64 eioc_rdma_addr;
+ u32 next_full_buf;
+ u32 next_free_buf;
+ u32 num_free_bufs;
+ u32 num_posted_bufs;
+ u32 sz_free_bundle;
+ int kick_on_free;
+ struct buff_pool_entry *buf_pool;
+ dma_addr_t buf_pool_dma;
+ int buf_pool_len;
+ struct rdma_dest *recv_bufs;
+ struct list_head avail_recv_bufs;
+};
+
+struct xmit_pool {
+ u32 buffer_sz;
+ u32 pool_sz;
+ u32 notify_count;
+ u32 notify_bundle;
+ u32 next_xmit_buf;
+ u32 last_comp_buf;
+ u32 num_xmit_bufs;
+ u32 next_xmit_pool;
+ u32 kick_count;
+ u32 kick_byte_count;
+ u32 kick_bundle;
+ u32 kick_byte_bundle;
+ int need_buffers;
+ int send_kicks;
+ uint32_t rdma_rkey;
+ u64 rdma_addr;
+ struct buff_pool_entry *buf_pool;
+ dma_addr_t buf_pool_dma;
+ int buf_pool_len;
+ struct rdma_io *xmit_bufs;
+ u8 *xmit_data;
+ dma_addr_t xmitdata_dma;
+ int xmitdata_len;
+};
+
+struct data {
+ struct viport *parent;
+ struct data_config *config;
+ struct ib_mr *mr;
+ struct vnic_ib_conn ib_conn;
+ u8 *local_storage;
+ struct vnic_recv_pool_config host_pool_parms;
+ struct vnic_recv_pool_config eioc_pool_parms;
+ struct recv_pool recv_pool;
+ struct xmit_pool xmit_pool;
+ u8 *region_data;
+ dma_addr_t region_data_dma;
+ struct rdma_io free_bufs_io;
+ struct send_io kick_io;
+ struct list_head recv_ios;
+ spinlock_t recv_ios_lock;
+ spinlock_t xmit_buf_lock;
+ int kick_timer_on;
+ int connected;
+ struct timer_list kick_timer;
+ struct completion done;
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ struct {
+ u32 xmit_num;
+ u32 recv_num;
+ u32 free_buf_sends;
+ u32 free_buf_num;
+ u32 free_buf_min;
+ u32 kick_recvs;
+ u32 kick_reqs;
+ u32 no_xmit_bufs;
+ cycles_t no_xmit_buf_time;
+ } statistics;
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+};
+
+int data_init(struct data *data, struct viport *viport,
+ struct data_config *config, struct ib_pd *pd);
+
+int data_connect(struct data *data);
+void data_connected(struct data *data);
+void data_disconnect(struct data *data);
+
+int data_xmit_packet(struct data *data, struct sk_buff *skb);
+
+void data_cleanup(struct data *data);
+
+#define data_is_connected(data) \
+ (vnic_ib_conn_connected(&((data)->ib_conn)))
+#define data_path_id(data) (data)->config->path_id
+#define data_eioc_pool(data) &(data)->eioc_pool_parms
+#define data_host_pool(data) &(data)->host_pool_parms
+#define data_eioc_pool_min(data) &(data)->config->eioc_min
+#define data_host_pool_min(data) &(data)->config->host_min
+#define data_eioc_pool_max(data) &(data)->config->eioc_max
+#define data_host_pool_max(data) &(data)->config->host_max
+#define data_local_pool_addr(data) (data)->xmit_pool.rdma_addr
+#define data_local_pool_rkey(data) (data)->xmit_pool.rdma_rkey
+#define data_remote_pool_addr(data) &(data)->recv_pool.eioc_rdma_addr
+#define data_remote_pool_rkey(data) &(data)->recv_pool.eioc_rdma_rkey
+
+#define data_max_mtu(data) \
+ MAX_PAYLOAD(min((data)->recv_pool.buffer_sz, \
+ (data)->xmit_pool.buffer_sz)) - VLAN_ETH_HLEN
+
+#define data_len(data, trailer) be16_to_cpu(trailer->data_length)
+#define data_offset(data, trailer) \
+ data->recv_pool.buffer_sz - sizeof(struct viport_trailer) \
+ - ALIGN(data_len(data, trailer), VIPORT_TRAILER_ALIGNMENT) \
+ + trailer->data_alignment_offset
+
+/* the following macros manipulate ring buffer indexes.
+ * the ring buffer size must be a power of 2.
+ */
+#define ADD(index, increment, size) (((index) + (increment))&((size) - 1))
+#define NEXT(index, size) ADD(index, 1, size)
+#define INC(index, increment, size) (index) = ADD(index, increment, size)
+
+#endif /* VNIC_DATA_H_INCLUDED */
diff --git a/drivers/infiniband/ulp/vnic/vnic_trailer.h b/drivers/infiniband/ulp/vnic/vnic_trailer.h
new file mode 100644
index 0000000..dd8a073
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_trailer.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2006 QLogic, 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
+ * 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.
+ */
+
+#ifndef VNIC_TRAILER_H_INCLUDED
+#define VNIC_TRAILER_H_INCLUDED
+
+/* pkt_flags values */
+enum {
+ PF_CHASH_VALID = 0x01,
+ PF_IPSEC_VALID = 0x02,
+ PF_TCP_SEGMENT = 0x04,
+ PF_KICK = 0x08,
+ PF_VLAN_INSERT = 0x10,
+ PF_PVID_OVERRIDDEN = 0x20,
+ PF_FCS_INCLUDED = 0x40,
+ PF_FORCE_ROUTE = 0x80
+};
+
+/* tx_chksum_flags values */
+enum {
+ TX_CHKSUM_FLAGS_CHECKSUM_V4 = 0x01,
+ TX_CHKSUM_FLAGS_CHECKSUM_V6 = 0x02,
+ TX_CHKSUM_FLAGS_TCP_CHECKSUM = 0x04,
+ TX_CHKSUM_FLAGS_UDP_CHECKSUM = 0x08,
+ TX_CHKSUM_FLAGS_IP_CHECKSUM = 0x10
+};
+
+/* rx_chksum_flags values */
+enum {
+ RX_CHKSUM_FLAGS_TCP_CHECKSUM_FAILED = 0x01,
+ RX_CHKSUM_FLAGS_UDP_CHECKSUM_FAILED = 0x02,
+ RX_CHKSUM_FLAGS_IP_CHECKSUM_FAILED = 0x04,
+ RX_CHKSUM_FLAGS_TCP_CHECKSUM_SUCCEEDED = 0x08,
+ RX_CHKSUM_FLAGS_UDP_CHECKSUM_SUCCEEDED = 0x10,
+ RX_CHKSUM_FLAGS_IP_CHECKSUM_SUCCEEDED = 0x20,
+ RX_CHKSUM_FLAGS_LOOPBACK = 0x40,
+ RX_CHKSUM_FLAGS_RESERVED = 0x80
+};
+
+/* connection_hash_and_valid values */
+enum {
+ CHV_VALID = 0x80,
+ CHV_HASH_MASH = 0x7f
+};
+
+struct viport_trailer {
+ s8 data_alignment_offset;
+ u8 rndis_header_length; /* reserved for use by edp */
+ __be16 data_length;
+ u8 pkt_flags;
+ u8 tx_chksum_flags;
+ u8 rx_chksum_flags;
+ u8 ip_sec_flags;
+ u32 tcp_seq_no;
+ u32 ip_sec_offload_handle;
+ u32 ip_sec_next_offload_handle;
+ u8 dest_mac_addr[6];
+ __be16 vlan;
+ u16 time_stamp;
+ u8 origin;
+ u8 connection_hash_and_valid;
+};
+
+#define VIPORT_TRAILER_ALIGNMENT 32
+
+#define BUFFER_SIZE(len) \
+ (sizeof(struct viport_trailer) + \
+ ALIGN((len), VIPORT_TRAILER_ALIGNMENT))
+
+#define MAX_PAYLOAD(len) \
+ ALIGN_DOWN((len) - sizeof(struct viport_trailer), \
+ VIPORT_TRAILER_ALIGNMENT)
+
+#endif /* VNIC_TRAILER_H_INCLUDED */
More information about the general
mailing list