162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is part of the Chelsio T4 Ethernet driver for Linux. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2003-2016 Chelsio Communications, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/bitmap.h> 3862306a36Sopenharmony_ci#include <linux/crc32.h> 3962306a36Sopenharmony_ci#include <linux/ctype.h> 4062306a36Sopenharmony_ci#include <linux/debugfs.h> 4162306a36Sopenharmony_ci#include <linux/err.h> 4262306a36Sopenharmony_ci#include <linux/etherdevice.h> 4362306a36Sopenharmony_ci#include <linux/firmware.h> 4462306a36Sopenharmony_ci#include <linux/if.h> 4562306a36Sopenharmony_ci#include <linux/if_vlan.h> 4662306a36Sopenharmony_ci#include <linux/init.h> 4762306a36Sopenharmony_ci#include <linux/log2.h> 4862306a36Sopenharmony_ci#include <linux/mdio.h> 4962306a36Sopenharmony_ci#include <linux/module.h> 5062306a36Sopenharmony_ci#include <linux/moduleparam.h> 5162306a36Sopenharmony_ci#include <linux/mutex.h> 5262306a36Sopenharmony_ci#include <linux/netdevice.h> 5362306a36Sopenharmony_ci#include <linux/pci.h> 5462306a36Sopenharmony_ci#include <linux/rtnetlink.h> 5562306a36Sopenharmony_ci#include <linux/sched.h> 5662306a36Sopenharmony_ci#include <linux/seq_file.h> 5762306a36Sopenharmony_ci#include <linux/sockios.h> 5862306a36Sopenharmony_ci#include <linux/vmalloc.h> 5962306a36Sopenharmony_ci#include <linux/workqueue.h> 6062306a36Sopenharmony_ci#include <net/neighbour.h> 6162306a36Sopenharmony_ci#include <net/netevent.h> 6262306a36Sopenharmony_ci#include <net/addrconf.h> 6362306a36Sopenharmony_ci#include <net/bonding.h> 6462306a36Sopenharmony_ci#include <linux/uaccess.h> 6562306a36Sopenharmony_ci#include <linux/crash_dump.h> 6662306a36Sopenharmony_ci#include <net/udp_tunnel.h> 6762306a36Sopenharmony_ci#include <net/xfrm.h> 6862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 6962306a36Sopenharmony_ci#include <net/tls.h> 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#include "cxgb4.h" 7362306a36Sopenharmony_ci#include "cxgb4_filter.h" 7462306a36Sopenharmony_ci#include "t4_regs.h" 7562306a36Sopenharmony_ci#include "t4_values.h" 7662306a36Sopenharmony_ci#include "t4_msg.h" 7762306a36Sopenharmony_ci#include "t4fw_api.h" 7862306a36Sopenharmony_ci#include "t4fw_version.h" 7962306a36Sopenharmony_ci#include "cxgb4_dcb.h" 8062306a36Sopenharmony_ci#include "srq.h" 8162306a36Sopenharmony_ci#include "cxgb4_debugfs.h" 8262306a36Sopenharmony_ci#include "clip_tbl.h" 8362306a36Sopenharmony_ci#include "l2t.h" 8462306a36Sopenharmony_ci#include "smt.h" 8562306a36Sopenharmony_ci#include "sched.h" 8662306a36Sopenharmony_ci#include "cxgb4_tc_u32.h" 8762306a36Sopenharmony_ci#include "cxgb4_tc_flower.h" 8862306a36Sopenharmony_ci#include "cxgb4_tc_mqprio.h" 8962306a36Sopenharmony_ci#include "cxgb4_tc_matchall.h" 9062306a36Sopenharmony_ci#include "cxgb4_ptp.h" 9162306a36Sopenharmony_ci#include "cxgb4_cudbg.h" 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cichar cxgb4_driver_name[] = KBUILD_MODNAME; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define DRV_DESC "Chelsio T4/T5/T6 Network Driver" 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ 9862306a36Sopenharmony_ci NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ 9962306a36Sopenharmony_ci NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* Macros needed to support the PCI Device ID Table ... 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \ 10462306a36Sopenharmony_ci static const struct pci_device_id cxgb4_pci_tbl[] = { 10562306a36Sopenharmony_ci#define CXGB4_UNIFIED_PF 0x4 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION CXGB4_UNIFIED_PF 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* Include PCI Device IDs for both PF4 and PF0-3 so our PCI probe() routine is 11062306a36Sopenharmony_ci * called for both. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_FUNCTION2 0x0 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define CH_PCI_ID_TABLE_ENTRY(devid) \ 11562306a36Sopenharmony_ci {PCI_VDEVICE(CHELSIO, (devid)), CXGB4_UNIFIED_PF} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define CH_PCI_DEVICE_ID_TABLE_DEFINE_END \ 11862306a36Sopenharmony_ci { 0, } \ 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#include "t4_pci_id_tbl.h" 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define FW4_FNAME "cxgb4/t4fw.bin" 12462306a36Sopenharmony_ci#define FW5_FNAME "cxgb4/t5fw.bin" 12562306a36Sopenharmony_ci#define FW6_FNAME "cxgb4/t6fw.bin" 12662306a36Sopenharmony_ci#define FW4_CFNAME "cxgb4/t4-config.txt" 12762306a36Sopenharmony_ci#define FW5_CFNAME "cxgb4/t5-config.txt" 12862306a36Sopenharmony_ci#define FW6_CFNAME "cxgb4/t6-config.txt" 12962306a36Sopenharmony_ci#define PHY_AQ1202_FIRMWARE "cxgb4/aq1202_fw.cld" 13062306a36Sopenharmony_ci#define PHY_BCM84834_FIRMWARE "cxgb4/bcm8483.bin" 13162306a36Sopenharmony_ci#define PHY_AQ1202_DEVICEID 0x4409 13262306a36Sopenharmony_ci#define PHY_BCM84834_DEVICEID 0x4486 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC); 13562306a36Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications"); 13662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 13762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); 13862306a36Sopenharmony_ciMODULE_FIRMWARE(FW4_FNAME); 13962306a36Sopenharmony_ciMODULE_FIRMWARE(FW5_FNAME); 14062306a36Sopenharmony_ciMODULE_FIRMWARE(FW6_FNAME); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* 14362306a36Sopenharmony_ci * The driver uses the best interrupt scheme available on a platform in the 14462306a36Sopenharmony_ci * order MSI-X, MSI, legacy INTx interrupts. This parameter determines which 14562306a36Sopenharmony_ci * of these schemes the driver may consider as follows: 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * msi = 2: choose from among all three options 14862306a36Sopenharmony_ci * msi = 1: only consider MSI and INTx interrupts 14962306a36Sopenharmony_ci * msi = 0: force INTx interrupts 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic int msi = 2; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cimodule_param(msi, int, 0644); 15462306a36Sopenharmony_ciMODULE_PARM_DESC(msi, "whether to use INTx (0), MSI (1) or MSI-X (2)"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * Normally we tell the chip to deliver Ingress Packets into our DMA buffers 15862306a36Sopenharmony_ci * offset by 2 bytes in order to have the IP headers line up on 4-byte 15962306a36Sopenharmony_ci * boundaries. This is a requirement for many architectures which will throw 16062306a36Sopenharmony_ci * a machine check fault if an attempt is made to access one of the 4-byte IP 16162306a36Sopenharmony_ci * header fields on a non-4-byte boundary. And it's a major performance issue 16262306a36Sopenharmony_ci * even on some architectures which allow it like some implementations of the 16362306a36Sopenharmony_ci * x86 ISA. However, some architectures don't mind this and for some very 16462306a36Sopenharmony_ci * edge-case performance sensitive applications (like forwarding large volumes 16562306a36Sopenharmony_ci * of small packets), setting this DMA offset to 0 will decrease the number of 16662306a36Sopenharmony_ci * PCI-E Bus transfers enough to measurably affect performance. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic int rx_dma_offset = 2; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* TX Queue select used to determine what algorithm to use for selecting TX 17162306a36Sopenharmony_ci * queue. Select between the kernel provided function (select_queue=0) or user 17262306a36Sopenharmony_ci * cxgb_select_queue function (select_queue=1) 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * Default: select_queue=0 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistatic int select_queue; 17762306a36Sopenharmony_cimodule_param(select_queue, int, 0644); 17862306a36Sopenharmony_ciMODULE_PARM_DESC(select_queue, 17962306a36Sopenharmony_ci "Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method."); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct dentry *cxgb4_debugfs_root; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciLIST_HEAD(adapter_list); 18462306a36Sopenharmony_ciDEFINE_MUTEX(uld_mutex); 18562306a36Sopenharmony_ciLIST_HEAD(uld_list); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int cfg_queues(struct adapter *adap); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void link_report(struct net_device *dev) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci if (!netif_carrier_ok(dev)) 19262306a36Sopenharmony_ci netdev_info(dev, "link down\n"); 19362306a36Sopenharmony_ci else { 19462306a36Sopenharmony_ci static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" }; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci const char *s; 19762306a36Sopenharmony_ci const struct port_info *p = netdev_priv(dev); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci switch (p->link_cfg.speed) { 20062306a36Sopenharmony_ci case 100: 20162306a36Sopenharmony_ci s = "100Mbps"; 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case 1000: 20462306a36Sopenharmony_ci s = "1Gbps"; 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case 10000: 20762306a36Sopenharmony_ci s = "10Gbps"; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case 25000: 21062306a36Sopenharmony_ci s = "25Gbps"; 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci case 40000: 21362306a36Sopenharmony_ci s = "40Gbps"; 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci case 50000: 21662306a36Sopenharmony_ci s = "50Gbps"; 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci case 100000: 21962306a36Sopenharmony_ci s = "100Gbps"; 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci default: 22262306a36Sopenharmony_ci pr_info("%s: unsupported speed: %d\n", 22362306a36Sopenharmony_ci dev->name, p->link_cfg.speed); 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, 22862306a36Sopenharmony_ci fc[p->link_cfg.fc]); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 23362306a36Sopenharmony_ci/* Set up/tear down Data Center Bridging Priority mapping for a net device. */ 23462306a36Sopenharmony_cistatic void dcb_tx_queue_prio_enable(struct net_device *dev, int enable) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 23762306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 23862306a36Sopenharmony_ci struct sge_eth_txq *txq = &adap->sge.ethtxq[pi->first_qset]; 23962306a36Sopenharmony_ci int i; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* We use a simple mapping of Port TX Queue Index to DCB 24262306a36Sopenharmony_ci * Priority when we're enabling DCB. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci for (i = 0; i < pi->nqsets; i++, txq++) { 24562306a36Sopenharmony_ci u32 name, value; 24662306a36Sopenharmony_ci int err; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci name = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 24962306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V( 25062306a36Sopenharmony_ci FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH) | 25162306a36Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(txq->q.cntxt_id)); 25262306a36Sopenharmony_ci value = enable ? i : 0xffffffff; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Since we can be called while atomic (from "interrupt 25562306a36Sopenharmony_ci * level") we need to issue the Set Parameters Commannd 25662306a36Sopenharmony_ci * without sleeping (timeout < 0). 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci err = t4_set_params_timeout(adap, adap->mbox, adap->pf, 0, 1, 25962306a36Sopenharmony_ci &name, &value, 26062306a36Sopenharmony_ci -FW_CMD_MAX_TIMEOUT); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (err) 26362306a36Sopenharmony_ci dev_err(adap->pdev_dev, 26462306a36Sopenharmony_ci "Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n", 26562306a36Sopenharmony_ci enable ? "set" : "unset", pi->port_id, i, -err); 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci txq->dcb_prio = enable ? value : 0; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciint cxgb4_dcb_enabled(const struct net_device *dev) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!pi->dcb.enabled) 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return ((pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED) || 27962306a36Sopenharmony_ci (pi->dcb.state == CXGB4_DCB_STATE_HOST)); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_civoid t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct net_device *dev = adapter->port[port_id]; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* Skip changes from disabled ports. */ 28862306a36Sopenharmony_ci if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) { 28962306a36Sopenharmony_ci if (link_stat) 29062306a36Sopenharmony_ci netif_carrier_on(dev); 29162306a36Sopenharmony_ci else { 29262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 29362306a36Sopenharmony_ci if (cxgb4_dcb_enabled(dev)) { 29462306a36Sopenharmony_ci cxgb4_dcb_reset(dev); 29562306a36Sopenharmony_ci dcb_tx_queue_prio_enable(dev, false); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 29862306a36Sopenharmony_ci netif_carrier_off(dev); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci link_report(dev); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_civoid t4_os_portmod_changed(struct adapter *adap, int port_id) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci static const char *mod_str[] = { 30862306a36Sopenharmony_ci NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" 30962306a36Sopenharmony_ci }; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci struct net_device *dev = adap->port[port_id]; 31262306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 31562306a36Sopenharmony_ci netdev_info(dev, "port module unplugged\n"); 31662306a36Sopenharmony_ci else if (pi->mod_type < ARRAY_SIZE(mod_str)) 31762306a36Sopenharmony_ci netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); 31862306a36Sopenharmony_ci else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 31962306a36Sopenharmony_ci netdev_info(dev, "%s: unsupported port module inserted\n", 32062306a36Sopenharmony_ci dev->name); 32162306a36Sopenharmony_ci else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 32262306a36Sopenharmony_ci netdev_info(dev, "%s: unknown port module inserted\n", 32362306a36Sopenharmony_ci dev->name); 32462306a36Sopenharmony_ci else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR) 32562306a36Sopenharmony_ci netdev_info(dev, "%s: transceiver module error\n", dev->name); 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci netdev_info(dev, "%s: unknown module type %d inserted\n", 32862306a36Sopenharmony_ci dev->name, pi->mod_type); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* If the interface is running, then we'll need any "sticky" Link 33162306a36Sopenharmony_ci * Parameters redone with a new Transceiver Module. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_ci pi->link_cfg.redo_l1cfg = netif_running(dev); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ciint dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */ 33762306a36Sopenharmony_cimodule_param(dbfifo_int_thresh, int, 0644); 33862306a36Sopenharmony_ciMODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold"); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* 34162306a36Sopenharmony_ci * usecs to sleep while draining the dbfifo 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic int dbfifo_drain_delay = 1000; 34462306a36Sopenharmony_cimodule_param(dbfifo_drain_delay, int, 0644); 34562306a36Sopenharmony_ciMODULE_PARM_DESC(dbfifo_drain_delay, 34662306a36Sopenharmony_ci "usecs to sleep while draining the dbfifo"); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic inline int cxgb4_set_addr_hash(struct port_info *pi) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 35162306a36Sopenharmony_ci u64 vec = 0; 35262306a36Sopenharmony_ci bool ucast = false; 35362306a36Sopenharmony_ci struct hash_mac_addr *entry; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Calculate the hash vector for the updated list and program it */ 35662306a36Sopenharmony_ci list_for_each_entry(entry, &adap->mac_hlist, list) { 35762306a36Sopenharmony_ci ucast |= is_unicast_ether_addr(entry->addr); 35862306a36Sopenharmony_ci vec |= (1ULL << hash_mac_addr(entry->addr)); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast, 36162306a36Sopenharmony_ci vec, false); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 36762306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 36862306a36Sopenharmony_ci int ret; 36962306a36Sopenharmony_ci u64 mhash = 0; 37062306a36Sopenharmony_ci u64 uhash = 0; 37162306a36Sopenharmony_ci /* idx stores the index of allocated filters, 37262306a36Sopenharmony_ci * its size should be modified based on the number of 37362306a36Sopenharmony_ci * MAC addresses that we allocate filters for 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci u16 idx[1] = {}; 37762306a36Sopenharmony_ci bool free = false; 37862306a36Sopenharmony_ci bool ucast = is_unicast_ether_addr(mac_addr); 37962306a36Sopenharmony_ci const u8 *maclist[1] = {mac_addr}; 38062306a36Sopenharmony_ci struct hash_mac_addr *new_entry; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ret = cxgb4_alloc_mac_filt(adap, pi->viid, free, 1, maclist, 38362306a36Sopenharmony_ci idx, ucast ? &uhash : &mhash, false); 38462306a36Sopenharmony_ci if (ret < 0) 38562306a36Sopenharmony_ci goto out; 38662306a36Sopenharmony_ci /* if hash != 0, then add the addr to hash addr list 38762306a36Sopenharmony_ci * so on the end we will calculate the hash for the 38862306a36Sopenharmony_ci * list and program it 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci if (uhash || mhash) { 39162306a36Sopenharmony_ci new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC); 39262306a36Sopenharmony_ci if (!new_entry) 39362306a36Sopenharmony_ci return -ENOMEM; 39462306a36Sopenharmony_ci ether_addr_copy(new_entry->addr, mac_addr); 39562306a36Sopenharmony_ci list_add_tail(&new_entry->list, &adap->mac_hlist); 39662306a36Sopenharmony_ci ret = cxgb4_set_addr_hash(pi); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ciout: 39962306a36Sopenharmony_ci return ret < 0 ? ret : 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 40562306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 40662306a36Sopenharmony_ci int ret; 40762306a36Sopenharmony_ci const u8 *maclist[1] = {mac_addr}; 40862306a36Sopenharmony_ci struct hash_mac_addr *entry, *tmp; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* If the MAC address to be removed is in the hash addr 41162306a36Sopenharmony_ci * list, delete it from the list and update hash vector 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) { 41462306a36Sopenharmony_ci if (ether_addr_equal(entry->addr, mac_addr)) { 41562306a36Sopenharmony_ci list_del(&entry->list); 41662306a36Sopenharmony_ci kfree(entry); 41762306a36Sopenharmony_ci return cxgb4_set_addr_hash(pi); 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ret = cxgb4_free_mac_filt(adap, pi->viid, 1, maclist, false); 42262306a36Sopenharmony_ci return ret < 0 ? -EINVAL : 0; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* 42662306a36Sopenharmony_ci * Set Rx properties of a port, such as promiscruity, address filters, and MTU. 42762306a36Sopenharmony_ci * If @mtu is -1 it is left unchanged. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cistatic int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 43262306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci __dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync); 43562306a36Sopenharmony_ci __dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return t4_set_rxmode(adapter, adapter->mbox, pi->viid, pi->viid_mirror, 43862306a36Sopenharmony_ci mtu, (dev->flags & IFF_PROMISC) ? 1 : 0, 43962306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, 44062306a36Sopenharmony_ci sleep_ok); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/** 44462306a36Sopenharmony_ci * cxgb4_change_mac - Update match filter for a MAC address. 44562306a36Sopenharmony_ci * @pi: the port_info 44662306a36Sopenharmony_ci * @viid: the VI id 44762306a36Sopenharmony_ci * @tcam_idx: TCAM index of existing filter for old value of MAC address, 44862306a36Sopenharmony_ci * or -1 44962306a36Sopenharmony_ci * @addr: the new MAC address value 45062306a36Sopenharmony_ci * @persist: whether a new MAC allocation should be persistent 45162306a36Sopenharmony_ci * @smt_idx: the destination to store the new SMT index. 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * Modifies an MPS filter and sets it to the new MAC address if 45462306a36Sopenharmony_ci * @tcam_idx >= 0, or adds the MAC address to a new filter if 45562306a36Sopenharmony_ci * @tcam_idx < 0. In the latter case the address is added persistently 45662306a36Sopenharmony_ci * if @persist is %true. 45762306a36Sopenharmony_ci * Addresses are programmed to hash region, if tcam runs out of entries. 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ciint cxgb4_change_mac(struct port_info *pi, unsigned int viid, 46162306a36Sopenharmony_ci int *tcam_idx, const u8 *addr, bool persist, 46262306a36Sopenharmony_ci u8 *smt_idx) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 46562306a36Sopenharmony_ci struct hash_mac_addr *entry, *new_entry; 46662306a36Sopenharmony_ci int ret; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci ret = t4_change_mac(adapter, adapter->mbox, viid, 46962306a36Sopenharmony_ci *tcam_idx, addr, persist, smt_idx); 47062306a36Sopenharmony_ci /* We ran out of TCAM entries. try programming hash region. */ 47162306a36Sopenharmony_ci if (ret == -ENOMEM) { 47262306a36Sopenharmony_ci /* If the MAC address to be updated is in the hash addr 47362306a36Sopenharmony_ci * list, update it from the list 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci list_for_each_entry(entry, &adapter->mac_hlist, list) { 47662306a36Sopenharmony_ci if (entry->iface_mac) { 47762306a36Sopenharmony_ci ether_addr_copy(entry->addr, addr); 47862306a36Sopenharmony_ci goto set_hash; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); 48262306a36Sopenharmony_ci if (!new_entry) 48362306a36Sopenharmony_ci return -ENOMEM; 48462306a36Sopenharmony_ci ether_addr_copy(new_entry->addr, addr); 48562306a36Sopenharmony_ci new_entry->iface_mac = true; 48662306a36Sopenharmony_ci list_add_tail(&new_entry->list, &adapter->mac_hlist); 48762306a36Sopenharmony_ciset_hash: 48862306a36Sopenharmony_ci ret = cxgb4_set_addr_hash(pi); 48962306a36Sopenharmony_ci } else if (ret >= 0) { 49062306a36Sopenharmony_ci *tcam_idx = ret; 49162306a36Sopenharmony_ci ret = 0; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return ret; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci/* 49862306a36Sopenharmony_ci * link_start - enable a port 49962306a36Sopenharmony_ci * @dev: the port to enable 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * Performs the MAC and PHY actions needed to enable a port. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_cistatic int link_start(struct net_device *dev) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 50662306a36Sopenharmony_ci unsigned int mb = pi->adapter->mbox; 50762306a36Sopenharmony_ci int ret; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * We do not set address filters and promiscuity here, the stack does 51162306a36Sopenharmony_ci * that step explicitly. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci ret = t4_set_rxmode(pi->adapter, mb, pi->viid, pi->viid_mirror, 51462306a36Sopenharmony_ci dev->mtu, -1, -1, -1, 51562306a36Sopenharmony_ci !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true); 51662306a36Sopenharmony_ci if (ret == 0) 51762306a36Sopenharmony_ci ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt, 51862306a36Sopenharmony_ci dev->dev_addr, true, &pi->smt_idx); 51962306a36Sopenharmony_ci if (ret == 0) 52062306a36Sopenharmony_ci ret = t4_link_l1cfg(pi->adapter, mb, pi->tx_chan, 52162306a36Sopenharmony_ci &pi->link_cfg); 52262306a36Sopenharmony_ci if (ret == 0) { 52362306a36Sopenharmony_ci local_bh_disable(); 52462306a36Sopenharmony_ci ret = t4_enable_pi_params(pi->adapter, mb, pi, true, 52562306a36Sopenharmony_ci true, CXGB4_DCB_ENABLED); 52662306a36Sopenharmony_ci local_bh_enable(); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return ret; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 53362306a36Sopenharmony_ci/* Handle a Data Center Bridging update message from the firmware. */ 53462306a36Sopenharmony_cistatic void dcb_rpl(struct adapter *adap, const struct fw_port_cmd *pcmd) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci int port = FW_PORT_CMD_PORTID_G(ntohl(pcmd->op_to_portid)); 53762306a36Sopenharmony_ci struct net_device *dev = adap->port[adap->chan_map[port]]; 53862306a36Sopenharmony_ci int old_dcb_enabled = cxgb4_dcb_enabled(dev); 53962306a36Sopenharmony_ci int new_dcb_enabled; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci cxgb4_dcb_handle_fw_update(adap, pcmd); 54262306a36Sopenharmony_ci new_dcb_enabled = cxgb4_dcb_enabled(dev); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* If the DCB has become enabled or disabled on the port then we're 54562306a36Sopenharmony_ci * going to need to set up/tear down DCB Priority parameters for the 54662306a36Sopenharmony_ci * TX Queues associated with the port. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci if (new_dcb_enabled != old_dcb_enabled) 54962306a36Sopenharmony_ci dcb_tx_queue_prio_enable(dev, new_dcb_enabled); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* Response queue handler for the FW event queue. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_cistatic int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, 55662306a36Sopenharmony_ci const struct pkt_gl *gl) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci u8 opcode = ((const struct rss_header *)rsp)->opcode; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci rsp++; /* skip RSS header */ 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_ci if (unlikely(opcode == CPL_FW4_MSG && 56562306a36Sopenharmony_ci ((const struct cpl_fw4_msg *)rsp)->type == FW_TYPE_RSSCPL)) { 56662306a36Sopenharmony_ci rsp++; 56762306a36Sopenharmony_ci opcode = ((const struct rss_header *)rsp)->opcode; 56862306a36Sopenharmony_ci rsp++; 56962306a36Sopenharmony_ci if (opcode != CPL_SGE_EGR_UPDATE) { 57062306a36Sopenharmony_ci dev_err(q->adap->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n" 57162306a36Sopenharmony_ci , opcode); 57262306a36Sopenharmony_ci goto out; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (likely(opcode == CPL_SGE_EGR_UPDATE)) { 57762306a36Sopenharmony_ci const struct cpl_sge_egr_update *p = (void *)rsp; 57862306a36Sopenharmony_ci unsigned int qid = EGR_QID_G(ntohl(p->opcode_qid)); 57962306a36Sopenharmony_ci struct sge_txq *txq; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start]; 58262306a36Sopenharmony_ci txq->restarts++; 58362306a36Sopenharmony_ci if (txq->q_type == CXGB4_TXQ_ETH) { 58462306a36Sopenharmony_ci struct sge_eth_txq *eq; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci eq = container_of(txq, struct sge_eth_txq, q); 58762306a36Sopenharmony_ci t4_sge_eth_txq_egress_update(q->adap, eq, -1); 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci struct sge_uld_txq *oq; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci oq = container_of(txq, struct sge_uld_txq, q); 59262306a36Sopenharmony_ci tasklet_schedule(&oq->qresume_tsk); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci } else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) { 59562306a36Sopenharmony_ci const struct cpl_fw6_msg *p = (void *)rsp; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 59862306a36Sopenharmony_ci const struct fw_port_cmd *pcmd = (const void *)p->data; 59962306a36Sopenharmony_ci unsigned int cmd = FW_CMD_OP_G(ntohl(pcmd->op_to_portid)); 60062306a36Sopenharmony_ci unsigned int action = 60162306a36Sopenharmony_ci FW_PORT_CMD_ACTION_G(ntohl(pcmd->action_to_len16)); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (cmd == FW_PORT_CMD && 60462306a36Sopenharmony_ci (action == FW_PORT_ACTION_GET_PORT_INFO || 60562306a36Sopenharmony_ci action == FW_PORT_ACTION_GET_PORT_INFO32)) { 60662306a36Sopenharmony_ci int port = FW_PORT_CMD_PORTID_G( 60762306a36Sopenharmony_ci be32_to_cpu(pcmd->op_to_portid)); 60862306a36Sopenharmony_ci struct net_device *dev; 60962306a36Sopenharmony_ci int dcbxdis, state_input; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci dev = q->adap->port[q->adap->chan_map[port]]; 61262306a36Sopenharmony_ci dcbxdis = (action == FW_PORT_ACTION_GET_PORT_INFO 61362306a36Sopenharmony_ci ? !!(pcmd->u.info.dcbxdis_pkd & FW_PORT_CMD_DCBXDIS_F) 61462306a36Sopenharmony_ci : !!(be32_to_cpu(pcmd->u.info32.lstatus32_to_cbllen32) 61562306a36Sopenharmony_ci & FW_PORT_CMD_DCBXDIS32_F)); 61662306a36Sopenharmony_ci state_input = (dcbxdis 61762306a36Sopenharmony_ci ? CXGB4_DCB_INPUT_FW_DISABLED 61862306a36Sopenharmony_ci : CXGB4_DCB_INPUT_FW_ENABLED); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci cxgb4_dcb_state_fsm(dev, state_input); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (cmd == FW_PORT_CMD && 62462306a36Sopenharmony_ci action == FW_PORT_ACTION_L2_DCB_CFG) 62562306a36Sopenharmony_ci dcb_rpl(q->adap, pcmd); 62662306a36Sopenharmony_ci else 62762306a36Sopenharmony_ci#endif 62862306a36Sopenharmony_ci if (p->type == 0) 62962306a36Sopenharmony_ci t4_handle_fw_rpl(q->adap, p->data); 63062306a36Sopenharmony_ci } else if (opcode == CPL_L2T_WRITE_RPL) { 63162306a36Sopenharmony_ci const struct cpl_l2t_write_rpl *p = (void *)rsp; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci do_l2t_write_rpl(q->adap, p); 63462306a36Sopenharmony_ci } else if (opcode == CPL_SMT_WRITE_RPL) { 63562306a36Sopenharmony_ci const struct cpl_smt_write_rpl *p = (void *)rsp; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci do_smt_write_rpl(q->adap, p); 63862306a36Sopenharmony_ci } else if (opcode == CPL_SET_TCB_RPL) { 63962306a36Sopenharmony_ci const struct cpl_set_tcb_rpl *p = (void *)rsp; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci filter_rpl(q->adap, p); 64262306a36Sopenharmony_ci } else if (opcode == CPL_ACT_OPEN_RPL) { 64362306a36Sopenharmony_ci const struct cpl_act_open_rpl *p = (void *)rsp; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci hash_filter_rpl(q->adap, p); 64662306a36Sopenharmony_ci } else if (opcode == CPL_ABORT_RPL_RSS) { 64762306a36Sopenharmony_ci const struct cpl_abort_rpl_rss *p = (void *)rsp; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci hash_del_filter_rpl(q->adap, p); 65062306a36Sopenharmony_ci } else if (opcode == CPL_SRQ_TABLE_RPL) { 65162306a36Sopenharmony_ci const struct cpl_srq_table_rpl *p = (void *)rsp; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci do_srq_table_rpl(q->adap, p); 65462306a36Sopenharmony_ci } else 65562306a36Sopenharmony_ci dev_err(q->adap->pdev_dev, 65662306a36Sopenharmony_ci "unexpected CPL %#x on FW event queue\n", opcode); 65762306a36Sopenharmony_ciout: 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic void disable_msi(struct adapter *adapter) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci if (adapter->flags & CXGB4_USING_MSIX) { 66462306a36Sopenharmony_ci pci_disable_msix(adapter->pdev); 66562306a36Sopenharmony_ci adapter->flags &= ~CXGB4_USING_MSIX; 66662306a36Sopenharmony_ci } else if (adapter->flags & CXGB4_USING_MSI) { 66762306a36Sopenharmony_ci pci_disable_msi(adapter->pdev); 66862306a36Sopenharmony_ci adapter->flags &= ~CXGB4_USING_MSI; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/* 67362306a36Sopenharmony_ci * Interrupt handler for non-data events used with MSI-X. 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_cistatic irqreturn_t t4_nondata_intr(int irq, void *cookie) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct adapter *adap = cookie; 67862306a36Sopenharmony_ci u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A)); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (v & PFSW_F) { 68162306a36Sopenharmony_ci adap->swintr = 1; 68262306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A), v); 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci if (adap->flags & CXGB4_MASTER_PF) 68562306a36Sopenharmony_ci t4_slow_intr_handler(adap); 68662306a36Sopenharmony_ci return IRQ_HANDLED; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ciint cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec, 69062306a36Sopenharmony_ci cpumask_var_t *aff_mask, int idx) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci int rv; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (!zalloc_cpumask_var(aff_mask, GFP_KERNEL)) { 69562306a36Sopenharmony_ci dev_err(adap->pdev_dev, "alloc_cpumask_var failed\n"); 69662306a36Sopenharmony_ci return -ENOMEM; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(idx, dev_to_node(adap->pdev_dev)), 70062306a36Sopenharmony_ci *aff_mask); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci rv = irq_set_affinity_hint(vec, *aff_mask); 70362306a36Sopenharmony_ci if (rv) 70462306a36Sopenharmony_ci dev_warn(adap->pdev_dev, 70562306a36Sopenharmony_ci "irq_set_affinity_hint %u failed %d\n", 70662306a36Sopenharmony_ci vec, rv); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_civoid cxgb4_clear_msix_aff(unsigned short vec, cpumask_var_t aff_mask) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci irq_set_affinity_hint(vec, NULL); 71462306a36Sopenharmony_ci free_cpumask_var(aff_mask); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic int request_msix_queue_irqs(struct adapter *adap) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct sge *s = &adap->sge; 72062306a36Sopenharmony_ci struct msix_info *minfo; 72162306a36Sopenharmony_ci int err, ethqidx; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (s->fwevtq_msix_idx < 0) 72462306a36Sopenharmony_ci return -ENOMEM; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci err = request_irq(adap->msix_info[s->fwevtq_msix_idx].vec, 72762306a36Sopenharmony_ci t4_sge_intr_msix, 0, 72862306a36Sopenharmony_ci adap->msix_info[s->fwevtq_msix_idx].desc, 72962306a36Sopenharmony_ci &s->fw_evtq); 73062306a36Sopenharmony_ci if (err) 73162306a36Sopenharmony_ci return err; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci for_each_ethrxq(s, ethqidx) { 73462306a36Sopenharmony_ci minfo = s->ethrxq[ethqidx].msix; 73562306a36Sopenharmony_ci err = request_irq(minfo->vec, 73662306a36Sopenharmony_ci t4_sge_intr_msix, 0, 73762306a36Sopenharmony_ci minfo->desc, 73862306a36Sopenharmony_ci &s->ethrxq[ethqidx].rspq); 73962306a36Sopenharmony_ci if (err) 74062306a36Sopenharmony_ci goto unwind; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci cxgb4_set_msix_aff(adap, minfo->vec, 74362306a36Sopenharmony_ci &minfo->aff_mask, ethqidx); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ciunwind: 74862306a36Sopenharmony_ci while (--ethqidx >= 0) { 74962306a36Sopenharmony_ci minfo = s->ethrxq[ethqidx].msix; 75062306a36Sopenharmony_ci cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); 75162306a36Sopenharmony_ci free_irq(minfo->vec, &s->ethrxq[ethqidx].rspq); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); 75462306a36Sopenharmony_ci return err; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic void free_msix_queue_irqs(struct adapter *adap) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct sge *s = &adap->sge; 76062306a36Sopenharmony_ci struct msix_info *minfo; 76162306a36Sopenharmony_ci int i; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); 76462306a36Sopenharmony_ci for_each_ethrxq(s, i) { 76562306a36Sopenharmony_ci minfo = s->ethrxq[i].msix; 76662306a36Sopenharmony_ci cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); 76762306a36Sopenharmony_ci free_irq(minfo->vec, &s->ethrxq[i].rspq); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int setup_ppod_edram(struct adapter *adap) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci unsigned int param, val; 77462306a36Sopenharmony_ci int ret; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* Driver sends FW_PARAMS_PARAM_DEV_PPOD_EDRAM read command to check 77762306a36Sopenharmony_ci * if firmware supports ppod edram feature or not. If firmware 77862306a36Sopenharmony_ci * returns 1, then driver can enable this feature by sending 77962306a36Sopenharmony_ci * FW_PARAMS_PARAM_DEV_PPOD_EDRAM write command with value 1 to 78062306a36Sopenharmony_ci * enable ppod edram feature. 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 78362306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PPOD_EDRAM)); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 78662306a36Sopenharmony_ci if (ret < 0) { 78762306a36Sopenharmony_ci dev_warn(adap->pdev_dev, 78862306a36Sopenharmony_ci "querying PPOD_EDRAM support failed: %d\n", 78962306a36Sopenharmony_ci ret); 79062306a36Sopenharmony_ci return -1; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (val != 1) 79462306a36Sopenharmony_ci return -1; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); 79762306a36Sopenharmony_ci if (ret < 0) { 79862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 79962306a36Sopenharmony_ci "setting PPOD_EDRAM failed: %d\n", ret); 80062306a36Sopenharmony_ci return -1; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic void adap_config_hpfilter(struct adapter *adapter) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci u32 param, val = 0; 80862306a36Sopenharmony_ci int ret; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* Enable HP filter region. Older fw will fail this request and 81162306a36Sopenharmony_ci * it is fine. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci param = FW_PARAM_DEV(HPFILTER_REGION_SUPPORT); 81462306a36Sopenharmony_ci ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0, 81562306a36Sopenharmony_ci 1, ¶m, &val); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* An error means FW doesn't know about HP filter support, 81862306a36Sopenharmony_ci * it's not a problem, don't return an error. 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ci if (ret < 0) 82162306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 82262306a36Sopenharmony_ci "HP filter region isn't supported by FW\n"); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int cxgb4_config_rss(const struct port_info *pi, u16 *rss, 82662306a36Sopenharmony_ci u16 rss_size, u16 viid) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 82962306a36Sopenharmony_ci int ret; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ret = t4_config_rss_range(adap, adap->mbox, viid, 0, rss_size, rss, 83262306a36Sopenharmony_ci rss_size); 83362306a36Sopenharmony_ci if (ret) 83462306a36Sopenharmony_ci return ret; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* If Tunnel All Lookup isn't specified in the global RSS 83762306a36Sopenharmony_ci * Configuration, then we need to specify a default Ingress 83862306a36Sopenharmony_ci * Queue for any ingress packets which aren't hashed. We'll 83962306a36Sopenharmony_ci * use our first ingress queue ... 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ci return t4_config_vi_rss(adap, adap->mbox, viid, 84262306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F | 84362306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F | 84462306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F | 84562306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F | 84662306a36Sopenharmony_ci FW_RSS_VI_CONFIG_CMD_UDPEN_F, 84762306a36Sopenharmony_ci rss[0]); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/** 85162306a36Sopenharmony_ci * cxgb4_write_rss - write the RSS table for a given port 85262306a36Sopenharmony_ci * @pi: the port 85362306a36Sopenharmony_ci * @queues: array of queue indices for RSS 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Sets up the portion of the HW RSS table for the port's VI to distribute 85662306a36Sopenharmony_ci * packets to the Rx queues in @queues. 85762306a36Sopenharmony_ci * Should never be called before setting up sge eth rx queues 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ciint cxgb4_write_rss(const struct port_info *pi, const u16 *queues) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 86262306a36Sopenharmony_ci const struct sge_eth_rxq *rxq; 86362306a36Sopenharmony_ci int i, err; 86462306a36Sopenharmony_ci u16 *rss; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci rxq = &adapter->sge.ethrxq[pi->first_qset]; 86762306a36Sopenharmony_ci rss = kmalloc_array(pi->rss_size, sizeof(u16), GFP_KERNEL); 86862306a36Sopenharmony_ci if (!rss) 86962306a36Sopenharmony_ci return -ENOMEM; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* map the queue indices to queue ids */ 87262306a36Sopenharmony_ci for (i = 0; i < pi->rss_size; i++, queues++) 87362306a36Sopenharmony_ci rss[i] = rxq[*queues].rspq.abs_id; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci err = cxgb4_config_rss(pi, rss, pi->rss_size, pi->viid); 87662306a36Sopenharmony_ci kfree(rss); 87762306a36Sopenharmony_ci return err; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci/** 88162306a36Sopenharmony_ci * setup_rss - configure RSS 88262306a36Sopenharmony_ci * @adap: the adapter 88362306a36Sopenharmony_ci * 88462306a36Sopenharmony_ci * Sets up RSS for each port. 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_cistatic int setup_rss(struct adapter *adap) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci int i, j, err; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci for_each_port(adap, i) { 89162306a36Sopenharmony_ci const struct port_info *pi = adap2pinfo(adap, i); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* Fill default values with equal distribution */ 89462306a36Sopenharmony_ci for (j = 0; j < pi->rss_size; j++) 89562306a36Sopenharmony_ci pi->rss[j] = j % pi->nqsets; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci err = cxgb4_write_rss(pi, pi->rss); 89862306a36Sopenharmony_ci if (err) 89962306a36Sopenharmony_ci return err; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci return 0; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci/* 90562306a36Sopenharmony_ci * Return the channel of the ingress queue with the given qid. 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_cistatic unsigned int rxq_to_chan(const struct sge *p, unsigned int qid) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci qid -= p->ingr_start; 91062306a36Sopenharmony_ci return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_civoid cxgb4_quiesce_rx(struct sge_rspq *q) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci if (q->handler) 91662306a36Sopenharmony_ci napi_disable(&q->napi); 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci/* 92062306a36Sopenharmony_ci * Wait until all NAPI handlers are descheduled. 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_cistatic void quiesce_rx(struct adapter *adap) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci int i; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci for (i = 0; i < adap->sge.ingr_sz; i++) { 92762306a36Sopenharmony_ci struct sge_rspq *q = adap->sge.ingr_map[i]; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (!q) 93062306a36Sopenharmony_ci continue; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci cxgb4_quiesce_rx(q); 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci/* Disable interrupt and napi handler */ 93762306a36Sopenharmony_cistatic void disable_interrupts(struct adapter *adap) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct sge *s = &adap->sge; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) { 94262306a36Sopenharmony_ci t4_intr_disable(adap); 94362306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 94462306a36Sopenharmony_ci free_msix_queue_irqs(adap); 94562306a36Sopenharmony_ci free_irq(adap->msix_info[s->nd_msix_idx].vec, 94662306a36Sopenharmony_ci adap); 94762306a36Sopenharmony_ci } else { 94862306a36Sopenharmony_ci free_irq(adap->pdev->irq, adap); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci quiesce_rx(adap); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_civoid cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci if (q->handler) 95762306a36Sopenharmony_ci napi_enable(&q->napi); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* 0-increment GTS to start the timer and enable interrupts */ 96062306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), 96162306a36Sopenharmony_ci SEINTARM_V(q->intr_params) | 96262306a36Sopenharmony_ci INGRESSQID_V(q->cntxt_id)); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/* 96662306a36Sopenharmony_ci * Enable NAPI scheduling and interrupt generation for all Rx queues. 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_cistatic void enable_rx(struct adapter *adap) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci int i; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci for (i = 0; i < adap->sge.ingr_sz; i++) { 97362306a36Sopenharmony_ci struct sge_rspq *q = adap->sge.ingr_map[i]; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (!q) 97662306a36Sopenharmony_ci continue; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci cxgb4_enable_rx(adap, q); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int setup_non_data_intr(struct adapter *adap) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci int msix; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci adap->sge.nd_msix_idx = -1; 98762306a36Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 98862306a36Sopenharmony_ci return 0; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* Request MSI-X vector for non-data interrupt */ 99162306a36Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 99262306a36Sopenharmony_ci if (msix < 0) 99362306a36Sopenharmony_ci return -ENOMEM; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci snprintf(adap->msix_info[msix].desc, 99662306a36Sopenharmony_ci sizeof(adap->msix_info[msix].desc), 99762306a36Sopenharmony_ci "%s", adap->port[0]->name); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci adap->sge.nd_msix_idx = msix; 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int setup_fw_sge_queues(struct adapter *adap) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct sge *s = &adap->sge; 100662306a36Sopenharmony_ci int msix, err = 0; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci bitmap_zero(s->starving_fl, s->egr_sz); 100962306a36Sopenharmony_ci bitmap_zero(s->txq_maperr, s->egr_sz); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 101262306a36Sopenharmony_ci s->fwevtq_msix_idx = -1; 101362306a36Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 101462306a36Sopenharmony_ci if (msix < 0) 101562306a36Sopenharmony_ci return -ENOMEM; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci snprintf(adap->msix_info[msix].desc, 101862306a36Sopenharmony_ci sizeof(adap->msix_info[msix].desc), 101962306a36Sopenharmony_ci "%s-FWeventq", adap->port[0]->name); 102062306a36Sopenharmony_ci } else { 102162306a36Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, 102262306a36Sopenharmony_ci NULL, NULL, NULL, -1); 102362306a36Sopenharmony_ci if (err) 102462306a36Sopenharmony_ci return err; 102562306a36Sopenharmony_ci msix = -((int)s->intrq.abs_id + 1); 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], 102962306a36Sopenharmony_ci msix, NULL, fwevtq_handler, NULL, -1); 103062306a36Sopenharmony_ci if (err && msix >= 0) 103162306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, msix); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci s->fwevtq_msix_idx = msix; 103462306a36Sopenharmony_ci return err; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci/** 103862306a36Sopenharmony_ci * setup_sge_queues - configure SGE Tx/Rx/response queues 103962306a36Sopenharmony_ci * @adap: the adapter 104062306a36Sopenharmony_ci * 104162306a36Sopenharmony_ci * Determines how many sets of SGE queues to use and initializes them. 104262306a36Sopenharmony_ci * We support multiple queue sets per port if we have MSI-X, otherwise 104362306a36Sopenharmony_ci * just one queue set per port. 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_cistatic int setup_sge_queues(struct adapter *adap) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct sge_uld_rxq_info *rxq_info = NULL; 104862306a36Sopenharmony_ci struct sge *s = &adap->sge; 104962306a36Sopenharmony_ci unsigned int cmplqid = 0; 105062306a36Sopenharmony_ci int err, i, j, msix = 0; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (is_uld(adap)) 105362306a36Sopenharmony_ci rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 105662306a36Sopenharmony_ci msix = -((int)s->intrq.abs_id + 1); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci for_each_port(adap, i) { 105962306a36Sopenharmony_ci struct net_device *dev = adap->port[i]; 106062306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 106162306a36Sopenharmony_ci struct sge_eth_rxq *q = &s->ethrxq[pi->first_qset]; 106262306a36Sopenharmony_ci struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci for (j = 0; j < pi->nqsets; j++, q++) { 106562306a36Sopenharmony_ci if (msix >= 0) { 106662306a36Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 106762306a36Sopenharmony_ci if (msix < 0) { 106862306a36Sopenharmony_ci err = msix; 106962306a36Sopenharmony_ci goto freeout; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci snprintf(adap->msix_info[msix].desc, 107362306a36Sopenharmony_ci sizeof(adap->msix_info[msix].desc), 107462306a36Sopenharmony_ci "%s-Rx%d", dev->name, j); 107562306a36Sopenharmony_ci q->msix = &adap->msix_info[msix]; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, 107962306a36Sopenharmony_ci msix, &q->fl, 108062306a36Sopenharmony_ci t4_ethrx_handler, 108162306a36Sopenharmony_ci NULL, 108262306a36Sopenharmony_ci t4_get_tp_ch_map(adap, 108362306a36Sopenharmony_ci pi->tx_chan)); 108462306a36Sopenharmony_ci if (err) 108562306a36Sopenharmony_ci goto freeout; 108662306a36Sopenharmony_ci q->rspq.idx = j; 108762306a36Sopenharmony_ci memset(&q->stats, 0, sizeof(q->stats)); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci q = &s->ethrxq[pi->first_qset]; 109162306a36Sopenharmony_ci for (j = 0; j < pi->nqsets; j++, t++, q++) { 109262306a36Sopenharmony_ci err = t4_sge_alloc_eth_txq(adap, t, dev, 109362306a36Sopenharmony_ci netdev_get_tx_queue(dev, j), 109462306a36Sopenharmony_ci q->rspq.cntxt_id, 109562306a36Sopenharmony_ci !!(adap->flags & CXGB4_SGE_DBQ_TIMER)); 109662306a36Sopenharmony_ci if (err) 109762306a36Sopenharmony_ci goto freeout; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci for_each_port(adap, i) { 110262306a36Sopenharmony_ci /* Note that cmplqid below is 0 if we don't 110362306a36Sopenharmony_ci * have RDMA queues, and that's the right value. 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_ci if (rxq_info) 110662306a36Sopenharmony_ci cmplqid = rxq_info->uldrxq[i].rspq.cntxt_id; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci err = t4_sge_alloc_ctrl_txq(adap, &s->ctrlq[i], adap->port[i], 110962306a36Sopenharmony_ci s->fw_evtq.cntxt_id, cmplqid); 111062306a36Sopenharmony_ci if (err) 111162306a36Sopenharmony_ci goto freeout; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (!is_t4(adap->params.chip)) { 111562306a36Sopenharmony_ci err = t4_sge_alloc_eth_txq(adap, &s->ptptxq, adap->port[0], 111662306a36Sopenharmony_ci netdev_get_tx_queue(adap->port[0], 0) 111762306a36Sopenharmony_ci , s->fw_evtq.cntxt_id, false); 111862306a36Sopenharmony_ci if (err) 111962306a36Sopenharmony_ci goto freeout; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci t4_write_reg(adap, is_t4(adap->params.chip) ? 112362306a36Sopenharmony_ci MPS_TRC_RSS_CONTROL_A : 112462306a36Sopenharmony_ci MPS_T5_TRC_RSS_CONTROL_A, 112562306a36Sopenharmony_ci RSSCONTROL_V(netdev2pinfo(adap->port[0])->tx_chan) | 112662306a36Sopenharmony_ci QUEUENUMBER_V(s->ethrxq[0].rspq.abs_id)); 112762306a36Sopenharmony_ci return 0; 112862306a36Sopenharmony_cifreeout: 112962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Can't allocate queues, err=%d\n", -err); 113062306a36Sopenharmony_ci t4_free_sge_resources(adap); 113162306a36Sopenharmony_ci return err; 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, 113562306a36Sopenharmony_ci struct net_device *sb_dev) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci int txq; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 114062306a36Sopenharmony_ci /* If a Data Center Bridging has been successfully negotiated on this 114162306a36Sopenharmony_ci * link then we'll use the skb's priority to map it to a TX Queue. 114262306a36Sopenharmony_ci * The skb's priority is determined via the VLAN Tag Priority Code 114362306a36Sopenharmony_ci * Point field. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci if (cxgb4_dcb_enabled(dev) && !is_kdump_kernel()) { 114662306a36Sopenharmony_ci u16 vlan_tci; 114762306a36Sopenharmony_ci int err; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci err = vlan_get_tag(skb, &vlan_tci); 115062306a36Sopenharmony_ci if (unlikely(err)) { 115162306a36Sopenharmony_ci if (net_ratelimit()) 115262306a36Sopenharmony_ci netdev_warn(dev, 115362306a36Sopenharmony_ci "TX Packet without VLAN Tag on DCB Link\n"); 115462306a36Sopenharmony_ci txq = 0; 115562306a36Sopenharmony_ci } else { 115662306a36Sopenharmony_ci txq = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 115762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 115862306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_FCOE)) 115962306a36Sopenharmony_ci txq = skb->priority & 0x7; 116062306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci return txq; 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_DCB */ 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (dev->num_tc) { 116762306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 116862306a36Sopenharmony_ci u8 ver, proto; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ver = ip_hdr(skb)->version; 117162306a36Sopenharmony_ci proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr : 117262306a36Sopenharmony_ci ip_hdr(skb)->protocol; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci /* Send unsupported traffic pattern to normal NIC queues. */ 117562306a36Sopenharmony_ci txq = netdev_pick_tx(dev, skb, sb_dev); 117662306a36Sopenharmony_ci if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) || 117762306a36Sopenharmony_ci skb->encapsulation || 117862306a36Sopenharmony_ci tls_is_skb_tx_device_offloaded(skb) || 117962306a36Sopenharmony_ci (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) 118062306a36Sopenharmony_ci txq = txq % pi->nqsets; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci return txq; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (select_queue) { 118662306a36Sopenharmony_ci txq = (skb_rx_queue_recorded(skb) 118762306a36Sopenharmony_ci ? skb_get_rx_queue(skb) 118862306a36Sopenharmony_ci : smp_processor_id()); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci while (unlikely(txq >= dev->real_num_tx_queues)) 119162306a36Sopenharmony_ci txq -= dev->real_num_tx_queues; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci return txq; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci return netdev_pick_tx(dev, skb, NULL) % dev->real_num_tx_queues; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic int closest_timer(const struct sge *s, int time) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci int i, delta, match = 0, min_delta = INT_MAX; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { 120462306a36Sopenharmony_ci delta = time - s->timer_val[i]; 120562306a36Sopenharmony_ci if (delta < 0) 120662306a36Sopenharmony_ci delta = -delta; 120762306a36Sopenharmony_ci if (delta < min_delta) { 120862306a36Sopenharmony_ci min_delta = delta; 120962306a36Sopenharmony_ci match = i; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci return match; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int closest_thres(const struct sge *s, int thres) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci int i, delta, match = 0, min_delta = INT_MAX; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { 122062306a36Sopenharmony_ci delta = thres - s->counter_val[i]; 122162306a36Sopenharmony_ci if (delta < 0) 122262306a36Sopenharmony_ci delta = -delta; 122362306a36Sopenharmony_ci if (delta < min_delta) { 122462306a36Sopenharmony_ci min_delta = delta; 122562306a36Sopenharmony_ci match = i; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci return match; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/** 123262306a36Sopenharmony_ci * cxgb4_set_rspq_intr_params - set a queue's interrupt holdoff parameters 123362306a36Sopenharmony_ci * @q: the Rx queue 123462306a36Sopenharmony_ci * @us: the hold-off time in us, or 0 to disable timer 123562306a36Sopenharmony_ci * @cnt: the hold-off packet count, or 0 to disable counter 123662306a36Sopenharmony_ci * 123762306a36Sopenharmony_ci * Sets an Rx queue's interrupt hold-off time and packet count. At least 123862306a36Sopenharmony_ci * one of the two needs to be enabled for the queue to generate interrupts. 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_ciint cxgb4_set_rspq_intr_params(struct sge_rspq *q, 124162306a36Sopenharmony_ci unsigned int us, unsigned int cnt) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci struct adapter *adap = q->adap; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if ((us | cnt) == 0) 124662306a36Sopenharmony_ci cnt = 1; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (cnt) { 124962306a36Sopenharmony_ci int err; 125062306a36Sopenharmony_ci u32 v, new_idx; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci new_idx = closest_thres(&adap->sge, cnt); 125362306a36Sopenharmony_ci if (q->desc && q->pktcnt_idx != new_idx) { 125462306a36Sopenharmony_ci /* the queue has already been created, update it */ 125562306a36Sopenharmony_ci v = FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DMAQ) | 125662306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V( 125762306a36Sopenharmony_ci FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | 125862306a36Sopenharmony_ci FW_PARAMS_PARAM_YZ_V(q->cntxt_id); 125962306a36Sopenharmony_ci err = t4_set_params(adap, adap->mbox, adap->pf, 0, 1, 126062306a36Sopenharmony_ci &v, &new_idx); 126162306a36Sopenharmony_ci if (err) 126262306a36Sopenharmony_ci return err; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci q->pktcnt_idx = new_idx; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci us = us == 0 ? 6 : closest_timer(&adap->sge, us); 126862306a36Sopenharmony_ci q->intr_params = QINTR_TIMER_IDX_V(us) | QINTR_CNT_EN_V(cnt > 0); 126962306a36Sopenharmony_ci return 0; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic int cxgb_set_features(struct net_device *dev, netdev_features_t features) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 127562306a36Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 127662306a36Sopenharmony_ci int err; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (!(changed & NETIF_F_HW_VLAN_CTAG_RX)) 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci err = t4_set_rxmode(pi->adapter, pi->adapter->mbox, pi->viid, 128262306a36Sopenharmony_ci pi->viid_mirror, -1, -1, -1, -1, 128362306a36Sopenharmony_ci !!(features & NETIF_F_HW_VLAN_CTAG_RX), true); 128462306a36Sopenharmony_ci if (unlikely(err)) 128562306a36Sopenharmony_ci dev->features = features ^ NETIF_F_HW_VLAN_CTAG_RX; 128662306a36Sopenharmony_ci return err; 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_cistatic int setup_debugfs(struct adapter *adap) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci if (IS_ERR_OR_NULL(adap->debugfs_root)) 129262306a36Sopenharmony_ci return -1; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 129562306a36Sopenharmony_ci t4_setup_debugfs(adap); 129662306a36Sopenharmony_ci#endif 129762306a36Sopenharmony_ci return 0; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic void cxgb4_port_mirror_free_rxq(struct adapter *adap, 130162306a36Sopenharmony_ci struct sge_eth_rxq *mirror_rxq) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci if ((adap->flags & CXGB4_FULL_INIT_DONE) && 130462306a36Sopenharmony_ci !(adap->flags & CXGB4_SHUTTING_DOWN)) 130562306a36Sopenharmony_ci cxgb4_quiesce_rx(&mirror_rxq->rspq); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 130862306a36Sopenharmony_ci cxgb4_clear_msix_aff(mirror_rxq->msix->vec, 130962306a36Sopenharmony_ci mirror_rxq->msix->aff_mask); 131062306a36Sopenharmony_ci free_irq(mirror_rxq->msix->vec, &mirror_rxq->rspq); 131162306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, mirror_rxq->msix->idx); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci free_rspq_fl(adap, &mirror_rxq->rspq, &mirror_rxq->fl); 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic int cxgb4_port_mirror_alloc_queues(struct net_device *dev) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 132062306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 132162306a36Sopenharmony_ci struct sge_eth_rxq *mirror_rxq; 132262306a36Sopenharmony_ci struct sge *s = &adap->sge; 132362306a36Sopenharmony_ci int ret = 0, msix = 0; 132462306a36Sopenharmony_ci u16 i, rxqid; 132562306a36Sopenharmony_ci u16 *rss; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (!pi->vi_mirror_count) 132862306a36Sopenharmony_ci return 0; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci if (s->mirror_rxq[pi->port_id]) 133162306a36Sopenharmony_ci return 0; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci mirror_rxq = kcalloc(pi->nmirrorqsets, sizeof(*mirror_rxq), GFP_KERNEL); 133462306a36Sopenharmony_ci if (!mirror_rxq) 133562306a36Sopenharmony_ci return -ENOMEM; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci s->mirror_rxq[pi->port_id] = mirror_rxq; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 134062306a36Sopenharmony_ci msix = -((int)adap->sge.intrq.abs_id + 1); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci for (i = 0, rxqid = 0; i < pi->nmirrorqsets; i++, rxqid++) { 134362306a36Sopenharmony_ci mirror_rxq = &s->mirror_rxq[pi->port_id][i]; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci /* Allocate Mirror Rxqs */ 134662306a36Sopenharmony_ci if (msix >= 0) { 134762306a36Sopenharmony_ci msix = cxgb4_get_msix_idx_from_bmap(adap); 134862306a36Sopenharmony_ci if (msix < 0) { 134962306a36Sopenharmony_ci ret = msix; 135062306a36Sopenharmony_ci goto out_free_queues; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci mirror_rxq->msix = &adap->msix_info[msix]; 135462306a36Sopenharmony_ci snprintf(mirror_rxq->msix->desc, 135562306a36Sopenharmony_ci sizeof(mirror_rxq->msix->desc), 135662306a36Sopenharmony_ci "%s-mirrorrxq%d", dev->name, i); 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci init_rspq(adap, &mirror_rxq->rspq, 136062306a36Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_INTR_USEC, 136162306a36Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_PKT_CNT, 136262306a36Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_DESC_NUM, 136362306a36Sopenharmony_ci CXGB4_MIRROR_RXQ_DEFAULT_DESC_SIZE); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci mirror_rxq->fl.size = CXGB4_MIRROR_FLQ_DEFAULT_DESC_NUM; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = t4_sge_alloc_rxq(adap, &mirror_rxq->rspq, false, 136862306a36Sopenharmony_ci dev, msix, &mirror_rxq->fl, 136962306a36Sopenharmony_ci t4_ethrx_handler, NULL, 0); 137062306a36Sopenharmony_ci if (ret) 137162306a36Sopenharmony_ci goto out_free_msix_idx; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci /* Setup MSI-X vectors for Mirror Rxqs */ 137462306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 137562306a36Sopenharmony_ci ret = request_irq(mirror_rxq->msix->vec, 137662306a36Sopenharmony_ci t4_sge_intr_msix, 0, 137762306a36Sopenharmony_ci mirror_rxq->msix->desc, 137862306a36Sopenharmony_ci &mirror_rxq->rspq); 137962306a36Sopenharmony_ci if (ret) 138062306a36Sopenharmony_ci goto out_free_rxq; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci cxgb4_set_msix_aff(adap, mirror_rxq->msix->vec, 138362306a36Sopenharmony_ci &mirror_rxq->msix->aff_mask, i); 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* Start NAPI for Mirror Rxqs */ 138762306a36Sopenharmony_ci cxgb4_enable_rx(adap, &mirror_rxq->rspq); 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* Setup RSS for Mirror Rxqs */ 139162306a36Sopenharmony_ci rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); 139262306a36Sopenharmony_ci if (!rss) { 139362306a36Sopenharmony_ci ret = -ENOMEM; 139462306a36Sopenharmony_ci goto out_free_queues; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci mirror_rxq = &s->mirror_rxq[pi->port_id][0]; 139862306a36Sopenharmony_ci for (i = 0; i < pi->rss_size; i++) 139962306a36Sopenharmony_ci rss[i] = mirror_rxq[i % pi->nmirrorqsets].rspq.abs_id; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci ret = cxgb4_config_rss(pi, rss, pi->rss_size, pi->viid_mirror); 140262306a36Sopenharmony_ci kfree(rss); 140362306a36Sopenharmony_ci if (ret) 140462306a36Sopenharmony_ci goto out_free_queues; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return 0; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ciout_free_rxq: 140962306a36Sopenharmony_ci free_rspq_fl(adap, &mirror_rxq->rspq, &mirror_rxq->fl); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ciout_free_msix_idx: 141262306a36Sopenharmony_ci cxgb4_free_msix_idx_in_bmap(adap, mirror_rxq->msix->idx); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ciout_free_queues: 141562306a36Sopenharmony_ci while (rxqid-- > 0) 141662306a36Sopenharmony_ci cxgb4_port_mirror_free_rxq(adap, 141762306a36Sopenharmony_ci &s->mirror_rxq[pi->port_id][rxqid]); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci kfree(s->mirror_rxq[pi->port_id]); 142062306a36Sopenharmony_ci s->mirror_rxq[pi->port_id] = NULL; 142162306a36Sopenharmony_ci return ret; 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cistatic void cxgb4_port_mirror_free_queues(struct net_device *dev) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 142762306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 142862306a36Sopenharmony_ci struct sge *s = &adap->sge; 142962306a36Sopenharmony_ci u16 i; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (!pi->vi_mirror_count) 143262306a36Sopenharmony_ci return; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (!s->mirror_rxq[pi->port_id]) 143562306a36Sopenharmony_ci return; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci for (i = 0; i < pi->nmirrorqsets; i++) 143862306a36Sopenharmony_ci cxgb4_port_mirror_free_rxq(adap, 143962306a36Sopenharmony_ci &s->mirror_rxq[pi->port_id][i]); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci kfree(s->mirror_rxq[pi->port_id]); 144262306a36Sopenharmony_ci s->mirror_rxq[pi->port_id] = NULL; 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic int cxgb4_port_mirror_start(struct net_device *dev) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 144862306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 144962306a36Sopenharmony_ci int ret, idx = -1; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (!pi->vi_mirror_count) 145262306a36Sopenharmony_ci return 0; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* Mirror VIs can be created dynamically after stack had 145562306a36Sopenharmony_ci * already setup Rx modes like MTU, promisc, allmulti, etc. 145662306a36Sopenharmony_ci * on main VI. So, parse what the stack had setup on the 145762306a36Sopenharmony_ci * main VI and update the same on the mirror VI. 145862306a36Sopenharmony_ci */ 145962306a36Sopenharmony_ci ret = t4_set_rxmode(adap, adap->mbox, pi->viid, pi->viid_mirror, 146062306a36Sopenharmony_ci dev->mtu, (dev->flags & IFF_PROMISC) ? 1 : 0, 146162306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, 146262306a36Sopenharmony_ci !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true); 146362306a36Sopenharmony_ci if (ret) { 146462306a36Sopenharmony_ci dev_err(adap->pdev_dev, 146562306a36Sopenharmony_ci "Failed start up Rx mode for Mirror VI 0x%x, ret: %d\n", 146662306a36Sopenharmony_ci pi->viid_mirror, ret); 146762306a36Sopenharmony_ci return ret; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* Enable replication bit for the device's MAC address 147162306a36Sopenharmony_ci * in MPS TCAM, so that the packets for the main VI are 147262306a36Sopenharmony_ci * replicated to mirror VI. 147362306a36Sopenharmony_ci */ 147462306a36Sopenharmony_ci ret = cxgb4_update_mac_filt(pi, pi->viid_mirror, &idx, 147562306a36Sopenharmony_ci dev->dev_addr, true, NULL); 147662306a36Sopenharmony_ci if (ret) { 147762306a36Sopenharmony_ci dev_err(adap->pdev_dev, 147862306a36Sopenharmony_ci "Failed updating MAC filter for Mirror VI 0x%x, ret: %d\n", 147962306a36Sopenharmony_ci pi->viid_mirror, ret); 148062306a36Sopenharmony_ci return ret; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci /* Enabling a Virtual Interface can result in an interrupt 148462306a36Sopenharmony_ci * during the processing of the VI Enable command and, in some 148562306a36Sopenharmony_ci * paths, result in an attempt to issue another command in the 148662306a36Sopenharmony_ci * interrupt context. Thus, we disable interrupts during the 148762306a36Sopenharmony_ci * course of the VI Enable command ... 148862306a36Sopenharmony_ci */ 148962306a36Sopenharmony_ci local_bh_disable(); 149062306a36Sopenharmony_ci ret = t4_enable_vi_params(adap, adap->mbox, pi->viid_mirror, true, true, 149162306a36Sopenharmony_ci false); 149262306a36Sopenharmony_ci local_bh_enable(); 149362306a36Sopenharmony_ci if (ret) 149462306a36Sopenharmony_ci dev_err(adap->pdev_dev, 149562306a36Sopenharmony_ci "Failed starting Mirror VI 0x%x, ret: %d\n", 149662306a36Sopenharmony_ci pi->viid_mirror, ret); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return ret; 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic void cxgb4_port_mirror_stop(struct net_device *dev) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 150462306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci if (!pi->vi_mirror_count) 150762306a36Sopenharmony_ci return; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci t4_enable_vi_params(adap, adap->mbox, pi->viid_mirror, false, false, 151062306a36Sopenharmony_ci false); 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ciint cxgb4_port_mirror_alloc(struct net_device *dev) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 151662306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 151762306a36Sopenharmony_ci int ret = 0; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci if (!pi->nmirrorqsets) 152062306a36Sopenharmony_ci return -EOPNOTSUPP; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 152362306a36Sopenharmony_ci if (pi->viid_mirror) { 152462306a36Sopenharmony_ci pi->vi_mirror_count++; 152562306a36Sopenharmony_ci goto out_unlock; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci ret = t4_init_port_mirror(pi, adap->mbox, pi->port_id, adap->pf, 0, 152962306a36Sopenharmony_ci &pi->viid_mirror); 153062306a36Sopenharmony_ci if (ret) 153162306a36Sopenharmony_ci goto out_unlock; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci pi->vi_mirror_count = 1; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) { 153662306a36Sopenharmony_ci ret = cxgb4_port_mirror_alloc_queues(dev); 153762306a36Sopenharmony_ci if (ret) 153862306a36Sopenharmony_ci goto out_free_vi; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci ret = cxgb4_port_mirror_start(dev); 154162306a36Sopenharmony_ci if (ret) 154262306a36Sopenharmony_ci goto out_free_queues; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 154662306a36Sopenharmony_ci return 0; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ciout_free_queues: 154962306a36Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ciout_free_vi: 155262306a36Sopenharmony_ci pi->vi_mirror_count = 0; 155362306a36Sopenharmony_ci t4_free_vi(adap, adap->mbox, adap->pf, 0, pi->viid_mirror); 155462306a36Sopenharmony_ci pi->viid_mirror = 0; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ciout_unlock: 155762306a36Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 155862306a36Sopenharmony_ci return ret; 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_civoid cxgb4_port_mirror_free(struct net_device *dev) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 156462306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 156762306a36Sopenharmony_ci if (!pi->viid_mirror) 156862306a36Sopenharmony_ci goto out_unlock; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (pi->vi_mirror_count > 1) { 157162306a36Sopenharmony_ci pi->vi_mirror_count--; 157262306a36Sopenharmony_ci goto out_unlock; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci cxgb4_port_mirror_stop(dev); 157662306a36Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci pi->vi_mirror_count = 0; 157962306a36Sopenharmony_ci t4_free_vi(adap, adap->mbox, adap->pf, 0, pi->viid_mirror); 158062306a36Sopenharmony_ci pi->viid_mirror = 0; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ciout_unlock: 158362306a36Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci/* 158762306a36Sopenharmony_ci * upper-layer driver support 158862306a36Sopenharmony_ci */ 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci/* 159162306a36Sopenharmony_ci * Allocate an active-open TID and set it to the supplied value. 159262306a36Sopenharmony_ci */ 159362306a36Sopenharmony_ciint cxgb4_alloc_atid(struct tid_info *t, void *data) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci int atid = -1; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci spin_lock_bh(&t->atid_lock); 159862306a36Sopenharmony_ci if (t->afree) { 159962306a36Sopenharmony_ci union aopen_entry *p = t->afree; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci atid = (p - t->atid_tab) + t->atid_base; 160262306a36Sopenharmony_ci t->afree = p->next; 160362306a36Sopenharmony_ci p->data = data; 160462306a36Sopenharmony_ci t->atids_in_use++; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci spin_unlock_bh(&t->atid_lock); 160762306a36Sopenharmony_ci return atid; 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_atid); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci/* 161262306a36Sopenharmony_ci * Release an active-open TID. 161362306a36Sopenharmony_ci */ 161462306a36Sopenharmony_civoid cxgb4_free_atid(struct tid_info *t, unsigned int atid) 161562306a36Sopenharmony_ci{ 161662306a36Sopenharmony_ci union aopen_entry *p = &t->atid_tab[atid - t->atid_base]; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci spin_lock_bh(&t->atid_lock); 161962306a36Sopenharmony_ci p->next = t->afree; 162062306a36Sopenharmony_ci t->afree = p; 162162306a36Sopenharmony_ci t->atids_in_use--; 162262306a36Sopenharmony_ci spin_unlock_bh(&t->atid_lock); 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_free_atid); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci/* 162762306a36Sopenharmony_ci * Allocate a server TID and set it to the supplied value. 162862306a36Sopenharmony_ci */ 162962306a36Sopenharmony_ciint cxgb4_alloc_stid(struct tid_info *t, int family, void *data) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci int stid; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci spin_lock_bh(&t->stid_lock); 163462306a36Sopenharmony_ci if (family == PF_INET) { 163562306a36Sopenharmony_ci stid = find_first_zero_bit(t->stid_bmap, t->nstids); 163662306a36Sopenharmony_ci if (stid < t->nstids) 163762306a36Sopenharmony_ci __set_bit(stid, t->stid_bmap); 163862306a36Sopenharmony_ci else 163962306a36Sopenharmony_ci stid = -1; 164062306a36Sopenharmony_ci } else { 164162306a36Sopenharmony_ci stid = bitmap_find_free_region(t->stid_bmap, t->nstids, 1); 164262306a36Sopenharmony_ci if (stid < 0) 164362306a36Sopenharmony_ci stid = -1; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci if (stid >= 0) { 164662306a36Sopenharmony_ci t->stid_tab[stid].data = data; 164762306a36Sopenharmony_ci stid += t->stid_base; 164862306a36Sopenharmony_ci /* IPv6 requires max of 520 bits or 16 cells in TCAM 164962306a36Sopenharmony_ci * This is equivalent to 4 TIDs. With CLIP enabled it 165062306a36Sopenharmony_ci * needs 2 TIDs. 165162306a36Sopenharmony_ci */ 165262306a36Sopenharmony_ci if (family == PF_INET6) { 165362306a36Sopenharmony_ci t->stids_in_use += 2; 165462306a36Sopenharmony_ci t->v6_stids_in_use += 2; 165562306a36Sopenharmony_ci } else { 165662306a36Sopenharmony_ci t->stids_in_use++; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 166062306a36Sopenharmony_ci return stid; 166162306a36Sopenharmony_ci} 166262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_stid); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci/* Allocate a server filter TID and set it to the supplied value. 166562306a36Sopenharmony_ci */ 166662306a36Sopenharmony_ciint cxgb4_alloc_sftid(struct tid_info *t, int family, void *data) 166762306a36Sopenharmony_ci{ 166862306a36Sopenharmony_ci int stid; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci spin_lock_bh(&t->stid_lock); 167162306a36Sopenharmony_ci if (family == PF_INET) { 167262306a36Sopenharmony_ci stid = find_next_zero_bit(t->stid_bmap, 167362306a36Sopenharmony_ci t->nstids + t->nsftids, t->nstids); 167462306a36Sopenharmony_ci if (stid < (t->nstids + t->nsftids)) 167562306a36Sopenharmony_ci __set_bit(stid, t->stid_bmap); 167662306a36Sopenharmony_ci else 167762306a36Sopenharmony_ci stid = -1; 167862306a36Sopenharmony_ci } else { 167962306a36Sopenharmony_ci stid = -1; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci if (stid >= 0) { 168262306a36Sopenharmony_ci t->stid_tab[stid].data = data; 168362306a36Sopenharmony_ci stid -= t->nstids; 168462306a36Sopenharmony_ci stid += t->sftid_base; 168562306a36Sopenharmony_ci t->sftids_in_use++; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 168862306a36Sopenharmony_ci return stid; 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_alloc_sftid); 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci/* Release a server TID. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_civoid cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci /* Is it a server filter TID? */ 169762306a36Sopenharmony_ci if (t->nsftids && (stid >= t->sftid_base)) { 169862306a36Sopenharmony_ci stid -= t->sftid_base; 169962306a36Sopenharmony_ci stid += t->nstids; 170062306a36Sopenharmony_ci } else { 170162306a36Sopenharmony_ci stid -= t->stid_base; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci spin_lock_bh(&t->stid_lock); 170562306a36Sopenharmony_ci if (family == PF_INET) 170662306a36Sopenharmony_ci __clear_bit(stid, t->stid_bmap); 170762306a36Sopenharmony_ci else 170862306a36Sopenharmony_ci bitmap_release_region(t->stid_bmap, stid, 1); 170962306a36Sopenharmony_ci t->stid_tab[stid].data = NULL; 171062306a36Sopenharmony_ci if (stid < t->nstids) { 171162306a36Sopenharmony_ci if (family == PF_INET6) { 171262306a36Sopenharmony_ci t->stids_in_use -= 2; 171362306a36Sopenharmony_ci t->v6_stids_in_use -= 2; 171462306a36Sopenharmony_ci } else { 171562306a36Sopenharmony_ci t->stids_in_use--; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci } else { 171862306a36Sopenharmony_ci t->sftids_in_use--; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci spin_unlock_bh(&t->stid_lock); 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_free_stid); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci/* 172662306a36Sopenharmony_ci * Populate a TID_RELEASE WR. Caller must properly size the skb. 172762306a36Sopenharmony_ci */ 172862306a36Sopenharmony_cistatic void mk_tid_release(struct sk_buff *skb, unsigned int chan, 172962306a36Sopenharmony_ci unsigned int tid) 173062306a36Sopenharmony_ci{ 173162306a36Sopenharmony_ci struct cpl_tid_release *req; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); 173462306a36Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 173562306a36Sopenharmony_ci INIT_TP_WR(req, tid); 173662306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci/* 174062306a36Sopenharmony_ci * Queue a TID release request and if necessary schedule a work queue to 174162306a36Sopenharmony_ci * process it. 174262306a36Sopenharmony_ci */ 174362306a36Sopenharmony_cistatic void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, 174462306a36Sopenharmony_ci unsigned int tid) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci struct adapter *adap = container_of(t, struct adapter, tids); 174762306a36Sopenharmony_ci void **p = &t->tid_tab[tid - t->tid_base]; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci spin_lock_bh(&adap->tid_release_lock); 175062306a36Sopenharmony_ci *p = adap->tid_release_head; 175162306a36Sopenharmony_ci /* Low 2 bits encode the Tx channel number */ 175262306a36Sopenharmony_ci adap->tid_release_head = (void **)((uintptr_t)p | chan); 175362306a36Sopenharmony_ci if (!adap->tid_release_task_busy) { 175462306a36Sopenharmony_ci adap->tid_release_task_busy = true; 175562306a36Sopenharmony_ci queue_work(adap->workq, &adap->tid_release_task); 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci spin_unlock_bh(&adap->tid_release_lock); 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci/* 176162306a36Sopenharmony_ci * Process the list of pending TID release requests. 176262306a36Sopenharmony_ci */ 176362306a36Sopenharmony_cistatic void process_tid_release_list(struct work_struct *work) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci struct sk_buff *skb; 176662306a36Sopenharmony_ci struct adapter *adap; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci adap = container_of(work, struct adapter, tid_release_task); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci spin_lock_bh(&adap->tid_release_lock); 177162306a36Sopenharmony_ci while (adap->tid_release_head) { 177262306a36Sopenharmony_ci void **p = adap->tid_release_head; 177362306a36Sopenharmony_ci unsigned int chan = (uintptr_t)p & 3; 177462306a36Sopenharmony_ci p = (void *)p - chan; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci adap->tid_release_head = *p; 177762306a36Sopenharmony_ci *p = NULL; 177862306a36Sopenharmony_ci spin_unlock_bh(&adap->tid_release_lock); 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci while (!(skb = alloc_skb(sizeof(struct cpl_tid_release), 178162306a36Sopenharmony_ci GFP_KERNEL))) 178262306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci mk_tid_release(skb, chan, p - adap->tids.tid_tab); 178562306a36Sopenharmony_ci t4_ofld_send(adap, skb); 178662306a36Sopenharmony_ci spin_lock_bh(&adap->tid_release_lock); 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci adap->tid_release_task_busy = false; 178962306a36Sopenharmony_ci spin_unlock_bh(&adap->tid_release_lock); 179062306a36Sopenharmony_ci} 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci/* 179362306a36Sopenharmony_ci * Release a TID and inform HW. If we are unable to allocate the release 179462306a36Sopenharmony_ci * message we defer to a work queue. 179562306a36Sopenharmony_ci */ 179662306a36Sopenharmony_civoid cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid, 179762306a36Sopenharmony_ci unsigned short family) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci struct adapter *adap = container_of(t, struct adapter, tids); 180062306a36Sopenharmony_ci struct sk_buff *skb; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci WARN_ON(tid_out_of_range(&adap->tids, tid)); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (t->tid_tab[tid - adap->tids.tid_base]) { 180562306a36Sopenharmony_ci t->tid_tab[tid - adap->tids.tid_base] = NULL; 180662306a36Sopenharmony_ci atomic_dec(&t->conns_in_use); 180762306a36Sopenharmony_ci if (t->hash_base && (tid >= t->hash_base)) { 180862306a36Sopenharmony_ci if (family == AF_INET6) 180962306a36Sopenharmony_ci atomic_sub(2, &t->hash_tids_in_use); 181062306a36Sopenharmony_ci else 181162306a36Sopenharmony_ci atomic_dec(&t->hash_tids_in_use); 181262306a36Sopenharmony_ci } else { 181362306a36Sopenharmony_ci if (family == AF_INET6) 181462306a36Sopenharmony_ci atomic_sub(2, &t->tids_in_use); 181562306a36Sopenharmony_ci else 181662306a36Sopenharmony_ci atomic_dec(&t->tids_in_use); 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); 182162306a36Sopenharmony_ci if (likely(skb)) { 182262306a36Sopenharmony_ci mk_tid_release(skb, chan, tid); 182362306a36Sopenharmony_ci t4_ofld_send(adap, skb); 182462306a36Sopenharmony_ci } else 182562306a36Sopenharmony_ci cxgb4_queue_tid_release(t, chan, tid); 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_tid); 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci/* 183062306a36Sopenharmony_ci * Allocate and initialize the TID tables. Returns 0 on success. 183162306a36Sopenharmony_ci */ 183262306a36Sopenharmony_cistatic int tid_init(struct tid_info *t) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci struct adapter *adap = container_of(t, struct adapter, tids); 183562306a36Sopenharmony_ci unsigned int max_ftids = t->nftids + t->nsftids; 183662306a36Sopenharmony_ci unsigned int natids = t->natids; 183762306a36Sopenharmony_ci unsigned int hpftid_bmap_size; 183862306a36Sopenharmony_ci unsigned int eotid_bmap_size; 183962306a36Sopenharmony_ci unsigned int stid_bmap_size; 184062306a36Sopenharmony_ci unsigned int ftid_bmap_size; 184162306a36Sopenharmony_ci size_t size; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids); 184462306a36Sopenharmony_ci ftid_bmap_size = BITS_TO_LONGS(t->nftids); 184562306a36Sopenharmony_ci hpftid_bmap_size = BITS_TO_LONGS(t->nhpftids); 184662306a36Sopenharmony_ci eotid_bmap_size = BITS_TO_LONGS(t->neotids); 184762306a36Sopenharmony_ci size = t->ntids * sizeof(*t->tid_tab) + 184862306a36Sopenharmony_ci natids * sizeof(*t->atid_tab) + 184962306a36Sopenharmony_ci t->nstids * sizeof(*t->stid_tab) + 185062306a36Sopenharmony_ci t->nsftids * sizeof(*t->stid_tab) + 185162306a36Sopenharmony_ci stid_bmap_size * sizeof(long) + 185262306a36Sopenharmony_ci t->nhpftids * sizeof(*t->hpftid_tab) + 185362306a36Sopenharmony_ci hpftid_bmap_size * sizeof(long) + 185462306a36Sopenharmony_ci max_ftids * sizeof(*t->ftid_tab) + 185562306a36Sopenharmony_ci ftid_bmap_size * sizeof(long) + 185662306a36Sopenharmony_ci t->neotids * sizeof(*t->eotid_tab) + 185762306a36Sopenharmony_ci eotid_bmap_size * sizeof(long); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci t->tid_tab = kvzalloc(size, GFP_KERNEL); 186062306a36Sopenharmony_ci if (!t->tid_tab) 186162306a36Sopenharmony_ci return -ENOMEM; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; 186462306a36Sopenharmony_ci t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; 186562306a36Sopenharmony_ci t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids]; 186662306a36Sopenharmony_ci t->hpftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size]; 186762306a36Sopenharmony_ci t->hpftid_bmap = (unsigned long *)&t->hpftid_tab[t->nhpftids]; 186862306a36Sopenharmony_ci t->ftid_tab = (struct filter_entry *)&t->hpftid_bmap[hpftid_bmap_size]; 186962306a36Sopenharmony_ci t->ftid_bmap = (unsigned long *)&t->ftid_tab[max_ftids]; 187062306a36Sopenharmony_ci t->eotid_tab = (struct eotid_entry *)&t->ftid_bmap[ftid_bmap_size]; 187162306a36Sopenharmony_ci t->eotid_bmap = (unsigned long *)&t->eotid_tab[t->neotids]; 187262306a36Sopenharmony_ci spin_lock_init(&t->stid_lock); 187362306a36Sopenharmony_ci spin_lock_init(&t->atid_lock); 187462306a36Sopenharmony_ci spin_lock_init(&t->ftid_lock); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci t->stids_in_use = 0; 187762306a36Sopenharmony_ci t->v6_stids_in_use = 0; 187862306a36Sopenharmony_ci t->sftids_in_use = 0; 187962306a36Sopenharmony_ci t->afree = NULL; 188062306a36Sopenharmony_ci t->atids_in_use = 0; 188162306a36Sopenharmony_ci atomic_set(&t->tids_in_use, 0); 188262306a36Sopenharmony_ci atomic_set(&t->conns_in_use, 0); 188362306a36Sopenharmony_ci atomic_set(&t->hash_tids_in_use, 0); 188462306a36Sopenharmony_ci atomic_set(&t->eotids_in_use, 0); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci /* Setup the free list for atid_tab and clear the stid bitmap. */ 188762306a36Sopenharmony_ci if (natids) { 188862306a36Sopenharmony_ci while (--natids) 188962306a36Sopenharmony_ci t->atid_tab[natids - 1].next = &t->atid_tab[natids]; 189062306a36Sopenharmony_ci t->afree = t->atid_tab; 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (is_offload(adap)) { 189462306a36Sopenharmony_ci bitmap_zero(t->stid_bmap, t->nstids + t->nsftids); 189562306a36Sopenharmony_ci /* Reserve stid 0 for T4/T5 adapters */ 189662306a36Sopenharmony_ci if (!t->stid_base && 189762306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 189862306a36Sopenharmony_ci __set_bit(0, t->stid_bmap); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (t->neotids) 190162306a36Sopenharmony_ci bitmap_zero(t->eotid_bmap, t->neotids); 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci if (t->nhpftids) 190562306a36Sopenharmony_ci bitmap_zero(t->hpftid_bmap, t->nhpftids); 190662306a36Sopenharmony_ci bitmap_zero(t->ftid_bmap, t->nftids); 190762306a36Sopenharmony_ci return 0; 190862306a36Sopenharmony_ci} 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci/** 191162306a36Sopenharmony_ci * cxgb4_create_server - create an IP server 191262306a36Sopenharmony_ci * @dev: the device 191362306a36Sopenharmony_ci * @stid: the server TID 191462306a36Sopenharmony_ci * @sip: local IP address to bind server to 191562306a36Sopenharmony_ci * @sport: the server's TCP port 191662306a36Sopenharmony_ci * @vlan: the VLAN header information 191762306a36Sopenharmony_ci * @queue: queue to direct messages from this server to 191862306a36Sopenharmony_ci * 191962306a36Sopenharmony_ci * Create an IP server for the given port and address. 192062306a36Sopenharmony_ci * Returns <0 on error and one of the %NET_XMIT_* values on success. 192162306a36Sopenharmony_ci */ 192262306a36Sopenharmony_ciint cxgb4_create_server(const struct net_device *dev, unsigned int stid, 192362306a36Sopenharmony_ci __be32 sip, __be16 sport, __be16 vlan, 192462306a36Sopenharmony_ci unsigned int queue) 192562306a36Sopenharmony_ci{ 192662306a36Sopenharmony_ci unsigned int chan; 192762306a36Sopenharmony_ci struct sk_buff *skb; 192862306a36Sopenharmony_ci struct adapter *adap; 192962306a36Sopenharmony_ci struct cpl_pass_open_req *req; 193062306a36Sopenharmony_ci int ret; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_KERNEL); 193362306a36Sopenharmony_ci if (!skb) 193462306a36Sopenharmony_ci return -ENOMEM; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci adap = netdev2adap(dev); 193762306a36Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 193862306a36Sopenharmony_ci INIT_TP_WR(req, 0); 193962306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); 194062306a36Sopenharmony_ci req->local_port = sport; 194162306a36Sopenharmony_ci req->peer_port = htons(0); 194262306a36Sopenharmony_ci req->local_ip = sip; 194362306a36Sopenharmony_ci req->peer_ip = htonl(0); 194462306a36Sopenharmony_ci chan = rxq_to_chan(&adap->sge, queue); 194562306a36Sopenharmony_ci req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); 194662306a36Sopenharmony_ci req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | 194762306a36Sopenharmony_ci SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); 194862306a36Sopenharmony_ci ret = t4_mgmt_tx(adap, skb); 194962306a36Sopenharmony_ci return net_xmit_eval(ret); 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server); 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci/* cxgb4_create_server6 - create an IPv6 server 195462306a36Sopenharmony_ci * @dev: the device 195562306a36Sopenharmony_ci * @stid: the server TID 195662306a36Sopenharmony_ci * @sip: local IPv6 address to bind server to 195762306a36Sopenharmony_ci * @sport: the server's TCP port 195862306a36Sopenharmony_ci * @queue: queue to direct messages from this server to 195962306a36Sopenharmony_ci * 196062306a36Sopenharmony_ci * Create an IPv6 server for the given port and address. 196162306a36Sopenharmony_ci * Returns <0 on error and one of the %NET_XMIT_* values on success. 196262306a36Sopenharmony_ci */ 196362306a36Sopenharmony_ciint cxgb4_create_server6(const struct net_device *dev, unsigned int stid, 196462306a36Sopenharmony_ci const struct in6_addr *sip, __be16 sport, 196562306a36Sopenharmony_ci unsigned int queue) 196662306a36Sopenharmony_ci{ 196762306a36Sopenharmony_ci unsigned int chan; 196862306a36Sopenharmony_ci struct sk_buff *skb; 196962306a36Sopenharmony_ci struct adapter *adap; 197062306a36Sopenharmony_ci struct cpl_pass_open_req6 *req; 197162306a36Sopenharmony_ci int ret; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_KERNEL); 197462306a36Sopenharmony_ci if (!skb) 197562306a36Sopenharmony_ci return -ENOMEM; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci adap = netdev2adap(dev); 197862306a36Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 197962306a36Sopenharmony_ci INIT_TP_WR(req, 0); 198062306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ6, stid)); 198162306a36Sopenharmony_ci req->local_port = sport; 198262306a36Sopenharmony_ci req->peer_port = htons(0); 198362306a36Sopenharmony_ci req->local_ip_hi = *(__be64 *)(sip->s6_addr); 198462306a36Sopenharmony_ci req->local_ip_lo = *(__be64 *)(sip->s6_addr + 8); 198562306a36Sopenharmony_ci req->peer_ip_hi = cpu_to_be64(0); 198662306a36Sopenharmony_ci req->peer_ip_lo = cpu_to_be64(0); 198762306a36Sopenharmony_ci chan = rxq_to_chan(&adap->sge, queue); 198862306a36Sopenharmony_ci req->opt0 = cpu_to_be64(TX_CHAN_V(chan)); 198962306a36Sopenharmony_ci req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) | 199062306a36Sopenharmony_ci SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue)); 199162306a36Sopenharmony_ci ret = t4_mgmt_tx(adap, skb); 199262306a36Sopenharmony_ci return net_xmit_eval(ret); 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server6); 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ciint cxgb4_remove_server(const struct net_device *dev, unsigned int stid, 199762306a36Sopenharmony_ci unsigned int queue, bool ipv6) 199862306a36Sopenharmony_ci{ 199962306a36Sopenharmony_ci struct sk_buff *skb; 200062306a36Sopenharmony_ci struct adapter *adap; 200162306a36Sopenharmony_ci struct cpl_close_listsvr_req *req; 200262306a36Sopenharmony_ci int ret; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci adap = netdev2adap(dev); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci skb = alloc_skb(sizeof(*req), GFP_KERNEL); 200762306a36Sopenharmony_ci if (!skb) 200862306a36Sopenharmony_ci return -ENOMEM; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci req = __skb_put(skb, sizeof(*req)); 201162306a36Sopenharmony_ci INIT_TP_WR(req, 0); 201262306a36Sopenharmony_ci OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid)); 201362306a36Sopenharmony_ci req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) : 201462306a36Sopenharmony_ci LISTSVR_IPV6_V(0)) | QUEUENO_V(queue)); 201562306a36Sopenharmony_ci ret = t4_mgmt_tx(adap, skb); 201662306a36Sopenharmony_ci return net_xmit_eval(ret); 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_server); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci/** 202162306a36Sopenharmony_ci * cxgb4_best_mtu - find the entry in the MTU table closest to an MTU 202262306a36Sopenharmony_ci * @mtus: the HW MTU table 202362306a36Sopenharmony_ci * @mtu: the target MTU 202462306a36Sopenharmony_ci * @idx: index of selected entry in the MTU table 202562306a36Sopenharmony_ci * 202662306a36Sopenharmony_ci * Returns the index and the value in the HW MTU table that is closest to 202762306a36Sopenharmony_ci * but does not exceed @mtu, unless @mtu is smaller than any value in the 202862306a36Sopenharmony_ci * table, in which case that smallest available value is selected. 202962306a36Sopenharmony_ci */ 203062306a36Sopenharmony_ciunsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, 203162306a36Sopenharmony_ci unsigned int *idx) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci unsigned int i = 0; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci while (i < NMTUS - 1 && mtus[i + 1] <= mtu) 203662306a36Sopenharmony_ci ++i; 203762306a36Sopenharmony_ci if (idx) 203862306a36Sopenharmony_ci *idx = i; 203962306a36Sopenharmony_ci return mtus[i]; 204062306a36Sopenharmony_ci} 204162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_best_mtu); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci/** 204462306a36Sopenharmony_ci * cxgb4_best_aligned_mtu - find best MTU, [hopefully] data size aligned 204562306a36Sopenharmony_ci * @mtus: the HW MTU table 204662306a36Sopenharmony_ci * @header_size: Header Size 204762306a36Sopenharmony_ci * @data_size_max: maximum Data Segment Size 204862306a36Sopenharmony_ci * @data_size_align: desired Data Segment Size Alignment (2^N) 204962306a36Sopenharmony_ci * @mtu_idxp: HW MTU Table Index return value pointer (possibly NULL) 205062306a36Sopenharmony_ci * 205162306a36Sopenharmony_ci * Similar to cxgb4_best_mtu() but instead of searching the Hardware 205262306a36Sopenharmony_ci * MTU Table based solely on a Maximum MTU parameter, we break that 205362306a36Sopenharmony_ci * parameter up into a Header Size and Maximum Data Segment Size, and 205462306a36Sopenharmony_ci * provide a desired Data Segment Size Alignment. If we find an MTU in 205562306a36Sopenharmony_ci * the Hardware MTU Table which will result in a Data Segment Size with 205662306a36Sopenharmony_ci * the requested alignment _and_ that MTU isn't "too far" from the 205762306a36Sopenharmony_ci * closest MTU, then we'll return that rather than the closest MTU. 205862306a36Sopenharmony_ci */ 205962306a36Sopenharmony_ciunsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus, 206062306a36Sopenharmony_ci unsigned short header_size, 206162306a36Sopenharmony_ci unsigned short data_size_max, 206262306a36Sopenharmony_ci unsigned short data_size_align, 206362306a36Sopenharmony_ci unsigned int *mtu_idxp) 206462306a36Sopenharmony_ci{ 206562306a36Sopenharmony_ci unsigned short max_mtu = header_size + data_size_max; 206662306a36Sopenharmony_ci unsigned short data_size_align_mask = data_size_align - 1; 206762306a36Sopenharmony_ci int mtu_idx, aligned_mtu_idx; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci /* Scan the MTU Table till we find an MTU which is larger than our 207062306a36Sopenharmony_ci * Maximum MTU or we reach the end of the table. Along the way, 207162306a36Sopenharmony_ci * record the last MTU found, if any, which will result in a Data 207262306a36Sopenharmony_ci * Segment Length matching the requested alignment. 207362306a36Sopenharmony_ci */ 207462306a36Sopenharmony_ci for (mtu_idx = 0, aligned_mtu_idx = -1; mtu_idx < NMTUS; mtu_idx++) { 207562306a36Sopenharmony_ci unsigned short data_size = mtus[mtu_idx] - header_size; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci /* If this MTU minus the Header Size would result in a 207862306a36Sopenharmony_ci * Data Segment Size of the desired alignment, remember it. 207962306a36Sopenharmony_ci */ 208062306a36Sopenharmony_ci if ((data_size & data_size_align_mask) == 0) 208162306a36Sopenharmony_ci aligned_mtu_idx = mtu_idx; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci /* If we're not at the end of the Hardware MTU Table and the 208462306a36Sopenharmony_ci * next element is larger than our Maximum MTU, drop out of 208562306a36Sopenharmony_ci * the loop. 208662306a36Sopenharmony_ci */ 208762306a36Sopenharmony_ci if (mtu_idx+1 < NMTUS && mtus[mtu_idx+1] > max_mtu) 208862306a36Sopenharmony_ci break; 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* If we fell out of the loop because we ran to the end of the table, 209262306a36Sopenharmony_ci * then we just have to use the last [largest] entry. 209362306a36Sopenharmony_ci */ 209462306a36Sopenharmony_ci if (mtu_idx == NMTUS) 209562306a36Sopenharmony_ci mtu_idx--; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci /* If we found an MTU which resulted in the requested Data Segment 209862306a36Sopenharmony_ci * Length alignment and that's "not far" from the largest MTU which is 209962306a36Sopenharmony_ci * less than or equal to the maximum MTU, then use that. 210062306a36Sopenharmony_ci */ 210162306a36Sopenharmony_ci if (aligned_mtu_idx >= 0 && 210262306a36Sopenharmony_ci mtu_idx - aligned_mtu_idx <= 1) 210362306a36Sopenharmony_ci mtu_idx = aligned_mtu_idx; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci /* If the caller has passed in an MTU Index pointer, pass the 210662306a36Sopenharmony_ci * MTU Index back. Return the MTU value. 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_ci if (mtu_idxp) 210962306a36Sopenharmony_ci *mtu_idxp = mtu_idx; 211062306a36Sopenharmony_ci return mtus[mtu_idx]; 211162306a36Sopenharmony_ci} 211262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_best_aligned_mtu); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci/** 211562306a36Sopenharmony_ci * cxgb4_port_chan - get the HW channel of a port 211662306a36Sopenharmony_ci * @dev: the net device for the port 211762306a36Sopenharmony_ci * 211862306a36Sopenharmony_ci * Return the HW Tx channel of the given port. 211962306a36Sopenharmony_ci */ 212062306a36Sopenharmony_ciunsigned int cxgb4_port_chan(const struct net_device *dev) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci return netdev2pinfo(dev)->tx_chan; 212362306a36Sopenharmony_ci} 212462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_chan); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci/** 212762306a36Sopenharmony_ci * cxgb4_port_e2cchan - get the HW c-channel of a port 212862306a36Sopenharmony_ci * @dev: the net device for the port 212962306a36Sopenharmony_ci * 213062306a36Sopenharmony_ci * Return the HW RX c-channel of the given port. 213162306a36Sopenharmony_ci */ 213262306a36Sopenharmony_ciunsigned int cxgb4_port_e2cchan(const struct net_device *dev) 213362306a36Sopenharmony_ci{ 213462306a36Sopenharmony_ci return netdev2pinfo(dev)->rx_cchan; 213562306a36Sopenharmony_ci} 213662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_e2cchan); 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ciunsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo) 213962306a36Sopenharmony_ci{ 214062306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 214162306a36Sopenharmony_ci u32 v1, v2, lp_count, hp_count; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); 214462306a36Sopenharmony_ci v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); 214562306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 214662306a36Sopenharmony_ci lp_count = LP_COUNT_G(v1); 214762306a36Sopenharmony_ci hp_count = HP_COUNT_G(v1); 214862306a36Sopenharmony_ci } else { 214962306a36Sopenharmony_ci lp_count = LP_COUNT_T5_G(v1); 215062306a36Sopenharmony_ci hp_count = HP_COUNT_T5_G(v2); 215162306a36Sopenharmony_ci } 215262306a36Sopenharmony_ci return lpfifo ? lp_count : hp_count; 215362306a36Sopenharmony_ci} 215462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_dbfifo_count); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci/** 215762306a36Sopenharmony_ci * cxgb4_port_viid - get the VI id of a port 215862306a36Sopenharmony_ci * @dev: the net device for the port 215962306a36Sopenharmony_ci * 216062306a36Sopenharmony_ci * Return the VI id of the given port. 216162306a36Sopenharmony_ci */ 216262306a36Sopenharmony_ciunsigned int cxgb4_port_viid(const struct net_device *dev) 216362306a36Sopenharmony_ci{ 216462306a36Sopenharmony_ci return netdev2pinfo(dev)->viid; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_viid); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci/** 216962306a36Sopenharmony_ci * cxgb4_port_idx - get the index of a port 217062306a36Sopenharmony_ci * @dev: the net device for the port 217162306a36Sopenharmony_ci * 217262306a36Sopenharmony_ci * Return the index of the given port. 217362306a36Sopenharmony_ci */ 217462306a36Sopenharmony_ciunsigned int cxgb4_port_idx(const struct net_device *dev) 217562306a36Sopenharmony_ci{ 217662306a36Sopenharmony_ci return netdev2pinfo(dev)->port_id; 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_port_idx); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_civoid cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, 218162306a36Sopenharmony_ci struct tp_tcp_stats *v6) 218262306a36Sopenharmony_ci{ 218362306a36Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci spin_lock(&adap->stats_lock); 218662306a36Sopenharmony_ci t4_tp_get_tcp_stats(adap, v4, v6, false); 218762306a36Sopenharmony_ci spin_unlock(&adap->stats_lock); 218862306a36Sopenharmony_ci} 218962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_get_tcp_stats); 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_civoid cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, 219262306a36Sopenharmony_ci const unsigned int *pgsz_order) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask); 219762306a36Sopenharmony_ci t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) | 219862306a36Sopenharmony_ci HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) | 219962306a36Sopenharmony_ci HPZ3_V(pgsz_order[3])); 220062306a36Sopenharmony_ci} 220162306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_iscsi_init); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ciint cxgb4_flush_eq_cache(struct net_device *dev) 220462306a36Sopenharmony_ci{ 220562306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci return t4_sge_ctxt_flush(adap, adap->mbox, CTXT_EGRESS); 220862306a36Sopenharmony_ci} 220962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_flush_eq_cache); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx) 221262306a36Sopenharmony_ci{ 221362306a36Sopenharmony_ci u32 addr = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A) + 24 * qid + 8; 221462306a36Sopenharmony_ci __be64 indices; 221562306a36Sopenharmony_ci int ret; 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci spin_lock(&adap->win0_lock); 221862306a36Sopenharmony_ci ret = t4_memory_rw(adap, 0, MEM_EDC0, addr, 221962306a36Sopenharmony_ci sizeof(indices), (__be32 *)&indices, 222062306a36Sopenharmony_ci T4_MEMORY_READ); 222162306a36Sopenharmony_ci spin_unlock(&adap->win0_lock); 222262306a36Sopenharmony_ci if (!ret) { 222362306a36Sopenharmony_ci *cidx = (be64_to_cpu(indices) >> 25) & 0xffff; 222462306a36Sopenharmony_ci *pidx = (be64_to_cpu(indices) >> 9) & 0xffff; 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci return ret; 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ciint cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, 223062306a36Sopenharmony_ci u16 size) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 223362306a36Sopenharmony_ci u16 hw_pidx, hw_cidx; 223462306a36Sopenharmony_ci int ret; 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci ret = read_eq_indices(adap, qid, &hw_pidx, &hw_cidx); 223762306a36Sopenharmony_ci if (ret) 223862306a36Sopenharmony_ci goto out; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci if (pidx != hw_pidx) { 224162306a36Sopenharmony_ci u16 delta; 224262306a36Sopenharmony_ci u32 val; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci if (pidx >= hw_pidx) 224562306a36Sopenharmony_ci delta = pidx - hw_pidx; 224662306a36Sopenharmony_ci else 224762306a36Sopenharmony_ci delta = size - hw_pidx + pidx; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 225062306a36Sopenharmony_ci val = PIDX_V(delta); 225162306a36Sopenharmony_ci else 225262306a36Sopenharmony_ci val = PIDX_T5_V(delta); 225362306a36Sopenharmony_ci wmb(); 225462306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 225562306a36Sopenharmony_ci QID_V(qid) | val); 225662306a36Sopenharmony_ci } 225762306a36Sopenharmony_ciout: 225862306a36Sopenharmony_ci return ret; 225962306a36Sopenharmony_ci} 226062306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_sync_txq_pidx); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ciint cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte) 226362306a36Sopenharmony_ci{ 226462306a36Sopenharmony_ci u32 edc0_size, edc1_size, mc0_size, mc1_size, size; 226562306a36Sopenharmony_ci u32 edc0_end, edc1_end, mc0_end, mc1_end; 226662306a36Sopenharmony_ci u32 offset, memtype, memaddr; 226762306a36Sopenharmony_ci struct adapter *adap; 226862306a36Sopenharmony_ci u32 hma_size = 0; 226962306a36Sopenharmony_ci int ret; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci adap = netdev2adap(dev); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci offset = ((stag >> 8) * 32) + adap->vres.stag.start; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci /* Figure out where the offset lands in the Memory Type/Address scheme. 227662306a36Sopenharmony_ci * This code assumes that the memory is laid out starting at offset 0 227762306a36Sopenharmony_ci * with no breaks as: EDC0, EDC1, MC0, MC1. All cards have both EDC0 227862306a36Sopenharmony_ci * and EDC1. Some cards will have neither MC0 nor MC1, most cards have 227962306a36Sopenharmony_ci * MC0, and some have both MC0 and MC1. 228062306a36Sopenharmony_ci */ 228162306a36Sopenharmony_ci size = t4_read_reg(adap, MA_EDRAM0_BAR_A); 228262306a36Sopenharmony_ci edc0_size = EDRAM0_SIZE_G(size) << 20; 228362306a36Sopenharmony_ci size = t4_read_reg(adap, MA_EDRAM1_BAR_A); 228462306a36Sopenharmony_ci edc1_size = EDRAM1_SIZE_G(size) << 20; 228562306a36Sopenharmony_ci size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A); 228662306a36Sopenharmony_ci mc0_size = EXT_MEM0_SIZE_G(size) << 20; 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci if (t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A) & HMA_MUX_F) { 228962306a36Sopenharmony_ci size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A); 229062306a36Sopenharmony_ci hma_size = EXT_MEM1_SIZE_G(size) << 20; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci edc0_end = edc0_size; 229362306a36Sopenharmony_ci edc1_end = edc0_end + edc1_size; 229462306a36Sopenharmony_ci mc0_end = edc1_end + mc0_size; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci if (offset < edc0_end) { 229762306a36Sopenharmony_ci memtype = MEM_EDC0; 229862306a36Sopenharmony_ci memaddr = offset; 229962306a36Sopenharmony_ci } else if (offset < edc1_end) { 230062306a36Sopenharmony_ci memtype = MEM_EDC1; 230162306a36Sopenharmony_ci memaddr = offset - edc0_end; 230262306a36Sopenharmony_ci } else { 230362306a36Sopenharmony_ci if (hma_size && (offset < (edc1_end + hma_size))) { 230462306a36Sopenharmony_ci memtype = MEM_HMA; 230562306a36Sopenharmony_ci memaddr = offset - edc1_end; 230662306a36Sopenharmony_ci } else if (offset < mc0_end) { 230762306a36Sopenharmony_ci memtype = MEM_MC0; 230862306a36Sopenharmony_ci memaddr = offset - edc1_end; 230962306a36Sopenharmony_ci } else if (is_t5(adap->params.chip)) { 231062306a36Sopenharmony_ci size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A); 231162306a36Sopenharmony_ci mc1_size = EXT_MEM1_SIZE_G(size) << 20; 231262306a36Sopenharmony_ci mc1_end = mc0_end + mc1_size; 231362306a36Sopenharmony_ci if (offset < mc1_end) { 231462306a36Sopenharmony_ci memtype = MEM_MC1; 231562306a36Sopenharmony_ci memaddr = offset - mc0_end; 231662306a36Sopenharmony_ci } else { 231762306a36Sopenharmony_ci /* offset beyond the end of any memory */ 231862306a36Sopenharmony_ci goto err; 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci } else { 232162306a36Sopenharmony_ci /* T4/T6 only has a single memory channel */ 232262306a36Sopenharmony_ci goto err; 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci spin_lock(&adap->win0_lock); 232762306a36Sopenharmony_ci ret = t4_memory_rw(adap, 0, memtype, memaddr, 32, tpte, T4_MEMORY_READ); 232862306a36Sopenharmony_ci spin_unlock(&adap->win0_lock); 232962306a36Sopenharmony_ci return ret; 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_cierr: 233262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "stag %#x, offset %#x out of range\n", 233362306a36Sopenharmony_ci stag, offset); 233462306a36Sopenharmony_ci return -EINVAL; 233562306a36Sopenharmony_ci} 233662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_read_tpte); 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ciu64 cxgb4_read_sge_timestamp(struct net_device *dev) 233962306a36Sopenharmony_ci{ 234062306a36Sopenharmony_ci u32 hi, lo; 234162306a36Sopenharmony_ci struct adapter *adap; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci adap = netdev2adap(dev); 234462306a36Sopenharmony_ci lo = t4_read_reg(adap, SGE_TIMESTAMP_LO_A); 234562306a36Sopenharmony_ci hi = TSVAL_G(t4_read_reg(adap, SGE_TIMESTAMP_HI_A)); 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci return ((u64)hi << 32) | (u64)lo; 234862306a36Sopenharmony_ci} 234962306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_read_sge_timestamp); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ciint cxgb4_bar2_sge_qregs(struct net_device *dev, 235262306a36Sopenharmony_ci unsigned int qid, 235362306a36Sopenharmony_ci enum cxgb4_bar2_qtype qtype, 235462306a36Sopenharmony_ci int user, 235562306a36Sopenharmony_ci u64 *pbar2_qoffset, 235662306a36Sopenharmony_ci unsigned int *pbar2_qid) 235762306a36Sopenharmony_ci{ 235862306a36Sopenharmony_ci return t4_bar2_sge_qregs(netdev2adap(dev), 235962306a36Sopenharmony_ci qid, 236062306a36Sopenharmony_ci (qtype == CXGB4_BAR2_QTYPE_EGRESS 236162306a36Sopenharmony_ci ? T4_BAR2_QTYPE_EGRESS 236262306a36Sopenharmony_ci : T4_BAR2_QTYPE_INGRESS), 236362306a36Sopenharmony_ci user, 236462306a36Sopenharmony_ci pbar2_qoffset, 236562306a36Sopenharmony_ci pbar2_qid); 236662306a36Sopenharmony_ci} 236762306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_bar2_sge_qregs); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_cistatic struct pci_driver cxgb4_driver; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_cistatic void check_neigh_update(struct neighbour *neigh) 237262306a36Sopenharmony_ci{ 237362306a36Sopenharmony_ci const struct device *parent; 237462306a36Sopenharmony_ci const struct net_device *netdev = neigh->dev; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci if (is_vlan_dev(netdev)) 237762306a36Sopenharmony_ci netdev = vlan_dev_real_dev(netdev); 237862306a36Sopenharmony_ci parent = netdev->dev.parent; 237962306a36Sopenharmony_ci if (parent && parent->driver == &cxgb4_driver.driver) 238062306a36Sopenharmony_ci t4_l2t_update(dev_get_drvdata(parent), neigh); 238162306a36Sopenharmony_ci} 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_cistatic int netevent_cb(struct notifier_block *nb, unsigned long event, 238462306a36Sopenharmony_ci void *data) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci switch (event) { 238762306a36Sopenharmony_ci case NETEVENT_NEIGH_UPDATE: 238862306a36Sopenharmony_ci check_neigh_update(data); 238962306a36Sopenharmony_ci break; 239062306a36Sopenharmony_ci case NETEVENT_REDIRECT: 239162306a36Sopenharmony_ci default: 239262306a36Sopenharmony_ci break; 239362306a36Sopenharmony_ci } 239462306a36Sopenharmony_ci return 0; 239562306a36Sopenharmony_ci} 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_cistatic bool netevent_registered; 239862306a36Sopenharmony_cistatic struct notifier_block cxgb4_netevent_nb = { 239962306a36Sopenharmony_ci .notifier_call = netevent_cb 240062306a36Sopenharmony_ci}; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_cistatic void drain_db_fifo(struct adapter *adap, int usecs) 240362306a36Sopenharmony_ci{ 240462306a36Sopenharmony_ci u32 v1, v2, lp_count, hp_count; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci do { 240762306a36Sopenharmony_ci v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A); 240862306a36Sopenharmony_ci v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A); 240962306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 241062306a36Sopenharmony_ci lp_count = LP_COUNT_G(v1); 241162306a36Sopenharmony_ci hp_count = HP_COUNT_G(v1); 241262306a36Sopenharmony_ci } else { 241362306a36Sopenharmony_ci lp_count = LP_COUNT_T5_G(v1); 241462306a36Sopenharmony_ci hp_count = HP_COUNT_T5_G(v2); 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci if (lp_count == 0 && hp_count == 0) 241862306a36Sopenharmony_ci break; 241962306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 242062306a36Sopenharmony_ci schedule_timeout(usecs_to_jiffies(usecs)); 242162306a36Sopenharmony_ci } while (1); 242262306a36Sopenharmony_ci} 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_cistatic void disable_txq_db(struct sge_txq *q) 242562306a36Sopenharmony_ci{ 242662306a36Sopenharmony_ci unsigned long flags; 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci spin_lock_irqsave(&q->db_lock, flags); 242962306a36Sopenharmony_ci q->db_disabled = 1; 243062306a36Sopenharmony_ci spin_unlock_irqrestore(&q->db_lock, flags); 243162306a36Sopenharmony_ci} 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_cistatic void enable_txq_db(struct adapter *adap, struct sge_txq *q) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci spin_lock_irq(&q->db_lock); 243662306a36Sopenharmony_ci if (q->db_pidx_inc) { 243762306a36Sopenharmony_ci /* Make sure that all writes to the TX descriptors 243862306a36Sopenharmony_ci * are committed before we tell HW about them. 243962306a36Sopenharmony_ci */ 244062306a36Sopenharmony_ci wmb(); 244162306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 244262306a36Sopenharmony_ci QID_V(q->cntxt_id) | PIDX_V(q->db_pidx_inc)); 244362306a36Sopenharmony_ci q->db_pidx_inc = 0; 244462306a36Sopenharmony_ci } 244562306a36Sopenharmony_ci q->db_disabled = 0; 244662306a36Sopenharmony_ci spin_unlock_irq(&q->db_lock); 244762306a36Sopenharmony_ci} 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cistatic void disable_dbs(struct adapter *adap) 245062306a36Sopenharmony_ci{ 245162306a36Sopenharmony_ci int i; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci for_each_ethrxq(&adap->sge, i) 245462306a36Sopenharmony_ci disable_txq_db(&adap->sge.ethtxq[i].q); 245562306a36Sopenharmony_ci if (is_offload(adap)) { 245662306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info = 245762306a36Sopenharmony_ci adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci if (txq_info) { 246062306a36Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 246162306a36Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci disable_txq_db(&txq->q); 246462306a36Sopenharmony_ci } 246562306a36Sopenharmony_ci } 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci for_each_port(adap, i) 246862306a36Sopenharmony_ci disable_txq_db(&adap->sge.ctrlq[i].q); 246962306a36Sopenharmony_ci} 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_cistatic void enable_dbs(struct adapter *adap) 247262306a36Sopenharmony_ci{ 247362306a36Sopenharmony_ci int i; 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci for_each_ethrxq(&adap->sge, i) 247662306a36Sopenharmony_ci enable_txq_db(adap, &adap->sge.ethtxq[i].q); 247762306a36Sopenharmony_ci if (is_offload(adap)) { 247862306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info = 247962306a36Sopenharmony_ci adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci if (txq_info) { 248262306a36Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 248362306a36Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci enable_txq_db(adap, &txq->q); 248662306a36Sopenharmony_ci } 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci for_each_port(adap, i) 249062306a36Sopenharmony_ci enable_txq_db(adap, &adap->sge.ctrlq[i].q); 249162306a36Sopenharmony_ci} 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_cistatic void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd) 249462306a36Sopenharmony_ci{ 249562306a36Sopenharmony_ci enum cxgb4_uld type = CXGB4_ULD_RDMA; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci if (adap->uld && adap->uld[type].handle) 249862306a36Sopenharmony_ci adap->uld[type].control(adap->uld[type].handle, cmd); 249962306a36Sopenharmony_ci} 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_cistatic void process_db_full(struct work_struct *work) 250262306a36Sopenharmony_ci{ 250362306a36Sopenharmony_ci struct adapter *adap; 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci adap = container_of(work, struct adapter, db_full_task); 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 250862306a36Sopenharmony_ci enable_dbs(adap); 250962306a36Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); 251062306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 251162306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_INT_ENABLE3_A, 251262306a36Sopenharmony_ci DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 251362306a36Sopenharmony_ci DBFIFO_HP_INT_F | DBFIFO_LP_INT_F); 251462306a36Sopenharmony_ci else 251562306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_INT_ENABLE3_A, 251662306a36Sopenharmony_ci DBFIFO_LP_INT_F, DBFIFO_LP_INT_F); 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_cistatic void sync_txq_pidx(struct adapter *adap, struct sge_txq *q) 252062306a36Sopenharmony_ci{ 252162306a36Sopenharmony_ci u16 hw_pidx, hw_cidx; 252262306a36Sopenharmony_ci int ret; 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci spin_lock_irq(&q->db_lock); 252562306a36Sopenharmony_ci ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx); 252662306a36Sopenharmony_ci if (ret) 252762306a36Sopenharmony_ci goto out; 252862306a36Sopenharmony_ci if (q->db_pidx != hw_pidx) { 252962306a36Sopenharmony_ci u16 delta; 253062306a36Sopenharmony_ci u32 val; 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci if (q->db_pidx >= hw_pidx) 253362306a36Sopenharmony_ci delta = q->db_pidx - hw_pidx; 253462306a36Sopenharmony_ci else 253562306a36Sopenharmony_ci delta = q->size - hw_pidx + q->db_pidx; 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (is_t4(adap->params.chip)) 253862306a36Sopenharmony_ci val = PIDX_V(delta); 253962306a36Sopenharmony_ci else 254062306a36Sopenharmony_ci val = PIDX_T5_V(delta); 254162306a36Sopenharmony_ci wmb(); 254262306a36Sopenharmony_ci t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A), 254362306a36Sopenharmony_ci QID_V(q->cntxt_id) | val); 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ciout: 254662306a36Sopenharmony_ci q->db_disabled = 0; 254762306a36Sopenharmony_ci q->db_pidx_inc = 0; 254862306a36Sopenharmony_ci spin_unlock_irq(&q->db_lock); 254962306a36Sopenharmony_ci if (ret) 255062306a36Sopenharmony_ci CH_WARN(adap, "DB drop recovery failed.\n"); 255162306a36Sopenharmony_ci} 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_cistatic void recover_all_queues(struct adapter *adap) 255462306a36Sopenharmony_ci{ 255562306a36Sopenharmony_ci int i; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci for_each_ethrxq(&adap->sge, i) 255862306a36Sopenharmony_ci sync_txq_pidx(adap, &adap->sge.ethtxq[i].q); 255962306a36Sopenharmony_ci if (is_offload(adap)) { 256062306a36Sopenharmony_ci struct sge_uld_txq_info *txq_info = 256162306a36Sopenharmony_ci adap->sge.uld_txq_info[CXGB4_TX_OFLD]; 256262306a36Sopenharmony_ci if (txq_info) { 256362306a36Sopenharmony_ci for_each_ofldtxq(&adap->sge, i) { 256462306a36Sopenharmony_ci struct sge_uld_txq *txq = &txq_info->uldtxq[i]; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci sync_txq_pidx(adap, &txq->q); 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci } 257062306a36Sopenharmony_ci for_each_port(adap, i) 257162306a36Sopenharmony_ci sync_txq_pidx(adap, &adap->sge.ctrlq[i].q); 257262306a36Sopenharmony_ci} 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_cistatic void process_db_drop(struct work_struct *work) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci struct adapter *adap; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci adap = container_of(work, struct adapter, db_drop_task); 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 258162306a36Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 258262306a36Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP); 258362306a36Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 258462306a36Sopenharmony_ci recover_all_queues(adap); 258562306a36Sopenharmony_ci drain_db_fifo(adap, dbfifo_drain_delay); 258662306a36Sopenharmony_ci enable_dbs(adap); 258762306a36Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY); 258862306a36Sopenharmony_ci } else if (is_t5(adap->params.chip)) { 258962306a36Sopenharmony_ci u32 dropped_db = t4_read_reg(adap, 0x010ac); 259062306a36Sopenharmony_ci u16 qid = (dropped_db >> 15) & 0x1ffff; 259162306a36Sopenharmony_ci u16 pidx_inc = dropped_db & 0x1fff; 259262306a36Sopenharmony_ci u64 bar2_qoffset; 259362306a36Sopenharmony_ci unsigned int bar2_qid; 259462306a36Sopenharmony_ci int ret; 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci ret = t4_bar2_sge_qregs(adap, qid, T4_BAR2_QTYPE_EGRESS, 259762306a36Sopenharmony_ci 0, &bar2_qoffset, &bar2_qid); 259862306a36Sopenharmony_ci if (ret) 259962306a36Sopenharmony_ci dev_err(adap->pdev_dev, "doorbell drop recovery: " 260062306a36Sopenharmony_ci "qid=%d, pidx_inc=%d\n", qid, pidx_inc); 260162306a36Sopenharmony_ci else 260262306a36Sopenharmony_ci writel(PIDX_T5_V(pidx_inc) | QID_V(bar2_qid), 260362306a36Sopenharmony_ci adap->bar2 + bar2_qoffset + SGE_UDB_KDOORBELL); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci /* Re-enable BAR2 WC */ 260662306a36Sopenharmony_ci t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15); 260762306a36Sopenharmony_ci } 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) 261062306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0); 261162306a36Sopenharmony_ci} 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_civoid t4_db_full(struct adapter *adap) 261462306a36Sopenharmony_ci{ 261562306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 261662306a36Sopenharmony_ci disable_dbs(adap); 261762306a36Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); 261862306a36Sopenharmony_ci t4_set_reg_field(adap, SGE_INT_ENABLE3_A, 261962306a36Sopenharmony_ci DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 0); 262062306a36Sopenharmony_ci queue_work(adap->workq, &adap->db_full_task); 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_civoid t4_db_dropped(struct adapter *adap) 262562306a36Sopenharmony_ci{ 262662306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 262762306a36Sopenharmony_ci disable_dbs(adap); 262862306a36Sopenharmony_ci notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); 262962306a36Sopenharmony_ci } 263062306a36Sopenharmony_ci queue_work(adap->workq, &adap->db_drop_task); 263162306a36Sopenharmony_ci} 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_civoid t4_register_netevent_notifier(void) 263462306a36Sopenharmony_ci{ 263562306a36Sopenharmony_ci if (!netevent_registered) { 263662306a36Sopenharmony_ci register_netevent_notifier(&cxgb4_netevent_nb); 263762306a36Sopenharmony_ci netevent_registered = true; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci} 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_cistatic void detach_ulds(struct adapter *adap) 264262306a36Sopenharmony_ci{ 264362306a36Sopenharmony_ci unsigned int i; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci if (!is_uld(adap)) 264662306a36Sopenharmony_ci return; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci mutex_lock(&uld_mutex); 264962306a36Sopenharmony_ci list_del(&adap->list_node); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci for (i = 0; i < CXGB4_ULD_MAX; i++) 265262306a36Sopenharmony_ci if (adap->uld && adap->uld[i].handle) 265362306a36Sopenharmony_ci adap->uld[i].state_change(adap->uld[i].handle, 265462306a36Sopenharmony_ci CXGB4_STATE_DETACH); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci if (netevent_registered && list_empty(&adapter_list)) { 265762306a36Sopenharmony_ci unregister_netevent_notifier(&cxgb4_netevent_nb); 265862306a36Sopenharmony_ci netevent_registered = false; 265962306a36Sopenharmony_ci } 266062306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 266162306a36Sopenharmony_ci} 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_cistatic void notify_ulds(struct adapter *adap, enum cxgb4_state new_state) 266462306a36Sopenharmony_ci{ 266562306a36Sopenharmony_ci unsigned int i; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci mutex_lock(&uld_mutex); 266862306a36Sopenharmony_ci for (i = 0; i < CXGB4_ULD_MAX; i++) 266962306a36Sopenharmony_ci if (adap->uld && adap->uld[i].handle) 267062306a36Sopenharmony_ci adap->uld[i].state_change(adap->uld[i].handle, 267162306a36Sopenharmony_ci new_state); 267262306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 267362306a36Sopenharmony_ci} 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 267662306a36Sopenharmony_cistatic int cxgb4_inet6addr_handler(struct notifier_block *this, 267762306a36Sopenharmony_ci unsigned long event, void *data) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci struct inet6_ifaddr *ifa = data; 268062306a36Sopenharmony_ci struct net_device *event_dev = ifa->idev->dev; 268162306a36Sopenharmony_ci const struct device *parent = NULL; 268262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BONDING) 268362306a36Sopenharmony_ci struct adapter *adap; 268462306a36Sopenharmony_ci#endif 268562306a36Sopenharmony_ci if (is_vlan_dev(event_dev)) 268662306a36Sopenharmony_ci event_dev = vlan_dev_real_dev(event_dev); 268762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_BONDING) 268862306a36Sopenharmony_ci if (event_dev->flags & IFF_MASTER) { 268962306a36Sopenharmony_ci list_for_each_entry(adap, &adapter_list, list_node) { 269062306a36Sopenharmony_ci switch (event) { 269162306a36Sopenharmony_ci case NETDEV_UP: 269262306a36Sopenharmony_ci cxgb4_clip_get(adap->port[0], 269362306a36Sopenharmony_ci (const u32 *)ifa, 1); 269462306a36Sopenharmony_ci break; 269562306a36Sopenharmony_ci case NETDEV_DOWN: 269662306a36Sopenharmony_ci cxgb4_clip_release(adap->port[0], 269762306a36Sopenharmony_ci (const u32 *)ifa, 1); 269862306a36Sopenharmony_ci break; 269962306a36Sopenharmony_ci default: 270062306a36Sopenharmony_ci break; 270162306a36Sopenharmony_ci } 270262306a36Sopenharmony_ci } 270362306a36Sopenharmony_ci return NOTIFY_OK; 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci#endif 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci if (event_dev) 270862306a36Sopenharmony_ci parent = event_dev->dev.parent; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci if (parent && parent->driver == &cxgb4_driver.driver) { 271162306a36Sopenharmony_ci switch (event) { 271262306a36Sopenharmony_ci case NETDEV_UP: 271362306a36Sopenharmony_ci cxgb4_clip_get(event_dev, (const u32 *)ifa, 1); 271462306a36Sopenharmony_ci break; 271562306a36Sopenharmony_ci case NETDEV_DOWN: 271662306a36Sopenharmony_ci cxgb4_clip_release(event_dev, (const u32 *)ifa, 1); 271762306a36Sopenharmony_ci break; 271862306a36Sopenharmony_ci default: 271962306a36Sopenharmony_ci break; 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci return NOTIFY_OK; 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_cistatic bool inet6addr_registered; 272662306a36Sopenharmony_cistatic struct notifier_block cxgb4_inet6addr_notifier = { 272762306a36Sopenharmony_ci .notifier_call = cxgb4_inet6addr_handler 272862306a36Sopenharmony_ci}; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_cistatic void update_clip(const struct adapter *adap) 273162306a36Sopenharmony_ci{ 273262306a36Sopenharmony_ci int i; 273362306a36Sopenharmony_ci struct net_device *dev; 273462306a36Sopenharmony_ci int ret; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci rcu_read_lock(); 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci for (i = 0; i < MAX_NPORTS; i++) { 273962306a36Sopenharmony_ci dev = adap->port[i]; 274062306a36Sopenharmony_ci ret = 0; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci if (dev) 274362306a36Sopenharmony_ci ret = cxgb4_update_root_dev_clip(dev); 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci if (ret < 0) 274662306a36Sopenharmony_ci break; 274762306a36Sopenharmony_ci } 274862306a36Sopenharmony_ci rcu_read_unlock(); 274962306a36Sopenharmony_ci} 275062306a36Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */ 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci/** 275362306a36Sopenharmony_ci * cxgb_up - enable the adapter 275462306a36Sopenharmony_ci * @adap: adapter being enabled 275562306a36Sopenharmony_ci * 275662306a36Sopenharmony_ci * Called when the first port is enabled, this function performs the 275762306a36Sopenharmony_ci * actions necessary to make an adapter operational, such as completing 275862306a36Sopenharmony_ci * the initialization of HW modules, and enabling interrupts. 275962306a36Sopenharmony_ci * 276062306a36Sopenharmony_ci * Must be called with the rtnl lock held. 276162306a36Sopenharmony_ci */ 276262306a36Sopenharmony_cistatic int cxgb_up(struct adapter *adap) 276362306a36Sopenharmony_ci{ 276462306a36Sopenharmony_ci struct sge *s = &adap->sge; 276562306a36Sopenharmony_ci int err; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci mutex_lock(&uld_mutex); 276862306a36Sopenharmony_ci err = setup_sge_queues(adap); 276962306a36Sopenharmony_ci if (err) 277062306a36Sopenharmony_ci goto rel_lock; 277162306a36Sopenharmony_ci err = setup_rss(adap); 277262306a36Sopenharmony_ci if (err) 277362306a36Sopenharmony_ci goto freeq; 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 277662306a36Sopenharmony_ci if (s->nd_msix_idx < 0) { 277762306a36Sopenharmony_ci err = -ENOMEM; 277862306a36Sopenharmony_ci goto irq_err; 277962306a36Sopenharmony_ci } 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci err = request_irq(adap->msix_info[s->nd_msix_idx].vec, 278262306a36Sopenharmony_ci t4_nondata_intr, 0, 278362306a36Sopenharmony_ci adap->msix_info[s->nd_msix_idx].desc, adap); 278462306a36Sopenharmony_ci if (err) 278562306a36Sopenharmony_ci goto irq_err; 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci err = request_msix_queue_irqs(adap); 278862306a36Sopenharmony_ci if (err) 278962306a36Sopenharmony_ci goto irq_err_free_nd_msix; 279062306a36Sopenharmony_ci } else { 279162306a36Sopenharmony_ci err = request_irq(adap->pdev->irq, t4_intr_handler(adap), 279262306a36Sopenharmony_ci (adap->flags & CXGB4_USING_MSI) ? 0 279362306a36Sopenharmony_ci : IRQF_SHARED, 279462306a36Sopenharmony_ci adap->port[0]->name, adap); 279562306a36Sopenharmony_ci if (err) 279662306a36Sopenharmony_ci goto irq_err; 279762306a36Sopenharmony_ci } 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci enable_rx(adap); 280062306a36Sopenharmony_ci t4_sge_start(adap); 280162306a36Sopenharmony_ci t4_intr_enable(adap); 280262306a36Sopenharmony_ci adap->flags |= CXGB4_FULL_INIT_DONE; 280362306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci notify_ulds(adap, CXGB4_STATE_UP); 280662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 280762306a36Sopenharmony_ci update_clip(adap); 280862306a36Sopenharmony_ci#endif 280962306a36Sopenharmony_ci return err; 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ciirq_err_free_nd_msix: 281262306a36Sopenharmony_ci free_irq(adap->msix_info[s->nd_msix_idx].vec, adap); 281362306a36Sopenharmony_ciirq_err: 281462306a36Sopenharmony_ci dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); 281562306a36Sopenharmony_cifreeq: 281662306a36Sopenharmony_ci t4_free_sge_resources(adap); 281762306a36Sopenharmony_cirel_lock: 281862306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 281962306a36Sopenharmony_ci return err; 282062306a36Sopenharmony_ci} 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_cistatic void cxgb_down(struct adapter *adapter) 282362306a36Sopenharmony_ci{ 282462306a36Sopenharmony_ci cancel_work_sync(&adapter->tid_release_task); 282562306a36Sopenharmony_ci cancel_work_sync(&adapter->db_full_task); 282662306a36Sopenharmony_ci cancel_work_sync(&adapter->db_drop_task); 282762306a36Sopenharmony_ci adapter->tid_release_task_busy = false; 282862306a36Sopenharmony_ci adapter->tid_release_head = NULL; 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci t4_sge_stop(adapter); 283162306a36Sopenharmony_ci t4_free_sge_resources(adapter); 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci adapter->flags &= ~CXGB4_FULL_INIT_DONE; 283462306a36Sopenharmony_ci} 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci/* 283762306a36Sopenharmony_ci * net_device operations 283862306a36Sopenharmony_ci */ 283962306a36Sopenharmony_cistatic int cxgb_open(struct net_device *dev) 284062306a36Sopenharmony_ci{ 284162306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 284262306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 284362306a36Sopenharmony_ci int err; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci netif_carrier_off(dev); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (!(adapter->flags & CXGB4_FULL_INIT_DONE)) { 284862306a36Sopenharmony_ci err = cxgb_up(adapter); 284962306a36Sopenharmony_ci if (err < 0) 285062306a36Sopenharmony_ci return err; 285162306a36Sopenharmony_ci } 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci /* It's possible that the basic port information could have 285462306a36Sopenharmony_ci * changed since we first read it. 285562306a36Sopenharmony_ci */ 285662306a36Sopenharmony_ci err = t4_update_port_info(pi); 285762306a36Sopenharmony_ci if (err < 0) 285862306a36Sopenharmony_ci return err; 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci err = link_start(dev); 286162306a36Sopenharmony_ci if (err) 286262306a36Sopenharmony_ci return err; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci if (pi->nmirrorqsets) { 286562306a36Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 286662306a36Sopenharmony_ci err = cxgb4_port_mirror_alloc_queues(dev); 286762306a36Sopenharmony_ci if (err) 286862306a36Sopenharmony_ci goto out_unlock; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci err = cxgb4_port_mirror_start(dev); 287162306a36Sopenharmony_ci if (err) 287262306a36Sopenharmony_ci goto out_free_queues; 287362306a36Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 287462306a36Sopenharmony_ci } 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci netif_tx_start_all_queues(dev); 287762306a36Sopenharmony_ci return 0; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ciout_free_queues: 288062306a36Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ciout_unlock: 288362306a36Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 288462306a36Sopenharmony_ci return err; 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_cistatic int cxgb_close(struct net_device *dev) 288862306a36Sopenharmony_ci{ 288962306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 289062306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 289162306a36Sopenharmony_ci int ret; 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci netif_tx_stop_all_queues(dev); 289462306a36Sopenharmony_ci netif_carrier_off(dev); 289562306a36Sopenharmony_ci ret = t4_enable_pi_params(adapter, adapter->pf, pi, 289662306a36Sopenharmony_ci false, false, false); 289762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 289862306a36Sopenharmony_ci cxgb4_dcb_reset(dev); 289962306a36Sopenharmony_ci dcb_tx_queue_prio_enable(dev, false); 290062306a36Sopenharmony_ci#endif 290162306a36Sopenharmony_ci if (ret) 290262306a36Sopenharmony_ci return ret; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci if (pi->nmirrorqsets) { 290562306a36Sopenharmony_ci mutex_lock(&pi->vi_mirror_mutex); 290662306a36Sopenharmony_ci cxgb4_port_mirror_stop(dev); 290762306a36Sopenharmony_ci cxgb4_port_mirror_free_queues(dev); 290862306a36Sopenharmony_ci mutex_unlock(&pi->vi_mirror_mutex); 290962306a36Sopenharmony_ci } 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci return 0; 291262306a36Sopenharmony_ci} 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ciint cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid, 291562306a36Sopenharmony_ci __be32 sip, __be16 sport, __be16 vlan, 291662306a36Sopenharmony_ci unsigned int queue, unsigned char port, unsigned char mask) 291762306a36Sopenharmony_ci{ 291862306a36Sopenharmony_ci int ret; 291962306a36Sopenharmony_ci struct filter_entry *f; 292062306a36Sopenharmony_ci struct adapter *adap; 292162306a36Sopenharmony_ci int i; 292262306a36Sopenharmony_ci u8 *val; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci adap = netdev2adap(dev); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci /* Adjust stid to correct filter index */ 292762306a36Sopenharmony_ci stid -= adap->tids.sftid_base; 292862306a36Sopenharmony_ci stid += adap->tids.nftids; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci /* Check to make sure the filter requested is writable ... 293162306a36Sopenharmony_ci */ 293262306a36Sopenharmony_ci f = &adap->tids.ftid_tab[stid]; 293362306a36Sopenharmony_ci ret = writable_filter(f); 293462306a36Sopenharmony_ci if (ret) 293562306a36Sopenharmony_ci return ret; 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci /* Clear out any old resources being used by the filter before 293862306a36Sopenharmony_ci * we start constructing the new filter. 293962306a36Sopenharmony_ci */ 294062306a36Sopenharmony_ci if (f->valid) 294162306a36Sopenharmony_ci clear_filter(adap, f); 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci /* Clear out filter specifications */ 294462306a36Sopenharmony_ci memset(&f->fs, 0, sizeof(struct ch_filter_specification)); 294562306a36Sopenharmony_ci f->fs.val.lport = be16_to_cpu(sport); 294662306a36Sopenharmony_ci f->fs.mask.lport = ~0; 294762306a36Sopenharmony_ci val = (u8 *)&sip; 294862306a36Sopenharmony_ci if ((val[0] | val[1] | val[2] | val[3]) != 0) { 294962306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 295062306a36Sopenharmony_ci f->fs.val.lip[i] = val[i]; 295162306a36Sopenharmony_ci f->fs.mask.lip[i] = ~0; 295262306a36Sopenharmony_ci } 295362306a36Sopenharmony_ci if (adap->params.tp.vlan_pri_map & PORT_F) { 295462306a36Sopenharmony_ci f->fs.val.iport = port; 295562306a36Sopenharmony_ci f->fs.mask.iport = mask; 295662306a36Sopenharmony_ci } 295762306a36Sopenharmony_ci } 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci if (adap->params.tp.vlan_pri_map & PROTOCOL_F) { 296062306a36Sopenharmony_ci f->fs.val.proto = IPPROTO_TCP; 296162306a36Sopenharmony_ci f->fs.mask.proto = ~0; 296262306a36Sopenharmony_ci } 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci f->fs.dirsteer = 1; 296562306a36Sopenharmony_ci f->fs.iq = queue; 296662306a36Sopenharmony_ci /* Mark filter as locked */ 296762306a36Sopenharmony_ci f->locked = 1; 296862306a36Sopenharmony_ci f->fs.rpttid = 1; 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci /* Save the actual tid. We need this to get the corresponding 297162306a36Sopenharmony_ci * filter entry structure in filter_rpl. 297262306a36Sopenharmony_ci */ 297362306a36Sopenharmony_ci f->tid = stid + adap->tids.ftid_base; 297462306a36Sopenharmony_ci ret = set_filter_wr(adap, stid); 297562306a36Sopenharmony_ci if (ret) { 297662306a36Sopenharmony_ci clear_filter(adap, f); 297762306a36Sopenharmony_ci return ret; 297862306a36Sopenharmony_ci } 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci return 0; 298162306a36Sopenharmony_ci} 298262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_create_server_filter); 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ciint cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, 298562306a36Sopenharmony_ci unsigned int queue, bool ipv6) 298662306a36Sopenharmony_ci{ 298762306a36Sopenharmony_ci struct filter_entry *f; 298862306a36Sopenharmony_ci struct adapter *adap; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci adap = netdev2adap(dev); 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci /* Adjust stid to correct filter index */ 299362306a36Sopenharmony_ci stid -= adap->tids.sftid_base; 299462306a36Sopenharmony_ci stid += adap->tids.nftids; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci f = &adap->tids.ftid_tab[stid]; 299762306a36Sopenharmony_ci /* Unlock the filter */ 299862306a36Sopenharmony_ci f->locked = 0; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci return delete_filter(adap, stid); 300162306a36Sopenharmony_ci} 300262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb4_remove_server_filter); 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_cistatic void cxgb_get_stats(struct net_device *dev, 300562306a36Sopenharmony_ci struct rtnl_link_stats64 *ns) 300662306a36Sopenharmony_ci{ 300762306a36Sopenharmony_ci struct port_stats stats; 300862306a36Sopenharmony_ci struct port_info *p = netdev_priv(dev); 300962306a36Sopenharmony_ci struct adapter *adapter = p->adapter; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci /* Block retrieving statistics during EEH error 301262306a36Sopenharmony_ci * recovery. Otherwise, the recovery might fail 301362306a36Sopenharmony_ci * and the PCI device will be removed permanently 301462306a36Sopenharmony_ci */ 301562306a36Sopenharmony_ci spin_lock(&adapter->stats_lock); 301662306a36Sopenharmony_ci if (!netif_device_present(dev)) { 301762306a36Sopenharmony_ci spin_unlock(&adapter->stats_lock); 301862306a36Sopenharmony_ci return; 301962306a36Sopenharmony_ci } 302062306a36Sopenharmony_ci t4_get_port_stats_offset(adapter, p->tx_chan, &stats, 302162306a36Sopenharmony_ci &p->stats_base); 302262306a36Sopenharmony_ci spin_unlock(&adapter->stats_lock); 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci ns->tx_bytes = stats.tx_octets; 302562306a36Sopenharmony_ci ns->tx_packets = stats.tx_frames; 302662306a36Sopenharmony_ci ns->rx_bytes = stats.rx_octets; 302762306a36Sopenharmony_ci ns->rx_packets = stats.rx_frames; 302862306a36Sopenharmony_ci ns->multicast = stats.rx_mcast_frames; 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci /* detailed rx_errors */ 303162306a36Sopenharmony_ci ns->rx_length_errors = stats.rx_jabber + stats.rx_too_long + 303262306a36Sopenharmony_ci stats.rx_runt; 303362306a36Sopenharmony_ci ns->rx_over_errors = 0; 303462306a36Sopenharmony_ci ns->rx_crc_errors = stats.rx_fcs_err; 303562306a36Sopenharmony_ci ns->rx_frame_errors = stats.rx_symbol_err; 303662306a36Sopenharmony_ci ns->rx_dropped = stats.rx_ovflow0 + stats.rx_ovflow1 + 303762306a36Sopenharmony_ci stats.rx_ovflow2 + stats.rx_ovflow3 + 303862306a36Sopenharmony_ci stats.rx_trunc0 + stats.rx_trunc1 + 303962306a36Sopenharmony_ci stats.rx_trunc2 + stats.rx_trunc3; 304062306a36Sopenharmony_ci ns->rx_missed_errors = 0; 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ci /* detailed tx_errors */ 304362306a36Sopenharmony_ci ns->tx_aborted_errors = 0; 304462306a36Sopenharmony_ci ns->tx_carrier_errors = 0; 304562306a36Sopenharmony_ci ns->tx_fifo_errors = 0; 304662306a36Sopenharmony_ci ns->tx_heartbeat_errors = 0; 304762306a36Sopenharmony_ci ns->tx_window_errors = 0; 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci ns->tx_errors = stats.tx_error_frames; 305062306a36Sopenharmony_ci ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err + 305162306a36Sopenharmony_ci ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors; 305262306a36Sopenharmony_ci} 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_cistatic int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) 305562306a36Sopenharmony_ci{ 305662306a36Sopenharmony_ci unsigned int mbox; 305762306a36Sopenharmony_ci int ret = 0, prtad, devad; 305862306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 305962306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 306062306a36Sopenharmony_ci struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci switch (cmd) { 306362306a36Sopenharmony_ci case SIOCGMIIPHY: 306462306a36Sopenharmony_ci if (pi->mdio_addr < 0) 306562306a36Sopenharmony_ci return -EOPNOTSUPP; 306662306a36Sopenharmony_ci data->phy_id = pi->mdio_addr; 306762306a36Sopenharmony_ci break; 306862306a36Sopenharmony_ci case SIOCGMIIREG: 306962306a36Sopenharmony_ci case SIOCSMIIREG: 307062306a36Sopenharmony_ci if (mdio_phy_id_is_c45(data->phy_id)) { 307162306a36Sopenharmony_ci prtad = mdio_phy_id_prtad(data->phy_id); 307262306a36Sopenharmony_ci devad = mdio_phy_id_devad(data->phy_id); 307362306a36Sopenharmony_ci } else if (data->phy_id < 32) { 307462306a36Sopenharmony_ci prtad = data->phy_id; 307562306a36Sopenharmony_ci devad = 0; 307662306a36Sopenharmony_ci data->reg_num &= 0x1f; 307762306a36Sopenharmony_ci } else 307862306a36Sopenharmony_ci return -EINVAL; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci mbox = pi->adapter->pf; 308162306a36Sopenharmony_ci if (cmd == SIOCGMIIREG) 308262306a36Sopenharmony_ci ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad, 308362306a36Sopenharmony_ci data->reg_num, &data->val_out); 308462306a36Sopenharmony_ci else 308562306a36Sopenharmony_ci ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad, 308662306a36Sopenharmony_ci data->reg_num, data->val_in); 308762306a36Sopenharmony_ci break; 308862306a36Sopenharmony_ci case SIOCGHWTSTAMP: 308962306a36Sopenharmony_ci return copy_to_user(req->ifr_data, &pi->tstamp_config, 309062306a36Sopenharmony_ci sizeof(pi->tstamp_config)) ? 309162306a36Sopenharmony_ci -EFAULT : 0; 309262306a36Sopenharmony_ci case SIOCSHWTSTAMP: 309362306a36Sopenharmony_ci if (copy_from_user(&pi->tstamp_config, req->ifr_data, 309462306a36Sopenharmony_ci sizeof(pi->tstamp_config))) 309562306a36Sopenharmony_ci return -EFAULT; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 309862306a36Sopenharmony_ci switch (pi->tstamp_config.tx_type) { 309962306a36Sopenharmony_ci case HWTSTAMP_TX_OFF: 310062306a36Sopenharmony_ci case HWTSTAMP_TX_ON: 310162306a36Sopenharmony_ci break; 310262306a36Sopenharmony_ci default: 310362306a36Sopenharmony_ci return -ERANGE; 310462306a36Sopenharmony_ci } 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci switch (pi->tstamp_config.rx_filter) { 310762306a36Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 310862306a36Sopenharmony_ci pi->rxtstamp = false; 310962306a36Sopenharmony_ci break; 311062306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 311162306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 311262306a36Sopenharmony_ci cxgb4_ptprx_timestamping(pi, pi->port_id, 311362306a36Sopenharmony_ci PTP_TS_L4); 311462306a36Sopenharmony_ci break; 311562306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 311662306a36Sopenharmony_ci cxgb4_ptprx_timestamping(pi, pi->port_id, 311762306a36Sopenharmony_ci PTP_TS_L2_L4); 311862306a36Sopenharmony_ci break; 311962306a36Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 312062306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 312162306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 312262306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 312362306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 312462306a36Sopenharmony_ci pi->rxtstamp = true; 312562306a36Sopenharmony_ci break; 312662306a36Sopenharmony_ci default: 312762306a36Sopenharmony_ci pi->tstamp_config.rx_filter = 312862306a36Sopenharmony_ci HWTSTAMP_FILTER_NONE; 312962306a36Sopenharmony_ci return -ERANGE; 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci if ((pi->tstamp_config.tx_type == HWTSTAMP_TX_OFF) && 313362306a36Sopenharmony_ci (pi->tstamp_config.rx_filter == 313462306a36Sopenharmony_ci HWTSTAMP_FILTER_NONE)) { 313562306a36Sopenharmony_ci if (cxgb4_ptp_txtype(adapter, pi->port_id) >= 0) 313662306a36Sopenharmony_ci pi->ptp_enable = false; 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci if (pi->tstamp_config.rx_filter != 314062306a36Sopenharmony_ci HWTSTAMP_FILTER_NONE) { 314162306a36Sopenharmony_ci if (cxgb4_ptp_redirect_rx_packet(adapter, 314262306a36Sopenharmony_ci pi) >= 0) 314362306a36Sopenharmony_ci pi->ptp_enable = true; 314462306a36Sopenharmony_ci } 314562306a36Sopenharmony_ci } else { 314662306a36Sopenharmony_ci /* For T4 Adapters */ 314762306a36Sopenharmony_ci switch (pi->tstamp_config.rx_filter) { 314862306a36Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 314962306a36Sopenharmony_ci pi->rxtstamp = false; 315062306a36Sopenharmony_ci break; 315162306a36Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 315262306a36Sopenharmony_ci pi->rxtstamp = true; 315362306a36Sopenharmony_ci break; 315462306a36Sopenharmony_ci default: 315562306a36Sopenharmony_ci pi->tstamp_config.rx_filter = 315662306a36Sopenharmony_ci HWTSTAMP_FILTER_NONE; 315762306a36Sopenharmony_ci return -ERANGE; 315862306a36Sopenharmony_ci } 315962306a36Sopenharmony_ci } 316062306a36Sopenharmony_ci return copy_to_user(req->ifr_data, &pi->tstamp_config, 316162306a36Sopenharmony_ci sizeof(pi->tstamp_config)) ? 316262306a36Sopenharmony_ci -EFAULT : 0; 316362306a36Sopenharmony_ci default: 316462306a36Sopenharmony_ci return -EOPNOTSUPP; 316562306a36Sopenharmony_ci } 316662306a36Sopenharmony_ci return ret; 316762306a36Sopenharmony_ci} 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_cistatic void cxgb_set_rxmode(struct net_device *dev) 317062306a36Sopenharmony_ci{ 317162306a36Sopenharmony_ci /* unfortunately we can't return errors to the stack */ 317262306a36Sopenharmony_ci set_rxmode(dev, -1, false); 317362306a36Sopenharmony_ci} 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_cistatic int cxgb_change_mtu(struct net_device *dev, int new_mtu) 317662306a36Sopenharmony_ci{ 317762306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 317862306a36Sopenharmony_ci int ret; 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci ret = t4_set_rxmode(pi->adapter, pi->adapter->mbox, pi->viid, 318162306a36Sopenharmony_ci pi->viid_mirror, new_mtu, -1, -1, -1, -1, true); 318262306a36Sopenharmony_ci if (!ret) 318362306a36Sopenharmony_ci dev->mtu = new_mtu; 318462306a36Sopenharmony_ci return ret; 318562306a36Sopenharmony_ci} 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV 318862306a36Sopenharmony_cistatic int cxgb4_mgmt_open(struct net_device *dev) 318962306a36Sopenharmony_ci{ 319062306a36Sopenharmony_ci /* Turn carrier off since we don't have to transmit anything on this 319162306a36Sopenharmony_ci * interface. 319262306a36Sopenharmony_ci */ 319362306a36Sopenharmony_ci netif_carrier_off(dev); 319462306a36Sopenharmony_ci return 0; 319562306a36Sopenharmony_ci} 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci/* Fill MAC address that will be assigned by the FW */ 319862306a36Sopenharmony_cistatic void cxgb4_mgmt_fill_vf_station_mac_addr(struct adapter *adap) 319962306a36Sopenharmony_ci{ 320062306a36Sopenharmony_ci u8 hw_addr[ETH_ALEN], macaddr[ETH_ALEN]; 320162306a36Sopenharmony_ci unsigned int i, vf, nvfs; 320262306a36Sopenharmony_ci u16 a, b; 320362306a36Sopenharmony_ci int err; 320462306a36Sopenharmony_ci u8 *na; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci err = t4_get_raw_vpd_params(adap, &adap->params.vpd); 320762306a36Sopenharmony_ci if (err) 320862306a36Sopenharmony_ci return; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci na = adap->params.vpd.na; 321162306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 321262306a36Sopenharmony_ci hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 + 321362306a36Sopenharmony_ci hex2val(na[2 * i + 1])); 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci a = (hw_addr[0] << 8) | hw_addr[1]; 321662306a36Sopenharmony_ci b = (hw_addr[1] << 8) | hw_addr[2]; 321762306a36Sopenharmony_ci a ^= b; 321862306a36Sopenharmony_ci a |= 0x0200; /* locally assigned Ethernet MAC address */ 321962306a36Sopenharmony_ci a &= ~0x0100; /* not a multicast Ethernet MAC address */ 322062306a36Sopenharmony_ci macaddr[0] = a >> 8; 322162306a36Sopenharmony_ci macaddr[1] = a & 0xff; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci for (i = 2; i < 5; i++) 322462306a36Sopenharmony_ci macaddr[i] = hw_addr[i + 1]; 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_ci for (vf = 0, nvfs = pci_sriov_get_totalvfs(adap->pdev); 322762306a36Sopenharmony_ci vf < nvfs; vf++) { 322862306a36Sopenharmony_ci macaddr[5] = adap->pf * nvfs + vf; 322962306a36Sopenharmony_ci ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, macaddr); 323062306a36Sopenharmony_ci } 323162306a36Sopenharmony_ci} 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_mac(struct net_device *dev, int vf, u8 *mac) 323462306a36Sopenharmony_ci{ 323562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 323662306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 323762306a36Sopenharmony_ci int ret; 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci /* verify MAC addr is valid */ 324062306a36Sopenharmony_ci if (!is_valid_ether_addr(mac)) { 324162306a36Sopenharmony_ci dev_err(pi->adapter->pdev_dev, 324262306a36Sopenharmony_ci "Invalid Ethernet address %pM for VF %d\n", 324362306a36Sopenharmony_ci mac, vf); 324462306a36Sopenharmony_ci return -EINVAL; 324562306a36Sopenharmony_ci } 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci dev_info(pi->adapter->pdev_dev, 324862306a36Sopenharmony_ci "Setting MAC %pM on VF %d\n", mac, vf); 324962306a36Sopenharmony_ci ret = t4_set_vf_mac_acl(adap, vf + 1, 1, mac); 325062306a36Sopenharmony_ci if (!ret) 325162306a36Sopenharmony_ci ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, mac); 325262306a36Sopenharmony_ci return ret; 325362306a36Sopenharmony_ci} 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_cistatic int cxgb4_mgmt_get_vf_config(struct net_device *dev, 325662306a36Sopenharmony_ci int vf, struct ifla_vf_info *ivi) 325762306a36Sopenharmony_ci{ 325862306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 325962306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 326062306a36Sopenharmony_ci struct vf_info *vfinfo; 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci if (vf >= adap->num_vfs) 326362306a36Sopenharmony_ci return -EINVAL; 326462306a36Sopenharmony_ci vfinfo = &adap->vfinfo[vf]; 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci ivi->vf = vf; 326762306a36Sopenharmony_ci ivi->max_tx_rate = vfinfo->tx_rate; 326862306a36Sopenharmony_ci ivi->min_tx_rate = 0; 326962306a36Sopenharmony_ci ether_addr_copy(ivi->mac, vfinfo->vf_mac_addr); 327062306a36Sopenharmony_ci ivi->vlan = vfinfo->vlan; 327162306a36Sopenharmony_ci ivi->linkstate = vfinfo->link_state; 327262306a36Sopenharmony_ci return 0; 327362306a36Sopenharmony_ci} 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_cistatic int cxgb4_mgmt_get_phys_port_id(struct net_device *dev, 327662306a36Sopenharmony_ci struct netdev_phys_item_id *ppid) 327762306a36Sopenharmony_ci{ 327862306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 327962306a36Sopenharmony_ci unsigned int phy_port_id; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci phy_port_id = pi->adapter->adap_idx * 10 + pi->port_id; 328262306a36Sopenharmony_ci ppid->id_len = sizeof(phy_port_id); 328362306a36Sopenharmony_ci memcpy(ppid->id, &phy_port_id, ppid->id_len); 328462306a36Sopenharmony_ci return 0; 328562306a36Sopenharmony_ci} 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf, 328862306a36Sopenharmony_ci int min_tx_rate, int max_tx_rate) 328962306a36Sopenharmony_ci{ 329062306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 329162306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 329262306a36Sopenharmony_ci unsigned int link_ok, speed, mtu; 329362306a36Sopenharmony_ci u32 fw_pfvf, fw_class; 329462306a36Sopenharmony_ci int class_id = vf; 329562306a36Sopenharmony_ci int ret; 329662306a36Sopenharmony_ci u16 pktsize; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci if (vf >= adap->num_vfs) 329962306a36Sopenharmony_ci return -EINVAL; 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci if (min_tx_rate) { 330262306a36Sopenharmony_ci dev_err(adap->pdev_dev, 330362306a36Sopenharmony_ci "Min tx rate (%d) (> 0) for VF %d is Invalid.\n", 330462306a36Sopenharmony_ci min_tx_rate, vf); 330562306a36Sopenharmony_ci return -EINVAL; 330662306a36Sopenharmony_ci } 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci if (max_tx_rate == 0) { 330962306a36Sopenharmony_ci /* unbind VF to to any Traffic Class */ 331062306a36Sopenharmony_ci fw_pfvf = 331162306a36Sopenharmony_ci (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 331262306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); 331362306a36Sopenharmony_ci fw_class = 0xffffffff; 331462306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, 331562306a36Sopenharmony_ci &fw_pfvf, &fw_class); 331662306a36Sopenharmony_ci if (ret) { 331762306a36Sopenharmony_ci dev_err(adap->pdev_dev, 331862306a36Sopenharmony_ci "Err %d in unbinding PF %d VF %d from TX Rate Limiting\n", 331962306a36Sopenharmony_ci ret, adap->pf, vf); 332062306a36Sopenharmony_ci return -EINVAL; 332162306a36Sopenharmony_ci } 332262306a36Sopenharmony_ci dev_info(adap->pdev_dev, 332362306a36Sopenharmony_ci "PF %d VF %d is unbound from TX Rate Limiting\n", 332462306a36Sopenharmony_ci adap->pf, vf); 332562306a36Sopenharmony_ci adap->vfinfo[vf].tx_rate = 0; 332662306a36Sopenharmony_ci return 0; 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci ret = t4_get_link_params(pi, &link_ok, &speed, &mtu); 333062306a36Sopenharmony_ci if (ret != FW_SUCCESS) { 333162306a36Sopenharmony_ci dev_err(adap->pdev_dev, 333262306a36Sopenharmony_ci "Failed to get link information for VF %d\n", vf); 333362306a36Sopenharmony_ci return -EINVAL; 333462306a36Sopenharmony_ci } 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci if (!link_ok) { 333762306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Link down for VF %d\n", vf); 333862306a36Sopenharmony_ci return -EINVAL; 333962306a36Sopenharmony_ci } 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci if (max_tx_rate > speed) { 334262306a36Sopenharmony_ci dev_err(adap->pdev_dev, 334362306a36Sopenharmony_ci "Max tx rate %d for VF %d can't be > link-speed %u", 334462306a36Sopenharmony_ci max_tx_rate, vf, speed); 334562306a36Sopenharmony_ci return -EINVAL; 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci pktsize = mtu; 334962306a36Sopenharmony_ci /* subtract ethhdr size and 4 bytes crc since, f/w appends it */ 335062306a36Sopenharmony_ci pktsize = pktsize - sizeof(struct ethhdr) - 4; 335162306a36Sopenharmony_ci /* subtract ipv4 hdr size, tcp hdr size to get typical IPv4 MSS size */ 335262306a36Sopenharmony_ci pktsize = pktsize - sizeof(struct iphdr) - sizeof(struct tcphdr); 335362306a36Sopenharmony_ci /* configure Traffic Class for rate-limiting */ 335462306a36Sopenharmony_ci ret = t4_sched_params(adap, SCHED_CLASS_TYPE_PACKET, 335562306a36Sopenharmony_ci SCHED_CLASS_LEVEL_CL_RL, 335662306a36Sopenharmony_ci SCHED_CLASS_MODE_CLASS, 335762306a36Sopenharmony_ci SCHED_CLASS_RATEUNIT_BITS, 335862306a36Sopenharmony_ci SCHED_CLASS_RATEMODE_ABS, 335962306a36Sopenharmony_ci pi->tx_chan, class_id, 0, 336062306a36Sopenharmony_ci max_tx_rate * 1000, 0, pktsize, 0); 336162306a36Sopenharmony_ci if (ret) { 336262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Err %d for Traffic Class config\n", 336362306a36Sopenharmony_ci ret); 336462306a36Sopenharmony_ci return -EINVAL; 336562306a36Sopenharmony_ci } 336662306a36Sopenharmony_ci dev_info(adap->pdev_dev, 336762306a36Sopenharmony_ci "Class %d with MSS %u configured with rate %u\n", 336862306a36Sopenharmony_ci class_id, pktsize, max_tx_rate); 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci /* bind VF to configured Traffic Class */ 337162306a36Sopenharmony_ci fw_pfvf = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 337262306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH)); 337362306a36Sopenharmony_ci fw_class = class_id; 337462306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, &fw_pfvf, 337562306a36Sopenharmony_ci &fw_class); 337662306a36Sopenharmony_ci if (ret) { 337762306a36Sopenharmony_ci dev_err(adap->pdev_dev, 337862306a36Sopenharmony_ci "Err %d in binding PF %d VF %d to Traffic Class %d\n", 337962306a36Sopenharmony_ci ret, adap->pf, vf, class_id); 338062306a36Sopenharmony_ci return -EINVAL; 338162306a36Sopenharmony_ci } 338262306a36Sopenharmony_ci dev_info(adap->pdev_dev, "PF %d VF %d is bound to Class %d\n", 338362306a36Sopenharmony_ci adap->pf, vf, class_id); 338462306a36Sopenharmony_ci adap->vfinfo[vf].tx_rate = max_tx_rate; 338562306a36Sopenharmony_ci return 0; 338662306a36Sopenharmony_ci} 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_vlan(struct net_device *dev, int vf, 338962306a36Sopenharmony_ci u16 vlan, u8 qos, __be16 vlan_proto) 339062306a36Sopenharmony_ci{ 339162306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 339262306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 339362306a36Sopenharmony_ci int ret; 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci if (vf >= adap->num_vfs || vlan > 4095 || qos > 7) 339662306a36Sopenharmony_ci return -EINVAL; 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q) || qos != 0) 339962306a36Sopenharmony_ci return -EPROTONOSUPPORT; 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci ret = t4_set_vlan_acl(adap, adap->mbox, vf + 1, vlan); 340262306a36Sopenharmony_ci if (!ret) { 340362306a36Sopenharmony_ci adap->vfinfo[vf].vlan = vlan; 340462306a36Sopenharmony_ci return 0; 340562306a36Sopenharmony_ci } 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci dev_err(adap->pdev_dev, "Err %d %s VLAN ACL for PF/VF %d/%d\n", 340862306a36Sopenharmony_ci ret, (vlan ? "setting" : "clearing"), adap->pf, vf); 340962306a36Sopenharmony_ci return ret; 341062306a36Sopenharmony_ci} 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_cistatic int cxgb4_mgmt_set_vf_link_state(struct net_device *dev, int vf, 341362306a36Sopenharmony_ci int link) 341462306a36Sopenharmony_ci{ 341562306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 341662306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 341762306a36Sopenharmony_ci u32 param, val; 341862306a36Sopenharmony_ci int ret = 0; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci if (vf >= adap->num_vfs) 342162306a36Sopenharmony_ci return -EINVAL; 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci switch (link) { 342462306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_AUTO: 342562306a36Sopenharmony_ci val = FW_VF_LINK_STATE_AUTO; 342662306a36Sopenharmony_ci break; 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_ENABLE: 342962306a36Sopenharmony_ci val = FW_VF_LINK_STATE_ENABLE; 343062306a36Sopenharmony_ci break; 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ci case IFLA_VF_LINK_STATE_DISABLE: 343362306a36Sopenharmony_ci val = FW_VF_LINK_STATE_DISABLE; 343462306a36Sopenharmony_ci break; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci default: 343762306a36Sopenharmony_ci return -EINVAL; 343862306a36Sopenharmony_ci } 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | 344162306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_LINK_STATE)); 344262306a36Sopenharmony_ci ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, 344362306a36Sopenharmony_ci ¶m, &val); 344462306a36Sopenharmony_ci if (ret) { 344562306a36Sopenharmony_ci dev_err(adap->pdev_dev, 344662306a36Sopenharmony_ci "Error %d in setting PF %d VF %d link state\n", 344762306a36Sopenharmony_ci ret, adap->pf, vf); 344862306a36Sopenharmony_ci return -EINVAL; 344962306a36Sopenharmony_ci } 345062306a36Sopenharmony_ci 345162306a36Sopenharmony_ci adap->vfinfo[vf].link_state = link; 345262306a36Sopenharmony_ci return ret; 345362306a36Sopenharmony_ci} 345462306a36Sopenharmony_ci#endif /* CONFIG_PCI_IOV */ 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_cistatic int cxgb_set_mac_addr(struct net_device *dev, void *p) 345762306a36Sopenharmony_ci{ 345862306a36Sopenharmony_ci int ret; 345962306a36Sopenharmony_ci struct sockaddr *addr = p; 346062306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 346362306a36Sopenharmony_ci return -EADDRNOTAVAIL; 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci ret = cxgb4_update_mac_filt(pi, pi->viid, &pi->xact_addr_filt, 346662306a36Sopenharmony_ci addr->sa_data, true, &pi->smt_idx); 346762306a36Sopenharmony_ci if (ret < 0) 346862306a36Sopenharmony_ci return ret; 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci eth_hw_addr_set(dev, addr->sa_data); 347162306a36Sopenharmony_ci return 0; 347262306a36Sopenharmony_ci} 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 347562306a36Sopenharmony_cistatic void cxgb_netpoll(struct net_device *dev) 347662306a36Sopenharmony_ci{ 347762306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 347862306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci if (adap->flags & CXGB4_USING_MSIX) { 348162306a36Sopenharmony_ci int i; 348262306a36Sopenharmony_ci struct sge_eth_rxq *rx = &adap->sge.ethrxq[pi->first_qset]; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci for (i = pi->nqsets; i; i--, rx++) 348562306a36Sopenharmony_ci t4_sge_intr_msix(0, &rx->rspq); 348662306a36Sopenharmony_ci } else 348762306a36Sopenharmony_ci t4_intr_handler(adap)(0, adap); 348862306a36Sopenharmony_ci} 348962306a36Sopenharmony_ci#endif 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_cistatic int cxgb_set_tx_maxrate(struct net_device *dev, int index, u32 rate) 349262306a36Sopenharmony_ci{ 349362306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 349462306a36Sopenharmony_ci struct adapter *adap = pi->adapter; 349562306a36Sopenharmony_ci struct ch_sched_queue qe = { 0 }; 349662306a36Sopenharmony_ci struct ch_sched_params p = { 0 }; 349762306a36Sopenharmony_ci struct sched_class *e; 349862306a36Sopenharmony_ci u32 req_rate; 349962306a36Sopenharmony_ci int err = 0; 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci if (!can_sched(dev)) 350262306a36Sopenharmony_ci return -ENOTSUPP; 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci if (index < 0 || index > pi->nqsets - 1) 350562306a36Sopenharmony_ci return -EINVAL; 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { 350862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 350962306a36Sopenharmony_ci "Failed to rate limit on queue %d. Link Down?\n", 351062306a36Sopenharmony_ci index); 351162306a36Sopenharmony_ci return -EINVAL; 351262306a36Sopenharmony_ci } 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci qe.queue = index; 351562306a36Sopenharmony_ci e = cxgb4_sched_queue_lookup(dev, &qe); 351662306a36Sopenharmony_ci if (e && e->info.u.params.level != SCHED_CLASS_LEVEL_CL_RL) { 351762306a36Sopenharmony_ci dev_err(adap->pdev_dev, 351862306a36Sopenharmony_ci "Queue %u already bound to class %u of type: %u\n", 351962306a36Sopenharmony_ci index, e->idx, e->info.u.params.level); 352062306a36Sopenharmony_ci return -EBUSY; 352162306a36Sopenharmony_ci } 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci /* Convert from Mbps to Kbps */ 352462306a36Sopenharmony_ci req_rate = rate * 1000; 352562306a36Sopenharmony_ci 352662306a36Sopenharmony_ci /* Max rate is 100 Gbps */ 352762306a36Sopenharmony_ci if (req_rate > SCHED_MAX_RATE_KBPS) { 352862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 352962306a36Sopenharmony_ci "Invalid rate %u Mbps, Max rate is %u Mbps\n", 353062306a36Sopenharmony_ci rate, SCHED_MAX_RATE_KBPS / 1000); 353162306a36Sopenharmony_ci return -ERANGE; 353262306a36Sopenharmony_ci } 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci /* First unbind the queue from any existing class */ 353562306a36Sopenharmony_ci memset(&qe, 0, sizeof(qe)); 353662306a36Sopenharmony_ci qe.queue = index; 353762306a36Sopenharmony_ci qe.class = SCHED_CLS_NONE; 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_ci err = cxgb4_sched_class_unbind(dev, (void *)(&qe), SCHED_QUEUE); 354062306a36Sopenharmony_ci if (err) { 354162306a36Sopenharmony_ci dev_err(adap->pdev_dev, 354262306a36Sopenharmony_ci "Unbinding Queue %d on port %d fail. Err: %d\n", 354362306a36Sopenharmony_ci index, pi->port_id, err); 354462306a36Sopenharmony_ci return err; 354562306a36Sopenharmony_ci } 354662306a36Sopenharmony_ci 354762306a36Sopenharmony_ci /* Queue already unbound */ 354862306a36Sopenharmony_ci if (!req_rate) 354962306a36Sopenharmony_ci return 0; 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci /* Fetch any available unused or matching scheduling class */ 355262306a36Sopenharmony_ci p.type = SCHED_CLASS_TYPE_PACKET; 355362306a36Sopenharmony_ci p.u.params.level = SCHED_CLASS_LEVEL_CL_RL; 355462306a36Sopenharmony_ci p.u.params.mode = SCHED_CLASS_MODE_CLASS; 355562306a36Sopenharmony_ci p.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS; 355662306a36Sopenharmony_ci p.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS; 355762306a36Sopenharmony_ci p.u.params.channel = pi->tx_chan; 355862306a36Sopenharmony_ci p.u.params.class = SCHED_CLS_NONE; 355962306a36Sopenharmony_ci p.u.params.minrate = 0; 356062306a36Sopenharmony_ci p.u.params.maxrate = req_rate; 356162306a36Sopenharmony_ci p.u.params.weight = 0; 356262306a36Sopenharmony_ci p.u.params.pktsize = dev->mtu; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci e = cxgb4_sched_class_alloc(dev, &p); 356562306a36Sopenharmony_ci if (!e) 356662306a36Sopenharmony_ci return -ENOMEM; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci /* Bind the queue to a scheduling class */ 356962306a36Sopenharmony_ci memset(&qe, 0, sizeof(qe)); 357062306a36Sopenharmony_ci qe.queue = index; 357162306a36Sopenharmony_ci qe.class = e->idx; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci err = cxgb4_sched_class_bind(dev, (void *)(&qe), SCHED_QUEUE); 357462306a36Sopenharmony_ci if (err) 357562306a36Sopenharmony_ci dev_err(adap->pdev_dev, 357662306a36Sopenharmony_ci "Queue rate limiting failed. Err: %d\n", err); 357762306a36Sopenharmony_ci return err; 357862306a36Sopenharmony_ci} 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_cistatic int cxgb_setup_tc_flower(struct net_device *dev, 358162306a36Sopenharmony_ci struct flow_cls_offload *cls_flower) 358262306a36Sopenharmony_ci{ 358362306a36Sopenharmony_ci switch (cls_flower->command) { 358462306a36Sopenharmony_ci case FLOW_CLS_REPLACE: 358562306a36Sopenharmony_ci return cxgb4_tc_flower_replace(dev, cls_flower); 358662306a36Sopenharmony_ci case FLOW_CLS_DESTROY: 358762306a36Sopenharmony_ci return cxgb4_tc_flower_destroy(dev, cls_flower); 358862306a36Sopenharmony_ci case FLOW_CLS_STATS: 358962306a36Sopenharmony_ci return cxgb4_tc_flower_stats(dev, cls_flower); 359062306a36Sopenharmony_ci default: 359162306a36Sopenharmony_ci return -EOPNOTSUPP; 359262306a36Sopenharmony_ci } 359362306a36Sopenharmony_ci} 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_cistatic int cxgb_setup_tc_cls_u32(struct net_device *dev, 359662306a36Sopenharmony_ci struct tc_cls_u32_offload *cls_u32) 359762306a36Sopenharmony_ci{ 359862306a36Sopenharmony_ci switch (cls_u32->command) { 359962306a36Sopenharmony_ci case TC_CLSU32_NEW_KNODE: 360062306a36Sopenharmony_ci case TC_CLSU32_REPLACE_KNODE: 360162306a36Sopenharmony_ci return cxgb4_config_knode(dev, cls_u32); 360262306a36Sopenharmony_ci case TC_CLSU32_DELETE_KNODE: 360362306a36Sopenharmony_ci return cxgb4_delete_knode(dev, cls_u32); 360462306a36Sopenharmony_ci default: 360562306a36Sopenharmony_ci return -EOPNOTSUPP; 360662306a36Sopenharmony_ci } 360762306a36Sopenharmony_ci} 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_cistatic int cxgb_setup_tc_matchall(struct net_device *dev, 361062306a36Sopenharmony_ci struct tc_cls_matchall_offload *cls_matchall, 361162306a36Sopenharmony_ci bool ingress) 361262306a36Sopenharmony_ci{ 361362306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci if (!adap->tc_matchall) 361662306a36Sopenharmony_ci return -ENOMEM; 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci switch (cls_matchall->command) { 361962306a36Sopenharmony_ci case TC_CLSMATCHALL_REPLACE: 362062306a36Sopenharmony_ci return cxgb4_tc_matchall_replace(dev, cls_matchall, ingress); 362162306a36Sopenharmony_ci case TC_CLSMATCHALL_DESTROY: 362262306a36Sopenharmony_ci return cxgb4_tc_matchall_destroy(dev, cls_matchall, ingress); 362362306a36Sopenharmony_ci case TC_CLSMATCHALL_STATS: 362462306a36Sopenharmony_ci if (ingress) 362562306a36Sopenharmony_ci return cxgb4_tc_matchall_stats(dev, cls_matchall); 362662306a36Sopenharmony_ci break; 362762306a36Sopenharmony_ci default: 362862306a36Sopenharmony_ci break; 362962306a36Sopenharmony_ci } 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci return -EOPNOTSUPP; 363262306a36Sopenharmony_ci} 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_cistatic int cxgb_setup_tc_block_ingress_cb(enum tc_setup_type type, 363562306a36Sopenharmony_ci void *type_data, void *cb_priv) 363662306a36Sopenharmony_ci{ 363762306a36Sopenharmony_ci struct net_device *dev = cb_priv; 363862306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 363962306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { 364262306a36Sopenharmony_ci dev_err(adap->pdev_dev, 364362306a36Sopenharmony_ci "Failed to setup tc on port %d. Link Down?\n", 364462306a36Sopenharmony_ci pi->port_id); 364562306a36Sopenharmony_ci return -EINVAL; 364662306a36Sopenharmony_ci } 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(dev, type_data)) 364962306a36Sopenharmony_ci return -EOPNOTSUPP; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci switch (type) { 365262306a36Sopenharmony_ci case TC_SETUP_CLSU32: 365362306a36Sopenharmony_ci return cxgb_setup_tc_cls_u32(dev, type_data); 365462306a36Sopenharmony_ci case TC_SETUP_CLSFLOWER: 365562306a36Sopenharmony_ci return cxgb_setup_tc_flower(dev, type_data); 365662306a36Sopenharmony_ci case TC_SETUP_CLSMATCHALL: 365762306a36Sopenharmony_ci return cxgb_setup_tc_matchall(dev, type_data, true); 365862306a36Sopenharmony_ci default: 365962306a36Sopenharmony_ci return -EOPNOTSUPP; 366062306a36Sopenharmony_ci } 366162306a36Sopenharmony_ci} 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_cistatic int cxgb_setup_tc_block_egress_cb(enum tc_setup_type type, 366462306a36Sopenharmony_ci void *type_data, void *cb_priv) 366562306a36Sopenharmony_ci{ 366662306a36Sopenharmony_ci struct net_device *dev = cb_priv; 366762306a36Sopenharmony_ci struct port_info *pi = netdev2pinfo(dev); 366862306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { 367162306a36Sopenharmony_ci dev_err(adap->pdev_dev, 367262306a36Sopenharmony_ci "Failed to setup tc on port %d. Link Down?\n", 367362306a36Sopenharmony_ci pi->port_id); 367462306a36Sopenharmony_ci return -EINVAL; 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(dev, type_data)) 367862306a36Sopenharmony_ci return -EOPNOTSUPP; 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci switch (type) { 368162306a36Sopenharmony_ci case TC_SETUP_CLSMATCHALL: 368262306a36Sopenharmony_ci return cxgb_setup_tc_matchall(dev, type_data, false); 368362306a36Sopenharmony_ci default: 368462306a36Sopenharmony_ci break; 368562306a36Sopenharmony_ci } 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_ci return -EOPNOTSUPP; 368862306a36Sopenharmony_ci} 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_cistatic int cxgb_setup_tc_mqprio(struct net_device *dev, 369162306a36Sopenharmony_ci struct tc_mqprio_qopt_offload *mqprio) 369262306a36Sopenharmony_ci{ 369362306a36Sopenharmony_ci struct adapter *adap = netdev2adap(dev); 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci if (!is_ethofld(adap) || !adap->tc_mqprio) 369662306a36Sopenharmony_ci return -ENOMEM; 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci return cxgb4_setup_tc_mqprio(dev, mqprio); 369962306a36Sopenharmony_ci} 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_cistatic LIST_HEAD(cxgb_block_cb_list); 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_cistatic int cxgb_setup_tc_block(struct net_device *dev, 370462306a36Sopenharmony_ci struct flow_block_offload *f) 370562306a36Sopenharmony_ci{ 370662306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 370762306a36Sopenharmony_ci flow_setup_cb_t *cb; 370862306a36Sopenharmony_ci bool ingress_only; 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci pi->tc_block_shared = f->block_shared; 371162306a36Sopenharmony_ci if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) { 371262306a36Sopenharmony_ci cb = cxgb_setup_tc_block_egress_cb; 371362306a36Sopenharmony_ci ingress_only = false; 371462306a36Sopenharmony_ci } else { 371562306a36Sopenharmony_ci cb = cxgb_setup_tc_block_ingress_cb; 371662306a36Sopenharmony_ci ingress_only = true; 371762306a36Sopenharmony_ci } 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci return flow_block_cb_setup_simple(f, &cxgb_block_cb_list, 372062306a36Sopenharmony_ci cb, pi, dev, ingress_only); 372162306a36Sopenharmony_ci} 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_cistatic int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type, 372462306a36Sopenharmony_ci void *type_data) 372562306a36Sopenharmony_ci{ 372662306a36Sopenharmony_ci switch (type) { 372762306a36Sopenharmony_ci case TC_SETUP_QDISC_MQPRIO: 372862306a36Sopenharmony_ci return cxgb_setup_tc_mqprio(dev, type_data); 372962306a36Sopenharmony_ci case TC_SETUP_BLOCK: 373062306a36Sopenharmony_ci return cxgb_setup_tc_block(dev, type_data); 373162306a36Sopenharmony_ci default: 373262306a36Sopenharmony_ci return -EOPNOTSUPP; 373362306a36Sopenharmony_ci } 373462306a36Sopenharmony_ci} 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_cistatic int cxgb_udp_tunnel_unset_port(struct net_device *netdev, 373762306a36Sopenharmony_ci unsigned int table, unsigned int entry, 373862306a36Sopenharmony_ci struct udp_tunnel_info *ti) 373962306a36Sopenharmony_ci{ 374062306a36Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 374162306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 374262306a36Sopenharmony_ci u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 }; 374362306a36Sopenharmony_ci int ret = 0, i; 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci switch (ti->type) { 374662306a36Sopenharmony_ci case UDP_TUNNEL_TYPE_VXLAN: 374762306a36Sopenharmony_ci adapter->vxlan_port = 0; 374862306a36Sopenharmony_ci t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A, 0); 374962306a36Sopenharmony_ci break; 375062306a36Sopenharmony_ci case UDP_TUNNEL_TYPE_GENEVE: 375162306a36Sopenharmony_ci adapter->geneve_port = 0; 375262306a36Sopenharmony_ci t4_write_reg(adapter, MPS_RX_GENEVE_TYPE_A, 0); 375362306a36Sopenharmony_ci break; 375462306a36Sopenharmony_ci default: 375562306a36Sopenharmony_ci return -EINVAL; 375662306a36Sopenharmony_ci } 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci /* Matchall mac entries can be deleted only after all tunnel ports 375962306a36Sopenharmony_ci * are brought down or removed. 376062306a36Sopenharmony_ci */ 376162306a36Sopenharmony_ci if (!adapter->rawf_cnt) 376262306a36Sopenharmony_ci return 0; 376362306a36Sopenharmony_ci for_each_port(adapter, i) { 376462306a36Sopenharmony_ci pi = adap2pinfo(adapter, i); 376562306a36Sopenharmony_ci ret = t4_free_raw_mac_filt(adapter, pi->viid, 376662306a36Sopenharmony_ci match_all_mac, match_all_mac, 376762306a36Sopenharmony_ci adapter->rawf_start + pi->port_id, 376862306a36Sopenharmony_ci 1, pi->port_id, false); 376962306a36Sopenharmony_ci if (ret < 0) { 377062306a36Sopenharmony_ci netdev_info(netdev, "Failed to free mac filter entry, for port %d\n", 377162306a36Sopenharmony_ci i); 377262306a36Sopenharmony_ci return ret; 377362306a36Sopenharmony_ci } 377462306a36Sopenharmony_ci } 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_ci return 0; 377762306a36Sopenharmony_ci} 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_cistatic int cxgb_udp_tunnel_set_port(struct net_device *netdev, 378062306a36Sopenharmony_ci unsigned int table, unsigned int entry, 378162306a36Sopenharmony_ci struct udp_tunnel_info *ti) 378262306a36Sopenharmony_ci{ 378362306a36Sopenharmony_ci struct port_info *pi = netdev_priv(netdev); 378462306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 378562306a36Sopenharmony_ci u8 match_all_mac[] = { 0, 0, 0, 0, 0, 0 }; 378662306a36Sopenharmony_ci int i, ret; 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci switch (ti->type) { 378962306a36Sopenharmony_ci case UDP_TUNNEL_TYPE_VXLAN: 379062306a36Sopenharmony_ci adapter->vxlan_port = ti->port; 379162306a36Sopenharmony_ci t4_write_reg(adapter, MPS_RX_VXLAN_TYPE_A, 379262306a36Sopenharmony_ci VXLAN_V(be16_to_cpu(ti->port)) | VXLAN_EN_F); 379362306a36Sopenharmony_ci break; 379462306a36Sopenharmony_ci case UDP_TUNNEL_TYPE_GENEVE: 379562306a36Sopenharmony_ci adapter->geneve_port = ti->port; 379662306a36Sopenharmony_ci t4_write_reg(adapter, MPS_RX_GENEVE_TYPE_A, 379762306a36Sopenharmony_ci GENEVE_V(be16_to_cpu(ti->port)) | GENEVE_EN_F); 379862306a36Sopenharmony_ci break; 379962306a36Sopenharmony_ci default: 380062306a36Sopenharmony_ci return -EINVAL; 380162306a36Sopenharmony_ci } 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci /* Create a 'match all' mac filter entry for inner mac, 380462306a36Sopenharmony_ci * if raw mac interface is supported. Once the linux kernel provides 380562306a36Sopenharmony_ci * driver entry points for adding/deleting the inner mac addresses, 380662306a36Sopenharmony_ci * we will remove this 'match all' entry and fallback to adding 380762306a36Sopenharmony_ci * exact match filters. 380862306a36Sopenharmony_ci */ 380962306a36Sopenharmony_ci for_each_port(adapter, i) { 381062306a36Sopenharmony_ci pi = adap2pinfo(adapter, i); 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci ret = t4_alloc_raw_mac_filt(adapter, pi->viid, 381362306a36Sopenharmony_ci match_all_mac, 381462306a36Sopenharmony_ci match_all_mac, 381562306a36Sopenharmony_ci adapter->rawf_start + pi->port_id, 381662306a36Sopenharmony_ci 1, pi->port_id, false); 381762306a36Sopenharmony_ci if (ret < 0) { 381862306a36Sopenharmony_ci netdev_info(netdev, "Failed to allocate a mac filter entry, not adding port %d\n", 381962306a36Sopenharmony_ci be16_to_cpu(ti->port)); 382062306a36Sopenharmony_ci return ret; 382162306a36Sopenharmony_ci } 382262306a36Sopenharmony_ci } 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci return 0; 382562306a36Sopenharmony_ci} 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_cistatic const struct udp_tunnel_nic_info cxgb_udp_tunnels = { 382862306a36Sopenharmony_ci .set_port = cxgb_udp_tunnel_set_port, 382962306a36Sopenharmony_ci .unset_port = cxgb_udp_tunnel_unset_port, 383062306a36Sopenharmony_ci .tables = { 383162306a36Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 383262306a36Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, }, 383362306a36Sopenharmony_ci }, 383462306a36Sopenharmony_ci}; 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_cistatic netdev_features_t cxgb_features_check(struct sk_buff *skb, 383762306a36Sopenharmony_ci struct net_device *dev, 383862306a36Sopenharmony_ci netdev_features_t features) 383962306a36Sopenharmony_ci{ 384062306a36Sopenharmony_ci struct port_info *pi = netdev_priv(dev); 384162306a36Sopenharmony_ci struct adapter *adapter = pi->adapter; 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6) 384462306a36Sopenharmony_ci return features; 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci /* Check if hw supports offload for this packet */ 384762306a36Sopenharmony_ci if (!skb->encapsulation || cxgb_encap_offload_supported(skb)) 384862306a36Sopenharmony_ci return features; 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci /* Offload is not supported for this encapsulated packet */ 385162306a36Sopenharmony_ci return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 385262306a36Sopenharmony_ci} 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_cistatic netdev_features_t cxgb_fix_features(struct net_device *dev, 385562306a36Sopenharmony_ci netdev_features_t features) 385662306a36Sopenharmony_ci{ 385762306a36Sopenharmony_ci /* Disable GRO, if RX_CSUM is disabled */ 385862306a36Sopenharmony_ci if (!(features & NETIF_F_RXCSUM)) 385962306a36Sopenharmony_ci features &= ~NETIF_F_GRO; 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci return features; 386262306a36Sopenharmony_ci} 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_cistatic const struct net_device_ops cxgb4_netdev_ops = { 386562306a36Sopenharmony_ci .ndo_open = cxgb_open, 386662306a36Sopenharmony_ci .ndo_stop = cxgb_close, 386762306a36Sopenharmony_ci .ndo_start_xmit = t4_start_xmit, 386862306a36Sopenharmony_ci .ndo_select_queue = cxgb_select_queue, 386962306a36Sopenharmony_ci .ndo_get_stats64 = cxgb_get_stats, 387062306a36Sopenharmony_ci .ndo_set_rx_mode = cxgb_set_rxmode, 387162306a36Sopenharmony_ci .ndo_set_mac_address = cxgb_set_mac_addr, 387262306a36Sopenharmony_ci .ndo_set_features = cxgb_set_features, 387362306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 387462306a36Sopenharmony_ci .ndo_eth_ioctl = cxgb_ioctl, 387562306a36Sopenharmony_ci .ndo_change_mtu = cxgb_change_mtu, 387662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 387762306a36Sopenharmony_ci .ndo_poll_controller = cxgb_netpoll, 387862306a36Sopenharmony_ci#endif 387962306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_FCOE 388062306a36Sopenharmony_ci .ndo_fcoe_enable = cxgb_fcoe_enable, 388162306a36Sopenharmony_ci .ndo_fcoe_disable = cxgb_fcoe_disable, 388262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_T4_FCOE */ 388362306a36Sopenharmony_ci .ndo_set_tx_maxrate = cxgb_set_tx_maxrate, 388462306a36Sopenharmony_ci .ndo_setup_tc = cxgb_setup_tc, 388562306a36Sopenharmony_ci .ndo_features_check = cxgb_features_check, 388662306a36Sopenharmony_ci .ndo_fix_features = cxgb_fix_features, 388762306a36Sopenharmony_ci}; 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV 389062306a36Sopenharmony_cistatic const struct net_device_ops cxgb4_mgmt_netdev_ops = { 389162306a36Sopenharmony_ci .ndo_open = cxgb4_mgmt_open, 389262306a36Sopenharmony_ci .ndo_set_vf_mac = cxgb4_mgmt_set_vf_mac, 389362306a36Sopenharmony_ci .ndo_get_vf_config = cxgb4_mgmt_get_vf_config, 389462306a36Sopenharmony_ci .ndo_set_vf_rate = cxgb4_mgmt_set_vf_rate, 389562306a36Sopenharmony_ci .ndo_get_phys_port_id = cxgb4_mgmt_get_phys_port_id, 389662306a36Sopenharmony_ci .ndo_set_vf_vlan = cxgb4_mgmt_set_vf_vlan, 389762306a36Sopenharmony_ci .ndo_set_vf_link_state = cxgb4_mgmt_set_vf_link_state, 389862306a36Sopenharmony_ci}; 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_cistatic void cxgb4_mgmt_get_drvinfo(struct net_device *dev, 390162306a36Sopenharmony_ci struct ethtool_drvinfo *info) 390262306a36Sopenharmony_ci{ 390362306a36Sopenharmony_ci struct adapter *adapter = netdev2adap(dev); 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci strscpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); 390662306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(adapter->pdev), 390762306a36Sopenharmony_ci sizeof(info->bus_info)); 390862306a36Sopenharmony_ci} 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_cistatic const struct ethtool_ops cxgb4_mgmt_ethtool_ops = { 391162306a36Sopenharmony_ci .get_drvinfo = cxgb4_mgmt_get_drvinfo, 391262306a36Sopenharmony_ci}; 391362306a36Sopenharmony_ci#endif 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_cistatic void notify_fatal_err(struct work_struct *work) 391662306a36Sopenharmony_ci{ 391762306a36Sopenharmony_ci struct adapter *adap; 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci adap = container_of(work, struct adapter, fatal_err_notify_task); 392062306a36Sopenharmony_ci notify_ulds(adap, CXGB4_STATE_FATAL_ERROR); 392162306a36Sopenharmony_ci} 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_civoid t4_fatal_err(struct adapter *adap) 392462306a36Sopenharmony_ci{ 392562306a36Sopenharmony_ci int port; 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ci if (pci_channel_offline(adap->pdev)) 392862306a36Sopenharmony_ci return; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci /* Disable the SGE since ULDs are going to free resources that 393162306a36Sopenharmony_ci * could be exposed to the adapter. RDMA MWs for example... 393262306a36Sopenharmony_ci */ 393362306a36Sopenharmony_ci t4_shutdown_adapter(adap); 393462306a36Sopenharmony_ci for_each_port(adap, port) { 393562306a36Sopenharmony_ci struct net_device *dev = adap->port[port]; 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci /* If we get here in very early initialization the network 393862306a36Sopenharmony_ci * devices may not have been set up yet. 393962306a36Sopenharmony_ci */ 394062306a36Sopenharmony_ci if (!dev) 394162306a36Sopenharmony_ci continue; 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci netif_tx_stop_all_queues(dev); 394462306a36Sopenharmony_ci netif_carrier_off(dev); 394562306a36Sopenharmony_ci } 394662306a36Sopenharmony_ci dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); 394762306a36Sopenharmony_ci queue_work(adap->workq, &adap->fatal_err_notify_task); 394862306a36Sopenharmony_ci} 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_cistatic void setup_memwin(struct adapter *adap) 395162306a36Sopenharmony_ci{ 395262306a36Sopenharmony_ci u32 nic_win_base = t4_get_util_window(adap); 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci t4_setup_memwin(adap, nic_win_base, MEMWIN_NIC); 395562306a36Sopenharmony_ci} 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_cistatic void setup_memwin_rdma(struct adapter *adap) 395862306a36Sopenharmony_ci{ 395962306a36Sopenharmony_ci if (adap->vres.ocq.size) { 396062306a36Sopenharmony_ci u32 start; 396162306a36Sopenharmony_ci unsigned int sz_kb; 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ci start = t4_read_pcie_cfg4(adap, PCI_BASE_ADDRESS_2); 396462306a36Sopenharmony_ci start &= PCI_BASE_ADDRESS_MEM_MASK; 396562306a36Sopenharmony_ci start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres); 396662306a36Sopenharmony_ci sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; 396762306a36Sopenharmony_ci t4_write_reg(adap, 396862306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 3), 396962306a36Sopenharmony_ci start | BIR_V(1) | WINDOW_V(ilog2(sz_kb))); 397062306a36Sopenharmony_ci t4_write_reg(adap, 397162306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3), 397262306a36Sopenharmony_ci adap->vres.ocq.start); 397362306a36Sopenharmony_ci t4_read_reg(adap, 397462306a36Sopenharmony_ci PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3)); 397562306a36Sopenharmony_ci } 397662306a36Sopenharmony_ci} 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci/* HMA Definitions */ 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci/* The maximum number of address that can be send in a single FW cmd */ 398162306a36Sopenharmony_ci#define HMA_MAX_ADDR_IN_CMD 5 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci#define HMA_PAGE_SIZE PAGE_SIZE 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci#define HMA_MAX_NO_FW_ADDRESS (16 << 10) /* FW supports 16K addresses */ 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci#define HMA_PAGE_ORDER \ 398862306a36Sopenharmony_ci ((HMA_PAGE_SIZE < HMA_MAX_NO_FW_ADDRESS) ? \ 398962306a36Sopenharmony_ci ilog2(HMA_MAX_NO_FW_ADDRESS / HMA_PAGE_SIZE) : 0) 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci/* The minimum and maximum possible HMA sizes that can be specified in the FW 399262306a36Sopenharmony_ci * configuration(in units of MB). 399362306a36Sopenharmony_ci */ 399462306a36Sopenharmony_ci#define HMA_MIN_TOTAL_SIZE 1 399562306a36Sopenharmony_ci#define HMA_MAX_TOTAL_SIZE \ 399662306a36Sopenharmony_ci (((HMA_PAGE_SIZE << HMA_PAGE_ORDER) * \ 399762306a36Sopenharmony_ci HMA_MAX_NO_FW_ADDRESS) >> 20) 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_cistatic void adap_free_hma_mem(struct adapter *adapter) 400062306a36Sopenharmony_ci{ 400162306a36Sopenharmony_ci struct scatterlist *iter; 400262306a36Sopenharmony_ci struct page *page; 400362306a36Sopenharmony_ci int i; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci if (!adapter->hma.sgt) 400662306a36Sopenharmony_ci return; 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci if (adapter->hma.flags & HMA_DMA_MAPPED_FLAG) { 400962306a36Sopenharmony_ci dma_unmap_sg(adapter->pdev_dev, adapter->hma.sgt->sgl, 401062306a36Sopenharmony_ci adapter->hma.sgt->nents, DMA_BIDIRECTIONAL); 401162306a36Sopenharmony_ci adapter->hma.flags &= ~HMA_DMA_MAPPED_FLAG; 401262306a36Sopenharmony_ci } 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci for_each_sg(adapter->hma.sgt->sgl, iter, 401562306a36Sopenharmony_ci adapter->hma.sgt->orig_nents, i) { 401662306a36Sopenharmony_ci page = sg_page(iter); 401762306a36Sopenharmony_ci if (page) 401862306a36Sopenharmony_ci __free_pages(page, HMA_PAGE_ORDER); 401962306a36Sopenharmony_ci } 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci kfree(adapter->hma.phy_addr); 402262306a36Sopenharmony_ci sg_free_table(adapter->hma.sgt); 402362306a36Sopenharmony_ci kfree(adapter->hma.sgt); 402462306a36Sopenharmony_ci adapter->hma.sgt = NULL; 402562306a36Sopenharmony_ci} 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_cistatic int adap_config_hma(struct adapter *adapter) 402862306a36Sopenharmony_ci{ 402962306a36Sopenharmony_ci struct scatterlist *sgl, *iter; 403062306a36Sopenharmony_ci struct sg_table *sgt; 403162306a36Sopenharmony_ci struct page *newpage; 403262306a36Sopenharmony_ci unsigned int i, j, k; 403362306a36Sopenharmony_ci u32 param, hma_size; 403462306a36Sopenharmony_ci unsigned int ncmds; 403562306a36Sopenharmony_ci size_t page_size; 403662306a36Sopenharmony_ci u32 page_order; 403762306a36Sopenharmony_ci int node, ret; 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci /* HMA is supported only for T6+ cards. 404062306a36Sopenharmony_ci * Avoid initializing HMA in kdump kernels. 404162306a36Sopenharmony_ci */ 404262306a36Sopenharmony_ci if (is_kdump_kernel() || 404362306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(adapter->params.chip) < CHELSIO_T6) 404462306a36Sopenharmony_ci return 0; 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci /* Get the HMA region size required by fw */ 404762306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 404862306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HMA_SIZE)); 404962306a36Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, adapter->pf, 0, 405062306a36Sopenharmony_ci 1, ¶m, &hma_size); 405162306a36Sopenharmony_ci /* An error means card has its own memory or HMA is not supported by 405262306a36Sopenharmony_ci * the firmware. Return without any errors. 405362306a36Sopenharmony_ci */ 405462306a36Sopenharmony_ci if (ret || !hma_size) 405562306a36Sopenharmony_ci return 0; 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci if (hma_size < HMA_MIN_TOTAL_SIZE || 405862306a36Sopenharmony_ci hma_size > HMA_MAX_TOTAL_SIZE) { 405962306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 406062306a36Sopenharmony_ci "HMA size %uMB beyond bounds(%u-%lu)MB\n", 406162306a36Sopenharmony_ci hma_size, HMA_MIN_TOTAL_SIZE, HMA_MAX_TOTAL_SIZE); 406262306a36Sopenharmony_ci return -EINVAL; 406362306a36Sopenharmony_ci } 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_ci page_size = HMA_PAGE_SIZE; 406662306a36Sopenharmony_ci page_order = HMA_PAGE_ORDER; 406762306a36Sopenharmony_ci adapter->hma.sgt = kzalloc(sizeof(*adapter->hma.sgt), GFP_KERNEL); 406862306a36Sopenharmony_ci if (unlikely(!adapter->hma.sgt)) { 406962306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "HMA SG table allocation failed\n"); 407062306a36Sopenharmony_ci return -ENOMEM; 407162306a36Sopenharmony_ci } 407262306a36Sopenharmony_ci sgt = adapter->hma.sgt; 407362306a36Sopenharmony_ci /* FW returned value will be in MB's 407462306a36Sopenharmony_ci */ 407562306a36Sopenharmony_ci sgt->orig_nents = (hma_size << 20) / (page_size << page_order); 407662306a36Sopenharmony_ci if (sg_alloc_table(sgt, sgt->orig_nents, GFP_KERNEL)) { 407762306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "HMA SGL allocation failed\n"); 407862306a36Sopenharmony_ci kfree(adapter->hma.sgt); 407962306a36Sopenharmony_ci adapter->hma.sgt = NULL; 408062306a36Sopenharmony_ci return -ENOMEM; 408162306a36Sopenharmony_ci } 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci sgl = adapter->hma.sgt->sgl; 408462306a36Sopenharmony_ci node = dev_to_node(adapter->pdev_dev); 408562306a36Sopenharmony_ci for_each_sg(sgl, iter, sgt->orig_nents, i) { 408662306a36Sopenharmony_ci newpage = alloc_pages_node(node, __GFP_NOWARN | GFP_KERNEL | 408762306a36Sopenharmony_ci __GFP_ZERO, page_order); 408862306a36Sopenharmony_ci if (!newpage) { 408962306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 409062306a36Sopenharmony_ci "Not enough memory for HMA page allocation\n"); 409162306a36Sopenharmony_ci ret = -ENOMEM; 409262306a36Sopenharmony_ci goto free_hma; 409362306a36Sopenharmony_ci } 409462306a36Sopenharmony_ci sg_set_page(iter, newpage, page_size << page_order, 0); 409562306a36Sopenharmony_ci } 409662306a36Sopenharmony_ci 409762306a36Sopenharmony_ci sgt->nents = dma_map_sg(adapter->pdev_dev, sgl, sgt->orig_nents, 409862306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 409962306a36Sopenharmony_ci if (!sgt->nents) { 410062306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 410162306a36Sopenharmony_ci "Not enough memory for HMA DMA mapping"); 410262306a36Sopenharmony_ci ret = -ENOMEM; 410362306a36Sopenharmony_ci goto free_hma; 410462306a36Sopenharmony_ci } 410562306a36Sopenharmony_ci adapter->hma.flags |= HMA_DMA_MAPPED_FLAG; 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_ci adapter->hma.phy_addr = kcalloc(sgt->nents, sizeof(dma_addr_t), 410862306a36Sopenharmony_ci GFP_KERNEL); 410962306a36Sopenharmony_ci if (unlikely(!adapter->hma.phy_addr)) 411062306a36Sopenharmony_ci goto free_hma; 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci for_each_sg(sgl, iter, sgt->nents, i) { 411362306a36Sopenharmony_ci newpage = sg_page(iter); 411462306a36Sopenharmony_ci adapter->hma.phy_addr[i] = sg_dma_address(iter); 411562306a36Sopenharmony_ci } 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci ncmds = DIV_ROUND_UP(sgt->nents, HMA_MAX_ADDR_IN_CMD); 411862306a36Sopenharmony_ci /* Pass on the addresses to firmware */ 411962306a36Sopenharmony_ci for (i = 0, k = 0; i < ncmds; i++, k += HMA_MAX_ADDR_IN_CMD) { 412062306a36Sopenharmony_ci struct fw_hma_cmd hma_cmd; 412162306a36Sopenharmony_ci u8 naddr = HMA_MAX_ADDR_IN_CMD; 412262306a36Sopenharmony_ci u8 soc = 0, eoc = 0; 412362306a36Sopenharmony_ci u8 hma_mode = 1; /* Presently we support only Page table mode */ 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_ci soc = (i == 0) ? 1 : 0; 412662306a36Sopenharmony_ci eoc = (i == ncmds - 1) ? 1 : 0; 412762306a36Sopenharmony_ci 412862306a36Sopenharmony_ci /* For last cmd, set naddr corresponding to remaining 412962306a36Sopenharmony_ci * addresses 413062306a36Sopenharmony_ci */ 413162306a36Sopenharmony_ci if (i == ncmds - 1) { 413262306a36Sopenharmony_ci naddr = sgt->nents % HMA_MAX_ADDR_IN_CMD; 413362306a36Sopenharmony_ci naddr = naddr ? naddr : HMA_MAX_ADDR_IN_CMD; 413462306a36Sopenharmony_ci } 413562306a36Sopenharmony_ci memset(&hma_cmd, 0, sizeof(hma_cmd)); 413662306a36Sopenharmony_ci hma_cmd.op_pkd = htonl(FW_CMD_OP_V(FW_HMA_CMD) | 413762306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F); 413862306a36Sopenharmony_ci hma_cmd.retval_len16 = htonl(FW_LEN16(hma_cmd)); 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci hma_cmd.mode_to_pcie_params = 414162306a36Sopenharmony_ci htonl(FW_HMA_CMD_MODE_V(hma_mode) | 414262306a36Sopenharmony_ci FW_HMA_CMD_SOC_V(soc) | FW_HMA_CMD_EOC_V(eoc)); 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_ci /* HMA cmd size specified in MB's */ 414562306a36Sopenharmony_ci hma_cmd.naddr_size = 414662306a36Sopenharmony_ci htonl(FW_HMA_CMD_SIZE_V(hma_size) | 414762306a36Sopenharmony_ci FW_HMA_CMD_NADDR_V(naddr)); 414862306a36Sopenharmony_ci 414962306a36Sopenharmony_ci /* Total Page size specified in units of 4K */ 415062306a36Sopenharmony_ci hma_cmd.addr_size_pkd = 415162306a36Sopenharmony_ci htonl(FW_HMA_CMD_ADDR_SIZE_V 415262306a36Sopenharmony_ci ((page_size << page_order) >> 12)); 415362306a36Sopenharmony_ci 415462306a36Sopenharmony_ci /* Fill the 5 addresses */ 415562306a36Sopenharmony_ci for (j = 0; j < naddr; j++) { 415662306a36Sopenharmony_ci hma_cmd.phy_address[j] = 415762306a36Sopenharmony_ci cpu_to_be64(adapter->hma.phy_addr[j + k]); 415862306a36Sopenharmony_ci } 415962306a36Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &hma_cmd, 416062306a36Sopenharmony_ci sizeof(hma_cmd), &hma_cmd); 416162306a36Sopenharmony_ci if (ret) { 416262306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 416362306a36Sopenharmony_ci "HMA FW command failed with err %d\n", ret); 416462306a36Sopenharmony_ci goto free_hma; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci } 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci if (!ret) 416962306a36Sopenharmony_ci dev_info(adapter->pdev_dev, 417062306a36Sopenharmony_ci "Reserved %uMB host memory for HMA\n", hma_size); 417162306a36Sopenharmony_ci return ret; 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_cifree_hma: 417462306a36Sopenharmony_ci adap_free_hma_mem(adapter); 417562306a36Sopenharmony_ci return ret; 417662306a36Sopenharmony_ci} 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_cistatic int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) 417962306a36Sopenharmony_ci{ 418062306a36Sopenharmony_ci u32 v; 418162306a36Sopenharmony_ci int ret; 418262306a36Sopenharmony_ci 418362306a36Sopenharmony_ci /* Now that we've successfully configured and initialized the adapter 418462306a36Sopenharmony_ci * can ask the Firmware what resources it has provisioned for us. 418562306a36Sopenharmony_ci */ 418662306a36Sopenharmony_ci ret = t4_get_pfres(adap); 418762306a36Sopenharmony_ci if (ret) { 418862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 418962306a36Sopenharmony_ci "Unable to retrieve resource provisioning information\n"); 419062306a36Sopenharmony_ci return ret; 419162306a36Sopenharmony_ci } 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci /* get device capabilities */ 419462306a36Sopenharmony_ci memset(c, 0, sizeof(*c)); 419562306a36Sopenharmony_ci c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 419662306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F); 419762306a36Sopenharmony_ci c->cfvalid_to_len16 = htonl(FW_LEN16(*c)); 419862306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), c); 419962306a36Sopenharmony_ci if (ret < 0) 420062306a36Sopenharmony_ci return ret; 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_ci c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 420362306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_WRITE_F); 420462306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, c, sizeof(*c), NULL); 420562306a36Sopenharmony_ci if (ret < 0) 420662306a36Sopenharmony_ci return ret; 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ci ret = t4_config_glbl_rss(adap, adap->pf, 420962306a36Sopenharmony_ci FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, 421062306a36Sopenharmony_ci FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F | 421162306a36Sopenharmony_ci FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F); 421262306a36Sopenharmony_ci if (ret < 0) 421362306a36Sopenharmony_ci return ret; 421462306a36Sopenharmony_ci 421562306a36Sopenharmony_ci ret = t4_cfg_pfvf(adap, adap->mbox, adap->pf, 0, adap->sge.egr_sz, 64, 421662306a36Sopenharmony_ci MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, 421762306a36Sopenharmony_ci FW_CMD_CAP_PF); 421862306a36Sopenharmony_ci if (ret < 0) 421962306a36Sopenharmony_ci return ret; 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci t4_sge_init(adap); 422262306a36Sopenharmony_ci 422362306a36Sopenharmony_ci /* tweak some settings */ 422462306a36Sopenharmony_ci t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849); 422562306a36Sopenharmony_ci t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(PAGE_SHIFT - 12)); 422662306a36Sopenharmony_ci t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A); 422762306a36Sopenharmony_ci v = t4_read_reg(adap, TP_PIO_DATA_A); 422862306a36Sopenharmony_ci t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F); 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci /* first 4 Tx modulation queues point to consecutive Tx channels */ 423162306a36Sopenharmony_ci adap->params.tp.tx_modq_map = 0xE4; 423262306a36Sopenharmony_ci t4_write_reg(adap, TP_TX_MOD_QUEUE_REQ_MAP_A, 423362306a36Sopenharmony_ci TX_MOD_QUEUE_REQ_MAP_V(adap->params.tp.tx_modq_map)); 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_ci /* associate each Tx modulation queue with consecutive Tx channels */ 423662306a36Sopenharmony_ci v = 0x84218421; 423762306a36Sopenharmony_ci t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, 423862306a36Sopenharmony_ci &v, 1, TP_TX_SCHED_HDR_A); 423962306a36Sopenharmony_ci t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, 424062306a36Sopenharmony_ci &v, 1, TP_TX_SCHED_FIFO_A); 424162306a36Sopenharmony_ci t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, 424262306a36Sopenharmony_ci &v, 1, TP_TX_SCHED_PCMD_A); 424362306a36Sopenharmony_ci 424462306a36Sopenharmony_ci#define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */ 424562306a36Sopenharmony_ci if (is_offload(adap)) { 424662306a36Sopenharmony_ci t4_write_reg(adap, TP_TX_MOD_QUEUE_WEIGHT0_A, 424762306a36Sopenharmony_ci TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 424862306a36Sopenharmony_ci TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 424962306a36Sopenharmony_ci TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 425062306a36Sopenharmony_ci TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); 425162306a36Sopenharmony_ci t4_write_reg(adap, TP_TX_MOD_CHANNEL_WEIGHT_A, 425262306a36Sopenharmony_ci TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 425362306a36Sopenharmony_ci TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 425462306a36Sopenharmony_ci TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) | 425562306a36Sopenharmony_ci TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT)); 425662306a36Sopenharmony_ci } 425762306a36Sopenharmony_ci 425862306a36Sopenharmony_ci /* get basic stuff going */ 425962306a36Sopenharmony_ci return t4_early_init(adap, adap->pf); 426062306a36Sopenharmony_ci} 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci/* 426362306a36Sopenharmony_ci * Max # of ATIDs. The absolute HW max is 16K but we keep it lower. 426462306a36Sopenharmony_ci */ 426562306a36Sopenharmony_ci#define MAX_ATIDS 8192U 426662306a36Sopenharmony_ci 426762306a36Sopenharmony_ci/* 426862306a36Sopenharmony_ci * Phase 0 of initialization: contact FW, obtain config, perform basic init. 426962306a36Sopenharmony_ci * 427062306a36Sopenharmony_ci * If the firmware we're dealing with has Configuration File support, then 427162306a36Sopenharmony_ci * we use that to perform all configuration 427262306a36Sopenharmony_ci */ 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci/* 427562306a36Sopenharmony_ci * Tweak configuration based on module parameters, etc. Most of these have 427662306a36Sopenharmony_ci * defaults assigned to them by Firmware Configuration Files (if we're using 427762306a36Sopenharmony_ci * them) but need to be explicitly set if we're using hard-coded 427862306a36Sopenharmony_ci * initialization. But even in the case of using Firmware Configuration 427962306a36Sopenharmony_ci * Files, we'd like to expose the ability to change these via module 428062306a36Sopenharmony_ci * parameters so these are essentially common tweaks/settings for 428162306a36Sopenharmony_ci * Configuration Files and hard-coded initialization ... 428262306a36Sopenharmony_ci */ 428362306a36Sopenharmony_cistatic int adap_init0_tweaks(struct adapter *adapter) 428462306a36Sopenharmony_ci{ 428562306a36Sopenharmony_ci /* 428662306a36Sopenharmony_ci * Fix up various Host-Dependent Parameters like Page Size, Cache 428762306a36Sopenharmony_ci * Line Size, etc. The firmware default is for a 4KB Page Size and 428862306a36Sopenharmony_ci * 64B Cache Line Size ... 428962306a36Sopenharmony_ci */ 429062306a36Sopenharmony_ci t4_fixup_host_params(adapter, PAGE_SIZE, L1_CACHE_BYTES); 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_ci /* 429362306a36Sopenharmony_ci * Process module parameters which affect early initialization. 429462306a36Sopenharmony_ci */ 429562306a36Sopenharmony_ci if (rx_dma_offset != 2 && rx_dma_offset != 0) { 429662306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 429762306a36Sopenharmony_ci "Ignoring illegal rx_dma_offset=%d, using 2\n", 429862306a36Sopenharmony_ci rx_dma_offset); 429962306a36Sopenharmony_ci rx_dma_offset = 2; 430062306a36Sopenharmony_ci } 430162306a36Sopenharmony_ci t4_set_reg_field(adapter, SGE_CONTROL_A, 430262306a36Sopenharmony_ci PKTSHIFT_V(PKTSHIFT_M), 430362306a36Sopenharmony_ci PKTSHIFT_V(rx_dma_offset)); 430462306a36Sopenharmony_ci 430562306a36Sopenharmony_ci /* 430662306a36Sopenharmony_ci * Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux 430762306a36Sopenharmony_ci * adds the pseudo header itself. 430862306a36Sopenharmony_ci */ 430962306a36Sopenharmony_ci t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG_A, 431062306a36Sopenharmony_ci CSUM_HAS_PSEUDO_HDR_F, 0); 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_ci return 0; 431362306a36Sopenharmony_ci} 431462306a36Sopenharmony_ci 431562306a36Sopenharmony_ci/* 10Gb/s-BT PHY Support. chip-external 10Gb/s-BT PHYs are complex chips 431662306a36Sopenharmony_ci * unto themselves and they contain their own firmware to perform their 431762306a36Sopenharmony_ci * tasks ... 431862306a36Sopenharmony_ci */ 431962306a36Sopenharmony_cistatic int phy_aq1202_version(const u8 *phy_fw_data, 432062306a36Sopenharmony_ci size_t phy_fw_size) 432162306a36Sopenharmony_ci{ 432262306a36Sopenharmony_ci int offset; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci /* At offset 0x8 you're looking for the primary image's 432562306a36Sopenharmony_ci * starting offset which is 3 Bytes wide 432662306a36Sopenharmony_ci * 432762306a36Sopenharmony_ci * At offset 0xa of the primary image, you look for the offset 432862306a36Sopenharmony_ci * of the DRAM segment which is 3 Bytes wide. 432962306a36Sopenharmony_ci * 433062306a36Sopenharmony_ci * The FW version is at offset 0x27e of the DRAM and is 2 Bytes 433162306a36Sopenharmony_ci * wide 433262306a36Sopenharmony_ci */ 433362306a36Sopenharmony_ci #define be16(__p) (((__p)[0] << 8) | (__p)[1]) 433462306a36Sopenharmony_ci #define le16(__p) ((__p)[0] | ((__p)[1] << 8)) 433562306a36Sopenharmony_ci #define le24(__p) (le16(__p) | ((__p)[2] << 16)) 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_ci offset = le24(phy_fw_data + 0x8) << 12; 433862306a36Sopenharmony_ci offset = le24(phy_fw_data + offset + 0xa); 433962306a36Sopenharmony_ci return be16(phy_fw_data + offset + 0x27e); 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_ci #undef be16 434262306a36Sopenharmony_ci #undef le16 434362306a36Sopenharmony_ci #undef le24 434462306a36Sopenharmony_ci} 434562306a36Sopenharmony_ci 434662306a36Sopenharmony_cistatic struct info_10gbt_phy_fw { 434762306a36Sopenharmony_ci unsigned int phy_fw_id; /* PCI Device ID */ 434862306a36Sopenharmony_ci char *phy_fw_file; /* /lib/firmware/ PHY Firmware file */ 434962306a36Sopenharmony_ci int (*phy_fw_version)(const u8 *phy_fw_data, size_t phy_fw_size); 435062306a36Sopenharmony_ci int phy_flash; /* Has FLASH for PHY Firmware */ 435162306a36Sopenharmony_ci} phy_info_array[] = { 435262306a36Sopenharmony_ci { 435362306a36Sopenharmony_ci PHY_AQ1202_DEVICEID, 435462306a36Sopenharmony_ci PHY_AQ1202_FIRMWARE, 435562306a36Sopenharmony_ci phy_aq1202_version, 435662306a36Sopenharmony_ci 1, 435762306a36Sopenharmony_ci }, 435862306a36Sopenharmony_ci { 435962306a36Sopenharmony_ci PHY_BCM84834_DEVICEID, 436062306a36Sopenharmony_ci PHY_BCM84834_FIRMWARE, 436162306a36Sopenharmony_ci NULL, 436262306a36Sopenharmony_ci 0, 436362306a36Sopenharmony_ci }, 436462306a36Sopenharmony_ci { 0, NULL, NULL }, 436562306a36Sopenharmony_ci}; 436662306a36Sopenharmony_ci 436762306a36Sopenharmony_cistatic struct info_10gbt_phy_fw *find_phy_info(int devid) 436862306a36Sopenharmony_ci{ 436962306a36Sopenharmony_ci int i; 437062306a36Sopenharmony_ci 437162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(phy_info_array); i++) { 437262306a36Sopenharmony_ci if (phy_info_array[i].phy_fw_id == devid) 437362306a36Sopenharmony_ci return &phy_info_array[i]; 437462306a36Sopenharmony_ci } 437562306a36Sopenharmony_ci return NULL; 437662306a36Sopenharmony_ci} 437762306a36Sopenharmony_ci 437862306a36Sopenharmony_ci/* Handle updating of chip-external 10Gb/s-BT PHY firmware. This needs to 437962306a36Sopenharmony_ci * happen after the FW_RESET_CMD but before the FW_INITIALIZE_CMD. On error 438062306a36Sopenharmony_ci * we return a negative error number. If we transfer new firmware we return 1 438162306a36Sopenharmony_ci * (from t4_load_phy_fw()). If we don't do anything we return 0. 438262306a36Sopenharmony_ci */ 438362306a36Sopenharmony_cistatic int adap_init0_phy(struct adapter *adap) 438462306a36Sopenharmony_ci{ 438562306a36Sopenharmony_ci const struct firmware *phyf; 438662306a36Sopenharmony_ci int ret; 438762306a36Sopenharmony_ci struct info_10gbt_phy_fw *phy_info; 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_ci /* Use the device ID to determine which PHY file to flash. 439062306a36Sopenharmony_ci */ 439162306a36Sopenharmony_ci phy_info = find_phy_info(adap->pdev->device); 439262306a36Sopenharmony_ci if (!phy_info) { 439362306a36Sopenharmony_ci dev_warn(adap->pdev_dev, 439462306a36Sopenharmony_ci "No PHY Firmware file found for this PHY\n"); 439562306a36Sopenharmony_ci return -EOPNOTSUPP; 439662306a36Sopenharmony_ci } 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_ci /* If we have a T4 PHY firmware file under /lib/firmware/cxgb4/, then 439962306a36Sopenharmony_ci * use that. The adapter firmware provides us with a memory buffer 440062306a36Sopenharmony_ci * where we can load a PHY firmware file from the host if we want to 440162306a36Sopenharmony_ci * override the PHY firmware File in flash. 440262306a36Sopenharmony_ci */ 440362306a36Sopenharmony_ci ret = request_firmware_direct(&phyf, phy_info->phy_fw_file, 440462306a36Sopenharmony_ci adap->pdev_dev); 440562306a36Sopenharmony_ci if (ret < 0) { 440662306a36Sopenharmony_ci /* For adapters without FLASH attached to PHY for their 440762306a36Sopenharmony_ci * firmware, it's obviously a fatal error if we can't get the 440862306a36Sopenharmony_ci * firmware to the adapter. For adapters with PHY firmware 440962306a36Sopenharmony_ci * FLASH storage, it's worth a warning if we can't find the 441062306a36Sopenharmony_ci * PHY Firmware but we'll neuter the error ... 441162306a36Sopenharmony_ci */ 441262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "unable to find PHY Firmware image " 441362306a36Sopenharmony_ci "/lib/firmware/%s, error %d\n", 441462306a36Sopenharmony_ci phy_info->phy_fw_file, -ret); 441562306a36Sopenharmony_ci if (phy_info->phy_flash) { 441662306a36Sopenharmony_ci int cur_phy_fw_ver = 0; 441762306a36Sopenharmony_ci 441862306a36Sopenharmony_ci t4_phy_fw_ver(adap, &cur_phy_fw_ver); 441962306a36Sopenharmony_ci dev_warn(adap->pdev_dev, "continuing with, on-adapter " 442062306a36Sopenharmony_ci "FLASH copy, version %#x\n", cur_phy_fw_ver); 442162306a36Sopenharmony_ci ret = 0; 442262306a36Sopenharmony_ci } 442362306a36Sopenharmony_ci 442462306a36Sopenharmony_ci return ret; 442562306a36Sopenharmony_ci } 442662306a36Sopenharmony_ci 442762306a36Sopenharmony_ci /* Load PHY Firmware onto adapter. 442862306a36Sopenharmony_ci */ 442962306a36Sopenharmony_ci ret = t4_load_phy_fw(adap, MEMWIN_NIC, phy_info->phy_fw_version, 443062306a36Sopenharmony_ci (u8 *)phyf->data, phyf->size); 443162306a36Sopenharmony_ci if (ret < 0) 443262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "PHY Firmware transfer error %d\n", 443362306a36Sopenharmony_ci -ret); 443462306a36Sopenharmony_ci else if (ret > 0) { 443562306a36Sopenharmony_ci int new_phy_fw_ver = 0; 443662306a36Sopenharmony_ci 443762306a36Sopenharmony_ci if (phy_info->phy_fw_version) 443862306a36Sopenharmony_ci new_phy_fw_ver = phy_info->phy_fw_version(phyf->data, 443962306a36Sopenharmony_ci phyf->size); 444062306a36Sopenharmony_ci dev_info(adap->pdev_dev, "Successfully transferred PHY " 444162306a36Sopenharmony_ci "Firmware /lib/firmware/%s, version %#x\n", 444262306a36Sopenharmony_ci phy_info->phy_fw_file, new_phy_fw_ver); 444362306a36Sopenharmony_ci } 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci release_firmware(phyf); 444662306a36Sopenharmony_ci 444762306a36Sopenharmony_ci return ret; 444862306a36Sopenharmony_ci} 444962306a36Sopenharmony_ci 445062306a36Sopenharmony_ci/* 445162306a36Sopenharmony_ci * Attempt to initialize the adapter via a Firmware Configuration File. 445262306a36Sopenharmony_ci */ 445362306a36Sopenharmony_cistatic int adap_init0_config(struct adapter *adapter, int reset) 445462306a36Sopenharmony_ci{ 445562306a36Sopenharmony_ci char *fw_config_file, fw_config_file_path[256]; 445662306a36Sopenharmony_ci u32 finiver, finicsum, cfcsum, param, val; 445762306a36Sopenharmony_ci struct fw_caps_config_cmd caps_cmd; 445862306a36Sopenharmony_ci unsigned long mtype = 0, maddr = 0; 445962306a36Sopenharmony_ci const struct firmware *cf; 446062306a36Sopenharmony_ci char *config_name = NULL; 446162306a36Sopenharmony_ci int config_issued = 0; 446262306a36Sopenharmony_ci int ret; 446362306a36Sopenharmony_ci 446462306a36Sopenharmony_ci /* 446562306a36Sopenharmony_ci * Reset device if necessary. 446662306a36Sopenharmony_ci */ 446762306a36Sopenharmony_ci if (reset) { 446862306a36Sopenharmony_ci ret = t4_fw_reset(adapter, adapter->mbox, 446962306a36Sopenharmony_ci PIORSTMODE_F | PIORST_F); 447062306a36Sopenharmony_ci if (ret < 0) 447162306a36Sopenharmony_ci goto bye; 447262306a36Sopenharmony_ci } 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci /* If this is a 10Gb/s-BT adapter make sure the chip-external 447562306a36Sopenharmony_ci * 10Gb/s-BT PHYs have up-to-date firmware. Note that this step needs 447662306a36Sopenharmony_ci * to be performed after any global adapter RESET above since some 447762306a36Sopenharmony_ci * PHYs only have local RAM copies of the PHY firmware. 447862306a36Sopenharmony_ci */ 447962306a36Sopenharmony_ci if (is_10gbt_device(adapter->pdev->device)) { 448062306a36Sopenharmony_ci ret = adap_init0_phy(adapter); 448162306a36Sopenharmony_ci if (ret < 0) 448262306a36Sopenharmony_ci goto bye; 448362306a36Sopenharmony_ci } 448462306a36Sopenharmony_ci /* 448562306a36Sopenharmony_ci * If we have a T4 configuration file under /lib/firmware/cxgb4/, 448662306a36Sopenharmony_ci * then use that. Otherwise, use the configuration file stored 448762306a36Sopenharmony_ci * in the adapter flash ... 448862306a36Sopenharmony_ci */ 448962306a36Sopenharmony_ci switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { 449062306a36Sopenharmony_ci case CHELSIO_T4: 449162306a36Sopenharmony_ci fw_config_file = FW4_CFNAME; 449262306a36Sopenharmony_ci break; 449362306a36Sopenharmony_ci case CHELSIO_T5: 449462306a36Sopenharmony_ci fw_config_file = FW5_CFNAME; 449562306a36Sopenharmony_ci break; 449662306a36Sopenharmony_ci case CHELSIO_T6: 449762306a36Sopenharmony_ci fw_config_file = FW6_CFNAME; 449862306a36Sopenharmony_ci break; 449962306a36Sopenharmony_ci default: 450062306a36Sopenharmony_ci dev_err(adapter->pdev_dev, "Device %d is not supported\n", 450162306a36Sopenharmony_ci adapter->pdev->device); 450262306a36Sopenharmony_ci ret = -EINVAL; 450362306a36Sopenharmony_ci goto bye; 450462306a36Sopenharmony_ci } 450562306a36Sopenharmony_ci 450662306a36Sopenharmony_ci ret = request_firmware(&cf, fw_config_file, adapter->pdev_dev); 450762306a36Sopenharmony_ci if (ret < 0) { 450862306a36Sopenharmony_ci config_name = "On FLASH"; 450962306a36Sopenharmony_ci mtype = FW_MEMTYPE_CF_FLASH; 451062306a36Sopenharmony_ci maddr = t4_flash_cfg_addr(adapter); 451162306a36Sopenharmony_ci } else { 451262306a36Sopenharmony_ci u32 params[7], val[7]; 451362306a36Sopenharmony_ci 451462306a36Sopenharmony_ci sprintf(fw_config_file_path, 451562306a36Sopenharmony_ci "/lib/firmware/%s", fw_config_file); 451662306a36Sopenharmony_ci config_name = fw_config_file_path; 451762306a36Sopenharmony_ci 451862306a36Sopenharmony_ci if (cf->size >= FLASH_CFG_MAX_SIZE) 451962306a36Sopenharmony_ci ret = -ENOMEM; 452062306a36Sopenharmony_ci else { 452162306a36Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 452262306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); 452362306a36Sopenharmony_ci ret = t4_query_params(adapter, adapter->mbox, 452462306a36Sopenharmony_ci adapter->pf, 0, 1, params, val); 452562306a36Sopenharmony_ci if (ret == 0) { 452662306a36Sopenharmony_ci /* 452762306a36Sopenharmony_ci * For t4_memory_rw() below addresses and 452862306a36Sopenharmony_ci * sizes have to be in terms of multiples of 4 452962306a36Sopenharmony_ci * bytes. So, if the Configuration File isn't 453062306a36Sopenharmony_ci * a multiple of 4 bytes in length we'll have 453162306a36Sopenharmony_ci * to write that out separately since we can't 453262306a36Sopenharmony_ci * guarantee that the bytes following the 453362306a36Sopenharmony_ci * residual byte in the buffer returned by 453462306a36Sopenharmony_ci * request_firmware() are zeroed out ... 453562306a36Sopenharmony_ci */ 453662306a36Sopenharmony_ci size_t resid = cf->size & 0x3; 453762306a36Sopenharmony_ci size_t size = cf->size & ~0x3; 453862306a36Sopenharmony_ci __be32 *data = (__be32 *)cf->data; 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci mtype = FW_PARAMS_PARAM_Y_G(val[0]); 454162306a36Sopenharmony_ci maddr = FW_PARAMS_PARAM_Z_G(val[0]) << 16; 454262306a36Sopenharmony_ci 454362306a36Sopenharmony_ci spin_lock(&adapter->win0_lock); 454462306a36Sopenharmony_ci ret = t4_memory_rw(adapter, 0, mtype, maddr, 454562306a36Sopenharmony_ci size, data, T4_MEMORY_WRITE); 454662306a36Sopenharmony_ci if (ret == 0 && resid != 0) { 454762306a36Sopenharmony_ci union { 454862306a36Sopenharmony_ci __be32 word; 454962306a36Sopenharmony_ci char buf[4]; 455062306a36Sopenharmony_ci } last; 455162306a36Sopenharmony_ci int i; 455262306a36Sopenharmony_ci 455362306a36Sopenharmony_ci last.word = data[size >> 2]; 455462306a36Sopenharmony_ci for (i = resid; i < 4; i++) 455562306a36Sopenharmony_ci last.buf[i] = 0; 455662306a36Sopenharmony_ci ret = t4_memory_rw(adapter, 0, mtype, 455762306a36Sopenharmony_ci maddr + size, 455862306a36Sopenharmony_ci 4, &last.word, 455962306a36Sopenharmony_ci T4_MEMORY_WRITE); 456062306a36Sopenharmony_ci } 456162306a36Sopenharmony_ci spin_unlock(&adapter->win0_lock); 456262306a36Sopenharmony_ci } 456362306a36Sopenharmony_ci } 456462306a36Sopenharmony_ci 456562306a36Sopenharmony_ci release_firmware(cf); 456662306a36Sopenharmony_ci if (ret) 456762306a36Sopenharmony_ci goto bye; 456862306a36Sopenharmony_ci } 456962306a36Sopenharmony_ci 457062306a36Sopenharmony_ci val = 0; 457162306a36Sopenharmony_ci 457262306a36Sopenharmony_ci /* Ofld + Hash filter is supported. Older fw will fail this request and 457362306a36Sopenharmony_ci * it is fine. 457462306a36Sopenharmony_ci */ 457562306a36Sopenharmony_ci param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 457662306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_HASHFILTER_WITH_OFLD)); 457762306a36Sopenharmony_ci ret = t4_set_params(adapter, adapter->mbox, adapter->pf, 0, 457862306a36Sopenharmony_ci 1, ¶m, &val); 457962306a36Sopenharmony_ci 458062306a36Sopenharmony_ci /* FW doesn't know about Hash filter + ofld support, 458162306a36Sopenharmony_ci * it's not a problem, don't return an error. 458262306a36Sopenharmony_ci */ 458362306a36Sopenharmony_ci if (ret < 0) { 458462306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, 458562306a36Sopenharmony_ci "Hash filter with ofld is not supported by FW\n"); 458662306a36Sopenharmony_ci } 458762306a36Sopenharmony_ci 458862306a36Sopenharmony_ci /* 458962306a36Sopenharmony_ci * Issue a Capability Configuration command to the firmware to get it 459062306a36Sopenharmony_ci * to parse the Configuration File. We don't use t4_fw_config_file() 459162306a36Sopenharmony_ci * because we want the ability to modify various features after we've 459262306a36Sopenharmony_ci * processed the configuration file ... 459362306a36Sopenharmony_ci */ 459462306a36Sopenharmony_ci memset(&caps_cmd, 0, sizeof(caps_cmd)); 459562306a36Sopenharmony_ci caps_cmd.op_to_write = 459662306a36Sopenharmony_ci htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 459762306a36Sopenharmony_ci FW_CMD_REQUEST_F | 459862306a36Sopenharmony_ci FW_CMD_READ_F); 459962306a36Sopenharmony_ci caps_cmd.cfvalid_to_len16 = 460062306a36Sopenharmony_ci htonl(FW_CAPS_CONFIG_CMD_CFVALID_F | 460162306a36Sopenharmony_ci FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) | 460262306a36Sopenharmony_ci FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) | 460362306a36Sopenharmony_ci FW_LEN16(caps_cmd)); 460462306a36Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), 460562306a36Sopenharmony_ci &caps_cmd); 460662306a36Sopenharmony_ci 460762306a36Sopenharmony_ci /* If the CAPS_CONFIG failed with an ENOENT (for a Firmware 460862306a36Sopenharmony_ci * Configuration File in FLASH), our last gasp effort is to use the 460962306a36Sopenharmony_ci * Firmware Configuration File which is embedded in the firmware. A 461062306a36Sopenharmony_ci * very few early versions of the firmware didn't have one embedded 461162306a36Sopenharmony_ci * but we can ignore those. 461262306a36Sopenharmony_ci */ 461362306a36Sopenharmony_ci if (ret == -ENOENT) { 461462306a36Sopenharmony_ci memset(&caps_cmd, 0, sizeof(caps_cmd)); 461562306a36Sopenharmony_ci caps_cmd.op_to_write = 461662306a36Sopenharmony_ci htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 461762306a36Sopenharmony_ci FW_CMD_REQUEST_F | 461862306a36Sopenharmony_ci FW_CMD_READ_F); 461962306a36Sopenharmony_ci caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); 462062306a36Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, 462162306a36Sopenharmony_ci sizeof(caps_cmd), &caps_cmd); 462262306a36Sopenharmony_ci config_name = "Firmware Default"; 462362306a36Sopenharmony_ci } 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_ci config_issued = 1; 462662306a36Sopenharmony_ci if (ret < 0) 462762306a36Sopenharmony_ci goto bye; 462862306a36Sopenharmony_ci 462962306a36Sopenharmony_ci finiver = ntohl(caps_cmd.finiver); 463062306a36Sopenharmony_ci finicsum = ntohl(caps_cmd.finicsum); 463162306a36Sopenharmony_ci cfcsum = ntohl(caps_cmd.cfcsum); 463262306a36Sopenharmony_ci if (finicsum != cfcsum) 463362306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "Configuration File checksum "\ 463462306a36Sopenharmony_ci "mismatch: [fini] csum=%#x, computed csum=%#x\n", 463562306a36Sopenharmony_ci finicsum, cfcsum); 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_ci /* 463862306a36Sopenharmony_ci * And now tell the firmware to use the configuration we just loaded. 463962306a36Sopenharmony_ci */ 464062306a36Sopenharmony_ci caps_cmd.op_to_write = 464162306a36Sopenharmony_ci htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 464262306a36Sopenharmony_ci FW_CMD_REQUEST_F | 464362306a36Sopenharmony_ci FW_CMD_WRITE_F); 464462306a36Sopenharmony_ci caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); 464562306a36Sopenharmony_ci ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd), 464662306a36Sopenharmony_ci NULL); 464762306a36Sopenharmony_ci if (ret < 0) 464862306a36Sopenharmony_ci goto bye; 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci /* 465162306a36Sopenharmony_ci * Tweak configuration based on system architecture, module 465262306a36Sopenharmony_ci * parameters, etc. 465362306a36Sopenharmony_ci */ 465462306a36Sopenharmony_ci ret = adap_init0_tweaks(adapter); 465562306a36Sopenharmony_ci if (ret < 0) 465662306a36Sopenharmony_ci goto bye; 465762306a36Sopenharmony_ci 465862306a36Sopenharmony_ci /* We will proceed even if HMA init fails. */ 465962306a36Sopenharmony_ci ret = adap_config_hma(adapter); 466062306a36Sopenharmony_ci if (ret) 466162306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 466262306a36Sopenharmony_ci "HMA configuration failed with error %d\n", ret); 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_ci if (is_t6(adapter->params.chip)) { 466562306a36Sopenharmony_ci adap_config_hpfilter(adapter); 466662306a36Sopenharmony_ci ret = setup_ppod_edram(adapter); 466762306a36Sopenharmony_ci if (!ret) 466862306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Successfully enabled " 466962306a36Sopenharmony_ci "ppod edram feature\n"); 467062306a36Sopenharmony_ci } 467162306a36Sopenharmony_ci 467262306a36Sopenharmony_ci /* 467362306a36Sopenharmony_ci * And finally tell the firmware to initialize itself using the 467462306a36Sopenharmony_ci * parameters from the Configuration File. 467562306a36Sopenharmony_ci */ 467662306a36Sopenharmony_ci ret = t4_fw_initialize(adapter, adapter->mbox); 467762306a36Sopenharmony_ci if (ret < 0) 467862306a36Sopenharmony_ci goto bye; 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci /* Emit Firmware Configuration File information and return 468162306a36Sopenharmony_ci * successfully. 468262306a36Sopenharmony_ci */ 468362306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\ 468462306a36Sopenharmony_ci "Configuration File \"%s\", version %#x, computed checksum %#x\n", 468562306a36Sopenharmony_ci config_name, finiver, cfcsum); 468662306a36Sopenharmony_ci return 0; 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci /* 468962306a36Sopenharmony_ci * Something bad happened. Return the error ... (If the "error" 469062306a36Sopenharmony_ci * is that there's no Configuration File on the adapter we don't 469162306a36Sopenharmony_ci * want to issue a warning since this is fairly common.) 469262306a36Sopenharmony_ci */ 469362306a36Sopenharmony_cibye: 469462306a36Sopenharmony_ci if (config_issued && ret != -ENOENT) 469562306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, "\"%s\" configuration file error %d\n", 469662306a36Sopenharmony_ci config_name, -ret); 469762306a36Sopenharmony_ci return ret; 469862306a36Sopenharmony_ci} 469962306a36Sopenharmony_ci 470062306a36Sopenharmony_cistatic struct fw_info fw_info_array[] = { 470162306a36Sopenharmony_ci { 470262306a36Sopenharmony_ci .chip = CHELSIO_T4, 470362306a36Sopenharmony_ci .fs_name = FW4_CFNAME, 470462306a36Sopenharmony_ci .fw_mod_name = FW4_FNAME, 470562306a36Sopenharmony_ci .fw_hdr = { 470662306a36Sopenharmony_ci .chip = FW_HDR_CHIP_T4, 470762306a36Sopenharmony_ci .fw_ver = __cpu_to_be32(FW_VERSION(T4)), 470862306a36Sopenharmony_ci .intfver_nic = FW_INTFVER(T4, NIC), 470962306a36Sopenharmony_ci .intfver_vnic = FW_INTFVER(T4, VNIC), 471062306a36Sopenharmony_ci .intfver_ri = FW_INTFVER(T4, RI), 471162306a36Sopenharmony_ci .intfver_iscsi = FW_INTFVER(T4, ISCSI), 471262306a36Sopenharmony_ci .intfver_fcoe = FW_INTFVER(T4, FCOE), 471362306a36Sopenharmony_ci }, 471462306a36Sopenharmony_ci }, { 471562306a36Sopenharmony_ci .chip = CHELSIO_T5, 471662306a36Sopenharmony_ci .fs_name = FW5_CFNAME, 471762306a36Sopenharmony_ci .fw_mod_name = FW5_FNAME, 471862306a36Sopenharmony_ci .fw_hdr = { 471962306a36Sopenharmony_ci .chip = FW_HDR_CHIP_T5, 472062306a36Sopenharmony_ci .fw_ver = __cpu_to_be32(FW_VERSION(T5)), 472162306a36Sopenharmony_ci .intfver_nic = FW_INTFVER(T5, NIC), 472262306a36Sopenharmony_ci .intfver_vnic = FW_INTFVER(T5, VNIC), 472362306a36Sopenharmony_ci .intfver_ri = FW_INTFVER(T5, RI), 472462306a36Sopenharmony_ci .intfver_iscsi = FW_INTFVER(T5, ISCSI), 472562306a36Sopenharmony_ci .intfver_fcoe = FW_INTFVER(T5, FCOE), 472662306a36Sopenharmony_ci }, 472762306a36Sopenharmony_ci }, { 472862306a36Sopenharmony_ci .chip = CHELSIO_T6, 472962306a36Sopenharmony_ci .fs_name = FW6_CFNAME, 473062306a36Sopenharmony_ci .fw_mod_name = FW6_FNAME, 473162306a36Sopenharmony_ci .fw_hdr = { 473262306a36Sopenharmony_ci .chip = FW_HDR_CHIP_T6, 473362306a36Sopenharmony_ci .fw_ver = __cpu_to_be32(FW_VERSION(T6)), 473462306a36Sopenharmony_ci .intfver_nic = FW_INTFVER(T6, NIC), 473562306a36Sopenharmony_ci .intfver_vnic = FW_INTFVER(T6, VNIC), 473662306a36Sopenharmony_ci .intfver_ofld = FW_INTFVER(T6, OFLD), 473762306a36Sopenharmony_ci .intfver_ri = FW_INTFVER(T6, RI), 473862306a36Sopenharmony_ci .intfver_iscsipdu = FW_INTFVER(T6, ISCSIPDU), 473962306a36Sopenharmony_ci .intfver_iscsi = FW_INTFVER(T6, ISCSI), 474062306a36Sopenharmony_ci .intfver_fcoepdu = FW_INTFVER(T6, FCOEPDU), 474162306a36Sopenharmony_ci .intfver_fcoe = FW_INTFVER(T6, FCOE), 474262306a36Sopenharmony_ci }, 474362306a36Sopenharmony_ci } 474462306a36Sopenharmony_ci 474562306a36Sopenharmony_ci}; 474662306a36Sopenharmony_ci 474762306a36Sopenharmony_cistatic struct fw_info *find_fw_info(int chip) 474862306a36Sopenharmony_ci{ 474962306a36Sopenharmony_ci int i; 475062306a36Sopenharmony_ci 475162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) { 475262306a36Sopenharmony_ci if (fw_info_array[i].chip == chip) 475362306a36Sopenharmony_ci return &fw_info_array[i]; 475462306a36Sopenharmony_ci } 475562306a36Sopenharmony_ci return NULL; 475662306a36Sopenharmony_ci} 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_ci/* 475962306a36Sopenharmony_ci * Phase 0 of initialization: contact FW, obtain config, perform basic init. 476062306a36Sopenharmony_ci */ 476162306a36Sopenharmony_cistatic int adap_init0(struct adapter *adap, int vpd_skip) 476262306a36Sopenharmony_ci{ 476362306a36Sopenharmony_ci struct fw_caps_config_cmd caps_cmd; 476462306a36Sopenharmony_ci u32 params[7], val[7]; 476562306a36Sopenharmony_ci enum dev_state state; 476662306a36Sopenharmony_ci u32 v, port_vec; 476762306a36Sopenharmony_ci int reset = 1; 476862306a36Sopenharmony_ci int ret; 476962306a36Sopenharmony_ci 477062306a36Sopenharmony_ci /* Grab Firmware Device Log parameters as early as possible so we have 477162306a36Sopenharmony_ci * access to it for debugging, etc. 477262306a36Sopenharmony_ci */ 477362306a36Sopenharmony_ci ret = t4_init_devlog_params(adap); 477462306a36Sopenharmony_ci if (ret < 0) 477562306a36Sopenharmony_ci return ret; 477662306a36Sopenharmony_ci 477762306a36Sopenharmony_ci /* Contact FW, advertising Master capability */ 477862306a36Sopenharmony_ci ret = t4_fw_hello(adap, adap->mbox, adap->mbox, 477962306a36Sopenharmony_ci is_kdump_kernel() ? MASTER_MUST : MASTER_MAY, &state); 478062306a36Sopenharmony_ci if (ret < 0) { 478162306a36Sopenharmony_ci dev_err(adap->pdev_dev, "could not connect to FW, error %d\n", 478262306a36Sopenharmony_ci ret); 478362306a36Sopenharmony_ci return ret; 478462306a36Sopenharmony_ci } 478562306a36Sopenharmony_ci if (ret == adap->mbox) 478662306a36Sopenharmony_ci adap->flags |= CXGB4_MASTER_PF; 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_ci /* 478962306a36Sopenharmony_ci * If we're the Master PF Driver and the device is uninitialized, 479062306a36Sopenharmony_ci * then let's consider upgrading the firmware ... (We always want 479162306a36Sopenharmony_ci * to check the firmware version number in order to A. get it for 479262306a36Sopenharmony_ci * later reporting and B. to warn if the currently loaded firmware 479362306a36Sopenharmony_ci * is excessively mismatched relative to the driver.) 479462306a36Sopenharmony_ci */ 479562306a36Sopenharmony_ci 479662306a36Sopenharmony_ci t4_get_version_info(adap); 479762306a36Sopenharmony_ci ret = t4_check_fw_version(adap); 479862306a36Sopenharmony_ci /* If firmware is too old (not supported by driver) force an update. */ 479962306a36Sopenharmony_ci if (ret) 480062306a36Sopenharmony_ci state = DEV_STATE_UNINIT; 480162306a36Sopenharmony_ci if ((adap->flags & CXGB4_MASTER_PF) && state != DEV_STATE_INIT) { 480262306a36Sopenharmony_ci struct fw_info *fw_info; 480362306a36Sopenharmony_ci struct fw_hdr *card_fw; 480462306a36Sopenharmony_ci const struct firmware *fw; 480562306a36Sopenharmony_ci const u8 *fw_data = NULL; 480662306a36Sopenharmony_ci unsigned int fw_size = 0; 480762306a36Sopenharmony_ci 480862306a36Sopenharmony_ci /* This is the firmware whose headers the driver was compiled 480962306a36Sopenharmony_ci * against 481062306a36Sopenharmony_ci */ 481162306a36Sopenharmony_ci fw_info = find_fw_info(CHELSIO_CHIP_VERSION(adap->params.chip)); 481262306a36Sopenharmony_ci if (fw_info == NULL) { 481362306a36Sopenharmony_ci dev_err(adap->pdev_dev, 481462306a36Sopenharmony_ci "unable to get firmware info for chip %d.\n", 481562306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(adap->params.chip)); 481662306a36Sopenharmony_ci return -EINVAL; 481762306a36Sopenharmony_ci } 481862306a36Sopenharmony_ci 481962306a36Sopenharmony_ci /* allocate memory to read the header of the firmware on the 482062306a36Sopenharmony_ci * card 482162306a36Sopenharmony_ci */ 482262306a36Sopenharmony_ci card_fw = kvzalloc(sizeof(*card_fw), GFP_KERNEL); 482362306a36Sopenharmony_ci if (!card_fw) { 482462306a36Sopenharmony_ci ret = -ENOMEM; 482562306a36Sopenharmony_ci goto bye; 482662306a36Sopenharmony_ci } 482762306a36Sopenharmony_ci 482862306a36Sopenharmony_ci /* Get FW from from /lib/firmware/ */ 482962306a36Sopenharmony_ci ret = request_firmware(&fw, fw_info->fw_mod_name, 483062306a36Sopenharmony_ci adap->pdev_dev); 483162306a36Sopenharmony_ci if (ret < 0) { 483262306a36Sopenharmony_ci dev_err(adap->pdev_dev, 483362306a36Sopenharmony_ci "unable to load firmware image %s, error %d\n", 483462306a36Sopenharmony_ci fw_info->fw_mod_name, ret); 483562306a36Sopenharmony_ci } else { 483662306a36Sopenharmony_ci fw_data = fw->data; 483762306a36Sopenharmony_ci fw_size = fw->size; 483862306a36Sopenharmony_ci } 483962306a36Sopenharmony_ci 484062306a36Sopenharmony_ci /* upgrade FW logic */ 484162306a36Sopenharmony_ci ret = t4_prep_fw(adap, fw_info, fw_data, fw_size, card_fw, 484262306a36Sopenharmony_ci state, &reset); 484362306a36Sopenharmony_ci 484462306a36Sopenharmony_ci /* Cleaning up */ 484562306a36Sopenharmony_ci release_firmware(fw); 484662306a36Sopenharmony_ci kvfree(card_fw); 484762306a36Sopenharmony_ci 484862306a36Sopenharmony_ci if (ret < 0) 484962306a36Sopenharmony_ci goto bye; 485062306a36Sopenharmony_ci } 485162306a36Sopenharmony_ci 485262306a36Sopenharmony_ci /* If the firmware is initialized already, emit a simply note to that 485362306a36Sopenharmony_ci * effect. Otherwise, it's time to try initializing the adapter. 485462306a36Sopenharmony_ci */ 485562306a36Sopenharmony_ci if (state == DEV_STATE_INIT) { 485662306a36Sopenharmony_ci ret = adap_config_hma(adap); 485762306a36Sopenharmony_ci if (ret) 485862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 485962306a36Sopenharmony_ci "HMA configuration failed with error %d\n", 486062306a36Sopenharmony_ci ret); 486162306a36Sopenharmony_ci dev_info(adap->pdev_dev, "Coming up as %s: "\ 486262306a36Sopenharmony_ci "Adapter already initialized\n", 486362306a36Sopenharmony_ci adap->flags & CXGB4_MASTER_PF ? "MASTER" : "SLAVE"); 486462306a36Sopenharmony_ci } else { 486562306a36Sopenharmony_ci dev_info(adap->pdev_dev, "Coming up as MASTER: "\ 486662306a36Sopenharmony_ci "Initializing adapter\n"); 486762306a36Sopenharmony_ci 486862306a36Sopenharmony_ci /* Find out whether we're dealing with a version of the 486962306a36Sopenharmony_ci * firmware which has configuration file support. 487062306a36Sopenharmony_ci */ 487162306a36Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 487262306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF)); 487362306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, 487462306a36Sopenharmony_ci params, val); 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_ci /* If the firmware doesn't support Configuration Files, 487762306a36Sopenharmony_ci * return an error. 487862306a36Sopenharmony_ci */ 487962306a36Sopenharmony_ci if (ret < 0) { 488062306a36Sopenharmony_ci dev_err(adap->pdev_dev, "firmware doesn't support " 488162306a36Sopenharmony_ci "Firmware Configuration Files\n"); 488262306a36Sopenharmony_ci goto bye; 488362306a36Sopenharmony_ci } 488462306a36Sopenharmony_ci 488562306a36Sopenharmony_ci /* The firmware provides us with a memory buffer where we can 488662306a36Sopenharmony_ci * load a Configuration File from the host if we want to 488762306a36Sopenharmony_ci * override the Configuration File in flash. 488862306a36Sopenharmony_ci */ 488962306a36Sopenharmony_ci ret = adap_init0_config(adap, reset); 489062306a36Sopenharmony_ci if (ret == -ENOENT) { 489162306a36Sopenharmony_ci dev_err(adap->pdev_dev, "no Configuration File " 489262306a36Sopenharmony_ci "present on adapter.\n"); 489362306a36Sopenharmony_ci goto bye; 489462306a36Sopenharmony_ci } 489562306a36Sopenharmony_ci if (ret < 0) { 489662306a36Sopenharmony_ci dev_err(adap->pdev_dev, "could not initialize " 489762306a36Sopenharmony_ci "adapter, error %d\n", -ret); 489862306a36Sopenharmony_ci goto bye; 489962306a36Sopenharmony_ci } 490062306a36Sopenharmony_ci } 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci /* Now that we've successfully configured and initialized the adapter 490362306a36Sopenharmony_ci * (or found it already initialized), we can ask the Firmware what 490462306a36Sopenharmony_ci * resources it has provisioned for us. 490562306a36Sopenharmony_ci */ 490662306a36Sopenharmony_ci ret = t4_get_pfres(adap); 490762306a36Sopenharmony_ci if (ret) { 490862306a36Sopenharmony_ci dev_err(adap->pdev_dev, 490962306a36Sopenharmony_ci "Unable to retrieve resource provisioning information\n"); 491062306a36Sopenharmony_ci goto bye; 491162306a36Sopenharmony_ci } 491262306a36Sopenharmony_ci 491362306a36Sopenharmony_ci /* Grab VPD parameters. This should be done after we establish a 491462306a36Sopenharmony_ci * connection to the firmware since some of the VPD parameters 491562306a36Sopenharmony_ci * (notably the Core Clock frequency) are retrieved via requests to 491662306a36Sopenharmony_ci * the firmware. On the other hand, we need these fairly early on 491762306a36Sopenharmony_ci * so we do this right after getting ahold of the firmware. 491862306a36Sopenharmony_ci * 491962306a36Sopenharmony_ci * We need to do this after initializing the adapter because someone 492062306a36Sopenharmony_ci * could have FLASHed a new VPD which won't be read by the firmware 492162306a36Sopenharmony_ci * until we do the RESET ... 492262306a36Sopenharmony_ci */ 492362306a36Sopenharmony_ci if (!vpd_skip) { 492462306a36Sopenharmony_ci ret = t4_get_vpd_params(adap, &adap->params.vpd); 492562306a36Sopenharmony_ci if (ret < 0) 492662306a36Sopenharmony_ci goto bye; 492762306a36Sopenharmony_ci } 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_ci /* Find out what ports are available to us. Note that we need to do 493062306a36Sopenharmony_ci * this before calling adap_init0_no_config() since it needs nports 493162306a36Sopenharmony_ci * and portvec ... 493262306a36Sopenharmony_ci */ 493362306a36Sopenharmony_ci v = 493462306a36Sopenharmony_ci FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 493562306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_PORTVEC); 493662306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, &v, &port_vec); 493762306a36Sopenharmony_ci if (ret < 0) 493862306a36Sopenharmony_ci goto bye; 493962306a36Sopenharmony_ci 494062306a36Sopenharmony_ci adap->params.nports = hweight32(port_vec); 494162306a36Sopenharmony_ci adap->params.portvec = port_vec; 494262306a36Sopenharmony_ci 494362306a36Sopenharmony_ci /* Give the SGE code a chance to pull in anything that it needs ... 494462306a36Sopenharmony_ci * Note that this must be called after we retrieve our VPD parameters 494562306a36Sopenharmony_ci * in order to know how to convert core ticks to seconds, etc. 494662306a36Sopenharmony_ci */ 494762306a36Sopenharmony_ci ret = t4_sge_init(adap); 494862306a36Sopenharmony_ci if (ret < 0) 494962306a36Sopenharmony_ci goto bye; 495062306a36Sopenharmony_ci 495162306a36Sopenharmony_ci /* Grab the SGE Doorbell Queue Timer values. If successful, that 495262306a36Sopenharmony_ci * indicates that the Firmware and Hardware support this. 495362306a36Sopenharmony_ci */ 495462306a36Sopenharmony_ci params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) | 495562306a36Sopenharmony_ci FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK)); 495662306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 495762306a36Sopenharmony_ci 1, params, val); 495862306a36Sopenharmony_ci 495962306a36Sopenharmony_ci if (!ret) { 496062306a36Sopenharmony_ci adap->sge.dbqtimer_tick = val[0]; 496162306a36Sopenharmony_ci ret = t4_read_sge_dbqtimers(adap, 496262306a36Sopenharmony_ci ARRAY_SIZE(adap->sge.dbqtimer_val), 496362306a36Sopenharmony_ci adap->sge.dbqtimer_val); 496462306a36Sopenharmony_ci } 496562306a36Sopenharmony_ci 496662306a36Sopenharmony_ci if (!ret) 496762306a36Sopenharmony_ci adap->flags |= CXGB4_SGE_DBQ_TIMER; 496862306a36Sopenharmony_ci 496962306a36Sopenharmony_ci if (is_bypass_device(adap->pdev->device)) 497062306a36Sopenharmony_ci adap->params.bypass = 1; 497162306a36Sopenharmony_ci 497262306a36Sopenharmony_ci /* 497362306a36Sopenharmony_ci * Grab some of our basic fundamental operating parameters. 497462306a36Sopenharmony_ci */ 497562306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(EQ_START); 497662306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(L2T_START); 497762306a36Sopenharmony_ci params[2] = FW_PARAM_PFVF(L2T_END); 497862306a36Sopenharmony_ci params[3] = FW_PARAM_PFVF(FILTER_START); 497962306a36Sopenharmony_ci params[4] = FW_PARAM_PFVF(FILTER_END); 498062306a36Sopenharmony_ci params[5] = FW_PARAM_PFVF(IQFLINT_START); 498162306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params, val); 498262306a36Sopenharmony_ci if (ret < 0) 498362306a36Sopenharmony_ci goto bye; 498462306a36Sopenharmony_ci adap->sge.egr_start = val[0]; 498562306a36Sopenharmony_ci adap->l2t_start = val[1]; 498662306a36Sopenharmony_ci adap->l2t_end = val[2]; 498762306a36Sopenharmony_ci adap->tids.ftid_base = val[3]; 498862306a36Sopenharmony_ci adap->tids.nftids = val[4] - val[3] + 1; 498962306a36Sopenharmony_ci adap->sge.ingr_start = val[5]; 499062306a36Sopenharmony_ci 499162306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) { 499262306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(HPFILTER_START); 499362306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(HPFILTER_END); 499462306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 499562306a36Sopenharmony_ci params, val); 499662306a36Sopenharmony_ci if (ret < 0) 499762306a36Sopenharmony_ci goto bye; 499862306a36Sopenharmony_ci 499962306a36Sopenharmony_ci adap->tids.hpftid_base = val[0]; 500062306a36Sopenharmony_ci adap->tids.nhpftids = val[1] - val[0] + 1; 500162306a36Sopenharmony_ci 500262306a36Sopenharmony_ci /* Read the raw mps entries. In T6, the last 2 tcam entries 500362306a36Sopenharmony_ci * are reserved for raw mac addresses (rawf = 2, one per port). 500462306a36Sopenharmony_ci */ 500562306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(RAWF_START); 500662306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(RAWF_END); 500762306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 500862306a36Sopenharmony_ci params, val); 500962306a36Sopenharmony_ci if (ret == 0) { 501062306a36Sopenharmony_ci adap->rawf_start = val[0]; 501162306a36Sopenharmony_ci adap->rawf_cnt = val[1] - val[0] + 1; 501262306a36Sopenharmony_ci } 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci adap->tids.tid_base = 501562306a36Sopenharmony_ci t4_read_reg(adap, LE_DB_ACTIVE_TABLE_START_INDEX_A); 501662306a36Sopenharmony_ci } 501762306a36Sopenharmony_ci 501862306a36Sopenharmony_ci /* qids (ingress/egress) returned from firmware can be anywhere 501962306a36Sopenharmony_ci * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END. 502062306a36Sopenharmony_ci * Hence driver needs to allocate memory for this range to 502162306a36Sopenharmony_ci * store the queue info. Get the highest IQFLINT/EQ index returned 502262306a36Sopenharmony_ci * in FW_EQ_*_CMD.alloc command. 502362306a36Sopenharmony_ci */ 502462306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(EQ_END); 502562306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(IQFLINT_END); 502662306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val); 502762306a36Sopenharmony_ci if (ret < 0) 502862306a36Sopenharmony_ci goto bye; 502962306a36Sopenharmony_ci adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1; 503062306a36Sopenharmony_ci adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1; 503162306a36Sopenharmony_ci 503262306a36Sopenharmony_ci adap->sge.egr_map = kcalloc(adap->sge.egr_sz, 503362306a36Sopenharmony_ci sizeof(*adap->sge.egr_map), GFP_KERNEL); 503462306a36Sopenharmony_ci if (!adap->sge.egr_map) { 503562306a36Sopenharmony_ci ret = -ENOMEM; 503662306a36Sopenharmony_ci goto bye; 503762306a36Sopenharmony_ci } 503862306a36Sopenharmony_ci 503962306a36Sopenharmony_ci adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz, 504062306a36Sopenharmony_ci sizeof(*adap->sge.ingr_map), GFP_KERNEL); 504162306a36Sopenharmony_ci if (!adap->sge.ingr_map) { 504262306a36Sopenharmony_ci ret = -ENOMEM; 504362306a36Sopenharmony_ci goto bye; 504462306a36Sopenharmony_ci } 504562306a36Sopenharmony_ci 504662306a36Sopenharmony_ci /* Allocate the memory for the vaious egress queue bitmaps 504762306a36Sopenharmony_ci * ie starving_fl, txq_maperr and blocked_fl. 504862306a36Sopenharmony_ci */ 504962306a36Sopenharmony_ci adap->sge.starving_fl = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL); 505062306a36Sopenharmony_ci if (!adap->sge.starving_fl) { 505162306a36Sopenharmony_ci ret = -ENOMEM; 505262306a36Sopenharmony_ci goto bye; 505362306a36Sopenharmony_ci } 505462306a36Sopenharmony_ci 505562306a36Sopenharmony_ci adap->sge.txq_maperr = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL); 505662306a36Sopenharmony_ci if (!adap->sge.txq_maperr) { 505762306a36Sopenharmony_ci ret = -ENOMEM; 505862306a36Sopenharmony_ci goto bye; 505962306a36Sopenharmony_ci } 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 506262306a36Sopenharmony_ci adap->sge.blocked_fl = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL); 506362306a36Sopenharmony_ci if (!adap->sge.blocked_fl) { 506462306a36Sopenharmony_ci ret = -ENOMEM; 506562306a36Sopenharmony_ci goto bye; 506662306a36Sopenharmony_ci } 506762306a36Sopenharmony_ci#endif 506862306a36Sopenharmony_ci 506962306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(CLIP_START); 507062306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(CLIP_END); 507162306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val); 507262306a36Sopenharmony_ci if (ret < 0) 507362306a36Sopenharmony_ci goto bye; 507462306a36Sopenharmony_ci adap->clipt_start = val[0]; 507562306a36Sopenharmony_ci adap->clipt_end = val[1]; 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_ci /* Get the supported number of traffic classes */ 507862306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(NUM_TM_CLASS); 507962306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, val); 508062306a36Sopenharmony_ci if (ret < 0) { 508162306a36Sopenharmony_ci /* We couldn't retrieve the number of Traffic Classes 508262306a36Sopenharmony_ci * supported by the hardware/firmware. So we hard 508362306a36Sopenharmony_ci * code it here. 508462306a36Sopenharmony_ci */ 508562306a36Sopenharmony_ci adap->params.nsched_cls = is_t4(adap->params.chip) ? 15 : 16; 508662306a36Sopenharmony_ci } else { 508762306a36Sopenharmony_ci adap->params.nsched_cls = val[0]; 508862306a36Sopenharmony_ci } 508962306a36Sopenharmony_ci 509062306a36Sopenharmony_ci /* query params related to active filter region */ 509162306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START); 509262306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END); 509362306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val); 509462306a36Sopenharmony_ci /* If Active filter size is set we enable establishing 509562306a36Sopenharmony_ci * offload connection through firmware work request 509662306a36Sopenharmony_ci */ 509762306a36Sopenharmony_ci if ((val[0] != val[1]) && (ret >= 0)) { 509862306a36Sopenharmony_ci adap->flags |= CXGB4_FW_OFLD_CONN; 509962306a36Sopenharmony_ci adap->tids.aftid_base = val[0]; 510062306a36Sopenharmony_ci adap->tids.aftid_end = val[1]; 510162306a36Sopenharmony_ci } 510262306a36Sopenharmony_ci 510362306a36Sopenharmony_ci /* If we're running on newer firmware, let it know that we're 510462306a36Sopenharmony_ci * prepared to deal with encapsulated CPL messages. Older 510562306a36Sopenharmony_ci * firmware won't understand this and we'll just get 510662306a36Sopenharmony_ci * unencapsulated messages ... 510762306a36Sopenharmony_ci */ 510862306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 510962306a36Sopenharmony_ci val[0] = 1; 511062306a36Sopenharmony_ci (void)t4_set_params(adap, adap->mbox, adap->pf, 0, 1, params, val); 511162306a36Sopenharmony_ci 511262306a36Sopenharmony_ci /* 511362306a36Sopenharmony_ci * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL 511462306a36Sopenharmony_ci * capability. Earlier versions of the firmware didn't have the 511562306a36Sopenharmony_ci * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no 511662306a36Sopenharmony_ci * permission to use ULPTX MEMWRITE DSGL. 511762306a36Sopenharmony_ci */ 511862306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 511962306a36Sopenharmony_ci adap->params.ulptx_memwrite_dsgl = false; 512062306a36Sopenharmony_ci } else { 512162306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL); 512262306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 512362306a36Sopenharmony_ci 1, params, val); 512462306a36Sopenharmony_ci adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0); 512562306a36Sopenharmony_ci } 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci /* See if FW supports FW_RI_FR_NSMR_TPTE_WR work request */ 512862306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(RI_FR_NSMR_TPTE_WR); 512962306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 513062306a36Sopenharmony_ci 1, params, val); 513162306a36Sopenharmony_ci adap->params.fr_nsmr_tpte_wr_support = (ret == 0 && val[0] != 0); 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci /* See if FW supports FW_FILTER2 work request */ 513462306a36Sopenharmony_ci if (is_t4(adap->params.chip)) { 513562306a36Sopenharmony_ci adap->params.filter2_wr_support = false; 513662306a36Sopenharmony_ci } else { 513762306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(FILTER2_WR); 513862306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 513962306a36Sopenharmony_ci 1, params, val); 514062306a36Sopenharmony_ci adap->params.filter2_wr_support = (ret == 0 && val[0] != 0); 514162306a36Sopenharmony_ci } 514262306a36Sopenharmony_ci 514362306a36Sopenharmony_ci /* Check if FW supports returning vin and smt index. 514462306a36Sopenharmony_ci * If this is not supported, driver will interpret 514562306a36Sopenharmony_ci * these values from viid. 514662306a36Sopenharmony_ci */ 514762306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(OPAQUE_VIID_SMT_EXTN); 514862306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 514962306a36Sopenharmony_ci 1, params, val); 515062306a36Sopenharmony_ci adap->params.viid_smt_extn_support = (ret == 0 && val[0] != 0); 515162306a36Sopenharmony_ci 515262306a36Sopenharmony_ci /* 515362306a36Sopenharmony_ci * Get device capabilities so we can determine what resources we need 515462306a36Sopenharmony_ci * to manage. 515562306a36Sopenharmony_ci */ 515662306a36Sopenharmony_ci memset(&caps_cmd, 0, sizeof(caps_cmd)); 515762306a36Sopenharmony_ci caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) | 515862306a36Sopenharmony_ci FW_CMD_REQUEST_F | FW_CMD_READ_F); 515962306a36Sopenharmony_ci caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd)); 516062306a36Sopenharmony_ci ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd), 516162306a36Sopenharmony_ci &caps_cmd); 516262306a36Sopenharmony_ci if (ret < 0) 516362306a36Sopenharmony_ci goto bye; 516462306a36Sopenharmony_ci 516562306a36Sopenharmony_ci /* hash filter has some mandatory register settings to be tested and for 516662306a36Sopenharmony_ci * that it needs to test whether offload is enabled or not, hence 516762306a36Sopenharmony_ci * checking and setting it here. 516862306a36Sopenharmony_ci */ 516962306a36Sopenharmony_ci if (caps_cmd.ofldcaps) 517062306a36Sopenharmony_ci adap->params.offload = 1; 517162306a36Sopenharmony_ci 517262306a36Sopenharmony_ci if (caps_cmd.ofldcaps || 517362306a36Sopenharmony_ci (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) || 517462306a36Sopenharmony_ci (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD))) { 517562306a36Sopenharmony_ci /* query offload-related parameters */ 517662306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(NTID); 517762306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(SERVER_START); 517862306a36Sopenharmony_ci params[2] = FW_PARAM_PFVF(SERVER_END); 517962306a36Sopenharmony_ci params[3] = FW_PARAM_PFVF(TDDP_START); 518062306a36Sopenharmony_ci params[4] = FW_PARAM_PFVF(TDDP_END); 518162306a36Sopenharmony_ci params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 518262306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, 518362306a36Sopenharmony_ci params, val); 518462306a36Sopenharmony_ci if (ret < 0) 518562306a36Sopenharmony_ci goto bye; 518662306a36Sopenharmony_ci adap->tids.ntids = val[0]; 518762306a36Sopenharmony_ci adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); 518862306a36Sopenharmony_ci adap->tids.stid_base = val[1]; 518962306a36Sopenharmony_ci adap->tids.nstids = val[2] - val[1] + 1; 519062306a36Sopenharmony_ci /* 519162306a36Sopenharmony_ci * Setup server filter region. Divide the available filter 519262306a36Sopenharmony_ci * region into two parts. Regular filters get 1/3rd and server 519362306a36Sopenharmony_ci * filters get 2/3rd part. This is only enabled if workarond 519462306a36Sopenharmony_ci * path is enabled. 519562306a36Sopenharmony_ci * 1. For regular filters. 519662306a36Sopenharmony_ci * 2. Server filter: This are special filters which are used 519762306a36Sopenharmony_ci * to redirect SYN packets to offload queue. 519862306a36Sopenharmony_ci */ 519962306a36Sopenharmony_ci if (adap->flags & CXGB4_FW_OFLD_CONN && !is_bypass(adap)) { 520062306a36Sopenharmony_ci adap->tids.sftid_base = adap->tids.ftid_base + 520162306a36Sopenharmony_ci DIV_ROUND_UP(adap->tids.nftids, 3); 520262306a36Sopenharmony_ci adap->tids.nsftids = adap->tids.nftids - 520362306a36Sopenharmony_ci DIV_ROUND_UP(adap->tids.nftids, 3); 520462306a36Sopenharmony_ci adap->tids.nftids = adap->tids.sftid_base - 520562306a36Sopenharmony_ci adap->tids.ftid_base; 520662306a36Sopenharmony_ci } 520762306a36Sopenharmony_ci adap->vres.ddp.start = val[3]; 520862306a36Sopenharmony_ci adap->vres.ddp.size = val[4] - val[3] + 1; 520962306a36Sopenharmony_ci adap->params.ofldq_wr_cred = val[5]; 521062306a36Sopenharmony_ci 521162306a36Sopenharmony_ci if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) { 521262306a36Sopenharmony_ci init_hash_filter(adap); 521362306a36Sopenharmony_ci } else { 521462306a36Sopenharmony_ci adap->num_ofld_uld += 1; 521562306a36Sopenharmony_ci } 521662306a36Sopenharmony_ci 521762306a36Sopenharmony_ci if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD)) { 521862306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(ETHOFLD_START); 521962306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(ETHOFLD_END); 522062306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 522162306a36Sopenharmony_ci params, val); 522262306a36Sopenharmony_ci if (!ret) { 522362306a36Sopenharmony_ci adap->tids.eotid_base = val[0]; 522462306a36Sopenharmony_ci adap->tids.neotids = min_t(u32, MAX_ATIDS, 522562306a36Sopenharmony_ci val[1] - val[0] + 1); 522662306a36Sopenharmony_ci adap->params.ethofld = 1; 522762306a36Sopenharmony_ci } 522862306a36Sopenharmony_ci } 522962306a36Sopenharmony_ci } 523062306a36Sopenharmony_ci if (caps_cmd.rdmacaps) { 523162306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(STAG_START); 523262306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(STAG_END); 523362306a36Sopenharmony_ci params[2] = FW_PARAM_PFVF(RQ_START); 523462306a36Sopenharmony_ci params[3] = FW_PARAM_PFVF(RQ_END); 523562306a36Sopenharmony_ci params[4] = FW_PARAM_PFVF(PBL_START); 523662306a36Sopenharmony_ci params[5] = FW_PARAM_PFVF(PBL_END); 523762306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, 523862306a36Sopenharmony_ci params, val); 523962306a36Sopenharmony_ci if (ret < 0) 524062306a36Sopenharmony_ci goto bye; 524162306a36Sopenharmony_ci adap->vres.stag.start = val[0]; 524262306a36Sopenharmony_ci adap->vres.stag.size = val[1] - val[0] + 1; 524362306a36Sopenharmony_ci adap->vres.rq.start = val[2]; 524462306a36Sopenharmony_ci adap->vres.rq.size = val[3] - val[2] + 1; 524562306a36Sopenharmony_ci adap->vres.pbl.start = val[4]; 524662306a36Sopenharmony_ci adap->vres.pbl.size = val[5] - val[4] + 1; 524762306a36Sopenharmony_ci 524862306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(SRQ_START); 524962306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(SRQ_END); 525062306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 525162306a36Sopenharmony_ci params, val); 525262306a36Sopenharmony_ci if (!ret) { 525362306a36Sopenharmony_ci adap->vres.srq.start = val[0]; 525462306a36Sopenharmony_ci adap->vres.srq.size = val[1] - val[0] + 1; 525562306a36Sopenharmony_ci } 525662306a36Sopenharmony_ci if (adap->vres.srq.size) { 525762306a36Sopenharmony_ci adap->srq = t4_init_srq(adap->vres.srq.size); 525862306a36Sopenharmony_ci if (!adap->srq) 525962306a36Sopenharmony_ci dev_warn(&adap->pdev->dev, "could not allocate SRQ, continuing\n"); 526062306a36Sopenharmony_ci } 526162306a36Sopenharmony_ci 526262306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(SQRQ_START); 526362306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(SQRQ_END); 526462306a36Sopenharmony_ci params[2] = FW_PARAM_PFVF(CQ_START); 526562306a36Sopenharmony_ci params[3] = FW_PARAM_PFVF(CQ_END); 526662306a36Sopenharmony_ci params[4] = FW_PARAM_PFVF(OCQ_START); 526762306a36Sopenharmony_ci params[5] = FW_PARAM_PFVF(OCQ_END); 526862306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 6, params, 526962306a36Sopenharmony_ci val); 527062306a36Sopenharmony_ci if (ret < 0) 527162306a36Sopenharmony_ci goto bye; 527262306a36Sopenharmony_ci adap->vres.qp.start = val[0]; 527362306a36Sopenharmony_ci adap->vres.qp.size = val[1] - val[0] + 1; 527462306a36Sopenharmony_ci adap->vres.cq.start = val[2]; 527562306a36Sopenharmony_ci adap->vres.cq.size = val[3] - val[2] + 1; 527662306a36Sopenharmony_ci adap->vres.ocq.start = val[4]; 527762306a36Sopenharmony_ci adap->vres.ocq.size = val[5] - val[4] + 1; 527862306a36Sopenharmony_ci 527962306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(MAXORDIRD_QP); 528062306a36Sopenharmony_ci params[1] = FW_PARAM_DEV(MAXIRD_ADAPTER); 528162306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, 528262306a36Sopenharmony_ci val); 528362306a36Sopenharmony_ci if (ret < 0) { 528462306a36Sopenharmony_ci adap->params.max_ordird_qp = 8; 528562306a36Sopenharmony_ci adap->params.max_ird_adapter = 32 * adap->tids.ntids; 528662306a36Sopenharmony_ci ret = 0; 528762306a36Sopenharmony_ci } else { 528862306a36Sopenharmony_ci adap->params.max_ordird_qp = val[0]; 528962306a36Sopenharmony_ci adap->params.max_ird_adapter = val[1]; 529062306a36Sopenharmony_ci } 529162306a36Sopenharmony_ci dev_info(adap->pdev_dev, 529262306a36Sopenharmony_ci "max_ordird_qp %d max_ird_adapter %d\n", 529362306a36Sopenharmony_ci adap->params.max_ordird_qp, 529462306a36Sopenharmony_ci adap->params.max_ird_adapter); 529562306a36Sopenharmony_ci 529662306a36Sopenharmony_ci /* Enable write_with_immediate if FW supports it */ 529762306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(RDMA_WRITE_WITH_IMM); 529862306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, 529962306a36Sopenharmony_ci val); 530062306a36Sopenharmony_ci adap->params.write_w_imm_support = (ret == 0 && val[0] != 0); 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_ci /* Enable write_cmpl if FW supports it */ 530362306a36Sopenharmony_ci params[0] = FW_PARAM_DEV(RI_WRITE_CMPL_WR); 530462306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, 530562306a36Sopenharmony_ci val); 530662306a36Sopenharmony_ci adap->params.write_cmpl_support = (ret == 0 && val[0] != 0); 530762306a36Sopenharmony_ci adap->num_ofld_uld += 2; 530862306a36Sopenharmony_ci } 530962306a36Sopenharmony_ci if (caps_cmd.iscsicaps) { 531062306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(ISCSI_START); 531162306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(ISCSI_END); 531262306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 531362306a36Sopenharmony_ci params, val); 531462306a36Sopenharmony_ci if (ret < 0) 531562306a36Sopenharmony_ci goto bye; 531662306a36Sopenharmony_ci adap->vres.iscsi.start = val[0]; 531762306a36Sopenharmony_ci adap->vres.iscsi.size = val[1] - val[0] + 1; 531862306a36Sopenharmony_ci if (is_t6(adap->params.chip)) { 531962306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(PPOD_EDRAM_START); 532062306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(PPOD_EDRAM_END); 532162306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, 532262306a36Sopenharmony_ci params, val); 532362306a36Sopenharmony_ci if (!ret) { 532462306a36Sopenharmony_ci adap->vres.ppod_edram.start = val[0]; 532562306a36Sopenharmony_ci adap->vres.ppod_edram.size = 532662306a36Sopenharmony_ci val[1] - val[0] + 1; 532762306a36Sopenharmony_ci 532862306a36Sopenharmony_ci dev_info(adap->pdev_dev, 532962306a36Sopenharmony_ci "ppod edram start 0x%x end 0x%x size 0x%x\n", 533062306a36Sopenharmony_ci val[0], val[1], 533162306a36Sopenharmony_ci adap->vres.ppod_edram.size); 533262306a36Sopenharmony_ci } 533362306a36Sopenharmony_ci } 533462306a36Sopenharmony_ci /* LIO target and cxgb4i initiaitor */ 533562306a36Sopenharmony_ci adap->num_ofld_uld += 2; 533662306a36Sopenharmony_ci } 533762306a36Sopenharmony_ci if (caps_cmd.cryptocaps) { 533862306a36Sopenharmony_ci if (ntohs(caps_cmd.cryptocaps) & 533962306a36Sopenharmony_ci FW_CAPS_CONFIG_CRYPTO_LOOKASIDE) { 534062306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(NCRYPTO_LOOKASIDE); 534162306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 534262306a36Sopenharmony_ci 2, params, val); 534362306a36Sopenharmony_ci if (ret < 0) { 534462306a36Sopenharmony_ci if (ret != -EINVAL) 534562306a36Sopenharmony_ci goto bye; 534662306a36Sopenharmony_ci } else { 534762306a36Sopenharmony_ci adap->vres.ncrypto_fc = val[0]; 534862306a36Sopenharmony_ci } 534962306a36Sopenharmony_ci adap->num_ofld_uld += 1; 535062306a36Sopenharmony_ci } 535162306a36Sopenharmony_ci if (ntohs(caps_cmd.cryptocaps) & 535262306a36Sopenharmony_ci FW_CAPS_CONFIG_TLS_INLINE) { 535362306a36Sopenharmony_ci params[0] = FW_PARAM_PFVF(TLS_START); 535462306a36Sopenharmony_ci params[1] = FW_PARAM_PFVF(TLS_END); 535562306a36Sopenharmony_ci ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 535662306a36Sopenharmony_ci 2, params, val); 535762306a36Sopenharmony_ci if (ret < 0) 535862306a36Sopenharmony_ci goto bye; 535962306a36Sopenharmony_ci adap->vres.key.start = val[0]; 536062306a36Sopenharmony_ci adap->vres.key.size = val[1] - val[0] + 1; 536162306a36Sopenharmony_ci adap->num_uld += 1; 536262306a36Sopenharmony_ci } 536362306a36Sopenharmony_ci adap->params.crypto = ntohs(caps_cmd.cryptocaps); 536462306a36Sopenharmony_ci } 536562306a36Sopenharmony_ci 536662306a36Sopenharmony_ci /* The MTU/MSS Table is initialized by now, so load their values. If 536762306a36Sopenharmony_ci * we're initializing the adapter, then we'll make any modifications 536862306a36Sopenharmony_ci * we want to the MTU/MSS Table and also initialize the congestion 536962306a36Sopenharmony_ci * parameters. 537062306a36Sopenharmony_ci */ 537162306a36Sopenharmony_ci t4_read_mtu_tbl(adap, adap->params.mtus, NULL); 537262306a36Sopenharmony_ci if (state != DEV_STATE_INIT) { 537362306a36Sopenharmony_ci int i; 537462306a36Sopenharmony_ci 537562306a36Sopenharmony_ci /* The default MTU Table contains values 1492 and 1500. 537662306a36Sopenharmony_ci * However, for TCP, it's better to have two values which are 537762306a36Sopenharmony_ci * a multiple of 8 +/- 4 bytes apart near this popular MTU. 537862306a36Sopenharmony_ci * This allows us to have a TCP Data Payload which is a 537962306a36Sopenharmony_ci * multiple of 8 regardless of what combination of TCP Options 538062306a36Sopenharmony_ci * are in use (always a multiple of 4 bytes) which is 538162306a36Sopenharmony_ci * important for performance reasons. For instance, if no 538262306a36Sopenharmony_ci * options are in use, then we have a 20-byte IP header and a 538362306a36Sopenharmony_ci * 20-byte TCP header. In this case, a 1500-byte MSS would 538462306a36Sopenharmony_ci * result in a TCP Data Payload of 1500 - 40 == 1460 bytes 538562306a36Sopenharmony_ci * which is not a multiple of 8. So using an MSS of 1488 in 538662306a36Sopenharmony_ci * this case results in a TCP Data Payload of 1448 bytes which 538762306a36Sopenharmony_ci * is a multiple of 8. On the other hand, if 12-byte TCP Time 538862306a36Sopenharmony_ci * Stamps have been negotiated, then an MTU of 1500 bytes 538962306a36Sopenharmony_ci * results in a TCP Data Payload of 1448 bytes which, as 539062306a36Sopenharmony_ci * above, is a multiple of 8 bytes ... 539162306a36Sopenharmony_ci */ 539262306a36Sopenharmony_ci for (i = 0; i < NMTUS; i++) 539362306a36Sopenharmony_ci if (adap->params.mtus[i] == 1492) { 539462306a36Sopenharmony_ci adap->params.mtus[i] = 1488; 539562306a36Sopenharmony_ci break; 539662306a36Sopenharmony_ci } 539762306a36Sopenharmony_ci 539862306a36Sopenharmony_ci t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, 539962306a36Sopenharmony_ci adap->params.b_wnd); 540062306a36Sopenharmony_ci } 540162306a36Sopenharmony_ci t4_init_sge_params(adap); 540262306a36Sopenharmony_ci adap->flags |= CXGB4_FW_OK; 540362306a36Sopenharmony_ci t4_init_tp_params(adap, true); 540462306a36Sopenharmony_ci return 0; 540562306a36Sopenharmony_ci 540662306a36Sopenharmony_ci /* 540762306a36Sopenharmony_ci * Something bad happened. If a command timed out or failed with EIO 540862306a36Sopenharmony_ci * FW does not operate within its spec or something catastrophic 540962306a36Sopenharmony_ci * happened to HW/FW, stop issuing commands. 541062306a36Sopenharmony_ci */ 541162306a36Sopenharmony_cibye: 541262306a36Sopenharmony_ci adap_free_hma_mem(adap); 541362306a36Sopenharmony_ci kfree(adap->sge.egr_map); 541462306a36Sopenharmony_ci kfree(adap->sge.ingr_map); 541562306a36Sopenharmony_ci bitmap_free(adap->sge.starving_fl); 541662306a36Sopenharmony_ci bitmap_free(adap->sge.txq_maperr); 541762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 541862306a36Sopenharmony_ci bitmap_free(adap->sge.blocked_fl); 541962306a36Sopenharmony_ci#endif 542062306a36Sopenharmony_ci if (ret != -ETIMEDOUT && ret != -EIO) 542162306a36Sopenharmony_ci t4_fw_bye(adap, adap->mbox); 542262306a36Sopenharmony_ci return ret; 542362306a36Sopenharmony_ci} 542462306a36Sopenharmony_ci 542562306a36Sopenharmony_ci/* EEH callbacks */ 542662306a36Sopenharmony_ci 542762306a36Sopenharmony_cistatic pci_ers_result_t eeh_err_detected(struct pci_dev *pdev, 542862306a36Sopenharmony_ci pci_channel_state_t state) 542962306a36Sopenharmony_ci{ 543062306a36Sopenharmony_ci int i; 543162306a36Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 543262306a36Sopenharmony_ci 543362306a36Sopenharmony_ci if (!adap) 543462306a36Sopenharmony_ci goto out; 543562306a36Sopenharmony_ci 543662306a36Sopenharmony_ci rtnl_lock(); 543762306a36Sopenharmony_ci adap->flags &= ~CXGB4_FW_OK; 543862306a36Sopenharmony_ci notify_ulds(adap, CXGB4_STATE_START_RECOVERY); 543962306a36Sopenharmony_ci spin_lock(&adap->stats_lock); 544062306a36Sopenharmony_ci for_each_port(adap, i) { 544162306a36Sopenharmony_ci struct net_device *dev = adap->port[i]; 544262306a36Sopenharmony_ci if (dev) { 544362306a36Sopenharmony_ci netif_device_detach(dev); 544462306a36Sopenharmony_ci netif_carrier_off(dev); 544562306a36Sopenharmony_ci } 544662306a36Sopenharmony_ci } 544762306a36Sopenharmony_ci spin_unlock(&adap->stats_lock); 544862306a36Sopenharmony_ci disable_interrupts(adap); 544962306a36Sopenharmony_ci if (adap->flags & CXGB4_FULL_INIT_DONE) 545062306a36Sopenharmony_ci cxgb_down(adap); 545162306a36Sopenharmony_ci rtnl_unlock(); 545262306a36Sopenharmony_ci if ((adap->flags & CXGB4_DEV_ENABLED)) { 545362306a36Sopenharmony_ci pci_disable_device(pdev); 545462306a36Sopenharmony_ci adap->flags &= ~CXGB4_DEV_ENABLED; 545562306a36Sopenharmony_ci } 545662306a36Sopenharmony_ciout: return state == pci_channel_io_perm_failure ? 545762306a36Sopenharmony_ci PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; 545862306a36Sopenharmony_ci} 545962306a36Sopenharmony_ci 546062306a36Sopenharmony_cistatic pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) 546162306a36Sopenharmony_ci{ 546262306a36Sopenharmony_ci int i, ret; 546362306a36Sopenharmony_ci struct fw_caps_config_cmd c; 546462306a36Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 546562306a36Sopenharmony_ci 546662306a36Sopenharmony_ci if (!adap) { 546762306a36Sopenharmony_ci pci_restore_state(pdev); 546862306a36Sopenharmony_ci pci_save_state(pdev); 546962306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 547062306a36Sopenharmony_ci } 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci if (!(adap->flags & CXGB4_DEV_ENABLED)) { 547362306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 547462306a36Sopenharmony_ci dev_err(&pdev->dev, "Cannot reenable PCI " 547562306a36Sopenharmony_ci "device after reset\n"); 547662306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 547762306a36Sopenharmony_ci } 547862306a36Sopenharmony_ci adap->flags |= CXGB4_DEV_ENABLED; 547962306a36Sopenharmony_ci } 548062306a36Sopenharmony_ci 548162306a36Sopenharmony_ci pci_set_master(pdev); 548262306a36Sopenharmony_ci pci_restore_state(pdev); 548362306a36Sopenharmony_ci pci_save_state(pdev); 548462306a36Sopenharmony_ci 548562306a36Sopenharmony_ci if (t4_wait_dev_ready(adap->regs) < 0) 548662306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 548762306a36Sopenharmony_ci if (t4_fw_hello(adap, adap->mbox, adap->pf, MASTER_MUST, NULL) < 0) 548862306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 548962306a36Sopenharmony_ci adap->flags |= CXGB4_FW_OK; 549062306a36Sopenharmony_ci if (adap_init1(adap, &c)) 549162306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 549262306a36Sopenharmony_ci 549362306a36Sopenharmony_ci for_each_port(adap, i) { 549462306a36Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 549562306a36Sopenharmony_ci u8 vivld = 0, vin = 0; 549662306a36Sopenharmony_ci 549762306a36Sopenharmony_ci ret = t4_alloc_vi(adap, adap->mbox, pi->tx_chan, adap->pf, 0, 1, 549862306a36Sopenharmony_ci NULL, NULL, &vivld, &vin); 549962306a36Sopenharmony_ci if (ret < 0) 550062306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 550162306a36Sopenharmony_ci pi->viid = ret; 550262306a36Sopenharmony_ci pi->xact_addr_filt = -1; 550362306a36Sopenharmony_ci /* If fw supports returning the VIN as part of FW_VI_CMD, 550462306a36Sopenharmony_ci * save the returned values. 550562306a36Sopenharmony_ci */ 550662306a36Sopenharmony_ci if (adap->params.viid_smt_extn_support) { 550762306a36Sopenharmony_ci pi->vivld = vivld; 550862306a36Sopenharmony_ci pi->vin = vin; 550962306a36Sopenharmony_ci } else { 551062306a36Sopenharmony_ci /* Retrieve the values from VIID */ 551162306a36Sopenharmony_ci pi->vivld = FW_VIID_VIVLD_G(pi->viid); 551262306a36Sopenharmony_ci pi->vin = FW_VIID_VIN_G(pi->viid); 551362306a36Sopenharmony_ci } 551462306a36Sopenharmony_ci } 551562306a36Sopenharmony_ci 551662306a36Sopenharmony_ci t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, 551762306a36Sopenharmony_ci adap->params.b_wnd); 551862306a36Sopenharmony_ci setup_memwin(adap); 551962306a36Sopenharmony_ci if (cxgb_up(adap)) 552062306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 552162306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 552262306a36Sopenharmony_ci} 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_cistatic void eeh_resume(struct pci_dev *pdev) 552562306a36Sopenharmony_ci{ 552662306a36Sopenharmony_ci int i; 552762306a36Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 552862306a36Sopenharmony_ci 552962306a36Sopenharmony_ci if (!adap) 553062306a36Sopenharmony_ci return; 553162306a36Sopenharmony_ci 553262306a36Sopenharmony_ci rtnl_lock(); 553362306a36Sopenharmony_ci for_each_port(adap, i) { 553462306a36Sopenharmony_ci struct net_device *dev = adap->port[i]; 553562306a36Sopenharmony_ci if (dev) { 553662306a36Sopenharmony_ci if (netif_running(dev)) { 553762306a36Sopenharmony_ci link_start(dev); 553862306a36Sopenharmony_ci cxgb_set_rxmode(dev); 553962306a36Sopenharmony_ci } 554062306a36Sopenharmony_ci netif_device_attach(dev); 554162306a36Sopenharmony_ci } 554262306a36Sopenharmony_ci } 554362306a36Sopenharmony_ci rtnl_unlock(); 554462306a36Sopenharmony_ci} 554562306a36Sopenharmony_ci 554662306a36Sopenharmony_cistatic void eeh_reset_prepare(struct pci_dev *pdev) 554762306a36Sopenharmony_ci{ 554862306a36Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 554962306a36Sopenharmony_ci int i; 555062306a36Sopenharmony_ci 555162306a36Sopenharmony_ci if (adapter->pf != 4) 555262306a36Sopenharmony_ci return; 555362306a36Sopenharmony_ci 555462306a36Sopenharmony_ci adapter->flags &= ~CXGB4_FW_OK; 555562306a36Sopenharmony_ci 555662306a36Sopenharmony_ci notify_ulds(adapter, CXGB4_STATE_DOWN); 555762306a36Sopenharmony_ci 555862306a36Sopenharmony_ci for_each_port(adapter, i) 555962306a36Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 556062306a36Sopenharmony_ci cxgb_close(adapter->port[i]); 556162306a36Sopenharmony_ci 556262306a36Sopenharmony_ci disable_interrupts(adapter); 556362306a36Sopenharmony_ci cxgb4_free_mps_ref_entries(adapter); 556462306a36Sopenharmony_ci 556562306a36Sopenharmony_ci adap_free_hma_mem(adapter); 556662306a36Sopenharmony_ci 556762306a36Sopenharmony_ci if (adapter->flags & CXGB4_FULL_INIT_DONE) 556862306a36Sopenharmony_ci cxgb_down(adapter); 556962306a36Sopenharmony_ci} 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_cistatic void eeh_reset_done(struct pci_dev *pdev) 557262306a36Sopenharmony_ci{ 557362306a36Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 557462306a36Sopenharmony_ci int err, i; 557562306a36Sopenharmony_ci 557662306a36Sopenharmony_ci if (adapter->pf != 4) 557762306a36Sopenharmony_ci return; 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ci err = t4_wait_dev_ready(adapter->regs); 558062306a36Sopenharmony_ci if (err < 0) { 558162306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 558262306a36Sopenharmony_ci "Device not ready, err %d", err); 558362306a36Sopenharmony_ci return; 558462306a36Sopenharmony_ci } 558562306a36Sopenharmony_ci 558662306a36Sopenharmony_ci setup_memwin(adapter); 558762306a36Sopenharmony_ci 558862306a36Sopenharmony_ci err = adap_init0(adapter, 1); 558962306a36Sopenharmony_ci if (err) { 559062306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 559162306a36Sopenharmony_ci "Adapter init failed, err %d", err); 559262306a36Sopenharmony_ci return; 559362306a36Sopenharmony_ci } 559462306a36Sopenharmony_ci 559562306a36Sopenharmony_ci setup_memwin_rdma(adapter); 559662306a36Sopenharmony_ci 559762306a36Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) { 559862306a36Sopenharmony_ci err = t4_port_init(adapter, adapter->pf, adapter->pf, 0); 559962306a36Sopenharmony_ci if (err) { 560062306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 560162306a36Sopenharmony_ci "Port init failed, err %d", err); 560262306a36Sopenharmony_ci return; 560362306a36Sopenharmony_ci } 560462306a36Sopenharmony_ci } 560562306a36Sopenharmony_ci 560662306a36Sopenharmony_ci err = cfg_queues(adapter); 560762306a36Sopenharmony_ci if (err) { 560862306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 560962306a36Sopenharmony_ci "Config queues failed, err %d", err); 561062306a36Sopenharmony_ci return; 561162306a36Sopenharmony_ci } 561262306a36Sopenharmony_ci 561362306a36Sopenharmony_ci cxgb4_init_mps_ref_entries(adapter); 561462306a36Sopenharmony_ci 561562306a36Sopenharmony_ci err = setup_fw_sge_queues(adapter); 561662306a36Sopenharmony_ci if (err) { 561762306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 561862306a36Sopenharmony_ci "FW sge queue allocation failed, err %d", err); 561962306a36Sopenharmony_ci return; 562062306a36Sopenharmony_ci } 562162306a36Sopenharmony_ci 562262306a36Sopenharmony_ci for_each_port(adapter, i) 562362306a36Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 562462306a36Sopenharmony_ci cxgb_open(adapter->port[i]); 562562306a36Sopenharmony_ci} 562662306a36Sopenharmony_ci 562762306a36Sopenharmony_cistatic const struct pci_error_handlers cxgb4_eeh = { 562862306a36Sopenharmony_ci .error_detected = eeh_err_detected, 562962306a36Sopenharmony_ci .slot_reset = eeh_slot_reset, 563062306a36Sopenharmony_ci .resume = eeh_resume, 563162306a36Sopenharmony_ci .reset_prepare = eeh_reset_prepare, 563262306a36Sopenharmony_ci .reset_done = eeh_reset_done, 563362306a36Sopenharmony_ci}; 563462306a36Sopenharmony_ci 563562306a36Sopenharmony_ci/* Return true if the Link Configuration supports "High Speeds" (those greater 563662306a36Sopenharmony_ci * than 1Gb/s). 563762306a36Sopenharmony_ci */ 563862306a36Sopenharmony_cistatic inline bool is_x_10g_port(const struct link_config *lc) 563962306a36Sopenharmony_ci{ 564062306a36Sopenharmony_ci unsigned int speeds, high_speeds; 564162306a36Sopenharmony_ci 564262306a36Sopenharmony_ci speeds = FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_G(lc->pcaps)); 564362306a36Sopenharmony_ci high_speeds = speeds & 564462306a36Sopenharmony_ci ~(FW_PORT_CAP32_SPEED_100M | FW_PORT_CAP32_SPEED_1G); 564562306a36Sopenharmony_ci 564662306a36Sopenharmony_ci return high_speeds != 0; 564762306a36Sopenharmony_ci} 564862306a36Sopenharmony_ci 564962306a36Sopenharmony_ci/* Perform default configuration of DMA queues depending on the number and type 565062306a36Sopenharmony_ci * of ports we found and the number of available CPUs. Most settings can be 565162306a36Sopenharmony_ci * modified by the admin prior to actual use. 565262306a36Sopenharmony_ci */ 565362306a36Sopenharmony_cistatic int cfg_queues(struct adapter *adap) 565462306a36Sopenharmony_ci{ 565562306a36Sopenharmony_ci u32 avail_qsets, avail_eth_qsets, avail_uld_qsets; 565662306a36Sopenharmony_ci u32 ncpus = num_online_cpus(); 565762306a36Sopenharmony_ci u32 niqflint, neq, num_ulds; 565862306a36Sopenharmony_ci struct sge *s = &adap->sge; 565962306a36Sopenharmony_ci u32 i, n10g = 0, qidx = 0; 566062306a36Sopenharmony_ci u32 q10g = 0, q1g; 566162306a36Sopenharmony_ci 566262306a36Sopenharmony_ci /* Reduce memory usage in kdump environment, disable all offload. */ 566362306a36Sopenharmony_ci if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { 566462306a36Sopenharmony_ci adap->params.offload = 0; 566562306a36Sopenharmony_ci adap->params.crypto = 0; 566662306a36Sopenharmony_ci adap->params.ethofld = 0; 566762306a36Sopenharmony_ci } 566862306a36Sopenharmony_ci 566962306a36Sopenharmony_ci /* Calculate the number of Ethernet Queue Sets available based on 567062306a36Sopenharmony_ci * resources provisioned for us. We always have an Asynchronous 567162306a36Sopenharmony_ci * Firmware Event Ingress Queue. If we're operating in MSI or Legacy 567262306a36Sopenharmony_ci * IRQ Pin Interrupt mode, then we'll also have a Forwarded Interrupt 567362306a36Sopenharmony_ci * Ingress Queue. Meanwhile, we need two Egress Queues for each 567462306a36Sopenharmony_ci * Queue Set: one for the Free List and one for the Ethernet TX Queue. 567562306a36Sopenharmony_ci * 567662306a36Sopenharmony_ci * Note that we should also take into account all of the various 567762306a36Sopenharmony_ci * Offload Queues. But, in any situation where we're operating in 567862306a36Sopenharmony_ci * a Resource Constrained Provisioning environment, doing any Offload 567962306a36Sopenharmony_ci * at all is problematic ... 568062306a36Sopenharmony_ci */ 568162306a36Sopenharmony_ci niqflint = adap->params.pfres.niqflint - 1; 568262306a36Sopenharmony_ci if (!(adap->flags & CXGB4_USING_MSIX)) 568362306a36Sopenharmony_ci niqflint--; 568462306a36Sopenharmony_ci neq = adap->params.pfres.neq / 2; 568562306a36Sopenharmony_ci avail_qsets = min(niqflint, neq); 568662306a36Sopenharmony_ci 568762306a36Sopenharmony_ci if (avail_qsets < adap->params.nports) { 568862306a36Sopenharmony_ci dev_err(adap->pdev_dev, "avail_eth_qsets=%d < nports=%d\n", 568962306a36Sopenharmony_ci avail_qsets, adap->params.nports); 569062306a36Sopenharmony_ci return -ENOMEM; 569162306a36Sopenharmony_ci } 569262306a36Sopenharmony_ci 569362306a36Sopenharmony_ci /* Count the number of 10Gb/s or better ports */ 569462306a36Sopenharmony_ci for_each_port(adap, i) 569562306a36Sopenharmony_ci n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); 569662306a36Sopenharmony_ci 569762306a36Sopenharmony_ci avail_eth_qsets = min_t(u32, avail_qsets, MAX_ETH_QSETS); 569862306a36Sopenharmony_ci 569962306a36Sopenharmony_ci /* We default to 1 queue per non-10G port and up to # of cores queues 570062306a36Sopenharmony_ci * per 10G port. 570162306a36Sopenharmony_ci */ 570262306a36Sopenharmony_ci if (n10g) 570362306a36Sopenharmony_ci q10g = (avail_eth_qsets - (adap->params.nports - n10g)) / n10g; 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 570662306a36Sopenharmony_ci /* For Data Center Bridging support we need to be able to support up 570762306a36Sopenharmony_ci * to 8 Traffic Priorities; each of which will be assigned to its 570862306a36Sopenharmony_ci * own TX Queue in order to prevent Head-Of-Line Blocking. 570962306a36Sopenharmony_ci */ 571062306a36Sopenharmony_ci q1g = 8; 571162306a36Sopenharmony_ci if (adap->params.nports * 8 > avail_eth_qsets) { 571262306a36Sopenharmony_ci dev_err(adap->pdev_dev, "DCB avail_eth_qsets=%d < %d!\n", 571362306a36Sopenharmony_ci avail_eth_qsets, adap->params.nports * 8); 571462306a36Sopenharmony_ci return -ENOMEM; 571562306a36Sopenharmony_ci } 571662306a36Sopenharmony_ci 571762306a36Sopenharmony_ci if (adap->params.nports * ncpus < avail_eth_qsets) 571862306a36Sopenharmony_ci q10g = max(8U, ncpus); 571962306a36Sopenharmony_ci else 572062306a36Sopenharmony_ci q10g = max(8U, q10g); 572162306a36Sopenharmony_ci 572262306a36Sopenharmony_ci while ((q10g * n10g) > 572362306a36Sopenharmony_ci (avail_eth_qsets - (adap->params.nports - n10g) * q1g)) 572462306a36Sopenharmony_ci q10g--; 572562306a36Sopenharmony_ci 572662306a36Sopenharmony_ci#else /* !CONFIG_CHELSIO_T4_DCB */ 572762306a36Sopenharmony_ci q1g = 1; 572862306a36Sopenharmony_ci q10g = min(q10g, ncpus); 572962306a36Sopenharmony_ci#endif /* !CONFIG_CHELSIO_T4_DCB */ 573062306a36Sopenharmony_ci if (is_kdump_kernel()) { 573162306a36Sopenharmony_ci q10g = 1; 573262306a36Sopenharmony_ci q1g = 1; 573362306a36Sopenharmony_ci } 573462306a36Sopenharmony_ci 573562306a36Sopenharmony_ci for_each_port(adap, i) { 573662306a36Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 573762306a36Sopenharmony_ci 573862306a36Sopenharmony_ci pi->first_qset = qidx; 573962306a36Sopenharmony_ci pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : q1g; 574062306a36Sopenharmony_ci qidx += pi->nqsets; 574162306a36Sopenharmony_ci } 574262306a36Sopenharmony_ci 574362306a36Sopenharmony_ci s->ethqsets = qidx; 574462306a36Sopenharmony_ci s->max_ethqsets = qidx; /* MSI-X may lower it later */ 574562306a36Sopenharmony_ci avail_qsets -= qidx; 574662306a36Sopenharmony_ci 574762306a36Sopenharmony_ci if (is_uld(adap)) { 574862306a36Sopenharmony_ci /* For offload we use 1 queue/channel if all ports are up to 1G, 574962306a36Sopenharmony_ci * otherwise we divide all available queues amongst the channels 575062306a36Sopenharmony_ci * capped by the number of available cores. 575162306a36Sopenharmony_ci */ 575262306a36Sopenharmony_ci num_ulds = adap->num_uld + adap->num_ofld_uld; 575362306a36Sopenharmony_ci i = min_t(u32, MAX_OFLD_QSETS, ncpus); 575462306a36Sopenharmony_ci avail_uld_qsets = roundup(i, adap->params.nports); 575562306a36Sopenharmony_ci if (avail_qsets < num_ulds * adap->params.nports) { 575662306a36Sopenharmony_ci adap->params.offload = 0; 575762306a36Sopenharmony_ci adap->params.crypto = 0; 575862306a36Sopenharmony_ci s->ofldqsets = 0; 575962306a36Sopenharmony_ci } else if (avail_qsets < num_ulds * avail_uld_qsets || !n10g) { 576062306a36Sopenharmony_ci s->ofldqsets = adap->params.nports; 576162306a36Sopenharmony_ci } else { 576262306a36Sopenharmony_ci s->ofldqsets = avail_uld_qsets; 576362306a36Sopenharmony_ci } 576462306a36Sopenharmony_ci 576562306a36Sopenharmony_ci avail_qsets -= num_ulds * s->ofldqsets; 576662306a36Sopenharmony_ci } 576762306a36Sopenharmony_ci 576862306a36Sopenharmony_ci /* ETHOFLD Queues used for QoS offload should follow same 576962306a36Sopenharmony_ci * allocation scheme as normal Ethernet Queues. 577062306a36Sopenharmony_ci */ 577162306a36Sopenharmony_ci if (is_ethofld(adap)) { 577262306a36Sopenharmony_ci if (avail_qsets < s->max_ethqsets) { 577362306a36Sopenharmony_ci adap->params.ethofld = 0; 577462306a36Sopenharmony_ci s->eoqsets = 0; 577562306a36Sopenharmony_ci } else { 577662306a36Sopenharmony_ci s->eoqsets = s->max_ethqsets; 577762306a36Sopenharmony_ci } 577862306a36Sopenharmony_ci avail_qsets -= s->eoqsets; 577962306a36Sopenharmony_ci } 578062306a36Sopenharmony_ci 578162306a36Sopenharmony_ci /* Mirror queues must follow same scheme as normal Ethernet 578262306a36Sopenharmony_ci * Queues, when there are enough queues available. Otherwise, 578362306a36Sopenharmony_ci * allocate at least 1 queue per port. If even 1 queue is not 578462306a36Sopenharmony_ci * available, then disable mirror queues support. 578562306a36Sopenharmony_ci */ 578662306a36Sopenharmony_ci if (avail_qsets >= s->max_ethqsets) 578762306a36Sopenharmony_ci s->mirrorqsets = s->max_ethqsets; 578862306a36Sopenharmony_ci else if (avail_qsets >= adap->params.nports) 578962306a36Sopenharmony_ci s->mirrorqsets = adap->params.nports; 579062306a36Sopenharmony_ci else 579162306a36Sopenharmony_ci s->mirrorqsets = 0; 579262306a36Sopenharmony_ci avail_qsets -= s->mirrorqsets; 579362306a36Sopenharmony_ci 579462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { 579562306a36Sopenharmony_ci struct sge_eth_rxq *r = &s->ethrxq[i]; 579662306a36Sopenharmony_ci 579762306a36Sopenharmony_ci init_rspq(adap, &r->rspq, 5, 10, 1024, 64); 579862306a36Sopenharmony_ci r->fl.size = 72; 579962306a36Sopenharmony_ci } 580062306a36Sopenharmony_ci 580162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++) 580262306a36Sopenharmony_ci s->ethtxq[i].q.size = 1024; 580362306a36Sopenharmony_ci 580462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) 580562306a36Sopenharmony_ci s->ctrlq[i].q.size = 512; 580662306a36Sopenharmony_ci 580762306a36Sopenharmony_ci if (!is_t4(adap->params.chip)) 580862306a36Sopenharmony_ci s->ptptxq.q.size = 8; 580962306a36Sopenharmony_ci 581062306a36Sopenharmony_ci init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64); 581162306a36Sopenharmony_ci init_rspq(adap, &s->intrq, 0, 1, 512, 64); 581262306a36Sopenharmony_ci 581362306a36Sopenharmony_ci return 0; 581462306a36Sopenharmony_ci} 581562306a36Sopenharmony_ci 581662306a36Sopenharmony_ci/* 581762306a36Sopenharmony_ci * Reduce the number of Ethernet queues across all ports to at most n. 581862306a36Sopenharmony_ci * n provides at least one queue per port. 581962306a36Sopenharmony_ci */ 582062306a36Sopenharmony_cistatic void reduce_ethqs(struct adapter *adap, int n) 582162306a36Sopenharmony_ci{ 582262306a36Sopenharmony_ci int i; 582362306a36Sopenharmony_ci struct port_info *pi; 582462306a36Sopenharmony_ci 582562306a36Sopenharmony_ci while (n < adap->sge.ethqsets) 582662306a36Sopenharmony_ci for_each_port(adap, i) { 582762306a36Sopenharmony_ci pi = adap2pinfo(adap, i); 582862306a36Sopenharmony_ci if (pi->nqsets > 1) { 582962306a36Sopenharmony_ci pi->nqsets--; 583062306a36Sopenharmony_ci adap->sge.ethqsets--; 583162306a36Sopenharmony_ci if (adap->sge.ethqsets <= n) 583262306a36Sopenharmony_ci break; 583362306a36Sopenharmony_ci } 583462306a36Sopenharmony_ci } 583562306a36Sopenharmony_ci 583662306a36Sopenharmony_ci n = 0; 583762306a36Sopenharmony_ci for_each_port(adap, i) { 583862306a36Sopenharmony_ci pi = adap2pinfo(adap, i); 583962306a36Sopenharmony_ci pi->first_qset = n; 584062306a36Sopenharmony_ci n += pi->nqsets; 584162306a36Sopenharmony_ci } 584262306a36Sopenharmony_ci} 584362306a36Sopenharmony_ci 584462306a36Sopenharmony_cistatic int alloc_msix_info(struct adapter *adap, u32 num_vec) 584562306a36Sopenharmony_ci{ 584662306a36Sopenharmony_ci struct msix_info *msix_info; 584762306a36Sopenharmony_ci 584862306a36Sopenharmony_ci msix_info = kcalloc(num_vec, sizeof(*msix_info), GFP_KERNEL); 584962306a36Sopenharmony_ci if (!msix_info) 585062306a36Sopenharmony_ci return -ENOMEM; 585162306a36Sopenharmony_ci 585262306a36Sopenharmony_ci adap->msix_bmap.msix_bmap = bitmap_zalloc(num_vec, GFP_KERNEL); 585362306a36Sopenharmony_ci if (!adap->msix_bmap.msix_bmap) { 585462306a36Sopenharmony_ci kfree(msix_info); 585562306a36Sopenharmony_ci return -ENOMEM; 585662306a36Sopenharmony_ci } 585762306a36Sopenharmony_ci 585862306a36Sopenharmony_ci spin_lock_init(&adap->msix_bmap.lock); 585962306a36Sopenharmony_ci adap->msix_bmap.mapsize = num_vec; 586062306a36Sopenharmony_ci 586162306a36Sopenharmony_ci adap->msix_info = msix_info; 586262306a36Sopenharmony_ci return 0; 586362306a36Sopenharmony_ci} 586462306a36Sopenharmony_ci 586562306a36Sopenharmony_cistatic void free_msix_info(struct adapter *adap) 586662306a36Sopenharmony_ci{ 586762306a36Sopenharmony_ci bitmap_free(adap->msix_bmap.msix_bmap); 586862306a36Sopenharmony_ci kfree(adap->msix_info); 586962306a36Sopenharmony_ci} 587062306a36Sopenharmony_ci 587162306a36Sopenharmony_ciint cxgb4_get_msix_idx_from_bmap(struct adapter *adap) 587262306a36Sopenharmony_ci{ 587362306a36Sopenharmony_ci struct msix_bmap *bmap = &adap->msix_bmap; 587462306a36Sopenharmony_ci unsigned int msix_idx; 587562306a36Sopenharmony_ci unsigned long flags; 587662306a36Sopenharmony_ci 587762306a36Sopenharmony_ci spin_lock_irqsave(&bmap->lock, flags); 587862306a36Sopenharmony_ci msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize); 587962306a36Sopenharmony_ci if (msix_idx < bmap->mapsize) { 588062306a36Sopenharmony_ci __set_bit(msix_idx, bmap->msix_bmap); 588162306a36Sopenharmony_ci } else { 588262306a36Sopenharmony_ci spin_unlock_irqrestore(&bmap->lock, flags); 588362306a36Sopenharmony_ci return -ENOSPC; 588462306a36Sopenharmony_ci } 588562306a36Sopenharmony_ci 588662306a36Sopenharmony_ci spin_unlock_irqrestore(&bmap->lock, flags); 588762306a36Sopenharmony_ci return msix_idx; 588862306a36Sopenharmony_ci} 588962306a36Sopenharmony_ci 589062306a36Sopenharmony_civoid cxgb4_free_msix_idx_in_bmap(struct adapter *adap, 589162306a36Sopenharmony_ci unsigned int msix_idx) 589262306a36Sopenharmony_ci{ 589362306a36Sopenharmony_ci struct msix_bmap *bmap = &adap->msix_bmap; 589462306a36Sopenharmony_ci unsigned long flags; 589562306a36Sopenharmony_ci 589662306a36Sopenharmony_ci spin_lock_irqsave(&bmap->lock, flags); 589762306a36Sopenharmony_ci __clear_bit(msix_idx, bmap->msix_bmap); 589862306a36Sopenharmony_ci spin_unlock_irqrestore(&bmap->lock, flags); 589962306a36Sopenharmony_ci} 590062306a36Sopenharmony_ci 590162306a36Sopenharmony_ci/* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ 590262306a36Sopenharmony_ci#define EXTRA_VECS 2 590362306a36Sopenharmony_ci 590462306a36Sopenharmony_cistatic int enable_msix(struct adapter *adap) 590562306a36Sopenharmony_ci{ 590662306a36Sopenharmony_ci u32 eth_need, uld_need = 0, ethofld_need = 0, mirror_need = 0; 590762306a36Sopenharmony_ci u32 ethqsets = 0, ofldqsets = 0, eoqsets = 0, mirrorqsets = 0; 590862306a36Sopenharmony_ci u8 num_uld = 0, nchan = adap->params.nports; 590962306a36Sopenharmony_ci u32 i, want, need, num_vec; 591062306a36Sopenharmony_ci struct sge *s = &adap->sge; 591162306a36Sopenharmony_ci struct msix_entry *entries; 591262306a36Sopenharmony_ci struct port_info *pi; 591362306a36Sopenharmony_ci int allocated, ret; 591462306a36Sopenharmony_ci 591562306a36Sopenharmony_ci want = s->max_ethqsets; 591662306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 591762306a36Sopenharmony_ci /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for 591862306a36Sopenharmony_ci * each port. 591962306a36Sopenharmony_ci */ 592062306a36Sopenharmony_ci need = 8 * nchan; 592162306a36Sopenharmony_ci#else 592262306a36Sopenharmony_ci need = nchan; 592362306a36Sopenharmony_ci#endif 592462306a36Sopenharmony_ci eth_need = need; 592562306a36Sopenharmony_ci if (is_uld(adap)) { 592662306a36Sopenharmony_ci num_uld = adap->num_ofld_uld + adap->num_uld; 592762306a36Sopenharmony_ci want += num_uld * s->ofldqsets; 592862306a36Sopenharmony_ci uld_need = num_uld * nchan; 592962306a36Sopenharmony_ci need += uld_need; 593062306a36Sopenharmony_ci } 593162306a36Sopenharmony_ci 593262306a36Sopenharmony_ci if (is_ethofld(adap)) { 593362306a36Sopenharmony_ci want += s->eoqsets; 593462306a36Sopenharmony_ci ethofld_need = eth_need; 593562306a36Sopenharmony_ci need += ethofld_need; 593662306a36Sopenharmony_ci } 593762306a36Sopenharmony_ci 593862306a36Sopenharmony_ci if (s->mirrorqsets) { 593962306a36Sopenharmony_ci want += s->mirrorqsets; 594062306a36Sopenharmony_ci mirror_need = nchan; 594162306a36Sopenharmony_ci need += mirror_need; 594262306a36Sopenharmony_ci } 594362306a36Sopenharmony_ci 594462306a36Sopenharmony_ci want += EXTRA_VECS; 594562306a36Sopenharmony_ci need += EXTRA_VECS; 594662306a36Sopenharmony_ci 594762306a36Sopenharmony_ci entries = kmalloc_array(want, sizeof(*entries), GFP_KERNEL); 594862306a36Sopenharmony_ci if (!entries) 594962306a36Sopenharmony_ci return -ENOMEM; 595062306a36Sopenharmony_ci 595162306a36Sopenharmony_ci for (i = 0; i < want; i++) 595262306a36Sopenharmony_ci entries[i].entry = i; 595362306a36Sopenharmony_ci 595462306a36Sopenharmony_ci allocated = pci_enable_msix_range(adap->pdev, entries, need, want); 595562306a36Sopenharmony_ci if (allocated < 0) { 595662306a36Sopenharmony_ci /* Disable offload and attempt to get vectors for NIC 595762306a36Sopenharmony_ci * only mode. 595862306a36Sopenharmony_ci */ 595962306a36Sopenharmony_ci want = s->max_ethqsets + EXTRA_VECS; 596062306a36Sopenharmony_ci need = eth_need + EXTRA_VECS; 596162306a36Sopenharmony_ci allocated = pci_enable_msix_range(adap->pdev, entries, 596262306a36Sopenharmony_ci need, want); 596362306a36Sopenharmony_ci if (allocated < 0) { 596462306a36Sopenharmony_ci dev_info(adap->pdev_dev, 596562306a36Sopenharmony_ci "Disabling MSI-X due to insufficient MSI-X vectors\n"); 596662306a36Sopenharmony_ci ret = allocated; 596762306a36Sopenharmony_ci goto out_free; 596862306a36Sopenharmony_ci } 596962306a36Sopenharmony_ci 597062306a36Sopenharmony_ci dev_info(adap->pdev_dev, 597162306a36Sopenharmony_ci "Disabling offload due to insufficient MSI-X vectors\n"); 597262306a36Sopenharmony_ci adap->params.offload = 0; 597362306a36Sopenharmony_ci adap->params.crypto = 0; 597462306a36Sopenharmony_ci adap->params.ethofld = 0; 597562306a36Sopenharmony_ci s->ofldqsets = 0; 597662306a36Sopenharmony_ci s->eoqsets = 0; 597762306a36Sopenharmony_ci s->mirrorqsets = 0; 597862306a36Sopenharmony_ci uld_need = 0; 597962306a36Sopenharmony_ci ethofld_need = 0; 598062306a36Sopenharmony_ci mirror_need = 0; 598162306a36Sopenharmony_ci } 598262306a36Sopenharmony_ci 598362306a36Sopenharmony_ci num_vec = allocated; 598462306a36Sopenharmony_ci if (num_vec < want) { 598562306a36Sopenharmony_ci /* Distribute available vectors to the various queue groups. 598662306a36Sopenharmony_ci * Every group gets its minimum requirement and NIC gets top 598762306a36Sopenharmony_ci * priority for leftovers. 598862306a36Sopenharmony_ci */ 598962306a36Sopenharmony_ci ethqsets = eth_need; 599062306a36Sopenharmony_ci if (is_uld(adap)) 599162306a36Sopenharmony_ci ofldqsets = nchan; 599262306a36Sopenharmony_ci if (is_ethofld(adap)) 599362306a36Sopenharmony_ci eoqsets = ethofld_need; 599462306a36Sopenharmony_ci if (s->mirrorqsets) 599562306a36Sopenharmony_ci mirrorqsets = mirror_need; 599662306a36Sopenharmony_ci 599762306a36Sopenharmony_ci num_vec -= need; 599862306a36Sopenharmony_ci while (num_vec) { 599962306a36Sopenharmony_ci if (num_vec < eth_need + ethofld_need || 600062306a36Sopenharmony_ci ethqsets > s->max_ethqsets) 600162306a36Sopenharmony_ci break; 600262306a36Sopenharmony_ci 600362306a36Sopenharmony_ci for_each_port(adap, i) { 600462306a36Sopenharmony_ci pi = adap2pinfo(adap, i); 600562306a36Sopenharmony_ci if (pi->nqsets < 2) 600662306a36Sopenharmony_ci continue; 600762306a36Sopenharmony_ci 600862306a36Sopenharmony_ci ethqsets++; 600962306a36Sopenharmony_ci num_vec--; 601062306a36Sopenharmony_ci if (ethofld_need) { 601162306a36Sopenharmony_ci eoqsets++; 601262306a36Sopenharmony_ci num_vec--; 601362306a36Sopenharmony_ci } 601462306a36Sopenharmony_ci } 601562306a36Sopenharmony_ci } 601662306a36Sopenharmony_ci 601762306a36Sopenharmony_ci if (is_uld(adap)) { 601862306a36Sopenharmony_ci while (num_vec) { 601962306a36Sopenharmony_ci if (num_vec < uld_need || 602062306a36Sopenharmony_ci ofldqsets > s->ofldqsets) 602162306a36Sopenharmony_ci break; 602262306a36Sopenharmony_ci 602362306a36Sopenharmony_ci ofldqsets++; 602462306a36Sopenharmony_ci num_vec -= uld_need; 602562306a36Sopenharmony_ci } 602662306a36Sopenharmony_ci } 602762306a36Sopenharmony_ci 602862306a36Sopenharmony_ci if (s->mirrorqsets) { 602962306a36Sopenharmony_ci while (num_vec) { 603062306a36Sopenharmony_ci if (num_vec < mirror_need || 603162306a36Sopenharmony_ci mirrorqsets > s->mirrorqsets) 603262306a36Sopenharmony_ci break; 603362306a36Sopenharmony_ci 603462306a36Sopenharmony_ci mirrorqsets++; 603562306a36Sopenharmony_ci num_vec -= mirror_need; 603662306a36Sopenharmony_ci } 603762306a36Sopenharmony_ci } 603862306a36Sopenharmony_ci } else { 603962306a36Sopenharmony_ci ethqsets = s->max_ethqsets; 604062306a36Sopenharmony_ci if (is_uld(adap)) 604162306a36Sopenharmony_ci ofldqsets = s->ofldqsets; 604262306a36Sopenharmony_ci if (is_ethofld(adap)) 604362306a36Sopenharmony_ci eoqsets = s->eoqsets; 604462306a36Sopenharmony_ci if (s->mirrorqsets) 604562306a36Sopenharmony_ci mirrorqsets = s->mirrorqsets; 604662306a36Sopenharmony_ci } 604762306a36Sopenharmony_ci 604862306a36Sopenharmony_ci if (ethqsets < s->max_ethqsets) { 604962306a36Sopenharmony_ci s->max_ethqsets = ethqsets; 605062306a36Sopenharmony_ci reduce_ethqs(adap, ethqsets); 605162306a36Sopenharmony_ci } 605262306a36Sopenharmony_ci 605362306a36Sopenharmony_ci if (is_uld(adap)) { 605462306a36Sopenharmony_ci s->ofldqsets = ofldqsets; 605562306a36Sopenharmony_ci s->nqs_per_uld = s->ofldqsets; 605662306a36Sopenharmony_ci } 605762306a36Sopenharmony_ci 605862306a36Sopenharmony_ci if (is_ethofld(adap)) 605962306a36Sopenharmony_ci s->eoqsets = eoqsets; 606062306a36Sopenharmony_ci 606162306a36Sopenharmony_ci if (s->mirrorqsets) { 606262306a36Sopenharmony_ci s->mirrorqsets = mirrorqsets; 606362306a36Sopenharmony_ci for_each_port(adap, i) { 606462306a36Sopenharmony_ci pi = adap2pinfo(adap, i); 606562306a36Sopenharmony_ci pi->nmirrorqsets = s->mirrorqsets / nchan; 606662306a36Sopenharmony_ci mutex_init(&pi->vi_mirror_mutex); 606762306a36Sopenharmony_ci } 606862306a36Sopenharmony_ci } 606962306a36Sopenharmony_ci 607062306a36Sopenharmony_ci /* map for msix */ 607162306a36Sopenharmony_ci ret = alloc_msix_info(adap, allocated); 607262306a36Sopenharmony_ci if (ret) 607362306a36Sopenharmony_ci goto out_disable_msix; 607462306a36Sopenharmony_ci 607562306a36Sopenharmony_ci for (i = 0; i < allocated; i++) { 607662306a36Sopenharmony_ci adap->msix_info[i].vec = entries[i].vector; 607762306a36Sopenharmony_ci adap->msix_info[i].idx = i; 607862306a36Sopenharmony_ci } 607962306a36Sopenharmony_ci 608062306a36Sopenharmony_ci dev_info(adap->pdev_dev, 608162306a36Sopenharmony_ci "%d MSI-X vectors allocated, nic %d eoqsets %d per uld %d mirrorqsets %d\n", 608262306a36Sopenharmony_ci allocated, s->max_ethqsets, s->eoqsets, s->nqs_per_uld, 608362306a36Sopenharmony_ci s->mirrorqsets); 608462306a36Sopenharmony_ci 608562306a36Sopenharmony_ci kfree(entries); 608662306a36Sopenharmony_ci return 0; 608762306a36Sopenharmony_ci 608862306a36Sopenharmony_ciout_disable_msix: 608962306a36Sopenharmony_ci pci_disable_msix(adap->pdev); 609062306a36Sopenharmony_ci 609162306a36Sopenharmony_ciout_free: 609262306a36Sopenharmony_ci kfree(entries); 609362306a36Sopenharmony_ci return ret; 609462306a36Sopenharmony_ci} 609562306a36Sopenharmony_ci 609662306a36Sopenharmony_ci#undef EXTRA_VECS 609762306a36Sopenharmony_ci 609862306a36Sopenharmony_cistatic int init_rss(struct adapter *adap) 609962306a36Sopenharmony_ci{ 610062306a36Sopenharmony_ci unsigned int i; 610162306a36Sopenharmony_ci int err; 610262306a36Sopenharmony_ci 610362306a36Sopenharmony_ci err = t4_init_rss_mode(adap, adap->mbox); 610462306a36Sopenharmony_ci if (err) 610562306a36Sopenharmony_ci return err; 610662306a36Sopenharmony_ci 610762306a36Sopenharmony_ci for_each_port(adap, i) { 610862306a36Sopenharmony_ci struct port_info *pi = adap2pinfo(adap, i); 610962306a36Sopenharmony_ci 611062306a36Sopenharmony_ci pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); 611162306a36Sopenharmony_ci if (!pi->rss) 611262306a36Sopenharmony_ci return -ENOMEM; 611362306a36Sopenharmony_ci } 611462306a36Sopenharmony_ci return 0; 611562306a36Sopenharmony_ci} 611662306a36Sopenharmony_ci 611762306a36Sopenharmony_ci/* Dump basic information about the adapter */ 611862306a36Sopenharmony_cistatic void print_adapter_info(struct adapter *adapter) 611962306a36Sopenharmony_ci{ 612062306a36Sopenharmony_ci /* Hardware/Firmware/etc. Version/Revision IDs */ 612162306a36Sopenharmony_ci t4_dump_version_info(adapter); 612262306a36Sopenharmony_ci 612362306a36Sopenharmony_ci /* Software/Hardware configuration */ 612462306a36Sopenharmony_ci dev_info(adapter->pdev_dev, "Configuration: %sNIC %s, %s capable\n", 612562306a36Sopenharmony_ci is_offload(adapter) ? "R" : "", 612662306a36Sopenharmony_ci ((adapter->flags & CXGB4_USING_MSIX) ? "MSI-X" : 612762306a36Sopenharmony_ci (adapter->flags & CXGB4_USING_MSI) ? "MSI" : ""), 612862306a36Sopenharmony_ci is_offload(adapter) ? "Offload" : "non-Offload"); 612962306a36Sopenharmony_ci} 613062306a36Sopenharmony_ci 613162306a36Sopenharmony_cistatic void print_port_info(const struct net_device *dev) 613262306a36Sopenharmony_ci{ 613362306a36Sopenharmony_ci char buf[80]; 613462306a36Sopenharmony_ci char *bufp = buf; 613562306a36Sopenharmony_ci const struct port_info *pi = netdev_priv(dev); 613662306a36Sopenharmony_ci const struct adapter *adap = pi->adapter; 613762306a36Sopenharmony_ci 613862306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100M) 613962306a36Sopenharmony_ci bufp += sprintf(bufp, "100M/"); 614062306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_1G) 614162306a36Sopenharmony_ci bufp += sprintf(bufp, "1G/"); 614262306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_10G) 614362306a36Sopenharmony_ci bufp += sprintf(bufp, "10G/"); 614462306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_25G) 614562306a36Sopenharmony_ci bufp += sprintf(bufp, "25G/"); 614662306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_40G) 614762306a36Sopenharmony_ci bufp += sprintf(bufp, "40G/"); 614862306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_50G) 614962306a36Sopenharmony_ci bufp += sprintf(bufp, "50G/"); 615062306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_100G) 615162306a36Sopenharmony_ci bufp += sprintf(bufp, "100G/"); 615262306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_200G) 615362306a36Sopenharmony_ci bufp += sprintf(bufp, "200G/"); 615462306a36Sopenharmony_ci if (pi->link_cfg.pcaps & FW_PORT_CAP32_SPEED_400G) 615562306a36Sopenharmony_ci bufp += sprintf(bufp, "400G/"); 615662306a36Sopenharmony_ci if (bufp != buf) 615762306a36Sopenharmony_ci --bufp; 615862306a36Sopenharmony_ci sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type)); 615962306a36Sopenharmony_ci 616062306a36Sopenharmony_ci netdev_info(dev, "Chelsio %s %s\n", adap->params.vpd.id, buf); 616162306a36Sopenharmony_ci} 616262306a36Sopenharmony_ci 616362306a36Sopenharmony_ci/* 616462306a36Sopenharmony_ci * Free the following resources: 616562306a36Sopenharmony_ci * - memory used for tables 616662306a36Sopenharmony_ci * - MSI/MSI-X 616762306a36Sopenharmony_ci * - net devices 616862306a36Sopenharmony_ci * - resources FW is holding for us 616962306a36Sopenharmony_ci */ 617062306a36Sopenharmony_cistatic void free_some_resources(struct adapter *adapter) 617162306a36Sopenharmony_ci{ 617262306a36Sopenharmony_ci unsigned int i; 617362306a36Sopenharmony_ci 617462306a36Sopenharmony_ci kvfree(adapter->smt); 617562306a36Sopenharmony_ci kvfree(adapter->l2t); 617662306a36Sopenharmony_ci kvfree(adapter->srq); 617762306a36Sopenharmony_ci t4_cleanup_sched(adapter); 617862306a36Sopenharmony_ci kvfree(adapter->tids.tid_tab); 617962306a36Sopenharmony_ci cxgb4_cleanup_tc_matchall(adapter); 618062306a36Sopenharmony_ci cxgb4_cleanup_tc_mqprio(adapter); 618162306a36Sopenharmony_ci cxgb4_cleanup_tc_flower(adapter); 618262306a36Sopenharmony_ci cxgb4_cleanup_tc_u32(adapter); 618362306a36Sopenharmony_ci cxgb4_cleanup_ethtool_filters(adapter); 618462306a36Sopenharmony_ci kfree(adapter->sge.egr_map); 618562306a36Sopenharmony_ci kfree(adapter->sge.ingr_map); 618662306a36Sopenharmony_ci bitmap_free(adapter->sge.starving_fl); 618762306a36Sopenharmony_ci bitmap_free(adapter->sge.txq_maperr); 618862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 618962306a36Sopenharmony_ci bitmap_free(adapter->sge.blocked_fl); 619062306a36Sopenharmony_ci#endif 619162306a36Sopenharmony_ci disable_msi(adapter); 619262306a36Sopenharmony_ci 619362306a36Sopenharmony_ci for_each_port(adapter, i) 619462306a36Sopenharmony_ci if (adapter->port[i]) { 619562306a36Sopenharmony_ci struct port_info *pi = adap2pinfo(adapter, i); 619662306a36Sopenharmony_ci 619762306a36Sopenharmony_ci if (pi->viid != 0) 619862306a36Sopenharmony_ci t4_free_vi(adapter, adapter->mbox, adapter->pf, 619962306a36Sopenharmony_ci 0, pi->viid); 620062306a36Sopenharmony_ci kfree(adap2pinfo(adapter, i)->rss); 620162306a36Sopenharmony_ci free_netdev(adapter->port[i]); 620262306a36Sopenharmony_ci } 620362306a36Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) 620462306a36Sopenharmony_ci t4_fw_bye(adapter, adapter->pf); 620562306a36Sopenharmony_ci} 620662306a36Sopenharmony_ci 620762306a36Sopenharmony_ci#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | \ 620862306a36Sopenharmony_ci NETIF_F_GSO_UDP_L4) 620962306a36Sopenharmony_ci#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ 621062306a36Sopenharmony_ci NETIF_F_GRO | NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) 621162306a36Sopenharmony_ci#define SEGMENT_SIZE 128 621262306a36Sopenharmony_ci 621362306a36Sopenharmony_cistatic int t4_get_chip_type(struct adapter *adap, int ver) 621462306a36Sopenharmony_ci{ 621562306a36Sopenharmony_ci u32 pl_rev = REV_G(t4_read_reg(adap, PL_REV_A)); 621662306a36Sopenharmony_ci 621762306a36Sopenharmony_ci switch (ver) { 621862306a36Sopenharmony_ci case CHELSIO_T4: 621962306a36Sopenharmony_ci return CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); 622062306a36Sopenharmony_ci case CHELSIO_T5: 622162306a36Sopenharmony_ci return CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev); 622262306a36Sopenharmony_ci case CHELSIO_T6: 622362306a36Sopenharmony_ci return CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); 622462306a36Sopenharmony_ci default: 622562306a36Sopenharmony_ci break; 622662306a36Sopenharmony_ci } 622762306a36Sopenharmony_ci return -EINVAL; 622862306a36Sopenharmony_ci} 622962306a36Sopenharmony_ci 623062306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV 623162306a36Sopenharmony_cistatic void cxgb4_mgmt_setup(struct net_device *dev) 623262306a36Sopenharmony_ci{ 623362306a36Sopenharmony_ci dev->type = ARPHRD_NONE; 623462306a36Sopenharmony_ci dev->mtu = 0; 623562306a36Sopenharmony_ci dev->hard_header_len = 0; 623662306a36Sopenharmony_ci dev->addr_len = 0; 623762306a36Sopenharmony_ci dev->tx_queue_len = 0; 623862306a36Sopenharmony_ci dev->flags |= IFF_NOARP; 623962306a36Sopenharmony_ci dev->priv_flags |= IFF_NO_QUEUE; 624062306a36Sopenharmony_ci 624162306a36Sopenharmony_ci /* Initialize the device structure. */ 624262306a36Sopenharmony_ci dev->netdev_ops = &cxgb4_mgmt_netdev_ops; 624362306a36Sopenharmony_ci dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops; 624462306a36Sopenharmony_ci} 624562306a36Sopenharmony_ci 624662306a36Sopenharmony_cistatic int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs) 624762306a36Sopenharmony_ci{ 624862306a36Sopenharmony_ci struct adapter *adap = pci_get_drvdata(pdev); 624962306a36Sopenharmony_ci int err = 0; 625062306a36Sopenharmony_ci int current_vfs = pci_num_vf(pdev); 625162306a36Sopenharmony_ci u32 pcie_fw; 625262306a36Sopenharmony_ci 625362306a36Sopenharmony_ci pcie_fw = readl(adap->regs + PCIE_FW_A); 625462306a36Sopenharmony_ci /* Check if fw is initialized */ 625562306a36Sopenharmony_ci if (!(pcie_fw & PCIE_FW_INIT_F)) { 625662306a36Sopenharmony_ci dev_warn(&pdev->dev, "Device not initialized\n"); 625762306a36Sopenharmony_ci return -EOPNOTSUPP; 625862306a36Sopenharmony_ci } 625962306a36Sopenharmony_ci 626062306a36Sopenharmony_ci /* If any of the VF's is already assigned to Guest OS, then 626162306a36Sopenharmony_ci * SRIOV for the same cannot be modified 626262306a36Sopenharmony_ci */ 626362306a36Sopenharmony_ci if (current_vfs && pci_vfs_assigned(pdev)) { 626462306a36Sopenharmony_ci dev_err(&pdev->dev, 626562306a36Sopenharmony_ci "Cannot modify SR-IOV while VFs are assigned\n"); 626662306a36Sopenharmony_ci return current_vfs; 626762306a36Sopenharmony_ci } 626862306a36Sopenharmony_ci /* Note that the upper-level code ensures that we're never called with 626962306a36Sopenharmony_ci * a non-zero "num_vfs" when we already have VFs instantiated. But 627062306a36Sopenharmony_ci * it never hurts to code defensively. 627162306a36Sopenharmony_ci */ 627262306a36Sopenharmony_ci if (num_vfs != 0 && current_vfs != 0) 627362306a36Sopenharmony_ci return -EBUSY; 627462306a36Sopenharmony_ci 627562306a36Sopenharmony_ci /* Nothing to do for no change. */ 627662306a36Sopenharmony_ci if (num_vfs == current_vfs) 627762306a36Sopenharmony_ci return num_vfs; 627862306a36Sopenharmony_ci 627962306a36Sopenharmony_ci /* Disable SRIOV when zero is passed. */ 628062306a36Sopenharmony_ci if (!num_vfs) { 628162306a36Sopenharmony_ci pci_disable_sriov(pdev); 628262306a36Sopenharmony_ci /* free VF Management Interface */ 628362306a36Sopenharmony_ci unregister_netdev(adap->port[0]); 628462306a36Sopenharmony_ci free_netdev(adap->port[0]); 628562306a36Sopenharmony_ci adap->port[0] = NULL; 628662306a36Sopenharmony_ci 628762306a36Sopenharmony_ci /* free VF resources */ 628862306a36Sopenharmony_ci adap->num_vfs = 0; 628962306a36Sopenharmony_ci kfree(adap->vfinfo); 629062306a36Sopenharmony_ci adap->vfinfo = NULL; 629162306a36Sopenharmony_ci return 0; 629262306a36Sopenharmony_ci } 629362306a36Sopenharmony_ci 629462306a36Sopenharmony_ci if (!current_vfs) { 629562306a36Sopenharmony_ci struct fw_pfvf_cmd port_cmd, port_rpl; 629662306a36Sopenharmony_ci struct net_device *netdev; 629762306a36Sopenharmony_ci unsigned int pmask, port; 629862306a36Sopenharmony_ci struct pci_dev *pbridge; 629962306a36Sopenharmony_ci struct port_info *pi; 630062306a36Sopenharmony_ci char name[IFNAMSIZ]; 630162306a36Sopenharmony_ci u32 devcap2; 630262306a36Sopenharmony_ci u16 flags; 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci /* If we want to instantiate Virtual Functions, then our 630562306a36Sopenharmony_ci * parent bridge's PCI-E needs to support Alternative Routing 630662306a36Sopenharmony_ci * ID (ARI) because our VFs will show up at function offset 8 630762306a36Sopenharmony_ci * and above. 630862306a36Sopenharmony_ci */ 630962306a36Sopenharmony_ci pbridge = pdev->bus->self; 631062306a36Sopenharmony_ci pcie_capability_read_word(pbridge, PCI_EXP_FLAGS, &flags); 631162306a36Sopenharmony_ci pcie_capability_read_dword(pbridge, PCI_EXP_DEVCAP2, &devcap2); 631262306a36Sopenharmony_ci 631362306a36Sopenharmony_ci if ((flags & PCI_EXP_FLAGS_VERS) < 2 || 631462306a36Sopenharmony_ci !(devcap2 & PCI_EXP_DEVCAP2_ARI)) { 631562306a36Sopenharmony_ci /* Our parent bridge does not support ARI so issue a 631662306a36Sopenharmony_ci * warning and skip instantiating the VFs. They 631762306a36Sopenharmony_ci * won't be reachable. 631862306a36Sopenharmony_ci */ 631962306a36Sopenharmony_ci dev_warn(&pdev->dev, "Parent bridge %02x:%02x.%x doesn't support ARI; can't instantiate Virtual Functions\n", 632062306a36Sopenharmony_ci pbridge->bus->number, PCI_SLOT(pbridge->devfn), 632162306a36Sopenharmony_ci PCI_FUNC(pbridge->devfn)); 632262306a36Sopenharmony_ci return -ENOTSUPP; 632362306a36Sopenharmony_ci } 632462306a36Sopenharmony_ci memset(&port_cmd, 0, sizeof(port_cmd)); 632562306a36Sopenharmony_ci port_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) | 632662306a36Sopenharmony_ci FW_CMD_REQUEST_F | 632762306a36Sopenharmony_ci FW_CMD_READ_F | 632862306a36Sopenharmony_ci FW_PFVF_CMD_PFN_V(adap->pf) | 632962306a36Sopenharmony_ci FW_PFVF_CMD_VFN_V(0)); 633062306a36Sopenharmony_ci port_cmd.retval_len16 = cpu_to_be32(FW_LEN16(port_cmd)); 633162306a36Sopenharmony_ci err = t4_wr_mbox(adap, adap->mbox, &port_cmd, sizeof(port_cmd), 633262306a36Sopenharmony_ci &port_rpl); 633362306a36Sopenharmony_ci if (err) 633462306a36Sopenharmony_ci return err; 633562306a36Sopenharmony_ci pmask = FW_PFVF_CMD_PMASK_G(be32_to_cpu(port_rpl.type_to_neq)); 633662306a36Sopenharmony_ci port = ffs(pmask) - 1; 633762306a36Sopenharmony_ci /* Allocate VF Management Interface. */ 633862306a36Sopenharmony_ci snprintf(name, IFNAMSIZ, "mgmtpf%d,%d", adap->adap_idx, 633962306a36Sopenharmony_ci adap->pf); 634062306a36Sopenharmony_ci netdev = alloc_netdev(sizeof(struct port_info), 634162306a36Sopenharmony_ci name, NET_NAME_UNKNOWN, cxgb4_mgmt_setup); 634262306a36Sopenharmony_ci if (!netdev) 634362306a36Sopenharmony_ci return -ENOMEM; 634462306a36Sopenharmony_ci 634562306a36Sopenharmony_ci pi = netdev_priv(netdev); 634662306a36Sopenharmony_ci pi->adapter = adap; 634762306a36Sopenharmony_ci pi->lport = port; 634862306a36Sopenharmony_ci pi->tx_chan = port; 634962306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 635062306a36Sopenharmony_ci 635162306a36Sopenharmony_ci adap->port[0] = netdev; 635262306a36Sopenharmony_ci pi->port_id = 0; 635362306a36Sopenharmony_ci 635462306a36Sopenharmony_ci err = register_netdev(adap->port[0]); 635562306a36Sopenharmony_ci if (err) { 635662306a36Sopenharmony_ci pr_info("Unable to register VF mgmt netdev %s\n", name); 635762306a36Sopenharmony_ci free_netdev(adap->port[0]); 635862306a36Sopenharmony_ci adap->port[0] = NULL; 635962306a36Sopenharmony_ci return err; 636062306a36Sopenharmony_ci } 636162306a36Sopenharmony_ci /* Allocate and set up VF Information. */ 636262306a36Sopenharmony_ci adap->vfinfo = kcalloc(pci_sriov_get_totalvfs(pdev), 636362306a36Sopenharmony_ci sizeof(struct vf_info), GFP_KERNEL); 636462306a36Sopenharmony_ci if (!adap->vfinfo) { 636562306a36Sopenharmony_ci unregister_netdev(adap->port[0]); 636662306a36Sopenharmony_ci free_netdev(adap->port[0]); 636762306a36Sopenharmony_ci adap->port[0] = NULL; 636862306a36Sopenharmony_ci return -ENOMEM; 636962306a36Sopenharmony_ci } 637062306a36Sopenharmony_ci cxgb4_mgmt_fill_vf_station_mac_addr(adap); 637162306a36Sopenharmony_ci } 637262306a36Sopenharmony_ci /* Instantiate the requested number of VFs. */ 637362306a36Sopenharmony_ci err = pci_enable_sriov(pdev, num_vfs); 637462306a36Sopenharmony_ci if (err) { 637562306a36Sopenharmony_ci pr_info("Unable to instantiate %d VFs\n", num_vfs); 637662306a36Sopenharmony_ci if (!current_vfs) { 637762306a36Sopenharmony_ci unregister_netdev(adap->port[0]); 637862306a36Sopenharmony_ci free_netdev(adap->port[0]); 637962306a36Sopenharmony_ci adap->port[0] = NULL; 638062306a36Sopenharmony_ci kfree(adap->vfinfo); 638162306a36Sopenharmony_ci adap->vfinfo = NULL; 638262306a36Sopenharmony_ci } 638362306a36Sopenharmony_ci return err; 638462306a36Sopenharmony_ci } 638562306a36Sopenharmony_ci 638662306a36Sopenharmony_ci adap->num_vfs = num_vfs; 638762306a36Sopenharmony_ci return num_vfs; 638862306a36Sopenharmony_ci} 638962306a36Sopenharmony_ci#endif /* CONFIG_PCI_IOV */ 639062306a36Sopenharmony_ci 639162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) || IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 639262306a36Sopenharmony_ci 639362306a36Sopenharmony_cistatic int chcr_offload_state(struct adapter *adap, 639462306a36Sopenharmony_ci enum cxgb4_netdev_tls_ops op_val) 639562306a36Sopenharmony_ci{ 639662306a36Sopenharmony_ci switch (op_val) { 639762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 639862306a36Sopenharmony_ci case CXGB4_TLSDEV_OPS: 639962306a36Sopenharmony_ci if (!adap->uld[CXGB4_ULD_KTLS].handle) { 640062306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, "ch_ktls driver is not loaded\n"); 640162306a36Sopenharmony_ci return -EOPNOTSUPP; 640262306a36Sopenharmony_ci } 640362306a36Sopenharmony_ci if (!adap->uld[CXGB4_ULD_KTLS].tlsdev_ops) { 640462306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 640562306a36Sopenharmony_ci "ch_ktls driver has no registered tlsdev_ops\n"); 640662306a36Sopenharmony_ci return -EOPNOTSUPP; 640762306a36Sopenharmony_ci } 640862306a36Sopenharmony_ci break; 640962306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */ 641062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 641162306a36Sopenharmony_ci case CXGB4_XFRMDEV_OPS: 641262306a36Sopenharmony_ci if (!adap->uld[CXGB4_ULD_IPSEC].handle) { 641362306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, "chipsec driver is not loaded\n"); 641462306a36Sopenharmony_ci return -EOPNOTSUPP; 641562306a36Sopenharmony_ci } 641662306a36Sopenharmony_ci if (!adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops) { 641762306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 641862306a36Sopenharmony_ci "chipsec driver has no registered xfrmdev_ops\n"); 641962306a36Sopenharmony_ci return -EOPNOTSUPP; 642062306a36Sopenharmony_ci } 642162306a36Sopenharmony_ci break; 642262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ 642362306a36Sopenharmony_ci default: 642462306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 642562306a36Sopenharmony_ci "driver has no support for offload %d\n", op_val); 642662306a36Sopenharmony_ci return -EOPNOTSUPP; 642762306a36Sopenharmony_ci } 642862306a36Sopenharmony_ci 642962306a36Sopenharmony_ci return 0; 643062306a36Sopenharmony_ci} 643162306a36Sopenharmony_ci 643262306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE || CONFIG_CHELSIO_IPSEC_INLINE */ 643362306a36Sopenharmony_ci 643462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 643562306a36Sopenharmony_ci 643662306a36Sopenharmony_cistatic int cxgb4_ktls_dev_add(struct net_device *netdev, struct sock *sk, 643762306a36Sopenharmony_ci enum tls_offload_ctx_dir direction, 643862306a36Sopenharmony_ci struct tls_crypto_info *crypto_info, 643962306a36Sopenharmony_ci u32 tcp_sn) 644062306a36Sopenharmony_ci{ 644162306a36Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 644262306a36Sopenharmony_ci int ret; 644362306a36Sopenharmony_ci 644462306a36Sopenharmony_ci mutex_lock(&uld_mutex); 644562306a36Sopenharmony_ci ret = chcr_offload_state(adap, CXGB4_TLSDEV_OPS); 644662306a36Sopenharmony_ci if (ret) 644762306a36Sopenharmony_ci goto out_unlock; 644862306a36Sopenharmony_ci 644962306a36Sopenharmony_ci ret = cxgb4_set_ktls_feature(adap, FW_PARAMS_PARAM_DEV_KTLS_HW_ENABLE); 645062306a36Sopenharmony_ci if (ret) 645162306a36Sopenharmony_ci goto out_unlock; 645262306a36Sopenharmony_ci 645362306a36Sopenharmony_ci ret = adap->uld[CXGB4_ULD_KTLS].tlsdev_ops->tls_dev_add(netdev, sk, 645462306a36Sopenharmony_ci direction, 645562306a36Sopenharmony_ci crypto_info, 645662306a36Sopenharmony_ci tcp_sn); 645762306a36Sopenharmony_ci /* if there is a failure, clear the refcount */ 645862306a36Sopenharmony_ci if (ret) 645962306a36Sopenharmony_ci cxgb4_set_ktls_feature(adap, 646062306a36Sopenharmony_ci FW_PARAMS_PARAM_DEV_KTLS_HW_DISABLE); 646162306a36Sopenharmony_ciout_unlock: 646262306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 646362306a36Sopenharmony_ci return ret; 646462306a36Sopenharmony_ci} 646562306a36Sopenharmony_ci 646662306a36Sopenharmony_cistatic void cxgb4_ktls_dev_del(struct net_device *netdev, 646762306a36Sopenharmony_ci struct tls_context *tls_ctx, 646862306a36Sopenharmony_ci enum tls_offload_ctx_dir direction) 646962306a36Sopenharmony_ci{ 647062306a36Sopenharmony_ci struct adapter *adap = netdev2adap(netdev); 647162306a36Sopenharmony_ci 647262306a36Sopenharmony_ci mutex_lock(&uld_mutex); 647362306a36Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_TLSDEV_OPS)) 647462306a36Sopenharmony_ci goto out_unlock; 647562306a36Sopenharmony_ci 647662306a36Sopenharmony_ci adap->uld[CXGB4_ULD_KTLS].tlsdev_ops->tls_dev_del(netdev, tls_ctx, 647762306a36Sopenharmony_ci direction); 647862306a36Sopenharmony_ci 647962306a36Sopenharmony_ciout_unlock: 648062306a36Sopenharmony_ci cxgb4_set_ktls_feature(adap, FW_PARAMS_PARAM_DEV_KTLS_HW_DISABLE); 648162306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 648262306a36Sopenharmony_ci} 648362306a36Sopenharmony_ci 648462306a36Sopenharmony_cistatic const struct tlsdev_ops cxgb4_ktls_ops = { 648562306a36Sopenharmony_ci .tls_dev_add = cxgb4_ktls_dev_add, 648662306a36Sopenharmony_ci .tls_dev_del = cxgb4_ktls_dev_del, 648762306a36Sopenharmony_ci}; 648862306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */ 648962306a36Sopenharmony_ci 649062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 649162306a36Sopenharmony_ci 649262306a36Sopenharmony_cistatic int cxgb4_xfrm_add_state(struct xfrm_state *x, 649362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 649462306a36Sopenharmony_ci{ 649562306a36Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 649662306a36Sopenharmony_ci int ret; 649762306a36Sopenharmony_ci 649862306a36Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 649962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "crypto uld critical resource is under use"); 650062306a36Sopenharmony_ci return -EBUSY; 650162306a36Sopenharmony_ci } 650262306a36Sopenharmony_ci ret = chcr_offload_state(adap, CXGB4_XFRMDEV_OPS); 650362306a36Sopenharmony_ci if (ret) 650462306a36Sopenharmony_ci goto out_unlock; 650562306a36Sopenharmony_ci 650662306a36Sopenharmony_ci ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_add(x, extack); 650762306a36Sopenharmony_ci 650862306a36Sopenharmony_ciout_unlock: 650962306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 651062306a36Sopenharmony_ci 651162306a36Sopenharmony_ci return ret; 651262306a36Sopenharmony_ci} 651362306a36Sopenharmony_ci 651462306a36Sopenharmony_cistatic void cxgb4_xfrm_del_state(struct xfrm_state *x) 651562306a36Sopenharmony_ci{ 651662306a36Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 651762306a36Sopenharmony_ci 651862306a36Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 651962306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 652062306a36Sopenharmony_ci "crypto uld critical resource is under use\n"); 652162306a36Sopenharmony_ci return; 652262306a36Sopenharmony_ci } 652362306a36Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 652462306a36Sopenharmony_ci goto out_unlock; 652562306a36Sopenharmony_ci 652662306a36Sopenharmony_ci adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_delete(x); 652762306a36Sopenharmony_ci 652862306a36Sopenharmony_ciout_unlock: 652962306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 653062306a36Sopenharmony_ci} 653162306a36Sopenharmony_ci 653262306a36Sopenharmony_cistatic void cxgb4_xfrm_free_state(struct xfrm_state *x) 653362306a36Sopenharmony_ci{ 653462306a36Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 653562306a36Sopenharmony_ci 653662306a36Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 653762306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 653862306a36Sopenharmony_ci "crypto uld critical resource is under use\n"); 653962306a36Sopenharmony_ci return; 654062306a36Sopenharmony_ci } 654162306a36Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 654262306a36Sopenharmony_ci goto out_unlock; 654362306a36Sopenharmony_ci 654462306a36Sopenharmony_ci adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_free(x); 654562306a36Sopenharmony_ci 654662306a36Sopenharmony_ciout_unlock: 654762306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 654862306a36Sopenharmony_ci} 654962306a36Sopenharmony_ci 655062306a36Sopenharmony_cistatic bool cxgb4_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *x) 655162306a36Sopenharmony_ci{ 655262306a36Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 655362306a36Sopenharmony_ci bool ret = false; 655462306a36Sopenharmony_ci 655562306a36Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 655662306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 655762306a36Sopenharmony_ci "crypto uld critical resource is under use\n"); 655862306a36Sopenharmony_ci return ret; 655962306a36Sopenharmony_ci } 656062306a36Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 656162306a36Sopenharmony_ci goto out_unlock; 656262306a36Sopenharmony_ci 656362306a36Sopenharmony_ci ret = adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_offload_ok(skb, x); 656462306a36Sopenharmony_ci 656562306a36Sopenharmony_ciout_unlock: 656662306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 656762306a36Sopenharmony_ci return ret; 656862306a36Sopenharmony_ci} 656962306a36Sopenharmony_ci 657062306a36Sopenharmony_cistatic void cxgb4_advance_esn_state(struct xfrm_state *x) 657162306a36Sopenharmony_ci{ 657262306a36Sopenharmony_ci struct adapter *adap = netdev2adap(x->xso.dev); 657362306a36Sopenharmony_ci 657462306a36Sopenharmony_ci if (!mutex_trylock(&uld_mutex)) { 657562306a36Sopenharmony_ci dev_dbg(adap->pdev_dev, 657662306a36Sopenharmony_ci "crypto uld critical resource is under use\n"); 657762306a36Sopenharmony_ci return; 657862306a36Sopenharmony_ci } 657962306a36Sopenharmony_ci if (chcr_offload_state(adap, CXGB4_XFRMDEV_OPS)) 658062306a36Sopenharmony_ci goto out_unlock; 658162306a36Sopenharmony_ci 658262306a36Sopenharmony_ci adap->uld[CXGB4_ULD_IPSEC].xfrmdev_ops->xdo_dev_state_advance_esn(x); 658362306a36Sopenharmony_ci 658462306a36Sopenharmony_ciout_unlock: 658562306a36Sopenharmony_ci mutex_unlock(&uld_mutex); 658662306a36Sopenharmony_ci} 658762306a36Sopenharmony_ci 658862306a36Sopenharmony_cistatic const struct xfrmdev_ops cxgb4_xfrmdev_ops = { 658962306a36Sopenharmony_ci .xdo_dev_state_add = cxgb4_xfrm_add_state, 659062306a36Sopenharmony_ci .xdo_dev_state_delete = cxgb4_xfrm_del_state, 659162306a36Sopenharmony_ci .xdo_dev_state_free = cxgb4_xfrm_free_state, 659262306a36Sopenharmony_ci .xdo_dev_offload_ok = cxgb4_ipsec_offload_ok, 659362306a36Sopenharmony_ci .xdo_dev_state_advance_esn = cxgb4_advance_esn_state, 659462306a36Sopenharmony_ci}; 659562306a36Sopenharmony_ci 659662306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ 659762306a36Sopenharmony_ci 659862306a36Sopenharmony_cistatic int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 659962306a36Sopenharmony_ci{ 660062306a36Sopenharmony_ci struct net_device *netdev; 660162306a36Sopenharmony_ci struct adapter *adapter; 660262306a36Sopenharmony_ci static int adap_idx = 1; 660362306a36Sopenharmony_ci int s_qpp, qpp, num_seg; 660462306a36Sopenharmony_ci struct port_info *pi; 660562306a36Sopenharmony_ci enum chip_type chip; 660662306a36Sopenharmony_ci void __iomem *regs; 660762306a36Sopenharmony_ci int func, chip_ver; 660862306a36Sopenharmony_ci u16 device_id; 660962306a36Sopenharmony_ci int i, err; 661062306a36Sopenharmony_ci u32 whoami; 661162306a36Sopenharmony_ci 661262306a36Sopenharmony_ci err = pci_request_regions(pdev, KBUILD_MODNAME); 661362306a36Sopenharmony_ci if (err) { 661462306a36Sopenharmony_ci /* Just info, some other driver may have claimed the device. */ 661562306a36Sopenharmony_ci dev_info(&pdev->dev, "cannot obtain PCI resources\n"); 661662306a36Sopenharmony_ci return err; 661762306a36Sopenharmony_ci } 661862306a36Sopenharmony_ci 661962306a36Sopenharmony_ci err = pci_enable_device(pdev); 662062306a36Sopenharmony_ci if (err) { 662162306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot enable PCI device\n"); 662262306a36Sopenharmony_ci goto out_release_regions; 662362306a36Sopenharmony_ci } 662462306a36Sopenharmony_ci 662562306a36Sopenharmony_ci regs = pci_ioremap_bar(pdev, 0); 662662306a36Sopenharmony_ci if (!regs) { 662762306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot map device registers\n"); 662862306a36Sopenharmony_ci err = -ENOMEM; 662962306a36Sopenharmony_ci goto out_disable_device; 663062306a36Sopenharmony_ci } 663162306a36Sopenharmony_ci 663262306a36Sopenharmony_ci adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); 663362306a36Sopenharmony_ci if (!adapter) { 663462306a36Sopenharmony_ci err = -ENOMEM; 663562306a36Sopenharmony_ci goto out_unmap_bar0; 663662306a36Sopenharmony_ci } 663762306a36Sopenharmony_ci 663862306a36Sopenharmony_ci adapter->regs = regs; 663962306a36Sopenharmony_ci err = t4_wait_dev_ready(regs); 664062306a36Sopenharmony_ci if (err < 0) 664162306a36Sopenharmony_ci goto out_free_adapter; 664262306a36Sopenharmony_ci 664362306a36Sopenharmony_ci /* We control everything through one PF */ 664462306a36Sopenharmony_ci whoami = t4_read_reg(adapter, PL_WHOAMI_A); 664562306a36Sopenharmony_ci pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 664662306a36Sopenharmony_ci chip = t4_get_chip_type(adapter, CHELSIO_PCI_ID_VER(device_id)); 664762306a36Sopenharmony_ci if ((int)chip < 0) { 664862306a36Sopenharmony_ci dev_err(&pdev->dev, "Device %d is not supported\n", device_id); 664962306a36Sopenharmony_ci err = chip; 665062306a36Sopenharmony_ci goto out_free_adapter; 665162306a36Sopenharmony_ci } 665262306a36Sopenharmony_ci chip_ver = CHELSIO_CHIP_VERSION(chip); 665362306a36Sopenharmony_ci func = chip_ver <= CHELSIO_T5 ? 665462306a36Sopenharmony_ci SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); 665562306a36Sopenharmony_ci 665662306a36Sopenharmony_ci adapter->pdev = pdev; 665762306a36Sopenharmony_ci adapter->pdev_dev = &pdev->dev; 665862306a36Sopenharmony_ci adapter->name = pci_name(pdev); 665962306a36Sopenharmony_ci adapter->mbox = func; 666062306a36Sopenharmony_ci adapter->pf = func; 666162306a36Sopenharmony_ci adapter->params.chip = chip; 666262306a36Sopenharmony_ci adapter->adap_idx = adap_idx; 666362306a36Sopenharmony_ci adapter->msg_enable = DFLT_MSG_ENABLE; 666462306a36Sopenharmony_ci adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) + 666562306a36Sopenharmony_ci (sizeof(struct mbox_cmd) * 666662306a36Sopenharmony_ci T4_OS_LOG_MBOX_CMDS), 666762306a36Sopenharmony_ci GFP_KERNEL); 666862306a36Sopenharmony_ci if (!adapter->mbox_log) { 666962306a36Sopenharmony_ci err = -ENOMEM; 667062306a36Sopenharmony_ci goto out_free_adapter; 667162306a36Sopenharmony_ci } 667262306a36Sopenharmony_ci spin_lock_init(&adapter->mbox_lock); 667362306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->mlist.list); 667462306a36Sopenharmony_ci adapter->mbox_log->size = T4_OS_LOG_MBOX_CMDS; 667562306a36Sopenharmony_ci pci_set_drvdata(pdev, adapter); 667662306a36Sopenharmony_ci 667762306a36Sopenharmony_ci if (func != ent->driver_data) { 667862306a36Sopenharmony_ci pci_disable_device(pdev); 667962306a36Sopenharmony_ci pci_save_state(pdev); /* to restore SR-IOV later */ 668062306a36Sopenharmony_ci return 0; 668162306a36Sopenharmony_ci } 668262306a36Sopenharmony_ci 668362306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 668462306a36Sopenharmony_ci if (err) { 668562306a36Sopenharmony_ci dev_err(&pdev->dev, "no usable DMA configuration\n"); 668662306a36Sopenharmony_ci goto out_free_adapter; 668762306a36Sopenharmony_ci } 668862306a36Sopenharmony_ci 668962306a36Sopenharmony_ci pci_set_master(pdev); 669062306a36Sopenharmony_ci pci_save_state(pdev); 669162306a36Sopenharmony_ci adap_idx++; 669262306a36Sopenharmony_ci adapter->workq = create_singlethread_workqueue("cxgb4"); 669362306a36Sopenharmony_ci if (!adapter->workq) { 669462306a36Sopenharmony_ci err = -ENOMEM; 669562306a36Sopenharmony_ci goto out_free_adapter; 669662306a36Sopenharmony_ci } 669762306a36Sopenharmony_ci 669862306a36Sopenharmony_ci /* PCI device has been enabled */ 669962306a36Sopenharmony_ci adapter->flags |= CXGB4_DEV_ENABLED; 670062306a36Sopenharmony_ci memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map)); 670162306a36Sopenharmony_ci 670262306a36Sopenharmony_ci /* If possible, we use PCIe Relaxed Ordering Attribute to deliver 670362306a36Sopenharmony_ci * Ingress Packet Data to Free List Buffers in order to allow for 670462306a36Sopenharmony_ci * chipset performance optimizations between the Root Complex and 670562306a36Sopenharmony_ci * Memory Controllers. (Messages to the associated Ingress Queue 670662306a36Sopenharmony_ci * notifying new Packet Placement in the Free Lists Buffers will be 670762306a36Sopenharmony_ci * send without the Relaxed Ordering Attribute thus guaranteeing that 670862306a36Sopenharmony_ci * all preceding PCIe Transaction Layer Packets will be processed 670962306a36Sopenharmony_ci * first.) But some Root Complexes have various issues with Upstream 671062306a36Sopenharmony_ci * Transaction Layer Packets with the Relaxed Ordering Attribute set. 671162306a36Sopenharmony_ci * The PCIe devices which under the Root Complexes will be cleared the 671262306a36Sopenharmony_ci * Relaxed Ordering bit in the configuration space, So we check our 671362306a36Sopenharmony_ci * PCIe configuration space to see if it's flagged with advice against 671462306a36Sopenharmony_ci * using Relaxed Ordering. 671562306a36Sopenharmony_ci */ 671662306a36Sopenharmony_ci if (!pcie_relaxed_ordering_enabled(pdev)) 671762306a36Sopenharmony_ci adapter->flags |= CXGB4_ROOT_NO_RELAXED_ORDERING; 671862306a36Sopenharmony_ci 671962306a36Sopenharmony_ci spin_lock_init(&adapter->stats_lock); 672062306a36Sopenharmony_ci spin_lock_init(&adapter->tid_release_lock); 672162306a36Sopenharmony_ci spin_lock_init(&adapter->win0_lock); 672262306a36Sopenharmony_ci 672362306a36Sopenharmony_ci INIT_WORK(&adapter->tid_release_task, process_tid_release_list); 672462306a36Sopenharmony_ci INIT_WORK(&adapter->db_full_task, process_db_full); 672562306a36Sopenharmony_ci INIT_WORK(&adapter->db_drop_task, process_db_drop); 672662306a36Sopenharmony_ci INIT_WORK(&adapter->fatal_err_notify_task, notify_fatal_err); 672762306a36Sopenharmony_ci 672862306a36Sopenharmony_ci err = t4_prep_adapter(adapter); 672962306a36Sopenharmony_ci if (err) 673062306a36Sopenharmony_ci goto out_free_adapter; 673162306a36Sopenharmony_ci 673262306a36Sopenharmony_ci if (is_kdump_kernel()) { 673362306a36Sopenharmony_ci /* Collect hardware state and append to /proc/vmcore */ 673462306a36Sopenharmony_ci err = cxgb4_cudbg_vmcore_add_dump(adapter); 673562306a36Sopenharmony_ci if (err) { 673662306a36Sopenharmony_ci dev_warn(adapter->pdev_dev, 673762306a36Sopenharmony_ci "Fail collecting vmcore device dump, err: %d. Continuing\n", 673862306a36Sopenharmony_ci err); 673962306a36Sopenharmony_ci err = 0; 674062306a36Sopenharmony_ci } 674162306a36Sopenharmony_ci } 674262306a36Sopenharmony_ci 674362306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) { 674462306a36Sopenharmony_ci s_qpp = (QUEUESPERPAGEPF0_S + 674562306a36Sopenharmony_ci (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * 674662306a36Sopenharmony_ci adapter->pf); 674762306a36Sopenharmony_ci qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter, 674862306a36Sopenharmony_ci SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp); 674962306a36Sopenharmony_ci num_seg = PAGE_SIZE / SEGMENT_SIZE; 675062306a36Sopenharmony_ci 675162306a36Sopenharmony_ci /* Each segment size is 128B. Write coalescing is enabled only 675262306a36Sopenharmony_ci * when SGE_EGRESS_QUEUES_PER_PAGE_PF reg value for the 675362306a36Sopenharmony_ci * queue is less no of segments that can be accommodated in 675462306a36Sopenharmony_ci * a page size. 675562306a36Sopenharmony_ci */ 675662306a36Sopenharmony_ci if (qpp > num_seg) { 675762306a36Sopenharmony_ci dev_err(&pdev->dev, 675862306a36Sopenharmony_ci "Incorrect number of egress queues per page\n"); 675962306a36Sopenharmony_ci err = -EINVAL; 676062306a36Sopenharmony_ci goto out_free_adapter; 676162306a36Sopenharmony_ci } 676262306a36Sopenharmony_ci adapter->bar2 = ioremap_wc(pci_resource_start(pdev, 2), 676362306a36Sopenharmony_ci pci_resource_len(pdev, 2)); 676462306a36Sopenharmony_ci if (!adapter->bar2) { 676562306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot map device bar2 region\n"); 676662306a36Sopenharmony_ci err = -ENOMEM; 676762306a36Sopenharmony_ci goto out_free_adapter; 676862306a36Sopenharmony_ci } 676962306a36Sopenharmony_ci } 677062306a36Sopenharmony_ci 677162306a36Sopenharmony_ci setup_memwin(adapter); 677262306a36Sopenharmony_ci err = adap_init0(adapter, 0); 677362306a36Sopenharmony_ci if (err) 677462306a36Sopenharmony_ci goto out_unmap_bar; 677562306a36Sopenharmony_ci 677662306a36Sopenharmony_ci setup_memwin_rdma(adapter); 677762306a36Sopenharmony_ci 677862306a36Sopenharmony_ci /* configure SGE_STAT_CFG_A to read WC stats */ 677962306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) 678062306a36Sopenharmony_ci t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7) | 678162306a36Sopenharmony_ci (is_t5(adapter->params.chip) ? STATMODE_V(0) : 678262306a36Sopenharmony_ci T6_STATMODE_V(0))); 678362306a36Sopenharmony_ci 678462306a36Sopenharmony_ci /* Initialize hash mac addr list */ 678562306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->mac_hlist); 678662306a36Sopenharmony_ci 678762306a36Sopenharmony_ci for_each_port(adapter, i) { 678862306a36Sopenharmony_ci /* For supporting MQPRIO Offload, need some extra 678962306a36Sopenharmony_ci * queues for each ETHOFLD TIDs. Keep it equal to 679062306a36Sopenharmony_ci * MAX_ATIDs for now. Once we connect to firmware 679162306a36Sopenharmony_ci * later and query the EOTID params, we'll come to 679262306a36Sopenharmony_ci * know the actual # of EOTIDs supported. 679362306a36Sopenharmony_ci */ 679462306a36Sopenharmony_ci netdev = alloc_etherdev_mq(sizeof(struct port_info), 679562306a36Sopenharmony_ci MAX_ETH_QSETS + MAX_ATIDS); 679662306a36Sopenharmony_ci if (!netdev) { 679762306a36Sopenharmony_ci err = -ENOMEM; 679862306a36Sopenharmony_ci goto out_free_dev; 679962306a36Sopenharmony_ci } 680062306a36Sopenharmony_ci 680162306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 680262306a36Sopenharmony_ci 680362306a36Sopenharmony_ci adapter->port[i] = netdev; 680462306a36Sopenharmony_ci pi = netdev_priv(netdev); 680562306a36Sopenharmony_ci pi->adapter = adapter; 680662306a36Sopenharmony_ci pi->xact_addr_filt = -1; 680762306a36Sopenharmony_ci pi->port_id = i; 680862306a36Sopenharmony_ci netdev->irq = pdev->irq; 680962306a36Sopenharmony_ci 681062306a36Sopenharmony_ci netdev->hw_features = NETIF_F_SG | TSO_FLAGS | 681162306a36Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 681262306a36Sopenharmony_ci NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_GRO | 681362306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | 681462306a36Sopenharmony_ci NETIF_F_HW_TC | NETIF_F_NTUPLE | NETIF_F_HIGHDMA; 681562306a36Sopenharmony_ci 681662306a36Sopenharmony_ci if (chip_ver > CHELSIO_T5) { 681762306a36Sopenharmony_ci netdev->hw_enc_features |= NETIF_F_IP_CSUM | 681862306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | 681962306a36Sopenharmony_ci NETIF_F_RXCSUM | 682062306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 682162306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 682262306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6; 682362306a36Sopenharmony_ci 682462306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL | 682562306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 682662306a36Sopenharmony_ci NETIF_F_HW_TLS_RECORD; 682762306a36Sopenharmony_ci 682862306a36Sopenharmony_ci if (adapter->rawf_cnt) 682962306a36Sopenharmony_ci netdev->udp_tunnel_nic_info = &cxgb_udp_tunnels; 683062306a36Sopenharmony_ci } 683162306a36Sopenharmony_ci 683262306a36Sopenharmony_ci netdev->features |= netdev->hw_features; 683362306a36Sopenharmony_ci netdev->vlan_features = netdev->features & VLAN_FEAT; 683462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) 683562306a36Sopenharmony_ci if (pi->adapter->params.crypto & FW_CAPS_CONFIG_TLS_HW) { 683662306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_HW_TLS_TX; 683762306a36Sopenharmony_ci netdev->tlsdev_ops = &cxgb4_ktls_ops; 683862306a36Sopenharmony_ci /* initialize the refcount */ 683962306a36Sopenharmony_ci refcount_set(&pi->adapter->chcr_ktls.ktls_refcount, 0); 684062306a36Sopenharmony_ci } 684162306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_TLS_DEVICE */ 684262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CHELSIO_IPSEC_INLINE) 684362306a36Sopenharmony_ci if (pi->adapter->params.crypto & FW_CAPS_CONFIG_IPSEC_INLINE) { 684462306a36Sopenharmony_ci netdev->hw_enc_features |= NETIF_F_HW_ESP; 684562306a36Sopenharmony_ci netdev->features |= NETIF_F_HW_ESP; 684662306a36Sopenharmony_ci netdev->xfrmdev_ops = &cxgb4_xfrmdev_ops; 684762306a36Sopenharmony_ci } 684862306a36Sopenharmony_ci#endif /* CONFIG_CHELSIO_IPSEC_INLINE */ 684962306a36Sopenharmony_ci 685062306a36Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 685162306a36Sopenharmony_ci 685262306a36Sopenharmony_ci /* MTU range: 81 - 9600 */ 685362306a36Sopenharmony_ci netdev->min_mtu = 81; /* accommodate SACK */ 685462306a36Sopenharmony_ci netdev->max_mtu = MAX_MTU; 685562306a36Sopenharmony_ci 685662306a36Sopenharmony_ci netdev->netdev_ops = &cxgb4_netdev_ops; 685762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 685862306a36Sopenharmony_ci netdev->dcbnl_ops = &cxgb4_dcb_ops; 685962306a36Sopenharmony_ci cxgb4_dcb_state_init(netdev); 686062306a36Sopenharmony_ci cxgb4_dcb_version_init(netdev); 686162306a36Sopenharmony_ci#endif 686262306a36Sopenharmony_ci cxgb4_set_ethtool_ops(netdev); 686362306a36Sopenharmony_ci } 686462306a36Sopenharmony_ci 686562306a36Sopenharmony_ci cxgb4_init_ethtool_dump(adapter); 686662306a36Sopenharmony_ci 686762306a36Sopenharmony_ci pci_set_drvdata(pdev, adapter); 686862306a36Sopenharmony_ci 686962306a36Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) { 687062306a36Sopenharmony_ci err = t4_port_init(adapter, func, func, 0); 687162306a36Sopenharmony_ci if (err) 687262306a36Sopenharmony_ci goto out_free_dev; 687362306a36Sopenharmony_ci } else if (adapter->params.nports == 1) { 687462306a36Sopenharmony_ci /* If we don't have a connection to the firmware -- possibly 687562306a36Sopenharmony_ci * because of an error -- grab the raw VPD parameters so we 687662306a36Sopenharmony_ci * can set the proper MAC Address on the debug network 687762306a36Sopenharmony_ci * interface that we've created. 687862306a36Sopenharmony_ci */ 687962306a36Sopenharmony_ci u8 hw_addr[ETH_ALEN]; 688062306a36Sopenharmony_ci u8 *na = adapter->params.vpd.na; 688162306a36Sopenharmony_ci 688262306a36Sopenharmony_ci err = t4_get_raw_vpd_params(adapter, &adapter->params.vpd); 688362306a36Sopenharmony_ci if (!err) { 688462306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 688562306a36Sopenharmony_ci hw_addr[i] = (hex2val(na[2 * i + 0]) * 16 + 688662306a36Sopenharmony_ci hex2val(na[2 * i + 1])); 688762306a36Sopenharmony_ci t4_set_hw_addr(adapter, 0, hw_addr); 688862306a36Sopenharmony_ci } 688962306a36Sopenharmony_ci } 689062306a36Sopenharmony_ci 689162306a36Sopenharmony_ci if (!(adapter->flags & CXGB4_FW_OK)) 689262306a36Sopenharmony_ci goto fw_attach_fail; 689362306a36Sopenharmony_ci 689462306a36Sopenharmony_ci /* Configure queues and allocate tables now, they can be needed as 689562306a36Sopenharmony_ci * soon as the first register_netdev completes. 689662306a36Sopenharmony_ci */ 689762306a36Sopenharmony_ci err = cfg_queues(adapter); 689862306a36Sopenharmony_ci if (err) 689962306a36Sopenharmony_ci goto out_free_dev; 690062306a36Sopenharmony_ci 690162306a36Sopenharmony_ci adapter->smt = t4_init_smt(); 690262306a36Sopenharmony_ci if (!adapter->smt) { 690362306a36Sopenharmony_ci /* We tolerate a lack of SMT, giving up some functionality */ 690462306a36Sopenharmony_ci dev_warn(&pdev->dev, "could not allocate SMT, continuing\n"); 690562306a36Sopenharmony_ci } 690662306a36Sopenharmony_ci 690762306a36Sopenharmony_ci adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end); 690862306a36Sopenharmony_ci if (!adapter->l2t) { 690962306a36Sopenharmony_ci /* We tolerate a lack of L2T, giving up some functionality */ 691062306a36Sopenharmony_ci dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); 691162306a36Sopenharmony_ci adapter->params.offload = 0; 691262306a36Sopenharmony_ci } 691362306a36Sopenharmony_ci 691462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 691562306a36Sopenharmony_ci if (chip_ver <= CHELSIO_T5 && 691662306a36Sopenharmony_ci (!(t4_read_reg(adapter, LE_DB_CONFIG_A) & ASLIPCOMPEN_F))) { 691762306a36Sopenharmony_ci /* CLIP functionality is not present in hardware, 691862306a36Sopenharmony_ci * hence disable all offload features 691962306a36Sopenharmony_ci */ 692062306a36Sopenharmony_ci dev_warn(&pdev->dev, 692162306a36Sopenharmony_ci "CLIP not enabled in hardware, continuing\n"); 692262306a36Sopenharmony_ci adapter->params.offload = 0; 692362306a36Sopenharmony_ci } else { 692462306a36Sopenharmony_ci adapter->clipt = t4_init_clip_tbl(adapter->clipt_start, 692562306a36Sopenharmony_ci adapter->clipt_end); 692662306a36Sopenharmony_ci if (!adapter->clipt) { 692762306a36Sopenharmony_ci /* We tolerate a lack of clip_table, giving up 692862306a36Sopenharmony_ci * some functionality 692962306a36Sopenharmony_ci */ 693062306a36Sopenharmony_ci dev_warn(&pdev->dev, 693162306a36Sopenharmony_ci "could not allocate Clip table, continuing\n"); 693262306a36Sopenharmony_ci adapter->params.offload = 0; 693362306a36Sopenharmony_ci } 693462306a36Sopenharmony_ci } 693562306a36Sopenharmony_ci#endif 693662306a36Sopenharmony_ci 693762306a36Sopenharmony_ci for_each_port(adapter, i) { 693862306a36Sopenharmony_ci pi = adap2pinfo(adapter, i); 693962306a36Sopenharmony_ci pi->sched_tbl = t4_init_sched(adapter->params.nsched_cls); 694062306a36Sopenharmony_ci if (!pi->sched_tbl) 694162306a36Sopenharmony_ci dev_warn(&pdev->dev, 694262306a36Sopenharmony_ci "could not activate scheduling on port %d\n", 694362306a36Sopenharmony_ci i); 694462306a36Sopenharmony_ci } 694562306a36Sopenharmony_ci 694662306a36Sopenharmony_ci if (is_offload(adapter) || is_hashfilter(adapter)) { 694762306a36Sopenharmony_ci if (t4_read_reg(adapter, LE_DB_CONFIG_A) & HASHEN_F) { 694862306a36Sopenharmony_ci u32 v; 694962306a36Sopenharmony_ci 695062306a36Sopenharmony_ci v = t4_read_reg(adapter, LE_DB_HASH_CONFIG_A); 695162306a36Sopenharmony_ci if (chip_ver <= CHELSIO_T5) { 695262306a36Sopenharmony_ci adapter->tids.nhash = 1 << HASHTIDSIZE_G(v); 695362306a36Sopenharmony_ci v = t4_read_reg(adapter, LE_DB_TID_HASHBASE_A); 695462306a36Sopenharmony_ci adapter->tids.hash_base = v / 4; 695562306a36Sopenharmony_ci } else { 695662306a36Sopenharmony_ci adapter->tids.nhash = HASHTBLSIZE_G(v) << 3; 695762306a36Sopenharmony_ci v = t4_read_reg(adapter, 695862306a36Sopenharmony_ci T6_LE_DB_HASH_TID_BASE_A); 695962306a36Sopenharmony_ci adapter->tids.hash_base = v; 696062306a36Sopenharmony_ci } 696162306a36Sopenharmony_ci } 696262306a36Sopenharmony_ci } 696362306a36Sopenharmony_ci 696462306a36Sopenharmony_ci if (tid_init(&adapter->tids) < 0) { 696562306a36Sopenharmony_ci dev_warn(&pdev->dev, "could not allocate TID table, " 696662306a36Sopenharmony_ci "continuing\n"); 696762306a36Sopenharmony_ci adapter->params.offload = 0; 696862306a36Sopenharmony_ci } else { 696962306a36Sopenharmony_ci adapter->tc_u32 = cxgb4_init_tc_u32(adapter); 697062306a36Sopenharmony_ci if (!adapter->tc_u32) 697162306a36Sopenharmony_ci dev_warn(&pdev->dev, 697262306a36Sopenharmony_ci "could not offload tc u32, continuing\n"); 697362306a36Sopenharmony_ci 697462306a36Sopenharmony_ci if (cxgb4_init_tc_flower(adapter)) 697562306a36Sopenharmony_ci dev_warn(&pdev->dev, 697662306a36Sopenharmony_ci "could not offload tc flower, continuing\n"); 697762306a36Sopenharmony_ci 697862306a36Sopenharmony_ci if (cxgb4_init_tc_mqprio(adapter)) 697962306a36Sopenharmony_ci dev_warn(&pdev->dev, 698062306a36Sopenharmony_ci "could not offload tc mqprio, continuing\n"); 698162306a36Sopenharmony_ci 698262306a36Sopenharmony_ci if (cxgb4_init_tc_matchall(adapter)) 698362306a36Sopenharmony_ci dev_warn(&pdev->dev, 698462306a36Sopenharmony_ci "could not offload tc matchall, continuing\n"); 698562306a36Sopenharmony_ci if (cxgb4_init_ethtool_filters(adapter)) 698662306a36Sopenharmony_ci dev_warn(&pdev->dev, 698762306a36Sopenharmony_ci "could not initialize ethtool filters, continuing\n"); 698862306a36Sopenharmony_ci } 698962306a36Sopenharmony_ci 699062306a36Sopenharmony_ci /* See what interrupts we'll be using */ 699162306a36Sopenharmony_ci if (msi > 1 && enable_msix(adapter) == 0) 699262306a36Sopenharmony_ci adapter->flags |= CXGB4_USING_MSIX; 699362306a36Sopenharmony_ci else if (msi > 0 && pci_enable_msi(pdev) == 0) { 699462306a36Sopenharmony_ci adapter->flags |= CXGB4_USING_MSI; 699562306a36Sopenharmony_ci if (msi > 1) 699662306a36Sopenharmony_ci free_msix_info(adapter); 699762306a36Sopenharmony_ci } 699862306a36Sopenharmony_ci 699962306a36Sopenharmony_ci /* check for PCI Express bandwidth capabiltites */ 700062306a36Sopenharmony_ci pcie_print_link_status(pdev); 700162306a36Sopenharmony_ci 700262306a36Sopenharmony_ci cxgb4_init_mps_ref_entries(adapter); 700362306a36Sopenharmony_ci 700462306a36Sopenharmony_ci err = init_rss(adapter); 700562306a36Sopenharmony_ci if (err) 700662306a36Sopenharmony_ci goto out_free_dev; 700762306a36Sopenharmony_ci 700862306a36Sopenharmony_ci err = setup_non_data_intr(adapter); 700962306a36Sopenharmony_ci if (err) { 701062306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 701162306a36Sopenharmony_ci "Non Data interrupt allocation failed, err: %d\n", err); 701262306a36Sopenharmony_ci goto out_free_dev; 701362306a36Sopenharmony_ci } 701462306a36Sopenharmony_ci 701562306a36Sopenharmony_ci err = setup_fw_sge_queues(adapter); 701662306a36Sopenharmony_ci if (err) { 701762306a36Sopenharmony_ci dev_err(adapter->pdev_dev, 701862306a36Sopenharmony_ci "FW sge queue allocation failed, err %d", err); 701962306a36Sopenharmony_ci goto out_free_dev; 702062306a36Sopenharmony_ci } 702162306a36Sopenharmony_ci 702262306a36Sopenharmony_cifw_attach_fail: 702362306a36Sopenharmony_ci /* 702462306a36Sopenharmony_ci * The card is now ready to go. If any errors occur during device 702562306a36Sopenharmony_ci * registration we do not fail the whole card but rather proceed only 702662306a36Sopenharmony_ci * with the ports we manage to register successfully. However we must 702762306a36Sopenharmony_ci * register at least one net device. 702862306a36Sopenharmony_ci */ 702962306a36Sopenharmony_ci for_each_port(adapter, i) { 703062306a36Sopenharmony_ci pi = adap2pinfo(adapter, i); 703162306a36Sopenharmony_ci adapter->port[i]->dev_port = pi->lport; 703262306a36Sopenharmony_ci netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); 703362306a36Sopenharmony_ci netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); 703462306a36Sopenharmony_ci 703562306a36Sopenharmony_ci netif_carrier_off(adapter->port[i]); 703662306a36Sopenharmony_ci 703762306a36Sopenharmony_ci err = register_netdev(adapter->port[i]); 703862306a36Sopenharmony_ci if (err) 703962306a36Sopenharmony_ci break; 704062306a36Sopenharmony_ci adapter->chan_map[pi->tx_chan] = i; 704162306a36Sopenharmony_ci print_port_info(adapter->port[i]); 704262306a36Sopenharmony_ci } 704362306a36Sopenharmony_ci if (i == 0) { 704462306a36Sopenharmony_ci dev_err(&pdev->dev, "could not register any net devices\n"); 704562306a36Sopenharmony_ci goto out_free_dev; 704662306a36Sopenharmony_ci } 704762306a36Sopenharmony_ci if (err) { 704862306a36Sopenharmony_ci dev_warn(&pdev->dev, "only %d net devices registered\n", i); 704962306a36Sopenharmony_ci err = 0; 705062306a36Sopenharmony_ci } 705162306a36Sopenharmony_ci 705262306a36Sopenharmony_ci if (cxgb4_debugfs_root) { 705362306a36Sopenharmony_ci adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), 705462306a36Sopenharmony_ci cxgb4_debugfs_root); 705562306a36Sopenharmony_ci setup_debugfs(adapter); 705662306a36Sopenharmony_ci } 705762306a36Sopenharmony_ci 705862306a36Sopenharmony_ci /* PCIe EEH recovery on powerpc platforms needs fundamental reset */ 705962306a36Sopenharmony_ci pdev->needs_freset = 1; 706062306a36Sopenharmony_ci 706162306a36Sopenharmony_ci if (is_uld(adapter)) 706262306a36Sopenharmony_ci cxgb4_uld_enable(adapter); 706362306a36Sopenharmony_ci 706462306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) 706562306a36Sopenharmony_ci cxgb4_ptp_init(adapter); 706662306a36Sopenharmony_ci 706762306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_THERMAL) && 706862306a36Sopenharmony_ci !is_t4(adapter->params.chip) && (adapter->flags & CXGB4_FW_OK)) 706962306a36Sopenharmony_ci cxgb4_thermal_init(adapter); 707062306a36Sopenharmony_ci 707162306a36Sopenharmony_ci print_adapter_info(adapter); 707262306a36Sopenharmony_ci return 0; 707362306a36Sopenharmony_ci 707462306a36Sopenharmony_ci out_free_dev: 707562306a36Sopenharmony_ci t4_free_sge_resources(adapter); 707662306a36Sopenharmony_ci free_some_resources(adapter); 707762306a36Sopenharmony_ci if (adapter->flags & CXGB4_USING_MSIX) 707862306a36Sopenharmony_ci free_msix_info(adapter); 707962306a36Sopenharmony_ci if (adapter->num_uld || adapter->num_ofld_uld) 708062306a36Sopenharmony_ci t4_uld_mem_free(adapter); 708162306a36Sopenharmony_ci out_unmap_bar: 708262306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) 708362306a36Sopenharmony_ci iounmap(adapter->bar2); 708462306a36Sopenharmony_ci out_free_adapter: 708562306a36Sopenharmony_ci if (adapter->workq) 708662306a36Sopenharmony_ci destroy_workqueue(adapter->workq); 708762306a36Sopenharmony_ci 708862306a36Sopenharmony_ci kfree(adapter->mbox_log); 708962306a36Sopenharmony_ci kfree(adapter); 709062306a36Sopenharmony_ci out_unmap_bar0: 709162306a36Sopenharmony_ci iounmap(regs); 709262306a36Sopenharmony_ci out_disable_device: 709362306a36Sopenharmony_ci pci_disable_device(pdev); 709462306a36Sopenharmony_ci out_release_regions: 709562306a36Sopenharmony_ci pci_release_regions(pdev); 709662306a36Sopenharmony_ci return err; 709762306a36Sopenharmony_ci} 709862306a36Sopenharmony_ci 709962306a36Sopenharmony_cistatic void remove_one(struct pci_dev *pdev) 710062306a36Sopenharmony_ci{ 710162306a36Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 710262306a36Sopenharmony_ci struct hash_mac_addr *entry, *tmp; 710362306a36Sopenharmony_ci 710462306a36Sopenharmony_ci if (!adapter) { 710562306a36Sopenharmony_ci pci_release_regions(pdev); 710662306a36Sopenharmony_ci return; 710762306a36Sopenharmony_ci } 710862306a36Sopenharmony_ci 710962306a36Sopenharmony_ci /* If we allocated filters, free up state associated with any 711062306a36Sopenharmony_ci * valid filters ... 711162306a36Sopenharmony_ci */ 711262306a36Sopenharmony_ci clear_all_filters(adapter); 711362306a36Sopenharmony_ci 711462306a36Sopenharmony_ci adapter->flags |= CXGB4_SHUTTING_DOWN; 711562306a36Sopenharmony_ci 711662306a36Sopenharmony_ci if (adapter->pf == 4) { 711762306a36Sopenharmony_ci int i; 711862306a36Sopenharmony_ci 711962306a36Sopenharmony_ci /* Tear down per-adapter Work Queue first since it can contain 712062306a36Sopenharmony_ci * references to our adapter data structure. 712162306a36Sopenharmony_ci */ 712262306a36Sopenharmony_ci destroy_workqueue(adapter->workq); 712362306a36Sopenharmony_ci 712462306a36Sopenharmony_ci detach_ulds(adapter); 712562306a36Sopenharmony_ci 712662306a36Sopenharmony_ci for_each_port(adapter, i) 712762306a36Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 712862306a36Sopenharmony_ci unregister_netdev(adapter->port[i]); 712962306a36Sopenharmony_ci 713062306a36Sopenharmony_ci t4_uld_clean_up(adapter); 713162306a36Sopenharmony_ci 713262306a36Sopenharmony_ci adap_free_hma_mem(adapter); 713362306a36Sopenharmony_ci 713462306a36Sopenharmony_ci disable_interrupts(adapter); 713562306a36Sopenharmony_ci 713662306a36Sopenharmony_ci cxgb4_free_mps_ref_entries(adapter); 713762306a36Sopenharmony_ci 713862306a36Sopenharmony_ci debugfs_remove_recursive(adapter->debugfs_root); 713962306a36Sopenharmony_ci 714062306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) 714162306a36Sopenharmony_ci cxgb4_ptp_stop(adapter); 714262306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_THERMAL)) 714362306a36Sopenharmony_ci cxgb4_thermal_remove(adapter); 714462306a36Sopenharmony_ci 714562306a36Sopenharmony_ci if (adapter->flags & CXGB4_FULL_INIT_DONE) 714662306a36Sopenharmony_ci cxgb_down(adapter); 714762306a36Sopenharmony_ci 714862306a36Sopenharmony_ci if (adapter->flags & CXGB4_USING_MSIX) 714962306a36Sopenharmony_ci free_msix_info(adapter); 715062306a36Sopenharmony_ci if (adapter->num_uld || adapter->num_ofld_uld) 715162306a36Sopenharmony_ci t4_uld_mem_free(adapter); 715262306a36Sopenharmony_ci free_some_resources(adapter); 715362306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &adapter->mac_hlist, 715462306a36Sopenharmony_ci list) { 715562306a36Sopenharmony_ci list_del(&entry->list); 715662306a36Sopenharmony_ci kfree(entry); 715762306a36Sopenharmony_ci } 715862306a36Sopenharmony_ci 715962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 716062306a36Sopenharmony_ci t4_cleanup_clip_tbl(adapter); 716162306a36Sopenharmony_ci#endif 716262306a36Sopenharmony_ci if (!is_t4(adapter->params.chip)) 716362306a36Sopenharmony_ci iounmap(adapter->bar2); 716462306a36Sopenharmony_ci } 716562306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV 716662306a36Sopenharmony_ci else { 716762306a36Sopenharmony_ci cxgb4_iov_configure(adapter->pdev, 0); 716862306a36Sopenharmony_ci } 716962306a36Sopenharmony_ci#endif 717062306a36Sopenharmony_ci iounmap(adapter->regs); 717162306a36Sopenharmony_ci if ((adapter->flags & CXGB4_DEV_ENABLED)) { 717262306a36Sopenharmony_ci pci_disable_device(pdev); 717362306a36Sopenharmony_ci adapter->flags &= ~CXGB4_DEV_ENABLED; 717462306a36Sopenharmony_ci } 717562306a36Sopenharmony_ci pci_release_regions(pdev); 717662306a36Sopenharmony_ci kfree(adapter->mbox_log); 717762306a36Sopenharmony_ci synchronize_rcu(); 717862306a36Sopenharmony_ci kfree(adapter); 717962306a36Sopenharmony_ci} 718062306a36Sopenharmony_ci 718162306a36Sopenharmony_ci/* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt 718262306a36Sopenharmony_ci * delivery. This is essentially a stripped down version of the PCI remove() 718362306a36Sopenharmony_ci * function where we do the minimal amount of work necessary to shutdown any 718462306a36Sopenharmony_ci * further activity. 718562306a36Sopenharmony_ci */ 718662306a36Sopenharmony_cistatic void shutdown_one(struct pci_dev *pdev) 718762306a36Sopenharmony_ci{ 718862306a36Sopenharmony_ci struct adapter *adapter = pci_get_drvdata(pdev); 718962306a36Sopenharmony_ci 719062306a36Sopenharmony_ci /* As with remove_one() above (see extended comment), we only want do 719162306a36Sopenharmony_ci * do cleanup on PCI Devices which went all the way through init_one() 719262306a36Sopenharmony_ci * ... 719362306a36Sopenharmony_ci */ 719462306a36Sopenharmony_ci if (!adapter) { 719562306a36Sopenharmony_ci pci_release_regions(pdev); 719662306a36Sopenharmony_ci return; 719762306a36Sopenharmony_ci } 719862306a36Sopenharmony_ci 719962306a36Sopenharmony_ci adapter->flags |= CXGB4_SHUTTING_DOWN; 720062306a36Sopenharmony_ci 720162306a36Sopenharmony_ci if (adapter->pf == 4) { 720262306a36Sopenharmony_ci int i; 720362306a36Sopenharmony_ci 720462306a36Sopenharmony_ci for_each_port(adapter, i) 720562306a36Sopenharmony_ci if (adapter->port[i]->reg_state == NETREG_REGISTERED) 720662306a36Sopenharmony_ci cxgb_close(adapter->port[i]); 720762306a36Sopenharmony_ci 720862306a36Sopenharmony_ci rtnl_lock(); 720962306a36Sopenharmony_ci cxgb4_mqprio_stop_offload(adapter); 721062306a36Sopenharmony_ci rtnl_unlock(); 721162306a36Sopenharmony_ci 721262306a36Sopenharmony_ci if (is_uld(adapter)) { 721362306a36Sopenharmony_ci detach_ulds(adapter); 721462306a36Sopenharmony_ci t4_uld_clean_up(adapter); 721562306a36Sopenharmony_ci } 721662306a36Sopenharmony_ci 721762306a36Sopenharmony_ci disable_interrupts(adapter); 721862306a36Sopenharmony_ci disable_msi(adapter); 721962306a36Sopenharmony_ci 722062306a36Sopenharmony_ci t4_sge_stop(adapter); 722162306a36Sopenharmony_ci if (adapter->flags & CXGB4_FW_OK) 722262306a36Sopenharmony_ci t4_fw_bye(adapter, adapter->mbox); 722362306a36Sopenharmony_ci } 722462306a36Sopenharmony_ci} 722562306a36Sopenharmony_ci 722662306a36Sopenharmony_cistatic struct pci_driver cxgb4_driver = { 722762306a36Sopenharmony_ci .name = KBUILD_MODNAME, 722862306a36Sopenharmony_ci .id_table = cxgb4_pci_tbl, 722962306a36Sopenharmony_ci .probe = init_one, 723062306a36Sopenharmony_ci .remove = remove_one, 723162306a36Sopenharmony_ci .shutdown = shutdown_one, 723262306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV 723362306a36Sopenharmony_ci .sriov_configure = cxgb4_iov_configure, 723462306a36Sopenharmony_ci#endif 723562306a36Sopenharmony_ci .err_handler = &cxgb4_eeh, 723662306a36Sopenharmony_ci}; 723762306a36Sopenharmony_ci 723862306a36Sopenharmony_cistatic int __init cxgb4_init_module(void) 723962306a36Sopenharmony_ci{ 724062306a36Sopenharmony_ci int ret; 724162306a36Sopenharmony_ci 724262306a36Sopenharmony_ci cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 724362306a36Sopenharmony_ci 724462306a36Sopenharmony_ci ret = pci_register_driver(&cxgb4_driver); 724562306a36Sopenharmony_ci if (ret < 0) 724662306a36Sopenharmony_ci goto err_pci; 724762306a36Sopenharmony_ci 724862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 724962306a36Sopenharmony_ci if (!inet6addr_registered) { 725062306a36Sopenharmony_ci ret = register_inet6addr_notifier(&cxgb4_inet6addr_notifier); 725162306a36Sopenharmony_ci if (ret) 725262306a36Sopenharmony_ci pci_unregister_driver(&cxgb4_driver); 725362306a36Sopenharmony_ci else 725462306a36Sopenharmony_ci inet6addr_registered = true; 725562306a36Sopenharmony_ci } 725662306a36Sopenharmony_ci#endif 725762306a36Sopenharmony_ci 725862306a36Sopenharmony_ci if (ret == 0) 725962306a36Sopenharmony_ci return ret; 726062306a36Sopenharmony_ci 726162306a36Sopenharmony_cierr_pci: 726262306a36Sopenharmony_ci debugfs_remove(cxgb4_debugfs_root); 726362306a36Sopenharmony_ci 726462306a36Sopenharmony_ci return ret; 726562306a36Sopenharmony_ci} 726662306a36Sopenharmony_ci 726762306a36Sopenharmony_cistatic void __exit cxgb4_cleanup_module(void) 726862306a36Sopenharmony_ci{ 726962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 727062306a36Sopenharmony_ci if (inet6addr_registered) { 727162306a36Sopenharmony_ci unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); 727262306a36Sopenharmony_ci inet6addr_registered = false; 727362306a36Sopenharmony_ci } 727462306a36Sopenharmony_ci#endif 727562306a36Sopenharmony_ci pci_unregister_driver(&cxgb4_driver); 727662306a36Sopenharmony_ci debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ 727762306a36Sopenharmony_ci} 727862306a36Sopenharmony_ci 727962306a36Sopenharmony_cimodule_init(cxgb4_init_module); 728062306a36Sopenharmony_cimodule_exit(cxgb4_cleanup_module); 7281