162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/list.h> 3662306a36Sopenharmony_ci#include <linux/slab.h> 3762306a36Sopenharmony_ci#include <net/neighbour.h> 3862306a36Sopenharmony_ci#include <linux/notifier.h> 3962306a36Sopenharmony_ci#include <linux/atomic.h> 4062306a36Sopenharmony_ci#include <linux/proc_fs.h> 4162306a36Sopenharmony_ci#include <linux/if_vlan.h> 4262306a36Sopenharmony_ci#include <net/netevent.h> 4362306a36Sopenharmony_ci#include <linux/highmem.h> 4462306a36Sopenharmony_ci#include <linux/vmalloc.h> 4562306a36Sopenharmony_ci#include <linux/export.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include "common.h" 4862306a36Sopenharmony_ci#include "regs.h" 4962306a36Sopenharmony_ci#include "cxgb3_ioctl.h" 5062306a36Sopenharmony_ci#include "cxgb3_ctl_defs.h" 5162306a36Sopenharmony_ci#include "cxgb3_defs.h" 5262306a36Sopenharmony_ci#include "l2t.h" 5362306a36Sopenharmony_ci#include "firmware_exports.h" 5462306a36Sopenharmony_ci#include "cxgb3_offload.h" 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic LIST_HEAD(client_list); 5762306a36Sopenharmony_cistatic LIST_HEAD(ofld_dev_list); 5862306a36Sopenharmony_cistatic DEFINE_MUTEX(cxgb3_db_lock); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic DEFINE_RWLOCK(adapter_list_lock); 6162306a36Sopenharmony_cistatic LIST_HEAD(adapter_list); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const unsigned int MAX_ATIDS = 64 * 1024; 6462306a36Sopenharmony_cistatic const unsigned int ATID_BASE = 0x10000; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void cxgb_neigh_update(struct neighbour *neigh); 6762306a36Sopenharmony_cistatic void cxgb_redirect(struct dst_entry *old, struct dst_entry *new, 6862306a36Sopenharmony_ci struct neighbour *neigh, const void *daddr); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline int offload_activated(struct t3cdev *tdev) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci const struct adapter *adapter = tdev2adap(tdev); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * cxgb3_register_client - register an offload client 7962306a36Sopenharmony_ci * @client: the client 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Add the client to the client list, 8262306a36Sopenharmony_ci * and call backs the client for each activated offload device 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_civoid cxgb3_register_client(struct cxgb3_client *client) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct t3cdev *tdev; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 8962306a36Sopenharmony_ci list_add_tail(&client->client_list, &client_list); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (client->add) { 9262306a36Sopenharmony_ci list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { 9362306a36Sopenharmony_ci if (offload_activated(tdev)) 9462306a36Sopenharmony_ci client->add(tdev); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_register_client); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/** 10362306a36Sopenharmony_ci * cxgb3_unregister_client - unregister an offload client 10462306a36Sopenharmony_ci * @client: the client 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Remove the client to the client list, 10762306a36Sopenharmony_ci * and call backs the client for each activated offload device. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_civoid cxgb3_unregister_client(struct cxgb3_client *client) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct t3cdev *tdev; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 11462306a36Sopenharmony_ci list_del(&client->client_list); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (client->remove) { 11762306a36Sopenharmony_ci list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { 11862306a36Sopenharmony_ci if (offload_activated(tdev)) 11962306a36Sopenharmony_ci client->remove(tdev); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_unregister_client); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/** 12862306a36Sopenharmony_ci * cxgb3_add_clients - activate registered clients for an offload device 12962306a36Sopenharmony_ci * @tdev: the offload device 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Call backs all registered clients once a offload device is activated 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_civoid cxgb3_add_clients(struct t3cdev *tdev) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct cxgb3_client *client; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 13862306a36Sopenharmony_ci list_for_each_entry(client, &client_list, client_list) { 13962306a36Sopenharmony_ci if (client->add) 14062306a36Sopenharmony_ci client->add(tdev); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/** 14662306a36Sopenharmony_ci * cxgb3_remove_clients - deactivates registered clients 14762306a36Sopenharmony_ci * for an offload device 14862306a36Sopenharmony_ci * @tdev: the offload device 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * Call backs all registered clients once a offload device is deactivated 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_civoid cxgb3_remove_clients(struct t3cdev *tdev) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct cxgb3_client *client; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 15762306a36Sopenharmony_ci list_for_each_entry(client, &client_list, client_list) { 15862306a36Sopenharmony_ci if (client->remove) 15962306a36Sopenharmony_ci client->remove(tdev); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_civoid cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct cxgb3_client *client; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 16962306a36Sopenharmony_ci list_for_each_entry(client, &client_list, client_list) { 17062306a36Sopenharmony_ci if (client->event_handler) 17162306a36Sopenharmony_ci client->event_handler(tdev, event, port); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic struct net_device *get_iff_from_mac(struct adapter *adapter, 17762306a36Sopenharmony_ci const unsigned char *mac, 17862306a36Sopenharmony_ci unsigned int vlan) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int i; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci for_each_port(adapter, i) { 18362306a36Sopenharmony_ci struct net_device *dev = adapter->port[i]; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (ether_addr_equal(dev->dev_addr, mac)) { 18662306a36Sopenharmony_ci rcu_read_lock(); 18762306a36Sopenharmony_ci if (vlan && vlan != VLAN_VID_MASK) { 18862306a36Sopenharmony_ci dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), vlan); 18962306a36Sopenharmony_ci } else if (netif_is_bond_slave(dev)) { 19062306a36Sopenharmony_ci struct net_device *upper_dev; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci while ((upper_dev = 19362306a36Sopenharmony_ci netdev_master_upper_dev_get_rcu(dev))) 19462306a36Sopenharmony_ci dev = upper_dev; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci rcu_read_unlock(); 19762306a36Sopenharmony_ci return dev; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci return NULL; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, 20462306a36Sopenharmony_ci void *data) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int i; 20762306a36Sopenharmony_ci int ret = 0; 20862306a36Sopenharmony_ci unsigned int val = 0; 20962306a36Sopenharmony_ci struct ulp_iscsi_info *uiip = data; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci switch (req) { 21262306a36Sopenharmony_ci case ULP_ISCSI_GET_PARAMS: 21362306a36Sopenharmony_ci uiip->pdev = adapter->pdev; 21462306a36Sopenharmony_ci uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); 21562306a36Sopenharmony_ci uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); 21662306a36Sopenharmony_ci uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ); 21962306a36Sopenharmony_ci for (i = 0; i < 4; i++, val >>= 8) 22062306a36Sopenharmony_ci uiip->pgsz_factor[i] = val & 0xFF; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci val = t3_read_reg(adapter, A_TP_PARA_REG7); 22362306a36Sopenharmony_ci uiip->max_txsz = 22462306a36Sopenharmony_ci uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0, 22562306a36Sopenharmony_ci (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1); 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * On tx, the iscsi pdu has to be <= tx page size and has to 22862306a36Sopenharmony_ci * fit into the Tx PM FIFO. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci val = min(adapter->params.tp.tx_pg_size, 23162306a36Sopenharmony_ci t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); 23262306a36Sopenharmony_ci uiip->max_txsz = min(val, uiip->max_txsz); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* set MaxRxData to 16224 */ 23562306a36Sopenharmony_ci val = t3_read_reg(adapter, A_TP_PARA_REG2); 23662306a36Sopenharmony_ci if ((val >> S_MAXRXDATA) != 0x3f60) { 23762306a36Sopenharmony_ci val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE); 23862306a36Sopenharmony_ci val |= V_MAXRXDATA(0x3f60); 23962306a36Sopenharmony_ci pr_info("%s, iscsi set MaxRxData to 16224 (0x%x)\n", 24062306a36Sopenharmony_ci adapter->name, val); 24162306a36Sopenharmony_ci t3_write_reg(adapter, A_TP_PARA_REG2, val); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* 24562306a36Sopenharmony_ci * on rx, the iscsi pdu has to be < rx page size and the 24662306a36Sopenharmony_ci * max rx data length programmed in TP 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci val = min(adapter->params.tp.rx_pg_size, 24962306a36Sopenharmony_ci ((t3_read_reg(adapter, A_TP_PARA_REG2)) >> 25062306a36Sopenharmony_ci S_MAXRXDATA) & M_MAXRXDATA); 25162306a36Sopenharmony_ci uiip->max_rxsz = min(val, uiip->max_rxsz); 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case ULP_ISCSI_SET_PARAMS: 25462306a36Sopenharmony_ci t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); 25562306a36Sopenharmony_ci /* program the ddp page sizes */ 25662306a36Sopenharmony_ci for (i = 0; i < 4; i++) 25762306a36Sopenharmony_ci val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); 25862306a36Sopenharmony_ci if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) { 25962306a36Sopenharmony_ci pr_info("%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u\n", 26062306a36Sopenharmony_ci adapter->name, val, uiip->pgsz_factor[0], 26162306a36Sopenharmony_ci uiip->pgsz_factor[1], uiip->pgsz_factor[2], 26262306a36Sopenharmony_ci uiip->pgsz_factor[3]); 26362306a36Sopenharmony_ci t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci default: 26762306a36Sopenharmony_ci ret = -EOPNOTSUPP; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return ret; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* Response queue used for RDMA events. */ 27362306a36Sopenharmony_ci#define ASYNC_NOTIF_RSPQ 0 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci int ret = 0; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci switch (req) { 28062306a36Sopenharmony_ci case RDMA_GET_PARAMS: { 28162306a36Sopenharmony_ci struct rdma_info *rdma = data; 28262306a36Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci rdma->udbell_physbase = pci_resource_start(pdev, 2); 28562306a36Sopenharmony_ci rdma->udbell_len = pci_resource_len(pdev, 2); 28662306a36Sopenharmony_ci rdma->tpt_base = 28762306a36Sopenharmony_ci t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); 28862306a36Sopenharmony_ci rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); 28962306a36Sopenharmony_ci rdma->pbl_base = 29062306a36Sopenharmony_ci t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); 29162306a36Sopenharmony_ci rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); 29262306a36Sopenharmony_ci rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); 29362306a36Sopenharmony_ci rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); 29462306a36Sopenharmony_ci rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL; 29562306a36Sopenharmony_ci rdma->pdev = pdev; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci case RDMA_CQ_OP:{ 29962306a36Sopenharmony_ci unsigned long flags; 30062306a36Sopenharmony_ci struct rdma_cq_op *rdma = data; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* may be called in any context */ 30362306a36Sopenharmony_ci spin_lock_irqsave(&adapter->sge.reg_lock, flags); 30462306a36Sopenharmony_ci ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op, 30562306a36Sopenharmony_ci rdma->credits); 30662306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci case RDMA_GET_MEM:{ 31062306a36Sopenharmony_ci struct ch_mem_range *t = data; 31162306a36Sopenharmony_ci struct mc7 *mem; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if ((t->addr & 7) || (t->len & 7)) 31462306a36Sopenharmony_ci return -EINVAL; 31562306a36Sopenharmony_ci if (t->mem_id == MEM_CM) 31662306a36Sopenharmony_ci mem = &adapter->cm; 31762306a36Sopenharmony_ci else if (t->mem_id == MEM_PMRX) 31862306a36Sopenharmony_ci mem = &adapter->pmrx; 31962306a36Sopenharmony_ci else if (t->mem_id == MEM_PMTX) 32062306a36Sopenharmony_ci mem = &adapter->pmtx; 32162306a36Sopenharmony_ci else 32262306a36Sopenharmony_ci return -EINVAL; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ret = 32562306a36Sopenharmony_ci t3_mc7_bd_read(mem, t->addr / 8, t->len / 8, 32662306a36Sopenharmony_ci (u64 *) t->buf); 32762306a36Sopenharmony_ci if (ret) 32862306a36Sopenharmony_ci return ret; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci case RDMA_CQ_SETUP:{ 33262306a36Sopenharmony_ci struct rdma_cq_setup *rdma = data; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 33562306a36Sopenharmony_ci ret = 33662306a36Sopenharmony_ci t3_sge_init_cqcntxt(adapter, rdma->id, 33762306a36Sopenharmony_ci rdma->base_addr, rdma->size, 33862306a36Sopenharmony_ci ASYNC_NOTIF_RSPQ, 33962306a36Sopenharmony_ci rdma->ovfl_mode, rdma->credits, 34062306a36Sopenharmony_ci rdma->credit_thres); 34162306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci case RDMA_CQ_DISABLE: 34562306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 34662306a36Sopenharmony_ci ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data); 34762306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case RDMA_CTRL_QP_SETUP:{ 35062306a36Sopenharmony_ci struct rdma_ctrlqp_setup *rdma = data; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci spin_lock_irq(&adapter->sge.reg_lock); 35362306a36Sopenharmony_ci ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, 35462306a36Sopenharmony_ci SGE_CNTXT_RDMA, 35562306a36Sopenharmony_ci ASYNC_NOTIF_RSPQ, 35662306a36Sopenharmony_ci rdma->base_addr, rdma->size, 35762306a36Sopenharmony_ci FW_RI_TID_START, 1, 0); 35862306a36Sopenharmony_ci spin_unlock_irq(&adapter->sge.reg_lock); 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci case RDMA_GET_MIB: { 36262306a36Sopenharmony_ci spin_lock(&adapter->stats_lock); 36362306a36Sopenharmony_ci t3_tp_get_mib_stats(adapter, (struct tp_mib_stats *)data); 36462306a36Sopenharmony_ci spin_unlock(&adapter->stats_lock); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci default: 36862306a36Sopenharmony_ci ret = -EOPNOTSUPP; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci return ret; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct adapter *adapter = tdev2adap(tdev); 37662306a36Sopenharmony_ci struct tid_range *tid; 37762306a36Sopenharmony_ci struct mtutab *mtup; 37862306a36Sopenharmony_ci struct iff_mac *iffmacp; 37962306a36Sopenharmony_ci struct ddp_params *ddpp; 38062306a36Sopenharmony_ci struct adap_ports *ports; 38162306a36Sopenharmony_ci struct ofld_page_info *rx_page_info; 38262306a36Sopenharmony_ci struct tp_params *tp = &adapter->params.tp; 38362306a36Sopenharmony_ci int i; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci switch (req) { 38662306a36Sopenharmony_ci case GET_MAX_OUTSTANDING_WR: 38762306a36Sopenharmony_ci *(unsigned int *)data = FW_WR_NUM; 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case GET_WR_LEN: 39062306a36Sopenharmony_ci *(unsigned int *)data = WR_FLITS; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci case GET_TX_MAX_CHUNK: 39362306a36Sopenharmony_ci *(unsigned int *)data = 1 << 20; /* 1MB */ 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci case GET_TID_RANGE: 39662306a36Sopenharmony_ci tid = data; 39762306a36Sopenharmony_ci tid->num = t3_mc5_size(&adapter->mc5) - 39862306a36Sopenharmony_ci adapter->params.mc5.nroutes - 39962306a36Sopenharmony_ci adapter->params.mc5.nfilters - adapter->params.mc5.nservers; 40062306a36Sopenharmony_ci tid->base = 0; 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci case GET_STID_RANGE: 40362306a36Sopenharmony_ci tid = data; 40462306a36Sopenharmony_ci tid->num = adapter->params.mc5.nservers; 40562306a36Sopenharmony_ci tid->base = t3_mc5_size(&adapter->mc5) - tid->num - 40662306a36Sopenharmony_ci adapter->params.mc5.nfilters - adapter->params.mc5.nroutes; 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci case GET_L2T_CAPACITY: 40962306a36Sopenharmony_ci *(unsigned int *)data = 2048; 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case GET_MTUS: 41262306a36Sopenharmony_ci mtup = data; 41362306a36Sopenharmony_ci mtup->size = NMTUS; 41462306a36Sopenharmony_ci mtup->mtus = adapter->params.mtus; 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci case GET_IFF_FROM_MAC: 41762306a36Sopenharmony_ci iffmacp = data; 41862306a36Sopenharmony_ci iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr, 41962306a36Sopenharmony_ci iffmacp->vlan_tag & 42062306a36Sopenharmony_ci VLAN_VID_MASK); 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case GET_DDP_PARAMS: 42362306a36Sopenharmony_ci ddpp = data; 42462306a36Sopenharmony_ci ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT); 42562306a36Sopenharmony_ci ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT); 42662306a36Sopenharmony_ci ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK); 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci case GET_PORTS: 42962306a36Sopenharmony_ci ports = data; 43062306a36Sopenharmony_ci ports->nports = adapter->params.nports; 43162306a36Sopenharmony_ci for_each_port(adapter, i) 43262306a36Sopenharmony_ci ports->lldevs[i] = adapter->port[i]; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case ULP_ISCSI_GET_PARAMS: 43562306a36Sopenharmony_ci case ULP_ISCSI_SET_PARAMS: 43662306a36Sopenharmony_ci if (!offload_running(adapter)) 43762306a36Sopenharmony_ci return -EAGAIN; 43862306a36Sopenharmony_ci return cxgb_ulp_iscsi_ctl(adapter, req, data); 43962306a36Sopenharmony_ci case RDMA_GET_PARAMS: 44062306a36Sopenharmony_ci case RDMA_CQ_OP: 44162306a36Sopenharmony_ci case RDMA_CQ_SETUP: 44262306a36Sopenharmony_ci case RDMA_CQ_DISABLE: 44362306a36Sopenharmony_ci case RDMA_CTRL_QP_SETUP: 44462306a36Sopenharmony_ci case RDMA_GET_MEM: 44562306a36Sopenharmony_ci case RDMA_GET_MIB: 44662306a36Sopenharmony_ci if (!offload_running(adapter)) 44762306a36Sopenharmony_ci return -EAGAIN; 44862306a36Sopenharmony_ci return cxgb_rdma_ctl(adapter, req, data); 44962306a36Sopenharmony_ci case GET_RX_PAGE_INFO: 45062306a36Sopenharmony_ci rx_page_info = data; 45162306a36Sopenharmony_ci rx_page_info->page_size = tp->rx_pg_size; 45262306a36Sopenharmony_ci rx_page_info->num = tp->rx_num_pgs; 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci case GET_ISCSI_IPV4ADDR: { 45562306a36Sopenharmony_ci struct iscsi_ipv4addr *p = data; 45662306a36Sopenharmony_ci struct port_info *pi = netdev_priv(p->dev); 45762306a36Sopenharmony_ci p->ipv4addr = pi->iscsi_ipv4addr; 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci case GET_EMBEDDED_INFO: { 46162306a36Sopenharmony_ci struct ch_embedded_info *e = data; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci spin_lock(&adapter->stats_lock); 46462306a36Sopenharmony_ci t3_get_fw_version(adapter, &e->fw_vers); 46562306a36Sopenharmony_ci t3_get_tp_version(adapter, &e->tp_vers); 46662306a36Sopenharmony_ci spin_unlock(&adapter->stats_lock); 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci default: 47062306a36Sopenharmony_ci return -EOPNOTSUPP; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* 47662306a36Sopenharmony_ci * Dummy handler for Rx offload packets in case we get an offload packet before 47762306a36Sopenharmony_ci * proper processing is setup. This complains and drops the packet as it isn't 47862306a36Sopenharmony_ci * normal to get offload packets at this stage. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, 48162306a36Sopenharmony_ci int n) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci while (n--) 48462306a36Sopenharmony_ci dev_kfree_skb_any(skbs[n]); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_civoid cxgb3_set_dummy_ops(struct t3cdev *dev) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci dev->recv = rx_offload_blackhole; 49562306a36Sopenharmony_ci dev->neigh_update = dummy_neigh_update; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/* 49962306a36Sopenharmony_ci * Free an active-open TID. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_civoid *cxgb3_free_atid(struct t3cdev *tdev, int atid) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; 50462306a36Sopenharmony_ci union active_open_entry *p = atid2entry(t, atid); 50562306a36Sopenharmony_ci void *ctx = p->t3c_tid.ctx; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci spin_lock_bh(&t->atid_lock); 50862306a36Sopenharmony_ci p->next = t->afree; 50962306a36Sopenharmony_ci t->afree = p; 51062306a36Sopenharmony_ci t->atids_in_use--; 51162306a36Sopenharmony_ci spin_unlock_bh(&t->atid_lock); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return ctx; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_free_atid); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/* 51962306a36Sopenharmony_ci * Free a server TID and return it to the free pool. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_civoid cxgb3_free_stid(struct t3cdev *tdev, int stid) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; 52462306a36Sopenharmony_ci union listen_entry *p = stid2entry(t, stid); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci spin_lock_bh(&t->stid_lock); 52762306a36Sopenharmony_ci p->next = t->sfree; 52862306a36Sopenharmony_ci t->sfree = p; 52962306a36Sopenharmony_ci t->stids_in_use--; 53062306a36Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_free_stid); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_civoid cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client, 53662306a36Sopenharmony_ci void *ctx, unsigned int tid) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci t->tid_tab[tid].client = client; 54162306a36Sopenharmony_ci t->tid_tab[tid].ctx = ctx; 54262306a36Sopenharmony_ci atomic_inc(&t->tids_in_use); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_insert_tid); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci/* 54862306a36Sopenharmony_ci * Populate a TID_RELEASE WR. The skb must be already propely sized. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_cistatic inline void mk_tid_release(struct sk_buff *skb, unsigned int tid) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct cpl_tid_release *req; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci skb->priority = CPL_PRIORITY_SETUP; 55562306a36Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 55662306a36Sopenharmony_ci req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 55762306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic void t3_process_tid_release_list(struct work_struct *work) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci struct t3c_data *td = container_of(work, struct t3c_data, 56362306a36Sopenharmony_ci tid_release_task); 56462306a36Sopenharmony_ci struct sk_buff *skb; 56562306a36Sopenharmony_ci struct t3cdev *tdev = td->dev; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci spin_lock_bh(&td->tid_release_lock); 56962306a36Sopenharmony_ci while (td->tid_release_list) { 57062306a36Sopenharmony_ci struct t3c_tid_entry *p = td->tid_release_list; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci td->tid_release_list = p->ctx; 57362306a36Sopenharmony_ci spin_unlock_bh(&td->tid_release_lock); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci skb = alloc_skb(sizeof(struct cpl_tid_release), 57662306a36Sopenharmony_ci GFP_KERNEL); 57762306a36Sopenharmony_ci if (!skb) 57862306a36Sopenharmony_ci skb = td->nofail_skb; 57962306a36Sopenharmony_ci if (!skb) { 58062306a36Sopenharmony_ci spin_lock_bh(&td->tid_release_lock); 58162306a36Sopenharmony_ci p->ctx = (void *)td->tid_release_list; 58262306a36Sopenharmony_ci td->tid_release_list = p; 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci mk_tid_release(skb, p - td->tid_maps.tid_tab); 58662306a36Sopenharmony_ci cxgb3_ofld_send(tdev, skb); 58762306a36Sopenharmony_ci p->ctx = NULL; 58862306a36Sopenharmony_ci if (skb == td->nofail_skb) 58962306a36Sopenharmony_ci td->nofail_skb = 59062306a36Sopenharmony_ci alloc_skb(sizeof(struct cpl_tid_release), 59162306a36Sopenharmony_ci GFP_KERNEL); 59262306a36Sopenharmony_ci spin_lock_bh(&td->tid_release_lock); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; 59562306a36Sopenharmony_ci spin_unlock_bh(&td->tid_release_lock); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (!td->nofail_skb) 59862306a36Sopenharmony_ci td->nofail_skb = 59962306a36Sopenharmony_ci alloc_skb(sizeof(struct cpl_tid_release), 60062306a36Sopenharmony_ci GFP_KERNEL); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* use ctx as a next pointer in the tid release list */ 60462306a36Sopenharmony_civoid cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct t3c_data *td = T3C_DATA(tdev); 60762306a36Sopenharmony_ci struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid]; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci spin_lock_bh(&td->tid_release_lock); 61062306a36Sopenharmony_ci p->ctx = (void *)td->tid_release_list; 61162306a36Sopenharmony_ci p->client = NULL; 61262306a36Sopenharmony_ci td->tid_release_list = p; 61362306a36Sopenharmony_ci if (!p->ctx || td->release_list_incomplete) 61462306a36Sopenharmony_ci schedule_work(&td->tid_release_task); 61562306a36Sopenharmony_ci spin_unlock_bh(&td->tid_release_lock); 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_queue_tid_release); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/* 62162306a36Sopenharmony_ci * Remove a tid from the TID table. A client may defer processing its last 62262306a36Sopenharmony_ci * CPL message if it is locked at the time it arrives, and while the message 62362306a36Sopenharmony_ci * sits in the client's backlog the TID may be reused for another connection. 62462306a36Sopenharmony_ci * To handle this we atomically switch the TID association if it still points 62562306a36Sopenharmony_ci * to the original client context. 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_civoid cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci BUG_ON(tid >= t->ntids); 63262306a36Sopenharmony_ci if (tdev->type == T3A) 63362306a36Sopenharmony_ci (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL); 63462306a36Sopenharmony_ci else { 63562306a36Sopenharmony_ci struct sk_buff *skb; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); 63862306a36Sopenharmony_ci if (likely(skb)) { 63962306a36Sopenharmony_ci mk_tid_release(skb, tid); 64062306a36Sopenharmony_ci cxgb3_ofld_send(tdev, skb); 64162306a36Sopenharmony_ci t->tid_tab[tid].ctx = NULL; 64262306a36Sopenharmony_ci } else 64362306a36Sopenharmony_ci cxgb3_queue_tid_release(tdev, tid); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci atomic_dec(&t->tids_in_use); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_remove_tid); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ciint cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, 65162306a36Sopenharmony_ci void *ctx) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci int atid = -1; 65462306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci spin_lock_bh(&t->atid_lock); 65762306a36Sopenharmony_ci if (t->afree && 65862306a36Sopenharmony_ci t->atids_in_use + atomic_read(&t->tids_in_use) + MC5_MIN_TIDS <= 65962306a36Sopenharmony_ci t->ntids) { 66062306a36Sopenharmony_ci union active_open_entry *p = t->afree; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci atid = (p - t->atid_tab) + t->atid_base; 66362306a36Sopenharmony_ci t->afree = p->next; 66462306a36Sopenharmony_ci p->t3c_tid.ctx = ctx; 66562306a36Sopenharmony_ci p->t3c_tid.client = client; 66662306a36Sopenharmony_ci t->atids_in_use++; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci spin_unlock_bh(&t->atid_lock); 66962306a36Sopenharmony_ci return atid; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_alloc_atid); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ciint cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client, 67562306a36Sopenharmony_ci void *ctx) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci int stid = -1; 67862306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci spin_lock_bh(&t->stid_lock); 68162306a36Sopenharmony_ci if (t->sfree) { 68262306a36Sopenharmony_ci union listen_entry *p = t->sfree; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci stid = (p - t->stid_tab) + t->stid_base; 68562306a36Sopenharmony_ci t->sfree = p->next; 68662306a36Sopenharmony_ci p->t3c_tid.ctx = ctx; 68762306a36Sopenharmony_ci p->t3c_tid.client = client; 68862306a36Sopenharmony_ci t->stids_in_use++; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 69162306a36Sopenharmony_ci return stid; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_alloc_stid); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci/* Get the t3cdev associated with a net_device */ 69762306a36Sopenharmony_cistruct t3cdev *dev2t3cdev(struct net_device *dev) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return (struct t3cdev *)pi->adapter; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ciEXPORT_SYMBOL(dev2t3cdev); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct cpl_smt_write_rpl *rpl = cplhdr(skb); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (rpl->status != CPL_ERR_NONE) 71162306a36Sopenharmony_ci pr_err("Unexpected SMT_WRITE_RPL status %u for entry %u\n", 71262306a36Sopenharmony_ci rpl->status, GET_TID(rpl)); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return CPL_RET_BUF_DONE; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct cpl_l2t_write_rpl *rpl = cplhdr(skb); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (rpl->status != CPL_ERR_NONE) 72262306a36Sopenharmony_ci pr_err("Unexpected L2T_WRITE_RPL status %u for entry %u\n", 72362306a36Sopenharmony_ci rpl->status, GET_TID(rpl)); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return CPL_RET_BUF_DONE; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct cpl_rte_write_rpl *rpl = cplhdr(skb); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (rpl->status != CPL_ERR_NONE) 73362306a36Sopenharmony_ci pr_err("Unexpected RTE_WRITE_RPL status %u for entry %u\n", 73462306a36Sopenharmony_ci rpl->status, GET_TID(rpl)); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return CPL_RET_BUF_DONE; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct cpl_act_open_rpl *rpl = cplhdr(skb); 74262306a36Sopenharmony_ci unsigned int atid = G_TID(ntohl(rpl->atid)); 74362306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); 74662306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client && 74762306a36Sopenharmony_ci t3c_tid->client->handlers && 74862306a36Sopenharmony_ci t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { 74962306a36Sopenharmony_ci return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, 75062306a36Sopenharmony_ci t3c_tid-> 75162306a36Sopenharmony_ci ctx); 75262306a36Sopenharmony_ci } else { 75362306a36Sopenharmony_ci pr_err("%s: received clientless CPL command 0x%x\n", 75462306a36Sopenharmony_ci dev->name, CPL_ACT_OPEN_RPL); 75562306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci union opcode_tid *p = cplhdr(skb); 76262306a36Sopenharmony_ci unsigned int stid = G_TID(ntohl(p->opcode_tid)); 76362306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); 76662306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && 76762306a36Sopenharmony_ci t3c_tid->client->handlers[p->opcode]) { 76862306a36Sopenharmony_ci return t3c_tid->client->handlers[p->opcode] (dev, skb, 76962306a36Sopenharmony_ci t3c_tid->ctx); 77062306a36Sopenharmony_ci } else { 77162306a36Sopenharmony_ci pr_err("%s: received clientless CPL command 0x%x\n", 77262306a36Sopenharmony_ci dev->name, p->opcode); 77362306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci union opcode_tid *p = cplhdr(skb); 78062306a36Sopenharmony_ci unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); 78162306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); 78462306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && 78562306a36Sopenharmony_ci t3c_tid->client->handlers[p->opcode]) { 78662306a36Sopenharmony_ci return t3c_tid->client->handlers[p->opcode] 78762306a36Sopenharmony_ci (dev, skb, t3c_tid->ctx); 78862306a36Sopenharmony_ci } else { 78962306a36Sopenharmony_ci pr_err("%s: received clientless CPL command 0x%x\n", 79062306a36Sopenharmony_ci dev->name, p->opcode); 79162306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic int do_cr(struct t3cdev *dev, struct sk_buff *skb) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct cpl_pass_accept_req *req = cplhdr(skb); 79862306a36Sopenharmony_ci unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); 79962306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(dev))->tid_maps; 80062306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 80162306a36Sopenharmony_ci unsigned int tid = GET_TID(req); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (unlikely(tid >= t->ntids)) { 80462306a36Sopenharmony_ci printk("%s: passive open TID %u too large\n", 80562306a36Sopenharmony_ci dev->name, tid); 80662306a36Sopenharmony_ci t3_fatal_err(tdev2adap(dev)); 80762306a36Sopenharmony_ci return CPL_RET_BUF_DONE; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci t3c_tid = lookup_stid(t, stid); 81162306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && 81262306a36Sopenharmony_ci t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { 81362306a36Sopenharmony_ci return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] 81462306a36Sopenharmony_ci (dev, skb, t3c_tid->ctx); 81562306a36Sopenharmony_ci } else { 81662306a36Sopenharmony_ci pr_err("%s: received clientless CPL command 0x%x\n", 81762306a36Sopenharmony_ci dev->name, CPL_PASS_ACCEPT_REQ); 81862306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/* 82362306a36Sopenharmony_ci * Returns an sk_buff for a reply CPL message of size len. If the input 82462306a36Sopenharmony_ci * sk_buff has no other users it is trimmed and reused, otherwise a new buffer 82562306a36Sopenharmony_ci * is allocated. The input skb must be of size at least len. Note that this 82662306a36Sopenharmony_ci * operation does not destroy the original skb data even if it decides to reuse 82762306a36Sopenharmony_ci * the buffer. 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_cistatic struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len, 83062306a36Sopenharmony_ci gfp_t gfp) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci if (likely(!skb_cloned(skb))) { 83362306a36Sopenharmony_ci BUG_ON(skb->len < len); 83462306a36Sopenharmony_ci __skb_trim(skb, len); 83562306a36Sopenharmony_ci skb_get(skb); 83662306a36Sopenharmony_ci } else { 83762306a36Sopenharmony_ci skb = alloc_skb(len, gfp); 83862306a36Sopenharmony_ci if (skb) 83962306a36Sopenharmony_ci __skb_put(skb, len); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci return skb; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci union opcode_tid *p = cplhdr(skb); 84762306a36Sopenharmony_ci unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); 84862306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); 85162306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && 85262306a36Sopenharmony_ci t3c_tid->client->handlers[p->opcode]) { 85362306a36Sopenharmony_ci return t3c_tid->client->handlers[p->opcode] 85462306a36Sopenharmony_ci (dev, skb, t3c_tid->ctx); 85562306a36Sopenharmony_ci } else { 85662306a36Sopenharmony_ci struct cpl_abort_req_rss *req = cplhdr(skb); 85762306a36Sopenharmony_ci struct cpl_abort_rpl *rpl; 85862306a36Sopenharmony_ci struct sk_buff *reply_skb; 85962306a36Sopenharmony_ci unsigned int tid = GET_TID(req); 86062306a36Sopenharmony_ci u8 cmd = req->status; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (req->status == CPL_ERR_RTX_NEG_ADVICE || 86362306a36Sopenharmony_ci req->status == CPL_ERR_PERSIST_NEG_ADVICE) 86462306a36Sopenharmony_ci goto out; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci reply_skb = cxgb3_get_cpl_reply_skb(skb, 86762306a36Sopenharmony_ci sizeof(struct 86862306a36Sopenharmony_ci cpl_abort_rpl), 86962306a36Sopenharmony_ci GFP_ATOMIC); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (!reply_skb) { 87262306a36Sopenharmony_ci printk("do_abort_req_rss: couldn't get skb!\n"); 87362306a36Sopenharmony_ci goto out; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci reply_skb->priority = CPL_PRIORITY_DATA; 87662306a36Sopenharmony_ci __skb_put(reply_skb, sizeof(struct cpl_abort_rpl)); 87762306a36Sopenharmony_ci rpl = cplhdr(reply_skb); 87862306a36Sopenharmony_ci rpl->wr.wr_hi = 87962306a36Sopenharmony_ci htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); 88062306a36Sopenharmony_ci rpl->wr.wr_lo = htonl(V_WR_TID(tid)); 88162306a36Sopenharmony_ci OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid)); 88262306a36Sopenharmony_ci rpl->cmd = cmd; 88362306a36Sopenharmony_ci cxgb3_ofld_send(dev, reply_skb); 88462306a36Sopenharmony_ciout: 88562306a36Sopenharmony_ci return CPL_RET_BUF_DONE; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci struct cpl_act_establish *req = cplhdr(skb); 89262306a36Sopenharmony_ci unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); 89362306a36Sopenharmony_ci struct tid_info *t = &(T3C_DATA(dev))->tid_maps; 89462306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 89562306a36Sopenharmony_ci unsigned int tid = GET_TID(req); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (unlikely(tid >= t->ntids)) { 89862306a36Sopenharmony_ci printk("%s: active establish TID %u too large\n", 89962306a36Sopenharmony_ci dev->name, tid); 90062306a36Sopenharmony_ci t3_fatal_err(tdev2adap(dev)); 90162306a36Sopenharmony_ci return CPL_RET_BUF_DONE; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci t3c_tid = lookup_atid(t, atid); 90562306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && 90662306a36Sopenharmony_ci t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { 90762306a36Sopenharmony_ci return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] 90862306a36Sopenharmony_ci (dev, skb, t3c_tid->ctx); 90962306a36Sopenharmony_ci } else { 91062306a36Sopenharmony_ci pr_err("%s: received clientless CPL command 0x%x\n", 91162306a36Sopenharmony_ci dev->name, CPL_ACT_ESTABLISH); 91262306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int do_trace(struct t3cdev *dev, struct sk_buff *skb) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci struct cpl_trace_pkt *p = cplhdr(skb); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci skb->protocol = htons(0xffff); 92162306a36Sopenharmony_ci skb->dev = dev->lldev; 92262306a36Sopenharmony_ci skb_pull(skb, sizeof(*p)); 92362306a36Sopenharmony_ci skb_reset_mac_header(skb); 92462306a36Sopenharmony_ci netif_receive_skb(skb); 92562306a36Sopenharmony_ci return 0; 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci/* 92962306a36Sopenharmony_ci * That skb would better have come from process_responses() where we abuse 93062306a36Sopenharmony_ci * ->priority and ->csum to carry our data. NB: if we get to per-arch 93162306a36Sopenharmony_ci * ->csum, the things might get really interesting here. 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic inline u32 get_hwtid(struct sk_buff *skb) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci return ntohl((__force __be32)skb->priority) >> 8 & 0xfffff; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic inline u32 get_opcode(struct sk_buff *skb) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci return G_OPCODE(ntohl((__force __be32)skb->csum)); 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int do_term(struct t3cdev *dev, struct sk_buff *skb) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci unsigned int hwtid = get_hwtid(skb); 94762306a36Sopenharmony_ci unsigned int opcode = get_opcode(skb); 94862306a36Sopenharmony_ci struct t3c_tid_entry *t3c_tid; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); 95162306a36Sopenharmony_ci if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && 95262306a36Sopenharmony_ci t3c_tid->client->handlers[opcode]) { 95362306a36Sopenharmony_ci return t3c_tid->client->handlers[opcode] (dev, skb, 95462306a36Sopenharmony_ci t3c_tid->ctx); 95562306a36Sopenharmony_ci } else { 95662306a36Sopenharmony_ci pr_err("%s: received clientless CPL command 0x%x\n", 95762306a36Sopenharmony_ci dev->name, opcode); 95862306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic int nb_callback(struct notifier_block *self, unsigned long event, 96362306a36Sopenharmony_ci void *ctx) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci switch (event) { 96662306a36Sopenharmony_ci case (NETEVENT_NEIGH_UPDATE):{ 96762306a36Sopenharmony_ci cxgb_neigh_update((struct neighbour *)ctx); 96862306a36Sopenharmony_ci break; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci case (NETEVENT_REDIRECT):{ 97162306a36Sopenharmony_ci struct netevent_redirect *nr = ctx; 97262306a36Sopenharmony_ci cxgb_redirect(nr->old, nr->new, nr->neigh, 97362306a36Sopenharmony_ci nr->daddr); 97462306a36Sopenharmony_ci cxgb_neigh_update(nr->neigh); 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci default: 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci return 0; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic struct notifier_block nb = { 98462306a36Sopenharmony_ci .notifier_call = nb_callback 98562306a36Sopenharmony_ci}; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/* 98862306a36Sopenharmony_ci * Process a received packet with an unknown/unexpected CPL opcode. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_cistatic int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci pr_err("%s: received bad CPL command 0x%x\n", dev->name, *skb->data); 99362306a36Sopenharmony_ci return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci/* 99762306a36Sopenharmony_ci * Handlers for each CPL opcode 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_cistatic cpl_handler_func cpl_handlers[NUM_CPL_CMDS]; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/* 100262306a36Sopenharmony_ci * Add a new handler to the CPL dispatch table. A NULL handler may be supplied 100362306a36Sopenharmony_ci * to unregister an existing handler. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_civoid t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci if (opcode < NUM_CPL_CMDS) 100862306a36Sopenharmony_ci cpl_handlers[opcode] = h ? h : do_bad_cpl; 100962306a36Sopenharmony_ci else 101062306a36Sopenharmony_ci pr_err("T3C: handler registration for opcode %x failed\n", 101162306a36Sopenharmony_ci opcode); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ciEXPORT_SYMBOL(t3_register_cpl_handler); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci/* 101762306a36Sopenharmony_ci * T3CDEV's receive method. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_cistatic int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci while (n--) { 102262306a36Sopenharmony_ci struct sk_buff *skb = *skbs++; 102362306a36Sopenharmony_ci unsigned int opcode = get_opcode(skb); 102462306a36Sopenharmony_ci int ret = cpl_handlers[opcode] (dev, skb); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci#if VALIDATE_TID 102762306a36Sopenharmony_ci if (ret & CPL_RET_UNKNOWN_TID) { 102862306a36Sopenharmony_ci union opcode_tid *p = cplhdr(skb); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci pr_err("%s: CPL message (opcode %u) had unknown TID %u\n", 103162306a36Sopenharmony_ci dev->name, opcode, G_TID(ntohl(p->opcode_tid))); 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci#endif 103462306a36Sopenharmony_ci if (ret & CPL_RET_BUF_DONE) 103562306a36Sopenharmony_ci kfree_skb(skb); 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci/* 104162306a36Sopenharmony_ci * Sends an sk_buff to a T3C driver after dealing with any active network taps. 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_ciint cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci int r; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci local_bh_disable(); 104862306a36Sopenharmony_ci r = dev->send(dev, skb); 104962306a36Sopenharmony_ci local_bh_enable(); 105062306a36Sopenharmony_ci return r; 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_ofld_send); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic int is_offloading(struct net_device *dev) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct adapter *adapter; 105862306a36Sopenharmony_ci int i; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci read_lock_bh(&adapter_list_lock); 106162306a36Sopenharmony_ci list_for_each_entry(adapter, &adapter_list, adapter_list) { 106262306a36Sopenharmony_ci for_each_port(adapter, i) { 106362306a36Sopenharmony_ci if (dev == adapter->port[i]) { 106462306a36Sopenharmony_ci read_unlock_bh(&adapter_list_lock); 106562306a36Sopenharmony_ci return 1; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci read_unlock_bh(&adapter_list_lock); 107062306a36Sopenharmony_ci return 0; 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic void cxgb_neigh_update(struct neighbour *neigh) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci struct net_device *dev; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (!neigh) 107862306a36Sopenharmony_ci return; 107962306a36Sopenharmony_ci dev = neigh->dev; 108062306a36Sopenharmony_ci if (dev && (is_offloading(dev))) { 108162306a36Sopenharmony_ci struct t3cdev *tdev = dev2t3cdev(dev); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci BUG_ON(!tdev); 108462306a36Sopenharmony_ci t3_l2t_update(tdev, neigh); 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci struct sk_buff *skb; 109162306a36Sopenharmony_ci struct cpl_set_tcb_field *req; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_ATOMIC); 109462306a36Sopenharmony_ci if (!skb) { 109562306a36Sopenharmony_ci pr_err("%s: cannot allocate skb!\n", __func__); 109662306a36Sopenharmony_ci return; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci skb->priority = CPL_PRIORITY_CONTROL; 109962306a36Sopenharmony_ci req = skb_put(skb, sizeof(*req)); 110062306a36Sopenharmony_ci req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 110162306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); 110262306a36Sopenharmony_ci req->reply = 0; 110362306a36Sopenharmony_ci req->cpu_idx = 0; 110462306a36Sopenharmony_ci req->word = htons(W_TCB_L2T_IX); 110562306a36Sopenharmony_ci req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX)); 110662306a36Sopenharmony_ci req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx)); 110762306a36Sopenharmony_ci tdev->send(tdev, skb); 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic void cxgb_redirect(struct dst_entry *old, struct dst_entry *new, 111162306a36Sopenharmony_ci struct neighbour *neigh, 111262306a36Sopenharmony_ci const void *daddr) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct net_device *dev; 111562306a36Sopenharmony_ci struct tid_info *ti; 111662306a36Sopenharmony_ci struct t3cdev *tdev; 111762306a36Sopenharmony_ci u32 tid; 111862306a36Sopenharmony_ci int update_tcb; 111962306a36Sopenharmony_ci struct l2t_entry *e; 112062306a36Sopenharmony_ci struct t3c_tid_entry *te; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci dev = neigh->dev; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (!is_offloading(dev)) 112562306a36Sopenharmony_ci return; 112662306a36Sopenharmony_ci tdev = dev2t3cdev(dev); 112762306a36Sopenharmony_ci BUG_ON(!tdev); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci /* Add new L2T entry */ 113062306a36Sopenharmony_ci e = t3_l2t_get(tdev, new, dev, daddr); 113162306a36Sopenharmony_ci if (!e) { 113262306a36Sopenharmony_ci pr_err("%s: couldn't allocate new l2t entry!\n", __func__); 113362306a36Sopenharmony_ci return; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* Walk tid table and notify clients of dst change. */ 113762306a36Sopenharmony_ci ti = &(T3C_DATA(tdev))->tid_maps; 113862306a36Sopenharmony_ci for (tid = 0; tid < ti->ntids; tid++) { 113962306a36Sopenharmony_ci te = lookup_tid(ti, tid); 114062306a36Sopenharmony_ci BUG_ON(!te); 114162306a36Sopenharmony_ci if (te && te->ctx && te->client && te->client->redirect) { 114262306a36Sopenharmony_ci update_tcb = te->client->redirect(te->ctx, old, new, e); 114362306a36Sopenharmony_ci if (update_tcb) { 114462306a36Sopenharmony_ci rcu_read_lock(); 114562306a36Sopenharmony_ci l2t_hold(L2DATA(tdev), e); 114662306a36Sopenharmony_ci rcu_read_unlock(); 114762306a36Sopenharmony_ci set_l2t_ix(tdev, tid, e); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci l2t_release(tdev, e); 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci/* 115562306a36Sopenharmony_ci * Allocate and initialize the TID tables. Returns 0 on success. 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_cistatic int init_tid_tabs(struct tid_info *t, unsigned int ntids, 115862306a36Sopenharmony_ci unsigned int natids, unsigned int nstids, 115962306a36Sopenharmony_ci unsigned int atid_base, unsigned int stid_base) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci unsigned long size = ntids * sizeof(*t->tid_tab) + 116262306a36Sopenharmony_ci natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci t->tid_tab = kvzalloc(size, GFP_KERNEL); 116562306a36Sopenharmony_ci if (!t->tid_tab) 116662306a36Sopenharmony_ci return -ENOMEM; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci t->stid_tab = (union listen_entry *)&t->tid_tab[ntids]; 116962306a36Sopenharmony_ci t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids]; 117062306a36Sopenharmony_ci t->ntids = ntids; 117162306a36Sopenharmony_ci t->nstids = nstids; 117262306a36Sopenharmony_ci t->stid_base = stid_base; 117362306a36Sopenharmony_ci t->sfree = NULL; 117462306a36Sopenharmony_ci t->natids = natids; 117562306a36Sopenharmony_ci t->atid_base = atid_base; 117662306a36Sopenharmony_ci t->afree = NULL; 117762306a36Sopenharmony_ci t->stids_in_use = t->atids_in_use = 0; 117862306a36Sopenharmony_ci atomic_set(&t->tids_in_use, 0); 117962306a36Sopenharmony_ci spin_lock_init(&t->stid_lock); 118062306a36Sopenharmony_ci spin_lock_init(&t->atid_lock); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* 118362306a36Sopenharmony_ci * Setup the free lists for stid_tab and atid_tab. 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_ci if (nstids) { 118662306a36Sopenharmony_ci while (--nstids) 118762306a36Sopenharmony_ci t->stid_tab[nstids - 1].next = &t->stid_tab[nstids]; 118862306a36Sopenharmony_ci t->sfree = t->stid_tab; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci if (natids) { 119162306a36Sopenharmony_ci while (--natids) 119262306a36Sopenharmony_ci t->atid_tab[natids - 1].next = &t->atid_tab[natids]; 119362306a36Sopenharmony_ci t->afree = t->atid_tab; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci return 0; 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic void free_tid_maps(struct tid_info *t) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci kvfree(t->tid_tab); 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic inline void add_adapter(struct adapter *adap) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci write_lock_bh(&adapter_list_lock); 120662306a36Sopenharmony_ci list_add_tail(&adap->adapter_list, &adapter_list); 120762306a36Sopenharmony_ci write_unlock_bh(&adapter_list_lock); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic inline void remove_adapter(struct adapter *adap) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci write_lock_bh(&adapter_list_lock); 121362306a36Sopenharmony_ci list_del(&adap->adapter_list); 121462306a36Sopenharmony_ci write_unlock_bh(&adapter_list_lock); 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ciint cxgb3_offload_activate(struct adapter *adapter) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct t3cdev *dev = &adapter->tdev; 122062306a36Sopenharmony_ci int natids, err; 122162306a36Sopenharmony_ci struct t3c_data *t; 122262306a36Sopenharmony_ci struct tid_range stid_range, tid_range; 122362306a36Sopenharmony_ci struct mtutab mtutab; 122462306a36Sopenharmony_ci unsigned int l2t_capacity; 122562306a36Sopenharmony_ci struct l2t_data *l2td; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci t = kzalloc(sizeof(*t), GFP_KERNEL); 122862306a36Sopenharmony_ci if (!t) 122962306a36Sopenharmony_ci return -ENOMEM; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci err = -EOPNOTSUPP; 123262306a36Sopenharmony_ci if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 || 123362306a36Sopenharmony_ci dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 || 123462306a36Sopenharmony_ci dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 || 123562306a36Sopenharmony_ci dev->ctl(dev, GET_MTUS, &mtutab) < 0 || 123662306a36Sopenharmony_ci dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 || 123762306a36Sopenharmony_ci dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0) 123862306a36Sopenharmony_ci goto out_free; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci err = -ENOMEM; 124162306a36Sopenharmony_ci l2td = t3_init_l2t(l2t_capacity); 124262306a36Sopenharmony_ci if (!l2td) 124362306a36Sopenharmony_ci goto out_free; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci natids = min(tid_range.num / 2, MAX_ATIDS); 124662306a36Sopenharmony_ci err = init_tid_tabs(&t->tid_maps, tid_range.num, natids, 124762306a36Sopenharmony_ci stid_range.num, ATID_BASE, stid_range.base); 124862306a36Sopenharmony_ci if (err) 124962306a36Sopenharmony_ci goto out_free_l2t; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci t->mtus = mtutab.mtus; 125262306a36Sopenharmony_ci t->nmtus = mtutab.size; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci INIT_WORK(&t->tid_release_task, t3_process_tid_release_list); 125562306a36Sopenharmony_ci spin_lock_init(&t->tid_release_lock); 125662306a36Sopenharmony_ci INIT_LIST_HEAD(&t->list_node); 125762306a36Sopenharmony_ci t->dev = dev; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci RCU_INIT_POINTER(dev->l2opt, l2td); 126062306a36Sopenharmony_ci T3C_DATA(dev) = t; 126162306a36Sopenharmony_ci dev->recv = process_rx; 126262306a36Sopenharmony_ci dev->neigh_update = t3_l2t_update; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* Register netevent handler once */ 126562306a36Sopenharmony_ci if (list_empty(&adapter_list)) 126662306a36Sopenharmony_ci register_netevent_notifier(&nb); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); 126962306a36Sopenharmony_ci t->release_list_incomplete = 0; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci add_adapter(adapter); 127262306a36Sopenharmony_ci return 0; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ciout_free_l2t: 127562306a36Sopenharmony_ci kvfree(l2td); 127662306a36Sopenharmony_ciout_free: 127762306a36Sopenharmony_ci kfree(t); 127862306a36Sopenharmony_ci return err; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic void clean_l2_data(struct rcu_head *head) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci struct l2t_data *d = container_of(head, struct l2t_data, rcu_head); 128462306a36Sopenharmony_ci kvfree(d); 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_civoid cxgb3_offload_deactivate(struct adapter *adapter) 128962306a36Sopenharmony_ci{ 129062306a36Sopenharmony_ci struct t3cdev *tdev = &adapter->tdev; 129162306a36Sopenharmony_ci struct t3c_data *t = T3C_DATA(tdev); 129262306a36Sopenharmony_ci struct l2t_data *d; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci remove_adapter(adapter); 129562306a36Sopenharmony_ci if (list_empty(&adapter_list)) 129662306a36Sopenharmony_ci unregister_netevent_notifier(&nb); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci free_tid_maps(&t->tid_maps); 129962306a36Sopenharmony_ci T3C_DATA(tdev) = NULL; 130062306a36Sopenharmony_ci rcu_read_lock(); 130162306a36Sopenharmony_ci d = L2DATA(tdev); 130262306a36Sopenharmony_ci rcu_read_unlock(); 130362306a36Sopenharmony_ci RCU_INIT_POINTER(tdev->l2opt, NULL); 130462306a36Sopenharmony_ci call_rcu(&d->rcu_head, clean_l2_data); 130562306a36Sopenharmony_ci kfree_skb(t->nofail_skb); 130662306a36Sopenharmony_ci kfree(t); 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic inline void register_tdev(struct t3cdev *tdev) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci static int unit; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 131462306a36Sopenharmony_ci snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++); 131562306a36Sopenharmony_ci list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list); 131662306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic inline void unregister_tdev(struct t3cdev *tdev) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci mutex_lock(&cxgb3_db_lock); 132262306a36Sopenharmony_ci list_del(&tdev->ofld_dev_list); 132362306a36Sopenharmony_ci mutex_unlock(&cxgb3_db_lock); 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic inline int adap2type(struct adapter *adapter) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci int type = 0; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci switch (adapter->params.rev) { 133162306a36Sopenharmony_ci case T3_REV_A: 133262306a36Sopenharmony_ci type = T3A; 133362306a36Sopenharmony_ci break; 133462306a36Sopenharmony_ci case T3_REV_B: 133562306a36Sopenharmony_ci case T3_REV_B2: 133662306a36Sopenharmony_ci type = T3B; 133762306a36Sopenharmony_ci break; 133862306a36Sopenharmony_ci case T3_REV_C: 133962306a36Sopenharmony_ci type = T3C; 134062306a36Sopenharmony_ci break; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci return type; 134362306a36Sopenharmony_ci} 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_civoid cxgb3_adapter_ofld(struct adapter *adapter) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci struct t3cdev *tdev = &adapter->tdev; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci INIT_LIST_HEAD(&tdev->ofld_dev_list); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci cxgb3_set_dummy_ops(tdev); 135262306a36Sopenharmony_ci tdev->send = t3_offload_tx; 135362306a36Sopenharmony_ci tdev->ctl = cxgb_offload_ctl; 135462306a36Sopenharmony_ci tdev->type = adap2type(adapter); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci register_tdev(tdev); 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_civoid cxgb3_adapter_unofld(struct adapter *adapter) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct t3cdev *tdev = &adapter->tdev; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci tdev->recv = NULL; 136462306a36Sopenharmony_ci tdev->neigh_update = NULL; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci unregister_tdev(tdev); 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_civoid __init cxgb3_offload_init(void) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci int i; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci for (i = 0; i < NUM_CPL_CMDS; ++i) 137462306a36Sopenharmony_ci cpl_handlers[i] = do_bad_cpl; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl); 137762306a36Sopenharmony_ci t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl); 137862306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl); 137962306a36Sopenharmony_ci t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl); 138062306a36Sopenharmony_ci t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl); 138162306a36Sopenharmony_ci t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr); 138262306a36Sopenharmony_ci t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl); 138362306a36Sopenharmony_ci t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl); 138462306a36Sopenharmony_ci t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl); 138562306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl); 138662306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl); 138762306a36Sopenharmony_ci t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl); 138862306a36Sopenharmony_ci t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl); 138962306a36Sopenharmony_ci t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl); 139062306a36Sopenharmony_ci t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl); 139162306a36Sopenharmony_ci t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); 139262306a36Sopenharmony_ci t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); 139362306a36Sopenharmony_ci t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); 139462306a36Sopenharmony_ci t3_register_cpl_handler(CPL_SET_TCB_RPL, do_hwtid_rpl); 139562306a36Sopenharmony_ci t3_register_cpl_handler(CPL_GET_TCB_RPL, do_hwtid_rpl); 139662306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); 139762306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); 139862306a36Sopenharmony_ci t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); 139962306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl); 140062306a36Sopenharmony_ci t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl); 140162306a36Sopenharmony_ci t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl); 140262306a36Sopenharmony_ci} 1403