18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/list.h>
368c2ecf20Sopenharmony_ci#include <linux/slab.h>
378c2ecf20Sopenharmony_ci#include <net/neighbour.h>
388c2ecf20Sopenharmony_ci#include <linux/notifier.h>
398c2ecf20Sopenharmony_ci#include <linux/atomic.h>
408c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
418c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
428c2ecf20Sopenharmony_ci#include <net/netevent.h>
438c2ecf20Sopenharmony_ci#include <linux/highmem.h>
448c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
458c2ecf20Sopenharmony_ci#include <linux/export.h>
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#include "common.h"
488c2ecf20Sopenharmony_ci#include "regs.h"
498c2ecf20Sopenharmony_ci#include "cxgb3_ioctl.h"
508c2ecf20Sopenharmony_ci#include "cxgb3_ctl_defs.h"
518c2ecf20Sopenharmony_ci#include "cxgb3_defs.h"
528c2ecf20Sopenharmony_ci#include "l2t.h"
538c2ecf20Sopenharmony_ci#include "firmware_exports.h"
548c2ecf20Sopenharmony_ci#include "cxgb3_offload.h"
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic LIST_HEAD(client_list);
578c2ecf20Sopenharmony_cistatic LIST_HEAD(ofld_dev_list);
588c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(cxgb3_db_lock);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(adapter_list_lock);
618c2ecf20Sopenharmony_cistatic LIST_HEAD(adapter_list);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const unsigned int MAX_ATIDS = 64 * 1024;
648c2ecf20Sopenharmony_cistatic const unsigned int ATID_BASE = 0x10000;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void cxgb_neigh_update(struct neighbour *neigh);
678c2ecf20Sopenharmony_cistatic void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
688c2ecf20Sopenharmony_ci			  struct neighbour *neigh, const void *daddr);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline int offload_activated(struct t3cdev *tdev)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	const struct adapter *adapter = tdev2adap(tdev);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/**
788c2ecf20Sopenharmony_ci *	cxgb3_register_client - register an offload client
798c2ecf20Sopenharmony_ci *	@client: the client
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci *	Add the client to the client list,
828c2ecf20Sopenharmony_ci *	and call backs the client for each activated offload device
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_civoid cxgb3_register_client(struct cxgb3_client *client)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct t3cdev *tdev;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
898c2ecf20Sopenharmony_ci	list_add_tail(&client->client_list, &client_list);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (client->add) {
928c2ecf20Sopenharmony_ci		list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
938c2ecf20Sopenharmony_ci			if (offload_activated(tdev))
948c2ecf20Sopenharmony_ci				client->add(tdev);
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_register_client);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/**
1038c2ecf20Sopenharmony_ci *	cxgb3_unregister_client - unregister an offload client
1048c2ecf20Sopenharmony_ci *	@client: the client
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci *	Remove the client to the client list,
1078c2ecf20Sopenharmony_ci *	and call backs the client for each activated offload device.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_civoid cxgb3_unregister_client(struct cxgb3_client *client)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct t3cdev *tdev;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
1148c2ecf20Sopenharmony_ci	list_del(&client->client_list);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (client->remove) {
1178c2ecf20Sopenharmony_ci		list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
1188c2ecf20Sopenharmony_ci			if (offload_activated(tdev))
1198c2ecf20Sopenharmony_ci				client->remove(tdev);
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_unregister_client);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/**
1288c2ecf20Sopenharmony_ci *	cxgb3_add_clients - activate registered clients for an offload device
1298c2ecf20Sopenharmony_ci *	@tdev: the offload device
1308c2ecf20Sopenharmony_ci *
1318c2ecf20Sopenharmony_ci *	Call backs all registered clients once a offload device is activated
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_civoid cxgb3_add_clients(struct t3cdev *tdev)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct cxgb3_client *client;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
1388c2ecf20Sopenharmony_ci	list_for_each_entry(client, &client_list, client_list) {
1398c2ecf20Sopenharmony_ci		if (client->add)
1408c2ecf20Sopenharmony_ci			client->add(tdev);
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/**
1468c2ecf20Sopenharmony_ci *	cxgb3_remove_clients - deactivates registered clients
1478c2ecf20Sopenharmony_ci *			       for an offload device
1488c2ecf20Sopenharmony_ci *	@tdev: the offload device
1498c2ecf20Sopenharmony_ci *
1508c2ecf20Sopenharmony_ci *	Call backs all registered clients once a offload device is deactivated
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_civoid cxgb3_remove_clients(struct t3cdev *tdev)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct cxgb3_client *client;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
1578c2ecf20Sopenharmony_ci	list_for_each_entry(client, &client_list, client_list) {
1588c2ecf20Sopenharmony_ci		if (client->remove)
1598c2ecf20Sopenharmony_ci			client->remove(tdev);
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_civoid cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct cxgb3_client *client;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
1698c2ecf20Sopenharmony_ci	list_for_each_entry(client, &client_list, client_list) {
1708c2ecf20Sopenharmony_ci		if (client->event_handler)
1718c2ecf20Sopenharmony_ci			client->event_handler(tdev, event, port);
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic struct net_device *get_iff_from_mac(struct adapter *adapter,
1778c2ecf20Sopenharmony_ci					   const unsigned char *mac,
1788c2ecf20Sopenharmony_ci					   unsigned int vlan)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	int i;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	for_each_port(adapter, i) {
1838c2ecf20Sopenharmony_ci		struct net_device *dev = adapter->port[i];
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		if (ether_addr_equal(dev->dev_addr, mac)) {
1868c2ecf20Sopenharmony_ci			rcu_read_lock();
1878c2ecf20Sopenharmony_ci			if (vlan && vlan != VLAN_VID_MASK) {
1888c2ecf20Sopenharmony_ci				dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), vlan);
1898c2ecf20Sopenharmony_ci			} else if (netif_is_bond_slave(dev)) {
1908c2ecf20Sopenharmony_ci				struct net_device *upper_dev;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci				while ((upper_dev =
1938c2ecf20Sopenharmony_ci					netdev_master_upper_dev_get_rcu(dev)))
1948c2ecf20Sopenharmony_ci					dev = upper_dev;
1958c2ecf20Sopenharmony_ci			}
1968c2ecf20Sopenharmony_ci			rcu_read_unlock();
1978c2ecf20Sopenharmony_ci			return dev;
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci	return NULL;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
2048c2ecf20Sopenharmony_ci			      void *data)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	int i;
2078c2ecf20Sopenharmony_ci	int ret = 0;
2088c2ecf20Sopenharmony_ci	unsigned int val = 0;
2098c2ecf20Sopenharmony_ci	struct ulp_iscsi_info *uiip = data;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	switch (req) {
2128c2ecf20Sopenharmony_ci	case ULP_ISCSI_GET_PARAMS:
2138c2ecf20Sopenharmony_ci		uiip->pdev = adapter->pdev;
2148c2ecf20Sopenharmony_ci		uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
2158c2ecf20Sopenharmony_ci		uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
2168c2ecf20Sopenharmony_ci		uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ);
2198c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++, val >>= 8)
2208c2ecf20Sopenharmony_ci			uiip->pgsz_factor[i] = val & 0xFF;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		val = t3_read_reg(adapter, A_TP_PARA_REG7);
2238c2ecf20Sopenharmony_ci		uiip->max_txsz =
2248c2ecf20Sopenharmony_ci		uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0,
2258c2ecf20Sopenharmony_ci				     (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1);
2268c2ecf20Sopenharmony_ci		/*
2278c2ecf20Sopenharmony_ci		 * On tx, the iscsi pdu has to be <= tx page size and has to
2288c2ecf20Sopenharmony_ci		 * fit into the Tx PM FIFO.
2298c2ecf20Sopenharmony_ci		 */
2308c2ecf20Sopenharmony_ci		val = min(adapter->params.tp.tx_pg_size,
2318c2ecf20Sopenharmony_ci			  t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
2328c2ecf20Sopenharmony_ci		uiip->max_txsz = min(val, uiip->max_txsz);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		/* set MaxRxData to 16224 */
2358c2ecf20Sopenharmony_ci		val = t3_read_reg(adapter, A_TP_PARA_REG2);
2368c2ecf20Sopenharmony_ci		if ((val >> S_MAXRXDATA) != 0x3f60) {
2378c2ecf20Sopenharmony_ci			val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE);
2388c2ecf20Sopenharmony_ci			val |= V_MAXRXDATA(0x3f60);
2398c2ecf20Sopenharmony_ci			pr_info("%s, iscsi set MaxRxData to 16224 (0x%x)\n",
2408c2ecf20Sopenharmony_ci				adapter->name, val);
2418c2ecf20Sopenharmony_ci			t3_write_reg(adapter, A_TP_PARA_REG2, val);
2428c2ecf20Sopenharmony_ci		}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		/*
2458c2ecf20Sopenharmony_ci		 * on rx, the iscsi pdu has to be < rx page size and the
2468c2ecf20Sopenharmony_ci		 * the max rx data length programmed in TP
2478c2ecf20Sopenharmony_ci		 */
2488c2ecf20Sopenharmony_ci		val = min(adapter->params.tp.rx_pg_size,
2498c2ecf20Sopenharmony_ci			  ((t3_read_reg(adapter, A_TP_PARA_REG2)) >>
2508c2ecf20Sopenharmony_ci				S_MAXRXDATA) & M_MAXRXDATA);
2518c2ecf20Sopenharmony_ci		uiip->max_rxsz = min(val, uiip->max_rxsz);
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci	case ULP_ISCSI_SET_PARAMS:
2548c2ecf20Sopenharmony_ci		t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
2558c2ecf20Sopenharmony_ci		/* program the ddp page sizes */
2568c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
2578c2ecf20Sopenharmony_ci			val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
2588c2ecf20Sopenharmony_ci		if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) {
2598c2ecf20Sopenharmony_ci			pr_info("%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u\n",
2608c2ecf20Sopenharmony_ci				adapter->name, val, uiip->pgsz_factor[0],
2618c2ecf20Sopenharmony_ci				uiip->pgsz_factor[1], uiip->pgsz_factor[2],
2628c2ecf20Sopenharmony_ci				uiip->pgsz_factor[3]);
2638c2ecf20Sopenharmony_ci			t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val);
2648c2ecf20Sopenharmony_ci		}
2658c2ecf20Sopenharmony_ci		break;
2668c2ecf20Sopenharmony_ci	default:
2678c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci	return ret;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci/* Response queue used for RDMA events. */
2738c2ecf20Sopenharmony_ci#define ASYNC_NOTIF_RSPQ 0
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int ret = 0;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	switch (req) {
2808c2ecf20Sopenharmony_ci	case RDMA_GET_PARAMS: {
2818c2ecf20Sopenharmony_ci		struct rdma_info *rdma = data;
2828c2ecf20Sopenharmony_ci		struct pci_dev *pdev = adapter->pdev;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		rdma->udbell_physbase = pci_resource_start(pdev, 2);
2858c2ecf20Sopenharmony_ci		rdma->udbell_len = pci_resource_len(pdev, 2);
2868c2ecf20Sopenharmony_ci		rdma->tpt_base =
2878c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
2888c2ecf20Sopenharmony_ci		rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
2898c2ecf20Sopenharmony_ci		rdma->pbl_base =
2908c2ecf20Sopenharmony_ci			t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
2918c2ecf20Sopenharmony_ci		rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
2928c2ecf20Sopenharmony_ci		rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
2938c2ecf20Sopenharmony_ci		rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
2948c2ecf20Sopenharmony_ci		rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL;
2958c2ecf20Sopenharmony_ci		rdma->pdev = pdev;
2968c2ecf20Sopenharmony_ci		break;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	case RDMA_CQ_OP:{
2998c2ecf20Sopenharmony_ci		unsigned long flags;
3008c2ecf20Sopenharmony_ci		struct rdma_cq_op *rdma = data;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		/* may be called in any context */
3038c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adapter->sge.reg_lock, flags);
3048c2ecf20Sopenharmony_ci		ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op,
3058c2ecf20Sopenharmony_ci					rdma->credits);
3068c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci	case RDMA_GET_MEM:{
3108c2ecf20Sopenharmony_ci		struct ch_mem_range *t = data;
3118c2ecf20Sopenharmony_ci		struct mc7 *mem;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		if ((t->addr & 7) || (t->len & 7))
3148c2ecf20Sopenharmony_ci			return -EINVAL;
3158c2ecf20Sopenharmony_ci		if (t->mem_id == MEM_CM)
3168c2ecf20Sopenharmony_ci			mem = &adapter->cm;
3178c2ecf20Sopenharmony_ci		else if (t->mem_id == MEM_PMRX)
3188c2ecf20Sopenharmony_ci			mem = &adapter->pmrx;
3198c2ecf20Sopenharmony_ci		else if (t->mem_id == MEM_PMTX)
3208c2ecf20Sopenharmony_ci			mem = &adapter->pmtx;
3218c2ecf20Sopenharmony_ci		else
3228c2ecf20Sopenharmony_ci			return -EINVAL;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		ret =
3258c2ecf20Sopenharmony_ci			t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
3268c2ecf20Sopenharmony_ci					(u64 *) t->buf);
3278c2ecf20Sopenharmony_ci		if (ret)
3288c2ecf20Sopenharmony_ci			return ret;
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	case RDMA_CQ_SETUP:{
3328c2ecf20Sopenharmony_ci		struct rdma_cq_setup *rdma = data;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		spin_lock_irq(&adapter->sge.reg_lock);
3358c2ecf20Sopenharmony_ci		ret =
3368c2ecf20Sopenharmony_ci			t3_sge_init_cqcntxt(adapter, rdma->id,
3378c2ecf20Sopenharmony_ci					rdma->base_addr, rdma->size,
3388c2ecf20Sopenharmony_ci					ASYNC_NOTIF_RSPQ,
3398c2ecf20Sopenharmony_ci					rdma->ovfl_mode, rdma->credits,
3408c2ecf20Sopenharmony_ci					rdma->credit_thres);
3418c2ecf20Sopenharmony_ci		spin_unlock_irq(&adapter->sge.reg_lock);
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	case RDMA_CQ_DISABLE:
3458c2ecf20Sopenharmony_ci		spin_lock_irq(&adapter->sge.reg_lock);
3468c2ecf20Sopenharmony_ci		ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
3478c2ecf20Sopenharmony_ci		spin_unlock_irq(&adapter->sge.reg_lock);
3488c2ecf20Sopenharmony_ci		break;
3498c2ecf20Sopenharmony_ci	case RDMA_CTRL_QP_SETUP:{
3508c2ecf20Sopenharmony_ci		struct rdma_ctrlqp_setup *rdma = data;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		spin_lock_irq(&adapter->sge.reg_lock);
3538c2ecf20Sopenharmony_ci		ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
3548c2ecf20Sopenharmony_ci						SGE_CNTXT_RDMA,
3558c2ecf20Sopenharmony_ci						ASYNC_NOTIF_RSPQ,
3568c2ecf20Sopenharmony_ci						rdma->base_addr, rdma->size,
3578c2ecf20Sopenharmony_ci						FW_RI_TID_START, 1, 0);
3588c2ecf20Sopenharmony_ci		spin_unlock_irq(&adapter->sge.reg_lock);
3598c2ecf20Sopenharmony_ci		break;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	case RDMA_GET_MIB: {
3628c2ecf20Sopenharmony_ci		spin_lock(&adapter->stats_lock);
3638c2ecf20Sopenharmony_ci		t3_tp_get_mib_stats(adapter, (struct tp_mib_stats *)data);
3648c2ecf20Sopenharmony_ci		spin_unlock(&adapter->stats_lock);
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci	default:
3688c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	return ret;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct adapter *adapter = tdev2adap(tdev);
3768c2ecf20Sopenharmony_ci	struct tid_range *tid;
3778c2ecf20Sopenharmony_ci	struct mtutab *mtup;
3788c2ecf20Sopenharmony_ci	struct iff_mac *iffmacp;
3798c2ecf20Sopenharmony_ci	struct ddp_params *ddpp;
3808c2ecf20Sopenharmony_ci	struct adap_ports *ports;
3818c2ecf20Sopenharmony_ci	struct ofld_page_info *rx_page_info;
3828c2ecf20Sopenharmony_ci	struct tp_params *tp = &adapter->params.tp;
3838c2ecf20Sopenharmony_ci	int i;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	switch (req) {
3868c2ecf20Sopenharmony_ci	case GET_MAX_OUTSTANDING_WR:
3878c2ecf20Sopenharmony_ci		*(unsigned int *)data = FW_WR_NUM;
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci	case GET_WR_LEN:
3908c2ecf20Sopenharmony_ci		*(unsigned int *)data = WR_FLITS;
3918c2ecf20Sopenharmony_ci		break;
3928c2ecf20Sopenharmony_ci	case GET_TX_MAX_CHUNK:
3938c2ecf20Sopenharmony_ci		*(unsigned int *)data = 1 << 20;	/* 1MB */
3948c2ecf20Sopenharmony_ci		break;
3958c2ecf20Sopenharmony_ci	case GET_TID_RANGE:
3968c2ecf20Sopenharmony_ci		tid = data;
3978c2ecf20Sopenharmony_ci		tid->num = t3_mc5_size(&adapter->mc5) -
3988c2ecf20Sopenharmony_ci		    adapter->params.mc5.nroutes -
3998c2ecf20Sopenharmony_ci		    adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
4008c2ecf20Sopenharmony_ci		tid->base = 0;
4018c2ecf20Sopenharmony_ci		break;
4028c2ecf20Sopenharmony_ci	case GET_STID_RANGE:
4038c2ecf20Sopenharmony_ci		tid = data;
4048c2ecf20Sopenharmony_ci		tid->num = adapter->params.mc5.nservers;
4058c2ecf20Sopenharmony_ci		tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
4068c2ecf20Sopenharmony_ci		    adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci	case GET_L2T_CAPACITY:
4098c2ecf20Sopenharmony_ci		*(unsigned int *)data = 2048;
4108c2ecf20Sopenharmony_ci		break;
4118c2ecf20Sopenharmony_ci	case GET_MTUS:
4128c2ecf20Sopenharmony_ci		mtup = data;
4138c2ecf20Sopenharmony_ci		mtup->size = NMTUS;
4148c2ecf20Sopenharmony_ci		mtup->mtus = adapter->params.mtus;
4158c2ecf20Sopenharmony_ci		break;
4168c2ecf20Sopenharmony_ci	case GET_IFF_FROM_MAC:
4178c2ecf20Sopenharmony_ci		iffmacp = data;
4188c2ecf20Sopenharmony_ci		iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
4198c2ecf20Sopenharmony_ci						iffmacp->vlan_tag &
4208c2ecf20Sopenharmony_ci						VLAN_VID_MASK);
4218c2ecf20Sopenharmony_ci		break;
4228c2ecf20Sopenharmony_ci	case GET_DDP_PARAMS:
4238c2ecf20Sopenharmony_ci		ddpp = data;
4248c2ecf20Sopenharmony_ci		ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
4258c2ecf20Sopenharmony_ci		ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
4268c2ecf20Sopenharmony_ci		ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
4278c2ecf20Sopenharmony_ci		break;
4288c2ecf20Sopenharmony_ci	case GET_PORTS:
4298c2ecf20Sopenharmony_ci		ports = data;
4308c2ecf20Sopenharmony_ci		ports->nports = adapter->params.nports;
4318c2ecf20Sopenharmony_ci		for_each_port(adapter, i)
4328c2ecf20Sopenharmony_ci			ports->lldevs[i] = adapter->port[i];
4338c2ecf20Sopenharmony_ci		break;
4348c2ecf20Sopenharmony_ci	case ULP_ISCSI_GET_PARAMS:
4358c2ecf20Sopenharmony_ci	case ULP_ISCSI_SET_PARAMS:
4368c2ecf20Sopenharmony_ci		if (!offload_running(adapter))
4378c2ecf20Sopenharmony_ci			return -EAGAIN;
4388c2ecf20Sopenharmony_ci		return cxgb_ulp_iscsi_ctl(adapter, req, data);
4398c2ecf20Sopenharmony_ci	case RDMA_GET_PARAMS:
4408c2ecf20Sopenharmony_ci	case RDMA_CQ_OP:
4418c2ecf20Sopenharmony_ci	case RDMA_CQ_SETUP:
4428c2ecf20Sopenharmony_ci	case RDMA_CQ_DISABLE:
4438c2ecf20Sopenharmony_ci	case RDMA_CTRL_QP_SETUP:
4448c2ecf20Sopenharmony_ci	case RDMA_GET_MEM:
4458c2ecf20Sopenharmony_ci	case RDMA_GET_MIB:
4468c2ecf20Sopenharmony_ci		if (!offload_running(adapter))
4478c2ecf20Sopenharmony_ci			return -EAGAIN;
4488c2ecf20Sopenharmony_ci		return cxgb_rdma_ctl(adapter, req, data);
4498c2ecf20Sopenharmony_ci	case GET_RX_PAGE_INFO:
4508c2ecf20Sopenharmony_ci		rx_page_info = data;
4518c2ecf20Sopenharmony_ci		rx_page_info->page_size = tp->rx_pg_size;
4528c2ecf20Sopenharmony_ci		rx_page_info->num = tp->rx_num_pgs;
4538c2ecf20Sopenharmony_ci		break;
4548c2ecf20Sopenharmony_ci	case GET_ISCSI_IPV4ADDR: {
4558c2ecf20Sopenharmony_ci		struct iscsi_ipv4addr *p = data;
4568c2ecf20Sopenharmony_ci		struct port_info *pi = netdev_priv(p->dev);
4578c2ecf20Sopenharmony_ci		p->ipv4addr = pi->iscsi_ipv4addr;
4588c2ecf20Sopenharmony_ci		break;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci	case GET_EMBEDDED_INFO: {
4618c2ecf20Sopenharmony_ci		struct ch_embedded_info *e = data;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci		spin_lock(&adapter->stats_lock);
4648c2ecf20Sopenharmony_ci		t3_get_fw_version(adapter, &e->fw_vers);
4658c2ecf20Sopenharmony_ci		t3_get_tp_version(adapter, &e->tp_vers);
4668c2ecf20Sopenharmony_ci		spin_unlock(&adapter->stats_lock);
4678c2ecf20Sopenharmony_ci		break;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci	default:
4708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci/*
4768c2ecf20Sopenharmony_ci * Dummy handler for Rx offload packets in case we get an offload packet before
4778c2ecf20Sopenharmony_ci * proper processing is setup.  This complains and drops the packet as it isn't
4788c2ecf20Sopenharmony_ci * normal to get offload packets at this stage.
4798c2ecf20Sopenharmony_ci */
4808c2ecf20Sopenharmony_cistatic int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
4818c2ecf20Sopenharmony_ci				int n)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	while (n--)
4848c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skbs[n]);
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_civoid cxgb3_set_dummy_ops(struct t3cdev *dev)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	dev->recv = rx_offload_blackhole;
4958c2ecf20Sopenharmony_ci	dev->neigh_update = dummy_neigh_update;
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/*
4998c2ecf20Sopenharmony_ci * Free an active-open TID.
5008c2ecf20Sopenharmony_ci */
5018c2ecf20Sopenharmony_civoid *cxgb3_free_atid(struct t3cdev *tdev, int atid)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
5048c2ecf20Sopenharmony_ci	union active_open_entry *p = atid2entry(t, atid);
5058c2ecf20Sopenharmony_ci	void *ctx = p->t3c_tid.ctx;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	spin_lock_bh(&t->atid_lock);
5088c2ecf20Sopenharmony_ci	p->next = t->afree;
5098c2ecf20Sopenharmony_ci	t->afree = p;
5108c2ecf20Sopenharmony_ci	t->atids_in_use--;
5118c2ecf20Sopenharmony_ci	spin_unlock_bh(&t->atid_lock);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	return ctx;
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_free_atid);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci/*
5198c2ecf20Sopenharmony_ci * Free a server TID and return it to the free pool.
5208c2ecf20Sopenharmony_ci */
5218c2ecf20Sopenharmony_civoid cxgb3_free_stid(struct t3cdev *tdev, int stid)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
5248c2ecf20Sopenharmony_ci	union listen_entry *p = stid2entry(t, stid);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
5278c2ecf20Sopenharmony_ci	p->next = t->sfree;
5288c2ecf20Sopenharmony_ci	t->sfree = p;
5298c2ecf20Sopenharmony_ci	t->stids_in_use--;
5308c2ecf20Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_free_stid);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_civoid cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
5368c2ecf20Sopenharmony_ci		      void *ctx, unsigned int tid)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	t->tid_tab[tid].client = client;
5418c2ecf20Sopenharmony_ci	t->tid_tab[tid].ctx = ctx;
5428c2ecf20Sopenharmony_ci	atomic_inc(&t->tids_in_use);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_insert_tid);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/*
5488c2ecf20Sopenharmony_ci * Populate a TID_RELEASE WR.  The skb must be already propely sized.
5498c2ecf20Sopenharmony_ci */
5508c2ecf20Sopenharmony_cistatic inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	struct cpl_tid_release *req;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	skb->priority = CPL_PRIORITY_SETUP;
5558c2ecf20Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
5568c2ecf20Sopenharmony_ci	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
5578c2ecf20Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic void t3_process_tid_release_list(struct work_struct *work)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct t3c_data *td = container_of(work, struct t3c_data,
5638c2ecf20Sopenharmony_ci					   tid_release_task);
5648c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5658c2ecf20Sopenharmony_ci	struct t3cdev *tdev = td->dev;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	spin_lock_bh(&td->tid_release_lock);
5698c2ecf20Sopenharmony_ci	while (td->tid_release_list) {
5708c2ecf20Sopenharmony_ci		struct t3c_tid_entry *p = td->tid_release_list;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		td->tid_release_list = p->ctx;
5738c2ecf20Sopenharmony_ci		spin_unlock_bh(&td->tid_release_lock);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci		skb = alloc_skb(sizeof(struct cpl_tid_release),
5768c2ecf20Sopenharmony_ci				GFP_KERNEL);
5778c2ecf20Sopenharmony_ci		if (!skb)
5788c2ecf20Sopenharmony_ci			skb = td->nofail_skb;
5798c2ecf20Sopenharmony_ci		if (!skb) {
5808c2ecf20Sopenharmony_ci			spin_lock_bh(&td->tid_release_lock);
5818c2ecf20Sopenharmony_ci			p->ctx = (void *)td->tid_release_list;
5828c2ecf20Sopenharmony_ci			td->tid_release_list = p;
5838c2ecf20Sopenharmony_ci			break;
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci		mk_tid_release(skb, p - td->tid_maps.tid_tab);
5868c2ecf20Sopenharmony_ci		cxgb3_ofld_send(tdev, skb);
5878c2ecf20Sopenharmony_ci		p->ctx = NULL;
5888c2ecf20Sopenharmony_ci		if (skb == td->nofail_skb)
5898c2ecf20Sopenharmony_ci			td->nofail_skb =
5908c2ecf20Sopenharmony_ci				alloc_skb(sizeof(struct cpl_tid_release),
5918c2ecf20Sopenharmony_ci					GFP_KERNEL);
5928c2ecf20Sopenharmony_ci		spin_lock_bh(&td->tid_release_lock);
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci	td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1;
5958c2ecf20Sopenharmony_ci	spin_unlock_bh(&td->tid_release_lock);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (!td->nofail_skb)
5988c2ecf20Sopenharmony_ci		td->nofail_skb =
5998c2ecf20Sopenharmony_ci			alloc_skb(sizeof(struct cpl_tid_release),
6008c2ecf20Sopenharmony_ci				GFP_KERNEL);
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci/* use ctx as a next pointer in the tid release list */
6048c2ecf20Sopenharmony_civoid cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct t3c_data *td = T3C_DATA(tdev);
6078c2ecf20Sopenharmony_ci	struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	spin_lock_bh(&td->tid_release_lock);
6108c2ecf20Sopenharmony_ci	p->ctx = (void *)td->tid_release_list;
6118c2ecf20Sopenharmony_ci	p->client = NULL;
6128c2ecf20Sopenharmony_ci	td->tid_release_list = p;
6138c2ecf20Sopenharmony_ci	if (!p->ctx || td->release_list_incomplete)
6148c2ecf20Sopenharmony_ci		schedule_work(&td->tid_release_task);
6158c2ecf20Sopenharmony_ci	spin_unlock_bh(&td->tid_release_lock);
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_queue_tid_release);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci/*
6218c2ecf20Sopenharmony_ci * Remove a tid from the TID table.  A client may defer processing its last
6228c2ecf20Sopenharmony_ci * CPL message if it is locked at the time it arrives, and while the message
6238c2ecf20Sopenharmony_ci * sits in the client's backlog the TID may be reused for another connection.
6248c2ecf20Sopenharmony_ci * To handle this we atomically switch the TID association if it still points
6258c2ecf20Sopenharmony_ci * to the original client context.
6268c2ecf20Sopenharmony_ci */
6278c2ecf20Sopenharmony_civoid cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	BUG_ON(tid >= t->ntids);
6328c2ecf20Sopenharmony_ci	if (tdev->type == T3A)
6338c2ecf20Sopenharmony_ci		(void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
6348c2ecf20Sopenharmony_ci	else {
6358c2ecf20Sopenharmony_ci		struct sk_buff *skb;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
6388c2ecf20Sopenharmony_ci		if (likely(skb)) {
6398c2ecf20Sopenharmony_ci			mk_tid_release(skb, tid);
6408c2ecf20Sopenharmony_ci			cxgb3_ofld_send(tdev, skb);
6418c2ecf20Sopenharmony_ci			t->tid_tab[tid].ctx = NULL;
6428c2ecf20Sopenharmony_ci		} else
6438c2ecf20Sopenharmony_ci			cxgb3_queue_tid_release(tdev, tid);
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci	atomic_dec(&t->tids_in_use);
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_remove_tid);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ciint cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
6518c2ecf20Sopenharmony_ci		     void *ctx)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	int atid = -1;
6548c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	spin_lock_bh(&t->atid_lock);
6578c2ecf20Sopenharmony_ci	if (t->afree &&
6588c2ecf20Sopenharmony_ci	    t->atids_in_use + atomic_read(&t->tids_in_use) + MC5_MIN_TIDS <=
6598c2ecf20Sopenharmony_ci	    t->ntids) {
6608c2ecf20Sopenharmony_ci		union active_open_entry *p = t->afree;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		atid = (p - t->atid_tab) + t->atid_base;
6638c2ecf20Sopenharmony_ci		t->afree = p->next;
6648c2ecf20Sopenharmony_ci		p->t3c_tid.ctx = ctx;
6658c2ecf20Sopenharmony_ci		p->t3c_tid.client = client;
6668c2ecf20Sopenharmony_ci		t->atids_in_use++;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	spin_unlock_bh(&t->atid_lock);
6698c2ecf20Sopenharmony_ci	return atid;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_alloc_atid);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ciint cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
6758c2ecf20Sopenharmony_ci		     void *ctx)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	int stid = -1;
6788c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
6818c2ecf20Sopenharmony_ci	if (t->sfree) {
6828c2ecf20Sopenharmony_ci		union listen_entry *p = t->sfree;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		stid = (p - t->stid_tab) + t->stid_base;
6858c2ecf20Sopenharmony_ci		t->sfree = p->next;
6868c2ecf20Sopenharmony_ci		p->t3c_tid.ctx = ctx;
6878c2ecf20Sopenharmony_ci		p->t3c_tid.client = client;
6888c2ecf20Sopenharmony_ci		t->stids_in_use++;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
6918c2ecf20Sopenharmony_ci	return stid;
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_alloc_stid);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci/* Get the t3cdev associated with a net_device */
6978c2ecf20Sopenharmony_cistruct t3cdev *dev2t3cdev(struct net_device *dev)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return (struct t3cdev *)pi->adapter;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev2t3cdev);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	struct cpl_smt_write_rpl *rpl = cplhdr(skb);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE)
7118c2ecf20Sopenharmony_ci		pr_err("Unexpected SMT_WRITE_RPL status %u for entry %u\n",
7128c2ecf20Sopenharmony_ci		       rpl->status, GET_TID(rpl));
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	return CPL_RET_BUF_DONE;
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE)
7228c2ecf20Sopenharmony_ci		pr_err("Unexpected L2T_WRITE_RPL status %u for entry %u\n",
7238c2ecf20Sopenharmony_ci		       rpl->status, GET_TID(rpl));
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	return CPL_RET_BUF_DONE;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct cpl_rte_write_rpl *rpl = cplhdr(skb);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE)
7338c2ecf20Sopenharmony_ci		pr_err("Unexpected RTE_WRITE_RPL status %u for entry %u\n",
7348c2ecf20Sopenharmony_ci		       rpl->status, GET_TID(rpl));
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	return CPL_RET_BUF_DONE;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct cpl_act_open_rpl *rpl = cplhdr(skb);
7428c2ecf20Sopenharmony_ci	unsigned int atid = G_TID(ntohl(rpl->atid));
7438c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
7468c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client &&
7478c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers &&
7488c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
7498c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
7508c2ecf20Sopenharmony_ci								    t3c_tid->
7518c2ecf20Sopenharmony_ci								    ctx);
7528c2ecf20Sopenharmony_ci	} else {
7538c2ecf20Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
7548c2ecf20Sopenharmony_ci		       dev->name, CPL_ACT_OPEN_RPL);
7558c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	union opcode_tid *p = cplhdr(skb);
7628c2ecf20Sopenharmony_ci	unsigned int stid = G_TID(ntohl(p->opcode_tid));
7638c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
7668c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
7678c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[p->opcode]) {
7688c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[p->opcode] (dev, skb,
7698c2ecf20Sopenharmony_ci							     t3c_tid->ctx);
7708c2ecf20Sopenharmony_ci	} else {
7718c2ecf20Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
7728c2ecf20Sopenharmony_ci		       dev->name, p->opcode);
7738c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	union opcode_tid *p = cplhdr(skb);
7808c2ecf20Sopenharmony_ci	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
7818c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
7848c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
7858c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[p->opcode]) {
7868c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[p->opcode]
7878c2ecf20Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
7888c2ecf20Sopenharmony_ci	} else {
7898c2ecf20Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
7908c2ecf20Sopenharmony_ci		       dev->name, p->opcode);
7918c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistatic int do_cr(struct t3cdev *dev, struct sk_buff *skb)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct cpl_pass_accept_req *req = cplhdr(skb);
7988c2ecf20Sopenharmony_ci	unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
7998c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
8008c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
8018c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (unlikely(tid >= t->ntids)) {
8048c2ecf20Sopenharmony_ci		printk("%s: passive open TID %u too large\n",
8058c2ecf20Sopenharmony_ci		       dev->name, tid);
8068c2ecf20Sopenharmony_ci		t3_fatal_err(tdev2adap(dev));
8078c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE;
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	t3c_tid = lookup_stid(t, stid);
8118c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
8128c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
8138c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
8148c2ecf20Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
8158c2ecf20Sopenharmony_ci	} else {
8168c2ecf20Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
8178c2ecf20Sopenharmony_ci		       dev->name, CPL_PASS_ACCEPT_REQ);
8188c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci/*
8238c2ecf20Sopenharmony_ci * Returns an sk_buff for a reply CPL message of size len.  If the input
8248c2ecf20Sopenharmony_ci * sk_buff has no other users it is trimmed and reused, otherwise a new buffer
8258c2ecf20Sopenharmony_ci * is allocated.  The input skb must be of size at least len.  Note that this
8268c2ecf20Sopenharmony_ci * operation does not destroy the original skb data even if it decides to reuse
8278c2ecf20Sopenharmony_ci * the buffer.
8288c2ecf20Sopenharmony_ci */
8298c2ecf20Sopenharmony_cistatic struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len,
8308c2ecf20Sopenharmony_ci					       gfp_t gfp)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	if (likely(!skb_cloned(skb))) {
8338c2ecf20Sopenharmony_ci		BUG_ON(skb->len < len);
8348c2ecf20Sopenharmony_ci		__skb_trim(skb, len);
8358c2ecf20Sopenharmony_ci		skb_get(skb);
8368c2ecf20Sopenharmony_ci	} else {
8378c2ecf20Sopenharmony_ci		skb = alloc_skb(len, gfp);
8388c2ecf20Sopenharmony_ci		if (skb)
8398c2ecf20Sopenharmony_ci			__skb_put(skb, len);
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci	return skb;
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	union opcode_tid *p = cplhdr(skb);
8478c2ecf20Sopenharmony_ci	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
8488c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
8518c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
8528c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[p->opcode]) {
8538c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[p->opcode]
8548c2ecf20Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
8558c2ecf20Sopenharmony_ci	} else {
8568c2ecf20Sopenharmony_ci		struct cpl_abort_req_rss *req = cplhdr(skb);
8578c2ecf20Sopenharmony_ci		struct cpl_abort_rpl *rpl;
8588c2ecf20Sopenharmony_ci		struct sk_buff *reply_skb;
8598c2ecf20Sopenharmony_ci		unsigned int tid = GET_TID(req);
8608c2ecf20Sopenharmony_ci		u8 cmd = req->status;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		if (req->status == CPL_ERR_RTX_NEG_ADVICE ||
8638c2ecf20Sopenharmony_ci		    req->status == CPL_ERR_PERSIST_NEG_ADVICE)
8648c2ecf20Sopenharmony_ci			goto out;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		reply_skb = cxgb3_get_cpl_reply_skb(skb,
8678c2ecf20Sopenharmony_ci						    sizeof(struct
8688c2ecf20Sopenharmony_ci							   cpl_abort_rpl),
8698c2ecf20Sopenharmony_ci						    GFP_ATOMIC);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci		if (!reply_skb) {
8728c2ecf20Sopenharmony_ci			printk("do_abort_req_rss: couldn't get skb!\n");
8738c2ecf20Sopenharmony_ci			goto out;
8748c2ecf20Sopenharmony_ci		}
8758c2ecf20Sopenharmony_ci		reply_skb->priority = CPL_PRIORITY_DATA;
8768c2ecf20Sopenharmony_ci		__skb_put(reply_skb, sizeof(struct cpl_abort_rpl));
8778c2ecf20Sopenharmony_ci		rpl = cplhdr(reply_skb);
8788c2ecf20Sopenharmony_ci		rpl->wr.wr_hi =
8798c2ecf20Sopenharmony_ci		    htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
8808c2ecf20Sopenharmony_ci		rpl->wr.wr_lo = htonl(V_WR_TID(tid));
8818c2ecf20Sopenharmony_ci		OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid));
8828c2ecf20Sopenharmony_ci		rpl->cmd = cmd;
8838c2ecf20Sopenharmony_ci		cxgb3_ofld_send(dev, reply_skb);
8848c2ecf20Sopenharmony_ciout:
8858c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_cistatic int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	struct cpl_act_establish *req = cplhdr(skb);
8928c2ecf20Sopenharmony_ci	unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
8938c2ecf20Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
8948c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
8958c2ecf20Sopenharmony_ci	unsigned int tid = GET_TID(req);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	if (unlikely(tid >= t->ntids)) {
8988c2ecf20Sopenharmony_ci		printk("%s: active establish TID %u too large\n",
8998c2ecf20Sopenharmony_ci		       dev->name, tid);
9008c2ecf20Sopenharmony_ci		t3_fatal_err(tdev2adap(dev));
9018c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	t3c_tid = lookup_atid(t, atid);
9058c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
9068c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
9078c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
9088c2ecf20Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
9098c2ecf20Sopenharmony_ci	} else {
9108c2ecf20Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
9118c2ecf20Sopenharmony_ci		       dev->name, CPL_ACT_ESTABLISH);
9128c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_cistatic int do_trace(struct t3cdev *dev, struct sk_buff *skb)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct cpl_trace_pkt *p = cplhdr(skb);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	skb->protocol = htons(0xffff);
9218c2ecf20Sopenharmony_ci	skb->dev = dev->lldev;
9228c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(*p));
9238c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
9248c2ecf20Sopenharmony_ci	netif_receive_skb(skb);
9258c2ecf20Sopenharmony_ci	return 0;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci/*
9298c2ecf20Sopenharmony_ci * That skb would better have come from process_responses() where we abuse
9308c2ecf20Sopenharmony_ci * ->priority and ->csum to carry our data.  NB: if we get to per-arch
9318c2ecf20Sopenharmony_ci * ->csum, the things might get really interesting here.
9328c2ecf20Sopenharmony_ci */
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistatic inline u32 get_hwtid(struct sk_buff *skb)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	return ntohl((__force __be32)skb->priority) >> 8 & 0xfffff;
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_cistatic inline u32 get_opcode(struct sk_buff *skb)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	return G_OPCODE(ntohl((__force __be32)skb->csum));
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cistatic int do_term(struct t3cdev *dev, struct sk_buff *skb)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	unsigned int hwtid = get_hwtid(skb);
9478c2ecf20Sopenharmony_ci	unsigned int opcode = get_opcode(skb);
9488c2ecf20Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
9518c2ecf20Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
9528c2ecf20Sopenharmony_ci	    t3c_tid->client->handlers[opcode]) {
9538c2ecf20Sopenharmony_ci		return t3c_tid->client->handlers[opcode] (dev, skb,
9548c2ecf20Sopenharmony_ci							  t3c_tid->ctx);
9558c2ecf20Sopenharmony_ci	} else {
9568c2ecf20Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
9578c2ecf20Sopenharmony_ci		       dev->name, opcode);
9588c2ecf20Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_cistatic int nb_callback(struct notifier_block *self, unsigned long event,
9638c2ecf20Sopenharmony_ci		       void *ctx)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	switch (event) {
9668c2ecf20Sopenharmony_ci	case (NETEVENT_NEIGH_UPDATE):{
9678c2ecf20Sopenharmony_ci		cxgb_neigh_update((struct neighbour *)ctx);
9688c2ecf20Sopenharmony_ci		break;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci	case (NETEVENT_REDIRECT):{
9718c2ecf20Sopenharmony_ci		struct netevent_redirect *nr = ctx;
9728c2ecf20Sopenharmony_ci		cxgb_redirect(nr->old, nr->new, nr->neigh,
9738c2ecf20Sopenharmony_ci			      nr->daddr);
9748c2ecf20Sopenharmony_ci		cxgb_neigh_update(nr->neigh);
9758c2ecf20Sopenharmony_ci		break;
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci	default:
9788c2ecf20Sopenharmony_ci		break;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci	return 0;
9818c2ecf20Sopenharmony_ci}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_cistatic struct notifier_block nb = {
9848c2ecf20Sopenharmony_ci	.notifier_call = nb_callback
9858c2ecf20Sopenharmony_ci};
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci/*
9888c2ecf20Sopenharmony_ci * Process a received packet with an unknown/unexpected CPL opcode.
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_cistatic int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	pr_err("%s: received bad CPL command 0x%x\n", dev->name, *skb->data);
9938c2ecf20Sopenharmony_ci	return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci/*
9978c2ecf20Sopenharmony_ci * Handlers for each CPL opcode
9988c2ecf20Sopenharmony_ci */
9998c2ecf20Sopenharmony_cistatic cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci/*
10028c2ecf20Sopenharmony_ci * Add a new handler to the CPL dispatch table.  A NULL handler may be supplied
10038c2ecf20Sopenharmony_ci * to unregister an existing handler.
10048c2ecf20Sopenharmony_ci */
10058c2ecf20Sopenharmony_civoid t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	if (opcode < NUM_CPL_CMDS)
10088c2ecf20Sopenharmony_ci		cpl_handlers[opcode] = h ? h : do_bad_cpl;
10098c2ecf20Sopenharmony_ci	else
10108c2ecf20Sopenharmony_ci		pr_err("T3C: handler registration for opcode %x failed\n",
10118c2ecf20Sopenharmony_ci		       opcode);
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(t3_register_cpl_handler);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci/*
10178c2ecf20Sopenharmony_ci * T3CDEV's receive method.
10188c2ecf20Sopenharmony_ci */
10198c2ecf20Sopenharmony_cistatic int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	while (n--) {
10228c2ecf20Sopenharmony_ci		struct sk_buff *skb = *skbs++;
10238c2ecf20Sopenharmony_ci		unsigned int opcode = get_opcode(skb);
10248c2ecf20Sopenharmony_ci		int ret = cpl_handlers[opcode] (dev, skb);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci#if VALIDATE_TID
10278c2ecf20Sopenharmony_ci		if (ret & CPL_RET_UNKNOWN_TID) {
10288c2ecf20Sopenharmony_ci			union opcode_tid *p = cplhdr(skb);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci			pr_err("%s: CPL message (opcode %u) had unknown TID %u\n",
10318c2ecf20Sopenharmony_ci			       dev->name, opcode, G_TID(ntohl(p->opcode_tid)));
10328c2ecf20Sopenharmony_ci		}
10338c2ecf20Sopenharmony_ci#endif
10348c2ecf20Sopenharmony_ci		if (ret & CPL_RET_BUF_DONE)
10358c2ecf20Sopenharmony_ci			kfree_skb(skb);
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci	return 0;
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci/*
10418c2ecf20Sopenharmony_ci * Sends an sk_buff to a T3C driver after dealing with any active network taps.
10428c2ecf20Sopenharmony_ci */
10438c2ecf20Sopenharmony_ciint cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	int r;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	local_bh_disable();
10488c2ecf20Sopenharmony_ci	r = dev->send(dev, skb);
10498c2ecf20Sopenharmony_ci	local_bh_enable();
10508c2ecf20Sopenharmony_ci	return r;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb3_ofld_send);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic int is_offloading(struct net_device *dev)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	struct adapter *adapter;
10588c2ecf20Sopenharmony_ci	int i;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	read_lock_bh(&adapter_list_lock);
10618c2ecf20Sopenharmony_ci	list_for_each_entry(adapter, &adapter_list, adapter_list) {
10628c2ecf20Sopenharmony_ci		for_each_port(adapter, i) {
10638c2ecf20Sopenharmony_ci			if (dev == adapter->port[i]) {
10648c2ecf20Sopenharmony_ci				read_unlock_bh(&adapter_list_lock);
10658c2ecf20Sopenharmony_ci				return 1;
10668c2ecf20Sopenharmony_ci			}
10678c2ecf20Sopenharmony_ci		}
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci	read_unlock_bh(&adapter_list_lock);
10708c2ecf20Sopenharmony_ci	return 0;
10718c2ecf20Sopenharmony_ci}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic void cxgb_neigh_update(struct neighbour *neigh)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	struct net_device *dev;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	if (!neigh)
10788c2ecf20Sopenharmony_ci		return;
10798c2ecf20Sopenharmony_ci	dev = neigh->dev;
10808c2ecf20Sopenharmony_ci	if (dev && (is_offloading(dev))) {
10818c2ecf20Sopenharmony_ci		struct t3cdev *tdev = dev2t3cdev(dev);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci		BUG_ON(!tdev);
10848c2ecf20Sopenharmony_ci		t3_l2t_update(tdev, neigh);
10858c2ecf20Sopenharmony_ci	}
10868c2ecf20Sopenharmony_ci}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_cistatic void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10918c2ecf20Sopenharmony_ci	struct cpl_set_tcb_field *req;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
10948c2ecf20Sopenharmony_ci	if (!skb) {
10958c2ecf20Sopenharmony_ci		pr_err("%s: cannot allocate skb!\n", __func__);
10968c2ecf20Sopenharmony_ci		return;
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci	skb->priority = CPL_PRIORITY_CONTROL;
10998c2ecf20Sopenharmony_ci	req = skb_put(skb, sizeof(*req));
11008c2ecf20Sopenharmony_ci	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
11018c2ecf20Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
11028c2ecf20Sopenharmony_ci	req->reply = 0;
11038c2ecf20Sopenharmony_ci	req->cpu_idx = 0;
11048c2ecf20Sopenharmony_ci	req->word = htons(W_TCB_L2T_IX);
11058c2ecf20Sopenharmony_ci	req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
11068c2ecf20Sopenharmony_ci	req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
11078c2ecf20Sopenharmony_ci	tdev->send(tdev, skb);
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_cistatic void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
11118c2ecf20Sopenharmony_ci			  struct neighbour *neigh,
11128c2ecf20Sopenharmony_ci			  const void *daddr)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	struct net_device *dev;
11158c2ecf20Sopenharmony_ci	struct tid_info *ti;
11168c2ecf20Sopenharmony_ci	struct t3cdev *tdev;
11178c2ecf20Sopenharmony_ci	u32 tid;
11188c2ecf20Sopenharmony_ci	int update_tcb;
11198c2ecf20Sopenharmony_ci	struct l2t_entry *e;
11208c2ecf20Sopenharmony_ci	struct t3c_tid_entry *te;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	dev = neigh->dev;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (!is_offloading(dev))
11258c2ecf20Sopenharmony_ci		return;
11268c2ecf20Sopenharmony_ci	tdev = dev2t3cdev(dev);
11278c2ecf20Sopenharmony_ci	BUG_ON(!tdev);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	/* Add new L2T entry */
11308c2ecf20Sopenharmony_ci	e = t3_l2t_get(tdev, new, dev, daddr);
11318c2ecf20Sopenharmony_ci	if (!e) {
11328c2ecf20Sopenharmony_ci		pr_err("%s: couldn't allocate new l2t entry!\n", __func__);
11338c2ecf20Sopenharmony_ci		return;
11348c2ecf20Sopenharmony_ci	}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	/* Walk tid table and notify clients of dst change. */
11378c2ecf20Sopenharmony_ci	ti = &(T3C_DATA(tdev))->tid_maps;
11388c2ecf20Sopenharmony_ci	for (tid = 0; tid < ti->ntids; tid++) {
11398c2ecf20Sopenharmony_ci		te = lookup_tid(ti, tid);
11408c2ecf20Sopenharmony_ci		BUG_ON(!te);
11418c2ecf20Sopenharmony_ci		if (te && te->ctx && te->client && te->client->redirect) {
11428c2ecf20Sopenharmony_ci			update_tcb = te->client->redirect(te->ctx, old, new, e);
11438c2ecf20Sopenharmony_ci			if (update_tcb) {
11448c2ecf20Sopenharmony_ci				rcu_read_lock();
11458c2ecf20Sopenharmony_ci				l2t_hold(L2DATA(tdev), e);
11468c2ecf20Sopenharmony_ci				rcu_read_unlock();
11478c2ecf20Sopenharmony_ci				set_l2t_ix(tdev, tid, e);
11488c2ecf20Sopenharmony_ci			}
11498c2ecf20Sopenharmony_ci		}
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci	l2t_release(tdev, e);
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/*
11558c2ecf20Sopenharmony_ci * Allocate and initialize the TID tables.  Returns 0 on success.
11568c2ecf20Sopenharmony_ci */
11578c2ecf20Sopenharmony_cistatic int init_tid_tabs(struct tid_info *t, unsigned int ntids,
11588c2ecf20Sopenharmony_ci			 unsigned int natids, unsigned int nstids,
11598c2ecf20Sopenharmony_ci			 unsigned int atid_base, unsigned int stid_base)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	unsigned long size = ntids * sizeof(*t->tid_tab) +
11628c2ecf20Sopenharmony_ci	    natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	t->tid_tab = kvzalloc(size, GFP_KERNEL);
11658c2ecf20Sopenharmony_ci	if (!t->tid_tab)
11668c2ecf20Sopenharmony_ci		return -ENOMEM;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
11698c2ecf20Sopenharmony_ci	t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
11708c2ecf20Sopenharmony_ci	t->ntids = ntids;
11718c2ecf20Sopenharmony_ci	t->nstids = nstids;
11728c2ecf20Sopenharmony_ci	t->stid_base = stid_base;
11738c2ecf20Sopenharmony_ci	t->sfree = NULL;
11748c2ecf20Sopenharmony_ci	t->natids = natids;
11758c2ecf20Sopenharmony_ci	t->atid_base = atid_base;
11768c2ecf20Sopenharmony_ci	t->afree = NULL;
11778c2ecf20Sopenharmony_ci	t->stids_in_use = t->atids_in_use = 0;
11788c2ecf20Sopenharmony_ci	atomic_set(&t->tids_in_use, 0);
11798c2ecf20Sopenharmony_ci	spin_lock_init(&t->stid_lock);
11808c2ecf20Sopenharmony_ci	spin_lock_init(&t->atid_lock);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	/*
11838c2ecf20Sopenharmony_ci	 * Setup the free lists for stid_tab and atid_tab.
11848c2ecf20Sopenharmony_ci	 */
11858c2ecf20Sopenharmony_ci	if (nstids) {
11868c2ecf20Sopenharmony_ci		while (--nstids)
11878c2ecf20Sopenharmony_ci			t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
11888c2ecf20Sopenharmony_ci		t->sfree = t->stid_tab;
11898c2ecf20Sopenharmony_ci	}
11908c2ecf20Sopenharmony_ci	if (natids) {
11918c2ecf20Sopenharmony_ci		while (--natids)
11928c2ecf20Sopenharmony_ci			t->atid_tab[natids - 1].next = &t->atid_tab[natids];
11938c2ecf20Sopenharmony_ci		t->afree = t->atid_tab;
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci	return 0;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic void free_tid_maps(struct tid_info *t)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	kvfree(t->tid_tab);
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic inline void add_adapter(struct adapter *adap)
12048c2ecf20Sopenharmony_ci{
12058c2ecf20Sopenharmony_ci	write_lock_bh(&adapter_list_lock);
12068c2ecf20Sopenharmony_ci	list_add_tail(&adap->adapter_list, &adapter_list);
12078c2ecf20Sopenharmony_ci	write_unlock_bh(&adapter_list_lock);
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_cistatic inline void remove_adapter(struct adapter *adap)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	write_lock_bh(&adapter_list_lock);
12138c2ecf20Sopenharmony_ci	list_del(&adap->adapter_list);
12148c2ecf20Sopenharmony_ci	write_unlock_bh(&adapter_list_lock);
12158c2ecf20Sopenharmony_ci}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ciint cxgb3_offload_activate(struct adapter *adapter)
12188c2ecf20Sopenharmony_ci{
12198c2ecf20Sopenharmony_ci	struct t3cdev *dev = &adapter->tdev;
12208c2ecf20Sopenharmony_ci	int natids, err;
12218c2ecf20Sopenharmony_ci	struct t3c_data *t;
12228c2ecf20Sopenharmony_ci	struct tid_range stid_range, tid_range;
12238c2ecf20Sopenharmony_ci	struct mtutab mtutab;
12248c2ecf20Sopenharmony_ci	unsigned int l2t_capacity;
12258c2ecf20Sopenharmony_ci	struct l2t_data *l2td;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	t = kzalloc(sizeof(*t), GFP_KERNEL);
12288c2ecf20Sopenharmony_ci	if (!t)
12298c2ecf20Sopenharmony_ci		return -ENOMEM;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	err = -EOPNOTSUPP;
12328c2ecf20Sopenharmony_ci	if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
12338c2ecf20Sopenharmony_ci	    dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
12348c2ecf20Sopenharmony_ci	    dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
12358c2ecf20Sopenharmony_ci	    dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
12368c2ecf20Sopenharmony_ci	    dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
12378c2ecf20Sopenharmony_ci	    dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
12388c2ecf20Sopenharmony_ci		goto out_free;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	err = -ENOMEM;
12418c2ecf20Sopenharmony_ci	l2td = t3_init_l2t(l2t_capacity);
12428c2ecf20Sopenharmony_ci	if (!l2td)
12438c2ecf20Sopenharmony_ci		goto out_free;
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	natids = min(tid_range.num / 2, MAX_ATIDS);
12468c2ecf20Sopenharmony_ci	err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
12478c2ecf20Sopenharmony_ci			    stid_range.num, ATID_BASE, stid_range.base);
12488c2ecf20Sopenharmony_ci	if (err)
12498c2ecf20Sopenharmony_ci		goto out_free_l2t;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	t->mtus = mtutab.mtus;
12528c2ecf20Sopenharmony_ci	t->nmtus = mtutab.size;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
12558c2ecf20Sopenharmony_ci	spin_lock_init(&t->tid_release_lock);
12568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&t->list_node);
12578c2ecf20Sopenharmony_ci	t->dev = dev;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(dev->l2opt, l2td);
12608c2ecf20Sopenharmony_ci	T3C_DATA(dev) = t;
12618c2ecf20Sopenharmony_ci	dev->recv = process_rx;
12628c2ecf20Sopenharmony_ci	dev->neigh_update = t3_l2t_update;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	/* Register netevent handler once */
12658c2ecf20Sopenharmony_ci	if (list_empty(&adapter_list))
12668c2ecf20Sopenharmony_ci		register_netevent_notifier(&nb);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL);
12698c2ecf20Sopenharmony_ci	t->release_list_incomplete = 0;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	add_adapter(adapter);
12728c2ecf20Sopenharmony_ci	return 0;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ciout_free_l2t:
12758c2ecf20Sopenharmony_ci	kvfree(l2td);
12768c2ecf20Sopenharmony_ciout_free:
12778c2ecf20Sopenharmony_ci	kfree(t);
12788c2ecf20Sopenharmony_ci	return err;
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_cistatic void clean_l2_data(struct rcu_head *head)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	struct l2t_data *d = container_of(head, struct l2t_data, rcu_head);
12848c2ecf20Sopenharmony_ci	kvfree(d);
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_civoid cxgb3_offload_deactivate(struct adapter *adapter)
12898c2ecf20Sopenharmony_ci{
12908c2ecf20Sopenharmony_ci	struct t3cdev *tdev = &adapter->tdev;
12918c2ecf20Sopenharmony_ci	struct t3c_data *t = T3C_DATA(tdev);
12928c2ecf20Sopenharmony_ci	struct l2t_data *d;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	remove_adapter(adapter);
12958c2ecf20Sopenharmony_ci	if (list_empty(&adapter_list))
12968c2ecf20Sopenharmony_ci		unregister_netevent_notifier(&nb);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	free_tid_maps(&t->tid_maps);
12998c2ecf20Sopenharmony_ci	T3C_DATA(tdev) = NULL;
13008c2ecf20Sopenharmony_ci	rcu_read_lock();
13018c2ecf20Sopenharmony_ci	d = L2DATA(tdev);
13028c2ecf20Sopenharmony_ci	rcu_read_unlock();
13038c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(tdev->l2opt, NULL);
13048c2ecf20Sopenharmony_ci	call_rcu(&d->rcu_head, clean_l2_data);
13058c2ecf20Sopenharmony_ci	kfree_skb(t->nofail_skb);
13068c2ecf20Sopenharmony_ci	kfree(t);
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic inline void register_tdev(struct t3cdev *tdev)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	static int unit;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
13148c2ecf20Sopenharmony_ci	snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
13158c2ecf20Sopenharmony_ci	list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
13168c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cistatic inline void unregister_tdev(struct t3cdev *tdev)
13208c2ecf20Sopenharmony_ci{
13218c2ecf20Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
13228c2ecf20Sopenharmony_ci	list_del(&tdev->ofld_dev_list);
13238c2ecf20Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic inline int adap2type(struct adapter *adapter)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	int type = 0;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	switch (adapter->params.rev) {
13318c2ecf20Sopenharmony_ci	case T3_REV_A:
13328c2ecf20Sopenharmony_ci		type = T3A;
13338c2ecf20Sopenharmony_ci		break;
13348c2ecf20Sopenharmony_ci	case T3_REV_B:
13358c2ecf20Sopenharmony_ci	case T3_REV_B2:
13368c2ecf20Sopenharmony_ci		type = T3B;
13378c2ecf20Sopenharmony_ci		break;
13388c2ecf20Sopenharmony_ci	case T3_REV_C:
13398c2ecf20Sopenharmony_ci		type = T3C;
13408c2ecf20Sopenharmony_ci		break;
13418c2ecf20Sopenharmony_ci	}
13428c2ecf20Sopenharmony_ci	return type;
13438c2ecf20Sopenharmony_ci}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_civoid cxgb3_adapter_ofld(struct adapter *adapter)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	struct t3cdev *tdev = &adapter->tdev;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tdev->ofld_dev_list);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	cxgb3_set_dummy_ops(tdev);
13528c2ecf20Sopenharmony_ci	tdev->send = t3_offload_tx;
13538c2ecf20Sopenharmony_ci	tdev->ctl = cxgb_offload_ctl;
13548c2ecf20Sopenharmony_ci	tdev->type = adap2type(adapter);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	register_tdev(tdev);
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_civoid cxgb3_adapter_unofld(struct adapter *adapter)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct t3cdev *tdev = &adapter->tdev;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	tdev->recv = NULL;
13648c2ecf20Sopenharmony_ci	tdev->neigh_update = NULL;
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	unregister_tdev(tdev);
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_civoid __init cxgb3_offload_init(void)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	int i;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_CPL_CMDS; ++i)
13748c2ecf20Sopenharmony_ci		cpl_handlers[i] = do_bad_cpl;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
13778c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
13788c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl);
13798c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
13808c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
13818c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
13828c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
13838c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
13848c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
13858c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
13868c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
13878c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
13888c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
13898c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
13908c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
13918c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
13928c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
13938c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
13948c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_SET_TCB_RPL, do_hwtid_rpl);
13958c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_GET_TCB_RPL, do_hwtid_rpl);
13968c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
13978c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
13988c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
13998c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
14008c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
14018c2ecf20Sopenharmony_ci	t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
14028c2ecf20Sopenharmony_ci}
1403