[openib-general] [PATCH v2 11/14] CXGB3 Core ULP Demux Code.

Steve Wise swise at opengridcomputing.com
Fri Jun 23 07:30:21 PDT 2006


This code demuxes connection data and events from the LLD driver to the
various registered ULPs.  It also has the cxgb3 core module init logic,
which includes registering with the Network Event Notifier to obtain
L2/L3 events.
---

 drivers/infiniband/hw/cxgb3/t3c/t3c.c |  504 +++++++++++++++++++++++++++++++++
 drivers/infiniband/hw/cxgb3/t3c/t3c.h |  188 ++++++++++++
 2 files changed, 692 insertions(+), 0 deletions(-)

diff --git a/drivers/infiniband/hw/cxgb3/t3c/t3c.c b/drivers/infiniband/hw/cxgb3/t3c/t3c.c
new file mode 100644
index 0000000..53d978a
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/t3c/t3c.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006 Open Grid Computing, 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 <linux/list.h>
+#include <net/neighbour.h>
+#include <linux/notifier.h>
+#include <net/netevent.h>
+#include <asm/atomic.h>
+
+#include "defs.h"
+#include "l2t.h"
+#include <firmware_exports.h>
+#include "t3c.h"
+#include <t3_core.h>
+
+// #define T3C_DEBUG
+
+#define MOD "t3c: "
+#ifdef T3C_DEBUG
+#define assert(expr)                                                  \
+    if(!(expr)) {                                                     \
+        printk(KERN_ERR MOD "Assertion failed! %s, %s, %s, line %d\n",\
+               #expr, __FILE__, __FUNCTION__, __LINE__);              \
+    }
+#define dprintk(fmt, args...) do {printk(KERN_INFO MOD fmt, ##args);} while (0)
+#else
+#define assert(expr)          do {} while (0)
+#define dprintk(fmt, args...) do {} while (0)
+#endif 
+
+MODULE_AUTHOR("Steve Wise <swise at opengridcomputing.com>");
+MODULE_DESCRIPTION("Chelsio T3 Core Module");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("1.0");
+
+void __init t3cdev_init(void);
+void __exit t3cdev_exit(void);
+void unregister_t3cdev(struct t3cdev *dev);
+void register_t3cdev(struct t3cdev *dev, const char *name);
+
+static LIST_HEAD(client_list);
+
+void t3c_register_client(struct t3c_client *client)
+{
+	struct t3cdev *tdev;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	mutex_lock(&t3cdev_db_lock);
+	list_add_tail(&client->client_list, &client_list);
+	list_for_each_entry(tdev, &t3cdev_list, t3c_list) {
+		if (client->add) {
+			dprintk("%s - calling %s add fn with t3cdev %s\n", 
+				__FUNCTION__, client->name, tdev->name);
+			client->add(tdev);
+		}
+	}
+	mutex_unlock(&t3cdev_db_lock);
+}
+EXPORT_SYMBOL(t3c_register_client);
+
+void t3c_unregister_client(struct t3c_client *client)
+{
+	struct t3cdev *tdev;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	mutex_lock(&t3cdev_db_lock);
+	list_del(&client->client_list);
+	list_for_each_entry(tdev, &t3cdev_list, t3c_list) {
+		if (client->remove) {
+			dprintk("%s - calling %s remove fn with t3cdev %s\n", 
+				__FUNCTION__, client->name, tdev->name);
+			client->remove(tdev);
+		}
+	}
+	mutex_unlock(&t3cdev_db_lock);
+}
+EXPORT_SYMBOL(t3c_unregister_client);
+
+/* 
+ * Called by t3's pci add function.
+ */
+static void add_t3cdev(struct t3cdev *tdev)
+{
+	struct t3c_client *client;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	register_t3cdev(tdev, "cxgb3c%d");
+	attach_t3cdev(tdev);
+	list_for_each_entry(client, &client_list, client_list) {
+		if (client->add) {
+			dprintk("%s - calling %s add fn with t3cdev %s\n", 
+				__FUNCTION__, client->name, tdev->name);
+			client->add(tdev);
+		}
+	}
+}
+
+/*
+ * Called by t3's pci remove function.
+ */
+static void remove_t3cdev(struct t3cdev *tdev)
+{
+	struct t3c_client *client;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	list_for_each_entry(client, &client_list, client_list) {
+		if (client->remove) {
+			dprintk("%s - calling %s add fn with t3cdev %s\n", 
+				__FUNCTION__, client->name, tdev->name);
+			client->remove(tdev);
+		}
+	}
+	detach_t3cdev(tdev);
+	unregister_t3cdev(tdev);
+}
+
+/*
+ * Free an active-open TID.
+ */
+void t3c_free_atid(struct t3cdev *tdev, int atid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+	union active_open_entry *p = atid2entry(t, atid);
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	spin_lock_bh(&t->atid_lock);
+	p->next = t->afree;
+	t->afree = p;
+	t->atids_in_use--;
+	spin_unlock_bh(&t->atid_lock);
+}
+EXPORT_SYMBOL(t3c_free_atid);
+
+/*
+ * Free a server TID and return it to the free pool.  
+ */
+void t3c_free_stid(struct t3cdev *tdev, int stid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+	union listen_entry *p = stid2entry(t, stid);
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	spin_lock_bh(&t->stid_lock);
+	p->next = t->sfree;
+	t->sfree = p;
+	t->stids_in_use--;
+	spin_unlock_bh(&t->stid_lock);
+}
+EXPORT_SYMBOL(t3c_free_stid);
+
+void t3c_insert_tid(struct t3cdev *tdev, struct t3c_client *client, 
+	void *ctx, unsigned int tid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t->tid_tab[tid].client = client;
+	t->tid_tab[tid].ctx = ctx;
+	atomic_inc(&t->tids_in_use);
+}
+EXPORT_SYMBOL(t3c_insert_tid);
+
+/*
+ * Remove a t3c from the TID table.  A client may defer processing its last
+ * CPL message if it is locked at the time it arrives, and while the message
+ * sits in the client's backlog the TID may be reused for another connection.
+ * To handle this we atomically switch the TID association if it still points
+ * to the original client context.
+ */
+void t3c_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
+{
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
+	atomic_dec(&t->tids_in_use);
+}
+EXPORT_SYMBOL(t3c_remove_tid);
+
+int t3c_alloc_atid(struct t3cdev *tdev, struct t3c_client *client, void *ctx)
+{
+	int atid = -1;
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	spin_lock_bh(&t->atid_lock);
+	if (t->afree) {
+		union active_open_entry *p = t->afree;
+
+		atid = (p - t->atid_tab) + t->atid_base;
+		t->afree = p->next;
+		p->t3c_tid.ctx = ctx;
+		p->t3c_tid.client = client;
+		t->atids_in_use++;
+	}
+	spin_unlock_bh(&t->atid_lock);
+	return atid;
+}
+EXPORT_SYMBOL(t3c_alloc_atid);
+
+int t3c_alloc_stid(struct t3cdev *tdev, struct t3c_client *client, void *ctx)
+{
+	int stid = -1;
+	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	spin_lock_bh(&t->stid_lock);
+	if (t->sfree) {
+		union listen_entry *p = t->sfree;
+
+		stid = (p - t->stid_tab) + t->stid_base;
+		t->sfree = p->next;
+		p->t3c_tid.ctx = ctx;
+		p->t3c_tid.client = client;
+		t->stids_in_use++;
+	}
+	spin_unlock_bh(&t->stid_lock);
+	return stid;
+}
+EXPORT_SYMBOL(t3c_alloc_stid);
+
+static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_smt_write_rpl *rpl = cplhdr(skb);
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+		       "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+		       rpl->status, GET_TID(rpl));
+
+	return CPL_RET_BUF_DONE;
+}
+
+static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+		       rpl->status, GET_TID(rpl));
+
+	return CPL_RET_BUF_DONE;
+}
+
+static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_act_open_rpl *rpl = cplhdr(skb);
+	unsigned int atid = G_TID(ntohl(rpl->atid));
+	struct t3c_tid_entry *t3c_tid;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+	if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers && 
+		t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
+		return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, 
+			t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", 
+			dev->name, CPL_ACT_OPEN_RPL);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	union opcode_tid *p = cplhdr(skb);
+	unsigned int stid = G_TID(ntohl(p->opcode_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers && 
+		t3c_tid->client->handlers[p->opcode]) {
+		return t3c_tid->client->handlers[p->opcode] (dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", 
+			dev->name, p->opcode);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	union opcode_tid *p = cplhdr(skb);
+	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	dprintk("%s enter (%s line %u) opcode 0x%x tid %d\n", 
+		__FUNCTION__, __FILE__, __LINE__, p->opcode, hwtid);
+	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers && 
+		t3c_tid->client->handlers[p->opcode]) {
+		return t3c_tid->client->handlers[p->opcode]
+						(dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", 
+			dev->name, p->opcode);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_pass_accept_req *req = cplhdr(skb);
+	unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers && 
+		t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
+		return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
+						(dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", 
+			dev->name, CPL_PASS_ACCEPT_REQ);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_act_establish *req = cplhdr(skb);
+	unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+	struct t3c_tid_entry *t3c_tid;
+
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers && 
+		t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
+		return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
+						(dev, skb, t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", 
+			dev->name, CPL_PASS_ACCEPT_REQ);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
+
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+			"Unexpected SET_TCB_RPL status %u for tid %u\n",
+			rpl->status, GET_TID(rpl));
+	return CPL_RET_BUF_DONE;
+}
+
+static int do_trace(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_trace_pkt *p = cplhdr(skb);
+
+	skb->protocol = 0xffff;
+	skb->dev = dev->lldev;
+	skb_pull(skb, sizeof(*p));
+	skb->mac.raw = skb->data;
+	netif_receive_skb(skb);
+	return 0;
+}
+
+static int do_term(struct t3cdev *dev, struct sk_buff *skb)
+{
+	unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff;
+	unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+	struct t3c_tid_entry *t3c_tid;
+
+	dprintk("%s enter (%s line %u) opcode 0x%x tid %d\n",
+		__FUNCTION__, __FILE__, __LINE__, opcode, hwtid);
+
+	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+	if (t3c_tid->ctx && t3c_tid->client->handlers && 
+		t3c_tid->client->handlers[opcode]) {
+		return t3c_tid->client->handlers[opcode](dev,skb,t3c_tid->ctx);
+	} else {
+		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", 
+			dev->name, opcode);
+		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+	}
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event, 
+	void *ctx)
+{
+	switch (event) {
+		case (NETEVENT_NEIGH_UPDATE): {
+			t3c_neigh_update((struct neighbour *)ctx, 0);
+			break;
+		}
+		case (NETEVENT_ROUTE_UPDATE):
+			dprintk("%s ROUTE_UPDATE\n", __FUNCTION__);
+			break;
+		case (NETEVENT_PMTU_UPDATE):
+			dprintk("%s PMTU_UPDATE\n", __FUNCTION__);
+			break;
+		case (NETEVENT_REDIRECT): {
+			struct netevent_redirect *nr = ctx;
+			dprintk("%s REDIRECT old dst %p new dst %p "
+			       "old neigh %p new neigh %p old neigh key %x "
+			       "new neigh key %x\n", __FUNCTION__,
+				nr->old, nr->new, 
+				nr->old ? nr->old->neighbour : NULL, 
+				nr->new ? nr->new->neighbour : NULL, 
+				nr->old->neighbour ? 
+					*(u32*)nr->old->neighbour->primary_key
+					: 0,
+				nr->new->neighbour ? 
+					*(u32*)nr->new->neighbour->primary_key
+					: 0);
+			t3c_redirect(nr->old, nr->new);
+			t3c_neigh_update(nr->new->neighbour, 0);
+			break;
+		}
+		default:
+			printk(KERN_ERR "unknown net event notifier type %lu\n", 
+				event);
+			break;
+	}
+	return 0;
+}
+
+static struct notifier_block nb = {
+	.notifier_call = nb_callback
+};
+
+
+/*
+ * upcall struct for the t3 module.
+ */
+static struct t3_core core = {
+	.add 		= add_t3cdev,
+	.remove		= remove_t3cdev,
+};
+
+int __init t3c_init(void)
+{
+	t3cdev_init();
+	register_netevent_notifier(&nb);
+	dprintk("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
+	t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+	t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
+	t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
+	t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
+	t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
+	t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_hwtid_rpl);
+	t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
+	t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
+	t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
+	t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
+	t3_register_core(&core);
+	
+	return 0;
+}
+
+static void __exit t3c_exit(void)
+{
+	dprintk("%s (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+	t3_unregister_core(&core);
+	t3cdev_exit();
+	unregister_netevent_notifier(&nb);
+	return;
+}
+module_init(t3c_init);
+module_exit(t3c_exit);
diff --git a/drivers/infiniband/hw/cxgb3/t3c/t3c.h b/drivers/infiniband/hw/cxgb3/t3c/t3c.h
new file mode 100644
index 0000000..fdc51a8
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/t3c/t3c.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006 Open Grid Computing, 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 _CHELSIO_T3C_H
+#define _CHELSIO_T3C_H
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#include <tcb.h>
+#include <l2t.h>
+
+#include <t3cdev.h>
+#include <t3_cpl.h>
+
+/*
+ * Client registration.  Users of the T3 Core driver must register themselves. 
+ * The T3 Core driver will call the add function of every client for each T3 
+ * PCI device probed, passing up the t3cdev ptr.  Each client fills out an
+ * array of callback functions to process CPL messages.  
+ */
+typedef int (*t3c_cpl_handler_func)(struct t3cdev *dev, 
+				     struct sk_buff *skb, void *ctx);
+
+struct t3c_client {
+	char 			*name;
+	void 			(*add) (struct t3cdev *);
+	void 			(*remove) (struct t3cdev *);
+	t3c_cpl_handler_func 	*handlers;
+	int			(*redirect)(void *ctx, struct dst_entry *old, 
+					    struct dst_entry *new, 
+					    struct l2t_entry *l2t);
+	struct list_head	client_list;
+};
+
+void t3c_register_client(struct t3c_client *);
+void t3c_unregister_client(struct t3c_client *);
+
+/*
+ * TID allocation services. 
+ */
+int t3c_alloc_atid(struct t3cdev *dev, struct t3c_client *client, void *ctx);
+int t3c_alloc_stid(struct t3cdev *dev, struct t3c_client *client, void *ctx);
+void t3c_free_atid(struct t3cdev *dev, int atid);
+void t3c_free_stid(struct t3cdev *dev, int stid);
+void t3c_insert_tid(struct t3cdev *dev, struct t3c_client *client, void *ctx, 
+	unsigned int tid);
+void t3c_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid);
+
+struct t3c_tid_entry {
+	struct t3c_client 	*client;
+	void 			*ctx;
+};
+
+/* CPL message priority levels */
+enum {
+	CPL_PRIORITY_DATA = 0,     /* data messages */
+	CPL_PRIORITY_SETUP = 1,	   /* connection setup messages */
+	CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */
+	CPL_PRIORITY_LISTEN = 1,   /* listen start/stop messages */
+	CPL_PRIORITY_ACK = 1,      /* RX ACK messages */
+	CPL_PRIORITY_CONTROL = 1   /* TOE control messages */
+};
+
+/* Flags for return value of CPL message handlers */
+enum {
+	CPL_RET_BUF_DONE = 1,   // buffer processing done, buffer may be freed
+	CPL_RET_BAD_MSG = 2,    // bad CPL message (e.g., unknown opcode)
+	CPL_RET_UNKNOWN_TID = 4	// unexpected unknown TID
+};
+
+typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb);
+
+/*
+ * Returns a pointer to the first byte of the CPL header in an sk_buff that
+ * contains a CPL message.
+ */
+static inline void *cplhdr(struct sk_buff *skb)
+{
+	return skb->data;
+}
+
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
+
+union listen_entry {
+	struct t3c_tid_entry t3c_tid;
+	union listen_entry *next;
+};
+
+union active_open_entry {
+	struct t3c_tid_entry t3c_tid;
+	union active_open_entry *next;
+};
+
+/*
+ * Holds the size, base address, free list start, etc of the TID, server TID,
+ * and active-open TID tables for a TOE.  The tables themselves are allocated
+ * dynamically.
+ */
+struct tid_info {
+	struct t3c_tid_entry *tid_tab;
+	unsigned int ntids;
+	atomic_t tids_in_use;
+
+	union listen_entry *stid_tab;
+	unsigned int nstids;
+	unsigned int stid_base;
+
+	union active_open_entry *atid_tab;
+	unsigned int natids;
+	unsigned int atid_base;
+
+	/*
+	 * The following members are accessed R/W so we put them in their own
+	 * cache lines.
+	 *
+	 * XXX We could combine the atid fields above with the lock here since
+	 * atids are use once (unlike other tids).  OTOH the above fields are
+	 * usually in cache due to tid_tab.
+	 */
+	spinlock_t atid_lock ____cacheline_aligned_in_smp;
+	union active_open_entry *afree;
+	unsigned int atids_in_use;
+
+	spinlock_t stid_lock ____cacheline_aligned;
+	union listen_entry *sfree;
+	unsigned int stids_in_use;
+};
+
+struct t3c_data {
+	struct list_head list_node;
+	struct t3cdev *dev;
+	unsigned int tx_max_chunk;  /* max payload for TX_DATA */
+	unsigned int max_wrs;       /* max in-flight WRs per connection */
+	unsigned int ddp_llimit;    /* DDP parameters */
+	unsigned int ddp_ulimit;
+	unsigned int ddp_tagmask;
+	unsigned int nmtus;
+	const unsigned short *mtus;
+	struct tid_info tid_maps;
+};
+
+/*
+ * t3cdev -> t3c_data accessor
+ */
+#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt)
+
+/* XXX REMOVE THIS HACK WHEN 2.6.16 is published! */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#include <linux/mutex-backport.h>
+#else
+#include <linux/mutex.h>
+#endif /* XXX end of hack */
+
+extern struct mutex t3cdev_db_lock;
+extern struct list_head t3cdev_list;
+
+#endif




More information about the general mailing list