[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