[openib-general] [PATCH 14/18] [RFC] cxgb3 Core ULP demuxer

Steve Wise swise at opengridcomputing.com
Mon Mar 6 10:09:22 PST 2006


--- old/src/linux-kernel/infiniband/hw/cxgb3/t3c/t3c.c	1969-12-31 18:00:00.000000000 -0600
+++ new/src/linux-kernel/infiniband/hw/cxgb3/t3c/t3c.c	2006-03-06 09:26:21.000000000 -0600
@@ -0,0 +1,455 @@
+/*
+ * 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);
+
+extern struct semaphore t3cdev_db_lock;
+extern struct list_head t3cdev_list;
+
+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__);
+	down(&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);
+		}
+	}
+	up(&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__);
+	down(&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);
+		}
+	}
+	up(&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 %d\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 %u\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)\n", __FUNCTION__, __FILE__, __LINE__);
+	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 %u\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 %u\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 %u\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 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):
+			break;
+		case (NETEVENT_PMTU_UPDATE):
+			break;
+		case (NETEVENT_REDIRECT):
+			break;
+		default:
+			dprintk("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_hwtid_rpl);
+	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);
--- old/src/linux-kernel/infiniband/hw/cxgb3/t3c/t3c.h	1969-12-31 18:00:00.000000000 -0600
+++ new/src/linux-kernel/infiniband/hw/cxgb3/t3c/t3c.h	2006-03-06 09:26:21.000000000 -0600
@@ -0,0 +1,173 @@
+/*
+ * 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_t)(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_t 	*handlers;
+	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_t)(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_t 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)
+
+#endif




More information about the general mailing list