18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is part of the Chelsio T4 Ethernet driver for Linux. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 388c2ecf20Sopenharmony_ci#include <linux/crc32.h> 398c2ecf20Sopenharmony_ci#include <linux/ctype.h> 408c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 418c2ecf20Sopenharmony_ci#include <linux/err.h> 428c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 438c2ecf20Sopenharmony_ci#include <linux/firmware.h> 448c2ecf20Sopenharmony_ci#include <linux/if.h> 458c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 468c2ecf20Sopenharmony_ci#include <linux/init.h> 478c2ecf20Sopenharmony_ci#include <linux/log2.h> 488c2ecf20Sopenharmony_ci#include <linux/mdio.h> 498c2ecf20Sopenharmony_ci#include <linux/module.h> 508c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 518c2ecf20Sopenharmony_ci#include <linux/mutex.h> 528c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 538c2ecf20Sopenharmony_ci#include <linux/pci.h> 548c2ecf20Sopenharmony_ci#include <linux/aer.h> 558c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 568c2ecf20Sopenharmony_ci#include <linux/sched.h> 578c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 588c2ecf20Sopenharmony_ci#include <linux/sockios.h> 598c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 608c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 618c2ecf20Sopenharmony_ci#include <net/neighbour.h> 628c2ecf20Sopenharmony_ci#include <net/netevent.h> 638c2ecf20Sopenharmony_ci#include <net/addrconf.h> 648c2ecf20Sopenharmony_ci#include <net/bonding.h> 658c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 668c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 678c2ecf20Sopenharmony_ci#include <net/udp_tunnel.h> 688c2ecf20Sopenharmony_ci#include <net/xfrm.h> 698c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 708c2ecf20Sopenharmony_ci#include <net/tls.h> 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#include "cxgb4.h" 748c2ecf20Sopenharmony_ci#include "cxgb4_filter.h" 758c2ecf20Sopenharmony_ci#include "t4_regs.h" 768c2ecf20Sopenharmony_ci#include "t4_values.h" 778c2ecf20Sopenharmony_ci#include "t4_msg.h" 788c2ecf20Sopenharmony_ci#include "t4fw_api.h" 798c2ecf20Sopenharmony_ci#include "t4fw_version.h" 808c2ecf20Sopenharmony_ci#include "cxgb4_dcb.h" 818c2ecf20Sopenharmony_ci#include "srq.h" 828c2ecf20Sopenharmony_ci#include "cxgb4_debugfs.h" 838c2ecf20Sopenharmony_ci#include "clip_tbl.h" 848c2ecf20Sopenharmony_ci#include "l2t.h" 858c2ecf20Sopenharmony_ci#include "smt.h" 868c2ecf20Sopenharmony_ci#include "sched.h" 878c2ecf20Sopenharmony_ci#include "cxgb4_tc_u32.h" 888c2ecf20Sopenharmony_ci#include "cxgb4_tc_flower.h" 898c2ecf20Sopenharmony_ci#include "cxgb4_tc_mqprio.h" 908c2ecf20Sopenharmony_ci#include "cxgb4_tc_matchall.h" 918c2ecf20Sopenharmony_ci#include "cxgb4_ptp.h" 928c2ecf20Sopenharmony_ci#include "cxgb4_cudbg.h" 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cichar cxgb4_driver_name[] = KBUILD_MODNAME; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define DRV_DESC "Chelsio T4/T5/T6 Network Driver" 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ 998c2ecf20Sopenharmony_ci NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ 1008c2ecf20Sopenharmony_ci NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Macros needed to support the PCI Device ID Table ... 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \ 1058c2ecf20Sopenharmony_ci static const struct pci_device_id cxgb4_pci_tbl[] = { 1068c2ecf20Sopenharmony_ci#define CXGB4_UNIFIED_PF 0x4 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION CXGB4_UNIFIED_PF 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* Include PCI Device IDs for both PF4 and PF0-3 so our PCI probe() routine is 1118c2ecf20Sopenharmony_ci * called for both. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION2 0x0 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define CH_PCI_ID_TABLE_ENTRY(devid) \ 1168c2ecf20Sopenharmony_ci {PCI_VDEVICE(CHELSIO, (devid)), CXGB4_UNIFIED_PF} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_END \ 1198c2ecf20Sopenharmony_ci { 0, } \ 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#include "t4_pci_id_tbl.h" 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define FW4_FNAME "cxgb4/t4fw.bin" 1258c2ecf20Sopenharmony_ci#define FW5_FNAME "cxgb4/t5fw.bin" 1268c2ecf20Sopenharmony_ci#define FW6_FNAME "cxgb4/t6fw.bin" 1278c2ecf20Sopenharmony_ci#define FW4_CFNAME "cxgb4/t4-config.txt" 1288c2ecf20Sopenharmony_ci#define FW5_CFNAME "cxgb4/t5-config.txt" 1298c2ecf20Sopenharmony_ci#define FW6_CFNAME "cxgb4/t6-config.txt" 1308c2ecf20Sopenharmony_ci#define PHY_AQ1202_FIRMWARE "cxgb4/aq1202_fw.cld" 1318c2ecf20Sopenharmony_ci#define PHY_BCM84834_FIRMWARE "cxgb4/bcm8483.bin" 1328c2ecf20Sopenharmony_ci#define PHY_AQ1202_DEVICEID 0x4409 1338c2ecf20Sopenharmony_ci#define PHY_BCM84834_DEVICEID 0x4486 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC); 1368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications"); 1378c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); 1398c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW4_FNAME); 1408c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW5_FNAME); 1418c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW6_FNAME); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * The driver uses the best interrupt scheme available on a platform in the 1458c2ecf20Sopenharmony_ci * order MSI-X, MSI, legacy INTx interrupts. This parameter determines which 1468c2ecf20Sopenharmony_ci * of these schemes the driver may consider as follows: 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * msi = 2: choose from among all three options 1498c2ecf20Sopenharmony_ci * msi = 1: only consider MSI and INTx interrupts 1508c2ecf20Sopenharmony_ci * msi = 0: force INTx interrupts 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_cistatic int msi = 2; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cimodule_param(msi, int, 0644); 1558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msi, "whether to use INTx (0), MSI (1) or MSI-X (2)"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* 1588c2ecf20Sopenharmony_ci * Normally we tell the chip to deliver Ingress Packets into our DMA buffers 1598c2ecf20Sopenharmony_ci * offset by 2 bytes in order to have the IP headers line up on 4-byte 1608c2ecf20Sopenharmony_ci * boundaries. This is a requirement for many architectures which will throw 1618c2ecf20Sopenharmony_ci * a machine check fault if an attempt is made to access one of the 4-byte IP 1628c2ecf20Sopenharmony_ci * header fields on a non-4-byte boundary. And it's a major performance issue 1638c2ecf20Sopenharmony_ci * even on some architectures which allow it like some implementations of the 1648c2ecf20Sopenharmony_ci * x86 ISA. However, some architectures don't mind this and for some very 1658c2ecf20Sopenharmony_ci * edge-case performance sensitive applications (like forwarding large volumes 1668c2ecf20Sopenharmony_ci * of small packets), setting this DMA offset to 0 will decrease the number of 1678c2ecf20Sopenharmony_ci * PCI-E Bus transfers enough to measurably affect performance. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_cistatic int rx_dma_offset = 2; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* TX Queue select used to determine what algorithm to use for selecting TX 1728c2ecf20Sopenharmony_ci * queue. Select between the kernel provided function (select_queue=0) or user 1738c2ecf20Sopenharmony_ci * cxgb_select_queue function (select_queue=1) 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * Default: select_queue=0 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_cistatic int select_queue; 1788c2ecf20Sopenharmony_cimodule_param(select_queue, int, 0644); 1798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(select_queue, 1808c2ecf20Sopenharmony_ci "Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method."); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic struct dentry *cxgb4_debugfs_root; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciLIST_HEAD(adapter_list); 1858c2ecf20Sopenharmony_ciDEFINE_MUTEX(uld_mutex); 1868c2ecf20Sopenharmony_ciLIST_HEAD(uld_list); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int cfg_queues(struct adapter *adap); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void link_report(struct net_device *dev) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev)) 1938c2ecf20Sopenharmony_ci netdev_info(dev, "link down\n"); 1948c2ecf20Sopenharmony_ci else { 1958c2ecf20Sopenharmony_ci static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" }; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci const char *s; 1988c2ecf20Sopenharmony_ci const struct port_info *p = netdev_priv(dev); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch (p->link_cfg.speed) { 2018c2ecf20Sopenharmony_ci case 100: 2028c2ecf20Sopenharmony_ci s = "100Mbps"; 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case 1000: 2058c2ecf20Sopenharmony_ci s = "1Gbps"; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case 10000: 2088c2ecf20Sopenharmony_ci s = "10Gbps"; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case 25000: 2118c2ecf20Sopenharmony_ci s = "25Gbps"; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case 40000: 2148c2ecf20Sopenharmony_ci s = "40Gbps"; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case 50000: 2178c2ecf20Sopenharmony_ci s = "50Gbps"; 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case 100000: 2208c2ecf20Sopenharmony_ci s = "100Gbps"; 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci default: 2238c2ecf20Sopenharmony_ci pr_info("%s: unsupported speed: %d\n", 2248c2ecf20Sopenharmony_ci dev->name, p->link_cfg.speed); 2258c2ecf20Sopenharmony_ci return; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, 2298c2ecf20Sopenharmony_ci fc[p->link_cfg.fc]); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 2348c2ecf20Sopenharmony_ci/* Set up/tear down Data Center Bridging Priority mapping for a net device. */ 2358c2ecf20Sopenharmony_cistatic void dcb_tx_queue_prio_enable(struct net_device *dev, int enable) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 2388c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 2398c2ecf20Sopenharmony_ci struct sge_eth_txq *txq = &adap->sge.ethtxq[pi->first_qset]; 2408c2ecf20Sopenharmony_ci int i; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* We use a simple mapping of Port TX Queue Index to DCB 2438c2ecf20Sopenharmony_ci * Priority when we're enabling DCB. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci for (i = 0; i < pi->nqsets; i++, txq++) { 2468c2ecf20Sopenharmony_ci u32 name, value; 2478c2ecf20Sopenharmony_ci int err; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci name = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 2508c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V( 2518c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH) | 2528c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id)); 2538c2ecf20Sopenharmony_ci value = enable ? i : 0xffffffff; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Since we can be called while atomic (from "interrupt 2568c2ecf20Sopenharmony_ci * level") we need to issue the Set Parameters Commannd 2578c2ecf20Sopenharmony_ci * without sleeping (timeout < 0). 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci err = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1, 2608c2ecf20Sopenharmony_ci &name, &value, 2618c2ecf20Sopenharmony_ci -FW_CMD_MAX_TIMEOUT); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (err) 2648c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 2658c2ecf20Sopenharmony_ci "Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n", 2668c2ecf20Sopenharmony_ci enable ? "set" : "unset", pi->port_id, i, -err); 2678c2ecf20Sopenharmony_ci else 2688c2ecf20Sopenharmony_ci txq->dcb_prio = enable ? value : 0; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ciint cxgb4_dcb_enabled(const struct net_device *dev) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (!pi->dcb.enabled) 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return ((pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED) || 2808c2ecf20Sopenharmony_ci (pi->dcb.state == CXGB4_DCB_STATE_HOST)); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_civoid t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct net_device *dev = adapter->port[port_id]; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Skip changes from disabled ports. */ 2898c2ecf20Sopenharmony_ci if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) { 2908c2ecf20Sopenharmony_ci if (link_stat) 2918c2ecf20Sopenharmony_ci netif_carrier_on(dev); 2928c2ecf20Sopenharmony_ci else { 2938c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 2948c2ecf20Sopenharmony_ci if (cxgb4_dcb_enabled(dev)) { 2958c2ecf20Sopenharmony_ci cxgb4_dcb_reset(dev); 2968c2ecf20Sopenharmony_ci dcb_tx_queue_prio_enable(dev, false); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 2998c2ecf20Sopenharmony_ci netif_carrier_off(dev); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci link_report(dev); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_civoid t4_os_portmod_changed(struct adapter *adap, int port_id) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci static const char *mod_str[] = { 3098c2ecf20Sopenharmony_ci NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" 3108c2ecf20Sopenharmony_ci }; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci struct net_device *dev = adap->port[port_id]; 3138c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 3168c2ecf20Sopenharmony_ci netdev_info(dev, "port module unplugged\n"); 3178c2ecf20Sopenharmony_ci else if (pi->mod_type < ARRAY_SIZE(mod_str)) 3188c2ecf20Sopenharmony_ci netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); 3198c2ecf20Sopenharmony_ci else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 3208c2ecf20Sopenharmony_ci netdev_info(dev, "%s: unsupported port module inserted\n", 3218c2ecf20Sopenharmony_ci dev->name); 3228c2ecf20Sopenharmony_ci else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 3238c2ecf20Sopenharmony_ci netdev_info(dev, "%s: unknown port module inserted\n", 3248c2ecf20Sopenharmony_ci dev->name); 3258c2ecf20Sopenharmony_ci else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR) 3268c2ecf20Sopenharmony_ci netdev_info(dev, "%s: transceiver module error\n", dev->name); 3278c2ecf20Sopenharmony_ci else 3288c2ecf20Sopenharmony_ci netdev_info(dev, "%s: unknown module type %d inserted\n", 3298c2ecf20Sopenharmony_ci dev->name, pi->mod_type); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* If the interface is running, then we'll need any "sticky" Link 3328c2ecf20Sopenharmony_ci * Parameters redone with a new Transceiver Module. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci pi->link_cfg.redo_l1cfg = netif_running(dev); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */ 3388c2ecf20Sopenharmony_cimodule_param(dbfifo_int_thresh, int, 0644); 3398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold"); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/* 3428c2ecf20Sopenharmony_ci * usecs to sleep while draining the dbfifo 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_cistatic int dbfifo_drain_delay = 1000; 3458c2ecf20Sopenharmony_cimodule_param(dbfifo_drain_delay, int, 0644); 3468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dbfifo_drain_delay, 3478c2ecf20Sopenharmony_ci "usecs to sleep while draining the dbfifo"); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic inline int cxgb4_set_addr_hash(struct port_info *pi) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 3528c2ecf20Sopenharmony_ci u64 vec = 0; 3538c2ecf20Sopenharmony_ci bool ucast = false; 3548c2ecf20Sopenharmony_ci struct hash_mac_addr *entry; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Calculate the hash vector for the updated list and program it */ 3578c2ecf20Sopenharmony_ci list_for_each_entry(entry, &adap->mac_hlist, list) { 3588c2ecf20Sopenharmony_ci ucast |= is_unicast_ether_addr(entry->addr); 3598c2ecf20Sopenharmony_ci vec |= (1ULL << hash_mac_addr(entry->addr)); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast, 3628c2ecf20Sopenharmony_ci vec, false); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 3688c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci u64 mhash = 0; 3718c2ecf20Sopenharmony_ci u64 uhash = 0; 3728c2ecf20Sopenharmony_ci /* idx stores the index of allocated filters, 3738c2ecf20Sopenharmony_ci * its size should be modified based on the number of 3748c2ecf20Sopenharmony_ci * MAC addresses that we allocate filters for 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci u16 idx[1] = {}; 3788c2ecf20Sopenharmony_ci bool free = false; 3798c2ecf20Sopenharmony_ci bool ucast = is_unicast_ether_addr(mac_addr); 3808c2ecf20Sopenharmony_ci const u8 *maclist[1] = {mac_addr}; 3818c2ecf20Sopenharmony_ci struct hash_mac_addr *new_entry; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci ret = cxgb4_alloc_mac_filt(adap, pi->viid, free, 1, maclist, 3848c2ecf20Sopenharmony_ci idx, ucast ? &uhash : &mhash, false); 3858c2ecf20Sopenharmony_ci if (ret < 0) 3868c2ecf20Sopenharmony_ci goto out; 3878c2ecf20Sopenharmony_ci /* if hash != 0, then add the addr to hash addr list 3888c2ecf20Sopenharmony_ci * so on the end we will calculate the hash for the 3898c2ecf20Sopenharmony_ci * list and program it 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci if (uhash || mhash) { 3928c2ecf20Sopenharmony_ci new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC); 3938c2ecf20Sopenharmony_ci if (!new_entry) 3948c2ecf20Sopenharmony_ci return -ENOMEM; 3958c2ecf20Sopenharmony_ci ether_addr_copy(new_entry->addr, mac_addr); 3968c2ecf20Sopenharmony_ci list_add_tail(&new_entry->list, &adap->mac_hlist); 3978c2ecf20Sopenharmony_ci ret = cxgb4_set_addr_hash(pi); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ciout: 4008c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 4068c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 4078c2ecf20Sopenharmony_ci int ret; 4088c2ecf20Sopenharmony_ci const u8 *maclist[1] = {mac_addr}; 4098c2ecf20Sopenharmony_ci struct hash_mac_addr *entry, *tmp; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* If the MAC address to be removed is in the hash addr 4128c2ecf20Sopenharmony_ci * list, delete it from the list and update hash vector 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) { 4158c2ecf20Sopenharmony_ci if (ether_addr_equal(entry->addr, mac_addr)) { 4168c2ecf20Sopenharmony_ci list_del(&entry->list); 4178c2ecf20Sopenharmony_ci kfree(entry); 4188c2ecf20Sopenharmony_ci return cxgb4_set_addr_hash(pi); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ret = cxgb4_free_mac_filt(adap, pi->viid, 1, maclist, false); 4238c2ecf20Sopenharmony_ci return ret < 0 ? -EINVAL : 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* 4278c2ecf20Sopenharmony_ci * Set Rx properties of a port, such as promiscruity, address filters, and MTU. 4288c2ecf20Sopenharmony_ci * If @mtu is -1 it is left unchanged. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 4338c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci __dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync); 4368c2ecf20Sopenharmony_ci __dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return t4_set_rxmode(adapter, adapter->mbox, pi->viid, pi->viid_mirror, 4398c2ecf20Sopenharmony_ci mtu, (dev->flags & IFF_PROMISC) ? 1 : 0, 4408c2ecf20Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, 4418c2ecf20Sopenharmony_ci sleep_ok); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/** 4458c2ecf20Sopenharmony_ci * cxgb4_change_mac - Update match filter for a MAC address. 4468c2ecf20Sopenharmony_ci * @pi: the port_info 4478c2ecf20Sopenharmony_ci * @viid: the VI id 4488c2ecf20Sopenharmony_ci * @tcam_idx: TCAM index of existing filter for old value of MAC address, 4498c2ecf20Sopenharmony_ci * or -1 4508c2ecf20Sopenharmony_ci * @addr: the new MAC address value 4518c2ecf20Sopenharmony_ci * @persist: whether a new MAC allocation should be persistent 4528c2ecf20Sopenharmony_ci * @smt_idx: the destination to store the new SMT index. 4538c2ecf20Sopenharmony_ci * 4548c2ecf20Sopenharmony_ci * Modifies an MPS filter and sets it to the new MAC address if 4558c2ecf20Sopenharmony_ci * @tcam_idx >= 0, or adds the MAC address to a new filter if 4568c2ecf20Sopenharmony_ci * @tcam_idx < 0. In the latter case the address is added persistently 4578c2ecf20Sopenharmony_ci * if @persist is %true. 4588c2ecf20Sopenharmony_ci * Addresses are programmed to hash region, if tcam runs out of entries. 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ciint cxgb4_change_mac(struct port_info *pi, unsigned int viid, 4628c2ecf20Sopenharmony_ci int *tcam_idx, const u8 *addr, bool persist, 4638c2ecf20Sopenharmony_ci u8 *smt_idx) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 4668c2ecf20Sopenharmony_ci struct hash_mac_addr *entry, *new_entry; 4678c2ecf20Sopenharmony_ci int ret; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ret = t4_change_mac(adapter, adapter->mbox, viid, 4708c2ecf20Sopenharmony_ci *tcam_idx, addr, persist, smt_idx); 4718c2ecf20Sopenharmony_ci /* We ran out of TCAM entries. try programming hash region. */ 4728c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 4738c2ecf20Sopenharmony_ci /* If the MAC address to be updated is in the hash addr 4748c2ecf20Sopenharmony_ci * list, update it from the list 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci list_for_each_entry(entry, &adapter->mac_hlist, list) { 4778c2ecf20Sopenharmony_ci if (entry->iface_mac) { 4788c2ecf20Sopenharmony_ci ether_addr_copy(entry->addr, addr); 4798c2ecf20Sopenharmony_ci goto set_hash; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); 4838c2ecf20Sopenharmony_ci if (!new_entry) 4848c2ecf20Sopenharmony_ci return -ENOMEM; 4858c2ecf20Sopenharmony_ci ether_addr_copy(new_entry->addr, addr); 4868c2ecf20Sopenharmony_ci new_entry->iface_mac = true; 4878c2ecf20Sopenharmony_ci list_add_tail(&new_entry->list, &adapter->mac_hlist); 4888c2ecf20Sopenharmony_ciset_hash: 4898c2ecf20Sopenharmony_ci ret = cxgb4_set_addr_hash(pi); 4908c2ecf20Sopenharmony_ci } else if (ret >= 0) { 4918c2ecf20Sopenharmony_ci *tcam_idx = ret; 4928c2ecf20Sopenharmony_ci ret = 0; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/* 4998c2ecf20Sopenharmony_ci * link_start - enable a port 5008c2ecf20Sopenharmony_ci * @dev: the port to enable 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * Performs the MAC and PHY actions needed to enable a port. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_cistatic int link_start(struct net_device *dev) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 5078c2ecf20Sopenharmony_ci unsigned int mb = pi->adapter->mbox; 5088c2ecf20Sopenharmony_ci int ret; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* 5118c2ecf20Sopenharmony_ci * We do not set address filters and promiscuity here, the stack does 5128c2ecf20Sopenharmony_ci * that step explicitly. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci ret = t4_set_rxmode(pi->adapter, mb, pi->viid, pi->viid_mirror, 5158c2ecf20Sopenharmony_ci dev->mtu, -1, -1, -1, 5168c2ecf20Sopenharmony_ci !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true); 5178c2ecf20Sopenharmony_ci if (ret == 0) 5188c2ecf20Sopenharmony_ci ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt, 5198c2ecf20Sopenharmony_ci dev->dev_addr, true, &pi->smt_idx); 5208c2ecf20Sopenharmony_ci if (ret == 0) 5218c2ecf20Sopenharmony_ci ret = t4_link_l1cfg(pi->adapter, mb, pi->tx_chan, 5228c2ecf20Sopenharmony_ci &pi->link_cfg); 5238c2ecf20Sopenharmony_ci if (ret == 0) { 5248c2ecf20Sopenharmony_ci local_bh_disable(); 5258c2ecf20Sopenharmony_ci ret = t4_enable_pi_params(pi->adapter, mb, pi, true, 5268c2ecf20Sopenharmony_ci true, CXGB4_DCB_ENABLED); 5278c2ecf20Sopenharmony_ci local_bh_enable(); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 5348c2ecf20Sopenharmony_ci/* Handle a Data Center Bridging update message from the firmware. */ 5358c2ecf20Sopenharmony_cistatic void dcb_rpl(struct adapter *adap, const struct fw_port_cmd *pcmd) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci int port = FW_PORT_CMD_PORTID_G(ntohl(pcmd->op_to_portid)); 5388c2ecf20Sopenharmony_ci struct net_device *dev = adap->port[adap->chan_map[port]]; 5398c2ecf20Sopenharmony_ci int old_dcb_enabled = cxgb4_dcb_enabled(dev); 5408c2ecf20Sopenharmony_ci int new_dcb_enabled; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci cxgb4_dcb_handle_fw_update(adap, pcmd); 5438c2ecf20Sopenharmony_ci new_dcb_enabled = cxgb4_dcb_enabled(dev); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* If the DCB has become enabled or disabled on the port then we're 5468c2ecf20Sopenharmony_ci * going to need to set up/tear down DCB Priority parameters for the 5478c2ecf20Sopenharmony_ci * TX Queues associated with the port. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci if (new_dcb_enabled != old_dcb_enabled) 5508c2ecf20Sopenharmony_ci dcb_tx_queue_prio_enable(dev, new_dcb_enabled); 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* Response queue handler for the FW event queue. 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_cistatic int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, 5578c2ecf20Sopenharmony_ci const struct pkt_gl *gl) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci u8 opcode = ((const struct rss_header *)rsp)->opcode; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci rsp++; /* skip RSS header */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG. 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci if (unlikely(opcode == CPL_FW4_MSG && 5668c2ecf20Sopenharmony_ci ((const struct cpl_fw4_msg *)rsp)->type == FW_TYPE_RSSCPL)) { 5678c2ecf20Sopenharmony_ci rsp++; 5688c2ecf20Sopenharmony_ci opcode = ((const struct rss_header *)rsp)->opcode; 5698c2ecf20Sopenharmony_ci rsp++; 5708c2ecf20Sopenharmony_ci if (opcode != CPL_SGE_EGR_UPDATE) { 5718c2ecf20Sopenharmony_ci dev_err(q->adap->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n" 5728c2ecf20Sopenharmony_ci , opcode); 5738c2ecf20Sopenharmony_ci goto out; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (likely(opcode == CPL_SGE_EGR_UPDATE)) { 5788c2ecf20Sopenharmony_ci const struct cpl_sge_egr_update *p = (void *)rsp; 5798c2ecf20Sopenharmony_ci unsigned int qid = EGR_QID_G(ntohl(p->opcode_qid)); 5808c2ecf20Sopenharmony_ci struct sge_txq *txq; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start]; 5838c2ecf20Sopenharmony_ci txq->restarts++; 5848c2ecf20Sopenharmony_ci if (txq->q_type == CXGB4_TXQ_ETH) { 5858c2ecf20Sopenharmony_ci struct sge_eth_txq *eq; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci eq = container_of(txq, struct sge_eth_txq, q); 5888c2ecf20Sopenharmony_ci t4_sge_eth_txq_egress_update(q->adap, eq, -1); 5898c2ecf20Sopenharmony_ci } else { 5908c2ecf20Sopenharmony_ci struct sge_uld_txq *oq; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci oq = container_of(txq, struct sge_uld_txq, q); 5938c2ecf20Sopenharmony_ci tasklet_schedule(&oq->qresume_tsk); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci } else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) { 5968c2ecf20Sopenharmony_ci const struct cpl_fw6_msg *p = (void *)rsp; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 5998c2ecf20Sopenharmony_ci const struct fw_port_cmd *pcmd = (const void *)p->data; 6008c2ecf20Sopenharmony_ci unsigned int cmd = FW_CMD_OP_G(ntohl(pcmd->op_to_portid)); 6018c2ecf20Sopenharmony_ci unsigned int action = 6028c2ecf20Sopenharmony_ci FW_PORT_CMD_ACTION_G(ntohl(pcmd->action_to_len16)); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (cmd == FW_PORT_CMD && 6058c2ecf20Sopenharmony_ci (action == FW_PORT_ACTION_GET_PORT_INFO || 6068c2ecf20Sopenharmony_ci action == FW_PORT_ACTION_GET_PORT_INFO32)) { 6078c2ecf20Sopenharmony_ci int port = FW_PORT_CMD_PORTID_G( 6088c2ecf20Sopenharmony_ci be32_to_cpu(pcmd->op_to_portid)); 6098c2ecf20Sopenharmony_ci struct net_device *dev; 6108c2ecf20Sopenharmony_ci int dcbxdis, state_input; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci dev = q->adap->port[q->adap->chan_map[port]]; 6138c2ecf20Sopenharmony_ci dcbxdis = (action == FW_PORT_ACTION_GET_PORT_INFO 6148c2ecf20Sopenharmony_ci ? !!(pcmd->u.info.dcbxdis_pkd & FW_PORT_CMD_DCBXDIS_F) 6158c2ecf20Sopenharmony_ci : !!(be32_to_cpu(pcmd->u.info32.lstatus32_to_cbllen32) 6168c2ecf20Sopenharmony_ci & FW_PORT_CMD_DCBXDIS32_F)); 6178c2ecf20Sopenharmony_ci state_input = (dcbxdis 6188c2ecf20Sopenharmony_ci ? CXGB4_DCB_INPUT_FW_DISABLED 6198c2ecf20Sopenharmony_ci : CXGB4_DCB_INPUT_FW_ENABLED); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci cxgb4_dcb_state_fsm(dev, state_input); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (cmd == FW_PORT_CMD && 6258c2ecf20Sopenharmony_ci action == FW_PORT_ACTION_L2_DCB_CFG) 6268c2ecf20Sopenharmony_ci dcb_rpl(q->adap, pcmd); 6278c2ecf20Sopenharmony_ci else 6288c2ecf20Sopenharmony_ci#endif 6298c2ecf20Sopenharmony_ci if (p->type == 0) 6308c2ecf20Sopenharmony_ci t4_handle_fw_rpl(q->adap, p->data); 6318c2ecf20Sopenharmony_ci } else if (opcode == CPL_L2T_WRITE_RPL) { 6328c2ecf20Sopenharmony_ci const struct cpl_l2t_write_rpl *p = (void *)rsp; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci do_l2t_write_rpl(q->adap, p); 6358c2ecf20Sopenharmony_ci } else if (opcode == CPL_SMT_WRITE_RPL) { 6368c2ecf20Sopenharmony_ci const struct cpl_smt_write_rpl *p = (void *)rsp; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci do_smt_write_rpl(q->adap, p); 6398c2ecf20Sopenharmony_ci } else if (opcode == CPL_SET_TCB_RPL) { 6408c2ecf20Sopenharmony_ci const struct cpl_set_tcb_rpl *p = (void *)rsp; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci filter_rpl(q->adap, p); 6438c2ecf20Sopenharmony_ci } else if (opcode == CPL_ACT_OPEN_RPL) { 6448c2ecf20Sopenharmony_ci const struct cpl_act_open_rpl *p = (void *)rsp; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci hash_filter_rpl(q->adap, p); 6478c2ecf20Sopenharmony_ci } else if (opcode == CPL_ABORT_RPL_RSS) { 6488c2ecf20Sopenharmony_ci const struct cpl_abort_rpl_rss *p = (void *)rsp; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci hash_del_filter_rpl(q->adap, p); 6518c2ecf20Sopenharmony_ci } else if (opcode == CPL_SRQ_TABLE_RPL) { 6528c2ecf20Sopenharmony_ci const struct cpl_srq_table_rpl *p = (void *)rsp; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci do_srq_table_rpl(q->adap, p); 6558c2ecf20Sopenharmony_ci } else 6568c2ecf20Sopenharmony_ci dev_err(q->adap->pdev_dev, 6578c2ecf20Sopenharmony_ci "unexpected CPL %#x on FW event queue\n", opcode); 6588c2ecf20Sopenharmony_ciout: 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic void disable_msi(struct adapter *adapter) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_USING_MSIX) { 6658c2ecf20Sopenharmony_ci pci_disable_msix(adapter->pdev); 6668c2ecf20Sopenharmony_ci adapter->flags &= ~CXGB4_USING_MSIX; 6678c2ecf20Sopenharmony_ci } else if (adapter->flags & CXGB4_USING_MSI) { 6688c2ecf20Sopenharmony_ci pci_disable_msi(adapter->pdev); 6698c2ecf20Sopenharmony_ci adapter->flags &= ~CXGB4_USING_MSI; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci/* 6748c2ecf20Sopenharmony_ci * Interrupt handler for non-data events used with MSI-X. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_cistatic irqreturn_t t4_nondata_intr(int irq, void *cookie) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct adapter *adap = cookie; 6798c2ecf20Sopenharmony_ci u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A)); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (v & PFSW_F) { 6828c2ecf20Sopenharmony_ci adap->swintr = 1; 6838c2ecf20Sopenharmony_ci t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A), v); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_MASTER_PF) 6868c2ecf20Sopenharmony_ci t4_slow_intr_handler(adap); 6878c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ciint cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec, 6918c2ecf20Sopenharmony_ci cpumask_var_t *aff_mask, int idx) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci int rv; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (!zalloc_cpumask_var(aff_mask, GFP_KERNEL)) { 6968c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "alloc_cpumask_var failed\n"); 6978c2ecf20Sopenharmony_ci return -ENOMEM; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(idx, dev_to_node(adap->pdev_dev)), 7018c2ecf20Sopenharmony_ci *aff_mask); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci rv = irq_set_affinity_hint(vec, *aff_mask); 7048c2ecf20Sopenharmony_ci if (rv) 7058c2ecf20Sopenharmony_ci dev_warn(adap->pdev_dev, 7068c2ecf20Sopenharmony_ci "irq_set_affinity_hint %u failed %d\n", 7078c2ecf20Sopenharmony_ci vec, rv); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_civoid cxgb4_clear_msix_aff(unsigned short vec, cpumask_var_t aff_mask) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci irq_set_affinity_hint(vec, NULL); 7158c2ecf20Sopenharmony_ci free_cpumask_var(aff_mask); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int request_msix_queue_irqs(struct adapter *adap) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 7218c2ecf20Sopenharmony_ci struct msix_info *minfo; 7228c2ecf20Sopenharmony_ci int err, ethqidx; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (s->fwevtq_msix_idx < 0) 7258c2ecf20Sopenharmony_ci return -ENOMEM; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci err = request_irq(adap->msix_info[s->fwevtq_msix_idx].vec, 7288c2ecf20Sopenharmony_ci t4_sge_intr_msix, 0, 7298c2ecf20Sopenharmony_ci adap->msix_info[s->fwevtq_msix_idx].desc, 7308c2ecf20Sopenharmony_ci &s->fw_evtq); 7318c2ecf20Sopenharmony_ci if (err) 7328c2ecf20Sopenharmony_ci return err; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci for_each_ethrxq(s, ethqidx) { 7358c2ecf20Sopenharmony_ci minfo = s->ethrxq[ethqidx].msix; 7368c2ecf20Sopenharmony_ci err = request_irq(minfo->vec, 7378c2ecf20Sopenharmony_ci t4_sge_intr_msix, 0, 7388c2ecf20Sopenharmony_ci minfo->desc, 7398c2ecf20Sopenharmony_ci &s->ethrxq[ethqidx].rspq); 7408c2ecf20Sopenharmony_ci if (err) 7418c2ecf20Sopenharmony_ci goto unwind; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci cxgb4_set_msix_aff(adap, minfo->vec, 7448c2ecf20Sopenharmony_ci &minfo->aff_mask, ethqidx); 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ciunwind: 7498c2ecf20Sopenharmony_ci while (--ethqidx >= 0) { 7508c2ecf20Sopenharmony_ci minfo = s->ethrxq[ethqidx].msix; 7518c2ecf20Sopenharmony_ci cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); 7528c2ecf20Sopenharmony_ci free_irq(minfo->vec, &s->ethrxq[ethqidx].rspq); 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); 7558c2ecf20Sopenharmony_ci return err; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic void free_msix_queue_irqs(struct adapter *adap) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 7618c2ecf20Sopenharmony_ci struct msix_info *minfo; 7628c2ecf20Sopenharmony_ci int i; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); 7658c2ecf20Sopenharmony_ci for_each_ethrxq(s, i) { 7668c2ecf20Sopenharmony_ci minfo = s->ethrxq[i].msix; 7678c2ecf20Sopenharmony_ci cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); 7688c2ecf20Sopenharmony_ci free_irq(minfo->vec, &s->ethrxq[i].rspq); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int setup_ppod_edram(struct adapter *adap) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci unsigned int param, val; 7758c2ecf20Sopenharmony_ci int ret; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* Driver sends FW_PARAMS_PARAM_DEV_PPOD_EDRAM read command to check 7788c2ecf20Sopenharmony_ci * if firmware supports ppod edram feature or not. If firmware 7798c2ecf20Sopenharmony_ci * returns 1, then driver can enable this feature by sending 7808c2ecf20Sopenharmony_ci * FW_PARAMS_PARAM_DEV_PPOD_EDRAM write command with value 1 to 7818c2ecf20Sopenharmony_ci * enable ppod edram feature. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 7848c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PPOD_EDRAM)); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 7878c2ecf20Sopenharmony_ci if (ret < 0) { 7888c2ecf20Sopenharmony_ci dev_warn(adap->pdev_dev, 7898c2ecf20Sopenharmony_ci "querying PPOD_EDRAM support failed: %d\n", 7908c2ecf20Sopenharmony_ci ret); 7918c2ecf20Sopenharmony_ci return -1; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (val != 1) 7958c2ecf20Sopenharmony_ci return -1; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 7988c2ecf20Sopenharmony_ci if (ret < 0) { 7998c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 8008c2ecf20Sopenharmony_ci "setting PPOD_EDRAM failed: %d\n", ret); 8018c2ecf20Sopenharmony_ci return -1; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic void adap_config_hpfilter(struct adapter *adapter) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci u32 param, val = 0; 8098c2ecf20Sopenharmony_ci int ret; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* Enable HP filter region. Older fw will fail this request and 8128c2ecf20Sopenharmony_ci * it is fine. 8138c2ecf20Sopenharmony_ci */ 8148c2ecf20Sopenharmony_ci param = FW_PARAM_DEV(HPFILTER_REGION_SUPPORT); 8158c2ecf20Sopenharmony_ci ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0, 8168c2ecf20Sopenharmony_ci 1, ¶m, &val); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* An error means FW doesn't know about HP filter support, 8198c2ecf20Sopenharmony_ci * it's not a problem, don't return an error. 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci if (ret < 0) 8228c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 8238c2ecf20Sopenharmony_ci "HP filter region isn't supported by FW\n"); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int cxgb4_config_rss(const struct port_info *pi, u16 *rss, 8278c2ecf20Sopenharmony_ci u16 rss_size, u16 viid) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 8308c2ecf20Sopenharmony_ci int ret; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci ret = t4_config_rss_range(adap, adap->mbox, viid, 0, rss_size, rss, 8338c2ecf20Sopenharmony_ci rss_size); 8348c2ecf20Sopenharmony_ci if (ret) 8358c2ecf20Sopenharmony_ci return ret; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* If Tunnel All Lookup isn't specified in the global RSS 8388c2ecf20Sopenharmony_ci * Configuration, then we need to specify a default Ingress 8398c2ecf20Sopenharmony_ci * Queue for any ingress packets which aren't hashed. We'll 8408c2ecf20Sopenharmony_ci * use our first ingress queue ... 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_ci return t4_config_vi_rss(adap, adap->mbox, viid, 8438c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F | 8448c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F | 8458c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F | 8468c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F | 8478c2ecf20Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_UDPEN_F, 8488c2ecf20Sopenharmony_ci rss[0]); 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci/** 8528c2ecf20Sopenharmony_ci * cxgb4_write_rss - write the RSS table for a given port 8538c2ecf20Sopenharmony_ci * @pi: the port 8548c2ecf20Sopenharmony_ci * @queues: array of queue indices for RSS 8558c2ecf20Sopenharmony_ci * 8568c2ecf20Sopenharmony_ci * Sets up the portion of the HW RSS table for the port's VI to distribute 8578c2ecf20Sopenharmony_ci * packets to the Rx queues in @queues. 8588c2ecf20Sopenharmony_ci * Should never be called before setting up sge eth rx queues 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ciint cxgb4_write_rss(const struct port_info *pi, const u16 *queues) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 8638c2ecf20Sopenharmony_ci const struct sge_eth_rxq *rxq; 8648c2ecf20Sopenharmony_ci int i, err; 8658c2ecf20Sopenharmony_ci u16 *rss; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci rxq = &adapter->sge.ethrxq[pi->first_qset]; 8688c2ecf20Sopenharmony_ci rss = kmalloc_array(pi->rss_size, sizeof(u16), GFP_KERNEL); 8698c2ecf20Sopenharmony_ci if (!rss) 8708c2ecf20Sopenharmony_ci return -ENOMEM; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* map the queue indices to queue ids */ 8738c2ecf20Sopenharmony_ci for (i = 0; i < pi->rss_size; i++, queues++) 8748c2ecf20Sopenharmony_ci rss[i] = rxq[*queues].rspq.abs_id; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci err = cxgb4_config_rss(pi, rss, pi->rss_size, pi->viid); 8778c2ecf20Sopenharmony_ci kfree(rss); 8788c2ecf20Sopenharmony_ci return err; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci/** 8828c2ecf20Sopenharmony_ci * setup_rss - configure RSS 8838c2ecf20Sopenharmony_ci * @adap: the adapter 8848c2ecf20Sopenharmony_ci * 8858c2ecf20Sopenharmony_ci * Sets up RSS for each port. 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_cistatic int setup_rss(struct adapter *adap) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci int i, j, err; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci for_each_port(adap, i) { 8928c2ecf20Sopenharmony_ci const struct port_info *pi = adap2pinfo(adap, i); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* Fill default values with equal distribution */ 8958c2ecf20Sopenharmony_ci for (j = 0; j < pi->rss_size; j++) 8968c2ecf20Sopenharmony_ci pi->rss[j] = j % pi->nqsets; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci err = cxgb4_write_rss(pi, pi->rss); 8998c2ecf20Sopenharmony_ci if (err) 9008c2ecf20Sopenharmony_ci return err; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/* 9068c2ecf20Sopenharmony_ci * Return the channel of the ingress queue with the given qid. 9078c2ecf20Sopenharmony_ci */ 9088c2ecf20Sopenharmony_cistatic unsigned int rxq_to_chan(const struct sge *p, unsigned int qid) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci qid -= p->ingr_start; 9118c2ecf20Sopenharmony_ci return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_civoid cxgb4_quiesce_rx(struct sge_rspq *q) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci if (q->handler) 9178c2ecf20Sopenharmony_ci napi_disable(&q->napi); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/* 9218c2ecf20Sopenharmony_ci * Wait until all NAPI handlers are descheduled. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_cistatic void quiesce_rx(struct adapter *adap) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci int i; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci for (i = 0; i < adap->sge.ingr_sz; i++) { 9288c2ecf20Sopenharmony_ci struct sge_rspq *q = adap->sge.ingr_map[i]; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (!q) 9318c2ecf20Sopenharmony_ci continue; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci cxgb4_quiesce_rx(q); 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci/* Disable interrupt and napi handler */ 9388c2ecf20Sopenharmony_cistatic void disable_interrupts(struct adapter *adap) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) { 9438c2ecf20Sopenharmony_ci t4_intr_disable(adap); 9448c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 9458c2ecf20Sopenharmony_ci free_msix_queue_irqs(adap); 9468c2ecf20Sopenharmony_ci free_irq(adap->msix_info[s->nd_msix_idx].vec, 9478c2ecf20Sopenharmony_ci adap); 9488c2ecf20Sopenharmony_ci } else { 9498c2ecf20Sopenharmony_ci free_irq(adap->pdev->irq, adap); 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci quiesce_rx(adap); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_civoid cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci if (q->handler) 9588c2ecf20Sopenharmony_ci napi_enable(&q->napi); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* 0-increment GTS to start the timer and enable interrupts */ 9618c2ecf20Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), 9628c2ecf20Sopenharmony_ci SEINTARM_V(q->intr_params) | 9638c2ecf20Sopenharmony_ci INGRESSQID_V(q->cntxt_id)); 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/* 9678c2ecf20Sopenharmony_ci * Enable NAPI scheduling and interrupt generation for all Rx queues. 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_cistatic void enable_rx(struct adapter *adap) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci int i; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci for (i = 0; i < adap->sge.ingr_sz; i++) { 9748c2ecf20Sopenharmony_ci struct sge_rspq *q = adap->sge.ingr_map[i]; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (!q) 9778c2ecf20Sopenharmony_ci continue; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci cxgb4_enable_rx(adap, q); 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic int setup_non_data_intr(struct adapter *adap) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci int msix; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci adap->sge.nd_msix_idx = -1; 9888c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 9898c2ecf20Sopenharmony_ci return 0; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* Request MSI-X vector for non-data interrupt */ 9928c2ecf20Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 9938c2ecf20Sopenharmony_ci if (msix < 0) 9948c2ecf20Sopenharmony_ci return -ENOMEM; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci snprintf(adap->msix_info[msix].desc, 9978c2ecf20Sopenharmony_ci sizeof(adap->msix_info[msix].desc), 9988c2ecf20Sopenharmony_ci "%s", adap->port[0]->name); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci adap->sge.nd_msix_idx = msix; 10018c2ecf20Sopenharmony_ci return 0; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int setup_fw_sge_queues(struct adapter *adap) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 10078c2ecf20Sopenharmony_ci int msix, err = 0; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci bitmap_zero(s->starving_fl, s->egr_sz); 10108c2ecf20Sopenharmony_ci bitmap_zero(s->txq_maperr, s->egr_sz); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 10138c2ecf20Sopenharmony_ci s->fwevtq_msix_idx = -1; 10148c2ecf20Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 10158c2ecf20Sopenharmony_ci if (msix < 0) 10168c2ecf20Sopenharmony_ci return -ENOMEM; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci snprintf(adap->msix_info[msix].desc, 10198c2ecf20Sopenharmony_ci sizeof(adap->msix_info[msix].desc), 10208c2ecf20Sopenharmony_ci "%s-FWeventq", adap->port[0]->name); 10218c2ecf20Sopenharmony_ci } else { 10228c2ecf20Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, 10238c2ecf20Sopenharmony_ci NULL, NULL, NULL, -1); 10248c2ecf20Sopenharmony_ci if (err) 10258c2ecf20Sopenharmony_ci return err; 10268c2ecf20Sopenharmony_ci msix = -((int)s->intrq.abs_id + 1); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], 10308c2ecf20Sopenharmony_ci msix, NULL, fwevtq_handler, NULL, -1); 10318c2ecf20Sopenharmony_ci if (err && msix >= 0) 10328c2ecf20Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, msix); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci s->fwevtq_msix_idx = msix; 10358c2ecf20Sopenharmony_ci return err; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/** 10398c2ecf20Sopenharmony_ci * setup_sge_queues - configure SGE Tx/Rx/response queues 10408c2ecf20Sopenharmony_ci * @adap: the adapter 10418c2ecf20Sopenharmony_ci * 10428c2ecf20Sopenharmony_ci * Determines how many sets of SGE queues to use and initializes them. 10438c2ecf20Sopenharmony_ci * We support multiple queue sets per port if we have MSI-X, otherwise 10448c2ecf20Sopenharmony_ci * just one queue set per port. 10458c2ecf20Sopenharmony_ci */ 10468c2ecf20Sopenharmony_cistatic int setup_sge_queues(struct adapter *adap) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = NULL; 10498c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 10508c2ecf20Sopenharmony_ci unsigned int cmplqid = 0; 10518c2ecf20Sopenharmony_ci int err, i, j, msix = 0; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (is_uld(adap)) 10548c2ecf20Sopenharmony_ci rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 10578c2ecf20Sopenharmony_ci msix = -((int)s->intrq.abs_id + 1); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci for_each_port(adap, i) { 10608c2ecf20Sopenharmony_ci struct net_device *dev = adap->port[i]; 10618c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 10628c2ecf20Sopenharmony_ci struct sge_eth_rxq *q = &s->ethrxq[pi->first_qset]; 10638c2ecf20Sopenharmony_ci struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci for (j = 0; j < pi->nqsets; j++, q++) { 10668c2ecf20Sopenharmony_ci if (msix >= 0) { 10678c2ecf20Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 10688c2ecf20Sopenharmony_ci if (msix < 0) { 10698c2ecf20Sopenharmony_ci err = msix; 10708c2ecf20Sopenharmony_ci goto freeout; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci snprintf(adap->msix_info[msix].desc, 10748c2ecf20Sopenharmony_ci sizeof(adap->msix_info[msix].desc), 10758c2ecf20Sopenharmony_ci "%s-Rx%d", dev->name, j); 10768c2ecf20Sopenharmony_ci q->msix = &adap->msix_info[msix]; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, 10808c2ecf20Sopenharmony_ci msix, &q->fl, 10818c2ecf20Sopenharmony_ci t4_ethrx_handler, 10828c2ecf20Sopenharmony_ci NULL, 10838c2ecf20Sopenharmony_ci t4_get_tp_ch_map(adap, 10848c2ecf20Sopenharmony_ci pi->tx_chan)); 10858c2ecf20Sopenharmony_ci if (err) 10868c2ecf20Sopenharmony_ci goto freeout; 10878c2ecf20Sopenharmony_ci q->rspq.idx = j; 10888c2ecf20Sopenharmony_ci memset(&q->stats, 0, sizeof(q->stats)); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci q = &s->ethrxq[pi->first_qset]; 10928c2ecf20Sopenharmony_ci for (j = 0; j < pi->nqsets; j++, t++, q++) { 10938c2ecf20Sopenharmony_ci err = t4_sge_alloc_eth_txq(adap, t, dev, 10948c2ecf20Sopenharmony_ci netdev_get_tx_queue(dev, j), 10958c2ecf20Sopenharmony_ci q->rspq.cntxt_id, 10968c2ecf20Sopenharmony_ci !!(adap->flags & CXGB4_SGE_DBQ_TIMER)); 10978c2ecf20Sopenharmony_ci if (err) 10988c2ecf20Sopenharmony_ci goto freeout; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci for_each_port(adap, i) { 11038c2ecf20Sopenharmony_ci /* Note that cmplqid below is 0 if we don't 11048c2ecf20Sopenharmony_ci * have RDMA queues, and that's the right value. 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_ci if (rxq_info) 11078c2ecf20Sopenharmony_ci cmplqid = rxq_info->uldrxq[i].rspq.cntxt_id; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci err = t4_sge_alloc_ctrl_txq(adap, &s->ctrlq[i], adap->port[i], 11108c2ecf20Sopenharmony_ci s->fw_evtq.cntxt_id, cmplqid); 11118c2ecf20Sopenharmony_ci if (err) 11128c2ecf20Sopenharmony_ci goto freeout; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!is_t4(adap->params.chip)) { 11168c2ecf20Sopenharmony_ci err = t4_sge_alloc_eth_txq(adap, &s->ptptxq, adap->port[0], 11178c2ecf20Sopenharmony_ci netdev_get_tx_queue(adap->port[0], 0) 11188c2ecf20Sopenharmony_ci , s->fw_evtq.cntxt_id, false); 11198c2ecf20Sopenharmony_ci if (err) 11208c2ecf20Sopenharmony_ci goto freeout; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci t4_write_reg(adap, is_t4(adap->params.chip) ? 11248c2ecf20Sopenharmony_ci MPS_TRC_RSS_CONTROL_A : 11258c2ecf20Sopenharmony_ci MPS_T5_TRC_RSS_CONTROL_A, 11268c2ecf20Sopenharmony_ci RSSCONTROL_V(netdev2pinfo(adap->port[0])->tx_chan) | 11278c2ecf20Sopenharmony_ci QUEUENUMBER_V(s->ethrxq[0].rspq.abs_id)); 11288c2ecf20Sopenharmony_ci return 0; 11298c2ecf20Sopenharmony_cifreeout: 11308c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Can't allocate queues, err=%d\n", -err); 11318c2ecf20Sopenharmony_ci t4_free_sge_resources(adap); 11328c2ecf20Sopenharmony_ci return err; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, 11368c2ecf20Sopenharmony_ci struct net_device *sb_dev) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci int txq; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 11418c2ecf20Sopenharmony_ci /* If a Data Center Bridging has been successfully negotiated on this 11428c2ecf20Sopenharmony_ci * link then we'll use the skb's priority to map it to a TX Queue. 11438c2ecf20Sopenharmony_ci * The skb's priority is determined via the VLAN Tag Priority Code 11448c2ecf20Sopenharmony_ci * Point field. 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_ci if (cxgb4_dcb_enabled(dev) && !is_kdump_kernel()) { 11478c2ecf20Sopenharmony_ci u16 vlan_tci; 11488c2ecf20Sopenharmony_ci int err; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci err = vlan_get_tag(skb, &vlan_tci); 11518c2ecf20Sopenharmony_ci if (unlikely(err)) { 11528c2ecf20Sopenharmony_ci if (net_ratelimit()) 11538c2ecf20Sopenharmony_ci netdev_warn(dev, 11548c2ecf20Sopenharmony_ci "TX Packet without VLAN Tag on DCB Link\n"); 11558c2ecf20Sopenharmony_ci txq = 0; 11568c2ecf20Sopenharmony_ci } else { 11578c2ecf20Sopenharmony_ci txq = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 11588c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 11598c2ecf20Sopenharmony_ci if (skb->protocol == htons(ETH_P_FCOE)) 11608c2ecf20Sopenharmony_ci txq = skb->priority & 0x7; 11618c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci return txq; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (dev->num_tc) { 11688c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 11698c2ecf20Sopenharmony_ci u8 ver, proto; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci ver = ip_hdr(skb)->version; 11728c2ecf20Sopenharmony_ci proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr : 11738c2ecf20Sopenharmony_ci ip_hdr(skb)->protocol; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* Send unsupported traffic pattern to normal NIC queues. */ 11768c2ecf20Sopenharmony_ci txq = netdev_pick_tx(dev, skb, sb_dev); 11778c2ecf20Sopenharmony_ci if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) || 11788c2ecf20Sopenharmony_ci skb->encapsulation || 11798c2ecf20Sopenharmony_ci cxgb4_is_ktls_skb(skb) || 11808c2ecf20Sopenharmony_ci (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) 11818c2ecf20Sopenharmony_ci txq = txq % pi->nqsets; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci return txq; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (select_queue) { 11878c2ecf20Sopenharmony_ci txq = (skb_rx_queue_recorded(skb) 11888c2ecf20Sopenharmony_ci ? skb_get_rx_queue(skb) 11898c2ecf20Sopenharmony_ci : smp_processor_id()); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci while (unlikely(txq >= dev->real_num_tx_queues)) 11928c2ecf20Sopenharmony_ci txq -= dev->real_num_tx_queues; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci return txq; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci return netdev_pick_tx(dev, skb, NULL) % dev->real_num_tx_queues; 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic int closest_timer(const struct sge *s, int time) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci int i, delta, match = 0, min_delta = INT_MAX; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { 12058c2ecf20Sopenharmony_ci delta = time - s->timer_val[i]; 12068c2ecf20Sopenharmony_ci if (delta < 0) 12078c2ecf20Sopenharmony_ci delta = -delta; 12088c2ecf20Sopenharmony_ci if (delta < min_delta) { 12098c2ecf20Sopenharmony_ci min_delta = delta; 12108c2ecf20Sopenharmony_ci match = i; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci return match; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic int closest_thres(const struct sge *s, int thres) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci int i, delta, match = 0, min_delta = INT_MAX; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { 12218c2ecf20Sopenharmony_ci delta = thres - s->counter_val[i]; 12228c2ecf20Sopenharmony_ci if (delta < 0) 12238c2ecf20Sopenharmony_ci delta = -delta; 12248c2ecf20Sopenharmony_ci if (delta < min_delta) { 12258c2ecf20Sopenharmony_ci min_delta = delta; 12268c2ecf20Sopenharmony_ci match = i; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci return match; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci/** 12338c2ecf20Sopenharmony_ci * cxgb4_set_rspq_intr_params - set a queue's interrupt holdoff parameters 12348c2ecf20Sopenharmony_ci * @q: the Rx queue 12358c2ecf20Sopenharmony_ci * @us: the hold-off time in us, or 0 to disable timer 12368c2ecf20Sopenharmony_ci * @cnt: the hold-off packet count, or 0 to disable counter 12378c2ecf20Sopenharmony_ci * 12388c2ecf20Sopenharmony_ci * Sets an Rx queue's interrupt hold-off time and packet count. At least 12398c2ecf20Sopenharmony_ci * one of the two needs to be enabled for the queue to generate interrupts. 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ciint cxgb4_set_rspq_intr_params(struct sge_rspq *q, 12428c2ecf20Sopenharmony_ci unsigned int us, unsigned int cnt) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci struct adapter *adap = q->adap; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if ((us | cnt) == 0) 12478c2ecf20Sopenharmony_ci cnt = 1; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (cnt) { 12508c2ecf20Sopenharmony_ci int err; 12518c2ecf20Sopenharmony_ci u32 v, new_idx; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci new_idx = closest_thres(&adap->sge, cnt); 12548c2ecf20Sopenharmony_ci if (q->desc && q->pktcnt_idx != new_idx) { 12558c2ecf20Sopenharmony_ci /* the queue has already been created, update it */ 12568c2ecf20Sopenharmony_ci v = FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 12578c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V( 12588c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | 12598c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(q->cntxt_id); 12608c2ecf20Sopenharmony_ci err = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, 12618c2ecf20Sopenharmony_ci &v, &new_idx); 12628c2ecf20Sopenharmony_ci if (err) 12638c2ecf20Sopenharmony_ci return err; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci q->pktcnt_idx = new_idx; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci us = us == 0 ? 6 : closest_timer(&adap->sge, us); 12698c2ecf20Sopenharmony_ci q->intr_params = QINTR_TIMER_IDX_V(us) | QINTR_CNT_EN_V(cnt > 0); 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic int cxgb_set_features(struct net_device *dev, netdev_features_t features) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 12768c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 12778c2ecf20Sopenharmony_ci int err; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (!(changed & NETIF_F_HW_VLAN_CTAG_RX)) 12808c2ecf20Sopenharmony_ci return 0; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci err = t4_set_rxmode(pi->adapter, pi->adapter->mbox, pi->viid, 12838c2ecf20Sopenharmony_ci pi->viid_mirror, -1, -1, -1, -1, 12848c2ecf20Sopenharmony_ci !!(features & NETIF_F_HW_VLAN_CTAG_RX), true); 12858c2ecf20Sopenharmony_ci if (unlikely(err)) 12868c2ecf20Sopenharmony_ci dev->features = features ^ NETIF_F_HW_VLAN_CTAG_RX; 12878c2ecf20Sopenharmony_ci return err; 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic int setup_debugfs(struct adapter *adap) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(adap->debugfs_root)) 12938c2ecf20Sopenharmony_ci return -1; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 12968c2ecf20Sopenharmony_ci t4_setup_debugfs(adap); 12978c2ecf20Sopenharmony_ci#endif 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic void cxgb4_port_mirror_free_rxq(struct adapter *adap, 13028c2ecf20Sopenharmony_ci struct sge_eth_rxq *mirror_rxq) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci if ((adap->flags & CXGB4_FULL_INIT_DONE) && 13058c2ecf20Sopenharmony_ci !(adap->flags & CXGB4_SHUTTING_DOWN)) 13068c2ecf20Sopenharmony_ci cxgb4_quiesce_rx(&mirror_rxq->rspq); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 13098c2ecf20Sopenharmony_ci cxgb4_clear_msix_aff(mirror_rxq->msix->vec, 13108c2ecf20Sopenharmony_ci mirror_rxq->msix->aff_mask); 13118c2ecf20Sopenharmony_ci free_irq(mirror_rxq->msix->vec, &mirror_rxq->rspq); 13128c2ecf20Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, mirror_rxq->msix->idx); 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci free_rspq_fl(adap, &mirror_rxq->rspq, &mirror_rxq->fl); 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic int cxgb4_port_mirror_alloc_queues(struct net_device *dev) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 13218c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 13228c2ecf20Sopenharmony_ci struct sge_eth_rxq *mirror_rxq; 13238c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 13248c2ecf20Sopenharmony_ci int ret = 0, msix = 0; 13258c2ecf20Sopenharmony_ci u16 i, rxqid; 13268c2ecf20Sopenharmony_ci u16 *rss; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (!pi->vi_mirror_count) 13298c2ecf20Sopenharmony_ci return 0; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (s->mirror_rxq[pi->port_id]) 13328c2ecf20Sopenharmony_ci return 0; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci mirror_rxq = kcalloc(pi->nmirrorqsets, sizeof(*mirror_rxq), GFP_KERNEL); 13358c2ecf20Sopenharmony_ci if (!mirror_rxq) 13368c2ecf20Sopenharmony_ci return -ENOMEM; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci s->mirror_rxq[pi->port_id] = mirror_rxq; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 13418c2ecf20Sopenharmony_ci msix = -((int)adap->sge.intrq.abs_id + 1); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci for (i = 0, rxqid = 0; i < pi->nmirrorqsets; i++, rxqid++) { 13448c2ecf20Sopenharmony_ci mirror_rxq = &s->mirror_rxq[pi->port_id][i]; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* Allocate Mirror Rxqs */ 13478c2ecf20Sopenharmony_ci if (msix >= 0) { 13488c2ecf20Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 13498c2ecf20Sopenharmony_ci if (msix < 0) { 13508c2ecf20Sopenharmony_ci ret = msix; 13518c2ecf20Sopenharmony_ci goto out_free_queues; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci mirror_rxq->msix = &adap->msix_info[msix]; 13558c2ecf20Sopenharmony_ci snprintf(mirror_rxq->msix->desc, 13568c2ecf20Sopenharmony_ci sizeof(mirror_rxq->msix->desc), 13578c2ecf20Sopenharmony_ci "%s-mirrorrxq%d", dev->name, i); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci init_rspq(adap, &mirror_rxq->rspq, 13618c2ecf20Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_INTR_USEC, 13628c2ecf20Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_PKT_CNT, 13638c2ecf20Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_DESC_NUM, 13648c2ecf20Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_DESC_SIZE); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci mirror_rxq->fl.size = CXGB4_MIRROR_FLQ_DEFAULT_DESC_NUM; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci ret = t4_sge_alloc_rxq(adap, &mirror_rxq->rspq, false, 13698c2ecf20Sopenharmony_ci dev, msix, &mirror_rxq->fl, 13708c2ecf20Sopenharmony_ci t4_ethrx_handler, NULL, 0); 13718c2ecf20Sopenharmony_ci if (ret) 13728c2ecf20Sopenharmony_ci goto out_free_msix_idx; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* Setup MSI-X vectors for Mirror Rxqs */ 13758c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 13768c2ecf20Sopenharmony_ci ret = request_irq(mirror_rxq->msix->vec, 13778c2ecf20Sopenharmony_ci t4_sge_intr_msix, 0, 13788c2ecf20Sopenharmony_ci mirror_rxq->msix->desc, 13798c2ecf20Sopenharmony_ci &mirror_rxq->rspq); 13808c2ecf20Sopenharmony_ci if (ret) 13818c2ecf20Sopenharmony_ci goto out_free_rxq; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci cxgb4_set_msix_aff(adap, mirror_rxq->msix->vec, 13848c2ecf20Sopenharmony_ci &mirror_rxq->msix->aff_mask, i); 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci /* Start NAPI for Mirror Rxqs */ 13888c2ecf20Sopenharmony_ci cxgb4_enable_rx(adap, &mirror_rxq->rspq); 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* Setup RSS for Mirror Rxqs */ 13928c2ecf20Sopenharmony_ci rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); 13938c2ecf20Sopenharmony_ci if (!rss) { 13948c2ecf20Sopenharmony_ci ret = -ENOMEM; 13958c2ecf20Sopenharmony_ci goto out_free_queues; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci mirror_rxq = &s->mirror_rxq[pi->port_id][0]; 13998c2ecf20Sopenharmony_ci for (i = 0; i < pi->rss_size; i++) 14008c2ecf20Sopenharmony_ci rss[i] = mirror_rxq[i % pi->nmirrorqsets].rspq.abs_id; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci ret = cxgb4_config_rss(pi, rss, pi->rss_size, pi->viid_mirror); 14038c2ecf20Sopenharmony_ci kfree(rss); 14048c2ecf20Sopenharmony_ci if (ret) 14058c2ecf20Sopenharmony_ci goto out_free_queues; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci return 0; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ciout_free_rxq: 14108c2ecf20Sopenharmony_ci free_rspq_fl(adap, &mirror_rxq->rspq, &mirror_rxq->fl); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ciout_free_msix_idx: 14138c2ecf20Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, mirror_rxq->msix->idx); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ciout_free_queues: 14168c2ecf20Sopenharmony_ci while (rxqid-- > 0) 14178c2ecf20Sopenharmony_ci cxgb4_port_mirror_free_rxq(adap, 14188c2ecf20Sopenharmony_ci &s->mirror_rxq[pi->port_id][rxqid]); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci kfree(s->mirror_rxq[pi->port_id]); 14218c2ecf20Sopenharmony_ci s->mirror_rxq[pi->port_id] = NULL; 14228c2ecf20Sopenharmony_ci return ret; 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_cistatic void cxgb4_port_mirror_free_queues(struct net_device *dev) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 14288c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 14298c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 14308c2ecf20Sopenharmony_ci u16 i; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (!pi->vi_mirror_count) 14338c2ecf20Sopenharmony_ci return; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (!s->mirror_rxq[pi->port_id]) 14368c2ecf20Sopenharmony_ci return; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci for (i = 0; i < pi->nmirrorqsets; i++) 14398c2ecf20Sopenharmony_ci cxgb4_port_mirror_free_rxq(adap, 14408c2ecf20Sopenharmony_ci &s->mirror_rxq[pi->port_id][i]); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci kfree(s->mirror_rxq[pi->port_id]); 14438c2ecf20Sopenharmony_ci s->mirror_rxq[pi->port_id] = NULL; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic int cxgb4_port_mirror_start(struct net_device *dev) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 14498c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 14508c2ecf20Sopenharmony_ci int ret, idx = -1; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (!pi->vi_mirror_count) 14538c2ecf20Sopenharmony_ci return 0; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* Mirror VIs can be created dynamically after stack had 14568c2ecf20Sopenharmony_ci * already setup Rx modes like MTU, promisc, allmulti, etc. 14578c2ecf20Sopenharmony_ci * on main VI. So, parse what the stack had setup on the 14588c2ecf20Sopenharmony_ci * main VI and update the same on the mirror VI. 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_ci ret = t4_set_rxmode(adap, adap->mbox, pi->viid, pi->viid_mirror, 14618c2ecf20Sopenharmony_ci dev->mtu, (dev->flags & IFF_PROMISC) ? 1 : 0, 14628c2ecf20Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, 14638c2ecf20Sopenharmony_ci !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true); 14648c2ecf20Sopenharmony_ci if (ret) { 14658c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 14668c2ecf20Sopenharmony_ci "Failed start up Rx mode for Mirror VI 0x%x, ret: %d\n", 14678c2ecf20Sopenharmony_ci pi->viid_mirror, ret); 14688c2ecf20Sopenharmony_ci return ret; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* Enable replication bit for the device's MAC address 14728c2ecf20Sopenharmony_ci * in MPS TCAM, so that the packets for the main VI are 14738c2ecf20Sopenharmony_ci * replicated to mirror VI. 14748c2ecf20Sopenharmony_ci */ 14758c2ecf20Sopenharmony_ci ret = cxgb4_update_mac_filt(pi, pi->viid_mirror, &idx, 14768c2ecf20Sopenharmony_ci dev->dev_addr, true, NULL); 14778c2ecf20Sopenharmony_ci if (ret) { 14788c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 14798c2ecf20Sopenharmony_ci "Failed updating MAC filter for Mirror VI 0x%x, ret: %d\n", 14808c2ecf20Sopenharmony_ci pi->viid_mirror, ret); 14818c2ecf20Sopenharmony_ci return ret; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* Enabling a Virtual Interface can result in an interrupt 14858c2ecf20Sopenharmony_ci * during the processing of the VI Enable command and, in some 14868c2ecf20Sopenharmony_ci * paths, result in an attempt to issue another command in the 14878c2ecf20Sopenharmony_ci * interrupt context. Thus, we disable interrupts during the 14888c2ecf20Sopenharmony_ci * course of the VI Enable command ... 14898c2ecf20Sopenharmony_ci */ 14908c2ecf20Sopenharmony_ci local_bh_disable(); 14918c2ecf20Sopenharmony_ci ret = t4_enable_vi_params(adap, adap->mbox, pi->viid_mirror, true, true, 14928c2ecf20Sopenharmony_ci false); 14938c2ecf20Sopenharmony_ci local_bh_enable(); 14948c2ecf20Sopenharmony_ci if (ret) 14958c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 14968c2ecf20Sopenharmony_ci "Failed starting Mirror VI 0x%x, ret: %d\n", 14978c2ecf20Sopenharmony_ci pi->viid_mirror, ret); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return ret; 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cistatic void cxgb4_port_mirror_stop(struct net_device *dev) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 15058c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci if (!pi->vi_mirror_count) 15088c2ecf20Sopenharmony_ci return; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci t4_enable_vi_params(adap, adap->mbox, pi->viid_mirror, false, false, 15118c2ecf20Sopenharmony_ci false); 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ciint cxgb4_port_mirror_alloc(struct net_device *dev) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 15178c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 15188c2ecf20Sopenharmony_ci int ret = 0; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (!pi->nmirrorqsets) 15218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 15248c2ecf20Sopenharmony_ci if (pi->viid_mirror) { 15258c2ecf20Sopenharmony_ci pi->vi_mirror_count++; 15268c2ecf20Sopenharmony_ci goto out_unlock; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci ret = t4_init_port_mirror(pi, adap->mbox, pi->port_id, adap->pf, 0, 15308c2ecf20Sopenharmony_ci &pi->viid_mirror); 15318c2ecf20Sopenharmony_ci if (ret) 15328c2ecf20Sopenharmony_ci goto out_unlock; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci pi->vi_mirror_count = 1; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) { 15378c2ecf20Sopenharmony_ci ret = cxgb4_port_mirror_alloc_queues(dev); 15388c2ecf20Sopenharmony_ci if (ret) 15398c2ecf20Sopenharmony_ci goto out_free_vi; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci ret = cxgb4_port_mirror_start(dev); 15428c2ecf20Sopenharmony_ci if (ret) 15438c2ecf20Sopenharmony_ci goto out_free_queues; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 15478c2ecf20Sopenharmony_ci return 0; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ciout_free_queues: 15508c2ecf20Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ciout_free_vi: 15538c2ecf20Sopenharmony_ci pi->vi_mirror_count = 0; 15548c2ecf20Sopenharmony_ci t4_free_vi(adap, adap->mbox, adap->pf, 0, pi->viid_mirror); 15558c2ecf20Sopenharmony_ci pi->viid_mirror = 0; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ciout_unlock: 15588c2ecf20Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 15598c2ecf20Sopenharmony_ci return ret; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_civoid cxgb4_port_mirror_free(struct net_device *dev) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 15658c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 15688c2ecf20Sopenharmony_ci if (!pi->viid_mirror) 15698c2ecf20Sopenharmony_ci goto out_unlock; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (pi->vi_mirror_count > 1) { 15728c2ecf20Sopenharmony_ci pi->vi_mirror_count--; 15738c2ecf20Sopenharmony_ci goto out_unlock; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci cxgb4_port_mirror_stop(dev); 15778c2ecf20Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci pi->vi_mirror_count = 0; 15808c2ecf20Sopenharmony_ci t4_free_vi(adap, adap->mbox, adap->pf, 0, pi->viid_mirror); 15818c2ecf20Sopenharmony_ci pi->viid_mirror = 0; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ciout_unlock: 15848c2ecf20Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci/* 15888c2ecf20Sopenharmony_ci * upper-layer driver support 15898c2ecf20Sopenharmony_ci */ 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci/* 15928c2ecf20Sopenharmony_ci * Allocate an active-open TID and set it to the supplied value. 15938c2ecf20Sopenharmony_ci */ 15948c2ecf20Sopenharmony_ciint cxgb4_alloc_atid(struct tid_info *t, void *data) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci int atid = -1; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci spin_lock_bh(&t->atid_lock); 15998c2ecf20Sopenharmony_ci if (t->afree) { 16008c2ecf20Sopenharmony_ci union aopen_entry *p = t->afree; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci atid = (p - t->atid_tab) + t->atid_base; 16038c2ecf20Sopenharmony_ci t->afree = p->next; 16048c2ecf20Sopenharmony_ci p->data = data; 16058c2ecf20Sopenharmony_ci t->atids_in_use++; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci spin_unlock_bh(&t->atid_lock); 16088c2ecf20Sopenharmony_ci return atid; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_atid); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci/* 16138c2ecf20Sopenharmony_ci * Release an active-open TID. 16148c2ecf20Sopenharmony_ci */ 16158c2ecf20Sopenharmony_civoid cxgb4_free_atid(struct tid_info *t, unsigned int atid) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci union aopen_entry *p = &t->atid_tab[atid - t->atid_base]; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci spin_lock_bh(&t->atid_lock); 16208c2ecf20Sopenharmony_ci p->next = t->afree; 16218c2ecf20Sopenharmony_ci t->afree = p; 16228c2ecf20Sopenharmony_ci t->atids_in_use--; 16238c2ecf20Sopenharmony_ci spin_unlock_bh(&t->atid_lock); 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_free_atid); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci/* 16288c2ecf20Sopenharmony_ci * Allocate a server TID and set it to the supplied value. 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ciint cxgb4_alloc_stid(struct tid_info *t, int family, void *data) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci int stid; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci spin_lock_bh(&t->stid_lock); 16358c2ecf20Sopenharmony_ci if (family == PF_INET) { 16368c2ecf20Sopenharmony_ci stid = find_first_zero_bit(t->stid_bmap, t->nstids); 16378c2ecf20Sopenharmony_ci if (stid < t->nstids) 16388c2ecf20Sopenharmony_ci __set_bit(stid, t->stid_bmap); 16398c2ecf20Sopenharmony_ci else 16408c2ecf20Sopenharmony_ci stid = -1; 16418c2ecf20Sopenharmony_ci } else { 16428c2ecf20Sopenharmony_ci stid = bitmap_find_free_region(t->stid_bmap, t->nstids, 1); 16438c2ecf20Sopenharmony_ci if (stid < 0) 16448c2ecf20Sopenharmony_ci stid = -1; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci if (stid >= 0) { 16478c2ecf20Sopenharmony_ci t->stid_tab[stid].data = data; 16488c2ecf20Sopenharmony_ci stid += t->stid_base; 16498c2ecf20Sopenharmony_ci /* IPv6 requires max of 520 bits or 16 cells in TCAM 16508c2ecf20Sopenharmony_ci * This is equivalent to 4 TIDs. With CLIP enabled it 16518c2ecf20Sopenharmony_ci * needs 2 TIDs. 16528c2ecf20Sopenharmony_ci */ 16538c2ecf20Sopenharmony_ci if (family == PF_INET6) { 16548c2ecf20Sopenharmony_ci t->stids_in_use += 2; 16558c2ecf20Sopenharmony_ci t->v6_stids_in_use += 2; 16568c2ecf20Sopenharmony_ci } else { 16578c2ecf20Sopenharmony_ci t->stids_in_use++; 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 16618c2ecf20Sopenharmony_ci return stid; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_stid); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci/* Allocate a server filter TID and set it to the supplied value. 16668c2ecf20Sopenharmony_ci */ 16678c2ecf20Sopenharmony_ciint cxgb4_alloc_sftid(struct tid_info *t, int family, void *data) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci int stid; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci spin_lock_bh(&t->stid_lock); 16728c2ecf20Sopenharmony_ci if (family == PF_INET) { 16738c2ecf20Sopenharmony_ci stid = find_next_zero_bit(t->stid_bmap, 16748c2ecf20Sopenharmony_ci t->nstids + t->nsftids, t->nstids); 16758c2ecf20Sopenharmony_ci if (stid < (t->nstids + t->nsftids)) 16768c2ecf20Sopenharmony_ci __set_bit(stid, t->stid_bmap); 16778c2ecf20Sopenharmony_ci else 16788c2ecf20Sopenharmony_ci stid = -1; 16798c2ecf20Sopenharmony_ci } else { 16808c2ecf20Sopenharmony_ci stid = -1; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci if (stid >= 0) { 16838c2ecf20Sopenharmony_ci t->stid_tab[stid].data = data; 16848c2ecf20Sopenharmony_ci stid -= t->nstids; 16858c2ecf20Sopenharmony_ci stid += t->sftid_base; 16868c2ecf20Sopenharmony_ci t->sftids_in_use++; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 16898c2ecf20Sopenharmony_ci return stid; 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_sftid); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci/* Release a server TID. 16948c2ecf20Sopenharmony_ci */ 16958c2ecf20Sopenharmony_civoid cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci /* Is it a server filter TID? */ 16988c2ecf20Sopenharmony_ci if (t->nsftids && (stid >= t->sftid_base)) { 16998c2ecf20Sopenharmony_ci stid -= t->sftid_base; 17008c2ecf20Sopenharmony_ci stid += t->nstids; 17018c2ecf20Sopenharmony_ci } else { 17028c2ecf20Sopenharmony_ci stid -= t->stid_base; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci spin_lock_bh(&t->stid_lock); 17068c2ecf20Sopenharmony_ci if (family == PF_INET) 17078c2ecf20Sopenharmony_ci __clear_bit(stid, t->stid_bmap); 17088c2ecf20Sopenharmony_ci else 17098c2ecf20Sopenharmony_ci bitmap_release_region(t->stid_bmap, stid, 1); 17108c2ecf20Sopenharmony_ci t->stid_tab[stid].data = NULL; 17118c2ecf20Sopenharmony_ci if (stid < t->nstids) { 17128c2ecf20Sopenharmony_ci if (family == PF_INET6) { 17138c2ecf20Sopenharmony_ci t->stids_in_use -= 2; 17148c2ecf20Sopenharmony_ci t->v6_stids_in_use -= 2; 17158c2ecf20Sopenharmony_ci } else { 17168c2ecf20Sopenharmony_ci t->stids_in_use--; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci } else { 17198c2ecf20Sopenharmony_ci t->sftids_in_use--; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_free_stid); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci/* 17278c2ecf20Sopenharmony_ci * Populate a TID_RELEASE WR. Caller must properly size the skb. 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_cistatic void mk_tid_release(struct sk_buff *skb, unsigned int chan, 17308c2ecf20Sopenharmony_ci unsigned int tid) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct cpl_tid_release *req; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); 17358c2ecf20Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 17368c2ecf20Sopenharmony_ci INIT_TP_WR(req, tid); 17378c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci/* 17418c2ecf20Sopenharmony_ci * Queue a TID release request and if necessary schedule a work queue to 17428c2ecf20Sopenharmony_ci * process it. 17438c2ecf20Sopenharmony_ci */ 17448c2ecf20Sopenharmony_cistatic void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, 17458c2ecf20Sopenharmony_ci unsigned int tid) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct adapter *adap = container_of(t, struct adapter, tids); 17488c2ecf20Sopenharmony_ci void **p = &t->tid_tab[tid - t->tid_base]; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci spin_lock_bh(&adap->tid_release_lock); 17518c2ecf20Sopenharmony_ci *p = adap->tid_release_head; 17528c2ecf20Sopenharmony_ci /* Low 2 bits encode the Tx channel number */ 17538c2ecf20Sopenharmony_ci adap->tid_release_head = (void **)((uintptr_t)p | chan); 17548c2ecf20Sopenharmony_ci if (!adap->tid_release_task_busy) { 17558c2ecf20Sopenharmony_ci adap->tid_release_task_busy = true; 17568c2ecf20Sopenharmony_ci queue_work(adap->workq, &adap->tid_release_task); 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci spin_unlock_bh(&adap->tid_release_lock); 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci/* 17628c2ecf20Sopenharmony_ci * Process the list of pending TID release requests. 17638c2ecf20Sopenharmony_ci */ 17648c2ecf20Sopenharmony_cistatic void process_tid_release_list(struct work_struct *work) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci struct sk_buff *skb; 17678c2ecf20Sopenharmony_ci struct adapter *adap; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci adap = container_of(work, struct adapter, tid_release_task); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci spin_lock_bh(&adap->tid_release_lock); 17728c2ecf20Sopenharmony_ci while (adap->tid_release_head) { 17738c2ecf20Sopenharmony_ci void **p = adap->tid_release_head; 17748c2ecf20Sopenharmony_ci unsigned int chan = (uintptr_t)p & 3; 17758c2ecf20Sopenharmony_ci p = (void *)p - chan; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci adap->tid_release_head = *p; 17788c2ecf20Sopenharmony_ci *p = NULL; 17798c2ecf20Sopenharmony_ci spin_unlock_bh(&adap->tid_release_lock); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci while (!(skb = alloc_skb(sizeof(struct cpl_tid_release), 17828c2ecf20Sopenharmony_ci GFP_KERNEL))) 17838c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci mk_tid_release(skb, chan, p - adap->tids.tid_tab); 17868c2ecf20Sopenharmony_ci t4_ofld_send(adap, skb); 17878c2ecf20Sopenharmony_ci spin_lock_bh(&adap->tid_release_lock); 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci adap->tid_release_task_busy = false; 17908c2ecf20Sopenharmony_ci spin_unlock_bh(&adap->tid_release_lock); 17918c2ecf20Sopenharmony_ci} 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci/* 17948c2ecf20Sopenharmony_ci * Release a TID and inform HW. If we are unable to allocate the release 17958c2ecf20Sopenharmony_ci * message we defer to a work queue. 17968c2ecf20Sopenharmony_ci */ 17978c2ecf20Sopenharmony_civoid cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid, 17988c2ecf20Sopenharmony_ci unsigned short family) 17998c2ecf20Sopenharmony_ci{ 18008c2ecf20Sopenharmony_ci struct adapter *adap = container_of(t, struct adapter, tids); 18018c2ecf20Sopenharmony_ci struct sk_buff *skb; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci WARN_ON(tid_out_of_range(&adap->tids, tid)); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (t->tid_tab[tid - adap->tids.tid_base]) { 18068c2ecf20Sopenharmony_ci t->tid_tab[tid - adap->tids.tid_base] = NULL; 18078c2ecf20Sopenharmony_ci atomic_dec(&t->conns_in_use); 18088c2ecf20Sopenharmony_ci if (t->hash_base && (tid >= t->hash_base)) { 18098c2ecf20Sopenharmony_ci if (family == AF_INET6) 18108c2ecf20Sopenharmony_ci atomic_sub(2, &t->hash_tids_in_use); 18118c2ecf20Sopenharmony_ci else 18128c2ecf20Sopenharmony_ci atomic_dec(&t->hash_tids_in_use); 18138c2ecf20Sopenharmony_ci } else { 18148c2ecf20Sopenharmony_ci if (family == AF_INET6) 18158c2ecf20Sopenharmony_ci atomic_sub(2, &t->tids_in_use); 18168c2ecf20Sopenharmony_ci else 18178c2ecf20Sopenharmony_ci atomic_dec(&t->tids_in_use); 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); 18228c2ecf20Sopenharmony_ci if (likely(skb)) { 18238c2ecf20Sopenharmony_ci mk_tid_release(skb, chan, tid); 18248c2ecf20Sopenharmony_ci t4_ofld_send(adap, skb); 18258c2ecf20Sopenharmony_ci } else 18268c2ecf20Sopenharmony_ci cxgb4_queue_tid_release(t, chan, tid); 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_tid); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci/* 18318c2ecf20Sopenharmony_ci * Allocate and initialize the TID tables. Returns 0 on success. 18328c2ecf20Sopenharmony_ci */ 18338c2ecf20Sopenharmony_cistatic int tid_init(struct tid_info *t) 18348c2ecf20Sopenharmony_ci{ 18358c2ecf20Sopenharmony_ci struct adapter *adap = container_of(t, struct adapter, tids); 18368c2ecf20Sopenharmony_ci unsigned int max_ftids = t->nftids + t->nsftids; 18378c2ecf20Sopenharmony_ci unsigned int natids = t->natids; 18388c2ecf20Sopenharmony_ci unsigned int hpftid_bmap_size; 18398c2ecf20Sopenharmony_ci unsigned int eotid_bmap_size; 18408c2ecf20Sopenharmony_ci unsigned int stid_bmap_size; 18418c2ecf20Sopenharmony_ci unsigned int ftid_bmap_size; 18428c2ecf20Sopenharmony_ci size_t size; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids); 18458c2ecf20Sopenharmony_ci ftid_bmap_size = BITS_TO_LONGS(t->nftids); 18468c2ecf20Sopenharmony_ci hpftid_bmap_size = BITS_TO_LONGS(t->nhpftids); 18478c2ecf20Sopenharmony_ci eotid_bmap_size = BITS_TO_LONGS(t->neotids); 18488c2ecf20Sopenharmony_ci size = t->ntids * sizeof(*t->tid_tab) + 18498c2ecf20Sopenharmony_ci natids * sizeof(*t->atid_tab) + 18508c2ecf20Sopenharmony_ci t->nstids * sizeof(*t->stid_tab) + 18518c2ecf20Sopenharmony_ci t->nsftids * sizeof(*t->stid_tab) + 18528c2ecf20Sopenharmony_ci stid_bmap_size * sizeof(long) + 18538c2ecf20Sopenharmony_ci t->nhpftids * sizeof(*t->hpftid_tab) + 18548c2ecf20Sopenharmony_ci hpftid_bmap_size * sizeof(long) + 18558c2ecf20Sopenharmony_ci max_ftids * sizeof(*t->ftid_tab) + 18568c2ecf20Sopenharmony_ci ftid_bmap_size * sizeof(long) + 18578c2ecf20Sopenharmony_ci t->neotids * sizeof(*t->eotid_tab) + 18588c2ecf20Sopenharmony_ci eotid_bmap_size * sizeof(long); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci t->tid_tab = kvzalloc(size, GFP_KERNEL); 18618c2ecf20Sopenharmony_ci if (!t->tid_tab) 18628c2ecf20Sopenharmony_ci return -ENOMEM; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; 18658c2ecf20Sopenharmony_ci t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; 18668c2ecf20Sopenharmony_ci t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids]; 18678c2ecf20Sopenharmony_ci t->hpftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size]; 18688c2ecf20Sopenharmony_ci t->hpftid_bmap = (unsigned long *)&t->hpftid_tab[t->nhpftids]; 18698c2ecf20Sopenharmony_ci t->ftid_tab = (struct filter_entry *)&t->hpftid_bmap[hpftid_bmap_size]; 18708c2ecf20Sopenharmony_ci t->ftid_bmap = (unsigned long *)&t->ftid_tab[max_ftids]; 18718c2ecf20Sopenharmony_ci t->eotid_tab = (struct eotid_entry *)&t->ftid_bmap[ftid_bmap_size]; 18728c2ecf20Sopenharmony_ci t->eotid_bmap = (unsigned long *)&t->eotid_tab[t->neotids]; 18738c2ecf20Sopenharmony_ci spin_lock_init(&t->stid_lock); 18748c2ecf20Sopenharmony_ci spin_lock_init(&t->atid_lock); 18758c2ecf20Sopenharmony_ci spin_lock_init(&t->ftid_lock); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci t->stids_in_use = 0; 18788c2ecf20Sopenharmony_ci t->v6_stids_in_use = 0; 18798c2ecf20Sopenharmony_ci t->sftids_in_use = 0; 18808c2ecf20Sopenharmony_ci t->afree = NULL; 18818c2ecf20Sopenharmony_ci t->atids_in_use = 0; 18828c2ecf20Sopenharmony_ci atomic_set(&t->tids_in_use, 0); 18838c2ecf20Sopenharmony_ci atomic_set(&t->conns_in_use, 0); 18848c2ecf20Sopenharmony_ci atomic_set(&t->hash_tids_in_use, 0); 18858c2ecf20Sopenharmony_ci atomic_set(&t->eotids_in_use, 0); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* Setup the free list for atid_tab and clear the stid bitmap. */ 18888c2ecf20Sopenharmony_ci if (natids) { 18898c2ecf20Sopenharmony_ci while (--natids) 18908c2ecf20Sopenharmony_ci t->atid_tab[natids - 1].next = &t->atid_tab[natids]; 18918c2ecf20Sopenharmony_ci t->afree = t->atid_tab; 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (is_offload(adap)) { 18958c2ecf20Sopenharmony_ci bitmap_zero(t->stid_bmap, t->nstids + t->nsftids); 18968c2ecf20Sopenharmony_ci /* Reserve stid 0 for T4/T5 adapters */ 18978c2ecf20Sopenharmony_ci if (!t->stid_base && 18988c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 18998c2ecf20Sopenharmony_ci __set_bit(0, t->stid_bmap); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (t->neotids) 19028c2ecf20Sopenharmony_ci bitmap_zero(t->eotid_bmap, t->neotids); 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (t->nhpftids) 19068c2ecf20Sopenharmony_ci bitmap_zero(t->hpftid_bmap, t->nhpftids); 19078c2ecf20Sopenharmony_ci bitmap_zero(t->ftid_bmap, t->nftids); 19088c2ecf20Sopenharmony_ci return 0; 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci/** 19128c2ecf20Sopenharmony_ci * cxgb4_create_server - create an IP server 19138c2ecf20Sopenharmony_ci * @dev: the device 19148c2ecf20Sopenharmony_ci * @stid: the server TID 19158c2ecf20Sopenharmony_ci * @sip: local IP address to bind server to 19168c2ecf20Sopenharmony_ci * @sport: the server's TCP port 19178c2ecf20Sopenharmony_ci * @vlan: the VLAN header information 19188c2ecf20Sopenharmony_ci * @queue: queue to direct messages from this server to 19198c2ecf20Sopenharmony_ci * 19208c2ecf20Sopenharmony_ci * Create an IP server for the given port and address. 19218c2ecf20Sopenharmony_ci * Returns <0 on error and one of the %NET_XMIT_* values on success. 19228c2ecf20Sopenharmony_ci */ 19238c2ecf20Sopenharmony_ciint cxgb4_create_server(const struct net_device *dev, unsigned int stid, 19248c2ecf20Sopenharmony_ci __be32 sip, __be16 sport, __be16 vlan, 19258c2ecf20Sopenharmony_ci unsigned int queue) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci unsigned int chan; 19288c2ecf20Sopenharmony_ci struct sk_buff *skb; 19298c2ecf20Sopenharmony_ci struct adapter *adap; 19308c2ecf20Sopenharmony_ci struct cpl_pass_open_req *req; 19318c2ecf20Sopenharmony_ci int ret; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_KERNEL); 19348c2ecf20Sopenharmony_ci if (!skb) 19358c2ecf20Sopenharmony_ci return -ENOMEM; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 19388c2ecf20Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 19398c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 19408c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); 19418c2ecf20Sopenharmony_ci req->local_port = sport; 19428c2ecf20Sopenharmony_ci req->peer_port = htons(0); 19438c2ecf20Sopenharmony_ci req->local_ip = sip; 19448c2ecf20Sopenharmony_ci req->peer_ip = htonl(0); 19458c2ecf20Sopenharmony_ci chan = rxq_to_chan(&adap->sge, queue); 19468c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); 19478c2ecf20Sopenharmony_ci req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | 19488c2ecf20Sopenharmony_ci SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); 19498c2ecf20Sopenharmony_ci ret = t4_mgmt_tx(adap, skb); 19508c2ecf20Sopenharmony_ci return net_xmit_eval(ret); 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci/* cxgb4_create_server6 - create an IPv6 server 19558c2ecf20Sopenharmony_ci * @dev: the device 19568c2ecf20Sopenharmony_ci * @stid: the server TID 19578c2ecf20Sopenharmony_ci * @sip: local IPv6 address to bind server to 19588c2ecf20Sopenharmony_ci * @sport: the server's TCP port 19598c2ecf20Sopenharmony_ci * @queue: queue to direct messages from this server to 19608c2ecf20Sopenharmony_ci * 19618c2ecf20Sopenharmony_ci * Create an IPv6 server for the given port and address. 19628c2ecf20Sopenharmony_ci * Returns <0 on error and one of the %NET_XMIT_* values on success. 19638c2ecf20Sopenharmony_ci */ 19648c2ecf20Sopenharmony_ciint cxgb4_create_server6(const struct net_device *dev, unsigned int stid, 19658c2ecf20Sopenharmony_ci const struct in6_addr *sip, __be16 sport, 19668c2ecf20Sopenharmony_ci unsigned int queue) 19678c2ecf20Sopenharmony_ci{ 19688c2ecf20Sopenharmony_ci unsigned int chan; 19698c2ecf20Sopenharmony_ci struct sk_buff *skb; 19708c2ecf20Sopenharmony_ci struct adapter *adap; 19718c2ecf20Sopenharmony_ci struct cpl_pass_open_req6 *req; 19728c2ecf20Sopenharmony_ci int ret; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_KERNEL); 19758c2ecf20Sopenharmony_ci if (!skb) 19768c2ecf20Sopenharmony_ci return -ENOMEM; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 19798c2ecf20Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 19808c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 19818c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid)); 19828c2ecf20Sopenharmony_ci req->local_port = sport; 19838c2ecf20Sopenharmony_ci req->peer_port = htons(0); 19848c2ecf20Sopenharmony_ci req->local_ip_hi = *(__be64 *)(sip->s6_addr); 19858c2ecf20Sopenharmony_ci req->local_ip_lo = *(__be64 *)(sip->s6_addr + 8); 19868c2ecf20Sopenharmony_ci req->peer_ip_hi = cpu_to_be64(0); 19878c2ecf20Sopenharmony_ci req->peer_ip_lo = cpu_to_be64(0); 19888c2ecf20Sopenharmony_ci chan = rxq_to_chan(&adap->sge, queue); 19898c2ecf20Sopenharmony_ci req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); 19908c2ecf20Sopenharmony_ci req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | 19918c2ecf20Sopenharmony_ci SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); 19928c2ecf20Sopenharmony_ci ret = t4_mgmt_tx(adap, skb); 19938c2ecf20Sopenharmony_ci return net_xmit_eval(ret); 19948c2ecf20Sopenharmony_ci} 19958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server6); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ciint cxgb4_remove_server(const struct net_device *dev, unsigned int stid, 19988c2ecf20Sopenharmony_ci unsigned int queue, bool ipv6) 19998c2ecf20Sopenharmony_ci{ 20008c2ecf20Sopenharmony_ci struct sk_buff *skb; 20018c2ecf20Sopenharmony_ci struct adapter *adap; 20028c2ecf20Sopenharmony_ci struct cpl_close_listsvr_req *req; 20038c2ecf20Sopenharmony_ci int ret; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_KERNEL); 20088c2ecf20Sopenharmony_ci if (!skb) 20098c2ecf20Sopenharmony_ci return -ENOMEM; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 20128c2ecf20Sopenharmony_ci INIT_TP_WR(req, 0); 20138c2ecf20Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid)); 20148c2ecf20Sopenharmony_ci req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) : 20158c2ecf20Sopenharmony_ci LISTSVR_IPV6_V(0)) | QUEUENO_V(queue)); 20168c2ecf20Sopenharmony_ci ret = t4_mgmt_tx(adap, skb); 20178c2ecf20Sopenharmony_ci return net_xmit_eval(ret); 20188c2ecf20Sopenharmony_ci} 20198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_server); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci/** 20228c2ecf20Sopenharmony_ci * cxgb4_best_mtu - find the entry in the MTU table closest to an MTU 20238c2ecf20Sopenharmony_ci * @mtus: the HW MTU table 20248c2ecf20Sopenharmony_ci * @mtu: the target MTU 20258c2ecf20Sopenharmony_ci * @idx: index of selected entry in the MTU table 20268c2ecf20Sopenharmony_ci * 20278c2ecf20Sopenharmony_ci * Returns the index and the value in the HW MTU table that is closest to 20288c2ecf20Sopenharmony_ci * but does not exceed @mtu, unless @mtu is smaller than any value in the 20298c2ecf20Sopenharmony_ci * table, in which case that smallest available value is selected. 20308c2ecf20Sopenharmony_ci */ 20318c2ecf20Sopenharmony_ciunsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, 20328c2ecf20Sopenharmony_ci unsigned int *idx) 20338c2ecf20Sopenharmony_ci{ 20348c2ecf20Sopenharmony_ci unsigned int i = 0; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci while (i < NMTUS - 1 && mtus[i + 1] <= mtu) 20378c2ecf20Sopenharmony_ci ++i; 20388c2ecf20Sopenharmony_ci if (idx) 20398c2ecf20Sopenharmony_ci *idx = i; 20408c2ecf20Sopenharmony_ci return mtus[i]; 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_best_mtu); 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci/** 20458c2ecf20Sopenharmony_ci * cxgb4_best_aligned_mtu - find best MTU, [hopefully] data size aligned 20468c2ecf20Sopenharmony_ci * @mtus: the HW MTU table 20478c2ecf20Sopenharmony_ci * @header_size: Header Size 20488c2ecf20Sopenharmony_ci * @data_size_max: maximum Data Segment Size 20498c2ecf20Sopenharmony_ci * @data_size_align: desired Data Segment Size Alignment (2^N) 20508c2ecf20Sopenharmony_ci * @mtu_idxp: HW MTU Table Index return value pointer (possibly NULL) 20518c2ecf20Sopenharmony_ci * 20528c2ecf20Sopenharmony_ci * Similar to cxgb4_best_mtu() but instead of searching the Hardware 20538c2ecf20Sopenharmony_ci * MTU Table based solely on a Maximum MTU parameter, we break that 20548c2ecf20Sopenharmony_ci * parameter up into a Header Size and Maximum Data Segment Size, and 20558c2ecf20Sopenharmony_ci * provide a desired Data Segment Size Alignment. If we find an MTU in 20568c2ecf20Sopenharmony_ci * the Hardware MTU Table which will result in a Data Segment Size with 20578c2ecf20Sopenharmony_ci * the requested alignment _and_ that MTU isn't "too far" from the 20588c2ecf20Sopenharmony_ci * closest MTU, then we'll return that rather than the closest MTU. 20598c2ecf20Sopenharmony_ci */ 20608c2ecf20Sopenharmony_ciunsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus, 20618c2ecf20Sopenharmony_ci unsigned short header_size, 20628c2ecf20Sopenharmony_ci unsigned short data_size_max, 20638c2ecf20Sopenharmony_ci unsigned short data_size_align, 20648c2ecf20Sopenharmony_ci unsigned int *mtu_idxp) 20658c2ecf20Sopenharmony_ci{ 20668c2ecf20Sopenharmony_ci unsigned short max_mtu = header_size + data_size_max; 20678c2ecf20Sopenharmony_ci unsigned short data_size_align_mask = data_size_align - 1; 20688c2ecf20Sopenharmony_ci int mtu_idx, aligned_mtu_idx; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci /* Scan the MTU Table till we find an MTU which is larger than our 20718c2ecf20Sopenharmony_ci * Maximum MTU or we reach the end of the table. Along the way, 20728c2ecf20Sopenharmony_ci * record the last MTU found, if any, which will result in a Data 20738c2ecf20Sopenharmony_ci * Segment Length matching the requested alignment. 20748c2ecf20Sopenharmony_ci */ 20758c2ecf20Sopenharmony_ci for (mtu_idx = 0, aligned_mtu_idx = -1; mtu_idx < NMTUS; mtu_idx++) { 20768c2ecf20Sopenharmony_ci unsigned short data_size = mtus[mtu_idx] - header_size; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci /* If this MTU minus the Header Size would result in a 20798c2ecf20Sopenharmony_ci * Data Segment Size of the desired alignment, remember it. 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_ci if ((data_size & data_size_align_mask) == 0) 20828c2ecf20Sopenharmony_ci aligned_mtu_idx = mtu_idx; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci /* If we're not at the end of the Hardware MTU Table and the 20858c2ecf20Sopenharmony_ci * next element is larger than our Maximum MTU, drop out of 20868c2ecf20Sopenharmony_ci * the loop. 20878c2ecf20Sopenharmony_ci */ 20888c2ecf20Sopenharmony_ci if (mtu_idx+1 < NMTUS && mtus[mtu_idx+1] > max_mtu) 20898c2ecf20Sopenharmony_ci break; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci /* If we fell out of the loop because we ran to the end of the table, 20938c2ecf20Sopenharmony_ci * then we just have to use the last [largest] entry. 20948c2ecf20Sopenharmony_ci */ 20958c2ecf20Sopenharmony_ci if (mtu_idx == NMTUS) 20968c2ecf20Sopenharmony_ci mtu_idx--; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* If we found an MTU which resulted in the requested Data Segment 20998c2ecf20Sopenharmony_ci * Length alignment and that's "not far" from the largest MTU which is 21008c2ecf20Sopenharmony_ci * less than or equal to the maximum MTU, then use that. 21018c2ecf20Sopenharmony_ci */ 21028c2ecf20Sopenharmony_ci if (aligned_mtu_idx >= 0 && 21038c2ecf20Sopenharmony_ci mtu_idx - aligned_mtu_idx <= 1) 21048c2ecf20Sopenharmony_ci mtu_idx = aligned_mtu_idx; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* If the caller has passed in an MTU Index pointer, pass the 21078c2ecf20Sopenharmony_ci * MTU Index back. Return the MTU value. 21088c2ecf20Sopenharmony_ci */ 21098c2ecf20Sopenharmony_ci if (mtu_idxp) 21108c2ecf20Sopenharmony_ci *mtu_idxp = mtu_idx; 21118c2ecf20Sopenharmony_ci return mtus[mtu_idx]; 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_best_aligned_mtu); 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci/** 21168c2ecf20Sopenharmony_ci * cxgb4_port_chan - get the HW channel of a port 21178c2ecf20Sopenharmony_ci * @dev: the net device for the port 21188c2ecf20Sopenharmony_ci * 21198c2ecf20Sopenharmony_ci * Return the HW Tx channel of the given port. 21208c2ecf20Sopenharmony_ci */ 21218c2ecf20Sopenharmony_ciunsigned int cxgb4_port_chan(const struct net_device *dev) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci return netdev2pinfo(dev)->tx_chan; 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_chan); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci/** 21288c2ecf20Sopenharmony_ci * cxgb4_port_e2cchan - get the HW c-channel of a port 21298c2ecf20Sopenharmony_ci * @dev: the net device for the port 21308c2ecf20Sopenharmony_ci * 21318c2ecf20Sopenharmony_ci * Return the HW RX c-channel of the given port. 21328c2ecf20Sopenharmony_ci */ 21338c2ecf20Sopenharmony_ciunsigned int cxgb4_port_e2cchan(const struct net_device *dev) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci return netdev2pinfo(dev)->rx_cchan; 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_e2cchan); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ciunsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 21428c2ecf20Sopenharmony_ci u32 v1, v2, lp_count, hp_count; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); 21458c2ecf20Sopenharmony_ci v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); 21468c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 21478c2ecf20Sopenharmony_ci lp_count = LP_COUNT_G(v1); 21488c2ecf20Sopenharmony_ci hp_count = HP_COUNT_G(v1); 21498c2ecf20Sopenharmony_ci } else { 21508c2ecf20Sopenharmony_ci lp_count = LP_COUNT_T5_G(v1); 21518c2ecf20Sopenharmony_ci hp_count = HP_COUNT_T5_G(v2); 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci return lpfifo ? lp_count : hp_count; 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_dbfifo_count); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci/** 21588c2ecf20Sopenharmony_ci * cxgb4_port_viid - get the VI id of a port 21598c2ecf20Sopenharmony_ci * @dev: the net device for the port 21608c2ecf20Sopenharmony_ci * 21618c2ecf20Sopenharmony_ci * Return the VI id of the given port. 21628c2ecf20Sopenharmony_ci */ 21638c2ecf20Sopenharmony_ciunsigned int cxgb4_port_viid(const struct net_device *dev) 21648c2ecf20Sopenharmony_ci{ 21658c2ecf20Sopenharmony_ci return netdev2pinfo(dev)->viid; 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_viid); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci/** 21708c2ecf20Sopenharmony_ci * cxgb4_port_idx - get the index of a port 21718c2ecf20Sopenharmony_ci * @dev: the net device for the port 21728c2ecf20Sopenharmony_ci * 21738c2ecf20Sopenharmony_ci * Return the index of the given port. 21748c2ecf20Sopenharmony_ci */ 21758c2ecf20Sopenharmony_ciunsigned int cxgb4_port_idx(const struct net_device *dev) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci return netdev2pinfo(dev)->port_id; 21788c2ecf20Sopenharmony_ci} 21798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_idx); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_civoid cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, 21828c2ecf20Sopenharmony_ci struct tp_tcp_stats *v6) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci spin_lock(&adap->stats_lock); 21878c2ecf20Sopenharmony_ci t4_tp_get_tcp_stats(adap, v4, v6, false); 21888c2ecf20Sopenharmony_ci spin_unlock(&adap->stats_lock); 21898c2ecf20Sopenharmony_ci} 21908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_get_tcp_stats); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_civoid cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, 21938c2ecf20Sopenharmony_ci const unsigned int *pgsz_order) 21948c2ecf20Sopenharmony_ci{ 21958c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask); 21988c2ecf20Sopenharmony_ci t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) | 21998c2ecf20Sopenharmony_ci HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) | 22008c2ecf20Sopenharmony_ci HPZ3_V(pgsz_order[3])); 22018c2ecf20Sopenharmony_ci} 22028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_iscsi_init); 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ciint cxgb4_flush_eq_cache(struct net_device *dev) 22058c2ecf20Sopenharmony_ci{ 22068c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci return t4_sge_ctxt_flush(adap, adap->mbox, CTXT_EGRESS); 22098c2ecf20Sopenharmony_ci} 22108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_flush_eq_cache); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cistatic int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx) 22138c2ecf20Sopenharmony_ci{ 22148c2ecf20Sopenharmony_ci u32 addr = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A) + 24 * qid + 8; 22158c2ecf20Sopenharmony_ci __be64 indices; 22168c2ecf20Sopenharmony_ci int ret; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci spin_lock(&adap->win0_lock); 22198c2ecf20Sopenharmony_ci ret = t4_memory_rw(adap, 0, MEM_EDC0, addr, 22208c2ecf20Sopenharmony_ci sizeof(indices), (__be32 *)&indices, 22218c2ecf20Sopenharmony_ci T4_MEMORY_READ); 22228c2ecf20Sopenharmony_ci spin_unlock(&adap->win0_lock); 22238c2ecf20Sopenharmony_ci if (!ret) { 22248c2ecf20Sopenharmony_ci *cidx = (be64_to_cpu(indices) >> 25) & 0xffff; 22258c2ecf20Sopenharmony_ci *pidx = (be64_to_cpu(indices) >> 9) & 0xffff; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci return ret; 22288c2ecf20Sopenharmony_ci} 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ciint cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, 22318c2ecf20Sopenharmony_ci u16 size) 22328c2ecf20Sopenharmony_ci{ 22338c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 22348c2ecf20Sopenharmony_ci u16 hw_pidx, hw_cidx; 22358c2ecf20Sopenharmony_ci int ret; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci ret = read_eq_indices(adap, qid, &hw_pidx, &hw_cidx); 22388c2ecf20Sopenharmony_ci if (ret) 22398c2ecf20Sopenharmony_ci goto out; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci if (pidx != hw_pidx) { 22428c2ecf20Sopenharmony_ci u16 delta; 22438c2ecf20Sopenharmony_ci u32 val; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (pidx >= hw_pidx) 22468c2ecf20Sopenharmony_ci delta = pidx - hw_pidx; 22478c2ecf20Sopenharmony_ci else 22488c2ecf20Sopenharmony_ci delta = size - hw_pidx + pidx; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) 22518c2ecf20Sopenharmony_ci val = PIDX_V(delta); 22528c2ecf20Sopenharmony_ci else 22538c2ecf20Sopenharmony_ci val = PIDX_T5_V(delta); 22548c2ecf20Sopenharmony_ci wmb(); 22558c2ecf20Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 22568c2ecf20Sopenharmony_ci QID_V(qid) | val); 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ciout: 22598c2ecf20Sopenharmony_ci return ret; 22608c2ecf20Sopenharmony_ci} 22618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_sync_txq_pidx); 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ciint cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte) 22648c2ecf20Sopenharmony_ci{ 22658c2ecf20Sopenharmony_ci u32 edc0_size, edc1_size, mc0_size, mc1_size, size; 22668c2ecf20Sopenharmony_ci u32 edc0_end, edc1_end, mc0_end, mc1_end; 22678c2ecf20Sopenharmony_ci u32 offset, memtype, memaddr; 22688c2ecf20Sopenharmony_ci struct adapter *adap; 22698c2ecf20Sopenharmony_ci u32 hma_size = 0; 22708c2ecf20Sopenharmony_ci int ret; 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci offset = ((stag >> 8) * 32) + adap->vres.stag.start; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci /* Figure out where the offset lands in the Memory Type/Address scheme. 22778c2ecf20Sopenharmony_ci * This code assumes that the memory is laid out starting at offset 0 22788c2ecf20Sopenharmony_ci * with no breaks as: EDC0, EDC1, MC0, MC1. All cards have both EDC0 22798c2ecf20Sopenharmony_ci * and EDC1. Some cards will have neither MC0 nor MC1, most cards have 22808c2ecf20Sopenharmony_ci * MC0, and some have both MC0 and MC1. 22818c2ecf20Sopenharmony_ci */ 22828c2ecf20Sopenharmony_ci size = t4_read_reg(adap, MA_EDRAM0_BAR_A); 22838c2ecf20Sopenharmony_ci edc0_size = EDRAM0_SIZE_G(size) << 20; 22848c2ecf20Sopenharmony_ci size = t4_read_reg(adap, MA_EDRAM1_BAR_A); 22858c2ecf20Sopenharmony_ci edc1_size = EDRAM1_SIZE_G(size) << 20; 22868c2ecf20Sopenharmony_ci size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A); 22878c2ecf20Sopenharmony_ci mc0_size = EXT_MEM0_SIZE_G(size) << 20; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A) & HMA_MUX_F) { 22908c2ecf20Sopenharmony_ci size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A); 22918c2ecf20Sopenharmony_ci hma_size = EXT_MEM1_SIZE_G(size) << 20; 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci edc0_end = edc0_size; 22948c2ecf20Sopenharmony_ci edc1_end = edc0_end + edc1_size; 22958c2ecf20Sopenharmony_ci mc0_end = edc1_end + mc0_size; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci if (offset < edc0_end) { 22988c2ecf20Sopenharmony_ci memtype = MEM_EDC0; 22998c2ecf20Sopenharmony_ci memaddr = offset; 23008c2ecf20Sopenharmony_ci } else if (offset < edc1_end) { 23018c2ecf20Sopenharmony_ci memtype = MEM_EDC1; 23028c2ecf20Sopenharmony_ci memaddr = offset - edc0_end; 23038c2ecf20Sopenharmony_ci } else { 23048c2ecf20Sopenharmony_ci if (hma_size && (offset < (edc1_end + hma_size))) { 23058c2ecf20Sopenharmony_ci memtype = MEM_HMA; 23068c2ecf20Sopenharmony_ci memaddr = offset - edc1_end; 23078c2ecf20Sopenharmony_ci } else if (offset < mc0_end) { 23088c2ecf20Sopenharmony_ci memtype = MEM_MC0; 23098c2ecf20Sopenharmony_ci memaddr = offset - edc1_end; 23108c2ecf20Sopenharmony_ci } else if (is_t5(adap->params.chip)) { 23118c2ecf20Sopenharmony_ci size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A); 23128c2ecf20Sopenharmony_ci mc1_size = EXT_MEM1_SIZE_G(size) << 20; 23138c2ecf20Sopenharmony_ci mc1_end = mc0_end + mc1_size; 23148c2ecf20Sopenharmony_ci if (offset < mc1_end) { 23158c2ecf20Sopenharmony_ci memtype = MEM_MC1; 23168c2ecf20Sopenharmony_ci memaddr = offset - mc0_end; 23178c2ecf20Sopenharmony_ci } else { 23188c2ecf20Sopenharmony_ci /* offset beyond the end of any memory */ 23198c2ecf20Sopenharmony_ci goto err; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci } else { 23228c2ecf20Sopenharmony_ci /* T4/T6 only has a single memory channel */ 23238c2ecf20Sopenharmony_ci goto err; 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci spin_lock(&adap->win0_lock); 23288c2ecf20Sopenharmony_ci ret = t4_memory_rw(adap, 0, memtype, memaddr, 32, tpte, T4_MEMORY_READ); 23298c2ecf20Sopenharmony_ci spin_unlock(&adap->win0_lock); 23308c2ecf20Sopenharmony_ci return ret; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_cierr: 23338c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "stag %#x, offset %#x out of range\n", 23348c2ecf20Sopenharmony_ci stag, offset); 23358c2ecf20Sopenharmony_ci return -EINVAL; 23368c2ecf20Sopenharmony_ci} 23378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_read_tpte); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ciu64 cxgb4_read_sge_timestamp(struct net_device *dev) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci u32 hi, lo; 23428c2ecf20Sopenharmony_ci struct adapter *adap; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 23458c2ecf20Sopenharmony_ci lo = t4_read_reg(adap, SGE_TIMESTAMP_LO_A); 23468c2ecf20Sopenharmony_ci hi = TSVAL_G(t4_read_reg(adap, SGE_TIMESTAMP_HI_A)); 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci return ((u64)hi << 32) | (u64)lo; 23498c2ecf20Sopenharmony_ci} 23508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_read_sge_timestamp); 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ciint cxgb4_bar2_sge_qregs(struct net_device *dev, 23538c2ecf20Sopenharmony_ci unsigned int qid, 23548c2ecf20Sopenharmony_ci enum cxgb4_bar2_qtype qtype, 23558c2ecf20Sopenharmony_ci int user, 23568c2ecf20Sopenharmony_ci u64 *pbar2_qoffset, 23578c2ecf20Sopenharmony_ci unsigned int *pbar2_qid) 23588c2ecf20Sopenharmony_ci{ 23598c2ecf20Sopenharmony_ci return t4_bar2_sge_qregs(netdev2adap(dev), 23608c2ecf20Sopenharmony_ci qid, 23618c2ecf20Sopenharmony_ci (qtype == CXGB4_BAR2_QTYPE_EGRESS 23628c2ecf20Sopenharmony_ci ? T4_BAR2_QTYPE_EGRESS 23638c2ecf20Sopenharmony_ci : T4_BAR2_QTYPE_INGRESS), 23648c2ecf20Sopenharmony_ci user, 23658c2ecf20Sopenharmony_ci pbar2_qoffset, 23668c2ecf20Sopenharmony_ci pbar2_qid); 23678c2ecf20Sopenharmony_ci} 23688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_bar2_sge_qregs); 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_cistatic struct pci_driver cxgb4_driver; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cistatic void check_neigh_update(struct neighbour *neigh) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci const struct device *parent; 23758c2ecf20Sopenharmony_ci const struct net_device *netdev = neigh->dev; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci if (is_vlan_dev(netdev)) 23788c2ecf20Sopenharmony_ci netdev = vlan_dev_real_dev(netdev); 23798c2ecf20Sopenharmony_ci parent = netdev->dev.parent; 23808c2ecf20Sopenharmony_ci if (parent && parent->driver == &cxgb4_driver.driver) 23818c2ecf20Sopenharmony_ci t4_l2t_update(dev_get_drvdata(parent), neigh); 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_cistatic int netevent_cb(struct notifier_block *nb, unsigned long event, 23858c2ecf20Sopenharmony_ci void *data) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci switch (event) { 23888c2ecf20Sopenharmony_ci case NETEVENT_NEIGH_UPDATE: 23898c2ecf20Sopenharmony_ci check_neigh_update(data); 23908c2ecf20Sopenharmony_ci break; 23918c2ecf20Sopenharmony_ci case NETEVENT_REDIRECT: 23928c2ecf20Sopenharmony_ci default: 23938c2ecf20Sopenharmony_ci break; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci return 0; 23968c2ecf20Sopenharmony_ci} 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_cistatic bool netevent_registered; 23998c2ecf20Sopenharmony_cistatic struct notifier_block cxgb4_netevent_nb = { 24008c2ecf20Sopenharmony_ci .notifier_call = netevent_cb 24018c2ecf20Sopenharmony_ci}; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_cistatic void drain_db_fifo(struct adapter *adap, int usecs) 24048c2ecf20Sopenharmony_ci{ 24058c2ecf20Sopenharmony_ci u32 v1, v2, lp_count, hp_count; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci do { 24088c2ecf20Sopenharmony_ci v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); 24098c2ecf20Sopenharmony_ci v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); 24108c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 24118c2ecf20Sopenharmony_ci lp_count = LP_COUNT_G(v1); 24128c2ecf20Sopenharmony_ci hp_count = HP_COUNT_G(v1); 24138c2ecf20Sopenharmony_ci } else { 24148c2ecf20Sopenharmony_ci lp_count = LP_COUNT_T5_G(v1); 24158c2ecf20Sopenharmony_ci hp_count = HP_COUNT_T5_G(v2); 24168c2ecf20Sopenharmony_ci } 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci if (lp_count == 0 && hp_count == 0) 24198c2ecf20Sopenharmony_ci break; 24208c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 24218c2ecf20Sopenharmony_ci schedule_timeout(usecs_to_jiffies(usecs)); 24228c2ecf20Sopenharmony_ci } while (1); 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_cistatic void disable_txq_db(struct sge_txq *q) 24268c2ecf20Sopenharmony_ci{ 24278c2ecf20Sopenharmony_ci unsigned long flags; 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci spin_lock_irqsave(&q->db_lock, flags); 24308c2ecf20Sopenharmony_ci q->db_disabled = 1; 24318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&q->db_lock, flags); 24328c2ecf20Sopenharmony_ci} 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_cistatic void enable_txq_db(struct adapter *adap, struct sge_txq *q) 24358c2ecf20Sopenharmony_ci{ 24368c2ecf20Sopenharmony_ci spin_lock_irq(&q->db_lock); 24378c2ecf20Sopenharmony_ci if (q->db_pidx_inc) { 24388c2ecf20Sopenharmony_ci /* Make sure that all writes to the TX descriptors 24398c2ecf20Sopenharmony_ci * are committed before we tell HW about them. 24408c2ecf20Sopenharmony_ci */ 24418c2ecf20Sopenharmony_ci wmb(); 24428c2ecf20Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 24438c2ecf20Sopenharmony_ci QID_V(q->cntxt_id) | PIDX_V(q->db_pidx_inc)); 24448c2ecf20Sopenharmony_ci q->db_pidx_inc = 0; 24458c2ecf20Sopenharmony_ci } 24468c2ecf20Sopenharmony_ci q->db_disabled = 0; 24478c2ecf20Sopenharmony_ci spin_unlock_irq(&q->db_lock); 24488c2ecf20Sopenharmony_ci} 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_cistatic void disable_dbs(struct adapter *adap) 24518c2ecf20Sopenharmony_ci{ 24528c2ecf20Sopenharmony_ci int i; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci for_each_ethrxq(&adap->sge, i) 24558c2ecf20Sopenharmony_ci disable_txq_db(&adap->sge.ethtxq[i].q); 24568c2ecf20Sopenharmony_ci if (is_offload(adap)) { 24578c2ecf20Sopenharmony_ci struct sge_uld_txq_info *txq_info = 24588c2ecf20Sopenharmony_ci adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (txq_info) { 24618c2ecf20Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 24628c2ecf20Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci disable_txq_db(&txq->q); 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci for_each_port(adap, i) 24698c2ecf20Sopenharmony_ci disable_txq_db(&adap->sge.ctrlq[i].q); 24708c2ecf20Sopenharmony_ci} 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_cistatic void enable_dbs(struct adapter *adap) 24738c2ecf20Sopenharmony_ci{ 24748c2ecf20Sopenharmony_ci int i; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci for_each_ethrxq(&adap->sge, i) 24778c2ecf20Sopenharmony_ci enable_txq_db(adap, &adap->sge.ethtxq[i].q); 24788c2ecf20Sopenharmony_ci if (is_offload(adap)) { 24798c2ecf20Sopenharmony_ci struct sge_uld_txq_info *txq_info = 24808c2ecf20Sopenharmony_ci adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci if (txq_info) { 24838c2ecf20Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 24848c2ecf20Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci enable_txq_db(adap, &txq->q); 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci for_each_port(adap, i) 24918c2ecf20Sopenharmony_ci enable_txq_db(adap, &adap->sge.ctrlq[i].q); 24928c2ecf20Sopenharmony_ci} 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_cistatic void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd) 24958c2ecf20Sopenharmony_ci{ 24968c2ecf20Sopenharmony_ci enum cxgb4_uld type = CXGB4_ULD_RDMA; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci if (adap->uld && adap->uld[type].handle) 24998c2ecf20Sopenharmony_ci adap->uld[type].control(adap->uld[type].handle, cmd); 25008c2ecf20Sopenharmony_ci} 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_cistatic void process_db_full(struct work_struct *work) 25038c2ecf20Sopenharmony_ci{ 25048c2ecf20Sopenharmony_ci struct adapter *adap; 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci adap = container_of(work, struct adapter, db_full_task); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 25098c2ecf20Sopenharmony_ci enable_dbs(adap); 25108c2ecf20Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); 25118c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 25128c2ecf20Sopenharmony_ci t4_set_reg_field(adap, SGE_INT_ENABLE3_A, 25138c2ecf20Sopenharmony_ci DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 25148c2ecf20Sopenharmony_ci DBFIFO_HP_INT_F | DBFIFO_LP_INT_F); 25158c2ecf20Sopenharmony_ci else 25168c2ecf20Sopenharmony_ci t4_set_reg_field(adap, SGE_INT_ENABLE3_A, 25178c2ecf20Sopenharmony_ci DBFIFO_LP_INT_F, DBFIFO_LP_INT_F); 25188c2ecf20Sopenharmony_ci} 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_cistatic void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci u16 hw_pidx, hw_cidx; 25238c2ecf20Sopenharmony_ci int ret; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci spin_lock_irq(&q->db_lock); 25268c2ecf20Sopenharmony_ci ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx); 25278c2ecf20Sopenharmony_ci if (ret) 25288c2ecf20Sopenharmony_ci goto out; 25298c2ecf20Sopenharmony_ci if (q->db_pidx != hw_pidx) { 25308c2ecf20Sopenharmony_ci u16 delta; 25318c2ecf20Sopenharmony_ci u32 val; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci if (q->db_pidx >= hw_pidx) 25348c2ecf20Sopenharmony_ci delta = q->db_pidx - hw_pidx; 25358c2ecf20Sopenharmony_ci else 25368c2ecf20Sopenharmony_ci delta = q->size - hw_pidx + q->db_pidx; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) 25398c2ecf20Sopenharmony_ci val = PIDX_V(delta); 25408c2ecf20Sopenharmony_ci else 25418c2ecf20Sopenharmony_ci val = PIDX_T5_V(delta); 25428c2ecf20Sopenharmony_ci wmb(); 25438c2ecf20Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 25448c2ecf20Sopenharmony_ci QID_V(q->cntxt_id) | val); 25458c2ecf20Sopenharmony_ci } 25468c2ecf20Sopenharmony_ciout: 25478c2ecf20Sopenharmony_ci q->db_disabled = 0; 25488c2ecf20Sopenharmony_ci q->db_pidx_inc = 0; 25498c2ecf20Sopenharmony_ci spin_unlock_irq(&q->db_lock); 25508c2ecf20Sopenharmony_ci if (ret) 25518c2ecf20Sopenharmony_ci CH_WARN(adap, "DB drop recovery failed.\n"); 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cistatic void recover_all_queues(struct adapter *adap) 25558c2ecf20Sopenharmony_ci{ 25568c2ecf20Sopenharmony_ci int i; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci for_each_ethrxq(&adap->sge, i) 25598c2ecf20Sopenharmony_ci sync_txq_pidx(adap, &adap->sge.ethtxq[i].q); 25608c2ecf20Sopenharmony_ci if (is_offload(adap)) { 25618c2ecf20Sopenharmony_ci struct sge_uld_txq_info *txq_info = 25628c2ecf20Sopenharmony_ci adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 25638c2ecf20Sopenharmony_ci if (txq_info) { 25648c2ecf20Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 25658c2ecf20Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci sync_txq_pidx(adap, &txq->q); 25688c2ecf20Sopenharmony_ci } 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci for_each_port(adap, i) 25728c2ecf20Sopenharmony_ci sync_txq_pidx(adap, &adap->sge.ctrlq[i].q); 25738c2ecf20Sopenharmony_ci} 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_cistatic void process_db_drop(struct work_struct *work) 25768c2ecf20Sopenharmony_ci{ 25778c2ecf20Sopenharmony_ci struct adapter *adap; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci adap = container_of(work, struct adapter, db_drop_task); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 25828c2ecf20Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 25838c2ecf20Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP); 25848c2ecf20Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 25858c2ecf20Sopenharmony_ci recover_all_queues(adap); 25868c2ecf20Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 25878c2ecf20Sopenharmony_ci enable_dbs(adap); 25888c2ecf20Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); 25898c2ecf20Sopenharmony_ci } else if (is_t5(adap->params.chip)) { 25908c2ecf20Sopenharmony_ci u32 dropped_db = t4_read_reg(adap, 0x010ac); 25918c2ecf20Sopenharmony_ci u16 qid = (dropped_db >> 15) & 0x1ffff; 25928c2ecf20Sopenharmony_ci u16 pidx_inc = dropped_db & 0x1fff; 25938c2ecf20Sopenharmony_ci u64 bar2_qoffset; 25948c2ecf20Sopenharmony_ci unsigned int bar2_qid; 25958c2ecf20Sopenharmony_ci int ret; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci ret = t4_bar2_sge_qregs(adap, qid, T4_BAR2_QTYPE_EGRESS, 25988c2ecf20Sopenharmony_ci 0, &bar2_qoffset, &bar2_qid); 25998c2ecf20Sopenharmony_ci if (ret) 26008c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "doorbell drop recovery: " 26018c2ecf20Sopenharmony_ci "qid=%d, pidx_inc=%d\n", qid, pidx_inc); 26028c2ecf20Sopenharmony_ci else 26038c2ecf20Sopenharmony_ci writel(PIDX_T5_V(pidx_inc) | QID_V(bar2_qid), 26048c2ecf20Sopenharmony_ci adap->bar2 + bar2_qoffset + SGE_UDB_KDOORBELL); 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci /* Re-enable BAR2 WC */ 26078c2ecf20Sopenharmony_ci t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15); 26088c2ecf20Sopenharmony_ci } 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 26118c2ecf20Sopenharmony_ci t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0); 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_civoid t4_db_full(struct adapter *adap) 26158c2ecf20Sopenharmony_ci{ 26168c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 26178c2ecf20Sopenharmony_ci disable_dbs(adap); 26188c2ecf20Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); 26198c2ecf20Sopenharmony_ci t4_set_reg_field(adap, SGE_INT_ENABLE3_A, 26208c2ecf20Sopenharmony_ci DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 0); 26218c2ecf20Sopenharmony_ci queue_work(adap->workq, &adap->db_full_task); 26228c2ecf20Sopenharmony_ci } 26238c2ecf20Sopenharmony_ci} 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_civoid t4_db_dropped(struct adapter *adap) 26268c2ecf20Sopenharmony_ci{ 26278c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 26288c2ecf20Sopenharmony_ci disable_dbs(adap); 26298c2ecf20Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); 26308c2ecf20Sopenharmony_ci } 26318c2ecf20Sopenharmony_ci queue_work(adap->workq, &adap->db_drop_task); 26328c2ecf20Sopenharmony_ci} 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_civoid t4_register_netevent_notifier(void) 26358c2ecf20Sopenharmony_ci{ 26368c2ecf20Sopenharmony_ci if (!netevent_registered) { 26378c2ecf20Sopenharmony_ci register_netevent_notifier(&cxgb4_netevent_nb); 26388c2ecf20Sopenharmony_ci netevent_registered = true; 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_cistatic void detach_ulds(struct adapter *adap) 26438c2ecf20Sopenharmony_ci{ 26448c2ecf20Sopenharmony_ci unsigned int i; 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci if (!is_uld(adap)) 26478c2ecf20Sopenharmony_ci return; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci mutex_lock(&uld_mutex); 26508c2ecf20Sopenharmony_ci list_del(&adap->list_node); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci for (i = 0; i < CXGB4_ULD_MAX; i++) 26538c2ecf20Sopenharmony_ci if (adap->uld && adap->uld[i].handle) 26548c2ecf20Sopenharmony_ci adap->uld[i].state_change(adap->uld[i].handle, 26558c2ecf20Sopenharmony_ci CXGB4_STATE_DETACH); 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci if (netevent_registered && list_empty(&adapter_list)) { 26588c2ecf20Sopenharmony_ci unregister_netevent_notifier(&cxgb4_netevent_nb); 26598c2ecf20Sopenharmony_ci netevent_registered = false; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic void notify_ulds(struct adapter *adap, enum cxgb4_state new_state) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci unsigned int i; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci mutex_lock(&uld_mutex); 26698c2ecf20Sopenharmony_ci for (i = 0; i < CXGB4_ULD_MAX; i++) 26708c2ecf20Sopenharmony_ci if (adap->uld && adap->uld[i].handle) 26718c2ecf20Sopenharmony_ci adap->uld[i].state_change(adap->uld[i].handle, 26728c2ecf20Sopenharmony_ci new_state); 26738c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 26748c2ecf20Sopenharmony_ci} 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 26778c2ecf20Sopenharmony_cistatic int cxgb4_inet6addr_handler(struct notifier_block *this, 26788c2ecf20Sopenharmony_ci unsigned long event, void *data) 26798c2ecf20Sopenharmony_ci{ 26808c2ecf20Sopenharmony_ci struct inet6_ifaddr *ifa = data; 26818c2ecf20Sopenharmony_ci struct net_device *event_dev = ifa->idev->dev; 26828c2ecf20Sopenharmony_ci const struct device *parent = NULL; 26838c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_BONDING) 26848c2ecf20Sopenharmony_ci struct adapter *adap; 26858c2ecf20Sopenharmony_ci#endif 26868c2ecf20Sopenharmony_ci if (is_vlan_dev(event_dev)) 26878c2ecf20Sopenharmony_ci event_dev = vlan_dev_real_dev(event_dev); 26888c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_BONDING) 26898c2ecf20Sopenharmony_ci if (event_dev->flags & IFF_MASTER) { 26908c2ecf20Sopenharmony_ci list_for_each_entry(adap, &adapter_list, list_node) { 26918c2ecf20Sopenharmony_ci switch (event) { 26928c2ecf20Sopenharmony_ci case NETDEV_UP: 26938c2ecf20Sopenharmony_ci cxgb4_clip_get(adap->port[0], 26948c2ecf20Sopenharmony_ci (const u32 *)ifa, 1); 26958c2ecf20Sopenharmony_ci break; 26968c2ecf20Sopenharmony_ci case NETDEV_DOWN: 26978c2ecf20Sopenharmony_ci cxgb4_clip_release(adap->port[0], 26988c2ecf20Sopenharmony_ci (const u32 *)ifa, 1); 26998c2ecf20Sopenharmony_ci break; 27008c2ecf20Sopenharmony_ci default: 27018c2ecf20Sopenharmony_ci break; 27028c2ecf20Sopenharmony_ci } 27038c2ecf20Sopenharmony_ci } 27048c2ecf20Sopenharmony_ci return NOTIFY_OK; 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci#endif 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci if (event_dev) 27098c2ecf20Sopenharmony_ci parent = event_dev->dev.parent; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci if (parent && parent->driver == &cxgb4_driver.driver) { 27128c2ecf20Sopenharmony_ci switch (event) { 27138c2ecf20Sopenharmony_ci case NETDEV_UP: 27148c2ecf20Sopenharmony_ci cxgb4_clip_get(event_dev, (const u32 *)ifa, 1); 27158c2ecf20Sopenharmony_ci break; 27168c2ecf20Sopenharmony_ci case NETDEV_DOWN: 27178c2ecf20Sopenharmony_ci cxgb4_clip_release(event_dev, (const u32 *)ifa, 1); 27188c2ecf20Sopenharmony_ci break; 27198c2ecf20Sopenharmony_ci default: 27208c2ecf20Sopenharmony_ci break; 27218c2ecf20Sopenharmony_ci } 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci return NOTIFY_OK; 27248c2ecf20Sopenharmony_ci} 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_cistatic bool inet6addr_registered; 27278c2ecf20Sopenharmony_cistatic struct notifier_block cxgb4_inet6addr_notifier = { 27288c2ecf20Sopenharmony_ci .notifier_call = cxgb4_inet6addr_handler 27298c2ecf20Sopenharmony_ci}; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_cistatic void update_clip(const struct adapter *adap) 27328c2ecf20Sopenharmony_ci{ 27338c2ecf20Sopenharmony_ci int i; 27348c2ecf20Sopenharmony_ci struct net_device *dev; 27358c2ecf20Sopenharmony_ci int ret; 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci rcu_read_lock(); 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) { 27408c2ecf20Sopenharmony_ci dev = adap->port[i]; 27418c2ecf20Sopenharmony_ci ret = 0; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci if (dev) 27448c2ecf20Sopenharmony_ci ret = cxgb4_update_root_dev_clip(dev); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci if (ret < 0) 27478c2ecf20Sopenharmony_ci break; 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci rcu_read_unlock(); 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */ 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci/** 27548c2ecf20Sopenharmony_ci * cxgb_up - enable the adapter 27558c2ecf20Sopenharmony_ci * @adap: adapter being enabled 27568c2ecf20Sopenharmony_ci * 27578c2ecf20Sopenharmony_ci * Called when the first port is enabled, this function performs the 27588c2ecf20Sopenharmony_ci * actions necessary to make an adapter operational, such as completing 27598c2ecf20Sopenharmony_ci * the initialization of HW modules, and enabling interrupts. 27608c2ecf20Sopenharmony_ci * 27618c2ecf20Sopenharmony_ci * Must be called with the rtnl lock held. 27628c2ecf20Sopenharmony_ci */ 27638c2ecf20Sopenharmony_cistatic int cxgb_up(struct adapter *adap) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 27668c2ecf20Sopenharmony_ci int err; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci mutex_lock(&uld_mutex); 27698c2ecf20Sopenharmony_ci err = setup_sge_queues(adap); 27708c2ecf20Sopenharmony_ci if (err) 27718c2ecf20Sopenharmony_ci goto rel_lock; 27728c2ecf20Sopenharmony_ci err = setup_rss(adap); 27738c2ecf20Sopenharmony_ci if (err) 27748c2ecf20Sopenharmony_ci goto freeq; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 27778c2ecf20Sopenharmony_ci if (s->nd_msix_idx < 0) { 27788c2ecf20Sopenharmony_ci err = -ENOMEM; 27798c2ecf20Sopenharmony_ci goto irq_err; 27808c2ecf20Sopenharmony_ci } 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci err = request_irq(adap->msix_info[s->nd_msix_idx].vec, 27838c2ecf20Sopenharmony_ci t4_nondata_intr, 0, 27848c2ecf20Sopenharmony_ci adap->msix_info[s->nd_msix_idx].desc, adap); 27858c2ecf20Sopenharmony_ci if (err) 27868c2ecf20Sopenharmony_ci goto irq_err; 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci err = request_msix_queue_irqs(adap); 27898c2ecf20Sopenharmony_ci if (err) 27908c2ecf20Sopenharmony_ci goto irq_err_free_nd_msix; 27918c2ecf20Sopenharmony_ci } else { 27928c2ecf20Sopenharmony_ci err = request_irq(adap->pdev->irq, t4_intr_handler(adap), 27938c2ecf20Sopenharmony_ci (adap->flags & CXGB4_USING_MSI) ? 0 27948c2ecf20Sopenharmony_ci : IRQF_SHARED, 27958c2ecf20Sopenharmony_ci adap->port[0]->name, adap); 27968c2ecf20Sopenharmony_ci if (err) 27978c2ecf20Sopenharmony_ci goto irq_err; 27988c2ecf20Sopenharmony_ci } 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci enable_rx(adap); 28018c2ecf20Sopenharmony_ci t4_sge_start(adap); 28028c2ecf20Sopenharmony_ci t4_intr_enable(adap); 28038c2ecf20Sopenharmony_ci adap->flags |= CXGB4_FULL_INIT_DONE; 28048c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci notify_ulds(adap, CXGB4_STATE_UP); 28078c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 28088c2ecf20Sopenharmony_ci update_clip(adap); 28098c2ecf20Sopenharmony_ci#endif 28108c2ecf20Sopenharmony_ci return err; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ciirq_err_free_nd_msix: 28138c2ecf20Sopenharmony_ci free_irq(adap->msix_info[s->nd_msix_idx].vec, adap); 28148c2ecf20Sopenharmony_ciirq_err: 28158c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); 28168c2ecf20Sopenharmony_cifreeq: 28178c2ecf20Sopenharmony_ci t4_free_sge_resources(adap); 28188c2ecf20Sopenharmony_cirel_lock: 28198c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 28208c2ecf20Sopenharmony_ci return err; 28218c2ecf20Sopenharmony_ci} 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_cistatic void cxgb_down(struct adapter *adapter) 28248c2ecf20Sopenharmony_ci{ 28258c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->tid_release_task); 28268c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->db_full_task); 28278c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->db_drop_task); 28288c2ecf20Sopenharmony_ci adapter->tid_release_task_busy = false; 28298c2ecf20Sopenharmony_ci adapter->tid_release_head = NULL; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci t4_sge_stop(adapter); 28328c2ecf20Sopenharmony_ci t4_free_sge_resources(adapter); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci adapter->flags &= ~CXGB4_FULL_INIT_DONE; 28358c2ecf20Sopenharmony_ci} 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci/* 28388c2ecf20Sopenharmony_ci * net_device operations 28398c2ecf20Sopenharmony_ci */ 28408c2ecf20Sopenharmony_cistatic int cxgb_open(struct net_device *dev) 28418c2ecf20Sopenharmony_ci{ 28428c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 28438c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 28448c2ecf20Sopenharmony_ci int err; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci netif_carrier_off(dev); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) { 28498c2ecf20Sopenharmony_ci err = cxgb_up(adapter); 28508c2ecf20Sopenharmony_ci if (err < 0) 28518c2ecf20Sopenharmony_ci return err; 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci /* It's possible that the basic port information could have 28558c2ecf20Sopenharmony_ci * changed since we first read it. 28568c2ecf20Sopenharmony_ci */ 28578c2ecf20Sopenharmony_ci err = t4_update_port_info(pi); 28588c2ecf20Sopenharmony_ci if (err < 0) 28598c2ecf20Sopenharmony_ci return err; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci err = link_start(dev); 28628c2ecf20Sopenharmony_ci if (err) 28638c2ecf20Sopenharmony_ci return err; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (pi->nmirrorqsets) { 28668c2ecf20Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 28678c2ecf20Sopenharmony_ci err = cxgb4_port_mirror_alloc_queues(dev); 28688c2ecf20Sopenharmony_ci if (err) 28698c2ecf20Sopenharmony_ci goto out_unlock; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci err = cxgb4_port_mirror_start(dev); 28728c2ecf20Sopenharmony_ci if (err) 28738c2ecf20Sopenharmony_ci goto out_free_queues; 28748c2ecf20Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 28758c2ecf20Sopenharmony_ci } 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 28788c2ecf20Sopenharmony_ci return 0; 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ciout_free_queues: 28818c2ecf20Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ciout_unlock: 28848c2ecf20Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 28858c2ecf20Sopenharmony_ci return err; 28868c2ecf20Sopenharmony_ci} 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_cistatic int cxgb_close(struct net_device *dev) 28898c2ecf20Sopenharmony_ci{ 28908c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 28918c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 28928c2ecf20Sopenharmony_ci int ret; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 28958c2ecf20Sopenharmony_ci netif_carrier_off(dev); 28968c2ecf20Sopenharmony_ci ret = t4_enable_pi_params(adapter, adapter->pf, pi, 28978c2ecf20Sopenharmony_ci false, false, false); 28988c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 28998c2ecf20Sopenharmony_ci cxgb4_dcb_reset(dev); 29008c2ecf20Sopenharmony_ci dcb_tx_queue_prio_enable(dev, false); 29018c2ecf20Sopenharmony_ci#endif 29028c2ecf20Sopenharmony_ci if (ret) 29038c2ecf20Sopenharmony_ci return ret; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci if (pi->nmirrorqsets) { 29068c2ecf20Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 29078c2ecf20Sopenharmony_ci cxgb4_port_mirror_stop(dev); 29088c2ecf20Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 29098c2ecf20Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 29108c2ecf20Sopenharmony_ci } 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci return 0; 29138c2ecf20Sopenharmony_ci} 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ciint cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, 29168c2ecf20Sopenharmony_ci __be32 sip, __be16 sport, __be16 vlan, 29178c2ecf20Sopenharmony_ci unsigned int queue, unsigned char port, unsigned char mask) 29188c2ecf20Sopenharmony_ci{ 29198c2ecf20Sopenharmony_ci int ret; 29208c2ecf20Sopenharmony_ci struct filter_entry *f; 29218c2ecf20Sopenharmony_ci struct adapter *adap; 29228c2ecf20Sopenharmony_ci int i; 29238c2ecf20Sopenharmony_ci u8 *val; 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci /* Adjust stid to correct filter index */ 29288c2ecf20Sopenharmony_ci stid -= adap->tids.sftid_base; 29298c2ecf20Sopenharmony_ci stid += adap->tids.nftids; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci /* Check to make sure the filter requested is writable ... 29328c2ecf20Sopenharmony_ci */ 29338c2ecf20Sopenharmony_ci f = &adap->tids.ftid_tab[stid]; 29348c2ecf20Sopenharmony_ci ret = writable_filter(f); 29358c2ecf20Sopenharmony_ci if (ret) 29368c2ecf20Sopenharmony_ci return ret; 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci /* Clear out any old resources being used by the filter before 29398c2ecf20Sopenharmony_ci * we start constructing the new filter. 29408c2ecf20Sopenharmony_ci */ 29418c2ecf20Sopenharmony_ci if (f->valid) 29428c2ecf20Sopenharmony_ci clear_filter(adap, f); 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci /* Clear out filter specifications */ 29458c2ecf20Sopenharmony_ci memset(&f->fs, 0, sizeof(struct ch_filter_specification)); 29468c2ecf20Sopenharmony_ci f->fs.val.lport = be16_to_cpu(sport); 29478c2ecf20Sopenharmony_ci f->fs.mask.lport = ~0; 29488c2ecf20Sopenharmony_ci val = (u8 *)&sip; 29498c2ecf20Sopenharmony_ci if ((val[0] | val[1] | val[2] | val[3]) != 0) { 29508c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 29518c2ecf20Sopenharmony_ci f->fs.val.lip[i] = val[i]; 29528c2ecf20Sopenharmony_ci f->fs.mask.lip[i] = ~0; 29538c2ecf20Sopenharmony_ci } 29548c2ecf20Sopenharmony_ci if (adap->params.tp.vlan_pri_map & PORT_F) { 29558c2ecf20Sopenharmony_ci f->fs.val.iport = port; 29568c2ecf20Sopenharmony_ci f->fs.mask.iport = mask; 29578c2ecf20Sopenharmony_ci } 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci if (adap->params.tp.vlan_pri_map & PROTOCOL_F) { 29618c2ecf20Sopenharmony_ci f->fs.val.proto = IPPROTO_TCP; 29628c2ecf20Sopenharmony_ci f->fs.mask.proto = ~0; 29638c2ecf20Sopenharmony_ci } 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci f->fs.dirsteer = 1; 29668c2ecf20Sopenharmony_ci f->fs.iq = queue; 29678c2ecf20Sopenharmony_ci /* Mark filter as locked */ 29688c2ecf20Sopenharmony_ci f->locked = 1; 29698c2ecf20Sopenharmony_ci f->fs.rpttid = 1; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci /* Save the actual tid. We need this to get the corresponding 29728c2ecf20Sopenharmony_ci * filter entry structure in filter_rpl. 29738c2ecf20Sopenharmony_ci */ 29748c2ecf20Sopenharmony_ci f->tid = stid + adap->tids.ftid_base; 29758c2ecf20Sopenharmony_ci ret = set_filter_wr(adap, stid); 29768c2ecf20Sopenharmony_ci if (ret) { 29778c2ecf20Sopenharmony_ci clear_filter(adap, f); 29788c2ecf20Sopenharmony_ci return ret; 29798c2ecf20Sopenharmony_ci } 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci return 0; 29828c2ecf20Sopenharmony_ci} 29838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server_filter); 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ciint cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, 29868c2ecf20Sopenharmony_ci unsigned int queue, bool ipv6) 29878c2ecf20Sopenharmony_ci{ 29888c2ecf20Sopenharmony_ci struct filter_entry *f; 29898c2ecf20Sopenharmony_ci struct adapter *adap; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci adap = netdev2adap(dev); 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci /* Adjust stid to correct filter index */ 29948c2ecf20Sopenharmony_ci stid -= adap->tids.sftid_base; 29958c2ecf20Sopenharmony_ci stid += adap->tids.nftids; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci f = &adap->tids.ftid_tab[stid]; 29988c2ecf20Sopenharmony_ci /* Unlock the filter */ 29998c2ecf20Sopenharmony_ci f->locked = 0; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci return delete_filter(adap, stid); 30028c2ecf20Sopenharmony_ci} 30038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_server_filter); 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_cistatic void cxgb_get_stats(struct net_device *dev, 30068c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *ns) 30078c2ecf20Sopenharmony_ci{ 30088c2ecf20Sopenharmony_ci struct port_stats stats; 30098c2ecf20Sopenharmony_ci struct port_info *p = netdev_priv(dev); 30108c2ecf20Sopenharmony_ci struct adapter *adapter = p->adapter; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci /* Block retrieving statistics during EEH error 30138c2ecf20Sopenharmony_ci * recovery. Otherwise, the recovery might fail 30148c2ecf20Sopenharmony_ci * and the PCI device will be removed permanently 30158c2ecf20Sopenharmony_ci */ 30168c2ecf20Sopenharmony_ci spin_lock(&adapter->stats_lock); 30178c2ecf20Sopenharmony_ci if (!netif_device_present(dev)) { 30188c2ecf20Sopenharmony_ci spin_unlock(&adapter->stats_lock); 30198c2ecf20Sopenharmony_ci return; 30208c2ecf20Sopenharmony_ci } 30218c2ecf20Sopenharmony_ci t4_get_port_stats_offset(adapter, p->tx_chan, &stats, 30228c2ecf20Sopenharmony_ci &p->stats_base); 30238c2ecf20Sopenharmony_ci spin_unlock(&adapter->stats_lock); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci ns->tx_bytes = stats.tx_octets; 30268c2ecf20Sopenharmony_ci ns->tx_packets = stats.tx_frames; 30278c2ecf20Sopenharmony_ci ns->rx_bytes = stats.rx_octets; 30288c2ecf20Sopenharmony_ci ns->rx_packets = stats.rx_frames; 30298c2ecf20Sopenharmony_ci ns->multicast = stats.rx_mcast_frames; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci /* detailed rx_errors */ 30328c2ecf20Sopenharmony_ci ns->rx_length_errors = stats.rx_jabber + stats.rx_too_long + 30338c2ecf20Sopenharmony_ci stats.rx_runt; 30348c2ecf20Sopenharmony_ci ns->rx_over_errors = 0; 30358c2ecf20Sopenharmony_ci ns->rx_crc_errors = stats.rx_fcs_err; 30368c2ecf20Sopenharmony_ci ns->rx_frame_errors = stats.rx_symbol_err; 30378c2ecf20Sopenharmony_ci ns->rx_dropped = stats.rx_ovflow0 + stats.rx_ovflow1 + 30388c2ecf20Sopenharmony_ci stats.rx_ovflow2 + stats.rx_ovflow3 + 30398c2ecf20Sopenharmony_ci stats.rx_trunc0 + stats.rx_trunc1 + 30408c2ecf20Sopenharmony_ci stats.rx_trunc2 + stats.rx_trunc3; 30418c2ecf20Sopenharmony_ci ns->rx_missed_errors = 0; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci /* detailed tx_errors */ 30448c2ecf20Sopenharmony_ci ns->tx_aborted_errors = 0; 30458c2ecf20Sopenharmony_ci ns->tx_carrier_errors = 0; 30468c2ecf20Sopenharmony_ci ns->tx_fifo_errors = 0; 30478c2ecf20Sopenharmony_ci ns->tx_heartbeat_errors = 0; 30488c2ecf20Sopenharmony_ci ns->tx_window_errors = 0; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci ns->tx_errors = stats.tx_error_frames; 30518c2ecf20Sopenharmony_ci ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err + 30528c2ecf20Sopenharmony_ci ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors; 30538c2ecf20Sopenharmony_ci} 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_cistatic int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) 30568c2ecf20Sopenharmony_ci{ 30578c2ecf20Sopenharmony_ci unsigned int mbox; 30588c2ecf20Sopenharmony_ci int ret = 0, prtad, devad; 30598c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 30608c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 30618c2ecf20Sopenharmony_ci struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci switch (cmd) { 30648c2ecf20Sopenharmony_ci case SIOCGMIIPHY: 30658c2ecf20Sopenharmony_ci if (pi->mdio_addr < 0) 30668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30678c2ecf20Sopenharmony_ci data->phy_id = pi->mdio_addr; 30688c2ecf20Sopenharmony_ci break; 30698c2ecf20Sopenharmony_ci case SIOCGMIIREG: 30708c2ecf20Sopenharmony_ci case SIOCSMIIREG: 30718c2ecf20Sopenharmony_ci if (mdio_phy_id_is_c45(data->phy_id)) { 30728c2ecf20Sopenharmony_ci prtad = mdio_phy_id_prtad(data->phy_id); 30738c2ecf20Sopenharmony_ci devad = mdio_phy_id_devad(data->phy_id); 30748c2ecf20Sopenharmony_ci } else if (data->phy_id < 32) { 30758c2ecf20Sopenharmony_ci prtad = data->phy_id; 30768c2ecf20Sopenharmony_ci devad = 0; 30778c2ecf20Sopenharmony_ci data->reg_num &= 0x1f; 30788c2ecf20Sopenharmony_ci } else 30798c2ecf20Sopenharmony_ci return -EINVAL; 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci mbox = pi->adapter->pf; 30828c2ecf20Sopenharmony_ci if (cmd == SIOCGMIIREG) 30838c2ecf20Sopenharmony_ci ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad, 30848c2ecf20Sopenharmony_ci data->reg_num, &data->val_out); 30858c2ecf20Sopenharmony_ci else 30868c2ecf20Sopenharmony_ci ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad, 30878c2ecf20Sopenharmony_ci data->reg_num, data->val_in); 30888c2ecf20Sopenharmony_ci break; 30898c2ecf20Sopenharmony_ci case SIOCGHWTSTAMP: 30908c2ecf20Sopenharmony_ci return copy_to_user(req->ifr_data, &pi->tstamp_config, 30918c2ecf20Sopenharmony_ci sizeof(pi->tstamp_config)) ? 30928c2ecf20Sopenharmony_ci -EFAULT : 0; 30938c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 30948c2ecf20Sopenharmony_ci if (copy_from_user(&pi->tstamp_config, req->ifr_data, 30958c2ecf20Sopenharmony_ci sizeof(pi->tstamp_config))) 30968c2ecf20Sopenharmony_ci return -EFAULT; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 30998c2ecf20Sopenharmony_ci switch (pi->tstamp_config.tx_type) { 31008c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 31018c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 31028c2ecf20Sopenharmony_ci break; 31038c2ecf20Sopenharmony_ci default: 31048c2ecf20Sopenharmony_ci return -ERANGE; 31058c2ecf20Sopenharmony_ci } 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci switch (pi->tstamp_config.rx_filter) { 31088c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 31098c2ecf20Sopenharmony_ci pi->rxtstamp = false; 31108c2ecf20Sopenharmony_ci break; 31118c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 31128c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 31138c2ecf20Sopenharmony_ci cxgb4_ptprx_timestamping(pi, pi->port_id, 31148c2ecf20Sopenharmony_ci PTP_TS_L4); 31158c2ecf20Sopenharmony_ci break; 31168c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 31178c2ecf20Sopenharmony_ci cxgb4_ptprx_timestamping(pi, pi->port_id, 31188c2ecf20Sopenharmony_ci PTP_TS_L2_L4); 31198c2ecf20Sopenharmony_ci break; 31208c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 31218c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 31228c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 31238c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 31248c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 31258c2ecf20Sopenharmony_ci pi->rxtstamp = true; 31268c2ecf20Sopenharmony_ci break; 31278c2ecf20Sopenharmony_ci default: 31288c2ecf20Sopenharmony_ci pi->tstamp_config.rx_filter = 31298c2ecf20Sopenharmony_ci HWTSTAMP_FILTER_NONE; 31308c2ecf20Sopenharmony_ci return -ERANGE; 31318c2ecf20Sopenharmony_ci } 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci if ((pi->tstamp_config.tx_type == HWTSTAMP_TX_OFF) && 31348c2ecf20Sopenharmony_ci (pi->tstamp_config.rx_filter == 31358c2ecf20Sopenharmony_ci HWTSTAMP_FILTER_NONE)) { 31368c2ecf20Sopenharmony_ci if (cxgb4_ptp_txtype(adapter, pi->port_id) >= 0) 31378c2ecf20Sopenharmony_ci pi->ptp_enable = false; 31388c2ecf20Sopenharmony_ci } 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci if (pi->tstamp_config.rx_filter != 31418c2ecf20Sopenharmony_ci HWTSTAMP_FILTER_NONE) { 31428c2ecf20Sopenharmony_ci if (cxgb4_ptp_redirect_rx_packet(adapter, 31438c2ecf20Sopenharmony_ci pi) >= 0) 31448c2ecf20Sopenharmony_ci pi->ptp_enable = true; 31458c2ecf20Sopenharmony_ci } 31468c2ecf20Sopenharmony_ci } else { 31478c2ecf20Sopenharmony_ci /* For T4 Adapters */ 31488c2ecf20Sopenharmony_ci switch (pi->tstamp_config.rx_filter) { 31498c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 31508c2ecf20Sopenharmony_ci pi->rxtstamp = false; 31518c2ecf20Sopenharmony_ci break; 31528c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 31538c2ecf20Sopenharmony_ci pi->rxtstamp = true; 31548c2ecf20Sopenharmony_ci break; 31558c2ecf20Sopenharmony_ci default: 31568c2ecf20Sopenharmony_ci pi->tstamp_config.rx_filter = 31578c2ecf20Sopenharmony_ci HWTSTAMP_FILTER_NONE; 31588c2ecf20Sopenharmony_ci return -ERANGE; 31598c2ecf20Sopenharmony_ci } 31608c2ecf20Sopenharmony_ci } 31618c2ecf20Sopenharmony_ci return copy_to_user(req->ifr_data, &pi->tstamp_config, 31628c2ecf20Sopenharmony_ci sizeof(pi->tstamp_config)) ? 31638c2ecf20Sopenharmony_ci -EFAULT : 0; 31648c2ecf20Sopenharmony_ci default: 31658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 31668c2ecf20Sopenharmony_ci } 31678c2ecf20Sopenharmony_ci return ret; 31688c2ecf20Sopenharmony_ci} 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_cistatic void cxgb_set_rxmode(struct net_device *dev) 31718c2ecf20Sopenharmony_ci{ 31728c2ecf20Sopenharmony_ci /* unfortunately we can't return errors to the stack */ 31738c2ecf20Sopenharmony_ci set_rxmode(dev, -1, false); 31748c2ecf20Sopenharmony_ci} 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_cistatic int cxgb_change_mtu(struct net_device *dev, int new_mtu) 31778c2ecf20Sopenharmony_ci{ 31788c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 31798c2ecf20Sopenharmony_ci int ret; 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci ret = t4_set_rxmode(pi->adapter, pi->adapter->mbox, pi->viid, 31828c2ecf20Sopenharmony_ci pi->viid_mirror, new_mtu, -1, -1, -1, -1, true); 31838c2ecf20Sopenharmony_ci if (!ret) 31848c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 31858c2ecf20Sopenharmony_ci return ret; 31868c2ecf20Sopenharmony_ci} 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 31898c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_open(struct net_device *dev) 31908c2ecf20Sopenharmony_ci{ 31918c2ecf20Sopenharmony_ci /* Turn carrier off since we don't have to transmit anything on this 31928c2ecf20Sopenharmony_ci * interface. 31938c2ecf20Sopenharmony_ci */ 31948c2ecf20Sopenharmony_ci netif_carrier_off(dev); 31958c2ecf20Sopenharmony_ci return 0; 31968c2ecf20Sopenharmony_ci} 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci/* Fill MAC address that will be assigned by the FW */ 31998c2ecf20Sopenharmony_cistatic void cxgb4_mgmt_fill_vf_station_mac_addr(struct adapter *adap) 32008c2ecf20Sopenharmony_ci{ 32018c2ecf20Sopenharmony_ci u8 hw_addr[ETH_ALEN], macaddr[ETH_ALEN]; 32028c2ecf20Sopenharmony_ci unsigned int i, vf, nvfs; 32038c2ecf20Sopenharmony_ci u16 a, b; 32048c2ecf20Sopenharmony_ci int err; 32058c2ecf20Sopenharmony_ci u8 *na; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci adap->params.pci.vpd_cap_addr = pci_find_capability(adap->pdev, 32088c2ecf20Sopenharmony_ci PCI_CAP_ID_VPD); 32098c2ecf20Sopenharmony_ci err = t4_get_raw_vpd_params(adap, &adap->params.vpd); 32108c2ecf20Sopenharmony_ci if (err) 32118c2ecf20Sopenharmony_ci return; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci na = adap->params.vpd.na; 32148c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 32158c2ecf20Sopenharmony_ci hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 + 32168c2ecf20Sopenharmony_ci hex2val(na[2 * i + 1])); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci a = (hw_addr[0] << 8) | hw_addr[1]; 32198c2ecf20Sopenharmony_ci b = (hw_addr[1] << 8) | hw_addr[2]; 32208c2ecf20Sopenharmony_ci a ^= b; 32218c2ecf20Sopenharmony_ci a |= 0x0200; /* locally assigned Ethernet MAC address */ 32228c2ecf20Sopenharmony_ci a &= ~0x0100; /* not a multicast Ethernet MAC address */ 32238c2ecf20Sopenharmony_ci macaddr[0] = a >> 8; 32248c2ecf20Sopenharmony_ci macaddr[1] = a & 0xff; 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci for (i = 2; i < 5; i++) 32278c2ecf20Sopenharmony_ci macaddr[i] = hw_addr[i + 1]; 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci for (vf = 0, nvfs = pci_sriov_get_totalvfs(adap->pdev); 32308c2ecf20Sopenharmony_ci vf < nvfs; vf++) { 32318c2ecf20Sopenharmony_ci macaddr[5] = adap->pf * nvfs + vf; 32328c2ecf20Sopenharmony_ci ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, macaddr); 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci} 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 32378c2ecf20Sopenharmony_ci{ 32388c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 32398c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 32408c2ecf20Sopenharmony_ci int ret; 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci /* verify MAC addr is valid */ 32438c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(mac)) { 32448c2ecf20Sopenharmony_ci dev_err(pi->adapter->pdev_dev, 32458c2ecf20Sopenharmony_ci "Invalid Ethernet address %pM for VF %d\n", 32468c2ecf20Sopenharmony_ci mac, vf); 32478c2ecf20Sopenharmony_ci return -EINVAL; 32488c2ecf20Sopenharmony_ci } 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci dev_info(pi->adapter->pdev_dev, 32518c2ecf20Sopenharmony_ci "Setting MAC %pM on VF %d\n", mac, vf); 32528c2ecf20Sopenharmony_ci ret = t4_set_vf_mac_acl(adap, vf + 1, 1, mac); 32538c2ecf20Sopenharmony_ci if (!ret) 32548c2ecf20Sopenharmony_ci ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, mac); 32558c2ecf20Sopenharmony_ci return ret; 32568c2ecf20Sopenharmony_ci} 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_get_vf_config(struct net_device *dev, 32598c2ecf20Sopenharmony_ci int vf, struct ifla_vf_info *ivi) 32608c2ecf20Sopenharmony_ci{ 32618c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 32628c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 32638c2ecf20Sopenharmony_ci struct vf_info *vfinfo; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci if (vf >= adap->num_vfs) 32668c2ecf20Sopenharmony_ci return -EINVAL; 32678c2ecf20Sopenharmony_ci vfinfo = &adap->vfinfo[vf]; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci ivi->vf = vf; 32708c2ecf20Sopenharmony_ci ivi->max_tx_rate = vfinfo->tx_rate; 32718c2ecf20Sopenharmony_ci ivi->min_tx_rate = 0; 32728c2ecf20Sopenharmony_ci ether_addr_copy(ivi->mac, vfinfo->vf_mac_addr); 32738c2ecf20Sopenharmony_ci ivi->vlan = vfinfo->vlan; 32748c2ecf20Sopenharmony_ci ivi->linkstate = vfinfo->link_state; 32758c2ecf20Sopenharmony_ci return 0; 32768c2ecf20Sopenharmony_ci} 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_get_phys_port_id(struct net_device *dev, 32798c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 32808c2ecf20Sopenharmony_ci{ 32818c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 32828c2ecf20Sopenharmony_ci unsigned int phy_port_id; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci phy_port_id = pi->adapter->adap_idx * 10 + pi->port_id; 32858c2ecf20Sopenharmony_ci ppid->id_len = sizeof(phy_port_id); 32868c2ecf20Sopenharmony_ci memcpy(ppid->id, &phy_port_id, ppid->id_len); 32878c2ecf20Sopenharmony_ci return 0; 32888c2ecf20Sopenharmony_ci} 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf, 32918c2ecf20Sopenharmony_ci int min_tx_rate, int max_tx_rate) 32928c2ecf20Sopenharmony_ci{ 32938c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 32948c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 32958c2ecf20Sopenharmony_ci unsigned int link_ok, speed, mtu; 32968c2ecf20Sopenharmony_ci u32 fw_pfvf, fw_class; 32978c2ecf20Sopenharmony_ci int class_id = vf; 32988c2ecf20Sopenharmony_ci int ret; 32998c2ecf20Sopenharmony_ci u16 pktsize; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci if (vf >= adap->num_vfs) 33028c2ecf20Sopenharmony_ci return -EINVAL; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci if (min_tx_rate) { 33058c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 33068c2ecf20Sopenharmony_ci "Min tx rate (%d) (> 0) for VF %d is Invalid.\n", 33078c2ecf20Sopenharmony_ci min_tx_rate, vf); 33088c2ecf20Sopenharmony_ci return -EINVAL; 33098c2ecf20Sopenharmony_ci } 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci if (max_tx_rate == 0) { 33128c2ecf20Sopenharmony_ci /* unbind VF to to any Traffic Class */ 33138c2ecf20Sopenharmony_ci fw_pfvf = 33148c2ecf20Sopenharmony_ci (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 33158c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); 33168c2ecf20Sopenharmony_ci fw_class = 0xffffffff; 33178c2ecf20Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, 33188c2ecf20Sopenharmony_ci &fw_pfvf, &fw_class); 33198c2ecf20Sopenharmony_ci if (ret) { 33208c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 33218c2ecf20Sopenharmony_ci "Err %d in unbinding PF %d VF %d from TX Rate Limiting\n", 33228c2ecf20Sopenharmony_ci ret, adap->pf, vf); 33238c2ecf20Sopenharmony_ci return -EINVAL; 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 33268c2ecf20Sopenharmony_ci "PF %d VF %d is unbound from TX Rate Limiting\n", 33278c2ecf20Sopenharmony_ci adap->pf, vf); 33288c2ecf20Sopenharmony_ci adap->vfinfo[vf].tx_rate = 0; 33298c2ecf20Sopenharmony_ci return 0; 33308c2ecf20Sopenharmony_ci } 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci ret = t4_get_link_params(pi, &link_ok, &speed, &mtu); 33338c2ecf20Sopenharmony_ci if (ret != FW_SUCCESS) { 33348c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 33358c2ecf20Sopenharmony_ci "Failed to get link information for VF %d\n", vf); 33368c2ecf20Sopenharmony_ci return -EINVAL; 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci if (!link_ok) { 33408c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Link down for VF %d\n", vf); 33418c2ecf20Sopenharmony_ci return -EINVAL; 33428c2ecf20Sopenharmony_ci } 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci if (max_tx_rate > speed) { 33458c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 33468c2ecf20Sopenharmony_ci "Max tx rate %d for VF %d can't be > link-speed %u", 33478c2ecf20Sopenharmony_ci max_tx_rate, vf, speed); 33488c2ecf20Sopenharmony_ci return -EINVAL; 33498c2ecf20Sopenharmony_ci } 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci pktsize = mtu; 33528c2ecf20Sopenharmony_ci /* subtract ethhdr size and 4 bytes crc since, f/w appends it */ 33538c2ecf20Sopenharmony_ci pktsize = pktsize - sizeof(struct ethhdr) - 4; 33548c2ecf20Sopenharmony_ci /* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */ 33558c2ecf20Sopenharmony_ci pktsize = pktsize - sizeof(struct iphdr) - sizeof(struct tcphdr); 33568c2ecf20Sopenharmony_ci /* configure Traffic Class for rate-limiting */ 33578c2ecf20Sopenharmony_ci ret = t4_sched_params(adap, SCHED_CLASS_TYPE_PACKET, 33588c2ecf20Sopenharmony_ci SCHED_CLASS_LEVEL_CL_RL, 33598c2ecf20Sopenharmony_ci SCHED_CLASS_MODE_CLASS, 33608c2ecf20Sopenharmony_ci SCHED_CLASS_RATEUNIT_BITS, 33618c2ecf20Sopenharmony_ci SCHED_CLASS_RATEMODE_ABS, 33628c2ecf20Sopenharmony_ci pi->tx_chan, class_id, 0, 33638c2ecf20Sopenharmony_ci max_tx_rate * 1000, 0, pktsize, 0); 33648c2ecf20Sopenharmony_ci if (ret) { 33658c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n", 33668c2ecf20Sopenharmony_ci ret); 33678c2ecf20Sopenharmony_ci return -EINVAL; 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 33708c2ecf20Sopenharmony_ci "Class %d with MSS %u configured with rate %u\n", 33718c2ecf20Sopenharmony_ci class_id, pktsize, max_tx_rate); 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci /* bind VF to configured Traffic Class */ 33748c2ecf20Sopenharmony_ci fw_pfvf = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 33758c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); 33768c2ecf20Sopenharmony_ci fw_class = class_id; 33778c2ecf20Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, &fw_pfvf, 33788c2ecf20Sopenharmony_ci &fw_class); 33798c2ecf20Sopenharmony_ci if (ret) { 33808c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 33818c2ecf20Sopenharmony_ci "Err %d in binding PF %d VF %d to Traffic Class %d\n", 33828c2ecf20Sopenharmony_ci ret, adap->pf, vf, class_id); 33838c2ecf20Sopenharmony_ci return -EINVAL; 33848c2ecf20Sopenharmony_ci } 33858c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n", 33868c2ecf20Sopenharmony_ci adap->pf, vf, class_id); 33878c2ecf20Sopenharmony_ci adap->vfinfo[vf].tx_rate = max_tx_rate; 33888c2ecf20Sopenharmony_ci return 0; 33898c2ecf20Sopenharmony_ci} 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_set_vf_vlan(struct net_device *dev, int vf, 33928c2ecf20Sopenharmony_ci u16 vlan, u8 qos, __be16 vlan_proto) 33938c2ecf20Sopenharmony_ci{ 33948c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 33958c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 33968c2ecf20Sopenharmony_ci int ret; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci if (vf >= adap->num_vfs || vlan > 4095 || qos > 7) 33998c2ecf20Sopenharmony_ci return -EINVAL; 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q) || qos != 0) 34028c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci ret = t4_set_vlan_acl(adap, adap->mbox, vf + 1, vlan); 34058c2ecf20Sopenharmony_ci if (!ret) { 34068c2ecf20Sopenharmony_ci adap->vfinfo[vf].vlan = vlan; 34078c2ecf20Sopenharmony_ci return 0; 34088c2ecf20Sopenharmony_ci } 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "Err %d %s VLAN ACL for PF/VF %d/%d\n", 34118c2ecf20Sopenharmony_ci ret, (vlan ? "setting" : "clearing"), adap->pf, vf); 34128c2ecf20Sopenharmony_ci return ret; 34138c2ecf20Sopenharmony_ci} 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_cistatic int cxgb4_mgmt_set_vf_link_state(struct net_device *dev, int vf, 34168c2ecf20Sopenharmony_ci int link) 34178c2ecf20Sopenharmony_ci{ 34188c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 34198c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 34208c2ecf20Sopenharmony_ci u32 param, val; 34218c2ecf20Sopenharmony_ci int ret = 0; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if (vf >= adap->num_vfs) 34248c2ecf20Sopenharmony_ci return -EINVAL; 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci switch (link) { 34278c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 34288c2ecf20Sopenharmony_ci val = FW_VF_LINK_STATE_AUTO; 34298c2ecf20Sopenharmony_ci break; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 34328c2ecf20Sopenharmony_ci val = FW_VF_LINK_STATE_ENABLE; 34338c2ecf20Sopenharmony_ci break; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 34368c2ecf20Sopenharmony_ci val = FW_VF_LINK_STATE_DISABLE; 34378c2ecf20Sopenharmony_ci break; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci default: 34408c2ecf20Sopenharmony_ci return -EINVAL; 34418c2ecf20Sopenharmony_ci } 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 34448c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_LINK_STATE)); 34458c2ecf20Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, 34468c2ecf20Sopenharmony_ci ¶m, &val); 34478c2ecf20Sopenharmony_ci if (ret) { 34488c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 34498c2ecf20Sopenharmony_ci "Error %d in setting PF %d VF %d link state\n", 34508c2ecf20Sopenharmony_ci ret, adap->pf, vf); 34518c2ecf20Sopenharmony_ci return -EINVAL; 34528c2ecf20Sopenharmony_ci } 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci adap->vfinfo[vf].link_state = link; 34558c2ecf20Sopenharmony_ci return ret; 34568c2ecf20Sopenharmony_ci} 34578c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI_IOV */ 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_cistatic int cxgb_set_mac_addr(struct net_device *dev, void *p) 34608c2ecf20Sopenharmony_ci{ 34618c2ecf20Sopenharmony_ci int ret; 34628c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 34638c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 34668c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt, 34698c2ecf20Sopenharmony_ci addr->sa_data, true, &pi->smt_idx); 34708c2ecf20Sopenharmony_ci if (ret < 0) 34718c2ecf20Sopenharmony_ci return ret; 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 34748c2ecf20Sopenharmony_ci return 0; 34758c2ecf20Sopenharmony_ci} 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 34788c2ecf20Sopenharmony_cistatic void cxgb_netpoll(struct net_device *dev) 34798c2ecf20Sopenharmony_ci{ 34808c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 34818c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 34848c2ecf20Sopenharmony_ci int i; 34858c2ecf20Sopenharmony_ci struct sge_eth_rxq *rx = &adap->sge.ethrxq[pi->first_qset]; 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci for (i = pi->nqsets; i; i--, rx++) 34888c2ecf20Sopenharmony_ci t4_sge_intr_msix(0, &rx->rspq); 34898c2ecf20Sopenharmony_ci } else 34908c2ecf20Sopenharmony_ci t4_intr_handler(adap)(0, adap); 34918c2ecf20Sopenharmony_ci} 34928c2ecf20Sopenharmony_ci#endif 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_cistatic int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate) 34958c2ecf20Sopenharmony_ci{ 34968c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 34978c2ecf20Sopenharmony_ci struct adapter *adap = pi->adapter; 34988c2ecf20Sopenharmony_ci struct ch_sched_queue qe = { 0 }; 34998c2ecf20Sopenharmony_ci struct ch_sched_params p = { 0 }; 35008c2ecf20Sopenharmony_ci struct sched_class *e; 35018c2ecf20Sopenharmony_ci u32 req_rate; 35028c2ecf20Sopenharmony_ci int err = 0; 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci if (!can_sched(dev)) 35058c2ecf20Sopenharmony_ci return -ENOTSUPP; 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci if (index < 0 || index > pi->nqsets - 1) 35088c2ecf20Sopenharmony_ci return -EINVAL; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { 35118c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 35128c2ecf20Sopenharmony_ci "Failed to rate limit on queue %d. Link Down?\n", 35138c2ecf20Sopenharmony_ci index); 35148c2ecf20Sopenharmony_ci return -EINVAL; 35158c2ecf20Sopenharmony_ci } 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci qe.queue = index; 35188c2ecf20Sopenharmony_ci e = cxgb4_sched_queue_lookup(dev, &qe); 35198c2ecf20Sopenharmony_ci if (e && e->info.u.params.level != SCHED_CLASS_LEVEL_CL_RL) { 35208c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 35218c2ecf20Sopenharmony_ci "Queue %u already bound to class %u of type: %u\n", 35228c2ecf20Sopenharmony_ci index, e->idx, e->info.u.params.level); 35238c2ecf20Sopenharmony_ci return -EBUSY; 35248c2ecf20Sopenharmony_ci } 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci /* Convert from Mbps to Kbps */ 35278c2ecf20Sopenharmony_ci req_rate = rate * 1000; 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci /* Max rate is 100 Gbps */ 35308c2ecf20Sopenharmony_ci if (req_rate > SCHED_MAX_RATE_KBPS) { 35318c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 35328c2ecf20Sopenharmony_ci "Invalid rate %u Mbps, Max rate is %u Mbps\n", 35338c2ecf20Sopenharmony_ci rate, SCHED_MAX_RATE_KBPS / 1000); 35348c2ecf20Sopenharmony_ci return -ERANGE; 35358c2ecf20Sopenharmony_ci } 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci /* First unbind the queue from any existing class */ 35388c2ecf20Sopenharmony_ci memset(&qe, 0, sizeof(qe)); 35398c2ecf20Sopenharmony_ci qe.queue = index; 35408c2ecf20Sopenharmony_ci qe.class = SCHED_CLS_NONE; 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci err = cxgb4_sched_class_unbind(dev, (void *)(&qe), SCHED_QUEUE); 35438c2ecf20Sopenharmony_ci if (err) { 35448c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 35458c2ecf20Sopenharmony_ci "Unbinding Queue %d on port %d fail. Err: %d\n", 35468c2ecf20Sopenharmony_ci index, pi->port_id, err); 35478c2ecf20Sopenharmony_ci return err; 35488c2ecf20Sopenharmony_ci } 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci /* Queue already unbound */ 35518c2ecf20Sopenharmony_ci if (!req_rate) 35528c2ecf20Sopenharmony_ci return 0; 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci /* Fetch any available unused or matching scheduling class */ 35558c2ecf20Sopenharmony_ci p.type = SCHED_CLASS_TYPE_PACKET; 35568c2ecf20Sopenharmony_ci p.u.params.level = SCHED_CLASS_LEVEL_CL_RL; 35578c2ecf20Sopenharmony_ci p.u.params.mode = SCHED_CLASS_MODE_CLASS; 35588c2ecf20Sopenharmony_ci p.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS; 35598c2ecf20Sopenharmony_ci p.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS; 35608c2ecf20Sopenharmony_ci p.u.params.channel = pi->tx_chan; 35618c2ecf20Sopenharmony_ci p.u.params.class = SCHED_CLS_NONE; 35628c2ecf20Sopenharmony_ci p.u.params.minrate = 0; 35638c2ecf20Sopenharmony_ci p.u.params.maxrate = req_rate; 35648c2ecf20Sopenharmony_ci p.u.params.weight = 0; 35658c2ecf20Sopenharmony_ci p.u.params.pktsize = dev->mtu; 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_ci e = cxgb4_sched_class_alloc(dev, &p); 35688c2ecf20Sopenharmony_ci if (!e) 35698c2ecf20Sopenharmony_ci return -ENOMEM; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci /* Bind the queue to a scheduling class */ 35728c2ecf20Sopenharmony_ci memset(&qe, 0, sizeof(qe)); 35738c2ecf20Sopenharmony_ci qe.queue = index; 35748c2ecf20Sopenharmony_ci qe.class = e->idx; 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci err = cxgb4_sched_class_bind(dev, (void *)(&qe), SCHED_QUEUE); 35778c2ecf20Sopenharmony_ci if (err) 35788c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 35798c2ecf20Sopenharmony_ci "Queue rate limiting failed. Err: %d\n", err); 35808c2ecf20Sopenharmony_ci return err; 35818c2ecf20Sopenharmony_ci} 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_flower(struct net_device *dev, 35848c2ecf20Sopenharmony_ci struct flow_cls_offload *cls_flower) 35858c2ecf20Sopenharmony_ci{ 35868c2ecf20Sopenharmony_ci switch (cls_flower->command) { 35878c2ecf20Sopenharmony_ci case FLOW_CLS_REPLACE: 35888c2ecf20Sopenharmony_ci return cxgb4_tc_flower_replace(dev, cls_flower); 35898c2ecf20Sopenharmony_ci case FLOW_CLS_DESTROY: 35908c2ecf20Sopenharmony_ci return cxgb4_tc_flower_destroy(dev, cls_flower); 35918c2ecf20Sopenharmony_ci case FLOW_CLS_STATS: 35928c2ecf20Sopenharmony_ci return cxgb4_tc_flower_stats(dev, cls_flower); 35938c2ecf20Sopenharmony_ci default: 35948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 35958c2ecf20Sopenharmony_ci } 35968c2ecf20Sopenharmony_ci} 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_cls_u32(struct net_device *dev, 35998c2ecf20Sopenharmony_ci struct tc_cls_u32_offload *cls_u32) 36008c2ecf20Sopenharmony_ci{ 36018c2ecf20Sopenharmony_ci switch (cls_u32->command) { 36028c2ecf20Sopenharmony_ci case TC_CLSU32_NEW_KNODE: 36038c2ecf20Sopenharmony_ci case TC_CLSU32_REPLACE_KNODE: 36048c2ecf20Sopenharmony_ci return cxgb4_config_knode(dev, cls_u32); 36058c2ecf20Sopenharmony_ci case TC_CLSU32_DELETE_KNODE: 36068c2ecf20Sopenharmony_ci return cxgb4_delete_knode(dev, cls_u32); 36078c2ecf20Sopenharmony_ci default: 36088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36098c2ecf20Sopenharmony_ci } 36108c2ecf20Sopenharmony_ci} 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_matchall(struct net_device *dev, 36138c2ecf20Sopenharmony_ci struct tc_cls_matchall_offload *cls_matchall, 36148c2ecf20Sopenharmony_ci bool ingress) 36158c2ecf20Sopenharmony_ci{ 36168c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci if (!adap->tc_matchall) 36198c2ecf20Sopenharmony_ci return -ENOMEM; 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci switch (cls_matchall->command) { 36228c2ecf20Sopenharmony_ci case TC_CLSMATCHALL_REPLACE: 36238c2ecf20Sopenharmony_ci return cxgb4_tc_matchall_replace(dev, cls_matchall, ingress); 36248c2ecf20Sopenharmony_ci case TC_CLSMATCHALL_DESTROY: 36258c2ecf20Sopenharmony_ci return cxgb4_tc_matchall_destroy(dev, cls_matchall, ingress); 36268c2ecf20Sopenharmony_ci case TC_CLSMATCHALL_STATS: 36278c2ecf20Sopenharmony_ci if (ingress) 36288c2ecf20Sopenharmony_ci return cxgb4_tc_matchall_stats(dev, cls_matchall); 36298c2ecf20Sopenharmony_ci break; 36308c2ecf20Sopenharmony_ci default: 36318c2ecf20Sopenharmony_ci break; 36328c2ecf20Sopenharmony_ci } 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36358c2ecf20Sopenharmony_ci} 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_block_ingress_cb(enum tc_setup_type type, 36388c2ecf20Sopenharmony_ci void *type_data, void *cb_priv) 36398c2ecf20Sopenharmony_ci{ 36408c2ecf20Sopenharmony_ci struct net_device *dev = cb_priv; 36418c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 36428c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { 36458c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 36468c2ecf20Sopenharmony_ci "Failed to setup tc on port %d. Link Down?\n", 36478c2ecf20Sopenharmony_ci pi->port_id); 36488c2ecf20Sopenharmony_ci return -EINVAL; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(dev, type_data)) 36528c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci switch (type) { 36558c2ecf20Sopenharmony_ci case TC_SETUP_CLSU32: 36568c2ecf20Sopenharmony_ci return cxgb_setup_tc_cls_u32(dev, type_data); 36578c2ecf20Sopenharmony_ci case TC_SETUP_CLSFLOWER: 36588c2ecf20Sopenharmony_ci return cxgb_setup_tc_flower(dev, type_data); 36598c2ecf20Sopenharmony_ci case TC_SETUP_CLSMATCHALL: 36608c2ecf20Sopenharmony_ci return cxgb_setup_tc_matchall(dev, type_data, true); 36618c2ecf20Sopenharmony_ci default: 36628c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36638c2ecf20Sopenharmony_ci } 36648c2ecf20Sopenharmony_ci} 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_block_egress_cb(enum tc_setup_type type, 36678c2ecf20Sopenharmony_ci void *type_data, void *cb_priv) 36688c2ecf20Sopenharmony_ci{ 36698c2ecf20Sopenharmony_ci struct net_device *dev = cb_priv; 36708c2ecf20Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 36718c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { 36748c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 36758c2ecf20Sopenharmony_ci "Failed to setup tc on port %d. Link Down?\n", 36768c2ecf20Sopenharmony_ci pi->port_id); 36778c2ecf20Sopenharmony_ci return -EINVAL; 36788c2ecf20Sopenharmony_ci } 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(dev, type_data)) 36818c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci switch (type) { 36848c2ecf20Sopenharmony_ci case TC_SETUP_CLSMATCHALL: 36858c2ecf20Sopenharmony_ci return cxgb_setup_tc_matchall(dev, type_data, false); 36868c2ecf20Sopenharmony_ci default: 36878c2ecf20Sopenharmony_ci break; 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 36918c2ecf20Sopenharmony_ci} 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_mqprio(struct net_device *dev, 36948c2ecf20Sopenharmony_ci struct tc_mqprio_qopt_offload *mqprio) 36958c2ecf20Sopenharmony_ci{ 36968c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci if (!is_ethofld(adap) || !adap->tc_mqprio) 36998c2ecf20Sopenharmony_ci return -ENOMEM; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci return cxgb4_setup_tc_mqprio(dev, mqprio); 37028c2ecf20Sopenharmony_ci} 37038c2ecf20Sopenharmony_ci 37048c2ecf20Sopenharmony_cistatic LIST_HEAD(cxgb_block_cb_list); 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_cistatic int cxgb_setup_tc_block(struct net_device *dev, 37078c2ecf20Sopenharmony_ci struct flow_block_offload *f) 37088c2ecf20Sopenharmony_ci{ 37098c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 37108c2ecf20Sopenharmony_ci flow_setup_cb_t *cb; 37118c2ecf20Sopenharmony_ci bool ingress_only; 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci pi->tc_block_shared = f->block_shared; 37148c2ecf20Sopenharmony_ci if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) { 37158c2ecf20Sopenharmony_ci cb = cxgb_setup_tc_block_egress_cb; 37168c2ecf20Sopenharmony_ci ingress_only = false; 37178c2ecf20Sopenharmony_ci } else { 37188c2ecf20Sopenharmony_ci cb = cxgb_setup_tc_block_ingress_cb; 37198c2ecf20Sopenharmony_ci ingress_only = true; 37208c2ecf20Sopenharmony_ci } 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci return flow_block_cb_setup_simple(f, &cxgb_block_cb_list, 37238c2ecf20Sopenharmony_ci cb, pi, dev, ingress_only); 37248c2ecf20Sopenharmony_ci} 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_cistatic int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type, 37278c2ecf20Sopenharmony_ci void *type_data) 37288c2ecf20Sopenharmony_ci{ 37298c2ecf20Sopenharmony_ci switch (type) { 37308c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_MQPRIO: 37318c2ecf20Sopenharmony_ci return cxgb_setup_tc_mqprio(dev, type_data); 37328c2ecf20Sopenharmony_ci case TC_SETUP_BLOCK: 37338c2ecf20Sopenharmony_ci return cxgb_setup_tc_block(dev, type_data); 37348c2ecf20Sopenharmony_ci default: 37358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci} 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_cistatic int cxgb_udp_tunnel_unset_port(struct net_device *netdev, 37408c2ecf20Sopenharmony_ci unsigned int table, unsigned int entry, 37418c2ecf20Sopenharmony_ci struct udp_tunnel_info *ti) 37428c2ecf20Sopenharmony_ci{ 37438c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 37448c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 37458c2ecf20Sopenharmony_ci u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 }; 37468c2ecf20Sopenharmony_ci int ret = 0, i; 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci switch (ti->type) { 37498c2ecf20Sopenharmony_ci case UDP_TUNNEL_TYPE_VXLAN: 37508c2ecf20Sopenharmony_ci adapter->vxlan_port = 0; 37518c2ecf20Sopenharmony_ci t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A, 0); 37528c2ecf20Sopenharmony_ci break; 37538c2ecf20Sopenharmony_ci case UDP_TUNNEL_TYPE_GENEVE: 37548c2ecf20Sopenharmony_ci adapter->geneve_port = 0; 37558c2ecf20Sopenharmony_ci t4_write_reg(adapter, MPS_RX_GENEVE_TYPE_A, 0); 37568c2ecf20Sopenharmony_ci break; 37578c2ecf20Sopenharmony_ci default: 37588c2ecf20Sopenharmony_ci return -EINVAL; 37598c2ecf20Sopenharmony_ci } 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci /* Matchall mac entries can be deleted only after all tunnel ports 37628c2ecf20Sopenharmony_ci * are brought down or removed. 37638c2ecf20Sopenharmony_ci */ 37648c2ecf20Sopenharmony_ci if (!adapter->rawf_cnt) 37658c2ecf20Sopenharmony_ci return 0; 37668c2ecf20Sopenharmony_ci for_each_port(adapter, i) { 37678c2ecf20Sopenharmony_ci pi = adap2pinfo(adapter, i); 37688c2ecf20Sopenharmony_ci ret = t4_free_raw_mac_filt(adapter, pi->viid, 37698c2ecf20Sopenharmony_ci match_all_mac, match_all_mac, 37708c2ecf20Sopenharmony_ci adapter->rawf_start + pi->port_id, 37718c2ecf20Sopenharmony_ci 1, pi->port_id, false); 37728c2ecf20Sopenharmony_ci if (ret < 0) { 37738c2ecf20Sopenharmony_ci netdev_info(netdev, "Failed to free mac filter entry, for port %d\n", 37748c2ecf20Sopenharmony_ci i); 37758c2ecf20Sopenharmony_ci return ret; 37768c2ecf20Sopenharmony_ci } 37778c2ecf20Sopenharmony_ci } 37788c2ecf20Sopenharmony_ci 37798c2ecf20Sopenharmony_ci return 0; 37808c2ecf20Sopenharmony_ci} 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_cistatic int cxgb_udp_tunnel_set_port(struct net_device *netdev, 37838c2ecf20Sopenharmony_ci unsigned int table, unsigned int entry, 37848c2ecf20Sopenharmony_ci struct udp_tunnel_info *ti) 37858c2ecf20Sopenharmony_ci{ 37868c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 37878c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 37888c2ecf20Sopenharmony_ci u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 }; 37898c2ecf20Sopenharmony_ci int i, ret; 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci switch (ti->type) { 37928c2ecf20Sopenharmony_ci case UDP_TUNNEL_TYPE_VXLAN: 37938c2ecf20Sopenharmony_ci adapter->vxlan_port = ti->port; 37948c2ecf20Sopenharmony_ci t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A, 37958c2ecf20Sopenharmony_ci VXLAN_V(be16_to_cpu(ti->port)) | VXLAN_EN_F); 37968c2ecf20Sopenharmony_ci break; 37978c2ecf20Sopenharmony_ci case UDP_TUNNEL_TYPE_GENEVE: 37988c2ecf20Sopenharmony_ci adapter->geneve_port = ti->port; 37998c2ecf20Sopenharmony_ci t4_write_reg(adapter, MPS_RX_GENEVE_TYPE_A, 38008c2ecf20Sopenharmony_ci GENEVE_V(be16_to_cpu(ti->port)) | GENEVE_EN_F); 38018c2ecf20Sopenharmony_ci break; 38028c2ecf20Sopenharmony_ci default: 38038c2ecf20Sopenharmony_ci return -EINVAL; 38048c2ecf20Sopenharmony_ci } 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci /* Create a 'match all' mac filter entry for inner mac, 38078c2ecf20Sopenharmony_ci * if raw mac interface is supported. Once the linux kernel provides 38088c2ecf20Sopenharmony_ci * driver entry points for adding/deleting the inner mac addresses, 38098c2ecf20Sopenharmony_ci * we will remove this 'match all' entry and fallback to adding 38108c2ecf20Sopenharmony_ci * exact match filters. 38118c2ecf20Sopenharmony_ci */ 38128c2ecf20Sopenharmony_ci for_each_port(adapter, i) { 38138c2ecf20Sopenharmony_ci pi = adap2pinfo(adapter, i); 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci ret = t4_alloc_raw_mac_filt(adapter, pi->viid, 38168c2ecf20Sopenharmony_ci match_all_mac, 38178c2ecf20Sopenharmony_ci match_all_mac, 38188c2ecf20Sopenharmony_ci adapter->rawf_start + pi->port_id, 38198c2ecf20Sopenharmony_ci 1, pi->port_id, false); 38208c2ecf20Sopenharmony_ci if (ret < 0) { 38218c2ecf20Sopenharmony_ci netdev_info(netdev, "Failed to allocate a mac filter entry, not adding port %d\n", 38228c2ecf20Sopenharmony_ci be16_to_cpu(ti->port)); 38238c2ecf20Sopenharmony_ci return ret; 38248c2ecf20Sopenharmony_ci } 38258c2ecf20Sopenharmony_ci } 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci return 0; 38288c2ecf20Sopenharmony_ci} 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_cistatic const struct udp_tunnel_nic_info cxgb_udp_tunnels = { 38318c2ecf20Sopenharmony_ci .set_port = cxgb_udp_tunnel_set_port, 38328c2ecf20Sopenharmony_ci .unset_port = cxgb_udp_tunnel_unset_port, 38338c2ecf20Sopenharmony_ci .tables = { 38348c2ecf20Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 38358c2ecf20Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, }, 38368c2ecf20Sopenharmony_ci }, 38378c2ecf20Sopenharmony_ci}; 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_cistatic netdev_features_t cxgb_features_check(struct sk_buff *skb, 38408c2ecf20Sopenharmony_ci struct net_device *dev, 38418c2ecf20Sopenharmony_ci netdev_features_t features) 38428c2ecf20Sopenharmony_ci{ 38438c2ecf20Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 38448c2ecf20Sopenharmony_ci struct adapter *adapter = pi->adapter; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6) 38478c2ecf20Sopenharmony_ci return features; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci /* Check if hw supports offload for this packet */ 38508c2ecf20Sopenharmony_ci if (!skb->encapsulation || cxgb_encap_offload_supported(skb)) 38518c2ecf20Sopenharmony_ci return features; 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci /* Offload is not supported for this encapsulated packet */ 38548c2ecf20Sopenharmony_ci return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 38558c2ecf20Sopenharmony_ci} 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_cistatic netdev_features_t cxgb_fix_features(struct net_device *dev, 38588c2ecf20Sopenharmony_ci netdev_features_t features) 38598c2ecf20Sopenharmony_ci{ 38608c2ecf20Sopenharmony_ci /* Disable GRO, if RX_CSUM is disabled */ 38618c2ecf20Sopenharmony_ci if (!(features & NETIF_F_RXCSUM)) 38628c2ecf20Sopenharmony_ci features &= ~NETIF_F_GRO; 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci return features; 38658c2ecf20Sopenharmony_ci} 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_cistatic const struct net_device_ops cxgb4_netdev_ops = { 38688c2ecf20Sopenharmony_ci .ndo_open = cxgb_open, 38698c2ecf20Sopenharmony_ci .ndo_stop = cxgb_close, 38708c2ecf20Sopenharmony_ci .ndo_start_xmit = t4_start_xmit, 38718c2ecf20Sopenharmony_ci .ndo_select_queue = cxgb_select_queue, 38728c2ecf20Sopenharmony_ci .ndo_get_stats64 = cxgb_get_stats, 38738c2ecf20Sopenharmony_ci .ndo_set_rx_mode = cxgb_set_rxmode, 38748c2ecf20Sopenharmony_ci .ndo_set_mac_address = cxgb_set_mac_addr, 38758c2ecf20Sopenharmony_ci .ndo_set_features = cxgb_set_features, 38768c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 38778c2ecf20Sopenharmony_ci .ndo_do_ioctl = cxgb_ioctl, 38788c2ecf20Sopenharmony_ci .ndo_change_mtu = cxgb_change_mtu, 38798c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 38808c2ecf20Sopenharmony_ci .ndo_poll_controller = cxgb_netpoll, 38818c2ecf20Sopenharmony_ci#endif 38828c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 38838c2ecf20Sopenharmony_ci .ndo_fcoe_enable = cxgb_fcoe_enable, 38848c2ecf20Sopenharmony_ci .ndo_fcoe_disable = cxgb_fcoe_disable, 38858c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 38868c2ecf20Sopenharmony_ci .ndo_set_tx_maxrate = cxgb_set_tx_maxrate, 38878c2ecf20Sopenharmony_ci .ndo_setup_tc = cxgb_setup_tc, 38888c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 38898c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 38908c2ecf20Sopenharmony_ci .ndo_features_check = cxgb_features_check, 38918c2ecf20Sopenharmony_ci .ndo_fix_features = cxgb_fix_features, 38928c2ecf20Sopenharmony_ci}; 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 38958c2ecf20Sopenharmony_cistatic const struct net_device_ops cxgb4_mgmt_netdev_ops = { 38968c2ecf20Sopenharmony_ci .ndo_open = cxgb4_mgmt_open, 38978c2ecf20Sopenharmony_ci .ndo_set_vf_mac = cxgb4_mgmt_set_vf_mac, 38988c2ecf20Sopenharmony_ci .ndo_get_vf_config = cxgb4_mgmt_get_vf_config, 38998c2ecf20Sopenharmony_ci .ndo_set_vf_rate = cxgb4_mgmt_set_vf_rate, 39008c2ecf20Sopenharmony_ci .ndo_get_phys_port_id = cxgb4_mgmt_get_phys_port_id, 39018c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = cxgb4_mgmt_set_vf_vlan, 39028c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = cxgb4_mgmt_set_vf_link_state, 39038c2ecf20Sopenharmony_ci}; 39048c2ecf20Sopenharmony_ci#endif 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_cistatic void cxgb4_mgmt_get_drvinfo(struct net_device *dev, 39078c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 39088c2ecf20Sopenharmony_ci{ 39098c2ecf20Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); 39128c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(adapter->pdev), 39138c2ecf20Sopenharmony_ci sizeof(info->bus_info)); 39148c2ecf20Sopenharmony_ci} 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_cistatic const struct ethtool_ops cxgb4_mgmt_ethtool_ops = { 39178c2ecf20Sopenharmony_ci .get_drvinfo = cxgb4_mgmt_get_drvinfo, 39188c2ecf20Sopenharmony_ci}; 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_cistatic void notify_fatal_err(struct work_struct *work) 39218c2ecf20Sopenharmony_ci{ 39228c2ecf20Sopenharmony_ci struct adapter *adap; 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci adap = container_of(work, struct adapter, fatal_err_notify_task); 39258c2ecf20Sopenharmony_ci notify_ulds(adap, CXGB4_STATE_FATAL_ERROR); 39268c2ecf20Sopenharmony_ci} 39278c2ecf20Sopenharmony_ci 39288c2ecf20Sopenharmony_civoid t4_fatal_err(struct adapter *adap) 39298c2ecf20Sopenharmony_ci{ 39308c2ecf20Sopenharmony_ci int port; 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci if (pci_channel_offline(adap->pdev)) 39338c2ecf20Sopenharmony_ci return; 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci /* Disable the SGE since ULDs are going to free resources that 39368c2ecf20Sopenharmony_ci * could be exposed to the adapter. RDMA MWs for example... 39378c2ecf20Sopenharmony_ci */ 39388c2ecf20Sopenharmony_ci t4_shutdown_adapter(adap); 39398c2ecf20Sopenharmony_ci for_each_port(adap, port) { 39408c2ecf20Sopenharmony_ci struct net_device *dev = adap->port[port]; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci /* If we get here in very early initialization the network 39438c2ecf20Sopenharmony_ci * devices may not have been set up yet. 39448c2ecf20Sopenharmony_ci */ 39458c2ecf20Sopenharmony_ci if (!dev) 39468c2ecf20Sopenharmony_ci continue; 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 39498c2ecf20Sopenharmony_ci netif_carrier_off(dev); 39508c2ecf20Sopenharmony_ci } 39518c2ecf20Sopenharmony_ci dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); 39528c2ecf20Sopenharmony_ci queue_work(adap->workq, &adap->fatal_err_notify_task); 39538c2ecf20Sopenharmony_ci} 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_cistatic void setup_memwin(struct adapter *adap) 39568c2ecf20Sopenharmony_ci{ 39578c2ecf20Sopenharmony_ci u32 nic_win_base = t4_get_util_window(adap); 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci t4_setup_memwin(adap, nic_win_base, MEMWIN_NIC); 39608c2ecf20Sopenharmony_ci} 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_cistatic void setup_memwin_rdma(struct adapter *adap) 39638c2ecf20Sopenharmony_ci{ 39648c2ecf20Sopenharmony_ci if (adap->vres.ocq.size) { 39658c2ecf20Sopenharmony_ci u32 start; 39668c2ecf20Sopenharmony_ci unsigned int sz_kb; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci start = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_2); 39698c2ecf20Sopenharmony_ci start &= PCI_BASE_ADDRESS_MEM_MASK; 39708c2ecf20Sopenharmony_ci start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres); 39718c2ecf20Sopenharmony_ci sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; 39728c2ecf20Sopenharmony_ci t4_write_reg(adap, 39738c2ecf20Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 3), 39748c2ecf20Sopenharmony_ci start | BIR_V(1) | WINDOW_V(ilog2(sz_kb))); 39758c2ecf20Sopenharmony_ci t4_write_reg(adap, 39768c2ecf20Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3), 39778c2ecf20Sopenharmony_ci adap->vres.ocq.start); 39788c2ecf20Sopenharmony_ci t4_read_reg(adap, 39798c2ecf20Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3)); 39808c2ecf20Sopenharmony_ci } 39818c2ecf20Sopenharmony_ci} 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ci/* HMA Definitions */ 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci/* The maximum number of address that can be send in a single FW cmd */ 39868c2ecf20Sopenharmony_ci#define HMA_MAX_ADDR_IN_CMD 5 39878c2ecf20Sopenharmony_ci 39888c2ecf20Sopenharmony_ci#define HMA_PAGE_SIZE PAGE_SIZE 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci#define HMA_MAX_NO_FW_ADDRESS (16 << 10) /* FW supports 16K addresses */ 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci#define HMA_PAGE_ORDER \ 39938c2ecf20Sopenharmony_ci ((HMA_PAGE_SIZE < HMA_MAX_NO_FW_ADDRESS) ? \ 39948c2ecf20Sopenharmony_ci ilog2(HMA_MAX_NO_FW_ADDRESS / HMA_PAGE_SIZE) : 0) 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci/* The minimum and maximum possible HMA sizes that can be specified in the FW 39978c2ecf20Sopenharmony_ci * configuration(in units of MB). 39988c2ecf20Sopenharmony_ci */ 39998c2ecf20Sopenharmony_ci#define HMA_MIN_TOTAL_SIZE 1 40008c2ecf20Sopenharmony_ci#define HMA_MAX_TOTAL_SIZE \ 40018c2ecf20Sopenharmony_ci (((HMA_PAGE_SIZE << HMA_PAGE_ORDER) * \ 40028c2ecf20Sopenharmony_ci HMA_MAX_NO_FW_ADDRESS) >> 20) 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_cistatic void adap_free_hma_mem(struct adapter *adapter) 40058c2ecf20Sopenharmony_ci{ 40068c2ecf20Sopenharmony_ci struct scatterlist *iter; 40078c2ecf20Sopenharmony_ci struct page *page; 40088c2ecf20Sopenharmony_ci int i; 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_ci if (!adapter->hma.sgt) 40118c2ecf20Sopenharmony_ci return; 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci if (adapter->hma.flags & HMA_DMA_MAPPED_FLAG) { 40148c2ecf20Sopenharmony_ci dma_unmap_sg(adapter->pdev_dev, adapter->hma.sgt->sgl, 40158c2ecf20Sopenharmony_ci adapter->hma.sgt->nents, PCI_DMA_BIDIRECTIONAL); 40168c2ecf20Sopenharmony_ci adapter->hma.flags &= ~HMA_DMA_MAPPED_FLAG; 40178c2ecf20Sopenharmony_ci } 40188c2ecf20Sopenharmony_ci 40198c2ecf20Sopenharmony_ci for_each_sg(adapter->hma.sgt->sgl, iter, 40208c2ecf20Sopenharmony_ci adapter->hma.sgt->orig_nents, i) { 40218c2ecf20Sopenharmony_ci page = sg_page(iter); 40228c2ecf20Sopenharmony_ci if (page) 40238c2ecf20Sopenharmony_ci __free_pages(page, HMA_PAGE_ORDER); 40248c2ecf20Sopenharmony_ci } 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci kfree(adapter->hma.phy_addr); 40278c2ecf20Sopenharmony_ci sg_free_table(adapter->hma.sgt); 40288c2ecf20Sopenharmony_ci kfree(adapter->hma.sgt); 40298c2ecf20Sopenharmony_ci adapter->hma.sgt = NULL; 40308c2ecf20Sopenharmony_ci} 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_cistatic int adap_config_hma(struct adapter *adapter) 40338c2ecf20Sopenharmony_ci{ 40348c2ecf20Sopenharmony_ci struct scatterlist *sgl, *iter; 40358c2ecf20Sopenharmony_ci struct sg_table *sgt; 40368c2ecf20Sopenharmony_ci struct page *newpage; 40378c2ecf20Sopenharmony_ci unsigned int i, j, k; 40388c2ecf20Sopenharmony_ci u32 param, hma_size; 40398c2ecf20Sopenharmony_ci unsigned int ncmds; 40408c2ecf20Sopenharmony_ci size_t page_size; 40418c2ecf20Sopenharmony_ci u32 page_order; 40428c2ecf20Sopenharmony_ci int node, ret; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci /* HMA is supported only for T6+ cards. 40458c2ecf20Sopenharmony_ci * Avoid initializing HMA in kdump kernels. 40468c2ecf20Sopenharmony_ci */ 40478c2ecf20Sopenharmony_ci if (is_kdump_kernel() || 40488c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6) 40498c2ecf20Sopenharmony_ci return 0; 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci /* Get the HMA region size required by fw */ 40528c2ecf20Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 40538c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HMA_SIZE)); 40548c2ecf20Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 40558c2ecf20Sopenharmony_ci 1, ¶m, &hma_size); 40568c2ecf20Sopenharmony_ci /* An error means card has its own memory or HMA is not supported by 40578c2ecf20Sopenharmony_ci * the firmware. Return without any errors. 40588c2ecf20Sopenharmony_ci */ 40598c2ecf20Sopenharmony_ci if (ret || !hma_size) 40608c2ecf20Sopenharmony_ci return 0; 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci if (hma_size < HMA_MIN_TOTAL_SIZE || 40638c2ecf20Sopenharmony_ci hma_size > HMA_MAX_TOTAL_SIZE) { 40648c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 40658c2ecf20Sopenharmony_ci "HMA size %uMB beyond bounds(%u-%lu)MB\n", 40668c2ecf20Sopenharmony_ci hma_size, HMA_MIN_TOTAL_SIZE, HMA_MAX_TOTAL_SIZE); 40678c2ecf20Sopenharmony_ci return -EINVAL; 40688c2ecf20Sopenharmony_ci } 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci page_size = HMA_PAGE_SIZE; 40718c2ecf20Sopenharmony_ci page_order = HMA_PAGE_ORDER; 40728c2ecf20Sopenharmony_ci adapter->hma.sgt = kzalloc(sizeof(*adapter->hma.sgt), GFP_KERNEL); 40738c2ecf20Sopenharmony_ci if (unlikely(!adapter->hma.sgt)) { 40748c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "HMA SG table allocation failed\n"); 40758c2ecf20Sopenharmony_ci return -ENOMEM; 40768c2ecf20Sopenharmony_ci } 40778c2ecf20Sopenharmony_ci sgt = adapter->hma.sgt; 40788c2ecf20Sopenharmony_ci /* FW returned value will be in MB's 40798c2ecf20Sopenharmony_ci */ 40808c2ecf20Sopenharmony_ci sgt->orig_nents = (hma_size << 20) / (page_size << page_order); 40818c2ecf20Sopenharmony_ci if (sg_alloc_table(sgt, sgt->orig_nents, GFP_KERNEL)) { 40828c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "HMA SGL allocation failed\n"); 40838c2ecf20Sopenharmony_ci kfree(adapter->hma.sgt); 40848c2ecf20Sopenharmony_ci adapter->hma.sgt = NULL; 40858c2ecf20Sopenharmony_ci return -ENOMEM; 40868c2ecf20Sopenharmony_ci } 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci sgl = adapter->hma.sgt->sgl; 40898c2ecf20Sopenharmony_ci node = dev_to_node(adapter->pdev_dev); 40908c2ecf20Sopenharmony_ci for_each_sg(sgl, iter, sgt->orig_nents, i) { 40918c2ecf20Sopenharmony_ci newpage = alloc_pages_node(node, __GFP_NOWARN | GFP_KERNEL | 40928c2ecf20Sopenharmony_ci __GFP_ZERO, page_order); 40938c2ecf20Sopenharmony_ci if (!newpage) { 40948c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 40958c2ecf20Sopenharmony_ci "Not enough memory for HMA page allocation\n"); 40968c2ecf20Sopenharmony_ci ret = -ENOMEM; 40978c2ecf20Sopenharmony_ci goto free_hma; 40988c2ecf20Sopenharmony_ci } 40998c2ecf20Sopenharmony_ci sg_set_page(iter, newpage, page_size << page_order, 0); 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci sgt->nents = dma_map_sg(adapter->pdev_dev, sgl, sgt->orig_nents, 41038c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 41048c2ecf20Sopenharmony_ci if (!sgt->nents) { 41058c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 41068c2ecf20Sopenharmony_ci "Not enough memory for HMA DMA mapping"); 41078c2ecf20Sopenharmony_ci ret = -ENOMEM; 41088c2ecf20Sopenharmony_ci goto free_hma; 41098c2ecf20Sopenharmony_ci } 41108c2ecf20Sopenharmony_ci adapter->hma.flags |= HMA_DMA_MAPPED_FLAG; 41118c2ecf20Sopenharmony_ci 41128c2ecf20Sopenharmony_ci adapter->hma.phy_addr = kcalloc(sgt->nents, sizeof(dma_addr_t), 41138c2ecf20Sopenharmony_ci GFP_KERNEL); 41148c2ecf20Sopenharmony_ci if (unlikely(!adapter->hma.phy_addr)) 41158c2ecf20Sopenharmony_ci goto free_hma; 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci for_each_sg(sgl, iter, sgt->nents, i) { 41188c2ecf20Sopenharmony_ci newpage = sg_page(iter); 41198c2ecf20Sopenharmony_ci adapter->hma.phy_addr[i] = sg_dma_address(iter); 41208c2ecf20Sopenharmony_ci } 41218c2ecf20Sopenharmony_ci 41228c2ecf20Sopenharmony_ci ncmds = DIV_ROUND_UP(sgt->nents, HMA_MAX_ADDR_IN_CMD); 41238c2ecf20Sopenharmony_ci /* Pass on the addresses to firmware */ 41248c2ecf20Sopenharmony_ci for (i = 0, k = 0; i < ncmds; i++, k += HMA_MAX_ADDR_IN_CMD) { 41258c2ecf20Sopenharmony_ci struct fw_hma_cmd hma_cmd; 41268c2ecf20Sopenharmony_ci u8 naddr = HMA_MAX_ADDR_IN_CMD; 41278c2ecf20Sopenharmony_ci u8 soc = 0, eoc = 0; 41288c2ecf20Sopenharmony_ci u8 hma_mode = 1; /* Presently we support only Page table mode */ 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci soc = (i == 0) ? 1 : 0; 41318c2ecf20Sopenharmony_ci eoc = (i == ncmds - 1) ? 1 : 0; 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci /* For last cmd, set naddr corresponding to remaining 41348c2ecf20Sopenharmony_ci * addresses 41358c2ecf20Sopenharmony_ci */ 41368c2ecf20Sopenharmony_ci if (i == ncmds - 1) { 41378c2ecf20Sopenharmony_ci naddr = sgt->nents % HMA_MAX_ADDR_IN_CMD; 41388c2ecf20Sopenharmony_ci naddr = naddr ? naddr : HMA_MAX_ADDR_IN_CMD; 41398c2ecf20Sopenharmony_ci } 41408c2ecf20Sopenharmony_ci memset(&hma_cmd, 0, sizeof(hma_cmd)); 41418c2ecf20Sopenharmony_ci hma_cmd.op_pkd = htonl(FW_CMD_OP_V(FW_HMA_CMD) | 41428c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F); 41438c2ecf20Sopenharmony_ci hma_cmd.retval_len16 = htonl(FW_LEN16(hma_cmd)); 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci hma_cmd.mode_to_pcie_params = 41468c2ecf20Sopenharmony_ci htonl(FW_HMA_CMD_MODE_V(hma_mode) | 41478c2ecf20Sopenharmony_ci FW_HMA_CMD_SOC_V(soc) | FW_HMA_CMD_EOC_V(eoc)); 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci /* HMA cmd size specified in MB's */ 41508c2ecf20Sopenharmony_ci hma_cmd.naddr_size = 41518c2ecf20Sopenharmony_ci htonl(FW_HMA_CMD_SIZE_V(hma_size) | 41528c2ecf20Sopenharmony_ci FW_HMA_CMD_NADDR_V(naddr)); 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_ci /* Total Page size specified in units of 4K */ 41558c2ecf20Sopenharmony_ci hma_cmd.addr_size_pkd = 41568c2ecf20Sopenharmony_ci htonl(FW_HMA_CMD_ADDR_SIZE_V 41578c2ecf20Sopenharmony_ci ((page_size << page_order) >> 12)); 41588c2ecf20Sopenharmony_ci 41598c2ecf20Sopenharmony_ci /* Fill the 5 addresses */ 41608c2ecf20Sopenharmony_ci for (j = 0; j < naddr; j++) { 41618c2ecf20Sopenharmony_ci hma_cmd.phy_address[j] = 41628c2ecf20Sopenharmony_ci cpu_to_be64(adapter->hma.phy_addr[j + k]); 41638c2ecf20Sopenharmony_ci } 41648c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &hma_cmd, 41658c2ecf20Sopenharmony_ci sizeof(hma_cmd), &hma_cmd); 41668c2ecf20Sopenharmony_ci if (ret) { 41678c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 41688c2ecf20Sopenharmony_ci "HMA FW command failed with err %d\n", ret); 41698c2ecf20Sopenharmony_ci goto free_hma; 41708c2ecf20Sopenharmony_ci } 41718c2ecf20Sopenharmony_ci } 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_ci if (!ret) 41748c2ecf20Sopenharmony_ci dev_info(adapter->pdev_dev, 41758c2ecf20Sopenharmony_ci "Reserved %uMB host memory for HMA\n", hma_size); 41768c2ecf20Sopenharmony_ci return ret; 41778c2ecf20Sopenharmony_ci 41788c2ecf20Sopenharmony_cifree_hma: 41798c2ecf20Sopenharmony_ci adap_free_hma_mem(adapter); 41808c2ecf20Sopenharmony_ci return ret; 41818c2ecf20Sopenharmony_ci} 41828c2ecf20Sopenharmony_ci 41838c2ecf20Sopenharmony_cistatic int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) 41848c2ecf20Sopenharmony_ci{ 41858c2ecf20Sopenharmony_ci u32 v; 41868c2ecf20Sopenharmony_ci int ret; 41878c2ecf20Sopenharmony_ci 41888c2ecf20Sopenharmony_ci /* Now that we've successfully configured and initialized the adapter 41898c2ecf20Sopenharmony_ci * can ask the Firmware what resources it has provisioned for us. 41908c2ecf20Sopenharmony_ci */ 41918c2ecf20Sopenharmony_ci ret = t4_get_pfres(adap); 41928c2ecf20Sopenharmony_ci if (ret) { 41938c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 41948c2ecf20Sopenharmony_ci "Unable to retrieve resource provisioning information\n"); 41958c2ecf20Sopenharmony_ci return ret; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci /* get device capabilities */ 41998c2ecf20Sopenharmony_ci memset(c, 0, sizeof(*c)); 42008c2ecf20Sopenharmony_ci c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 42018c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F); 42028c2ecf20Sopenharmony_ci c->cfvalid_to_len16 = htonl(FW_LEN16(*c)); 42038c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), c); 42048c2ecf20Sopenharmony_ci if (ret < 0) 42058c2ecf20Sopenharmony_ci return ret; 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 42088c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F); 42098c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), NULL); 42108c2ecf20Sopenharmony_ci if (ret < 0) 42118c2ecf20Sopenharmony_ci return ret; 42128c2ecf20Sopenharmony_ci 42138c2ecf20Sopenharmony_ci ret = t4_config_glbl_rss(adap, adap->pf, 42148c2ecf20Sopenharmony_ci FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, 42158c2ecf20Sopenharmony_ci FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F | 42168c2ecf20Sopenharmony_ci FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F); 42178c2ecf20Sopenharmony_ci if (ret < 0) 42188c2ecf20Sopenharmony_ci return ret; 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci ret = t4_cfg_pfvf(adap, adap->mbox, adap->pf, 0, adap->sge.egr_sz, 64, 42218c2ecf20Sopenharmony_ci MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, 42228c2ecf20Sopenharmony_ci FW_CMD_CAP_PF); 42238c2ecf20Sopenharmony_ci if (ret < 0) 42248c2ecf20Sopenharmony_ci return ret; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci t4_sge_init(adap); 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci /* tweak some settings */ 42298c2ecf20Sopenharmony_ci t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849); 42308c2ecf20Sopenharmony_ci t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(PAGE_SHIFT - 12)); 42318c2ecf20Sopenharmony_ci t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A); 42328c2ecf20Sopenharmony_ci v = t4_read_reg(adap, TP_PIO_DATA_A); 42338c2ecf20Sopenharmony_ci t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F); 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci /* first 4 Tx modulation queues point to consecutive Tx channels */ 42368c2ecf20Sopenharmony_ci adap->params.tp.tx_modq_map = 0xE4; 42378c2ecf20Sopenharmony_ci t4_write_reg(adap, TP_TX_MOD_QUEUE_REQ_MAP_A, 42388c2ecf20Sopenharmony_ci TX_MOD_QUEUE_REQ_MAP_V(adap->params.tp.tx_modq_map)); 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci /* associate each Tx modulation queue with consecutive Tx channels */ 42418c2ecf20Sopenharmony_ci v = 0x84218421; 42428c2ecf20Sopenharmony_ci t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, 42438c2ecf20Sopenharmony_ci &v, 1, TP_TX_SCHED_HDR_A); 42448c2ecf20Sopenharmony_ci t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, 42458c2ecf20Sopenharmony_ci &v, 1, TP_TX_SCHED_FIFO_A); 42468c2ecf20Sopenharmony_ci t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, 42478c2ecf20Sopenharmony_ci &v, 1, TP_TX_SCHED_PCMD_A); 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci#define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */ 42508c2ecf20Sopenharmony_ci if (is_offload(adap)) { 42518c2ecf20Sopenharmony_ci t4_write_reg(adap, TP_TX_MOD_QUEUE_WEIGHT0_A, 42528c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 42538c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 42548c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 42558c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); 42568c2ecf20Sopenharmony_ci t4_write_reg(adap, TP_TX_MOD_CHANNEL_WEIGHT_A, 42578c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 42588c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 42598c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 42608c2ecf20Sopenharmony_ci TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); 42618c2ecf20Sopenharmony_ci } 42628c2ecf20Sopenharmony_ci 42638c2ecf20Sopenharmony_ci /* get basic stuff going */ 42648c2ecf20Sopenharmony_ci return t4_early_init(adap, adap->pf); 42658c2ecf20Sopenharmony_ci} 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci/* 42688c2ecf20Sopenharmony_ci * Max # of ATIDs. The absolute HW max is 16K but we keep it lower. 42698c2ecf20Sopenharmony_ci */ 42708c2ecf20Sopenharmony_ci#define MAX_ATIDS 8192U 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci/* 42738c2ecf20Sopenharmony_ci * Phase 0 of initialization: contact FW, obtain config, perform basic init. 42748c2ecf20Sopenharmony_ci * 42758c2ecf20Sopenharmony_ci * If the firmware we're dealing with has Configuration File support, then 42768c2ecf20Sopenharmony_ci * we use that to perform all configuration 42778c2ecf20Sopenharmony_ci */ 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_ci/* 42808c2ecf20Sopenharmony_ci * Tweak configuration based on module parameters, etc. Most of these have 42818c2ecf20Sopenharmony_ci * defaults assigned to them by Firmware Configuration Files (if we're using 42828c2ecf20Sopenharmony_ci * them) but need to be explicitly set if we're using hard-coded 42838c2ecf20Sopenharmony_ci * initialization. But even in the case of using Firmware Configuration 42848c2ecf20Sopenharmony_ci * Files, we'd like to expose the ability to change these via module 42858c2ecf20Sopenharmony_ci * parameters so these are essentially common tweaks/settings for 42868c2ecf20Sopenharmony_ci * Configuration Files and hard-coded initialization ... 42878c2ecf20Sopenharmony_ci */ 42888c2ecf20Sopenharmony_cistatic int adap_init0_tweaks(struct adapter *adapter) 42898c2ecf20Sopenharmony_ci{ 42908c2ecf20Sopenharmony_ci /* 42918c2ecf20Sopenharmony_ci * Fix up various Host-Dependent Parameters like Page Size, Cache 42928c2ecf20Sopenharmony_ci * Line Size, etc. The firmware default is for a 4KB Page Size and 42938c2ecf20Sopenharmony_ci * 64B Cache Line Size ... 42948c2ecf20Sopenharmony_ci */ 42958c2ecf20Sopenharmony_ci t4_fixup_host_params(adapter, PAGE_SIZE, L1_CACHE_BYTES); 42968c2ecf20Sopenharmony_ci 42978c2ecf20Sopenharmony_ci /* 42988c2ecf20Sopenharmony_ci * Process module parameters which affect early initialization. 42998c2ecf20Sopenharmony_ci */ 43008c2ecf20Sopenharmony_ci if (rx_dma_offset != 2 && rx_dma_offset != 0) { 43018c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, 43028c2ecf20Sopenharmony_ci "Ignoring illegal rx_dma_offset=%d, using 2\n", 43038c2ecf20Sopenharmony_ci rx_dma_offset); 43048c2ecf20Sopenharmony_ci rx_dma_offset = 2; 43058c2ecf20Sopenharmony_ci } 43068c2ecf20Sopenharmony_ci t4_set_reg_field(adapter, SGE_CONTROL_A, 43078c2ecf20Sopenharmony_ci PKTSHIFT_V(PKTSHIFT_M), 43088c2ecf20Sopenharmony_ci PKTSHIFT_V(rx_dma_offset)); 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci /* 43118c2ecf20Sopenharmony_ci * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux 43128c2ecf20Sopenharmony_ci * adds the pseudo header itself. 43138c2ecf20Sopenharmony_ci */ 43148c2ecf20Sopenharmony_ci t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG_A, 43158c2ecf20Sopenharmony_ci CSUM_HAS_PSEUDO_HDR_F, 0); 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci return 0; 43188c2ecf20Sopenharmony_ci} 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci/* 10Gb/s-BT PHY Support. chip-external 10Gb/s-BT PHYs are complex chips 43218c2ecf20Sopenharmony_ci * unto themselves and they contain their own firmware to perform their 43228c2ecf20Sopenharmony_ci * tasks ... 43238c2ecf20Sopenharmony_ci */ 43248c2ecf20Sopenharmony_cistatic int phy_aq1202_version(const u8 *phy_fw_data, 43258c2ecf20Sopenharmony_ci size_t phy_fw_size) 43268c2ecf20Sopenharmony_ci{ 43278c2ecf20Sopenharmony_ci int offset; 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci /* At offset 0x8 you're looking for the primary image's 43308c2ecf20Sopenharmony_ci * starting offset which is 3 Bytes wide 43318c2ecf20Sopenharmony_ci * 43328c2ecf20Sopenharmony_ci * At offset 0xa of the primary image, you look for the offset 43338c2ecf20Sopenharmony_ci * of the DRAM segment which is 3 Bytes wide. 43348c2ecf20Sopenharmony_ci * 43358c2ecf20Sopenharmony_ci * The FW version is at offset 0x27e of the DRAM and is 2 Bytes 43368c2ecf20Sopenharmony_ci * wide 43378c2ecf20Sopenharmony_ci */ 43388c2ecf20Sopenharmony_ci #define be16(__p) (((__p)[0] << 8) | (__p)[1]) 43398c2ecf20Sopenharmony_ci #define le16(__p) ((__p)[0] | ((__p)[1] << 8)) 43408c2ecf20Sopenharmony_ci #define le24(__p) (le16(__p) | ((__p)[2] << 16)) 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci offset = le24(phy_fw_data + 0x8) << 12; 43438c2ecf20Sopenharmony_ci offset = le24(phy_fw_data + offset + 0xa); 43448c2ecf20Sopenharmony_ci return be16(phy_fw_data + offset + 0x27e); 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci #undef be16 43478c2ecf20Sopenharmony_ci #undef le16 43488c2ecf20Sopenharmony_ci #undef le24 43498c2ecf20Sopenharmony_ci} 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_cistatic struct info_10gbt_phy_fw { 43528c2ecf20Sopenharmony_ci unsigned int phy_fw_id; /* PCI Device ID */ 43538c2ecf20Sopenharmony_ci char *phy_fw_file; /* /lib/firmware/ PHY Firmware file */ 43548c2ecf20Sopenharmony_ci int (*phy_fw_version)(const u8 *phy_fw_data, size_t phy_fw_size); 43558c2ecf20Sopenharmony_ci int phy_flash; /* Has FLASH for PHY Firmware */ 43568c2ecf20Sopenharmony_ci} phy_info_array[] = { 43578c2ecf20Sopenharmony_ci { 43588c2ecf20Sopenharmony_ci PHY_AQ1202_DEVICEID, 43598c2ecf20Sopenharmony_ci PHY_AQ1202_FIRMWARE, 43608c2ecf20Sopenharmony_ci phy_aq1202_version, 43618c2ecf20Sopenharmony_ci 1, 43628c2ecf20Sopenharmony_ci }, 43638c2ecf20Sopenharmony_ci { 43648c2ecf20Sopenharmony_ci PHY_BCM84834_DEVICEID, 43658c2ecf20Sopenharmony_ci PHY_BCM84834_FIRMWARE, 43668c2ecf20Sopenharmony_ci NULL, 43678c2ecf20Sopenharmony_ci 0, 43688c2ecf20Sopenharmony_ci }, 43698c2ecf20Sopenharmony_ci { 0, NULL, NULL }, 43708c2ecf20Sopenharmony_ci}; 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_cistatic struct info_10gbt_phy_fw *find_phy_info(int devid) 43738c2ecf20Sopenharmony_ci{ 43748c2ecf20Sopenharmony_ci int i; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(phy_info_array); i++) { 43778c2ecf20Sopenharmony_ci if (phy_info_array[i].phy_fw_id == devid) 43788c2ecf20Sopenharmony_ci return &phy_info_array[i]; 43798c2ecf20Sopenharmony_ci } 43808c2ecf20Sopenharmony_ci return NULL; 43818c2ecf20Sopenharmony_ci} 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci/* Handle updating of chip-external 10Gb/s-BT PHY firmware. This needs to 43848c2ecf20Sopenharmony_ci * happen after the FW_RESET_CMD but before the FW_INITIALIZE_CMD. On error 43858c2ecf20Sopenharmony_ci * we return a negative error number. If we transfer new firmware we return 1 43868c2ecf20Sopenharmony_ci * (from t4_load_phy_fw()). If we don't do anything we return 0. 43878c2ecf20Sopenharmony_ci */ 43888c2ecf20Sopenharmony_cistatic int adap_init0_phy(struct adapter *adap) 43898c2ecf20Sopenharmony_ci{ 43908c2ecf20Sopenharmony_ci const struct firmware *phyf; 43918c2ecf20Sopenharmony_ci int ret; 43928c2ecf20Sopenharmony_ci struct info_10gbt_phy_fw *phy_info; 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci /* Use the device ID to determine which PHY file to flash. 43958c2ecf20Sopenharmony_ci */ 43968c2ecf20Sopenharmony_ci phy_info = find_phy_info(adap->pdev->device); 43978c2ecf20Sopenharmony_ci if (!phy_info) { 43988c2ecf20Sopenharmony_ci dev_warn(adap->pdev_dev, 43998c2ecf20Sopenharmony_ci "No PHY Firmware file found for this PHY\n"); 44008c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 44018c2ecf20Sopenharmony_ci } 44028c2ecf20Sopenharmony_ci 44038c2ecf20Sopenharmony_ci /* If we have a T4 PHY firmware file under /lib/firmware/cxgb4/, then 44048c2ecf20Sopenharmony_ci * use that. The adapter firmware provides us with a memory buffer 44058c2ecf20Sopenharmony_ci * where we can load a PHY firmware file from the host if we want to 44068c2ecf20Sopenharmony_ci * override the PHY firmware File in flash. 44078c2ecf20Sopenharmony_ci */ 44088c2ecf20Sopenharmony_ci ret = request_firmware_direct(&phyf, phy_info->phy_fw_file, 44098c2ecf20Sopenharmony_ci adap->pdev_dev); 44108c2ecf20Sopenharmony_ci if (ret < 0) { 44118c2ecf20Sopenharmony_ci /* For adapters without FLASH attached to PHY for their 44128c2ecf20Sopenharmony_ci * firmware, it's obviously a fatal error if we can't get the 44138c2ecf20Sopenharmony_ci * firmware to the adapter. For adapters with PHY firmware 44148c2ecf20Sopenharmony_ci * FLASH storage, it's worth a warning if we can't find the 44158c2ecf20Sopenharmony_ci * PHY Firmware but we'll neuter the error ... 44168c2ecf20Sopenharmony_ci */ 44178c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "unable to find PHY Firmware image " 44188c2ecf20Sopenharmony_ci "/lib/firmware/%s, error %d\n", 44198c2ecf20Sopenharmony_ci phy_info->phy_fw_file, -ret); 44208c2ecf20Sopenharmony_ci if (phy_info->phy_flash) { 44218c2ecf20Sopenharmony_ci int cur_phy_fw_ver = 0; 44228c2ecf20Sopenharmony_ci 44238c2ecf20Sopenharmony_ci t4_phy_fw_ver(adap, &cur_phy_fw_ver); 44248c2ecf20Sopenharmony_ci dev_warn(adap->pdev_dev, "continuing with, on-adapter " 44258c2ecf20Sopenharmony_ci "FLASH copy, version %#x\n", cur_phy_fw_ver); 44268c2ecf20Sopenharmony_ci ret = 0; 44278c2ecf20Sopenharmony_ci } 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci return ret; 44308c2ecf20Sopenharmony_ci } 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci /* Load PHY Firmware onto adapter. 44338c2ecf20Sopenharmony_ci */ 44348c2ecf20Sopenharmony_ci ret = t4_load_phy_fw(adap, MEMWIN_NIC, phy_info->phy_fw_version, 44358c2ecf20Sopenharmony_ci (u8 *)phyf->data, phyf->size); 44368c2ecf20Sopenharmony_ci if (ret < 0) 44378c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "PHY Firmware transfer error %d\n", 44388c2ecf20Sopenharmony_ci -ret); 44398c2ecf20Sopenharmony_ci else if (ret > 0) { 44408c2ecf20Sopenharmony_ci int new_phy_fw_ver = 0; 44418c2ecf20Sopenharmony_ci 44428c2ecf20Sopenharmony_ci if (phy_info->phy_fw_version) 44438c2ecf20Sopenharmony_ci new_phy_fw_ver = phy_info->phy_fw_version(phyf->data, 44448c2ecf20Sopenharmony_ci phyf->size); 44458c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, "Successfully transferred PHY " 44468c2ecf20Sopenharmony_ci "Firmware /lib/firmware/%s, version %#x\n", 44478c2ecf20Sopenharmony_ci phy_info->phy_fw_file, new_phy_fw_ver); 44488c2ecf20Sopenharmony_ci } 44498c2ecf20Sopenharmony_ci 44508c2ecf20Sopenharmony_ci release_firmware(phyf); 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci return ret; 44538c2ecf20Sopenharmony_ci} 44548c2ecf20Sopenharmony_ci 44558c2ecf20Sopenharmony_ci/* 44568c2ecf20Sopenharmony_ci * Attempt to initialize the adapter via a Firmware Configuration File. 44578c2ecf20Sopenharmony_ci */ 44588c2ecf20Sopenharmony_cistatic int adap_init0_config(struct adapter *adapter, int reset) 44598c2ecf20Sopenharmony_ci{ 44608c2ecf20Sopenharmony_ci char *fw_config_file, fw_config_file_path[256]; 44618c2ecf20Sopenharmony_ci u32 finiver, finicsum, cfcsum, param, val; 44628c2ecf20Sopenharmony_ci struct fw_caps_config_cmd caps_cmd; 44638c2ecf20Sopenharmony_ci unsigned long mtype = 0, maddr = 0; 44648c2ecf20Sopenharmony_ci const struct firmware *cf; 44658c2ecf20Sopenharmony_ci char *config_name = NULL; 44668c2ecf20Sopenharmony_ci int config_issued = 0; 44678c2ecf20Sopenharmony_ci int ret; 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_ci /* 44708c2ecf20Sopenharmony_ci * Reset device if necessary. 44718c2ecf20Sopenharmony_ci */ 44728c2ecf20Sopenharmony_ci if (reset) { 44738c2ecf20Sopenharmony_ci ret = t4_fw_reset(adapter, adapter->mbox, 44748c2ecf20Sopenharmony_ci PIORSTMODE_F | PIORST_F); 44758c2ecf20Sopenharmony_ci if (ret < 0) 44768c2ecf20Sopenharmony_ci goto bye; 44778c2ecf20Sopenharmony_ci } 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci /* If this is a 10Gb/s-BT adapter make sure the chip-external 44808c2ecf20Sopenharmony_ci * 10Gb/s-BT PHYs have up-to-date firmware. Note that this step needs 44818c2ecf20Sopenharmony_ci * to be performed after any global adapter RESET above since some 44828c2ecf20Sopenharmony_ci * PHYs only have local RAM copies of the PHY firmware. 44838c2ecf20Sopenharmony_ci */ 44848c2ecf20Sopenharmony_ci if (is_10gbt_device(adapter->pdev->device)) { 44858c2ecf20Sopenharmony_ci ret = adap_init0_phy(adapter); 44868c2ecf20Sopenharmony_ci if (ret < 0) 44878c2ecf20Sopenharmony_ci goto bye; 44888c2ecf20Sopenharmony_ci } 44898c2ecf20Sopenharmony_ci /* 44908c2ecf20Sopenharmony_ci * If we have a T4 configuration file under /lib/firmware/cxgb4/, 44918c2ecf20Sopenharmony_ci * then use that. Otherwise, use the configuration file stored 44928c2ecf20Sopenharmony_ci * in the adapter flash ... 44938c2ecf20Sopenharmony_ci */ 44948c2ecf20Sopenharmony_ci switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { 44958c2ecf20Sopenharmony_ci case CHELSIO_T4: 44968c2ecf20Sopenharmony_ci fw_config_file = FW4_CFNAME; 44978c2ecf20Sopenharmony_ci break; 44988c2ecf20Sopenharmony_ci case CHELSIO_T5: 44998c2ecf20Sopenharmony_ci fw_config_file = FW5_CFNAME; 45008c2ecf20Sopenharmony_ci break; 45018c2ecf20Sopenharmony_ci case CHELSIO_T6: 45028c2ecf20Sopenharmony_ci fw_config_file = FW6_CFNAME; 45038c2ecf20Sopenharmony_ci break; 45048c2ecf20Sopenharmony_ci default: 45058c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, "Device %d is not supported\n", 45068c2ecf20Sopenharmony_ci adapter->pdev->device); 45078c2ecf20Sopenharmony_ci ret = -EINVAL; 45088c2ecf20Sopenharmony_ci goto bye; 45098c2ecf20Sopenharmony_ci } 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci ret = request_firmware(&cf, fw_config_file, adapter->pdev_dev); 45128c2ecf20Sopenharmony_ci if (ret < 0) { 45138c2ecf20Sopenharmony_ci config_name = "On FLASH"; 45148c2ecf20Sopenharmony_ci mtype = FW_MEMTYPE_CF_FLASH; 45158c2ecf20Sopenharmony_ci maddr = t4_flash_cfg_addr(adapter); 45168c2ecf20Sopenharmony_ci } else { 45178c2ecf20Sopenharmony_ci u32 params[7], val[7]; 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci sprintf(fw_config_file_path, 45208c2ecf20Sopenharmony_ci "/lib/firmware/%s", fw_config_file); 45218c2ecf20Sopenharmony_ci config_name = fw_config_file_path; 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci if (cf->size >= FLASH_CFG_MAX_SIZE) 45248c2ecf20Sopenharmony_ci ret = -ENOMEM; 45258c2ecf20Sopenharmony_ci else { 45268c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 45278c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); 45288c2ecf20Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, 45298c2ecf20Sopenharmony_ci adapter->pf, 0, 1, params, val); 45308c2ecf20Sopenharmony_ci if (ret == 0) { 45318c2ecf20Sopenharmony_ci /* 45328c2ecf20Sopenharmony_ci * For t4_memory_rw() below addresses and 45338c2ecf20Sopenharmony_ci * sizes have to be in terms of multiples of 4 45348c2ecf20Sopenharmony_ci * bytes. So, if the Configuration File isn't 45358c2ecf20Sopenharmony_ci * a multiple of 4 bytes in length we'll have 45368c2ecf20Sopenharmony_ci * to write that out separately since we can't 45378c2ecf20Sopenharmony_ci * guarantee that the bytes following the 45388c2ecf20Sopenharmony_ci * residual byte in the buffer returned by 45398c2ecf20Sopenharmony_ci * request_firmware() are zeroed out ... 45408c2ecf20Sopenharmony_ci */ 45418c2ecf20Sopenharmony_ci size_t resid = cf->size & 0x3; 45428c2ecf20Sopenharmony_ci size_t size = cf->size & ~0x3; 45438c2ecf20Sopenharmony_ci __be32 *data = (__be32 *)cf->data; 45448c2ecf20Sopenharmony_ci 45458c2ecf20Sopenharmony_ci mtype = FW_PARAMS_PARAM_Y_G(val[0]); 45468c2ecf20Sopenharmony_ci maddr = FW_PARAMS_PARAM_Z_G(val[0]) << 16; 45478c2ecf20Sopenharmony_ci 45488c2ecf20Sopenharmony_ci spin_lock(&adapter->win0_lock); 45498c2ecf20Sopenharmony_ci ret = t4_memory_rw(adapter, 0, mtype, maddr, 45508c2ecf20Sopenharmony_ci size, data, T4_MEMORY_WRITE); 45518c2ecf20Sopenharmony_ci if (ret == 0 && resid != 0) { 45528c2ecf20Sopenharmony_ci union { 45538c2ecf20Sopenharmony_ci __be32 word; 45548c2ecf20Sopenharmony_ci char buf[4]; 45558c2ecf20Sopenharmony_ci } last; 45568c2ecf20Sopenharmony_ci int i; 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci last.word = data[size >> 2]; 45598c2ecf20Sopenharmony_ci for (i = resid; i < 4; i++) 45608c2ecf20Sopenharmony_ci last.buf[i] = 0; 45618c2ecf20Sopenharmony_ci ret = t4_memory_rw(adapter, 0, mtype, 45628c2ecf20Sopenharmony_ci maddr + size, 45638c2ecf20Sopenharmony_ci 4, &last.word, 45648c2ecf20Sopenharmony_ci T4_MEMORY_WRITE); 45658c2ecf20Sopenharmony_ci } 45668c2ecf20Sopenharmony_ci spin_unlock(&adapter->win0_lock); 45678c2ecf20Sopenharmony_ci } 45688c2ecf20Sopenharmony_ci } 45698c2ecf20Sopenharmony_ci 45708c2ecf20Sopenharmony_ci release_firmware(cf); 45718c2ecf20Sopenharmony_ci if (ret) 45728c2ecf20Sopenharmony_ci goto bye; 45738c2ecf20Sopenharmony_ci } 45748c2ecf20Sopenharmony_ci 45758c2ecf20Sopenharmony_ci val = 0; 45768c2ecf20Sopenharmony_ci 45778c2ecf20Sopenharmony_ci /* Ofld + Hash filter is supported. Older fw will fail this request and 45788c2ecf20Sopenharmony_ci * it is fine. 45798c2ecf20Sopenharmony_ci */ 45808c2ecf20Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 45818c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HASHFILTER_WITH_OFLD)); 45828c2ecf20Sopenharmony_ci ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0, 45838c2ecf20Sopenharmony_ci 1, ¶m, &val); 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci /* FW doesn't know about Hash filter + ofld support, 45868c2ecf20Sopenharmony_ci * it's not a problem, don't return an error. 45878c2ecf20Sopenharmony_ci */ 45888c2ecf20Sopenharmony_ci if (ret < 0) { 45898c2ecf20Sopenharmony_ci dev_warn(adapter->pdev_dev, 45908c2ecf20Sopenharmony_ci "Hash filter with ofld is not supported by FW\n"); 45918c2ecf20Sopenharmony_ci } 45928c2ecf20Sopenharmony_ci 45938c2ecf20Sopenharmony_ci /* 45948c2ecf20Sopenharmony_ci * Issue a Capability Configuration command to the firmware to get it 45958c2ecf20Sopenharmony_ci * to parse the Configuration File. We don't use t4_fw_config_file() 45968c2ecf20Sopenharmony_ci * because we want the ability to modify various features after we've 45978c2ecf20Sopenharmony_ci * processed the configuration file ... 45988c2ecf20Sopenharmony_ci */ 45998c2ecf20Sopenharmony_ci memset(&caps_cmd, 0, sizeof(caps_cmd)); 46008c2ecf20Sopenharmony_ci caps_cmd.op_to_write = 46018c2ecf20Sopenharmony_ci htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 46028c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 46038c2ecf20Sopenharmony_ci FW_CMD_READ_F); 46048c2ecf20Sopenharmony_ci caps_cmd.cfvalid_to_len16 = 46058c2ecf20Sopenharmony_ci htonl(FW_CAPS_CONFIG_CMD_CFVALID_F | 46068c2ecf20Sopenharmony_ci FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) | 46078c2ecf20Sopenharmony_ci FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) | 46088c2ecf20Sopenharmony_ci FW_LEN16(caps_cmd)); 46098c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), 46108c2ecf20Sopenharmony_ci &caps_cmd); 46118c2ecf20Sopenharmony_ci 46128c2ecf20Sopenharmony_ci /* If the CAPS_CONFIG failed with an ENOENT (for a Firmware 46138c2ecf20Sopenharmony_ci * Configuration File in FLASH), our last gasp effort is to use the 46148c2ecf20Sopenharmony_ci * Firmware Configuration File which is embedded in the firmware. A 46158c2ecf20Sopenharmony_ci * very few early versions of the firmware didn't have one embedded 46168c2ecf20Sopenharmony_ci * but we can ignore those. 46178c2ecf20Sopenharmony_ci */ 46188c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 46198c2ecf20Sopenharmony_ci memset(&caps_cmd, 0, sizeof(caps_cmd)); 46208c2ecf20Sopenharmony_ci caps_cmd.op_to_write = 46218c2ecf20Sopenharmony_ci htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 46228c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 46238c2ecf20Sopenharmony_ci FW_CMD_READ_F); 46248c2ecf20Sopenharmony_ci caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); 46258c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, 46268c2ecf20Sopenharmony_ci sizeof(caps_cmd), &caps_cmd); 46278c2ecf20Sopenharmony_ci config_name = "Firmware Default"; 46288c2ecf20Sopenharmony_ci } 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci config_issued = 1; 46318c2ecf20Sopenharmony_ci if (ret < 0) 46328c2ecf20Sopenharmony_ci goto bye; 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci finiver = ntohl(caps_cmd.finiver); 46358c2ecf20Sopenharmony_ci finicsum = ntohl(caps_cmd.finicsum); 46368c2ecf20Sopenharmony_ci cfcsum = ntohl(caps_cmd.cfcsum); 46378c2ecf20Sopenharmony_ci if (finicsum != cfcsum) 46388c2ecf20Sopenharmony_ci dev_warn(adapter->pdev_dev, "Configuration File checksum "\ 46398c2ecf20Sopenharmony_ci "mismatch: [fini] csum=%#x, computed csum=%#x\n", 46408c2ecf20Sopenharmony_ci finicsum, cfcsum); 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci /* 46438c2ecf20Sopenharmony_ci * And now tell the firmware to use the configuration we just loaded. 46448c2ecf20Sopenharmony_ci */ 46458c2ecf20Sopenharmony_ci caps_cmd.op_to_write = 46468c2ecf20Sopenharmony_ci htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 46478c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 46488c2ecf20Sopenharmony_ci FW_CMD_WRITE_F); 46498c2ecf20Sopenharmony_ci caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); 46508c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), 46518c2ecf20Sopenharmony_ci NULL); 46528c2ecf20Sopenharmony_ci if (ret < 0) 46538c2ecf20Sopenharmony_ci goto bye; 46548c2ecf20Sopenharmony_ci 46558c2ecf20Sopenharmony_ci /* 46568c2ecf20Sopenharmony_ci * Tweak configuration based on system architecture, module 46578c2ecf20Sopenharmony_ci * parameters, etc. 46588c2ecf20Sopenharmony_ci */ 46598c2ecf20Sopenharmony_ci ret = adap_init0_tweaks(adapter); 46608c2ecf20Sopenharmony_ci if (ret < 0) 46618c2ecf20Sopenharmony_ci goto bye; 46628c2ecf20Sopenharmony_ci 46638c2ecf20Sopenharmony_ci /* We will proceed even if HMA init fails. */ 46648c2ecf20Sopenharmony_ci ret = adap_config_hma(adapter); 46658c2ecf20Sopenharmony_ci if (ret) 46668c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 46678c2ecf20Sopenharmony_ci "HMA configuration failed with error %d\n", ret); 46688c2ecf20Sopenharmony_ci 46698c2ecf20Sopenharmony_ci if (is_t6(adapter->params.chip)) { 46708c2ecf20Sopenharmony_ci adap_config_hpfilter(adapter); 46718c2ecf20Sopenharmony_ci ret = setup_ppod_edram(adapter); 46728c2ecf20Sopenharmony_ci if (!ret) 46738c2ecf20Sopenharmony_ci dev_info(adapter->pdev_dev, "Successfully enabled " 46748c2ecf20Sopenharmony_ci "ppod edram feature\n"); 46758c2ecf20Sopenharmony_ci } 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci /* 46788c2ecf20Sopenharmony_ci * And finally tell the firmware to initialize itself using the 46798c2ecf20Sopenharmony_ci * parameters from the Configuration File. 46808c2ecf20Sopenharmony_ci */ 46818c2ecf20Sopenharmony_ci ret = t4_fw_initialize(adapter, adapter->mbox); 46828c2ecf20Sopenharmony_ci if (ret < 0) 46838c2ecf20Sopenharmony_ci goto bye; 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci /* Emit Firmware Configuration File information and return 46868c2ecf20Sopenharmony_ci * successfully. 46878c2ecf20Sopenharmony_ci */ 46888c2ecf20Sopenharmony_ci dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\ 46898c2ecf20Sopenharmony_ci "Configuration File \"%s\", version %#x, computed checksum %#x\n", 46908c2ecf20Sopenharmony_ci config_name, finiver, cfcsum); 46918c2ecf20Sopenharmony_ci return 0; 46928c2ecf20Sopenharmony_ci 46938c2ecf20Sopenharmony_ci /* 46948c2ecf20Sopenharmony_ci * Something bad happened. Return the error ... (If the "error" 46958c2ecf20Sopenharmony_ci * is that there's no Configuration File on the adapter we don't 46968c2ecf20Sopenharmony_ci * want to issue a warning since this is fairly common.) 46978c2ecf20Sopenharmony_ci */ 46988c2ecf20Sopenharmony_cibye: 46998c2ecf20Sopenharmony_ci if (config_issued && ret != -ENOENT) 47008c2ecf20Sopenharmony_ci dev_warn(adapter->pdev_dev, "\"%s\" configuration file error %d\n", 47018c2ecf20Sopenharmony_ci config_name, -ret); 47028c2ecf20Sopenharmony_ci return ret; 47038c2ecf20Sopenharmony_ci} 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_cistatic struct fw_info fw_info_array[] = { 47068c2ecf20Sopenharmony_ci { 47078c2ecf20Sopenharmony_ci .chip = CHELSIO_T4, 47088c2ecf20Sopenharmony_ci .fs_name = FW4_CFNAME, 47098c2ecf20Sopenharmony_ci .fw_mod_name = FW4_FNAME, 47108c2ecf20Sopenharmony_ci .fw_hdr = { 47118c2ecf20Sopenharmony_ci .chip = FW_HDR_CHIP_T4, 47128c2ecf20Sopenharmony_ci .fw_ver = __cpu_to_be32(FW_VERSION(T4)), 47138c2ecf20Sopenharmony_ci .intfver_nic = FW_INTFVER(T4, NIC), 47148c2ecf20Sopenharmony_ci .intfver_vnic = FW_INTFVER(T4, VNIC), 47158c2ecf20Sopenharmony_ci .intfver_ri = FW_INTFVER(T4, RI), 47168c2ecf20Sopenharmony_ci .intfver_iscsi = FW_INTFVER(T4, ISCSI), 47178c2ecf20Sopenharmony_ci .intfver_fcoe = FW_INTFVER(T4, FCOE), 47188c2ecf20Sopenharmony_ci }, 47198c2ecf20Sopenharmony_ci }, { 47208c2ecf20Sopenharmony_ci .chip = CHELSIO_T5, 47218c2ecf20Sopenharmony_ci .fs_name = FW5_CFNAME, 47228c2ecf20Sopenharmony_ci .fw_mod_name = FW5_FNAME, 47238c2ecf20Sopenharmony_ci .fw_hdr = { 47248c2ecf20Sopenharmony_ci .chip = FW_HDR_CHIP_T5, 47258c2ecf20Sopenharmony_ci .fw_ver = __cpu_to_be32(FW_VERSION(T5)), 47268c2ecf20Sopenharmony_ci .intfver_nic = FW_INTFVER(T5, NIC), 47278c2ecf20Sopenharmony_ci .intfver_vnic = FW_INTFVER(T5, VNIC), 47288c2ecf20Sopenharmony_ci .intfver_ri = FW_INTFVER(T5, RI), 47298c2ecf20Sopenharmony_ci .intfver_iscsi = FW_INTFVER(T5, ISCSI), 47308c2ecf20Sopenharmony_ci .intfver_fcoe = FW_INTFVER(T5, FCOE), 47318c2ecf20Sopenharmony_ci }, 47328c2ecf20Sopenharmony_ci }, { 47338c2ecf20Sopenharmony_ci .chip = CHELSIO_T6, 47348c2ecf20Sopenharmony_ci .fs_name = FW6_CFNAME, 47358c2ecf20Sopenharmony_ci .fw_mod_name = FW6_FNAME, 47368c2ecf20Sopenharmony_ci .fw_hdr = { 47378c2ecf20Sopenharmony_ci .chip = FW_HDR_CHIP_T6, 47388c2ecf20Sopenharmony_ci .fw_ver = __cpu_to_be32(FW_VERSION(T6)), 47398c2ecf20Sopenharmony_ci .intfver_nic = FW_INTFVER(T6, NIC), 47408c2ecf20Sopenharmony_ci .intfver_vnic = FW_INTFVER(T6, VNIC), 47418c2ecf20Sopenharmony_ci .intfver_ofld = FW_INTFVER(T6, OFLD), 47428c2ecf20Sopenharmony_ci .intfver_ri = FW_INTFVER(T6, RI), 47438c2ecf20Sopenharmony_ci .intfver_iscsipdu = FW_INTFVER(T6, ISCSIPDU), 47448c2ecf20Sopenharmony_ci .intfver_iscsi = FW_INTFVER(T6, ISCSI), 47458c2ecf20Sopenharmony_ci .intfver_fcoepdu = FW_INTFVER(T6, FCOEPDU), 47468c2ecf20Sopenharmony_ci .intfver_fcoe = FW_INTFVER(T6, FCOE), 47478c2ecf20Sopenharmony_ci }, 47488c2ecf20Sopenharmony_ci } 47498c2ecf20Sopenharmony_ci 47508c2ecf20Sopenharmony_ci}; 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_cistatic struct fw_info *find_fw_info(int chip) 47538c2ecf20Sopenharmony_ci{ 47548c2ecf20Sopenharmony_ci int i; 47558c2ecf20Sopenharmony_ci 47568c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) { 47578c2ecf20Sopenharmony_ci if (fw_info_array[i].chip == chip) 47588c2ecf20Sopenharmony_ci return &fw_info_array[i]; 47598c2ecf20Sopenharmony_ci } 47608c2ecf20Sopenharmony_ci return NULL; 47618c2ecf20Sopenharmony_ci} 47628c2ecf20Sopenharmony_ci 47638c2ecf20Sopenharmony_ci/* 47648c2ecf20Sopenharmony_ci * Phase 0 of initialization: contact FW, obtain config, perform basic init. 47658c2ecf20Sopenharmony_ci */ 47668c2ecf20Sopenharmony_cistatic int adap_init0(struct adapter *adap, int vpd_skip) 47678c2ecf20Sopenharmony_ci{ 47688c2ecf20Sopenharmony_ci struct fw_caps_config_cmd caps_cmd; 47698c2ecf20Sopenharmony_ci u32 params[7], val[7]; 47708c2ecf20Sopenharmony_ci enum dev_state state; 47718c2ecf20Sopenharmony_ci u32 v, port_vec; 47728c2ecf20Sopenharmony_ci int reset = 1; 47738c2ecf20Sopenharmony_ci int ret; 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ci /* Grab Firmware Device Log parameters as early as possible so we have 47768c2ecf20Sopenharmony_ci * access to it for debugging, etc. 47778c2ecf20Sopenharmony_ci */ 47788c2ecf20Sopenharmony_ci ret = t4_init_devlog_params(adap); 47798c2ecf20Sopenharmony_ci if (ret < 0) 47808c2ecf20Sopenharmony_ci return ret; 47818c2ecf20Sopenharmony_ci 47828c2ecf20Sopenharmony_ci /* Contact FW, advertising Master capability */ 47838c2ecf20Sopenharmony_ci ret = t4_fw_hello(adap, adap->mbox, adap->mbox, 47848c2ecf20Sopenharmony_ci is_kdump_kernel() ? MASTER_MUST : MASTER_MAY, &state); 47858c2ecf20Sopenharmony_ci if (ret < 0) { 47868c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "could not connect to FW, error %d\n", 47878c2ecf20Sopenharmony_ci ret); 47888c2ecf20Sopenharmony_ci return ret; 47898c2ecf20Sopenharmony_ci } 47908c2ecf20Sopenharmony_ci if (ret == adap->mbox) 47918c2ecf20Sopenharmony_ci adap->flags |= CXGB4_MASTER_PF; 47928c2ecf20Sopenharmony_ci 47938c2ecf20Sopenharmony_ci /* 47948c2ecf20Sopenharmony_ci * If we're the Master PF Driver and the device is uninitialized, 47958c2ecf20Sopenharmony_ci * then let's consider upgrading the firmware ... (We always want 47968c2ecf20Sopenharmony_ci * to check the firmware version number in order to A. get it for 47978c2ecf20Sopenharmony_ci * later reporting and B. to warn if the currently loaded firmware 47988c2ecf20Sopenharmony_ci * is excessively mismatched relative to the driver.) 47998c2ecf20Sopenharmony_ci */ 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci t4_get_version_info(adap); 48028c2ecf20Sopenharmony_ci ret = t4_check_fw_version(adap); 48038c2ecf20Sopenharmony_ci /* If firmware is too old (not supported by driver) force an update. */ 48048c2ecf20Sopenharmony_ci if (ret) 48058c2ecf20Sopenharmony_ci state = DEV_STATE_UNINIT; 48068c2ecf20Sopenharmony_ci if ((adap->flags & CXGB4_MASTER_PF) && state != DEV_STATE_INIT) { 48078c2ecf20Sopenharmony_ci struct fw_info *fw_info; 48088c2ecf20Sopenharmony_ci struct fw_hdr *card_fw; 48098c2ecf20Sopenharmony_ci const struct firmware *fw; 48108c2ecf20Sopenharmony_ci const u8 *fw_data = NULL; 48118c2ecf20Sopenharmony_ci unsigned int fw_size = 0; 48128c2ecf20Sopenharmony_ci 48138c2ecf20Sopenharmony_ci /* This is the firmware whose headers the driver was compiled 48148c2ecf20Sopenharmony_ci * against 48158c2ecf20Sopenharmony_ci */ 48168c2ecf20Sopenharmony_ci fw_info = find_fw_info(CHELSIO_CHIP_VERSION(adap->params.chip)); 48178c2ecf20Sopenharmony_ci if (fw_info == NULL) { 48188c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 48198c2ecf20Sopenharmony_ci "unable to get firmware info for chip %d.\n", 48208c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(adap->params.chip)); 48218c2ecf20Sopenharmony_ci return -EINVAL; 48228c2ecf20Sopenharmony_ci } 48238c2ecf20Sopenharmony_ci 48248c2ecf20Sopenharmony_ci /* allocate memory to read the header of the firmware on the 48258c2ecf20Sopenharmony_ci * card 48268c2ecf20Sopenharmony_ci */ 48278c2ecf20Sopenharmony_ci card_fw = kvzalloc(sizeof(*card_fw), GFP_KERNEL); 48288c2ecf20Sopenharmony_ci if (!card_fw) { 48298c2ecf20Sopenharmony_ci ret = -ENOMEM; 48308c2ecf20Sopenharmony_ci goto bye; 48318c2ecf20Sopenharmony_ci } 48328c2ecf20Sopenharmony_ci 48338c2ecf20Sopenharmony_ci /* Get FW from from /lib/firmware/ */ 48348c2ecf20Sopenharmony_ci ret = request_firmware(&fw, fw_info->fw_mod_name, 48358c2ecf20Sopenharmony_ci adap->pdev_dev); 48368c2ecf20Sopenharmony_ci if (ret < 0) { 48378c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 48388c2ecf20Sopenharmony_ci "unable to load firmware image %s, error %d\n", 48398c2ecf20Sopenharmony_ci fw_info->fw_mod_name, ret); 48408c2ecf20Sopenharmony_ci } else { 48418c2ecf20Sopenharmony_ci fw_data = fw->data; 48428c2ecf20Sopenharmony_ci fw_size = fw->size; 48438c2ecf20Sopenharmony_ci } 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci /* upgrade FW logic */ 48468c2ecf20Sopenharmony_ci ret = t4_prep_fw(adap, fw_info, fw_data, fw_size, card_fw, 48478c2ecf20Sopenharmony_ci state, &reset); 48488c2ecf20Sopenharmony_ci 48498c2ecf20Sopenharmony_ci /* Cleaning up */ 48508c2ecf20Sopenharmony_ci release_firmware(fw); 48518c2ecf20Sopenharmony_ci kvfree(card_fw); 48528c2ecf20Sopenharmony_ci 48538c2ecf20Sopenharmony_ci if (ret < 0) 48548c2ecf20Sopenharmony_ci goto bye; 48558c2ecf20Sopenharmony_ci } 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci /* If the firmware is initialized already, emit a simply note to that 48588c2ecf20Sopenharmony_ci * effect. Otherwise, it's time to try initializing the adapter. 48598c2ecf20Sopenharmony_ci */ 48608c2ecf20Sopenharmony_ci if (state == DEV_STATE_INIT) { 48618c2ecf20Sopenharmony_ci ret = adap_config_hma(adap); 48628c2ecf20Sopenharmony_ci if (ret) 48638c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 48648c2ecf20Sopenharmony_ci "HMA configuration failed with error %d\n", 48658c2ecf20Sopenharmony_ci ret); 48668c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, "Coming up as %s: "\ 48678c2ecf20Sopenharmony_ci "Adapter already initialized\n", 48688c2ecf20Sopenharmony_ci adap->flags & CXGB4_MASTER_PF ? "MASTER" : "SLAVE"); 48698c2ecf20Sopenharmony_ci } else { 48708c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, "Coming up as MASTER: "\ 48718c2ecf20Sopenharmony_ci "Initializing adapter\n"); 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci /* Find out whether we're dealing with a version of the 48748c2ecf20Sopenharmony_ci * firmware which has configuration file support. 48758c2ecf20Sopenharmony_ci */ 48768c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 48778c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); 48788c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, 48798c2ecf20Sopenharmony_ci params, val); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci /* If the firmware doesn't support Configuration Files, 48828c2ecf20Sopenharmony_ci * return an error. 48838c2ecf20Sopenharmony_ci */ 48848c2ecf20Sopenharmony_ci if (ret < 0) { 48858c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "firmware doesn't support " 48868c2ecf20Sopenharmony_ci "Firmware Configuration Files\n"); 48878c2ecf20Sopenharmony_ci goto bye; 48888c2ecf20Sopenharmony_ci } 48898c2ecf20Sopenharmony_ci 48908c2ecf20Sopenharmony_ci /* The firmware provides us with a memory buffer where we can 48918c2ecf20Sopenharmony_ci * load a Configuration File from the host if we want to 48928c2ecf20Sopenharmony_ci * override the Configuration File in flash. 48938c2ecf20Sopenharmony_ci */ 48948c2ecf20Sopenharmony_ci ret = adap_init0_config(adap, reset); 48958c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 48968c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "no Configuration File " 48978c2ecf20Sopenharmony_ci "present on adapter.\n"); 48988c2ecf20Sopenharmony_ci goto bye; 48998c2ecf20Sopenharmony_ci } 49008c2ecf20Sopenharmony_ci if (ret < 0) { 49018c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "could not initialize " 49028c2ecf20Sopenharmony_ci "adapter, error %d\n", -ret); 49038c2ecf20Sopenharmony_ci goto bye; 49048c2ecf20Sopenharmony_ci } 49058c2ecf20Sopenharmony_ci } 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_ci /* Now that we've successfully configured and initialized the adapter 49088c2ecf20Sopenharmony_ci * (or found it already initialized), we can ask the Firmware what 49098c2ecf20Sopenharmony_ci * resources it has provisioned for us. 49108c2ecf20Sopenharmony_ci */ 49118c2ecf20Sopenharmony_ci ret = t4_get_pfres(adap); 49128c2ecf20Sopenharmony_ci if (ret) { 49138c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, 49148c2ecf20Sopenharmony_ci "Unable to retrieve resource provisioning information\n"); 49158c2ecf20Sopenharmony_ci goto bye; 49168c2ecf20Sopenharmony_ci } 49178c2ecf20Sopenharmony_ci 49188c2ecf20Sopenharmony_ci /* Grab VPD parameters. This should be done after we establish a 49198c2ecf20Sopenharmony_ci * connection to the firmware since some of the VPD parameters 49208c2ecf20Sopenharmony_ci * (notably the Core Clock frequency) are retrieved via requests to 49218c2ecf20Sopenharmony_ci * the firmware. On the other hand, we need these fairly early on 49228c2ecf20Sopenharmony_ci * so we do this right after getting ahold of the firmware. 49238c2ecf20Sopenharmony_ci * 49248c2ecf20Sopenharmony_ci * We need to do this after initializing the adapter because someone 49258c2ecf20Sopenharmony_ci * could have FLASHed a new VPD which won't be read by the firmware 49268c2ecf20Sopenharmony_ci * until we do the RESET ... 49278c2ecf20Sopenharmony_ci */ 49288c2ecf20Sopenharmony_ci if (!vpd_skip) { 49298c2ecf20Sopenharmony_ci ret = t4_get_vpd_params(adap, &adap->params.vpd); 49308c2ecf20Sopenharmony_ci if (ret < 0) 49318c2ecf20Sopenharmony_ci goto bye; 49328c2ecf20Sopenharmony_ci } 49338c2ecf20Sopenharmony_ci 49348c2ecf20Sopenharmony_ci /* Find out what ports are available to us. Note that we need to do 49358c2ecf20Sopenharmony_ci * this before calling adap_init0_no_config() since it needs nports 49368c2ecf20Sopenharmony_ci * and portvec ... 49378c2ecf20Sopenharmony_ci */ 49388c2ecf20Sopenharmony_ci v = 49398c2ecf20Sopenharmony_ci FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 49408c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PORTVEC); 49418c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &v, &port_vec); 49428c2ecf20Sopenharmony_ci if (ret < 0) 49438c2ecf20Sopenharmony_ci goto bye; 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci adap->params.nports = hweight32(port_vec); 49468c2ecf20Sopenharmony_ci adap->params.portvec = port_vec; 49478c2ecf20Sopenharmony_ci 49488c2ecf20Sopenharmony_ci /* Give the SGE code a chance to pull in anything that it needs ... 49498c2ecf20Sopenharmony_ci * Note that this must be called after we retrieve our VPD parameters 49508c2ecf20Sopenharmony_ci * in order to know how to convert core ticks to seconds, etc. 49518c2ecf20Sopenharmony_ci */ 49528c2ecf20Sopenharmony_ci ret = t4_sge_init(adap); 49538c2ecf20Sopenharmony_ci if (ret < 0) 49548c2ecf20Sopenharmony_ci goto bye; 49558c2ecf20Sopenharmony_ci 49568c2ecf20Sopenharmony_ci /* Grab the SGE Doorbell Queue Timer values. If successful, that 49578c2ecf20Sopenharmony_ci * indicates that the Firmware and Hardware support this. 49588c2ecf20Sopenharmony_ci */ 49598c2ecf20Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 49608c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK)); 49618c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 49628c2ecf20Sopenharmony_ci 1, params, val); 49638c2ecf20Sopenharmony_ci 49648c2ecf20Sopenharmony_ci if (!ret) { 49658c2ecf20Sopenharmony_ci adap->sge.dbqtimer_tick = val[0]; 49668c2ecf20Sopenharmony_ci ret = t4_read_sge_dbqtimers(adap, 49678c2ecf20Sopenharmony_ci ARRAY_SIZE(adap->sge.dbqtimer_val), 49688c2ecf20Sopenharmony_ci adap->sge.dbqtimer_val); 49698c2ecf20Sopenharmony_ci } 49708c2ecf20Sopenharmony_ci 49718c2ecf20Sopenharmony_ci if (!ret) 49728c2ecf20Sopenharmony_ci adap->flags |= CXGB4_SGE_DBQ_TIMER; 49738c2ecf20Sopenharmony_ci 49748c2ecf20Sopenharmony_ci if (is_bypass_device(adap->pdev->device)) 49758c2ecf20Sopenharmony_ci adap->params.bypass = 1; 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci /* 49788c2ecf20Sopenharmony_ci * Grab some of our basic fundamental operating parameters. 49798c2ecf20Sopenharmony_ci */ 49808c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(EQ_START); 49818c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(L2T_START); 49828c2ecf20Sopenharmony_ci params[2] = FW_PARAM_PFVF(L2T_END); 49838c2ecf20Sopenharmony_ci params[3] = FW_PARAM_PFVF(FILTER_START); 49848c2ecf20Sopenharmony_ci params[4] = FW_PARAM_PFVF(FILTER_END); 49858c2ecf20Sopenharmony_ci params[5] = FW_PARAM_PFVF(IQFLINT_START); 49868c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params, val); 49878c2ecf20Sopenharmony_ci if (ret < 0) 49888c2ecf20Sopenharmony_ci goto bye; 49898c2ecf20Sopenharmony_ci adap->sge.egr_start = val[0]; 49908c2ecf20Sopenharmony_ci adap->l2t_start = val[1]; 49918c2ecf20Sopenharmony_ci adap->l2t_end = val[2]; 49928c2ecf20Sopenharmony_ci adap->tids.ftid_base = val[3]; 49938c2ecf20Sopenharmony_ci adap->tids.nftids = val[4] - val[3] + 1; 49948c2ecf20Sopenharmony_ci adap->sge.ingr_start = val[5]; 49958c2ecf20Sopenharmony_ci 49968c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) { 49978c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(HPFILTER_START); 49988c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(HPFILTER_END); 49998c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 50008c2ecf20Sopenharmony_ci params, val); 50018c2ecf20Sopenharmony_ci if (ret < 0) 50028c2ecf20Sopenharmony_ci goto bye; 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_ci adap->tids.hpftid_base = val[0]; 50058c2ecf20Sopenharmony_ci adap->tids.nhpftids = val[1] - val[0] + 1; 50068c2ecf20Sopenharmony_ci 50078c2ecf20Sopenharmony_ci /* Read the raw mps entries. In T6, the last 2 tcam entries 50088c2ecf20Sopenharmony_ci * are reserved for raw mac addresses (rawf = 2, one per port). 50098c2ecf20Sopenharmony_ci */ 50108c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(RAWF_START); 50118c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(RAWF_END); 50128c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 50138c2ecf20Sopenharmony_ci params, val); 50148c2ecf20Sopenharmony_ci if (ret == 0) { 50158c2ecf20Sopenharmony_ci adap->rawf_start = val[0]; 50168c2ecf20Sopenharmony_ci adap->rawf_cnt = val[1] - val[0] + 1; 50178c2ecf20Sopenharmony_ci } 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci adap->tids.tid_base = 50208c2ecf20Sopenharmony_ci t4_read_reg(adap, LE_DB_ACTIVE_TABLE_START_INDEX_A); 50218c2ecf20Sopenharmony_ci } 50228c2ecf20Sopenharmony_ci 50238c2ecf20Sopenharmony_ci /* qids (ingress/egress) returned from firmware can be anywhere 50248c2ecf20Sopenharmony_ci * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END. 50258c2ecf20Sopenharmony_ci * Hence driver needs to allocate memory for this range to 50268c2ecf20Sopenharmony_ci * store the queue info. Get the highest IQFLINT/EQ index returned 50278c2ecf20Sopenharmony_ci * in FW_EQ_*_CMD.alloc command. 50288c2ecf20Sopenharmony_ci */ 50298c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(EQ_END); 50308c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(IQFLINT_END); 50318c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val); 50328c2ecf20Sopenharmony_ci if (ret < 0) 50338c2ecf20Sopenharmony_ci goto bye; 50348c2ecf20Sopenharmony_ci adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1; 50358c2ecf20Sopenharmony_ci adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1; 50368c2ecf20Sopenharmony_ci 50378c2ecf20Sopenharmony_ci adap->sge.egr_map = kcalloc(adap->sge.egr_sz, 50388c2ecf20Sopenharmony_ci sizeof(*adap->sge.egr_map), GFP_KERNEL); 50398c2ecf20Sopenharmony_ci if (!adap->sge.egr_map) { 50408c2ecf20Sopenharmony_ci ret = -ENOMEM; 50418c2ecf20Sopenharmony_ci goto bye; 50428c2ecf20Sopenharmony_ci } 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz, 50458c2ecf20Sopenharmony_ci sizeof(*adap->sge.ingr_map), GFP_KERNEL); 50468c2ecf20Sopenharmony_ci if (!adap->sge.ingr_map) { 50478c2ecf20Sopenharmony_ci ret = -ENOMEM; 50488c2ecf20Sopenharmony_ci goto bye; 50498c2ecf20Sopenharmony_ci } 50508c2ecf20Sopenharmony_ci 50518c2ecf20Sopenharmony_ci /* Allocate the memory for the vaious egress queue bitmaps 50528c2ecf20Sopenharmony_ci * ie starving_fl, txq_maperr and blocked_fl. 50538c2ecf20Sopenharmony_ci */ 50548c2ecf20Sopenharmony_ci adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), 50558c2ecf20Sopenharmony_ci sizeof(long), GFP_KERNEL); 50568c2ecf20Sopenharmony_ci if (!adap->sge.starving_fl) { 50578c2ecf20Sopenharmony_ci ret = -ENOMEM; 50588c2ecf20Sopenharmony_ci goto bye; 50598c2ecf20Sopenharmony_ci } 50608c2ecf20Sopenharmony_ci 50618c2ecf20Sopenharmony_ci adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), 50628c2ecf20Sopenharmony_ci sizeof(long), GFP_KERNEL); 50638c2ecf20Sopenharmony_ci if (!adap->sge.txq_maperr) { 50648c2ecf20Sopenharmony_ci ret = -ENOMEM; 50658c2ecf20Sopenharmony_ci goto bye; 50668c2ecf20Sopenharmony_ci } 50678c2ecf20Sopenharmony_ci 50688c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 50698c2ecf20Sopenharmony_ci adap->sge.blocked_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), 50708c2ecf20Sopenharmony_ci sizeof(long), GFP_KERNEL); 50718c2ecf20Sopenharmony_ci if (!adap->sge.blocked_fl) { 50728c2ecf20Sopenharmony_ci ret = -ENOMEM; 50738c2ecf20Sopenharmony_ci goto bye; 50748c2ecf20Sopenharmony_ci } 50758c2ecf20Sopenharmony_ci bitmap_zero(adap->sge.blocked_fl, adap->sge.egr_sz); 50768c2ecf20Sopenharmony_ci#endif 50778c2ecf20Sopenharmony_ci 50788c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(CLIP_START); 50798c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(CLIP_END); 50808c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val); 50818c2ecf20Sopenharmony_ci if (ret < 0) 50828c2ecf20Sopenharmony_ci goto bye; 50838c2ecf20Sopenharmony_ci adap->clipt_start = val[0]; 50848c2ecf20Sopenharmony_ci adap->clipt_end = val[1]; 50858c2ecf20Sopenharmony_ci 50868c2ecf20Sopenharmony_ci /* Get the supported number of traffic classes */ 50878c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(NUM_TM_CLASS); 50888c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, val); 50898c2ecf20Sopenharmony_ci if (ret < 0) { 50908c2ecf20Sopenharmony_ci /* We couldn't retrieve the number of Traffic Classes 50918c2ecf20Sopenharmony_ci * supported by the hardware/firmware. So we hard 50928c2ecf20Sopenharmony_ci * code it here. 50938c2ecf20Sopenharmony_ci */ 50948c2ecf20Sopenharmony_ci adap->params.nsched_cls = is_t4(adap->params.chip) ? 15 : 16; 50958c2ecf20Sopenharmony_ci } else { 50968c2ecf20Sopenharmony_ci adap->params.nsched_cls = val[0]; 50978c2ecf20Sopenharmony_ci } 50988c2ecf20Sopenharmony_ci 50998c2ecf20Sopenharmony_ci /* query params related to active filter region */ 51008c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START); 51018c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END); 51028c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val); 51038c2ecf20Sopenharmony_ci /* If Active filter size is set we enable establishing 51048c2ecf20Sopenharmony_ci * offload connection through firmware work request 51058c2ecf20Sopenharmony_ci */ 51068c2ecf20Sopenharmony_ci if ((val[0] != val[1]) && (ret >= 0)) { 51078c2ecf20Sopenharmony_ci adap->flags |= CXGB4_FW_OFLD_CONN; 51088c2ecf20Sopenharmony_ci adap->tids.aftid_base = val[0]; 51098c2ecf20Sopenharmony_ci adap->tids.aftid_end = val[1]; 51108c2ecf20Sopenharmony_ci } 51118c2ecf20Sopenharmony_ci 51128c2ecf20Sopenharmony_ci /* If we're running on newer firmware, let it know that we're 51138c2ecf20Sopenharmony_ci * prepared to deal with encapsulated CPL messages. Older 51148c2ecf20Sopenharmony_ci * firmware won't understand this and we'll just get 51158c2ecf20Sopenharmony_ci * unencapsulated messages ... 51168c2ecf20Sopenharmony_ci */ 51178c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 51188c2ecf20Sopenharmony_ci val[0] = 1; 51198c2ecf20Sopenharmony_ci (void)t4_set_params(adap, adap->mbox, adap->pf, 0, 1, params, val); 51208c2ecf20Sopenharmony_ci 51218c2ecf20Sopenharmony_ci /* 51228c2ecf20Sopenharmony_ci * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL 51238c2ecf20Sopenharmony_ci * capability. Earlier versions of the firmware didn't have the 51248c2ecf20Sopenharmony_ci * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no 51258c2ecf20Sopenharmony_ci * permission to use ULPTX MEMWRITE DSGL. 51268c2ecf20Sopenharmony_ci */ 51278c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 51288c2ecf20Sopenharmony_ci adap->params.ulptx_memwrite_dsgl = false; 51298c2ecf20Sopenharmony_ci } else { 51308c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL); 51318c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 51328c2ecf20Sopenharmony_ci 1, params, val); 51338c2ecf20Sopenharmony_ci adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0); 51348c2ecf20Sopenharmony_ci } 51358c2ecf20Sopenharmony_ci 51368c2ecf20Sopenharmony_ci /* See if FW supports FW_RI_FR_NSMR_TPTE_WR work request */ 51378c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(RI_FR_NSMR_TPTE_WR); 51388c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 51398c2ecf20Sopenharmony_ci 1, params, val); 51408c2ecf20Sopenharmony_ci adap->params.fr_nsmr_tpte_wr_support = (ret == 0 && val[0] != 0); 51418c2ecf20Sopenharmony_ci 51428c2ecf20Sopenharmony_ci /* See if FW supports FW_FILTER2 work request */ 51438c2ecf20Sopenharmony_ci if (is_t4(adap->params.chip)) { 51448c2ecf20Sopenharmony_ci adap->params.filter2_wr_support = 0; 51458c2ecf20Sopenharmony_ci } else { 51468c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(FILTER2_WR); 51478c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 51488c2ecf20Sopenharmony_ci 1, params, val); 51498c2ecf20Sopenharmony_ci adap->params.filter2_wr_support = (ret == 0 && val[0] != 0); 51508c2ecf20Sopenharmony_ci } 51518c2ecf20Sopenharmony_ci 51528c2ecf20Sopenharmony_ci /* Check if FW supports returning vin and smt index. 51538c2ecf20Sopenharmony_ci * If this is not supported, driver will interpret 51548c2ecf20Sopenharmony_ci * these values from viid. 51558c2ecf20Sopenharmony_ci */ 51568c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(OPAQUE_VIID_SMT_EXTN); 51578c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 51588c2ecf20Sopenharmony_ci 1, params, val); 51598c2ecf20Sopenharmony_ci adap->params.viid_smt_extn_support = (ret == 0 && val[0] != 0); 51608c2ecf20Sopenharmony_ci 51618c2ecf20Sopenharmony_ci /* 51628c2ecf20Sopenharmony_ci * Get device capabilities so we can determine what resources we need 51638c2ecf20Sopenharmony_ci * to manage. 51648c2ecf20Sopenharmony_ci */ 51658c2ecf20Sopenharmony_ci memset(&caps_cmd, 0, sizeof(caps_cmd)); 51668c2ecf20Sopenharmony_ci caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 51678c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F); 51688c2ecf20Sopenharmony_ci caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); 51698c2ecf20Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd), 51708c2ecf20Sopenharmony_ci &caps_cmd); 51718c2ecf20Sopenharmony_ci if (ret < 0) 51728c2ecf20Sopenharmony_ci goto bye; 51738c2ecf20Sopenharmony_ci 51748c2ecf20Sopenharmony_ci /* hash filter has some mandatory register settings to be tested and for 51758c2ecf20Sopenharmony_ci * that it needs to test whether offload is enabled or not, hence 51768c2ecf20Sopenharmony_ci * checking and setting it here. 51778c2ecf20Sopenharmony_ci */ 51788c2ecf20Sopenharmony_ci if (caps_cmd.ofldcaps) 51798c2ecf20Sopenharmony_ci adap->params.offload = 1; 51808c2ecf20Sopenharmony_ci 51818c2ecf20Sopenharmony_ci if (caps_cmd.ofldcaps || 51828c2ecf20Sopenharmony_ci (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) || 51838c2ecf20Sopenharmony_ci (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD))) { 51848c2ecf20Sopenharmony_ci /* query offload-related parameters */ 51858c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(NTID); 51868c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(SERVER_START); 51878c2ecf20Sopenharmony_ci params[2] = FW_PARAM_PFVF(SERVER_END); 51888c2ecf20Sopenharmony_ci params[3] = FW_PARAM_PFVF(TDDP_START); 51898c2ecf20Sopenharmony_ci params[4] = FW_PARAM_PFVF(TDDP_END); 51908c2ecf20Sopenharmony_ci params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 51918c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, 51928c2ecf20Sopenharmony_ci params, val); 51938c2ecf20Sopenharmony_ci if (ret < 0) 51948c2ecf20Sopenharmony_ci goto bye; 51958c2ecf20Sopenharmony_ci adap->tids.ntids = val[0]; 51968c2ecf20Sopenharmony_ci adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); 51978c2ecf20Sopenharmony_ci adap->tids.stid_base = val[1]; 51988c2ecf20Sopenharmony_ci adap->tids.nstids = val[2] - val[1] + 1; 51998c2ecf20Sopenharmony_ci /* 52008c2ecf20Sopenharmony_ci * Setup server filter region. Divide the available filter 52018c2ecf20Sopenharmony_ci * region into two parts. Regular filters get 1/3rd and server 52028c2ecf20Sopenharmony_ci * filters get 2/3rd part. This is only enabled if workarond 52038c2ecf20Sopenharmony_ci * path is enabled. 52048c2ecf20Sopenharmony_ci * 1. For regular filters. 52058c2ecf20Sopenharmony_ci * 2. Server filter: This are special filters which are used 52068c2ecf20Sopenharmony_ci * to redirect SYN packets to offload queue. 52078c2ecf20Sopenharmony_ci */ 52088c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_FW_OFLD_CONN && !is_bypass(adap)) { 52098c2ecf20Sopenharmony_ci adap->tids.sftid_base = adap->tids.ftid_base + 52108c2ecf20Sopenharmony_ci DIV_ROUND_UP(adap->tids.nftids, 3); 52118c2ecf20Sopenharmony_ci adap->tids.nsftids = adap->tids.nftids - 52128c2ecf20Sopenharmony_ci DIV_ROUND_UP(adap->tids.nftids, 3); 52138c2ecf20Sopenharmony_ci adap->tids.nftids = adap->tids.sftid_base - 52148c2ecf20Sopenharmony_ci adap->tids.ftid_base; 52158c2ecf20Sopenharmony_ci } 52168c2ecf20Sopenharmony_ci adap->vres.ddp.start = val[3]; 52178c2ecf20Sopenharmony_ci adap->vres.ddp.size = val[4] - val[3] + 1; 52188c2ecf20Sopenharmony_ci adap->params.ofldq_wr_cred = val[5]; 52198c2ecf20Sopenharmony_ci 52208c2ecf20Sopenharmony_ci if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) { 52218c2ecf20Sopenharmony_ci init_hash_filter(adap); 52228c2ecf20Sopenharmony_ci } else { 52238c2ecf20Sopenharmony_ci adap->num_ofld_uld += 1; 52248c2ecf20Sopenharmony_ci } 52258c2ecf20Sopenharmony_ci 52268c2ecf20Sopenharmony_ci if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD)) { 52278c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(ETHOFLD_START); 52288c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(ETHOFLD_END); 52298c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 52308c2ecf20Sopenharmony_ci params, val); 52318c2ecf20Sopenharmony_ci if (!ret) { 52328c2ecf20Sopenharmony_ci adap->tids.eotid_base = val[0]; 52338c2ecf20Sopenharmony_ci adap->tids.neotids = min_t(u32, MAX_ATIDS, 52348c2ecf20Sopenharmony_ci val[1] - val[0] + 1); 52358c2ecf20Sopenharmony_ci adap->params.ethofld = 1; 52368c2ecf20Sopenharmony_ci } 52378c2ecf20Sopenharmony_ci } 52388c2ecf20Sopenharmony_ci } 52398c2ecf20Sopenharmony_ci if (caps_cmd.rdmacaps) { 52408c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(STAG_START); 52418c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(STAG_END); 52428c2ecf20Sopenharmony_ci params[2] = FW_PARAM_PFVF(RQ_START); 52438c2ecf20Sopenharmony_ci params[3] = FW_PARAM_PFVF(RQ_END); 52448c2ecf20Sopenharmony_ci params[4] = FW_PARAM_PFVF(PBL_START); 52458c2ecf20Sopenharmony_ci params[5] = FW_PARAM_PFVF(PBL_END); 52468c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, 52478c2ecf20Sopenharmony_ci params, val); 52488c2ecf20Sopenharmony_ci if (ret < 0) 52498c2ecf20Sopenharmony_ci goto bye; 52508c2ecf20Sopenharmony_ci adap->vres.stag.start = val[0]; 52518c2ecf20Sopenharmony_ci adap->vres.stag.size = val[1] - val[0] + 1; 52528c2ecf20Sopenharmony_ci adap->vres.rq.start = val[2]; 52538c2ecf20Sopenharmony_ci adap->vres.rq.size = val[3] - val[2] + 1; 52548c2ecf20Sopenharmony_ci adap->vres.pbl.start = val[4]; 52558c2ecf20Sopenharmony_ci adap->vres.pbl.size = val[5] - val[4] + 1; 52568c2ecf20Sopenharmony_ci 52578c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(SRQ_START); 52588c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(SRQ_END); 52598c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 52608c2ecf20Sopenharmony_ci params, val); 52618c2ecf20Sopenharmony_ci if (!ret) { 52628c2ecf20Sopenharmony_ci adap->vres.srq.start = val[0]; 52638c2ecf20Sopenharmony_ci adap->vres.srq.size = val[1] - val[0] + 1; 52648c2ecf20Sopenharmony_ci } 52658c2ecf20Sopenharmony_ci if (adap->vres.srq.size) { 52668c2ecf20Sopenharmony_ci adap->srq = t4_init_srq(adap->vres.srq.size); 52678c2ecf20Sopenharmony_ci if (!adap->srq) 52688c2ecf20Sopenharmony_ci dev_warn(&adap->pdev->dev, "could not allocate SRQ, continuing\n"); 52698c2ecf20Sopenharmony_ci } 52708c2ecf20Sopenharmony_ci 52718c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(SQRQ_START); 52728c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(SQRQ_END); 52738c2ecf20Sopenharmony_ci params[2] = FW_PARAM_PFVF(CQ_START); 52748c2ecf20Sopenharmony_ci params[3] = FW_PARAM_PFVF(CQ_END); 52758c2ecf20Sopenharmony_ci params[4] = FW_PARAM_PFVF(OCQ_START); 52768c2ecf20Sopenharmony_ci params[5] = FW_PARAM_PFVF(OCQ_END); 52778c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params, 52788c2ecf20Sopenharmony_ci val); 52798c2ecf20Sopenharmony_ci if (ret < 0) 52808c2ecf20Sopenharmony_ci goto bye; 52818c2ecf20Sopenharmony_ci adap->vres.qp.start = val[0]; 52828c2ecf20Sopenharmony_ci adap->vres.qp.size = val[1] - val[0] + 1; 52838c2ecf20Sopenharmony_ci adap->vres.cq.start = val[2]; 52848c2ecf20Sopenharmony_ci adap->vres.cq.size = val[3] - val[2] + 1; 52858c2ecf20Sopenharmony_ci adap->vres.ocq.start = val[4]; 52868c2ecf20Sopenharmony_ci adap->vres.ocq.size = val[5] - val[4] + 1; 52878c2ecf20Sopenharmony_ci 52888c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(MAXORDIRD_QP); 52898c2ecf20Sopenharmony_ci params[1] = FW_PARAM_DEV(MAXIRD_ADAPTER); 52908c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, 52918c2ecf20Sopenharmony_ci val); 52928c2ecf20Sopenharmony_ci if (ret < 0) { 52938c2ecf20Sopenharmony_ci adap->params.max_ordird_qp = 8; 52948c2ecf20Sopenharmony_ci adap->params.max_ird_adapter = 32 * adap->tids.ntids; 52958c2ecf20Sopenharmony_ci ret = 0; 52968c2ecf20Sopenharmony_ci } else { 52978c2ecf20Sopenharmony_ci adap->params.max_ordird_qp = val[0]; 52988c2ecf20Sopenharmony_ci adap->params.max_ird_adapter = val[1]; 52998c2ecf20Sopenharmony_ci } 53008c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 53018c2ecf20Sopenharmony_ci "max_ordird_qp %d max_ird_adapter %d\n", 53028c2ecf20Sopenharmony_ci adap->params.max_ordird_qp, 53038c2ecf20Sopenharmony_ci adap->params.max_ird_adapter); 53048c2ecf20Sopenharmony_ci 53058c2ecf20Sopenharmony_ci /* Enable write_with_immediate if FW supports it */ 53068c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(RDMA_WRITE_WITH_IMM); 53078c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, 53088c2ecf20Sopenharmony_ci val); 53098c2ecf20Sopenharmony_ci adap->params.write_w_imm_support = (ret == 0 && val[0] != 0); 53108c2ecf20Sopenharmony_ci 53118c2ecf20Sopenharmony_ci /* Enable write_cmpl if FW supports it */ 53128c2ecf20Sopenharmony_ci params[0] = FW_PARAM_DEV(RI_WRITE_CMPL_WR); 53138c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, 53148c2ecf20Sopenharmony_ci val); 53158c2ecf20Sopenharmony_ci adap->params.write_cmpl_support = (ret == 0 && val[0] != 0); 53168c2ecf20Sopenharmony_ci adap->num_ofld_uld += 2; 53178c2ecf20Sopenharmony_ci } 53188c2ecf20Sopenharmony_ci if (caps_cmd.iscsicaps) { 53198c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(ISCSI_START); 53208c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(ISCSI_END); 53218c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 53228c2ecf20Sopenharmony_ci params, val); 53238c2ecf20Sopenharmony_ci if (ret < 0) 53248c2ecf20Sopenharmony_ci goto bye; 53258c2ecf20Sopenharmony_ci adap->vres.iscsi.start = val[0]; 53268c2ecf20Sopenharmony_ci adap->vres.iscsi.size = val[1] - val[0] + 1; 53278c2ecf20Sopenharmony_ci if (is_t6(adap->params.chip)) { 53288c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(PPOD_EDRAM_START); 53298c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(PPOD_EDRAM_END); 53308c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 53318c2ecf20Sopenharmony_ci params, val); 53328c2ecf20Sopenharmony_ci if (!ret) { 53338c2ecf20Sopenharmony_ci adap->vres.ppod_edram.start = val[0]; 53348c2ecf20Sopenharmony_ci adap->vres.ppod_edram.size = 53358c2ecf20Sopenharmony_ci val[1] - val[0] + 1; 53368c2ecf20Sopenharmony_ci 53378c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 53388c2ecf20Sopenharmony_ci "ppod edram start 0x%x end 0x%x size 0x%x\n", 53398c2ecf20Sopenharmony_ci val[0], val[1], 53408c2ecf20Sopenharmony_ci adap->vres.ppod_edram.size); 53418c2ecf20Sopenharmony_ci } 53428c2ecf20Sopenharmony_ci } 53438c2ecf20Sopenharmony_ci /* LIO target and cxgb4i initiaitor */ 53448c2ecf20Sopenharmony_ci adap->num_ofld_uld += 2; 53458c2ecf20Sopenharmony_ci } 53468c2ecf20Sopenharmony_ci if (caps_cmd.cryptocaps) { 53478c2ecf20Sopenharmony_ci if (ntohs(caps_cmd.cryptocaps) & 53488c2ecf20Sopenharmony_ci FW_CAPS_CONFIG_CRYPTO_LOOKASIDE) { 53498c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(NCRYPTO_LOOKASIDE); 53508c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 53518c2ecf20Sopenharmony_ci 2, params, val); 53528c2ecf20Sopenharmony_ci if (ret < 0) { 53538c2ecf20Sopenharmony_ci if (ret != -EINVAL) 53548c2ecf20Sopenharmony_ci goto bye; 53558c2ecf20Sopenharmony_ci } else { 53568c2ecf20Sopenharmony_ci adap->vres.ncrypto_fc = val[0]; 53578c2ecf20Sopenharmony_ci } 53588c2ecf20Sopenharmony_ci adap->num_ofld_uld += 1; 53598c2ecf20Sopenharmony_ci } 53608c2ecf20Sopenharmony_ci if (ntohs(caps_cmd.cryptocaps) & 53618c2ecf20Sopenharmony_ci FW_CAPS_CONFIG_TLS_INLINE) { 53628c2ecf20Sopenharmony_ci params[0] = FW_PARAM_PFVF(TLS_START); 53638c2ecf20Sopenharmony_ci params[1] = FW_PARAM_PFVF(TLS_END); 53648c2ecf20Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 53658c2ecf20Sopenharmony_ci 2, params, val); 53668c2ecf20Sopenharmony_ci if (ret < 0) 53678c2ecf20Sopenharmony_ci goto bye; 53688c2ecf20Sopenharmony_ci adap->vres.key.start = val[0]; 53698c2ecf20Sopenharmony_ci adap->vres.key.size = val[1] - val[0] + 1; 53708c2ecf20Sopenharmony_ci adap->num_uld += 1; 53718c2ecf20Sopenharmony_ci } 53728c2ecf20Sopenharmony_ci adap->params.crypto = ntohs(caps_cmd.cryptocaps); 53738c2ecf20Sopenharmony_ci } 53748c2ecf20Sopenharmony_ci 53758c2ecf20Sopenharmony_ci /* The MTU/MSS Table is initialized by now, so load their values. If 53768c2ecf20Sopenharmony_ci * we're initializing the adapter, then we'll make any modifications 53778c2ecf20Sopenharmony_ci * we want to the MTU/MSS Table and also initialize the congestion 53788c2ecf20Sopenharmony_ci * parameters. 53798c2ecf20Sopenharmony_ci */ 53808c2ecf20Sopenharmony_ci t4_read_mtu_tbl(adap, adap->params.mtus, NULL); 53818c2ecf20Sopenharmony_ci if (state != DEV_STATE_INIT) { 53828c2ecf20Sopenharmony_ci int i; 53838c2ecf20Sopenharmony_ci 53848c2ecf20Sopenharmony_ci /* The default MTU Table contains values 1492 and 1500. 53858c2ecf20Sopenharmony_ci * However, for TCP, it's better to have two values which are 53868c2ecf20Sopenharmony_ci * a multiple of 8 +/- 4 bytes apart near this popular MTU. 53878c2ecf20Sopenharmony_ci * This allows us to have a TCP Data Payload which is a 53888c2ecf20Sopenharmony_ci * multiple of 8 regardless of what combination of TCP Options 53898c2ecf20Sopenharmony_ci * are in use (always a multiple of 4 bytes) which is 53908c2ecf20Sopenharmony_ci * important for performance reasons. For instance, if no 53918c2ecf20Sopenharmony_ci * options are in use, then we have a 20-byte IP header and a 53928c2ecf20Sopenharmony_ci * 20-byte TCP header. In this case, a 1500-byte MSS would 53938c2ecf20Sopenharmony_ci * result in a TCP Data Payload of 1500 - 40 == 1460 bytes 53948c2ecf20Sopenharmony_ci * which is not a multiple of 8. So using an MSS of 1488 in 53958c2ecf20Sopenharmony_ci * this case results in a TCP Data Payload of 1448 bytes which 53968c2ecf20Sopenharmony_ci * is a multiple of 8. On the other hand, if 12-byte TCP Time 53978c2ecf20Sopenharmony_ci * Stamps have been negotiated, then an MTU of 1500 bytes 53988c2ecf20Sopenharmony_ci * results in a TCP Data Payload of 1448 bytes which, as 53998c2ecf20Sopenharmony_ci * above, is a multiple of 8 bytes ... 54008c2ecf20Sopenharmony_ci */ 54018c2ecf20Sopenharmony_ci for (i = 0; i < NMTUS; i++) 54028c2ecf20Sopenharmony_ci if (adap->params.mtus[i] == 1492) { 54038c2ecf20Sopenharmony_ci adap->params.mtus[i] = 1488; 54048c2ecf20Sopenharmony_ci break; 54058c2ecf20Sopenharmony_ci } 54068c2ecf20Sopenharmony_ci 54078c2ecf20Sopenharmony_ci t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, 54088c2ecf20Sopenharmony_ci adap->params.b_wnd); 54098c2ecf20Sopenharmony_ci } 54108c2ecf20Sopenharmony_ci t4_init_sge_params(adap); 54118c2ecf20Sopenharmony_ci adap->flags |= CXGB4_FW_OK; 54128c2ecf20Sopenharmony_ci t4_init_tp_params(adap, true); 54138c2ecf20Sopenharmony_ci return 0; 54148c2ecf20Sopenharmony_ci 54158c2ecf20Sopenharmony_ci /* 54168c2ecf20Sopenharmony_ci * Something bad happened. If a command timed out or failed with EIO 54178c2ecf20Sopenharmony_ci * FW does not operate within its spec or something catastrophic 54188c2ecf20Sopenharmony_ci * happened to HW/FW, stop issuing commands. 54198c2ecf20Sopenharmony_ci */ 54208c2ecf20Sopenharmony_cibye: 54218c2ecf20Sopenharmony_ci adap_free_hma_mem(adap); 54228c2ecf20Sopenharmony_ci kfree(adap->sge.egr_map); 54238c2ecf20Sopenharmony_ci kfree(adap->sge.ingr_map); 54248c2ecf20Sopenharmony_ci kfree(adap->sge.starving_fl); 54258c2ecf20Sopenharmony_ci kfree(adap->sge.txq_maperr); 54268c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 54278c2ecf20Sopenharmony_ci kfree(adap->sge.blocked_fl); 54288c2ecf20Sopenharmony_ci#endif 54298c2ecf20Sopenharmony_ci if (ret != -ETIMEDOUT && ret != -EIO) 54308c2ecf20Sopenharmony_ci t4_fw_bye(adap, adap->mbox); 54318c2ecf20Sopenharmony_ci return ret; 54328c2ecf20Sopenharmony_ci} 54338c2ecf20Sopenharmony_ci 54348c2ecf20Sopenharmony_ci/* EEH callbacks */ 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_cistatic pci_ers_result_t eeh_err_detected(struct pci_dev *pdev, 54378c2ecf20Sopenharmony_ci pci_channel_state_t state) 54388c2ecf20Sopenharmony_ci{ 54398c2ecf20Sopenharmony_ci int i; 54408c2ecf20Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 54418c2ecf20Sopenharmony_ci 54428c2ecf20Sopenharmony_ci if (!adap) 54438c2ecf20Sopenharmony_ci goto out; 54448c2ecf20Sopenharmony_ci 54458c2ecf20Sopenharmony_ci rtnl_lock(); 54468c2ecf20Sopenharmony_ci adap->flags &= ~CXGB4_FW_OK; 54478c2ecf20Sopenharmony_ci notify_ulds(adap, CXGB4_STATE_START_RECOVERY); 54488c2ecf20Sopenharmony_ci spin_lock(&adap->stats_lock); 54498c2ecf20Sopenharmony_ci for_each_port(adap, i) { 54508c2ecf20Sopenharmony_ci struct net_device *dev = adap->port[i]; 54518c2ecf20Sopenharmony_ci if (dev) { 54528c2ecf20Sopenharmony_ci netif_device_detach(dev); 54538c2ecf20Sopenharmony_ci netif_carrier_off(dev); 54548c2ecf20Sopenharmony_ci } 54558c2ecf20Sopenharmony_ci } 54568c2ecf20Sopenharmony_ci spin_unlock(&adap->stats_lock); 54578c2ecf20Sopenharmony_ci disable_interrupts(adap); 54588c2ecf20Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 54598c2ecf20Sopenharmony_ci cxgb_down(adap); 54608c2ecf20Sopenharmony_ci rtnl_unlock(); 54618c2ecf20Sopenharmony_ci if ((adap->flags & CXGB4_DEV_ENABLED)) { 54628c2ecf20Sopenharmony_ci pci_disable_device(pdev); 54638c2ecf20Sopenharmony_ci adap->flags &= ~CXGB4_DEV_ENABLED; 54648c2ecf20Sopenharmony_ci } 54658c2ecf20Sopenharmony_ciout: return state == pci_channel_io_perm_failure ? 54668c2ecf20Sopenharmony_ci PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; 54678c2ecf20Sopenharmony_ci} 54688c2ecf20Sopenharmony_ci 54698c2ecf20Sopenharmony_cistatic pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) 54708c2ecf20Sopenharmony_ci{ 54718c2ecf20Sopenharmony_ci int i, ret; 54728c2ecf20Sopenharmony_ci struct fw_caps_config_cmd c; 54738c2ecf20Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 54748c2ecf20Sopenharmony_ci 54758c2ecf20Sopenharmony_ci if (!adap) { 54768c2ecf20Sopenharmony_ci pci_restore_state(pdev); 54778c2ecf20Sopenharmony_ci pci_save_state(pdev); 54788c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 54798c2ecf20Sopenharmony_ci } 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_DEV_ENABLED)) { 54828c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 54838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot reenable PCI " 54848c2ecf20Sopenharmony_ci "device after reset\n"); 54858c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 54868c2ecf20Sopenharmony_ci } 54878c2ecf20Sopenharmony_ci adap->flags |= CXGB4_DEV_ENABLED; 54888c2ecf20Sopenharmony_ci } 54898c2ecf20Sopenharmony_ci 54908c2ecf20Sopenharmony_ci pci_set_master(pdev); 54918c2ecf20Sopenharmony_ci pci_restore_state(pdev); 54928c2ecf20Sopenharmony_ci pci_save_state(pdev); 54938c2ecf20Sopenharmony_ci 54948c2ecf20Sopenharmony_ci if (t4_wait_dev_ready(adap->regs) < 0) 54958c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 54968c2ecf20Sopenharmony_ci if (t4_fw_hello(adap, adap->mbox, adap->pf, MASTER_MUST, NULL) < 0) 54978c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 54988c2ecf20Sopenharmony_ci adap->flags |= CXGB4_FW_OK; 54998c2ecf20Sopenharmony_ci if (adap_init1(adap, &c)) 55008c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 55018c2ecf20Sopenharmony_ci 55028c2ecf20Sopenharmony_ci for_each_port(adap, i) { 55038c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 55048c2ecf20Sopenharmony_ci u8 vivld = 0, vin = 0; 55058c2ecf20Sopenharmony_ci 55068c2ecf20Sopenharmony_ci ret = t4_alloc_vi(adap, adap->mbox, pi->tx_chan, adap->pf, 0, 1, 55078c2ecf20Sopenharmony_ci NULL, NULL, &vivld, &vin); 55088c2ecf20Sopenharmony_ci if (ret < 0) 55098c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 55108c2ecf20Sopenharmony_ci pi->viid = ret; 55118c2ecf20Sopenharmony_ci pi->xact_addr_filt = -1; 55128c2ecf20Sopenharmony_ci /* If fw supports returning the VIN as part of FW_VI_CMD, 55138c2ecf20Sopenharmony_ci * save the returned values. 55148c2ecf20Sopenharmony_ci */ 55158c2ecf20Sopenharmony_ci if (adap->params.viid_smt_extn_support) { 55168c2ecf20Sopenharmony_ci pi->vivld = vivld; 55178c2ecf20Sopenharmony_ci pi->vin = vin; 55188c2ecf20Sopenharmony_ci } else { 55198c2ecf20Sopenharmony_ci /* Retrieve the values from VIID */ 55208c2ecf20Sopenharmony_ci pi->vivld = FW_VIID_VIVLD_G(pi->viid); 55218c2ecf20Sopenharmony_ci pi->vin = FW_VIID_VIN_G(pi->viid); 55228c2ecf20Sopenharmony_ci } 55238c2ecf20Sopenharmony_ci } 55248c2ecf20Sopenharmony_ci 55258c2ecf20Sopenharmony_ci t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, 55268c2ecf20Sopenharmony_ci adap->params.b_wnd); 55278c2ecf20Sopenharmony_ci setup_memwin(adap); 55288c2ecf20Sopenharmony_ci if (cxgb_up(adap)) 55298c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 55308c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 55318c2ecf20Sopenharmony_ci} 55328c2ecf20Sopenharmony_ci 55338c2ecf20Sopenharmony_cistatic void eeh_resume(struct pci_dev *pdev) 55348c2ecf20Sopenharmony_ci{ 55358c2ecf20Sopenharmony_ci int i; 55368c2ecf20Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 55378c2ecf20Sopenharmony_ci 55388c2ecf20Sopenharmony_ci if (!adap) 55398c2ecf20Sopenharmony_ci return; 55408c2ecf20Sopenharmony_ci 55418c2ecf20Sopenharmony_ci rtnl_lock(); 55428c2ecf20Sopenharmony_ci for_each_port(adap, i) { 55438c2ecf20Sopenharmony_ci struct net_device *dev = adap->port[i]; 55448c2ecf20Sopenharmony_ci if (dev) { 55458c2ecf20Sopenharmony_ci if (netif_running(dev)) { 55468c2ecf20Sopenharmony_ci link_start(dev); 55478c2ecf20Sopenharmony_ci cxgb_set_rxmode(dev); 55488c2ecf20Sopenharmony_ci } 55498c2ecf20Sopenharmony_ci netif_device_attach(dev); 55508c2ecf20Sopenharmony_ci } 55518c2ecf20Sopenharmony_ci } 55528c2ecf20Sopenharmony_ci rtnl_unlock(); 55538c2ecf20Sopenharmony_ci} 55548c2ecf20Sopenharmony_ci 55558c2ecf20Sopenharmony_cistatic void eeh_reset_prepare(struct pci_dev *pdev) 55568c2ecf20Sopenharmony_ci{ 55578c2ecf20Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 55588c2ecf20Sopenharmony_ci int i; 55598c2ecf20Sopenharmony_ci 55608c2ecf20Sopenharmony_ci if (adapter->pf != 4) 55618c2ecf20Sopenharmony_ci return; 55628c2ecf20Sopenharmony_ci 55638c2ecf20Sopenharmony_ci adapter->flags &= ~CXGB4_FW_OK; 55648c2ecf20Sopenharmony_ci 55658c2ecf20Sopenharmony_ci notify_ulds(adapter, CXGB4_STATE_DOWN); 55668c2ecf20Sopenharmony_ci 55678c2ecf20Sopenharmony_ci for_each_port(adapter, i) 55688c2ecf20Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 55698c2ecf20Sopenharmony_ci cxgb_close(adapter->port[i]); 55708c2ecf20Sopenharmony_ci 55718c2ecf20Sopenharmony_ci disable_interrupts(adapter); 55728c2ecf20Sopenharmony_ci cxgb4_free_mps_ref_entries(adapter); 55738c2ecf20Sopenharmony_ci 55748c2ecf20Sopenharmony_ci adap_free_hma_mem(adapter); 55758c2ecf20Sopenharmony_ci 55768c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FULL_INIT_DONE) 55778c2ecf20Sopenharmony_ci cxgb_down(adapter); 55788c2ecf20Sopenharmony_ci} 55798c2ecf20Sopenharmony_ci 55808c2ecf20Sopenharmony_cistatic void eeh_reset_done(struct pci_dev *pdev) 55818c2ecf20Sopenharmony_ci{ 55828c2ecf20Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 55838c2ecf20Sopenharmony_ci int err, i; 55848c2ecf20Sopenharmony_ci 55858c2ecf20Sopenharmony_ci if (adapter->pf != 4) 55868c2ecf20Sopenharmony_ci return; 55878c2ecf20Sopenharmony_ci 55888c2ecf20Sopenharmony_ci err = t4_wait_dev_ready(adapter->regs); 55898c2ecf20Sopenharmony_ci if (err < 0) { 55908c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 55918c2ecf20Sopenharmony_ci "Device not ready, err %d", err); 55928c2ecf20Sopenharmony_ci return; 55938c2ecf20Sopenharmony_ci } 55948c2ecf20Sopenharmony_ci 55958c2ecf20Sopenharmony_ci setup_memwin(adapter); 55968c2ecf20Sopenharmony_ci 55978c2ecf20Sopenharmony_ci err = adap_init0(adapter, 1); 55988c2ecf20Sopenharmony_ci if (err) { 55998c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 56008c2ecf20Sopenharmony_ci "Adapter init failed, err %d", err); 56018c2ecf20Sopenharmony_ci return; 56028c2ecf20Sopenharmony_ci } 56038c2ecf20Sopenharmony_ci 56048c2ecf20Sopenharmony_ci setup_memwin_rdma(adapter); 56058c2ecf20Sopenharmony_ci 56068c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) { 56078c2ecf20Sopenharmony_ci err = t4_port_init(adapter, adapter->pf, adapter->pf, 0); 56088c2ecf20Sopenharmony_ci if (err) { 56098c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 56108c2ecf20Sopenharmony_ci "Port init failed, err %d", err); 56118c2ecf20Sopenharmony_ci return; 56128c2ecf20Sopenharmony_ci } 56138c2ecf20Sopenharmony_ci } 56148c2ecf20Sopenharmony_ci 56158c2ecf20Sopenharmony_ci err = cfg_queues(adapter); 56168c2ecf20Sopenharmony_ci if (err) { 56178c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 56188c2ecf20Sopenharmony_ci "Config queues failed, err %d", err); 56198c2ecf20Sopenharmony_ci return; 56208c2ecf20Sopenharmony_ci } 56218c2ecf20Sopenharmony_ci 56228c2ecf20Sopenharmony_ci cxgb4_init_mps_ref_entries(adapter); 56238c2ecf20Sopenharmony_ci 56248c2ecf20Sopenharmony_ci err = setup_fw_sge_queues(adapter); 56258c2ecf20Sopenharmony_ci if (err) { 56268c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 56278c2ecf20Sopenharmony_ci "FW sge queue allocation failed, err %d", err); 56288c2ecf20Sopenharmony_ci return; 56298c2ecf20Sopenharmony_ci } 56308c2ecf20Sopenharmony_ci 56318c2ecf20Sopenharmony_ci for_each_port(adapter, i) 56328c2ecf20Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 56338c2ecf20Sopenharmony_ci cxgb_open(adapter->port[i]); 56348c2ecf20Sopenharmony_ci} 56358c2ecf20Sopenharmony_ci 56368c2ecf20Sopenharmony_cistatic const struct pci_error_handlers cxgb4_eeh = { 56378c2ecf20Sopenharmony_ci .error_detected = eeh_err_detected, 56388c2ecf20Sopenharmony_ci .slot_reset = eeh_slot_reset, 56398c2ecf20Sopenharmony_ci .resume = eeh_resume, 56408c2ecf20Sopenharmony_ci .reset_prepare = eeh_reset_prepare, 56418c2ecf20Sopenharmony_ci .reset_done = eeh_reset_done, 56428c2ecf20Sopenharmony_ci}; 56438c2ecf20Sopenharmony_ci 56448c2ecf20Sopenharmony_ci/* Return true if the Link Configuration supports "High Speeds" (those greater 56458c2ecf20Sopenharmony_ci * than 1Gb/s). 56468c2ecf20Sopenharmony_ci */ 56478c2ecf20Sopenharmony_cistatic inline bool is_x_10g_port(const struct link_config *lc) 56488c2ecf20Sopenharmony_ci{ 56498c2ecf20Sopenharmony_ci unsigned int speeds, high_speeds; 56508c2ecf20Sopenharmony_ci 56518c2ecf20Sopenharmony_ci speeds = FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_G(lc->pcaps)); 56528c2ecf20Sopenharmony_ci high_speeds = speeds & 56538c2ecf20Sopenharmony_ci ~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G); 56548c2ecf20Sopenharmony_ci 56558c2ecf20Sopenharmony_ci return high_speeds != 0; 56568c2ecf20Sopenharmony_ci} 56578c2ecf20Sopenharmony_ci 56588c2ecf20Sopenharmony_ci/* Perform default configuration of DMA queues depending on the number and type 56598c2ecf20Sopenharmony_ci * of ports we found and the number of available CPUs. Most settings can be 56608c2ecf20Sopenharmony_ci * modified by the admin prior to actual use. 56618c2ecf20Sopenharmony_ci */ 56628c2ecf20Sopenharmony_cistatic int cfg_queues(struct adapter *adap) 56638c2ecf20Sopenharmony_ci{ 56648c2ecf20Sopenharmony_ci u32 avail_qsets, avail_eth_qsets, avail_uld_qsets; 56658c2ecf20Sopenharmony_ci u32 ncpus = num_online_cpus(); 56668c2ecf20Sopenharmony_ci u32 niqflint, neq, num_ulds; 56678c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 56688c2ecf20Sopenharmony_ci u32 i, n10g = 0, qidx = 0; 56698c2ecf20Sopenharmony_ci u32 q10g = 0, q1g; 56708c2ecf20Sopenharmony_ci 56718c2ecf20Sopenharmony_ci /* Reduce memory usage in kdump environment, disable all offload. */ 56728c2ecf20Sopenharmony_ci if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { 56738c2ecf20Sopenharmony_ci adap->params.offload = 0; 56748c2ecf20Sopenharmony_ci adap->params.crypto = 0; 56758c2ecf20Sopenharmony_ci adap->params.ethofld = 0; 56768c2ecf20Sopenharmony_ci } 56778c2ecf20Sopenharmony_ci 56788c2ecf20Sopenharmony_ci /* Calculate the number of Ethernet Queue Sets available based on 56798c2ecf20Sopenharmony_ci * resources provisioned for us. We always have an Asynchronous 56808c2ecf20Sopenharmony_ci * Firmware Event Ingress Queue. If we're operating in MSI or Legacy 56818c2ecf20Sopenharmony_ci * IRQ Pin Interrupt mode, then we'll also have a Forwarded Interrupt 56828c2ecf20Sopenharmony_ci * Ingress Queue. Meanwhile, we need two Egress Queues for each 56838c2ecf20Sopenharmony_ci * Queue Set: one for the Free List and one for the Ethernet TX Queue. 56848c2ecf20Sopenharmony_ci * 56858c2ecf20Sopenharmony_ci * Note that we should also take into account all of the various 56868c2ecf20Sopenharmony_ci * Offload Queues. But, in any situation where we're operating in 56878c2ecf20Sopenharmony_ci * a Resource Constrained Provisioning environment, doing any Offload 56888c2ecf20Sopenharmony_ci * at all is problematic ... 56898c2ecf20Sopenharmony_ci */ 56908c2ecf20Sopenharmony_ci niqflint = adap->params.pfres.niqflint - 1; 56918c2ecf20Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 56928c2ecf20Sopenharmony_ci niqflint--; 56938c2ecf20Sopenharmony_ci neq = adap->params.pfres.neq / 2; 56948c2ecf20Sopenharmony_ci avail_qsets = min(niqflint, neq); 56958c2ecf20Sopenharmony_ci 56968c2ecf20Sopenharmony_ci if (avail_qsets < adap->params.nports) { 56978c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "avail_eth_qsets=%d < nports=%d\n", 56988c2ecf20Sopenharmony_ci avail_qsets, adap->params.nports); 56998c2ecf20Sopenharmony_ci return -ENOMEM; 57008c2ecf20Sopenharmony_ci } 57018c2ecf20Sopenharmony_ci 57028c2ecf20Sopenharmony_ci /* Count the number of 10Gb/s or better ports */ 57038c2ecf20Sopenharmony_ci for_each_port(adap, i) 57048c2ecf20Sopenharmony_ci n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); 57058c2ecf20Sopenharmony_ci 57068c2ecf20Sopenharmony_ci avail_eth_qsets = min_t(u32, avail_qsets, MAX_ETH_QSETS); 57078c2ecf20Sopenharmony_ci 57088c2ecf20Sopenharmony_ci /* We default to 1 queue per non-10G port and up to # of cores queues 57098c2ecf20Sopenharmony_ci * per 10G port. 57108c2ecf20Sopenharmony_ci */ 57118c2ecf20Sopenharmony_ci if (n10g) 57128c2ecf20Sopenharmony_ci q10g = (avail_eth_qsets - (adap->params.nports - n10g)) / n10g; 57138c2ecf20Sopenharmony_ci 57148c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 57158c2ecf20Sopenharmony_ci /* For Data Center Bridging support we need to be able to support up 57168c2ecf20Sopenharmony_ci * to 8 Traffic Priorities; each of which will be assigned to its 57178c2ecf20Sopenharmony_ci * own TX Queue in order to prevent Head-Of-Line Blocking. 57188c2ecf20Sopenharmony_ci */ 57198c2ecf20Sopenharmony_ci q1g = 8; 57208c2ecf20Sopenharmony_ci if (adap->params.nports * 8 > avail_eth_qsets) { 57218c2ecf20Sopenharmony_ci dev_err(adap->pdev_dev, "DCB avail_eth_qsets=%d < %d!\n", 57228c2ecf20Sopenharmony_ci avail_eth_qsets, adap->params.nports * 8); 57238c2ecf20Sopenharmony_ci return -ENOMEM; 57248c2ecf20Sopenharmony_ci } 57258c2ecf20Sopenharmony_ci 57268c2ecf20Sopenharmony_ci if (adap->params.nports * ncpus < avail_eth_qsets) 57278c2ecf20Sopenharmony_ci q10g = max(8U, ncpus); 57288c2ecf20Sopenharmony_ci else 57298c2ecf20Sopenharmony_ci q10g = max(8U, q10g); 57308c2ecf20Sopenharmony_ci 57318c2ecf20Sopenharmony_ci while ((q10g * n10g) > 57328c2ecf20Sopenharmony_ci (avail_eth_qsets - (adap->params.nports - n10g) * q1g)) 57338c2ecf20Sopenharmony_ci q10g--; 57348c2ecf20Sopenharmony_ci 57358c2ecf20Sopenharmony_ci#else /* !CONFIG_CHELSIO_T4_DCB */ 57368c2ecf20Sopenharmony_ci q1g = 1; 57378c2ecf20Sopenharmony_ci q10g = min(q10g, ncpus); 57388c2ecf20Sopenharmony_ci#endif /* !CONFIG_CHELSIO_T4_DCB */ 57398c2ecf20Sopenharmony_ci if (is_kdump_kernel()) { 57408c2ecf20Sopenharmony_ci q10g = 1; 57418c2ecf20Sopenharmony_ci q1g = 1; 57428c2ecf20Sopenharmony_ci } 57438c2ecf20Sopenharmony_ci 57448c2ecf20Sopenharmony_ci for_each_port(adap, i) { 57458c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 57468c2ecf20Sopenharmony_ci 57478c2ecf20Sopenharmony_ci pi->first_qset = qidx; 57488c2ecf20Sopenharmony_ci pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : q1g; 57498c2ecf20Sopenharmony_ci qidx += pi->nqsets; 57508c2ecf20Sopenharmony_ci } 57518c2ecf20Sopenharmony_ci 57528c2ecf20Sopenharmony_ci s->ethqsets = qidx; 57538c2ecf20Sopenharmony_ci s->max_ethqsets = qidx; /* MSI-X may lower it later */ 57548c2ecf20Sopenharmony_ci avail_qsets -= qidx; 57558c2ecf20Sopenharmony_ci 57568c2ecf20Sopenharmony_ci if (is_uld(adap)) { 57578c2ecf20Sopenharmony_ci /* For offload we use 1 queue/channel if all ports are up to 1G, 57588c2ecf20Sopenharmony_ci * otherwise we divide all available queues amongst the channels 57598c2ecf20Sopenharmony_ci * capped by the number of available cores. 57608c2ecf20Sopenharmony_ci */ 57618c2ecf20Sopenharmony_ci num_ulds = adap->num_uld + adap->num_ofld_uld; 57628c2ecf20Sopenharmony_ci i = min_t(u32, MAX_OFLD_QSETS, ncpus); 57638c2ecf20Sopenharmony_ci avail_uld_qsets = roundup(i, adap->params.nports); 57648c2ecf20Sopenharmony_ci if (avail_qsets < num_ulds * adap->params.nports) { 57658c2ecf20Sopenharmony_ci adap->params.offload = 0; 57668c2ecf20Sopenharmony_ci adap->params.crypto = 0; 57678c2ecf20Sopenharmony_ci s->ofldqsets = 0; 57688c2ecf20Sopenharmony_ci } else if (avail_qsets < num_ulds * avail_uld_qsets || !n10g) { 57698c2ecf20Sopenharmony_ci s->ofldqsets = adap->params.nports; 57708c2ecf20Sopenharmony_ci } else { 57718c2ecf20Sopenharmony_ci s->ofldqsets = avail_uld_qsets; 57728c2ecf20Sopenharmony_ci } 57738c2ecf20Sopenharmony_ci 57748c2ecf20Sopenharmony_ci avail_qsets -= num_ulds * s->ofldqsets; 57758c2ecf20Sopenharmony_ci } 57768c2ecf20Sopenharmony_ci 57778c2ecf20Sopenharmony_ci /* ETHOFLD Queues used for QoS offload should follow same 57788c2ecf20Sopenharmony_ci * allocation scheme as normal Ethernet Queues. 57798c2ecf20Sopenharmony_ci */ 57808c2ecf20Sopenharmony_ci if (is_ethofld(adap)) { 57818c2ecf20Sopenharmony_ci if (avail_qsets < s->max_ethqsets) { 57828c2ecf20Sopenharmony_ci adap->params.ethofld = 0; 57838c2ecf20Sopenharmony_ci s->eoqsets = 0; 57848c2ecf20Sopenharmony_ci } else { 57858c2ecf20Sopenharmony_ci s->eoqsets = s->max_ethqsets; 57868c2ecf20Sopenharmony_ci } 57878c2ecf20Sopenharmony_ci avail_qsets -= s->eoqsets; 57888c2ecf20Sopenharmony_ci } 57898c2ecf20Sopenharmony_ci 57908c2ecf20Sopenharmony_ci /* Mirror queues must follow same scheme as normal Ethernet 57918c2ecf20Sopenharmony_ci * Queues, when there are enough queues available. Otherwise, 57928c2ecf20Sopenharmony_ci * allocate at least 1 queue per port. If even 1 queue is not 57938c2ecf20Sopenharmony_ci * available, then disable mirror queues support. 57948c2ecf20Sopenharmony_ci */ 57958c2ecf20Sopenharmony_ci if (avail_qsets >= s->max_ethqsets) 57968c2ecf20Sopenharmony_ci s->mirrorqsets = s->max_ethqsets; 57978c2ecf20Sopenharmony_ci else if (avail_qsets >= adap->params.nports) 57988c2ecf20Sopenharmony_ci s->mirrorqsets = adap->params.nports; 57998c2ecf20Sopenharmony_ci else 58008c2ecf20Sopenharmony_ci s->mirrorqsets = 0; 58018c2ecf20Sopenharmony_ci avail_qsets -= s->mirrorqsets; 58028c2ecf20Sopenharmony_ci 58038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { 58048c2ecf20Sopenharmony_ci struct sge_eth_rxq *r = &s->ethrxq[i]; 58058c2ecf20Sopenharmony_ci 58068c2ecf20Sopenharmony_ci init_rspq(adap, &r->rspq, 5, 10, 1024, 64); 58078c2ecf20Sopenharmony_ci r->fl.size = 72; 58088c2ecf20Sopenharmony_ci } 58098c2ecf20Sopenharmony_ci 58108c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++) 58118c2ecf20Sopenharmony_ci s->ethtxq[i].q.size = 1024; 58128c2ecf20Sopenharmony_ci 58138c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) 58148c2ecf20Sopenharmony_ci s->ctrlq[i].q.size = 512; 58158c2ecf20Sopenharmony_ci 58168c2ecf20Sopenharmony_ci if (!is_t4(adap->params.chip)) 58178c2ecf20Sopenharmony_ci s->ptptxq.q.size = 8; 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64); 58208c2ecf20Sopenharmony_ci init_rspq(adap, &s->intrq, 0, 1, 512, 64); 58218c2ecf20Sopenharmony_ci 58228c2ecf20Sopenharmony_ci return 0; 58238c2ecf20Sopenharmony_ci} 58248c2ecf20Sopenharmony_ci 58258c2ecf20Sopenharmony_ci/* 58268c2ecf20Sopenharmony_ci * Reduce the number of Ethernet queues across all ports to at most n. 58278c2ecf20Sopenharmony_ci * n provides at least one queue per port. 58288c2ecf20Sopenharmony_ci */ 58298c2ecf20Sopenharmony_cistatic void reduce_ethqs(struct adapter *adap, int n) 58308c2ecf20Sopenharmony_ci{ 58318c2ecf20Sopenharmony_ci int i; 58328c2ecf20Sopenharmony_ci struct port_info *pi; 58338c2ecf20Sopenharmony_ci 58348c2ecf20Sopenharmony_ci while (n < adap->sge.ethqsets) 58358c2ecf20Sopenharmony_ci for_each_port(adap, i) { 58368c2ecf20Sopenharmony_ci pi = adap2pinfo(adap, i); 58378c2ecf20Sopenharmony_ci if (pi->nqsets > 1) { 58388c2ecf20Sopenharmony_ci pi->nqsets--; 58398c2ecf20Sopenharmony_ci adap->sge.ethqsets--; 58408c2ecf20Sopenharmony_ci if (adap->sge.ethqsets <= n) 58418c2ecf20Sopenharmony_ci break; 58428c2ecf20Sopenharmony_ci } 58438c2ecf20Sopenharmony_ci } 58448c2ecf20Sopenharmony_ci 58458c2ecf20Sopenharmony_ci n = 0; 58468c2ecf20Sopenharmony_ci for_each_port(adap, i) { 58478c2ecf20Sopenharmony_ci pi = adap2pinfo(adap, i); 58488c2ecf20Sopenharmony_ci pi->first_qset = n; 58498c2ecf20Sopenharmony_ci n += pi->nqsets; 58508c2ecf20Sopenharmony_ci } 58518c2ecf20Sopenharmony_ci} 58528c2ecf20Sopenharmony_ci 58538c2ecf20Sopenharmony_cistatic int alloc_msix_info(struct adapter *adap, u32 num_vec) 58548c2ecf20Sopenharmony_ci{ 58558c2ecf20Sopenharmony_ci struct msix_info *msix_info; 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci msix_info = kcalloc(num_vec, sizeof(*msix_info), GFP_KERNEL); 58588c2ecf20Sopenharmony_ci if (!msix_info) 58598c2ecf20Sopenharmony_ci return -ENOMEM; 58608c2ecf20Sopenharmony_ci 58618c2ecf20Sopenharmony_ci adap->msix_bmap.msix_bmap = kcalloc(BITS_TO_LONGS(num_vec), 58628c2ecf20Sopenharmony_ci sizeof(long), GFP_KERNEL); 58638c2ecf20Sopenharmony_ci if (!adap->msix_bmap.msix_bmap) { 58648c2ecf20Sopenharmony_ci kfree(msix_info); 58658c2ecf20Sopenharmony_ci return -ENOMEM; 58668c2ecf20Sopenharmony_ci } 58678c2ecf20Sopenharmony_ci 58688c2ecf20Sopenharmony_ci spin_lock_init(&adap->msix_bmap.lock); 58698c2ecf20Sopenharmony_ci adap->msix_bmap.mapsize = num_vec; 58708c2ecf20Sopenharmony_ci 58718c2ecf20Sopenharmony_ci adap->msix_info = msix_info; 58728c2ecf20Sopenharmony_ci return 0; 58738c2ecf20Sopenharmony_ci} 58748c2ecf20Sopenharmony_ci 58758c2ecf20Sopenharmony_cistatic void free_msix_info(struct adapter *adap) 58768c2ecf20Sopenharmony_ci{ 58778c2ecf20Sopenharmony_ci kfree(adap->msix_bmap.msix_bmap); 58788c2ecf20Sopenharmony_ci kfree(adap->msix_info); 58798c2ecf20Sopenharmony_ci} 58808c2ecf20Sopenharmony_ci 58818c2ecf20Sopenharmony_ciint cxgb4_get_msix_idx_from_bmap(struct adapter *adap) 58828c2ecf20Sopenharmony_ci{ 58838c2ecf20Sopenharmony_ci struct msix_bmap *bmap = &adap->msix_bmap; 58848c2ecf20Sopenharmony_ci unsigned int msix_idx; 58858c2ecf20Sopenharmony_ci unsigned long flags; 58868c2ecf20Sopenharmony_ci 58878c2ecf20Sopenharmony_ci spin_lock_irqsave(&bmap->lock, flags); 58888c2ecf20Sopenharmony_ci msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize); 58898c2ecf20Sopenharmony_ci if (msix_idx < bmap->mapsize) { 58908c2ecf20Sopenharmony_ci __set_bit(msix_idx, bmap->msix_bmap); 58918c2ecf20Sopenharmony_ci } else { 58928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bmap->lock, flags); 58938c2ecf20Sopenharmony_ci return -ENOSPC; 58948c2ecf20Sopenharmony_ci } 58958c2ecf20Sopenharmony_ci 58968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bmap->lock, flags); 58978c2ecf20Sopenharmony_ci return msix_idx; 58988c2ecf20Sopenharmony_ci} 58998c2ecf20Sopenharmony_ci 59008c2ecf20Sopenharmony_civoid cxgb4_free_msix_idx_in_bmap(struct adapter *adap, 59018c2ecf20Sopenharmony_ci unsigned int msix_idx) 59028c2ecf20Sopenharmony_ci{ 59038c2ecf20Sopenharmony_ci struct msix_bmap *bmap = &adap->msix_bmap; 59048c2ecf20Sopenharmony_ci unsigned long flags; 59058c2ecf20Sopenharmony_ci 59068c2ecf20Sopenharmony_ci spin_lock_irqsave(&bmap->lock, flags); 59078c2ecf20Sopenharmony_ci __clear_bit(msix_idx, bmap->msix_bmap); 59088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bmap->lock, flags); 59098c2ecf20Sopenharmony_ci} 59108c2ecf20Sopenharmony_ci 59118c2ecf20Sopenharmony_ci/* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ 59128c2ecf20Sopenharmony_ci#define EXTRA_VECS 2 59138c2ecf20Sopenharmony_ci 59148c2ecf20Sopenharmony_cistatic int enable_msix(struct adapter *adap) 59158c2ecf20Sopenharmony_ci{ 59168c2ecf20Sopenharmony_ci u32 eth_need, uld_need = 0, ethofld_need = 0, mirror_need = 0; 59178c2ecf20Sopenharmony_ci u32 ethqsets = 0, ofldqsets = 0, eoqsets = 0, mirrorqsets = 0; 59188c2ecf20Sopenharmony_ci u8 num_uld = 0, nchan = adap->params.nports; 59198c2ecf20Sopenharmony_ci u32 i, want, need, num_vec; 59208c2ecf20Sopenharmony_ci struct sge *s = &adap->sge; 59218c2ecf20Sopenharmony_ci struct msix_entry *entries; 59228c2ecf20Sopenharmony_ci struct port_info *pi; 59238c2ecf20Sopenharmony_ci int allocated, ret; 59248c2ecf20Sopenharmony_ci 59258c2ecf20Sopenharmony_ci want = s->max_ethqsets; 59268c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 59278c2ecf20Sopenharmony_ci /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for 59288c2ecf20Sopenharmony_ci * each port. 59298c2ecf20Sopenharmony_ci */ 59308c2ecf20Sopenharmony_ci need = 8 * nchan; 59318c2ecf20Sopenharmony_ci#else 59328c2ecf20Sopenharmony_ci need = nchan; 59338c2ecf20Sopenharmony_ci#endif 59348c2ecf20Sopenharmony_ci eth_need = need; 59358c2ecf20Sopenharmony_ci if (is_uld(adap)) { 59368c2ecf20Sopenharmony_ci num_uld = adap->num_ofld_uld + adap->num_uld; 59378c2ecf20Sopenharmony_ci want += num_uld * s->ofldqsets; 59388c2ecf20Sopenharmony_ci uld_need = num_uld * nchan; 59398c2ecf20Sopenharmony_ci need += uld_need; 59408c2ecf20Sopenharmony_ci } 59418c2ecf20Sopenharmony_ci 59428c2ecf20Sopenharmony_ci if (is_ethofld(adap)) { 59438c2ecf20Sopenharmony_ci want += s->eoqsets; 59448c2ecf20Sopenharmony_ci ethofld_need = eth_need; 59458c2ecf20Sopenharmony_ci need += ethofld_need; 59468c2ecf20Sopenharmony_ci } 59478c2ecf20Sopenharmony_ci 59488c2ecf20Sopenharmony_ci if (s->mirrorqsets) { 59498c2ecf20Sopenharmony_ci want += s->mirrorqsets; 59508c2ecf20Sopenharmony_ci mirror_need = nchan; 59518c2ecf20Sopenharmony_ci need += mirror_need; 59528c2ecf20Sopenharmony_ci } 59538c2ecf20Sopenharmony_ci 59548c2ecf20Sopenharmony_ci want += EXTRA_VECS; 59558c2ecf20Sopenharmony_ci need += EXTRA_VECS; 59568c2ecf20Sopenharmony_ci 59578c2ecf20Sopenharmony_ci entries = kmalloc_array(want, sizeof(*entries), GFP_KERNEL); 59588c2ecf20Sopenharmony_ci if (!entries) 59598c2ecf20Sopenharmony_ci return -ENOMEM; 59608c2ecf20Sopenharmony_ci 59618c2ecf20Sopenharmony_ci for (i = 0; i < want; i++) 59628c2ecf20Sopenharmony_ci entries[i].entry = i; 59638c2ecf20Sopenharmony_ci 59648c2ecf20Sopenharmony_ci allocated = pci_enable_msix_range(adap->pdev, entries, need, want); 59658c2ecf20Sopenharmony_ci if (allocated < 0) { 59668c2ecf20Sopenharmony_ci /* Disable offload and attempt to get vectors for NIC 59678c2ecf20Sopenharmony_ci * only mode. 59688c2ecf20Sopenharmony_ci */ 59698c2ecf20Sopenharmony_ci want = s->max_ethqsets + EXTRA_VECS; 59708c2ecf20Sopenharmony_ci need = eth_need + EXTRA_VECS; 59718c2ecf20Sopenharmony_ci allocated = pci_enable_msix_range(adap->pdev, entries, 59728c2ecf20Sopenharmony_ci need, want); 59738c2ecf20Sopenharmony_ci if (allocated < 0) { 59748c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 59758c2ecf20Sopenharmony_ci "Disabling MSI-X due to insufficient MSI-X vectors\n"); 59768c2ecf20Sopenharmony_ci ret = allocated; 59778c2ecf20Sopenharmony_ci goto out_free; 59788c2ecf20Sopenharmony_ci } 59798c2ecf20Sopenharmony_ci 59808c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 59818c2ecf20Sopenharmony_ci "Disabling offload due to insufficient MSI-X vectors\n"); 59828c2ecf20Sopenharmony_ci adap->params.offload = 0; 59838c2ecf20Sopenharmony_ci adap->params.crypto = 0; 59848c2ecf20Sopenharmony_ci adap->params.ethofld = 0; 59858c2ecf20Sopenharmony_ci s->ofldqsets = 0; 59868c2ecf20Sopenharmony_ci s->eoqsets = 0; 59878c2ecf20Sopenharmony_ci s->mirrorqsets = 0; 59888c2ecf20Sopenharmony_ci uld_need = 0; 59898c2ecf20Sopenharmony_ci ethofld_need = 0; 59908c2ecf20Sopenharmony_ci mirror_need = 0; 59918c2ecf20Sopenharmony_ci } 59928c2ecf20Sopenharmony_ci 59938c2ecf20Sopenharmony_ci num_vec = allocated; 59948c2ecf20Sopenharmony_ci if (num_vec < want) { 59958c2ecf20Sopenharmony_ci /* Distribute available vectors to the various queue groups. 59968c2ecf20Sopenharmony_ci * Every group gets its minimum requirement and NIC gets top 59978c2ecf20Sopenharmony_ci * priority for leftovers. 59988c2ecf20Sopenharmony_ci */ 59998c2ecf20Sopenharmony_ci ethqsets = eth_need; 60008c2ecf20Sopenharmony_ci if (is_uld(adap)) 60018c2ecf20Sopenharmony_ci ofldqsets = nchan; 60028c2ecf20Sopenharmony_ci if (is_ethofld(adap)) 60038c2ecf20Sopenharmony_ci eoqsets = ethofld_need; 60048c2ecf20Sopenharmony_ci if (s->mirrorqsets) 60058c2ecf20Sopenharmony_ci mirrorqsets = mirror_need; 60068c2ecf20Sopenharmony_ci 60078c2ecf20Sopenharmony_ci num_vec -= need; 60088c2ecf20Sopenharmony_ci while (num_vec) { 60098c2ecf20Sopenharmony_ci if (num_vec < eth_need + ethofld_need || 60108c2ecf20Sopenharmony_ci ethqsets > s->max_ethqsets) 60118c2ecf20Sopenharmony_ci break; 60128c2ecf20Sopenharmony_ci 60138c2ecf20Sopenharmony_ci for_each_port(adap, i) { 60148c2ecf20Sopenharmony_ci pi = adap2pinfo(adap, i); 60158c2ecf20Sopenharmony_ci if (pi->nqsets < 2) 60168c2ecf20Sopenharmony_ci continue; 60178c2ecf20Sopenharmony_ci 60188c2ecf20Sopenharmony_ci ethqsets++; 60198c2ecf20Sopenharmony_ci num_vec--; 60208c2ecf20Sopenharmony_ci if (ethofld_need) { 60218c2ecf20Sopenharmony_ci eoqsets++; 60228c2ecf20Sopenharmony_ci num_vec--; 60238c2ecf20Sopenharmony_ci } 60248c2ecf20Sopenharmony_ci } 60258c2ecf20Sopenharmony_ci } 60268c2ecf20Sopenharmony_ci 60278c2ecf20Sopenharmony_ci if (is_uld(adap)) { 60288c2ecf20Sopenharmony_ci while (num_vec) { 60298c2ecf20Sopenharmony_ci if (num_vec < uld_need || 60308c2ecf20Sopenharmony_ci ofldqsets > s->ofldqsets) 60318c2ecf20Sopenharmony_ci break; 60328c2ecf20Sopenharmony_ci 60338c2ecf20Sopenharmony_ci ofldqsets++; 60348c2ecf20Sopenharmony_ci num_vec -= uld_need; 60358c2ecf20Sopenharmony_ci } 60368c2ecf20Sopenharmony_ci } 60378c2ecf20Sopenharmony_ci 60388c2ecf20Sopenharmony_ci if (s->mirrorqsets) { 60398c2ecf20Sopenharmony_ci while (num_vec) { 60408c2ecf20Sopenharmony_ci if (num_vec < mirror_need || 60418c2ecf20Sopenharmony_ci mirrorqsets > s->mirrorqsets) 60428c2ecf20Sopenharmony_ci break; 60438c2ecf20Sopenharmony_ci 60448c2ecf20Sopenharmony_ci mirrorqsets++; 60458c2ecf20Sopenharmony_ci num_vec -= mirror_need; 60468c2ecf20Sopenharmony_ci } 60478c2ecf20Sopenharmony_ci } 60488c2ecf20Sopenharmony_ci } else { 60498c2ecf20Sopenharmony_ci ethqsets = s->max_ethqsets; 60508c2ecf20Sopenharmony_ci if (is_uld(adap)) 60518c2ecf20Sopenharmony_ci ofldqsets = s->ofldqsets; 60528c2ecf20Sopenharmony_ci if (is_ethofld(adap)) 60538c2ecf20Sopenharmony_ci eoqsets = s->eoqsets; 60548c2ecf20Sopenharmony_ci if (s->mirrorqsets) 60558c2ecf20Sopenharmony_ci mirrorqsets = s->mirrorqsets; 60568c2ecf20Sopenharmony_ci } 60578c2ecf20Sopenharmony_ci 60588c2ecf20Sopenharmony_ci if (ethqsets < s->max_ethqsets) { 60598c2ecf20Sopenharmony_ci s->max_ethqsets = ethqsets; 60608c2ecf20Sopenharmony_ci reduce_ethqs(adap, ethqsets); 60618c2ecf20Sopenharmony_ci } 60628c2ecf20Sopenharmony_ci 60638c2ecf20Sopenharmony_ci if (is_uld(adap)) { 60648c2ecf20Sopenharmony_ci s->ofldqsets = ofldqsets; 60658c2ecf20Sopenharmony_ci s->nqs_per_uld = s->ofldqsets; 60668c2ecf20Sopenharmony_ci } 60678c2ecf20Sopenharmony_ci 60688c2ecf20Sopenharmony_ci if (is_ethofld(adap)) 60698c2ecf20Sopenharmony_ci s->eoqsets = eoqsets; 60708c2ecf20Sopenharmony_ci 60718c2ecf20Sopenharmony_ci if (s->mirrorqsets) { 60728c2ecf20Sopenharmony_ci s->mirrorqsets = mirrorqsets; 60738c2ecf20Sopenharmony_ci for_each_port(adap, i) { 60748c2ecf20Sopenharmony_ci pi = adap2pinfo(adap, i); 60758c2ecf20Sopenharmony_ci pi->nmirrorqsets = s->mirrorqsets / nchan; 60768c2ecf20Sopenharmony_ci mutex_init(&pi->vi_mirror_mutex); 60778c2ecf20Sopenharmony_ci } 60788c2ecf20Sopenharmony_ci } 60798c2ecf20Sopenharmony_ci 60808c2ecf20Sopenharmony_ci /* map for msix */ 60818c2ecf20Sopenharmony_ci ret = alloc_msix_info(adap, allocated); 60828c2ecf20Sopenharmony_ci if (ret) 60838c2ecf20Sopenharmony_ci goto out_disable_msix; 60848c2ecf20Sopenharmony_ci 60858c2ecf20Sopenharmony_ci for (i = 0; i < allocated; i++) { 60868c2ecf20Sopenharmony_ci adap->msix_info[i].vec = entries[i].vector; 60878c2ecf20Sopenharmony_ci adap->msix_info[i].idx = i; 60888c2ecf20Sopenharmony_ci } 60898c2ecf20Sopenharmony_ci 60908c2ecf20Sopenharmony_ci dev_info(adap->pdev_dev, 60918c2ecf20Sopenharmony_ci "%d MSI-X vectors allocated, nic %d eoqsets %d per uld %d mirrorqsets %d\n", 60928c2ecf20Sopenharmony_ci allocated, s->max_ethqsets, s->eoqsets, s->nqs_per_uld, 60938c2ecf20Sopenharmony_ci s->mirrorqsets); 60948c2ecf20Sopenharmony_ci 60958c2ecf20Sopenharmony_ci kfree(entries); 60968c2ecf20Sopenharmony_ci return 0; 60978c2ecf20Sopenharmony_ci 60988c2ecf20Sopenharmony_ciout_disable_msix: 60998c2ecf20Sopenharmony_ci pci_disable_msix(adap->pdev); 61008c2ecf20Sopenharmony_ci 61018c2ecf20Sopenharmony_ciout_free: 61028c2ecf20Sopenharmony_ci kfree(entries); 61038c2ecf20Sopenharmony_ci return ret; 61048c2ecf20Sopenharmony_ci} 61058c2ecf20Sopenharmony_ci 61068c2ecf20Sopenharmony_ci#undef EXTRA_VECS 61078c2ecf20Sopenharmony_ci 61088c2ecf20Sopenharmony_cistatic int init_rss(struct adapter *adap) 61098c2ecf20Sopenharmony_ci{ 61108c2ecf20Sopenharmony_ci unsigned int i; 61118c2ecf20Sopenharmony_ci int err; 61128c2ecf20Sopenharmony_ci 61138c2ecf20Sopenharmony_ci err = t4_init_rss_mode(adap, adap->mbox); 61148c2ecf20Sopenharmony_ci if (err) 61158c2ecf20Sopenharmony_ci return err; 61168c2ecf20Sopenharmony_ci 61178c2ecf20Sopenharmony_ci for_each_port(adap, i) { 61188c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 61198c2ecf20Sopenharmony_ci 61208c2ecf20Sopenharmony_ci pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); 61218c2ecf20Sopenharmony_ci if (!pi->rss) 61228c2ecf20Sopenharmony_ci return -ENOMEM; 61238c2ecf20Sopenharmony_ci } 61248c2ecf20Sopenharmony_ci return 0; 61258c2ecf20Sopenharmony_ci} 61268c2ecf20Sopenharmony_ci 61278c2ecf20Sopenharmony_ci/* Dump basic information about the adapter */ 61288c2ecf20Sopenharmony_cistatic void print_adapter_info(struct adapter *adapter) 61298c2ecf20Sopenharmony_ci{ 61308c2ecf20Sopenharmony_ci /* Hardware/Firmware/etc. Version/Revision IDs */ 61318c2ecf20Sopenharmony_ci t4_dump_version_info(adapter); 61328c2ecf20Sopenharmony_ci 61338c2ecf20Sopenharmony_ci /* Software/Hardware configuration */ 61348c2ecf20Sopenharmony_ci dev_info(adapter->pdev_dev, "Configuration: %sNIC %s, %s capable\n", 61358c2ecf20Sopenharmony_ci is_offload(adapter) ? "R" : "", 61368c2ecf20Sopenharmony_ci ((adapter->flags & CXGB4_USING_MSIX) ? "MSI-X" : 61378c2ecf20Sopenharmony_ci (adapter->flags & CXGB4_USING_MSI) ? "MSI" : ""), 61388c2ecf20Sopenharmony_ci is_offload(adapter) ? "Offload" : "non-Offload"); 61398c2ecf20Sopenharmony_ci} 61408c2ecf20Sopenharmony_ci 61418c2ecf20Sopenharmony_cistatic void print_port_info(const struct net_device *dev) 61428c2ecf20Sopenharmony_ci{ 61438c2ecf20Sopenharmony_ci char buf[80]; 61448c2ecf20Sopenharmony_ci char *bufp = buf; 61458c2ecf20Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 61468c2ecf20Sopenharmony_ci const struct adapter *adap = pi->adapter; 61478c2ecf20Sopenharmony_ci 61488c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100M) 61498c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "100M/"); 61508c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_1G) 61518c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "1G/"); 61528c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_10G) 61538c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "10G/"); 61548c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_25G) 61558c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "25G/"); 61568c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_40G) 61578c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "40G/"); 61588c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_50G) 61598c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "50G/"); 61608c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100G) 61618c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "100G/"); 61628c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_200G) 61638c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "200G/"); 61648c2ecf20Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_400G) 61658c2ecf20Sopenharmony_ci bufp += sprintf(bufp, "400G/"); 61668c2ecf20Sopenharmony_ci if (bufp != buf) 61678c2ecf20Sopenharmony_ci --bufp; 61688c2ecf20Sopenharmony_ci sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type)); 61698c2ecf20Sopenharmony_ci 61708c2ecf20Sopenharmony_ci netdev_info(dev, "%s: Chelsio %s (%s) %s\n", 61718c2ecf20Sopenharmony_ci dev->name, adap->params.vpd.id, adap->name, buf); 61728c2ecf20Sopenharmony_ci} 61738c2ecf20Sopenharmony_ci 61748c2ecf20Sopenharmony_ci/* 61758c2ecf20Sopenharmony_ci * Free the following resources: 61768c2ecf20Sopenharmony_ci * - memory used for tables 61778c2ecf20Sopenharmony_ci * - MSI/MSI-X 61788c2ecf20Sopenharmony_ci * - net devices 61798c2ecf20Sopenharmony_ci * - resources FW is holding for us 61808c2ecf20Sopenharmony_ci */ 61818c2ecf20Sopenharmony_cistatic void free_some_resources(struct adapter *adapter) 61828c2ecf20Sopenharmony_ci{ 61838c2ecf20Sopenharmony_ci unsigned int i; 61848c2ecf20Sopenharmony_ci 61858c2ecf20Sopenharmony_ci kvfree(adapter->smt); 61868c2ecf20Sopenharmony_ci kvfree(adapter->l2t); 61878c2ecf20Sopenharmony_ci kvfree(adapter->srq); 61888c2ecf20Sopenharmony_ci t4_cleanup_sched(adapter); 61898c2ecf20Sopenharmony_ci kvfree(adapter->tids.tid_tab); 61908c2ecf20Sopenharmony_ci cxgb4_cleanup_tc_matchall(adapter); 61918c2ecf20Sopenharmony_ci cxgb4_cleanup_tc_mqprio(adapter); 61928c2ecf20Sopenharmony_ci cxgb4_cleanup_tc_flower(adapter); 61938c2ecf20Sopenharmony_ci cxgb4_cleanup_tc_u32(adapter); 61948c2ecf20Sopenharmony_ci cxgb4_cleanup_ethtool_filters(adapter); 61958c2ecf20Sopenharmony_ci kfree(adapter->sge.egr_map); 61968c2ecf20Sopenharmony_ci kfree(adapter->sge.ingr_map); 61978c2ecf20Sopenharmony_ci kfree(adapter->sge.starving_fl); 61988c2ecf20Sopenharmony_ci kfree(adapter->sge.txq_maperr); 61998c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 62008c2ecf20Sopenharmony_ci kfree(adapter->sge.blocked_fl); 62018c2ecf20Sopenharmony_ci#endif 62028c2ecf20Sopenharmony_ci disable_msi(adapter); 62038c2ecf20Sopenharmony_ci 62048c2ecf20Sopenharmony_ci for_each_port(adapter, i) 62058c2ecf20Sopenharmony_ci if (adapter->port[i]) { 62068c2ecf20Sopenharmony_ci struct port_info *pi = adap2pinfo(adapter, i); 62078c2ecf20Sopenharmony_ci 62088c2ecf20Sopenharmony_ci if (pi->viid != 0) 62098c2ecf20Sopenharmony_ci t4_free_vi(adapter, adapter->mbox, adapter->pf, 62108c2ecf20Sopenharmony_ci 0, pi->viid); 62118c2ecf20Sopenharmony_ci kfree(adap2pinfo(adapter, i)->rss); 62128c2ecf20Sopenharmony_ci free_netdev(adapter->port[i]); 62138c2ecf20Sopenharmony_ci } 62148c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) 62158c2ecf20Sopenharmony_ci t4_fw_bye(adapter, adapter->pf); 62168c2ecf20Sopenharmony_ci} 62178c2ecf20Sopenharmony_ci 62188c2ecf20Sopenharmony_ci#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | \ 62198c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_L4) 62208c2ecf20Sopenharmony_ci#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ 62218c2ecf20Sopenharmony_ci NETIF_F_GRO | NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) 62228c2ecf20Sopenharmony_ci#define SEGMENT_SIZE 128 62238c2ecf20Sopenharmony_ci 62248c2ecf20Sopenharmony_cistatic int t4_get_chip_type(struct adapter *adap, int ver) 62258c2ecf20Sopenharmony_ci{ 62268c2ecf20Sopenharmony_ci u32 pl_rev = REV_G(t4_read_reg(adap, PL_REV_A)); 62278c2ecf20Sopenharmony_ci 62288c2ecf20Sopenharmony_ci switch (ver) { 62298c2ecf20Sopenharmony_ci case CHELSIO_T4: 62308c2ecf20Sopenharmony_ci return CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); 62318c2ecf20Sopenharmony_ci case CHELSIO_T5: 62328c2ecf20Sopenharmony_ci return CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev); 62338c2ecf20Sopenharmony_ci case CHELSIO_T6: 62348c2ecf20Sopenharmony_ci return CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); 62358c2ecf20Sopenharmony_ci default: 62368c2ecf20Sopenharmony_ci break; 62378c2ecf20Sopenharmony_ci } 62388c2ecf20Sopenharmony_ci return -EINVAL; 62398c2ecf20Sopenharmony_ci} 62408c2ecf20Sopenharmony_ci 62418c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 62428c2ecf20Sopenharmony_cistatic void cxgb4_mgmt_setup(struct net_device *dev) 62438c2ecf20Sopenharmony_ci{ 62448c2ecf20Sopenharmony_ci dev->type = ARPHRD_NONE; 62458c2ecf20Sopenharmony_ci dev->mtu = 0; 62468c2ecf20Sopenharmony_ci dev->hard_header_len = 0; 62478c2ecf20Sopenharmony_ci dev->addr_len = 0; 62488c2ecf20Sopenharmony_ci dev->tx_queue_len = 0; 62498c2ecf20Sopenharmony_ci dev->flags |= IFF_NOARP; 62508c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE; 62518c2ecf20Sopenharmony_ci 62528c2ecf20Sopenharmony_ci /* Initialize the device structure. */ 62538c2ecf20Sopenharmony_ci dev->netdev_ops = &cxgb4_mgmt_netdev_ops; 62548c2ecf20Sopenharmony_ci dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops; 62558c2ecf20Sopenharmony_ci} 62568c2ecf20Sopenharmony_ci 62578c2ecf20Sopenharmony_cistatic int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs) 62588c2ecf20Sopenharmony_ci{ 62598c2ecf20Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 62608c2ecf20Sopenharmony_ci int err = 0; 62618c2ecf20Sopenharmony_ci int current_vfs = pci_num_vf(pdev); 62628c2ecf20Sopenharmony_ci u32 pcie_fw; 62638c2ecf20Sopenharmony_ci 62648c2ecf20Sopenharmony_ci pcie_fw = readl(adap->regs + PCIE_FW_A); 62658c2ecf20Sopenharmony_ci /* Check if fw is initialized */ 62668c2ecf20Sopenharmony_ci if (!(pcie_fw & PCIE_FW_INIT_F)) { 62678c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Device not initialized\n"); 62688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 62698c2ecf20Sopenharmony_ci } 62708c2ecf20Sopenharmony_ci 62718c2ecf20Sopenharmony_ci /* If any of the VF's is already assigned to Guest OS, then 62728c2ecf20Sopenharmony_ci * SRIOV for the same cannot be modified 62738c2ecf20Sopenharmony_ci */ 62748c2ecf20Sopenharmony_ci if (current_vfs && pci_vfs_assigned(pdev)) { 62758c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 62768c2ecf20Sopenharmony_ci "Cannot modify SR-IOV while VFs are assigned\n"); 62778c2ecf20Sopenharmony_ci return current_vfs; 62788c2ecf20Sopenharmony_ci } 62798c2ecf20Sopenharmony_ci /* Note that the upper-level code ensures that we're never called with 62808c2ecf20Sopenharmony_ci * a non-zero "num_vfs" when we already have VFs instantiated. But 62818c2ecf20Sopenharmony_ci * it never hurts to code defensively. 62828c2ecf20Sopenharmony_ci */ 62838c2ecf20Sopenharmony_ci if (num_vfs != 0 && current_vfs != 0) 62848c2ecf20Sopenharmony_ci return -EBUSY; 62858c2ecf20Sopenharmony_ci 62868c2ecf20Sopenharmony_ci /* Nothing to do for no change. */ 62878c2ecf20Sopenharmony_ci if (num_vfs == current_vfs) 62888c2ecf20Sopenharmony_ci return num_vfs; 62898c2ecf20Sopenharmony_ci 62908c2ecf20Sopenharmony_ci /* Disable SRIOV when zero is passed. */ 62918c2ecf20Sopenharmony_ci if (!num_vfs) { 62928c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 62938c2ecf20Sopenharmony_ci /* free VF Management Interface */ 62948c2ecf20Sopenharmony_ci unregister_netdev(adap->port[0]); 62958c2ecf20Sopenharmony_ci free_netdev(adap->port[0]); 62968c2ecf20Sopenharmony_ci adap->port[0] = NULL; 62978c2ecf20Sopenharmony_ci 62988c2ecf20Sopenharmony_ci /* free VF resources */ 62998c2ecf20Sopenharmony_ci adap->num_vfs = 0; 63008c2ecf20Sopenharmony_ci kfree(adap->vfinfo); 63018c2ecf20Sopenharmony_ci adap->vfinfo = NULL; 63028c2ecf20Sopenharmony_ci return 0; 63038c2ecf20Sopenharmony_ci } 63048c2ecf20Sopenharmony_ci 63058c2ecf20Sopenharmony_ci if (!current_vfs) { 63068c2ecf20Sopenharmony_ci struct fw_pfvf_cmd port_cmd, port_rpl; 63078c2ecf20Sopenharmony_ci struct net_device *netdev; 63088c2ecf20Sopenharmony_ci unsigned int pmask, port; 63098c2ecf20Sopenharmony_ci struct pci_dev *pbridge; 63108c2ecf20Sopenharmony_ci struct port_info *pi; 63118c2ecf20Sopenharmony_ci char name[IFNAMSIZ]; 63128c2ecf20Sopenharmony_ci u32 devcap2; 63138c2ecf20Sopenharmony_ci u16 flags; 63148c2ecf20Sopenharmony_ci 63158c2ecf20Sopenharmony_ci /* If we want to instantiate Virtual Functions, then our 63168c2ecf20Sopenharmony_ci * parent bridge's PCI-E needs to support Alternative Routing 63178c2ecf20Sopenharmony_ci * ID (ARI) because our VFs will show up at function offset 8 63188c2ecf20Sopenharmony_ci * and above. 63198c2ecf20Sopenharmony_ci */ 63208c2ecf20Sopenharmony_ci pbridge = pdev->bus->self; 63218c2ecf20Sopenharmony_ci pcie_capability_read_word(pbridge, PCI_EXP_FLAGS, &flags); 63228c2ecf20Sopenharmony_ci pcie_capability_read_dword(pbridge, PCI_EXP_DEVCAP2, &devcap2); 63238c2ecf20Sopenharmony_ci 63248c2ecf20Sopenharmony_ci if ((flags & PCI_EXP_FLAGS_VERS) < 2 || 63258c2ecf20Sopenharmony_ci !(devcap2 & PCI_EXP_DEVCAP2_ARI)) { 63268c2ecf20Sopenharmony_ci /* Our parent bridge does not support ARI so issue a 63278c2ecf20Sopenharmony_ci * warning and skip instantiating the VFs. They 63288c2ecf20Sopenharmony_ci * won't be reachable. 63298c2ecf20Sopenharmony_ci */ 63308c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Parent bridge %02x:%02x.%x doesn't support ARI; can't instantiate Virtual Functions\n", 63318c2ecf20Sopenharmony_ci pbridge->bus->number, PCI_SLOT(pbridge->devfn), 63328c2ecf20Sopenharmony_ci PCI_FUNC(pbridge->devfn)); 63338c2ecf20Sopenharmony_ci return -ENOTSUPP; 63348c2ecf20Sopenharmony_ci } 63358c2ecf20Sopenharmony_ci memset(&port_cmd, 0, sizeof(port_cmd)); 63368c2ecf20Sopenharmony_ci port_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) | 63378c2ecf20Sopenharmony_ci FW_CMD_REQUEST_F | 63388c2ecf20Sopenharmony_ci FW_CMD_READ_F | 63398c2ecf20Sopenharmony_ci FW_PFVF_CMD_PFN_V(adap->pf) | 63408c2ecf20Sopenharmony_ci FW_PFVF_CMD_VFN_V(0)); 63418c2ecf20Sopenharmony_ci port_cmd.retval_len16 = cpu_to_be32(FW_LEN16(port_cmd)); 63428c2ecf20Sopenharmony_ci err = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd), 63438c2ecf20Sopenharmony_ci &port_rpl); 63448c2ecf20Sopenharmony_ci if (err) 63458c2ecf20Sopenharmony_ci return err; 63468c2ecf20Sopenharmony_ci pmask = FW_PFVF_CMD_PMASK_G(be32_to_cpu(port_rpl.type_to_neq)); 63478c2ecf20Sopenharmony_ci port = ffs(pmask) - 1; 63488c2ecf20Sopenharmony_ci /* Allocate VF Management Interface. */ 63498c2ecf20Sopenharmony_ci snprintf(name, IFNAMSIZ, "mgmtpf%d,%d", adap->adap_idx, 63508c2ecf20Sopenharmony_ci adap->pf); 63518c2ecf20Sopenharmony_ci netdev = alloc_netdev(sizeof(struct port_info), 63528c2ecf20Sopenharmony_ci name, NET_NAME_UNKNOWN, cxgb4_mgmt_setup); 63538c2ecf20Sopenharmony_ci if (!netdev) 63548c2ecf20Sopenharmony_ci return -ENOMEM; 63558c2ecf20Sopenharmony_ci 63568c2ecf20Sopenharmony_ci pi = netdev_priv(netdev); 63578c2ecf20Sopenharmony_ci pi->adapter = adap; 63588c2ecf20Sopenharmony_ci pi->lport = port; 63598c2ecf20Sopenharmony_ci pi->tx_chan = port; 63608c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 63618c2ecf20Sopenharmony_ci 63628c2ecf20Sopenharmony_ci adap->port[0] = netdev; 63638c2ecf20Sopenharmony_ci pi->port_id = 0; 63648c2ecf20Sopenharmony_ci 63658c2ecf20Sopenharmony_ci err = register_netdev(adap->port[0]); 63668c2ecf20Sopenharmony_ci if (err) { 63678c2ecf20Sopenharmony_ci pr_info("Unable to register VF mgmt netdev %s\n", name); 63688c2ecf20Sopenharmony_ci free_netdev(adap->port[0]); 63698c2ecf20Sopenharmony_ci adap->port[0] = NULL; 63708c2ecf20Sopenharmony_ci return err; 63718c2ecf20Sopenharmony_ci } 63728c2ecf20Sopenharmony_ci /* Allocate and set up VF Information. */ 63738c2ecf20Sopenharmony_ci adap->vfinfo = kcalloc(pci_sriov_get_totalvfs(pdev), 63748c2ecf20Sopenharmony_ci sizeof(struct vf_info), GFP_KERNEL); 63758c2ecf20Sopenharmony_ci if (!adap->vfinfo) { 63768c2ecf20Sopenharmony_ci unregister_netdev(adap->port[0]); 63778c2ecf20Sopenharmony_ci free_netdev(adap->port[0]); 63788c2ecf20Sopenharmony_ci adap->port[0] = NULL; 63798c2ecf20Sopenharmony_ci return -ENOMEM; 63808c2ecf20Sopenharmony_ci } 63818c2ecf20Sopenharmony_ci cxgb4_mgmt_fill_vf_station_mac_addr(adap); 63828c2ecf20Sopenharmony_ci } 63838c2ecf20Sopenharmony_ci /* Instantiate the requested number of VFs. */ 63848c2ecf20Sopenharmony_ci err = pci_enable_sriov(pdev, num_vfs); 63858c2ecf20Sopenharmony_ci if (err) { 63868c2ecf20Sopenharmony_ci pr_info("Unable to instantiate %d VFs\n", num_vfs); 63878c2ecf20Sopenharmony_ci if (!current_vfs) { 63888c2ecf20Sopenharmony_ci unregister_netdev(adap->port[0]); 63898c2ecf20Sopenharmony_ci free_netdev(adap->port[0]); 63908c2ecf20Sopenharmony_ci adap->port[0] = NULL; 63918c2ecf20Sopenharmony_ci kfree(adap->vfinfo); 63928c2ecf20Sopenharmony_ci adap->vfinfo = NULL; 63938c2ecf20Sopenharmony_ci } 63948c2ecf20Sopenharmony_ci return err; 63958c2ecf20Sopenharmony_ci } 63968c2ecf20Sopenharmony_ci 63978c2ecf20Sopenharmony_ci adap->num_vfs = num_vfs; 63988c2ecf20Sopenharmony_ci return num_vfs; 63998c2ecf20Sopenharmony_ci} 64008c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI_IOV */ 64018c2ecf20Sopenharmony_ci 64028c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) || IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 64038c2ecf20Sopenharmony_ci 64048c2ecf20Sopenharmony_cistatic int chcr_offload_state(struct adapter *adap, 64058c2ecf20Sopenharmony_ci enum cxgb4_netdev_tls_ops op_val) 64068c2ecf20Sopenharmony_ci{ 64078c2ecf20Sopenharmony_ci switch (op_val) { 64088c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 64098c2ecf20Sopenharmony_ci case CXGB4_TLSDEV_OPS: 64108c2ecf20Sopenharmony_ci if (!adap->uld[CXGB4_ULD_KTLS].handle) { 64118c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, "ch_ktls driver is not loaded\n"); 64128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 64138c2ecf20Sopenharmony_ci } 64148c2ecf20Sopenharmony_ci if (!adap->uld[CXGB4_ULD_KTLS].tlsdev_ops) { 64158c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 64168c2ecf20Sopenharmony_ci "ch_ktls driver has no registered tlsdev_ops\n"); 64178c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 64188c2ecf20Sopenharmony_ci } 64198c2ecf20Sopenharmony_ci break; 64208c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */ 64218c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 64228c2ecf20Sopenharmony_ci case CXGB4_XFRMDEV_OPS: 64238c2ecf20Sopenharmony_ci if (!adap->uld[CXGB4_ULD_IPSEC].handle) { 64248c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, "chipsec driver is not loaded\n"); 64258c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 64268c2ecf20Sopenharmony_ci } 64278c2ecf20Sopenharmony_ci if (!adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops) { 64288c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 64298c2ecf20Sopenharmony_ci "chipsec driver has no registered xfrmdev_ops\n"); 64308c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 64318c2ecf20Sopenharmony_ci } 64328c2ecf20Sopenharmony_ci break; 64338c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ 64348c2ecf20Sopenharmony_ci default: 64358c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 64368c2ecf20Sopenharmony_ci "driver has no support for offload %d\n", op_val); 64378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 64388c2ecf20Sopenharmony_ci } 64398c2ecf20Sopenharmony_ci 64408c2ecf20Sopenharmony_ci return 0; 64418c2ecf20Sopenharmony_ci} 64428c2ecf20Sopenharmony_ci 64438c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE || CONFIG_CHELSIO_IPSEC_INLINE */ 64448c2ecf20Sopenharmony_ci 64458c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 64468c2ecf20Sopenharmony_ci 64478c2ecf20Sopenharmony_cistatic int cxgb4_ktls_dev_add(struct net_device *netdev, struct sock *sk, 64488c2ecf20Sopenharmony_ci enum tls_offload_ctx_dir direction, 64498c2ecf20Sopenharmony_ci struct tls_crypto_info *crypto_info, 64508c2ecf20Sopenharmony_ci u32 tcp_sn) 64518c2ecf20Sopenharmony_ci{ 64528c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 64538c2ecf20Sopenharmony_ci int ret; 64548c2ecf20Sopenharmony_ci 64558c2ecf20Sopenharmony_ci mutex_lock(&uld_mutex); 64568c2ecf20Sopenharmony_ci ret = chcr_offload_state(adap, CXGB4_TLSDEV_OPS); 64578c2ecf20Sopenharmony_ci if (ret) 64588c2ecf20Sopenharmony_ci goto out_unlock; 64598c2ecf20Sopenharmony_ci 64608c2ecf20Sopenharmony_ci ret = cxgb4_set_ktls_feature(adap, FW_PARAMS_PARAM_DEV_KTLS_HW_ENABLE); 64618c2ecf20Sopenharmony_ci if (ret) 64628c2ecf20Sopenharmony_ci goto out_unlock; 64638c2ecf20Sopenharmony_ci 64648c2ecf20Sopenharmony_ci ret = adap->uld[CXGB4_ULD_KTLS].tlsdev_ops->tls_dev_add(netdev, sk, 64658c2ecf20Sopenharmony_ci direction, 64668c2ecf20Sopenharmony_ci crypto_info, 64678c2ecf20Sopenharmony_ci tcp_sn); 64688c2ecf20Sopenharmony_ci /* if there is a failure, clear the refcount */ 64698c2ecf20Sopenharmony_ci if (ret) 64708c2ecf20Sopenharmony_ci cxgb4_set_ktls_feature(adap, 64718c2ecf20Sopenharmony_ci FW_PARAMS_PARAM_DEV_KTLS_HW_DISABLE); 64728c2ecf20Sopenharmony_ciout_unlock: 64738c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 64748c2ecf20Sopenharmony_ci return ret; 64758c2ecf20Sopenharmony_ci} 64768c2ecf20Sopenharmony_ci 64778c2ecf20Sopenharmony_cistatic void cxgb4_ktls_dev_del(struct net_device *netdev, 64788c2ecf20Sopenharmony_ci struct tls_context *tls_ctx, 64798c2ecf20Sopenharmony_ci enum tls_offload_ctx_dir direction) 64808c2ecf20Sopenharmony_ci{ 64818c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 64828c2ecf20Sopenharmony_ci 64838c2ecf20Sopenharmony_ci mutex_lock(&uld_mutex); 64848c2ecf20Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_TLSDEV_OPS)) 64858c2ecf20Sopenharmony_ci goto out_unlock; 64868c2ecf20Sopenharmony_ci 64878c2ecf20Sopenharmony_ci adap->uld[CXGB4_ULD_KTLS].tlsdev_ops->tls_dev_del(netdev, tls_ctx, 64888c2ecf20Sopenharmony_ci direction); 64898c2ecf20Sopenharmony_ci 64908c2ecf20Sopenharmony_ciout_unlock: 64918c2ecf20Sopenharmony_ci cxgb4_set_ktls_feature(adap, FW_PARAMS_PARAM_DEV_KTLS_HW_DISABLE); 64928c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 64938c2ecf20Sopenharmony_ci} 64948c2ecf20Sopenharmony_ci 64958c2ecf20Sopenharmony_cistatic const struct tlsdev_ops cxgb4_ktls_ops = { 64968c2ecf20Sopenharmony_ci .tls_dev_add = cxgb4_ktls_dev_add, 64978c2ecf20Sopenharmony_ci .tls_dev_del = cxgb4_ktls_dev_del, 64988c2ecf20Sopenharmony_ci}; 64998c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */ 65008c2ecf20Sopenharmony_ci 65018c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 65028c2ecf20Sopenharmony_ci 65038c2ecf20Sopenharmony_cistatic int cxgb4_xfrm_add_state(struct xfrm_state *x) 65048c2ecf20Sopenharmony_ci{ 65058c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 65068c2ecf20Sopenharmony_ci int ret; 65078c2ecf20Sopenharmony_ci 65088c2ecf20Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 65098c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 65108c2ecf20Sopenharmony_ci "crypto uld critical resource is under use\n"); 65118c2ecf20Sopenharmony_ci return -EBUSY; 65128c2ecf20Sopenharmony_ci } 65138c2ecf20Sopenharmony_ci ret = chcr_offload_state(adap, CXGB4_XFRMDEV_OPS); 65148c2ecf20Sopenharmony_ci if (ret) 65158c2ecf20Sopenharmony_ci goto out_unlock; 65168c2ecf20Sopenharmony_ci 65178c2ecf20Sopenharmony_ci ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(x); 65188c2ecf20Sopenharmony_ci 65198c2ecf20Sopenharmony_ciout_unlock: 65208c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 65218c2ecf20Sopenharmony_ci 65228c2ecf20Sopenharmony_ci return ret; 65238c2ecf20Sopenharmony_ci} 65248c2ecf20Sopenharmony_ci 65258c2ecf20Sopenharmony_cistatic void cxgb4_xfrm_del_state(struct xfrm_state *x) 65268c2ecf20Sopenharmony_ci{ 65278c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 65308c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 65318c2ecf20Sopenharmony_ci "crypto uld critical resource is under use\n"); 65328c2ecf20Sopenharmony_ci return; 65338c2ecf20Sopenharmony_ci } 65348c2ecf20Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 65358c2ecf20Sopenharmony_ci goto out_unlock; 65368c2ecf20Sopenharmony_ci 65378c2ecf20Sopenharmony_ci adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(x); 65388c2ecf20Sopenharmony_ci 65398c2ecf20Sopenharmony_ciout_unlock: 65408c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 65418c2ecf20Sopenharmony_ci} 65428c2ecf20Sopenharmony_ci 65438c2ecf20Sopenharmony_cistatic void cxgb4_xfrm_free_state(struct xfrm_state *x) 65448c2ecf20Sopenharmony_ci{ 65458c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 65468c2ecf20Sopenharmony_ci 65478c2ecf20Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 65488c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 65498c2ecf20Sopenharmony_ci "crypto uld critical resource is under use\n"); 65508c2ecf20Sopenharmony_ci return; 65518c2ecf20Sopenharmony_ci } 65528c2ecf20Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 65538c2ecf20Sopenharmony_ci goto out_unlock; 65548c2ecf20Sopenharmony_ci 65558c2ecf20Sopenharmony_ci adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(x); 65568c2ecf20Sopenharmony_ci 65578c2ecf20Sopenharmony_ciout_unlock: 65588c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 65598c2ecf20Sopenharmony_ci} 65608c2ecf20Sopenharmony_ci 65618c2ecf20Sopenharmony_cistatic bool cxgb4_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x) 65628c2ecf20Sopenharmony_ci{ 65638c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 65648c2ecf20Sopenharmony_ci bool ret = false; 65658c2ecf20Sopenharmony_ci 65668c2ecf20Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 65678c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 65688c2ecf20Sopenharmony_ci "crypto uld critical resource is under use\n"); 65698c2ecf20Sopenharmony_ci return ret; 65708c2ecf20Sopenharmony_ci } 65718c2ecf20Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 65728c2ecf20Sopenharmony_ci goto out_unlock; 65738c2ecf20Sopenharmony_ci 65748c2ecf20Sopenharmony_ci ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_offload_ok(skb, x); 65758c2ecf20Sopenharmony_ci 65768c2ecf20Sopenharmony_ciout_unlock: 65778c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 65788c2ecf20Sopenharmony_ci return ret; 65798c2ecf20Sopenharmony_ci} 65808c2ecf20Sopenharmony_ci 65818c2ecf20Sopenharmony_cistatic void cxgb4_advance_esn_state(struct xfrm_state *x) 65828c2ecf20Sopenharmony_ci{ 65838c2ecf20Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 65848c2ecf20Sopenharmony_ci 65858c2ecf20Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 65868c2ecf20Sopenharmony_ci dev_dbg(adap->pdev_dev, 65878c2ecf20Sopenharmony_ci "crypto uld critical resource is under use\n"); 65888c2ecf20Sopenharmony_ci return; 65898c2ecf20Sopenharmony_ci } 65908c2ecf20Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 65918c2ecf20Sopenharmony_ci goto out_unlock; 65928c2ecf20Sopenharmony_ci 65938c2ecf20Sopenharmony_ci adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_advance_esn(x); 65948c2ecf20Sopenharmony_ci 65958c2ecf20Sopenharmony_ciout_unlock: 65968c2ecf20Sopenharmony_ci mutex_unlock(&uld_mutex); 65978c2ecf20Sopenharmony_ci} 65988c2ecf20Sopenharmony_ci 65998c2ecf20Sopenharmony_cistatic const struct xfrmdev_ops cxgb4_xfrmdev_ops = { 66008c2ecf20Sopenharmony_ci .xdo_dev_state_add = cxgb4_xfrm_add_state, 66018c2ecf20Sopenharmony_ci .xdo_dev_state_delete = cxgb4_xfrm_del_state, 66028c2ecf20Sopenharmony_ci .xdo_dev_state_free = cxgb4_xfrm_free_state, 66038c2ecf20Sopenharmony_ci .xdo_dev_offload_ok = cxgb4_ipsec_offload_ok, 66048c2ecf20Sopenharmony_ci .xdo_dev_state_advance_esn = cxgb4_advance_esn_state, 66058c2ecf20Sopenharmony_ci}; 66068c2ecf20Sopenharmony_ci 66078c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ 66088c2ecf20Sopenharmony_ci 66098c2ecf20Sopenharmony_cistatic int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 66108c2ecf20Sopenharmony_ci{ 66118c2ecf20Sopenharmony_ci struct net_device *netdev; 66128c2ecf20Sopenharmony_ci struct adapter *adapter; 66138c2ecf20Sopenharmony_ci static int adap_idx = 1; 66148c2ecf20Sopenharmony_ci int s_qpp, qpp, num_seg; 66158c2ecf20Sopenharmony_ci struct port_info *pi; 66168c2ecf20Sopenharmony_ci bool highdma = false; 66178c2ecf20Sopenharmony_ci enum chip_type chip; 66188c2ecf20Sopenharmony_ci void __iomem *regs; 66198c2ecf20Sopenharmony_ci int func, chip_ver; 66208c2ecf20Sopenharmony_ci u16 device_id; 66218c2ecf20Sopenharmony_ci int i, err; 66228c2ecf20Sopenharmony_ci u32 whoami; 66238c2ecf20Sopenharmony_ci 66248c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, KBUILD_MODNAME); 66258c2ecf20Sopenharmony_ci if (err) { 66268c2ecf20Sopenharmony_ci /* Just info, some other driver may have claimed the device. */ 66278c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "cannot obtain PCI resources\n"); 66288c2ecf20Sopenharmony_ci return err; 66298c2ecf20Sopenharmony_ci } 66308c2ecf20Sopenharmony_ci 66318c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 66328c2ecf20Sopenharmony_ci if (err) { 66338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot enable PCI device\n"); 66348c2ecf20Sopenharmony_ci goto out_release_regions; 66358c2ecf20Sopenharmony_ci } 66368c2ecf20Sopenharmony_ci 66378c2ecf20Sopenharmony_ci regs = pci_ioremap_bar(pdev, 0); 66388c2ecf20Sopenharmony_ci if (!regs) { 66398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot map device registers\n"); 66408c2ecf20Sopenharmony_ci err = -ENOMEM; 66418c2ecf20Sopenharmony_ci goto out_disable_device; 66428c2ecf20Sopenharmony_ci } 66438c2ecf20Sopenharmony_ci 66448c2ecf20Sopenharmony_ci adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); 66458c2ecf20Sopenharmony_ci if (!adapter) { 66468c2ecf20Sopenharmony_ci err = -ENOMEM; 66478c2ecf20Sopenharmony_ci goto out_unmap_bar0; 66488c2ecf20Sopenharmony_ci } 66498c2ecf20Sopenharmony_ci 66508c2ecf20Sopenharmony_ci adapter->regs = regs; 66518c2ecf20Sopenharmony_ci err = t4_wait_dev_ready(regs); 66528c2ecf20Sopenharmony_ci if (err < 0) 66538c2ecf20Sopenharmony_ci goto out_free_adapter; 66548c2ecf20Sopenharmony_ci 66558c2ecf20Sopenharmony_ci /* We control everything through one PF */ 66568c2ecf20Sopenharmony_ci whoami = t4_read_reg(adapter, PL_WHOAMI_A); 66578c2ecf20Sopenharmony_ci pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 66588c2ecf20Sopenharmony_ci chip = t4_get_chip_type(adapter, CHELSIO_PCI_ID_VER(device_id)); 66598c2ecf20Sopenharmony_ci if ((int)chip < 0) { 66608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Device %d is not supported\n", device_id); 66618c2ecf20Sopenharmony_ci err = chip; 66628c2ecf20Sopenharmony_ci goto out_free_adapter; 66638c2ecf20Sopenharmony_ci } 66648c2ecf20Sopenharmony_ci chip_ver = CHELSIO_CHIP_VERSION(chip); 66658c2ecf20Sopenharmony_ci func = chip_ver <= CHELSIO_T5 ? 66668c2ecf20Sopenharmony_ci SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); 66678c2ecf20Sopenharmony_ci 66688c2ecf20Sopenharmony_ci adapter->pdev = pdev; 66698c2ecf20Sopenharmony_ci adapter->pdev_dev = &pdev->dev; 66708c2ecf20Sopenharmony_ci adapter->name = pci_name(pdev); 66718c2ecf20Sopenharmony_ci adapter->mbox = func; 66728c2ecf20Sopenharmony_ci adapter->pf = func; 66738c2ecf20Sopenharmony_ci adapter->params.chip = chip; 66748c2ecf20Sopenharmony_ci adapter->adap_idx = adap_idx; 66758c2ecf20Sopenharmony_ci adapter->msg_enable = DFLT_MSG_ENABLE; 66768c2ecf20Sopenharmony_ci adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) + 66778c2ecf20Sopenharmony_ci (sizeof(struct mbox_cmd) * 66788c2ecf20Sopenharmony_ci T4_OS_LOG_MBOX_CMDS), 66798c2ecf20Sopenharmony_ci GFP_KERNEL); 66808c2ecf20Sopenharmony_ci if (!adapter->mbox_log) { 66818c2ecf20Sopenharmony_ci err = -ENOMEM; 66828c2ecf20Sopenharmony_ci goto out_free_adapter; 66838c2ecf20Sopenharmony_ci } 66848c2ecf20Sopenharmony_ci spin_lock_init(&adapter->mbox_lock); 66858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->mlist.list); 66868c2ecf20Sopenharmony_ci adapter->mbox_log->size = T4_OS_LOG_MBOX_CMDS; 66878c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, adapter); 66888c2ecf20Sopenharmony_ci 66898c2ecf20Sopenharmony_ci if (func != ent->driver_data) { 66908c2ecf20Sopenharmony_ci pci_disable_device(pdev); 66918c2ecf20Sopenharmony_ci pci_save_state(pdev); /* to restore SR-IOV later */ 66928c2ecf20Sopenharmony_ci return 0; 66938c2ecf20Sopenharmony_ci } 66948c2ecf20Sopenharmony_ci 66958c2ecf20Sopenharmony_ci if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { 66968c2ecf20Sopenharmony_ci highdma = true; 66978c2ecf20Sopenharmony_ci err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 66988c2ecf20Sopenharmony_ci if (err) { 66998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " 67008c2ecf20Sopenharmony_ci "coherent allocations\n"); 67018c2ecf20Sopenharmony_ci goto out_free_adapter; 67028c2ecf20Sopenharmony_ci } 67038c2ecf20Sopenharmony_ci } else { 67048c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 67058c2ecf20Sopenharmony_ci if (err) { 67068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no usable DMA configuration\n"); 67078c2ecf20Sopenharmony_ci goto out_free_adapter; 67088c2ecf20Sopenharmony_ci } 67098c2ecf20Sopenharmony_ci } 67108c2ecf20Sopenharmony_ci 67118c2ecf20Sopenharmony_ci pci_enable_pcie_error_reporting(pdev); 67128c2ecf20Sopenharmony_ci pci_set_master(pdev); 67138c2ecf20Sopenharmony_ci pci_save_state(pdev); 67148c2ecf20Sopenharmony_ci adap_idx++; 67158c2ecf20Sopenharmony_ci adapter->workq = create_singlethread_workqueue("cxgb4"); 67168c2ecf20Sopenharmony_ci if (!adapter->workq) { 67178c2ecf20Sopenharmony_ci err = -ENOMEM; 67188c2ecf20Sopenharmony_ci goto out_free_adapter; 67198c2ecf20Sopenharmony_ci } 67208c2ecf20Sopenharmony_ci 67218c2ecf20Sopenharmony_ci /* PCI device has been enabled */ 67228c2ecf20Sopenharmony_ci adapter->flags |= CXGB4_DEV_ENABLED; 67238c2ecf20Sopenharmony_ci memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map)); 67248c2ecf20Sopenharmony_ci 67258c2ecf20Sopenharmony_ci /* If possible, we use PCIe Relaxed Ordering Attribute to deliver 67268c2ecf20Sopenharmony_ci * Ingress Packet Data to Free List Buffers in order to allow for 67278c2ecf20Sopenharmony_ci * chipset performance optimizations between the Root Complex and 67288c2ecf20Sopenharmony_ci * Memory Controllers. (Messages to the associated Ingress Queue 67298c2ecf20Sopenharmony_ci * notifying new Packet Placement in the Free Lists Buffers will be 67308c2ecf20Sopenharmony_ci * send without the Relaxed Ordering Attribute thus guaranteeing that 67318c2ecf20Sopenharmony_ci * all preceding PCIe Transaction Layer Packets will be processed 67328c2ecf20Sopenharmony_ci * first.) But some Root Complexes have various issues with Upstream 67338c2ecf20Sopenharmony_ci * Transaction Layer Packets with the Relaxed Ordering Attribute set. 67348c2ecf20Sopenharmony_ci * The PCIe devices which under the Root Complexes will be cleared the 67358c2ecf20Sopenharmony_ci * Relaxed Ordering bit in the configuration space, So we check our 67368c2ecf20Sopenharmony_ci * PCIe configuration space to see if it's flagged with advice against 67378c2ecf20Sopenharmony_ci * using Relaxed Ordering. 67388c2ecf20Sopenharmony_ci */ 67398c2ecf20Sopenharmony_ci if (!pcie_relaxed_ordering_enabled(pdev)) 67408c2ecf20Sopenharmony_ci adapter->flags |= CXGB4_ROOT_NO_RELAXED_ORDERING; 67418c2ecf20Sopenharmony_ci 67428c2ecf20Sopenharmony_ci spin_lock_init(&adapter->stats_lock); 67438c2ecf20Sopenharmony_ci spin_lock_init(&adapter->tid_release_lock); 67448c2ecf20Sopenharmony_ci spin_lock_init(&adapter->win0_lock); 67458c2ecf20Sopenharmony_ci 67468c2ecf20Sopenharmony_ci INIT_WORK(&adapter->tid_release_task, process_tid_release_list); 67478c2ecf20Sopenharmony_ci INIT_WORK(&adapter->db_full_task, process_db_full); 67488c2ecf20Sopenharmony_ci INIT_WORK(&adapter->db_drop_task, process_db_drop); 67498c2ecf20Sopenharmony_ci INIT_WORK(&adapter->fatal_err_notify_task, notify_fatal_err); 67508c2ecf20Sopenharmony_ci 67518c2ecf20Sopenharmony_ci err = t4_prep_adapter(adapter); 67528c2ecf20Sopenharmony_ci if (err) 67538c2ecf20Sopenharmony_ci goto out_free_adapter; 67548c2ecf20Sopenharmony_ci 67558c2ecf20Sopenharmony_ci if (is_kdump_kernel()) { 67568c2ecf20Sopenharmony_ci /* Collect hardware state and append to /proc/vmcore */ 67578c2ecf20Sopenharmony_ci err = cxgb4_cudbg_vmcore_add_dump(adapter); 67588c2ecf20Sopenharmony_ci if (err) { 67598c2ecf20Sopenharmony_ci dev_warn(adapter->pdev_dev, 67608c2ecf20Sopenharmony_ci "Fail collecting vmcore device dump, err: %d. Continuing\n", 67618c2ecf20Sopenharmony_ci err); 67628c2ecf20Sopenharmony_ci err = 0; 67638c2ecf20Sopenharmony_ci } 67648c2ecf20Sopenharmony_ci } 67658c2ecf20Sopenharmony_ci 67668c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 67678c2ecf20Sopenharmony_ci s_qpp = (QUEUESPERPAGEPF0_S + 67688c2ecf20Sopenharmony_ci (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * 67698c2ecf20Sopenharmony_ci adapter->pf); 67708c2ecf20Sopenharmony_ci qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter, 67718c2ecf20Sopenharmony_ci SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp); 67728c2ecf20Sopenharmony_ci num_seg = PAGE_SIZE / SEGMENT_SIZE; 67738c2ecf20Sopenharmony_ci 67748c2ecf20Sopenharmony_ci /* Each segment size is 128B. Write coalescing is enabled only 67758c2ecf20Sopenharmony_ci * when SGE_EGRESS_QUEUES_PER_PAGE_PF reg value for the 67768c2ecf20Sopenharmony_ci * queue is less no of segments that can be accommodated in 67778c2ecf20Sopenharmony_ci * a page size. 67788c2ecf20Sopenharmony_ci */ 67798c2ecf20Sopenharmony_ci if (qpp > num_seg) { 67808c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 67818c2ecf20Sopenharmony_ci "Incorrect number of egress queues per page\n"); 67828c2ecf20Sopenharmony_ci err = -EINVAL; 67838c2ecf20Sopenharmony_ci goto out_free_adapter; 67848c2ecf20Sopenharmony_ci } 67858c2ecf20Sopenharmony_ci adapter->bar2 = ioremap_wc(pci_resource_start(pdev, 2), 67868c2ecf20Sopenharmony_ci pci_resource_len(pdev, 2)); 67878c2ecf20Sopenharmony_ci if (!adapter->bar2) { 67888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot map device bar2 region\n"); 67898c2ecf20Sopenharmony_ci err = -ENOMEM; 67908c2ecf20Sopenharmony_ci goto out_free_adapter; 67918c2ecf20Sopenharmony_ci } 67928c2ecf20Sopenharmony_ci } 67938c2ecf20Sopenharmony_ci 67948c2ecf20Sopenharmony_ci setup_memwin(adapter); 67958c2ecf20Sopenharmony_ci err = adap_init0(adapter, 0); 67968c2ecf20Sopenharmony_ci if (err) 67978c2ecf20Sopenharmony_ci goto out_unmap_bar; 67988c2ecf20Sopenharmony_ci 67998c2ecf20Sopenharmony_ci setup_memwin_rdma(adapter); 68008c2ecf20Sopenharmony_ci 68018c2ecf20Sopenharmony_ci /* configure SGE_STAT_CFG_A to read WC stats */ 68028c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) 68038c2ecf20Sopenharmony_ci t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7) | 68048c2ecf20Sopenharmony_ci (is_t5(adapter->params.chip) ? STATMODE_V(0) : 68058c2ecf20Sopenharmony_ci T6_STATMODE_V(0))); 68068c2ecf20Sopenharmony_ci 68078c2ecf20Sopenharmony_ci /* Initialize hash mac addr list */ 68088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->mac_hlist); 68098c2ecf20Sopenharmony_ci 68108c2ecf20Sopenharmony_ci for_each_port(adapter, i) { 68118c2ecf20Sopenharmony_ci /* For supporting MQPRIO Offload, need some extra 68128c2ecf20Sopenharmony_ci * queues for each ETHOFLD TIDs. Keep it equal to 68138c2ecf20Sopenharmony_ci * MAX_ATIDs for now. Once we connect to firmware 68148c2ecf20Sopenharmony_ci * later and query the EOTID params, we'll come to 68158c2ecf20Sopenharmony_ci * know the actual # of EOTIDs supported. 68168c2ecf20Sopenharmony_ci */ 68178c2ecf20Sopenharmony_ci netdev = alloc_etherdev_mq(sizeof(struct port_info), 68188c2ecf20Sopenharmony_ci MAX_ETH_QSETS + MAX_ATIDS); 68198c2ecf20Sopenharmony_ci if (!netdev) { 68208c2ecf20Sopenharmony_ci err = -ENOMEM; 68218c2ecf20Sopenharmony_ci goto out_free_dev; 68228c2ecf20Sopenharmony_ci } 68238c2ecf20Sopenharmony_ci 68248c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 68258c2ecf20Sopenharmony_ci 68268c2ecf20Sopenharmony_ci adapter->port[i] = netdev; 68278c2ecf20Sopenharmony_ci pi = netdev_priv(netdev); 68288c2ecf20Sopenharmony_ci pi->adapter = adapter; 68298c2ecf20Sopenharmony_ci pi->xact_addr_filt = -1; 68308c2ecf20Sopenharmony_ci pi->port_id = i; 68318c2ecf20Sopenharmony_ci netdev->irq = pdev->irq; 68328c2ecf20Sopenharmony_ci 68338c2ecf20Sopenharmony_ci netdev->hw_features = NETIF_F_SG | TSO_FLAGS | 68348c2ecf20Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 68358c2ecf20Sopenharmony_ci NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_GRO | 68368c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | 68378c2ecf20Sopenharmony_ci NETIF_F_HW_TC | NETIF_F_NTUPLE; 68388c2ecf20Sopenharmony_ci 68398c2ecf20Sopenharmony_ci if (chip_ver > CHELSIO_T5) { 68408c2ecf20Sopenharmony_ci netdev->hw_enc_features |= NETIF_F_IP_CSUM | 68418c2ecf20Sopenharmony_ci NETIF_F_IPV6_CSUM | 68428c2ecf20Sopenharmony_ci NETIF_F_RXCSUM | 68438c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 68448c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 68458c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6; 68468c2ecf20Sopenharmony_ci 68478c2ecf20Sopenharmony_ci netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL | 68488c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 68498c2ecf20Sopenharmony_ci NETIF_F_HW_TLS_RECORD; 68508c2ecf20Sopenharmony_ci 68518c2ecf20Sopenharmony_ci if (adapter->rawf_cnt) 68528c2ecf20Sopenharmony_ci netdev->udp_tunnel_nic_info = &cxgb_udp_tunnels; 68538c2ecf20Sopenharmony_ci } 68548c2ecf20Sopenharmony_ci 68558c2ecf20Sopenharmony_ci if (highdma) 68568c2ecf20Sopenharmony_ci netdev->hw_features |= NETIF_F_HIGHDMA; 68578c2ecf20Sopenharmony_ci netdev->features |= netdev->hw_features; 68588c2ecf20Sopenharmony_ci netdev->vlan_features = netdev->features & VLAN_FEAT; 68598c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 68608c2ecf20Sopenharmony_ci if (pi->adapter->params.crypto & FW_CAPS_CONFIG_TLS_HW) { 68618c2ecf20Sopenharmony_ci netdev->hw_features |= NETIF_F_HW_TLS_TX; 68628c2ecf20Sopenharmony_ci netdev->tlsdev_ops = &cxgb4_ktls_ops; 68638c2ecf20Sopenharmony_ci /* initialize the refcount */ 68648c2ecf20Sopenharmony_ci refcount_set(&pi->adapter->chcr_ktls.ktls_refcount, 0); 68658c2ecf20Sopenharmony_ci } 68668c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */ 68678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 68688c2ecf20Sopenharmony_ci if (pi->adapter->params.crypto & FW_CAPS_CONFIG_IPSEC_INLINE) { 68698c2ecf20Sopenharmony_ci netdev->hw_enc_features |= NETIF_F_HW_ESP; 68708c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_HW_ESP; 68718c2ecf20Sopenharmony_ci netdev->xfrmdev_ops = &cxgb4_xfrmdev_ops; 68728c2ecf20Sopenharmony_ci } 68738c2ecf20Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ 68748c2ecf20Sopenharmony_ci 68758c2ecf20Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 68768c2ecf20Sopenharmony_ci 68778c2ecf20Sopenharmony_ci /* MTU range: 81 - 9600 */ 68788c2ecf20Sopenharmony_ci netdev->min_mtu = 81; /* accommodate SACK */ 68798c2ecf20Sopenharmony_ci netdev->max_mtu = MAX_MTU; 68808c2ecf20Sopenharmony_ci 68818c2ecf20Sopenharmony_ci netdev->netdev_ops = &cxgb4_netdev_ops; 68828c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 68838c2ecf20Sopenharmony_ci netdev->dcbnl_ops = &cxgb4_dcb_ops; 68848c2ecf20Sopenharmony_ci cxgb4_dcb_state_init(netdev); 68858c2ecf20Sopenharmony_ci cxgb4_dcb_version_init(netdev); 68868c2ecf20Sopenharmony_ci#endif 68878c2ecf20Sopenharmony_ci cxgb4_set_ethtool_ops(netdev); 68888c2ecf20Sopenharmony_ci } 68898c2ecf20Sopenharmony_ci 68908c2ecf20Sopenharmony_ci cxgb4_init_ethtool_dump(adapter); 68918c2ecf20Sopenharmony_ci 68928c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, adapter); 68938c2ecf20Sopenharmony_ci 68948c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) { 68958c2ecf20Sopenharmony_ci err = t4_port_init(adapter, func, func, 0); 68968c2ecf20Sopenharmony_ci if (err) 68978c2ecf20Sopenharmony_ci goto out_free_dev; 68988c2ecf20Sopenharmony_ci } else if (adapter->params.nports == 1) { 68998c2ecf20Sopenharmony_ci /* If we don't have a connection to the firmware -- possibly 69008c2ecf20Sopenharmony_ci * because of an error -- grab the raw VPD parameters so we 69018c2ecf20Sopenharmony_ci * can set the proper MAC Address on the debug network 69028c2ecf20Sopenharmony_ci * interface that we've created. 69038c2ecf20Sopenharmony_ci */ 69048c2ecf20Sopenharmony_ci u8 hw_addr[ETH_ALEN]; 69058c2ecf20Sopenharmony_ci u8 *na = adapter->params.vpd.na; 69068c2ecf20Sopenharmony_ci 69078c2ecf20Sopenharmony_ci err = t4_get_raw_vpd_params(adapter, &adapter->params.vpd); 69088c2ecf20Sopenharmony_ci if (!err) { 69098c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 69108c2ecf20Sopenharmony_ci hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 + 69118c2ecf20Sopenharmony_ci hex2val(na[2 * i + 1])); 69128c2ecf20Sopenharmony_ci t4_set_hw_addr(adapter, 0, hw_addr); 69138c2ecf20Sopenharmony_ci } 69148c2ecf20Sopenharmony_ci } 69158c2ecf20Sopenharmony_ci 69168c2ecf20Sopenharmony_ci if (!(adapter->flags & CXGB4_FW_OK)) 69178c2ecf20Sopenharmony_ci goto fw_attach_fail; 69188c2ecf20Sopenharmony_ci 69198c2ecf20Sopenharmony_ci /* Configure queues and allocate tables now, they can be needed as 69208c2ecf20Sopenharmony_ci * soon as the first register_netdev completes. 69218c2ecf20Sopenharmony_ci */ 69228c2ecf20Sopenharmony_ci err = cfg_queues(adapter); 69238c2ecf20Sopenharmony_ci if (err) 69248c2ecf20Sopenharmony_ci goto out_free_dev; 69258c2ecf20Sopenharmony_ci 69268c2ecf20Sopenharmony_ci adapter->smt = t4_init_smt(); 69278c2ecf20Sopenharmony_ci if (!adapter->smt) { 69288c2ecf20Sopenharmony_ci /* We tolerate a lack of SMT, giving up some functionality */ 69298c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "could not allocate SMT, continuing\n"); 69308c2ecf20Sopenharmony_ci } 69318c2ecf20Sopenharmony_ci 69328c2ecf20Sopenharmony_ci adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end); 69338c2ecf20Sopenharmony_ci if (!adapter->l2t) { 69348c2ecf20Sopenharmony_ci /* We tolerate a lack of L2T, giving up some functionality */ 69358c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); 69368c2ecf20Sopenharmony_ci adapter->params.offload = 0; 69378c2ecf20Sopenharmony_ci } 69388c2ecf20Sopenharmony_ci 69398c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 69408c2ecf20Sopenharmony_ci if (chip_ver <= CHELSIO_T5 && 69418c2ecf20Sopenharmony_ci (!(t4_read_reg(adapter, LE_DB_CONFIG_A) & ASLIPCOMPEN_F))) { 69428c2ecf20Sopenharmony_ci /* CLIP functionality is not present in hardware, 69438c2ecf20Sopenharmony_ci * hence disable all offload features 69448c2ecf20Sopenharmony_ci */ 69458c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 69468c2ecf20Sopenharmony_ci "CLIP not enabled in hardware, continuing\n"); 69478c2ecf20Sopenharmony_ci adapter->params.offload = 0; 69488c2ecf20Sopenharmony_ci } else { 69498c2ecf20Sopenharmony_ci adapter->clipt = t4_init_clip_tbl(adapter->clipt_start, 69508c2ecf20Sopenharmony_ci adapter->clipt_end); 69518c2ecf20Sopenharmony_ci if (!adapter->clipt) { 69528c2ecf20Sopenharmony_ci /* We tolerate a lack of clip_table, giving up 69538c2ecf20Sopenharmony_ci * some functionality 69548c2ecf20Sopenharmony_ci */ 69558c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 69568c2ecf20Sopenharmony_ci "could not allocate Clip table, continuing\n"); 69578c2ecf20Sopenharmony_ci adapter->params.offload = 0; 69588c2ecf20Sopenharmony_ci } 69598c2ecf20Sopenharmony_ci } 69608c2ecf20Sopenharmony_ci#endif 69618c2ecf20Sopenharmony_ci 69628c2ecf20Sopenharmony_ci for_each_port(adapter, i) { 69638c2ecf20Sopenharmony_ci pi = adap2pinfo(adapter, i); 69648c2ecf20Sopenharmony_ci pi->sched_tbl = t4_init_sched(adapter->params.nsched_cls); 69658c2ecf20Sopenharmony_ci if (!pi->sched_tbl) 69668c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 69678c2ecf20Sopenharmony_ci "could not activate scheduling on port %d\n", 69688c2ecf20Sopenharmony_ci i); 69698c2ecf20Sopenharmony_ci } 69708c2ecf20Sopenharmony_ci 69718c2ecf20Sopenharmony_ci if (is_offload(adapter) || is_hashfilter(adapter)) { 69728c2ecf20Sopenharmony_ci if (t4_read_reg(adapter, LE_DB_CONFIG_A) & HASHEN_F) { 69738c2ecf20Sopenharmony_ci u32 v; 69748c2ecf20Sopenharmony_ci 69758c2ecf20Sopenharmony_ci v = t4_read_reg(adapter, LE_DB_HASH_CONFIG_A); 69768c2ecf20Sopenharmony_ci if (chip_ver <= CHELSIO_T5) { 69778c2ecf20Sopenharmony_ci adapter->tids.nhash = 1 << HASHTIDSIZE_G(v); 69788c2ecf20Sopenharmony_ci v = t4_read_reg(adapter, LE_DB_TID_HASHBASE_A); 69798c2ecf20Sopenharmony_ci adapter->tids.hash_base = v / 4; 69808c2ecf20Sopenharmony_ci } else { 69818c2ecf20Sopenharmony_ci adapter->tids.nhash = HASHTBLSIZE_G(v) << 3; 69828c2ecf20Sopenharmony_ci v = t4_read_reg(adapter, 69838c2ecf20Sopenharmony_ci T6_LE_DB_HASH_TID_BASE_A); 69848c2ecf20Sopenharmony_ci adapter->tids.hash_base = v; 69858c2ecf20Sopenharmony_ci } 69868c2ecf20Sopenharmony_ci } 69878c2ecf20Sopenharmony_ci } 69888c2ecf20Sopenharmony_ci 69898c2ecf20Sopenharmony_ci if (tid_init(&adapter->tids) < 0) { 69908c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "could not allocate TID table, " 69918c2ecf20Sopenharmony_ci "continuing\n"); 69928c2ecf20Sopenharmony_ci adapter->params.offload = 0; 69938c2ecf20Sopenharmony_ci } else { 69948c2ecf20Sopenharmony_ci adapter->tc_u32 = cxgb4_init_tc_u32(adapter); 69958c2ecf20Sopenharmony_ci if (!adapter->tc_u32) 69968c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 69978c2ecf20Sopenharmony_ci "could not offload tc u32, continuing\n"); 69988c2ecf20Sopenharmony_ci 69998c2ecf20Sopenharmony_ci if (cxgb4_init_tc_flower(adapter)) 70008c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 70018c2ecf20Sopenharmony_ci "could not offload tc flower, continuing\n"); 70028c2ecf20Sopenharmony_ci 70038c2ecf20Sopenharmony_ci if (cxgb4_init_tc_mqprio(adapter)) 70048c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 70058c2ecf20Sopenharmony_ci "could not offload tc mqprio, continuing\n"); 70068c2ecf20Sopenharmony_ci 70078c2ecf20Sopenharmony_ci if (cxgb4_init_tc_matchall(adapter)) 70088c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 70098c2ecf20Sopenharmony_ci "could not offload tc matchall, continuing\n"); 70108c2ecf20Sopenharmony_ci if (cxgb4_init_ethtool_filters(adapter)) 70118c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 70128c2ecf20Sopenharmony_ci "could not initialize ethtool filters, continuing\n"); 70138c2ecf20Sopenharmony_ci } 70148c2ecf20Sopenharmony_ci 70158c2ecf20Sopenharmony_ci /* See what interrupts we'll be using */ 70168c2ecf20Sopenharmony_ci if (msi > 1 && enable_msix(adapter) == 0) 70178c2ecf20Sopenharmony_ci adapter->flags |= CXGB4_USING_MSIX; 70188c2ecf20Sopenharmony_ci else if (msi > 0 && pci_enable_msi(pdev) == 0) { 70198c2ecf20Sopenharmony_ci adapter->flags |= CXGB4_USING_MSI; 70208c2ecf20Sopenharmony_ci if (msi > 1) 70218c2ecf20Sopenharmony_ci free_msix_info(adapter); 70228c2ecf20Sopenharmony_ci } 70238c2ecf20Sopenharmony_ci 70248c2ecf20Sopenharmony_ci /* check for PCI Express bandwidth capabiltites */ 70258c2ecf20Sopenharmony_ci pcie_print_link_status(pdev); 70268c2ecf20Sopenharmony_ci 70278c2ecf20Sopenharmony_ci cxgb4_init_mps_ref_entries(adapter); 70288c2ecf20Sopenharmony_ci 70298c2ecf20Sopenharmony_ci err = init_rss(adapter); 70308c2ecf20Sopenharmony_ci if (err) 70318c2ecf20Sopenharmony_ci goto out_free_dev; 70328c2ecf20Sopenharmony_ci 70338c2ecf20Sopenharmony_ci err = setup_non_data_intr(adapter); 70348c2ecf20Sopenharmony_ci if (err) { 70358c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 70368c2ecf20Sopenharmony_ci "Non Data interrupt allocation failed, err: %d\n", err); 70378c2ecf20Sopenharmony_ci goto out_free_dev; 70388c2ecf20Sopenharmony_ci } 70398c2ecf20Sopenharmony_ci 70408c2ecf20Sopenharmony_ci err = setup_fw_sge_queues(adapter); 70418c2ecf20Sopenharmony_ci if (err) { 70428c2ecf20Sopenharmony_ci dev_err(adapter->pdev_dev, 70438c2ecf20Sopenharmony_ci "FW sge queue allocation failed, err %d", err); 70448c2ecf20Sopenharmony_ci goto out_free_dev; 70458c2ecf20Sopenharmony_ci } 70468c2ecf20Sopenharmony_ci 70478c2ecf20Sopenharmony_cifw_attach_fail: 70488c2ecf20Sopenharmony_ci /* 70498c2ecf20Sopenharmony_ci * The card is now ready to go. If any errors occur during device 70508c2ecf20Sopenharmony_ci * registration we do not fail the whole card but rather proceed only 70518c2ecf20Sopenharmony_ci * with the ports we manage to register successfully. However we must 70528c2ecf20Sopenharmony_ci * register at least one net device. 70538c2ecf20Sopenharmony_ci */ 70548c2ecf20Sopenharmony_ci for_each_port(adapter, i) { 70558c2ecf20Sopenharmony_ci pi = adap2pinfo(adapter, i); 70568c2ecf20Sopenharmony_ci adapter->port[i]->dev_port = pi->lport; 70578c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); 70588c2ecf20Sopenharmony_ci netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); 70598c2ecf20Sopenharmony_ci 70608c2ecf20Sopenharmony_ci netif_carrier_off(adapter->port[i]); 70618c2ecf20Sopenharmony_ci 70628c2ecf20Sopenharmony_ci err = register_netdev(adapter->port[i]); 70638c2ecf20Sopenharmony_ci if (err) 70648c2ecf20Sopenharmony_ci break; 70658c2ecf20Sopenharmony_ci adapter->chan_map[pi->tx_chan] = i; 70668c2ecf20Sopenharmony_ci print_port_info(adapter->port[i]); 70678c2ecf20Sopenharmony_ci } 70688c2ecf20Sopenharmony_ci if (i == 0) { 70698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not register any net devices\n"); 70708c2ecf20Sopenharmony_ci goto out_free_dev; 70718c2ecf20Sopenharmony_ci } 70728c2ecf20Sopenharmony_ci if (err) { 70738c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "only %d net devices registered\n", i); 70748c2ecf20Sopenharmony_ci err = 0; 70758c2ecf20Sopenharmony_ci } 70768c2ecf20Sopenharmony_ci 70778c2ecf20Sopenharmony_ci if (cxgb4_debugfs_root) { 70788c2ecf20Sopenharmony_ci adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), 70798c2ecf20Sopenharmony_ci cxgb4_debugfs_root); 70808c2ecf20Sopenharmony_ci setup_debugfs(adapter); 70818c2ecf20Sopenharmony_ci } 70828c2ecf20Sopenharmony_ci 70838c2ecf20Sopenharmony_ci /* PCIe EEH recovery on powerpc platforms needs fundamental reset */ 70848c2ecf20Sopenharmony_ci pdev->needs_freset = 1; 70858c2ecf20Sopenharmony_ci 70868c2ecf20Sopenharmony_ci if (is_uld(adapter)) 70878c2ecf20Sopenharmony_ci cxgb4_uld_enable(adapter); 70888c2ecf20Sopenharmony_ci 70898c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) 70908c2ecf20Sopenharmony_ci cxgb4_ptp_init(adapter); 70918c2ecf20Sopenharmony_ci 70928c2ecf20Sopenharmony_ci if (IS_REACHABLE(CONFIG_THERMAL) && 70938c2ecf20Sopenharmony_ci !is_t4(adapter->params.chip) && (adapter->flags & CXGB4_FW_OK)) 70948c2ecf20Sopenharmony_ci cxgb4_thermal_init(adapter); 70958c2ecf20Sopenharmony_ci 70968c2ecf20Sopenharmony_ci print_adapter_info(adapter); 70978c2ecf20Sopenharmony_ci return 0; 70988c2ecf20Sopenharmony_ci 70998c2ecf20Sopenharmony_ci out_free_dev: 71008c2ecf20Sopenharmony_ci t4_free_sge_resources(adapter); 71018c2ecf20Sopenharmony_ci free_some_resources(adapter); 71028c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_USING_MSIX) 71038c2ecf20Sopenharmony_ci free_msix_info(adapter); 71048c2ecf20Sopenharmony_ci if (adapter->num_uld || adapter->num_ofld_uld) 71058c2ecf20Sopenharmony_ci t4_uld_mem_free(adapter); 71068c2ecf20Sopenharmony_ci out_unmap_bar: 71078c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) 71088c2ecf20Sopenharmony_ci iounmap(adapter->bar2); 71098c2ecf20Sopenharmony_ci out_free_adapter: 71108c2ecf20Sopenharmony_ci if (adapter->workq) 71118c2ecf20Sopenharmony_ci destroy_workqueue(adapter->workq); 71128c2ecf20Sopenharmony_ci 71138c2ecf20Sopenharmony_ci kfree(adapter->mbox_log); 71148c2ecf20Sopenharmony_ci kfree(adapter); 71158c2ecf20Sopenharmony_ci out_unmap_bar0: 71168c2ecf20Sopenharmony_ci iounmap(regs); 71178c2ecf20Sopenharmony_ci out_disable_device: 71188c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 71198c2ecf20Sopenharmony_ci pci_disable_device(pdev); 71208c2ecf20Sopenharmony_ci out_release_regions: 71218c2ecf20Sopenharmony_ci pci_release_regions(pdev); 71228c2ecf20Sopenharmony_ci return err; 71238c2ecf20Sopenharmony_ci} 71248c2ecf20Sopenharmony_ci 71258c2ecf20Sopenharmony_cistatic void remove_one(struct pci_dev *pdev) 71268c2ecf20Sopenharmony_ci{ 71278c2ecf20Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 71288c2ecf20Sopenharmony_ci struct hash_mac_addr *entry, *tmp; 71298c2ecf20Sopenharmony_ci 71308c2ecf20Sopenharmony_ci if (!adapter) { 71318c2ecf20Sopenharmony_ci pci_release_regions(pdev); 71328c2ecf20Sopenharmony_ci return; 71338c2ecf20Sopenharmony_ci } 71348c2ecf20Sopenharmony_ci 71358c2ecf20Sopenharmony_ci /* If we allocated filters, free up state associated with any 71368c2ecf20Sopenharmony_ci * valid filters ... 71378c2ecf20Sopenharmony_ci */ 71388c2ecf20Sopenharmony_ci clear_all_filters(adapter); 71398c2ecf20Sopenharmony_ci 71408c2ecf20Sopenharmony_ci adapter->flags |= CXGB4_SHUTTING_DOWN; 71418c2ecf20Sopenharmony_ci 71428c2ecf20Sopenharmony_ci if (adapter->pf == 4) { 71438c2ecf20Sopenharmony_ci int i; 71448c2ecf20Sopenharmony_ci 71458c2ecf20Sopenharmony_ci /* Tear down per-adapter Work Queue first since it can contain 71468c2ecf20Sopenharmony_ci * references to our adapter data structure. 71478c2ecf20Sopenharmony_ci */ 71488c2ecf20Sopenharmony_ci destroy_workqueue(adapter->workq); 71498c2ecf20Sopenharmony_ci 71508c2ecf20Sopenharmony_ci detach_ulds(adapter); 71518c2ecf20Sopenharmony_ci 71528c2ecf20Sopenharmony_ci for_each_port(adapter, i) 71538c2ecf20Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 71548c2ecf20Sopenharmony_ci unregister_netdev(adapter->port[i]); 71558c2ecf20Sopenharmony_ci 71568c2ecf20Sopenharmony_ci t4_uld_clean_up(adapter); 71578c2ecf20Sopenharmony_ci 71588c2ecf20Sopenharmony_ci adap_free_hma_mem(adapter); 71598c2ecf20Sopenharmony_ci 71608c2ecf20Sopenharmony_ci disable_interrupts(adapter); 71618c2ecf20Sopenharmony_ci 71628c2ecf20Sopenharmony_ci cxgb4_free_mps_ref_entries(adapter); 71638c2ecf20Sopenharmony_ci 71648c2ecf20Sopenharmony_ci debugfs_remove_recursive(adapter->debugfs_root); 71658c2ecf20Sopenharmony_ci 71668c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) 71678c2ecf20Sopenharmony_ci cxgb4_ptp_stop(adapter); 71688c2ecf20Sopenharmony_ci if (IS_REACHABLE(CONFIG_THERMAL)) 71698c2ecf20Sopenharmony_ci cxgb4_thermal_remove(adapter); 71708c2ecf20Sopenharmony_ci 71718c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FULL_INIT_DONE) 71728c2ecf20Sopenharmony_ci cxgb_down(adapter); 71738c2ecf20Sopenharmony_ci 71748c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_USING_MSIX) 71758c2ecf20Sopenharmony_ci free_msix_info(adapter); 71768c2ecf20Sopenharmony_ci if (adapter->num_uld || adapter->num_ofld_uld) 71778c2ecf20Sopenharmony_ci t4_uld_mem_free(adapter); 71788c2ecf20Sopenharmony_ci free_some_resources(adapter); 71798c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &adapter->mac_hlist, 71808c2ecf20Sopenharmony_ci list) { 71818c2ecf20Sopenharmony_ci list_del(&entry->list); 71828c2ecf20Sopenharmony_ci kfree(entry); 71838c2ecf20Sopenharmony_ci } 71848c2ecf20Sopenharmony_ci 71858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 71868c2ecf20Sopenharmony_ci t4_cleanup_clip_tbl(adapter); 71878c2ecf20Sopenharmony_ci#endif 71888c2ecf20Sopenharmony_ci if (!is_t4(adapter->params.chip)) 71898c2ecf20Sopenharmony_ci iounmap(adapter->bar2); 71908c2ecf20Sopenharmony_ci } 71918c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 71928c2ecf20Sopenharmony_ci else { 71938c2ecf20Sopenharmony_ci cxgb4_iov_configure(adapter->pdev, 0); 71948c2ecf20Sopenharmony_ci } 71958c2ecf20Sopenharmony_ci#endif 71968c2ecf20Sopenharmony_ci iounmap(adapter->regs); 71978c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 71988c2ecf20Sopenharmony_ci if ((adapter->flags & CXGB4_DEV_ENABLED)) { 71998c2ecf20Sopenharmony_ci pci_disable_device(pdev); 72008c2ecf20Sopenharmony_ci adapter->flags &= ~CXGB4_DEV_ENABLED; 72018c2ecf20Sopenharmony_ci } 72028c2ecf20Sopenharmony_ci pci_release_regions(pdev); 72038c2ecf20Sopenharmony_ci kfree(adapter->mbox_log); 72048c2ecf20Sopenharmony_ci synchronize_rcu(); 72058c2ecf20Sopenharmony_ci kfree(adapter); 72068c2ecf20Sopenharmony_ci} 72078c2ecf20Sopenharmony_ci 72088c2ecf20Sopenharmony_ci/* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt 72098c2ecf20Sopenharmony_ci * delivery. This is essentially a stripped down version of the PCI remove() 72108c2ecf20Sopenharmony_ci * function where we do the minimal amount of work necessary to shutdown any 72118c2ecf20Sopenharmony_ci * further activity. 72128c2ecf20Sopenharmony_ci */ 72138c2ecf20Sopenharmony_cistatic void shutdown_one(struct pci_dev *pdev) 72148c2ecf20Sopenharmony_ci{ 72158c2ecf20Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 72168c2ecf20Sopenharmony_ci 72178c2ecf20Sopenharmony_ci /* As with remove_one() above (see extended comment), we only want do 72188c2ecf20Sopenharmony_ci * do cleanup on PCI Devices which went all the way through init_one() 72198c2ecf20Sopenharmony_ci * ... 72208c2ecf20Sopenharmony_ci */ 72218c2ecf20Sopenharmony_ci if (!adapter) { 72228c2ecf20Sopenharmony_ci pci_release_regions(pdev); 72238c2ecf20Sopenharmony_ci return; 72248c2ecf20Sopenharmony_ci } 72258c2ecf20Sopenharmony_ci 72268c2ecf20Sopenharmony_ci adapter->flags |= CXGB4_SHUTTING_DOWN; 72278c2ecf20Sopenharmony_ci 72288c2ecf20Sopenharmony_ci if (adapter->pf == 4) { 72298c2ecf20Sopenharmony_ci int i; 72308c2ecf20Sopenharmony_ci 72318c2ecf20Sopenharmony_ci for_each_port(adapter, i) 72328c2ecf20Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 72338c2ecf20Sopenharmony_ci cxgb_close(adapter->port[i]); 72348c2ecf20Sopenharmony_ci 72358c2ecf20Sopenharmony_ci rtnl_lock(); 72368c2ecf20Sopenharmony_ci cxgb4_mqprio_stop_offload(adapter); 72378c2ecf20Sopenharmony_ci rtnl_unlock(); 72388c2ecf20Sopenharmony_ci 72398c2ecf20Sopenharmony_ci if (is_uld(adapter)) { 72408c2ecf20Sopenharmony_ci detach_ulds(adapter); 72418c2ecf20Sopenharmony_ci t4_uld_clean_up(adapter); 72428c2ecf20Sopenharmony_ci } 72438c2ecf20Sopenharmony_ci 72448c2ecf20Sopenharmony_ci disable_interrupts(adapter); 72458c2ecf20Sopenharmony_ci disable_msi(adapter); 72468c2ecf20Sopenharmony_ci 72478c2ecf20Sopenharmony_ci t4_sge_stop(adapter); 72488c2ecf20Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) 72498c2ecf20Sopenharmony_ci t4_fw_bye(adapter, adapter->mbox); 72508c2ecf20Sopenharmony_ci } 72518c2ecf20Sopenharmony_ci} 72528c2ecf20Sopenharmony_ci 72538c2ecf20Sopenharmony_cistatic struct pci_driver cxgb4_driver = { 72548c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 72558c2ecf20Sopenharmony_ci .id_table = cxgb4_pci_tbl, 72568c2ecf20Sopenharmony_ci .probe = init_one, 72578c2ecf20Sopenharmony_ci .remove = remove_one, 72588c2ecf20Sopenharmony_ci .shutdown = shutdown_one, 72598c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV 72608c2ecf20Sopenharmony_ci .sriov_configure = cxgb4_iov_configure, 72618c2ecf20Sopenharmony_ci#endif 72628c2ecf20Sopenharmony_ci .err_handler = &cxgb4_eeh, 72638c2ecf20Sopenharmony_ci}; 72648c2ecf20Sopenharmony_ci 72658c2ecf20Sopenharmony_cistatic int __init cxgb4_init_module(void) 72668c2ecf20Sopenharmony_ci{ 72678c2ecf20Sopenharmony_ci int ret; 72688c2ecf20Sopenharmony_ci 72698c2ecf20Sopenharmony_ci cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 72708c2ecf20Sopenharmony_ci 72718c2ecf20Sopenharmony_ci ret = pci_register_driver(&cxgb4_driver); 72728c2ecf20Sopenharmony_ci if (ret < 0) 72738c2ecf20Sopenharmony_ci goto err_pci; 72748c2ecf20Sopenharmony_ci 72758c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 72768c2ecf20Sopenharmony_ci if (!inet6addr_registered) { 72778c2ecf20Sopenharmony_ci ret = register_inet6addr_notifier(&cxgb4_inet6addr_notifier); 72788c2ecf20Sopenharmony_ci if (ret) 72798c2ecf20Sopenharmony_ci pci_unregister_driver(&cxgb4_driver); 72808c2ecf20Sopenharmony_ci else 72818c2ecf20Sopenharmony_ci inet6addr_registered = true; 72828c2ecf20Sopenharmony_ci } 72838c2ecf20Sopenharmony_ci#endif 72848c2ecf20Sopenharmony_ci 72858c2ecf20Sopenharmony_ci if (ret == 0) 72868c2ecf20Sopenharmony_ci return ret; 72878c2ecf20Sopenharmony_ci 72888c2ecf20Sopenharmony_cierr_pci: 72898c2ecf20Sopenharmony_ci debugfs_remove(cxgb4_debugfs_root); 72908c2ecf20Sopenharmony_ci 72918c2ecf20Sopenharmony_ci return ret; 72928c2ecf20Sopenharmony_ci} 72938c2ecf20Sopenharmony_ci 72948c2ecf20Sopenharmony_cistatic void __exit cxgb4_cleanup_module(void) 72958c2ecf20Sopenharmony_ci{ 72968c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 72978c2ecf20Sopenharmony_ci if (inet6addr_registered) { 72988c2ecf20Sopenharmony_ci unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); 72998c2ecf20Sopenharmony_ci inet6addr_registered = false; 73008c2ecf20Sopenharmony_ci } 73018c2ecf20Sopenharmony_ci#endif 73028c2ecf20Sopenharmony_ci pci_unregister_driver(&cxgb4_driver); 73038c2ecf20Sopenharmony_ci debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ 73048c2ecf20Sopenharmony_ci} 73058c2ecf20Sopenharmony_ci 73068c2ecf20Sopenharmony_cimodule_init(cxgb4_init_module); 73078c2ecf20Sopenharmony_cimodule_exit(cxgb4_cleanup_module); 7308