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