162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015 Cavium, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/interrupt.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <linux/etherdevice.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/if_vlan.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "nic_reg.h" 1462306a36Sopenharmony_ci#include "nic.h" 1562306a36Sopenharmony_ci#include "q_struct.h" 1662306a36Sopenharmony_ci#include "thunder_bgx.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define DRV_NAME "nicpf" 1962306a36Sopenharmony_ci#define DRV_VERSION "1.0" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define NIC_VF_PER_MBX_REG 64 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct hw_info { 2462306a36Sopenharmony_ci u8 bgx_cnt; 2562306a36Sopenharmony_ci u8 chans_per_lmac; 2662306a36Sopenharmony_ci u8 chans_per_bgx; /* Rx/Tx chans */ 2762306a36Sopenharmony_ci u8 chans_per_rgx; 2862306a36Sopenharmony_ci u8 chans_per_lbk; 2962306a36Sopenharmony_ci u16 cpi_cnt; 3062306a36Sopenharmony_ci u16 rssi_cnt; 3162306a36Sopenharmony_ci u16 rss_ind_tbl_size; 3262306a36Sopenharmony_ci u16 tl4_cnt; 3362306a36Sopenharmony_ci u16 tl3_cnt; 3462306a36Sopenharmony_ci u8 tl2_cnt; 3562306a36Sopenharmony_ci u8 tl1_cnt; 3662306a36Sopenharmony_ci bool tl1_per_bgx; /* TL1 per BGX or per LMAC */ 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct nicpf { 4062306a36Sopenharmony_ci struct pci_dev *pdev; 4162306a36Sopenharmony_ci struct hw_info *hw; 4262306a36Sopenharmony_ci u8 node; 4362306a36Sopenharmony_ci unsigned int flags; 4462306a36Sopenharmony_ci u8 num_vf_en; /* No of VF enabled */ 4562306a36Sopenharmony_ci bool vf_enabled[MAX_NUM_VFS_SUPPORTED]; 4662306a36Sopenharmony_ci void __iomem *reg_base; /* Register start address */ 4762306a36Sopenharmony_ci u8 num_sqs_en; /* Secondary qsets enabled */ 4862306a36Sopenharmony_ci u64 nicvf[MAX_NUM_VFS_SUPPORTED]; 4962306a36Sopenharmony_ci u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF]; 5062306a36Sopenharmony_ci u8 pqs_vf[MAX_NUM_VFS_SUPPORTED]; 5162306a36Sopenharmony_ci bool sqs_used[MAX_NUM_VFS_SUPPORTED]; 5262306a36Sopenharmony_ci struct pkind_cfg pkind; 5362306a36Sopenharmony_ci#define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF)) 5462306a36Sopenharmony_ci#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) 5562306a36Sopenharmony_ci#define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF) 5662306a36Sopenharmony_ci u8 *vf_lmac_map; 5762306a36Sopenharmony_ci u16 cpi_base[MAX_NUM_VFS_SUPPORTED]; 5862306a36Sopenharmony_ci u16 rssi_base[MAX_NUM_VFS_SUPPORTED]; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* MSI-X */ 6162306a36Sopenharmony_ci u8 num_vec; 6262306a36Sopenharmony_ci unsigned int irq_allocated[NIC_PF_MSIX_VECTORS]; 6362306a36Sopenharmony_ci char irq_name[NIC_PF_MSIX_VECTORS][20]; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* Supported devices */ 6762306a36Sopenharmony_cistatic const struct pci_device_id nic_id_table[] = { 6862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_NIC_PF) }, 6962306a36Sopenharmony_ci { 0, } /* end of table */ 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciMODULE_AUTHOR("Sunil Goutham"); 7362306a36Sopenharmony_ciMODULE_DESCRIPTION("Cavium Thunder NIC Physical Function Driver"); 7462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 7562306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 7662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nic_id_table); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* The Cavium ThunderX network controller can *only* be found in SoCs 7962306a36Sopenharmony_ci * containing the ThunderX ARM64 CPU implementation. All accesses to the device 8062306a36Sopenharmony_ci * registers on this platform are implicitly strongly ordered with respect 8162306a36Sopenharmony_ci * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use 8262306a36Sopenharmony_ci * with no memory barriers in this driver. The readq()/writeq() functions add 8362306a36Sopenharmony_ci * explicit ordering operation which in this case are redundant, and only 8462306a36Sopenharmony_ci * add overhead. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Register read/write APIs */ 8862306a36Sopenharmony_cistatic void nic_reg_write(struct nicpf *nic, u64 offset, u64 val) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci writeq_relaxed(val, nic->reg_base + offset); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic u64 nic_reg_read(struct nicpf *nic, u64 offset) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return readq_relaxed(nic->reg_base + offset); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* PF -> VF mailbox communication APIs */ 9962306a36Sopenharmony_cistatic void nic_enable_mbx_intr(struct nicpf *nic) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci int vf_cnt = pci_sriov_get_totalvfs(nic->pdev); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define INTR_MASK(vfs) ((vfs < 64) ? (BIT_ULL(vfs) - 1) : (~0ull)) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Clear it, to avoid spurious interrupts (if any) */ 10662306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_INT, INTR_MASK(vf_cnt)); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Enable mailbox interrupt for all VFs */ 10962306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, INTR_MASK(vf_cnt)); 11062306a36Sopenharmony_ci /* One mailbox intr enable reg per 64 VFs */ 11162306a36Sopenharmony_ci if (vf_cnt > 64) { 11262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_INT + sizeof(u64), 11362306a36Sopenharmony_ci INTR_MASK(vf_cnt - 64)); 11462306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), 11562306a36Sopenharmony_ci INTR_MASK(vf_cnt - 64)); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), BIT_ULL(vf)); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic u64 nic_get_mbx_addr(int vf) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* Send a mailbox message to VF 13062306a36Sopenharmony_ci * @vf: vf to which this message to be sent 13162306a36Sopenharmony_ci * @mbx: Message to be sent 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci void __iomem *mbx_addr = nic->reg_base + nic_get_mbx_addr(vf); 13662306a36Sopenharmony_ci u64 *msg = (u64 *)mbx; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* In first revision HW, mbox interrupt is triggerred 13962306a36Sopenharmony_ci * when PF writes to MBOX(1), in next revisions when 14062306a36Sopenharmony_ci * PF writes to MBOX(0) 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci if (pass1_silicon(nic->pdev)) { 14362306a36Sopenharmony_ci /* see the comment for nic_reg_write()/nic_reg_read() 14462306a36Sopenharmony_ci * functions above 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci writeq_relaxed(msg[0], mbx_addr); 14762306a36Sopenharmony_ci writeq_relaxed(msg[1], mbx_addr + 8); 14862306a36Sopenharmony_ci } else { 14962306a36Sopenharmony_ci writeq_relaxed(msg[1], mbx_addr + 8); 15062306a36Sopenharmony_ci writeq_relaxed(msg[0], mbx_addr); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* Responds to VF's READY message with VF's 15562306a36Sopenharmony_ci * ID, node, MAC address e.t.c 15662306a36Sopenharmony_ci * @vf: VF which sent READY message 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistatic void nic_mbx_send_ready(struct nicpf *nic, int vf) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci union nic_mbx mbx = {}; 16162306a36Sopenharmony_ci int bgx_idx, lmac; 16262306a36Sopenharmony_ci const char *mac; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci mbx.nic_cfg.msg = NIC_MBOX_MSG_READY; 16562306a36Sopenharmony_ci mbx.nic_cfg.vf_id = vf; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (vf < nic->num_vf_en) { 17062306a36Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 17162306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); 17462306a36Sopenharmony_ci if (mac) 17562306a36Sopenharmony_ci ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; 17862306a36Sopenharmony_ci mbx.nic_cfg.node_id = nic->node; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci mbx.nic_cfg.loopback_supported = vf < nic->num_vf_en; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* ACKs VF's mailbox message 18662306a36Sopenharmony_ci * @vf: VF to which ACK to be sent 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_cistatic void nic_mbx_send_ack(struct nicpf *nic, int vf) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci union nic_mbx mbx = {}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci mbx.msg.msg = NIC_MBOX_MSG_ACK; 19362306a36Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* NACKs VF's mailbox message that PF is not able to 19762306a36Sopenharmony_ci * complete the action 19862306a36Sopenharmony_ci * @vf: VF to which ACK to be sent 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_cistatic void nic_mbx_send_nack(struct nicpf *nic, int vf) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci union nic_mbx mbx = {}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci mbx.msg.msg = NIC_MBOX_MSG_NACK; 20562306a36Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* Flush all in flight receive packets to memory and 20962306a36Sopenharmony_ci * bring down an active RQ 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistatic int nic_rcv_queue_sw_sync(struct nicpf *nic) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci u16 timeout = ~0x00; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); 21662306a36Sopenharmony_ci /* Wait till sync cycle is finished */ 21762306a36Sopenharmony_ci while (timeout) { 21862306a36Sopenharmony_ci if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci timeout--; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); 22362306a36Sopenharmony_ci if (!timeout) { 22462306a36Sopenharmony_ci dev_err(&nic->pdev->dev, "Receive queue software sync failed"); 22562306a36Sopenharmony_ci return 1; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* Get BGX Rx/Tx stats and respond to VF's request */ 23162306a36Sopenharmony_cistatic void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci int bgx_idx, lmac; 23462306a36Sopenharmony_ci union nic_mbx mbx = {}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 23762306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS; 24062306a36Sopenharmony_ci mbx.bgx_stats.vf_id = bgx->vf_id; 24162306a36Sopenharmony_ci mbx.bgx_stats.rx = bgx->rx; 24262306a36Sopenharmony_ci mbx.bgx_stats.idx = bgx->idx; 24362306a36Sopenharmony_ci if (bgx->rx) 24462306a36Sopenharmony_ci mbx.bgx_stats.stats = bgx_get_rx_stats(nic->node, bgx_idx, 24562306a36Sopenharmony_ci lmac, bgx->idx); 24662306a36Sopenharmony_ci else 24762306a36Sopenharmony_ci mbx.bgx_stats.stats = bgx_get_tx_stats(nic->node, bgx_idx, 24862306a36Sopenharmony_ci lmac, bgx->idx); 24962306a36Sopenharmony_ci nic_send_msg_to_vf(nic, bgx->vf_id, &mbx); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* Update hardware min/max frame size */ 25362306a36Sopenharmony_cistatic int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci int bgx, lmac, lmac_cnt; 25662306a36Sopenharmony_ci u64 lmac_credits; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) 25962306a36Sopenharmony_ci return 1; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 26262306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 26362306a36Sopenharmony_ci lmac += bgx * MAX_LMAC_PER_BGX; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci new_frs += VLAN_ETH_HLEN + ETH_FCS_LEN + 4; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Update corresponding LMAC credits */ 26862306a36Sopenharmony_ci lmac_cnt = bgx_get_lmac_count(nic->node, bgx); 26962306a36Sopenharmony_ci lmac_credits = nic_reg_read(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8)); 27062306a36Sopenharmony_ci lmac_credits &= ~(0xFFFFFULL << 12); 27162306a36Sopenharmony_ci lmac_credits |= (((((48 * 1024) / lmac_cnt) - new_frs) / 16) << 12); 27262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credits); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Enforce MTU in HW 27562306a36Sopenharmony_ci * This config is supported only from 88xx pass 2.0 onwards. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci if (!pass1_silicon(nic->pdev)) 27862306a36Sopenharmony_ci nic_reg_write(nic, 27962306a36Sopenharmony_ci NIC_PF_LMAC_0_7_CFG2 + (lmac * 8), new_frs); 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* Set minimum transmit packet size */ 28462306a36Sopenharmony_cistatic void nic_set_tx_pkt_pad(struct nicpf *nic, int size) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int lmac, max_lmac; 28762306a36Sopenharmony_ci u16 sdevid; 28862306a36Sopenharmony_ci u64 lmac_cfg; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* There is a issue in HW where-in while sending GSO sized 29162306a36Sopenharmony_ci * pkts as part of TSO, if pkt len falls below this size 29262306a36Sopenharmony_ci * NIC will zero PAD packet and also updates IP total length. 29362306a36Sopenharmony_ci * Hence set this value to lessthan min pkt size of MAC+IP+TCP 29462306a36Sopenharmony_ci * headers, BGX will do the padding to transmit 64 byte pkt. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci if (size > 52) 29762306a36Sopenharmony_ci size = 52; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); 30062306a36Sopenharmony_ci /* 81xx's RGX has only one LMAC */ 30162306a36Sopenharmony_ci if (sdevid == PCI_SUBSYS_DEVID_81XX_NIC_PF) 30262306a36Sopenharmony_ci max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1; 30362306a36Sopenharmony_ci else 30462306a36Sopenharmony_ci max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci for (lmac = 0; lmac < max_lmac; lmac++) { 30762306a36Sopenharmony_ci lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); 30862306a36Sopenharmony_ci lmac_cfg &= ~(0xF << 2); 30962306a36Sopenharmony_ci lmac_cfg |= ((size / 4) << 2); 31062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* Function to check number of LMACs present and set VF::LMAC mapping. 31562306a36Sopenharmony_ci * Mapping will be used while initializing channels. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic void nic_set_lmac_vf_mapping(struct nicpf *nic) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unsigned bgx_map = bgx_get_map(nic->node); 32062306a36Sopenharmony_ci int bgx, next_bgx_lmac = 0; 32162306a36Sopenharmony_ci int lmac, lmac_cnt = 0; 32262306a36Sopenharmony_ci u64 lmac_credit; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci nic->num_vf_en = 0; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) { 32762306a36Sopenharmony_ci if (!(bgx_map & (1 << bgx))) 32862306a36Sopenharmony_ci continue; 32962306a36Sopenharmony_ci lmac_cnt = bgx_get_lmac_count(nic->node, bgx); 33062306a36Sopenharmony_ci for (lmac = 0; lmac < lmac_cnt; lmac++) 33162306a36Sopenharmony_ci nic->vf_lmac_map[next_bgx_lmac++] = 33262306a36Sopenharmony_ci NIC_SET_VF_LMAC_MAP(bgx, lmac); 33362306a36Sopenharmony_ci nic->num_vf_en += lmac_cnt; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Program LMAC credits */ 33662306a36Sopenharmony_ci lmac_credit = (1ull << 1); /* channel credit enable */ 33762306a36Sopenharmony_ci lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ 33862306a36Sopenharmony_ci /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ 33962306a36Sopenharmony_ci lmac_credit |= (((((48 * 1024) / lmac_cnt) - 34062306a36Sopenharmony_ci NIC_HW_MAX_FRS) / 16) << 12); 34162306a36Sopenharmony_ci lmac = bgx * MAX_LMAC_PER_BGX; 34262306a36Sopenharmony_ci for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) 34362306a36Sopenharmony_ci nic_reg_write(nic, 34462306a36Sopenharmony_ci NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), 34562306a36Sopenharmony_ci lmac_credit); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* On CN81XX there are only 8 VFs but max possible no of 34862306a36Sopenharmony_ci * interfaces are 9. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci if (nic->num_vf_en >= pci_sriov_get_totalvfs(nic->pdev)) { 35162306a36Sopenharmony_ci nic->num_vf_en = pci_sriov_get_totalvfs(nic->pdev); 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void nic_get_hw_info(struct nicpf *nic) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci u16 sdevid; 36062306a36Sopenharmony_ci struct hw_info *hw = nic->hw; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci switch (sdevid) { 36562306a36Sopenharmony_ci case PCI_SUBSYS_DEVID_88XX_NIC_PF: 36662306a36Sopenharmony_ci hw->bgx_cnt = MAX_BGX_PER_CN88XX; 36762306a36Sopenharmony_ci hw->chans_per_lmac = 16; 36862306a36Sopenharmony_ci hw->chans_per_bgx = 128; 36962306a36Sopenharmony_ci hw->cpi_cnt = 2048; 37062306a36Sopenharmony_ci hw->rssi_cnt = 4096; 37162306a36Sopenharmony_ci hw->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE; 37262306a36Sopenharmony_ci hw->tl3_cnt = 256; 37362306a36Sopenharmony_ci hw->tl2_cnt = 64; 37462306a36Sopenharmony_ci hw->tl1_cnt = 2; 37562306a36Sopenharmony_ci hw->tl1_per_bgx = true; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case PCI_SUBSYS_DEVID_81XX_NIC_PF: 37862306a36Sopenharmony_ci hw->bgx_cnt = MAX_BGX_PER_CN81XX; 37962306a36Sopenharmony_ci hw->chans_per_lmac = 8; 38062306a36Sopenharmony_ci hw->chans_per_bgx = 32; 38162306a36Sopenharmony_ci hw->chans_per_rgx = 8; 38262306a36Sopenharmony_ci hw->chans_per_lbk = 24; 38362306a36Sopenharmony_ci hw->cpi_cnt = 512; 38462306a36Sopenharmony_ci hw->rssi_cnt = 256; 38562306a36Sopenharmony_ci hw->rss_ind_tbl_size = 32; /* Max RSSI / Max interfaces */ 38662306a36Sopenharmony_ci hw->tl3_cnt = 64; 38762306a36Sopenharmony_ci hw->tl2_cnt = 16; 38862306a36Sopenharmony_ci hw->tl1_cnt = 10; 38962306a36Sopenharmony_ci hw->tl1_per_bgx = false; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case PCI_SUBSYS_DEVID_83XX_NIC_PF: 39262306a36Sopenharmony_ci hw->bgx_cnt = MAX_BGX_PER_CN83XX; 39362306a36Sopenharmony_ci hw->chans_per_lmac = 8; 39462306a36Sopenharmony_ci hw->chans_per_bgx = 32; 39562306a36Sopenharmony_ci hw->chans_per_lbk = 64; 39662306a36Sopenharmony_ci hw->cpi_cnt = 2048; 39762306a36Sopenharmony_ci hw->rssi_cnt = 1024; 39862306a36Sopenharmony_ci hw->rss_ind_tbl_size = 64; /* Max RSSI / Max interfaces */ 39962306a36Sopenharmony_ci hw->tl3_cnt = 256; 40062306a36Sopenharmony_ci hw->tl2_cnt = 64; 40162306a36Sopenharmony_ci hw->tl1_cnt = 18; 40262306a36Sopenharmony_ci hw->tl1_per_bgx = false; 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci hw->tl4_cnt = MAX_QUEUES_PER_QSET * pci_sriov_get_totalvfs(nic->pdev); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci#define BGX0_BLOCK 8 40962306a36Sopenharmony_ci#define BGX1_BLOCK 9 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic void nic_init_hw(struct nicpf *nic) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int i; 41462306a36Sopenharmony_ci u64 cqm_cfg; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* Enable NIC HW block */ 41762306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CFG, 0x3); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* Enable backpressure */ 42062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* TNS and TNS bypass modes are present only on 88xx 42362306a36Sopenharmony_ci * Also offset of this CSR has changed in 81xx and 83xx. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { 42662306a36Sopenharmony_ci /* Disable TNS mode on both interfaces */ 42762306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, 42862306a36Sopenharmony_ci (NIC_TNS_BYPASS_MODE << 7) | 42962306a36Sopenharmony_ci BGX0_BLOCK | (1ULL << 16)); 43062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), 43162306a36Sopenharmony_ci (NIC_TNS_BYPASS_MODE << 7) | 43262306a36Sopenharmony_ci BGX1_BLOCK | (1ULL << 16)); 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci /* Configure timestamp generation timeout to 10us */ 43562306a36Sopenharmony_ci for (i = 0; i < nic->hw->bgx_cnt; i++) 43662306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3), 43762306a36Sopenharmony_ci (1ULL << 16)); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, 44162306a36Sopenharmony_ci (1ULL << 63) | BGX0_BLOCK); 44262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), 44362306a36Sopenharmony_ci (1ULL << 63) | BGX1_BLOCK); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* PKIND configuration */ 44662306a36Sopenharmony_ci nic->pkind.minlen = 0; 44762306a36Sopenharmony_ci nic->pkind.maxlen = NIC_HW_MAX_FRS + VLAN_ETH_HLEN + ETH_FCS_LEN + 4; 44862306a36Sopenharmony_ci nic->pkind.lenerr_en = 1; 44962306a36Sopenharmony_ci nic->pkind.rx_hdr = 0; 45062306a36Sopenharmony_ci nic->pkind.hdr_sl = 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci for (i = 0; i < NIC_MAX_PKIND; i++) 45362306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), 45462306a36Sopenharmony_ci *(u64 *)&nic->pkind); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Timer config */ 45962306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Enable VLAN ethertype matching and stripping */ 46262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, 46362306a36Sopenharmony_ci (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* Check if HW expected value is higher (could be in future chips) */ 46662306a36Sopenharmony_ci cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); 46762306a36Sopenharmony_ci if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) 46862306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* Channel parse index configuration */ 47262306a36Sopenharmony_cistatic void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct hw_info *hw = nic->hw; 47562306a36Sopenharmony_ci u32 vnic, bgx, lmac, chan; 47662306a36Sopenharmony_ci u32 padd, cpi_count = 0; 47762306a36Sopenharmony_ci u64 cpi_base, cpi, rssi_base, rssi; 47862306a36Sopenharmony_ci u8 qset, rq_idx = 0; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci vnic = cfg->vf_id; 48162306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 48262306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx); 48562306a36Sopenharmony_ci cpi_base = vnic * NIC_MAX_CPI_PER_LMAC; 48662306a36Sopenharmony_ci rssi_base = vnic * hw->rss_ind_tbl_size; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Rx channel configuration */ 48962306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), 49062306a36Sopenharmony_ci (1ull << 63) | (vnic << 0)); 49162306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), 49262306a36Sopenharmony_ci ((u64)cfg->cpi_alg << 62) | (cpi_base << 48)); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (cfg->cpi_alg == CPI_ALG_NONE) 49562306a36Sopenharmony_ci cpi_count = 1; 49662306a36Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ 49762306a36Sopenharmony_ci cpi_count = 8; 49862306a36Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ 49962306a36Sopenharmony_ci cpi_count = 16; 50062306a36Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ 50162306a36Sopenharmony_ci cpi_count = NIC_MAX_CPI_PER_LMAC; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* RSS Qset, Qidx mapping */ 50462306a36Sopenharmony_ci qset = cfg->vf_id; 50562306a36Sopenharmony_ci rssi = rssi_base; 50662306a36Sopenharmony_ci for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { 50762306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), 50862306a36Sopenharmony_ci (qset << 3) | rq_idx); 50962306a36Sopenharmony_ci rq_idx++; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci rssi = 0; 51362306a36Sopenharmony_ci cpi = cpi_base; 51462306a36Sopenharmony_ci for (; cpi < (cpi_base + cpi_count); cpi++) { 51562306a36Sopenharmony_ci /* Determine port to channel adder */ 51662306a36Sopenharmony_ci if (cfg->cpi_alg != CPI_ALG_DIFF) 51762306a36Sopenharmony_ci padd = cpi % cpi_count; 51862306a36Sopenharmony_ci else 51962306a36Sopenharmony_ci padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* Leave RSS_SIZE as '0' to disable RSS */ 52262306a36Sopenharmony_ci if (pass1_silicon(nic->pdev)) { 52362306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 52462306a36Sopenharmony_ci (vnic << 24) | (padd << 16) | 52562306a36Sopenharmony_ci (rssi_base + rssi)); 52662306a36Sopenharmony_ci } else { 52762306a36Sopenharmony_ci /* Set MPI_ALG to '0' to disable MCAM parsing */ 52862306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 52962306a36Sopenharmony_ci (padd << 16)); 53062306a36Sopenharmony_ci /* MPI index is same as CPI if MPI_ALG is not enabled */ 53162306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3), 53262306a36Sopenharmony_ci (vnic << 24) | (rssi_base + rssi)); 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if ((rssi + 1) >= cfg->rq_cnt) 53662306a36Sopenharmony_ci continue; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (cfg->cpi_alg == CPI_ALG_VLAN) 53962306a36Sopenharmony_ci rssi++; 54062306a36Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_VLAN16) 54162306a36Sopenharmony_ci rssi = ((cpi - cpi_base) & 0xe) >> 1; 54262306a36Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_DIFF) 54362306a36Sopenharmony_ci rssi = ((cpi - cpi_base) & 0x38) >> 3; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci nic->cpi_base[cfg->vf_id] = cpi_base; 54662306a36Sopenharmony_ci nic->rssi_base[cfg->vf_id] = rssi_base; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci/* Responsds to VF with its RSS indirection table size */ 55062306a36Sopenharmony_cistatic void nic_send_rss_size(struct nicpf *nic, int vf) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci union nic_mbx mbx = {}; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE; 55562306a36Sopenharmony_ci mbx.rss_size.ind_tbl_size = nic->hw->rss_ind_tbl_size; 55662306a36Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/* Receive side scaling configuration 56062306a36Sopenharmony_ci * configure: 56162306a36Sopenharmony_ci * - RSS index 56262306a36Sopenharmony_ci * - indir table i.e hash::RQ mapping 56362306a36Sopenharmony_ci * - no of hash bits to consider 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci u8 qset, idx = 0; 56862306a36Sopenharmony_ci u64 cpi_cfg, cpi_base, rssi_base, rssi; 56962306a36Sopenharmony_ci u64 idx_addr; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci rssi_base = nic->rssi_base[cfg->vf_id] + cfg->tbl_offset; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci rssi = rssi_base; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci for (; rssi < (rssi_base + cfg->tbl_len); rssi++) { 57662306a36Sopenharmony_ci u8 svf = cfg->ind_tbl[idx] >> 3; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (svf) 57962306a36Sopenharmony_ci qset = nic->vf_sqs[cfg->vf_id][svf - 1]; 58062306a36Sopenharmony_ci else 58162306a36Sopenharmony_ci qset = cfg->vf_id; 58262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), 58362306a36Sopenharmony_ci (qset << 3) | (cfg->ind_tbl[idx] & 0x7)); 58462306a36Sopenharmony_ci idx++; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci cpi_base = nic->cpi_base[cfg->vf_id]; 58862306a36Sopenharmony_ci if (pass1_silicon(nic->pdev)) 58962306a36Sopenharmony_ci idx_addr = NIC_PF_CPI_0_2047_CFG; 59062306a36Sopenharmony_ci else 59162306a36Sopenharmony_ci idx_addr = NIC_PF_MPI_0_2047_CFG; 59262306a36Sopenharmony_ci cpi_cfg = nic_reg_read(nic, idx_addr | (cpi_base << 3)); 59362306a36Sopenharmony_ci cpi_cfg &= ~(0xFULL << 20); 59462306a36Sopenharmony_ci cpi_cfg |= (cfg->hash_bits << 20); 59562306a36Sopenharmony_ci nic_reg_write(nic, idx_addr | (cpi_base << 3), cpi_cfg); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* 4 level transmit side scheduler configutation 59962306a36Sopenharmony_ci * for TNS bypass mode 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * Sample configuration for SQ0 on 88xx 60262306a36Sopenharmony_ci * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0 60362306a36Sopenharmony_ci * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0 60462306a36Sopenharmony_ci * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0 60562306a36Sopenharmony_ci * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0 60662306a36Sopenharmony_ci * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1 60762306a36Sopenharmony_ci * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1 60862306a36Sopenharmony_ci * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 60962306a36Sopenharmony_ci * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_cistatic void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, 61262306a36Sopenharmony_ci struct sq_cfg_msg *sq) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct hw_info *hw = nic->hw; 61562306a36Sopenharmony_ci u32 bgx, lmac, chan; 61662306a36Sopenharmony_ci u32 tl2, tl3, tl4; 61762306a36Sopenharmony_ci u32 rr_quantum; 61862306a36Sopenharmony_ci u8 sq_idx = sq->sq_num; 61962306a36Sopenharmony_ci u8 pqs_vnic; 62062306a36Sopenharmony_ci int svf; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (sq->sqs_mode) 62362306a36Sopenharmony_ci pqs_vnic = nic->pqs_vf[vnic]; 62462306a36Sopenharmony_ci else 62562306a36Sopenharmony_ci pqs_vnic = vnic; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 62862306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* 24 bytes for FCS, IPG and preamble */ 63162306a36Sopenharmony_ci rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* For 88xx 0-511 TL4 transmits via BGX0 and 63462306a36Sopenharmony_ci * 512-1023 TL4s transmit via BGX1. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci if (hw->tl1_per_bgx) { 63762306a36Sopenharmony_ci tl4 = bgx * (hw->tl4_cnt / hw->bgx_cnt); 63862306a36Sopenharmony_ci if (!sq->sqs_mode) { 63962306a36Sopenharmony_ci tl4 += (lmac * MAX_QUEUES_PER_QSET); 64062306a36Sopenharmony_ci } else { 64162306a36Sopenharmony_ci for (svf = 0; svf < MAX_SQS_PER_VF; svf++) { 64262306a36Sopenharmony_ci if (nic->vf_sqs[pqs_vnic][svf] == vnic) 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci tl4 += (MAX_LMAC_PER_BGX * MAX_QUEUES_PER_QSET); 64662306a36Sopenharmony_ci tl4 += (lmac * MAX_QUEUES_PER_QSET * MAX_SQS_PER_VF); 64762306a36Sopenharmony_ci tl4 += (svf * MAX_QUEUES_PER_QSET); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci } else { 65062306a36Sopenharmony_ci tl4 = (vnic * MAX_QUEUES_PER_QSET); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci tl4 += sq_idx; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci tl3 = tl4 / (hw->tl4_cnt / hw->tl3_cnt); 65562306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | 65662306a36Sopenharmony_ci ((u64)vnic << NIC_QS_ID_SHIFT) | 65762306a36Sopenharmony_ci ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4); 65862306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3), 65962306a36Sopenharmony_ci ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* On 88xx 0-127 channels are for BGX0 and 66462306a36Sopenharmony_ci * 127-255 channels for BGX1. 66562306a36Sopenharmony_ci * 66662306a36Sopenharmony_ci * On 81xx/83xx TL3_CHAN reg should be configured with channel 66762306a36Sopenharmony_ci * within LMAC i.e 0-7 and not the actual channel number like on 88xx 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx); 67062306a36Sopenharmony_ci if (hw->tl1_per_bgx) 67162306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan); 67262306a36Sopenharmony_ci else 67362306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), 0); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Enable backpressure on the channel */ 67662306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci tl2 = tl3 >> 2; 67962306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2); 68062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum); 68162306a36Sopenharmony_ci /* No priorities as of now */ 68262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Unlike 88xx where TL2s 0-31 transmits to TL1 '0' and rest to TL1 '1' 68562306a36Sopenharmony_ci * on 81xx/83xx TL2 needs to be configured to transmit to one of the 68662306a36Sopenharmony_ci * possible LMACs. 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * This register doesn't exist on 88xx. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci if (!hw->tl1_per_bgx) 69162306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL2_LMAC | (tl2 << 3), 69262306a36Sopenharmony_ci lmac + (bgx * MAX_LMAC_PER_BGX)); 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/* Send primary nicvf pointer to secondary QS's VF */ 69662306a36Sopenharmony_cistatic void nic_send_pnicvf(struct nicpf *nic, int sqs) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci union nic_mbx mbx = {}; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci mbx.nicvf.msg = NIC_MBOX_MSG_PNICVF_PTR; 70162306a36Sopenharmony_ci mbx.nicvf.nicvf = nic->nicvf[nic->pqs_vf[sqs]]; 70262306a36Sopenharmony_ci nic_send_msg_to_vf(nic, sqs, &mbx); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* Send SQS's nicvf pointer to primary QS's VF */ 70662306a36Sopenharmony_cistatic void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci union nic_mbx mbx = {}; 70962306a36Sopenharmony_ci int sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id]; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR; 71262306a36Sopenharmony_ci mbx.nicvf.sqs_id = nicvf->sqs_id; 71362306a36Sopenharmony_ci mbx.nicvf.nicvf = nic->nicvf[sqs_id]; 71462306a36Sopenharmony_ci nic_send_msg_to_vf(nic, nicvf->vf_id, &mbx); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* Find next available Qset that can be assigned as a 71862306a36Sopenharmony_ci * secondary Qset to a VF. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_cistatic int nic_nxt_avail_sqs(struct nicpf *nic) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci int sqs; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci for (sqs = 0; sqs < nic->num_sqs_en; sqs++) { 72562306a36Sopenharmony_ci if (!nic->sqs_used[sqs]) 72662306a36Sopenharmony_ci nic->sqs_used[sqs] = true; 72762306a36Sopenharmony_ci else 72862306a36Sopenharmony_ci continue; 72962306a36Sopenharmony_ci return sqs + nic->num_vf_en; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci return -1; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci/* Allocate additional Qsets for requested VF */ 73562306a36Sopenharmony_cistatic void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci union nic_mbx mbx = {}; 73862306a36Sopenharmony_ci int idx, alloc_qs = 0; 73962306a36Sopenharmony_ci int sqs_id; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (!nic->num_sqs_en) 74262306a36Sopenharmony_ci goto send_mbox; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci for (idx = 0; idx < sqs->qs_count; idx++) { 74562306a36Sopenharmony_ci sqs_id = nic_nxt_avail_sqs(nic); 74662306a36Sopenharmony_ci if (sqs_id < 0) 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci nic->vf_sqs[sqs->vf_id][idx] = sqs_id; 74962306a36Sopenharmony_ci nic->pqs_vf[sqs_id] = sqs->vf_id; 75062306a36Sopenharmony_ci alloc_qs++; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cisend_mbox: 75462306a36Sopenharmony_ci mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS; 75562306a36Sopenharmony_ci mbx.sqs_alloc.vf_id = sqs->vf_id; 75662306a36Sopenharmony_ci mbx.sqs_alloc.qs_count = alloc_qs; 75762306a36Sopenharmony_ci nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci int bgx_idx, lmac_idx; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (lbk->vf_id >= nic->num_vf_en) 76562306a36Sopenharmony_ci return -1; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 76862306a36Sopenharmony_ci lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Enable moving average calculation. 77362306a36Sopenharmony_ci * Keep the LVL/AVG delay to HW enforced minimum so that, not too many 77462306a36Sopenharmony_ci * packets sneek in between average calculations. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_CQ_AVG_CFG, 77762306a36Sopenharmony_ci (BIT_ULL(20) | 0x2ull << 14 | 0x1)); 77862306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RRM_AVG_CFG, 77962306a36Sopenharmony_ci (BIT_ULL(20) | 0x3ull << 14 | 0x1)); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/* Reset statistics counters */ 78562306a36Sopenharmony_cistatic int nic_reset_stat_counters(struct nicpf *nic, 78662306a36Sopenharmony_ci int vf, struct reset_stat_cfg *cfg) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci int i, stat, qnum; 78962306a36Sopenharmony_ci u64 reg_addr; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci for (i = 0; i < RX_STATS_ENUM_LAST; i++) { 79262306a36Sopenharmony_ci if (cfg->rx_stat_mask & BIT(i)) { 79362306a36Sopenharmony_ci reg_addr = NIC_PF_VNIC_0_127_RX_STAT_0_13 | 79462306a36Sopenharmony_ci (vf << NIC_QS_ID_SHIFT) | 79562306a36Sopenharmony_ci (i << 3); 79662306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci for (i = 0; i < TX_STATS_ENUM_LAST; i++) { 80162306a36Sopenharmony_ci if (cfg->tx_stat_mask & BIT(i)) { 80262306a36Sopenharmony_ci reg_addr = NIC_PF_VNIC_0_127_TX_STAT_0_4 | 80362306a36Sopenharmony_ci (vf << NIC_QS_ID_SHIFT) | 80462306a36Sopenharmony_ci (i << 3); 80562306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci for (i = 0; i <= 15; i++) { 81062306a36Sopenharmony_ci qnum = i >> 1; 81162306a36Sopenharmony_ci stat = i & 1 ? 1 : 0; 81262306a36Sopenharmony_ci reg_addr = (vf << NIC_QS_ID_SHIFT) | 81362306a36Sopenharmony_ci (qnum << NIC_Q_NUM_SHIFT) | (stat << 3); 81462306a36Sopenharmony_ci if (cfg->rq_stat_mask & BIT(i)) { 81562306a36Sopenharmony_ci reg_addr |= NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1; 81662306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci if (cfg->sq_stat_mask & BIT(i)) { 81962306a36Sopenharmony_ci reg_addr |= NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1; 82062306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return 0; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic void nic_enable_tunnel_parsing(struct nicpf *nic, int vf) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci u64 prot_def = (IPV6_PROT << 32) | (IPV4_PROT << 16) | ET_PROT; 83062306a36Sopenharmony_ci u64 vxlan_prot_def = (IPV6_PROT_DEF << 32) | 83162306a36Sopenharmony_ci (IPV4_PROT_DEF) << 16 | ET_PROT_DEF; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Configure tunnel parsing parameters */ 83462306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_GENEVE_DEF, 83562306a36Sopenharmony_ci (1ULL << 63 | UDP_GENEVE_PORT_NUM)); 83662306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_GENEVE_PROT_DEF, 83762306a36Sopenharmony_ci ((7ULL << 61) | prot_def)); 83862306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_NVGRE_PROT_DEF, 83962306a36Sopenharmony_ci ((7ULL << 61) | prot_def)); 84062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_VXLAN_DEF_0_1, 84162306a36Sopenharmony_ci ((1ULL << 63) | UDP_VXLAN_PORT_NUM)); 84262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_VXLAN_PROT_DEF, 84362306a36Sopenharmony_ci ((0xfULL << 60) | vxlan_prot_def)); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic void nic_enable_vf(struct nicpf *nic, int vf, bool enable) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci int bgx, lmac; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci nic->vf_enabled[vf] = enable; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (vf >= nic->num_vf_en) 85362306a36Sopenharmony_ci return; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 85662306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci int bgx, lmac; 86462306a36Sopenharmony_ci struct pfc pfc; 86562306a36Sopenharmony_ci union nic_mbx mbx = {}; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (vf >= nic->num_vf_en) 86862306a36Sopenharmony_ci return; 86962306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 87062306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (cfg->get) { 87362306a36Sopenharmony_ci bgx_lmac_get_pfc(nic->node, bgx, lmac, &pfc); 87462306a36Sopenharmony_ci mbx.pfc.msg = NIC_MBOX_MSG_PFC; 87562306a36Sopenharmony_ci mbx.pfc.autoneg = pfc.autoneg; 87662306a36Sopenharmony_ci mbx.pfc.fc_rx = pfc.fc_rx; 87762306a36Sopenharmony_ci mbx.pfc.fc_tx = pfc.fc_tx; 87862306a36Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 87962306a36Sopenharmony_ci } else { 88062306a36Sopenharmony_ci bgx_lmac_set_pfc(nic->node, bgx, lmac, cfg); 88162306a36Sopenharmony_ci nic_mbx_send_ack(nic, vf); 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/* Enable or disable HW timestamping by BGX for pkts received on a LMAC */ 88662306a36Sopenharmony_cistatic void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct pkind_cfg *pkind; 88962306a36Sopenharmony_ci u8 lmac, bgx_idx; 89062306a36Sopenharmony_ci u64 pkind_val, pkind_idx; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (vf >= nic->num_vf_en) 89362306a36Sopenharmony_ci return; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 89662306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX; 89962306a36Sopenharmony_ci pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3)); 90062306a36Sopenharmony_ci pkind = (struct pkind_cfg *)&pkind_val; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (ptp->enable && !pkind->hdr_sl) { 90362306a36Sopenharmony_ci /* Skiplen to exclude 8byte timestamp while parsing pkt 90462306a36Sopenharmony_ci * If not configured, will result in L2 errors. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_ci pkind->hdr_sl = 4; 90762306a36Sopenharmony_ci /* Adjust max packet length allowed */ 90862306a36Sopenharmony_ci pkind->maxlen += (pkind->hdr_sl * 2); 90962306a36Sopenharmony_ci bgx_config_timestamping(nic->node, bgx_idx, lmac, true); 91062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3), 91162306a36Sopenharmony_ci (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588); 91262306a36Sopenharmony_ci } else if (!ptp->enable && pkind->hdr_sl) { 91362306a36Sopenharmony_ci pkind->maxlen -= (pkind->hdr_sl * 2); 91462306a36Sopenharmony_ci pkind->hdr_sl = 0; 91562306a36Sopenharmony_ci bgx_config_timestamping(nic->node, bgx_idx, lmac, false); 91662306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3), 91762306a36Sopenharmony_ci (ETYPE_ALG_SKIP << 16) | ETH_P_8021Q); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci/* Get BGX LMAC link status and update corresponding VF 92462306a36Sopenharmony_ci * if there is a change, valid only if internal L2 switch 92562306a36Sopenharmony_ci * is not present otherwise VF link is always treated as up 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_cistatic void nic_link_status_get(struct nicpf *nic, u8 vf) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci union nic_mbx mbx = {}; 93062306a36Sopenharmony_ci struct bgx_link_status link; 93162306a36Sopenharmony_ci u8 bgx, lmac; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* Get BGX, LMAC indices for the VF */ 93662306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 93762306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* Get interface link status */ 94062306a36Sopenharmony_ci bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* Send a mbox message to VF with current link status */ 94362306a36Sopenharmony_ci mbx.link_status.link_up = link.link_up; 94462306a36Sopenharmony_ci mbx.link_status.duplex = link.duplex; 94562306a36Sopenharmony_ci mbx.link_status.speed = link.speed; 94662306a36Sopenharmony_ci mbx.link_status.mac_type = link.mac_type; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci /* reply with link status */ 94962306a36Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 95362306a36Sopenharmony_cistatic void nic_handle_mbx_intr(struct nicpf *nic, int vf) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci union nic_mbx mbx = {}; 95662306a36Sopenharmony_ci u64 *mbx_data; 95762306a36Sopenharmony_ci u64 mbx_addr; 95862306a36Sopenharmony_ci u64 reg_addr; 95962306a36Sopenharmony_ci u64 cfg; 96062306a36Sopenharmony_ci int bgx, lmac; 96162306a36Sopenharmony_ci int i; 96262306a36Sopenharmony_ci int ret = 0; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci mbx_addr = nic_get_mbx_addr(vf); 96562306a36Sopenharmony_ci mbx_data = (u64 *)&mbx; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { 96862306a36Sopenharmony_ci *mbx_data = nic_reg_read(nic, mbx_addr); 96962306a36Sopenharmony_ci mbx_data++; 97062306a36Sopenharmony_ci mbx_addr += sizeof(u64); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci dev_dbg(&nic->pdev->dev, "%s: Mailbox msg 0x%02x from VF%d\n", 97462306a36Sopenharmony_ci __func__, mbx.msg.msg, vf); 97562306a36Sopenharmony_ci switch (mbx.msg.msg) { 97662306a36Sopenharmony_ci case NIC_MBOX_MSG_READY: 97762306a36Sopenharmony_ci nic_mbx_send_ready(nic, vf); 97862306a36Sopenharmony_ci return; 97962306a36Sopenharmony_ci case NIC_MBOX_MSG_QS_CFG: 98062306a36Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_CFG | 98162306a36Sopenharmony_ci (mbx.qs.num << NIC_QS_ID_SHIFT); 98262306a36Sopenharmony_ci cfg = mbx.qs.cfg; 98362306a36Sopenharmony_ci /* Check if its a secondary Qset */ 98462306a36Sopenharmony_ci if (vf >= nic->num_vf_en) { 98562306a36Sopenharmony_ci cfg = cfg & (~0x7FULL); 98662306a36Sopenharmony_ci /* Assign this Qset to primary Qset's VF */ 98762306a36Sopenharmony_ci cfg |= nic->pqs_vf[vf]; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, cfg); 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci case NIC_MBOX_MSG_RQ_CFG: 99262306a36Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | 99362306a36Sopenharmony_ci (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 99462306a36Sopenharmony_ci (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 99562306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.rq.cfg); 99662306a36Sopenharmony_ci /* Enable CQE_RX2_S extension in CQE_RX descriptor. 99762306a36Sopenharmony_ci * This gets appended by default on 81xx/83xx chips, 99862306a36Sopenharmony_ci * for consistency enabling the same on 88xx pass2 99962306a36Sopenharmony_ci * where this is introduced. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci if (pass2_silicon(nic->pdev)) 100262306a36Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_CFG, 0x01); 100362306a36Sopenharmony_ci if (!pass1_silicon(nic->pdev)) 100462306a36Sopenharmony_ci nic_enable_tunnel_parsing(nic, vf); 100562306a36Sopenharmony_ci break; 100662306a36Sopenharmony_ci case NIC_MBOX_MSG_RQ_BP_CFG: 100762306a36Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG | 100862306a36Sopenharmony_ci (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 100962306a36Sopenharmony_ci (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 101062306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.rq.cfg); 101162306a36Sopenharmony_ci break; 101262306a36Sopenharmony_ci case NIC_MBOX_MSG_RQ_SW_SYNC: 101362306a36Sopenharmony_ci ret = nic_rcv_queue_sw_sync(nic); 101462306a36Sopenharmony_ci break; 101562306a36Sopenharmony_ci case NIC_MBOX_MSG_RQ_DROP_CFG: 101662306a36Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG | 101762306a36Sopenharmony_ci (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 101862306a36Sopenharmony_ci (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 101962306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.rq.cfg); 102062306a36Sopenharmony_ci break; 102162306a36Sopenharmony_ci case NIC_MBOX_MSG_SQ_CFG: 102262306a36Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG | 102362306a36Sopenharmony_ci (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | 102462306a36Sopenharmony_ci (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); 102562306a36Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.sq.cfg); 102662306a36Sopenharmony_ci nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci case NIC_MBOX_MSG_SET_MAC: 102962306a36Sopenharmony_ci if (vf >= nic->num_vf_en) { 103062306a36Sopenharmony_ci ret = -1; /* NACK */ 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci lmac = mbx.mac.vf_id; 103462306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 103562306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 103662306a36Sopenharmony_ci bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr); 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci case NIC_MBOX_MSG_SET_MAX_FRS: 103962306a36Sopenharmony_ci ret = nic_update_hw_frs(nic, mbx.frs.max_frs, 104062306a36Sopenharmony_ci mbx.frs.vf_id); 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case NIC_MBOX_MSG_CPI_CFG: 104362306a36Sopenharmony_ci nic_config_cpi(nic, &mbx.cpi_cfg); 104462306a36Sopenharmony_ci break; 104562306a36Sopenharmony_ci case NIC_MBOX_MSG_RSS_SIZE: 104662306a36Sopenharmony_ci nic_send_rss_size(nic, vf); 104762306a36Sopenharmony_ci return; 104862306a36Sopenharmony_ci case NIC_MBOX_MSG_RSS_CFG: 104962306a36Sopenharmony_ci case NIC_MBOX_MSG_RSS_CFG_CONT: 105062306a36Sopenharmony_ci nic_config_rss(nic, &mbx.rss_cfg); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case NIC_MBOX_MSG_CFG_DONE: 105362306a36Sopenharmony_ci /* Last message of VF config msg sequence */ 105462306a36Sopenharmony_ci nic_enable_vf(nic, vf, true); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci case NIC_MBOX_MSG_SHUTDOWN: 105762306a36Sopenharmony_ci /* First msg in VF teardown sequence */ 105862306a36Sopenharmony_ci if (vf >= nic->num_vf_en) 105962306a36Sopenharmony_ci nic->sqs_used[vf - nic->num_vf_en] = false; 106062306a36Sopenharmony_ci nic->pqs_vf[vf] = 0; 106162306a36Sopenharmony_ci nic_enable_vf(nic, vf, false); 106262306a36Sopenharmony_ci break; 106362306a36Sopenharmony_ci case NIC_MBOX_MSG_ALLOC_SQS: 106462306a36Sopenharmony_ci nic_alloc_sqs(nic, &mbx.sqs_alloc); 106562306a36Sopenharmony_ci return; 106662306a36Sopenharmony_ci case NIC_MBOX_MSG_NICVF_PTR: 106762306a36Sopenharmony_ci nic->nicvf[vf] = mbx.nicvf.nicvf; 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci case NIC_MBOX_MSG_PNICVF_PTR: 107062306a36Sopenharmony_ci nic_send_pnicvf(nic, vf); 107162306a36Sopenharmony_ci return; 107262306a36Sopenharmony_ci case NIC_MBOX_MSG_SNICVF_PTR: 107362306a36Sopenharmony_ci nic_send_snicvf(nic, &mbx.nicvf); 107462306a36Sopenharmony_ci return; 107562306a36Sopenharmony_ci case NIC_MBOX_MSG_BGX_STATS: 107662306a36Sopenharmony_ci nic_get_bgx_stats(nic, &mbx.bgx_stats); 107762306a36Sopenharmony_ci return; 107862306a36Sopenharmony_ci case NIC_MBOX_MSG_LOOPBACK: 107962306a36Sopenharmony_ci ret = nic_config_loopback(nic, &mbx.lbk); 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci case NIC_MBOX_MSG_RESET_STAT_COUNTER: 108262306a36Sopenharmony_ci ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat); 108362306a36Sopenharmony_ci break; 108462306a36Sopenharmony_ci case NIC_MBOX_MSG_PFC: 108562306a36Sopenharmony_ci nic_pause_frame(nic, vf, &mbx.pfc); 108662306a36Sopenharmony_ci return; 108762306a36Sopenharmony_ci case NIC_MBOX_MSG_PTP_CFG: 108862306a36Sopenharmony_ci nic_config_timestamp(nic, vf, &mbx.ptp); 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci case NIC_MBOX_MSG_RESET_XCAST: 109162306a36Sopenharmony_ci if (vf >= nic->num_vf_en) { 109262306a36Sopenharmony_ci ret = -1; /* NACK */ 109362306a36Sopenharmony_ci break; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 109662306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 109762306a36Sopenharmony_ci bgx_reset_xcast_mode(nic->node, bgx, lmac, 109862306a36Sopenharmony_ci vf < NIC_VF_PER_MBX_REG ? vf : 109962306a36Sopenharmony_ci vf - NIC_VF_PER_MBX_REG); 110062306a36Sopenharmony_ci break; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci case NIC_MBOX_MSG_ADD_MCAST: 110362306a36Sopenharmony_ci if (vf >= nic->num_vf_en) { 110462306a36Sopenharmony_ci ret = -1; /* NACK */ 110562306a36Sopenharmony_ci break; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 110862306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 110962306a36Sopenharmony_ci bgx_set_dmac_cam_filter(nic->node, bgx, lmac, 111062306a36Sopenharmony_ci mbx.xcast.mac, 111162306a36Sopenharmony_ci vf < NIC_VF_PER_MBX_REG ? vf : 111262306a36Sopenharmony_ci vf - NIC_VF_PER_MBX_REG); 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci case NIC_MBOX_MSG_SET_XCAST: 111662306a36Sopenharmony_ci if (vf >= nic->num_vf_en) { 111762306a36Sopenharmony_ci ret = -1; /* NACK */ 111862306a36Sopenharmony_ci break; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 112162306a36Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 112262306a36Sopenharmony_ci bgx_set_xcast_mode(nic->node, bgx, lmac, mbx.xcast.mode); 112362306a36Sopenharmony_ci break; 112462306a36Sopenharmony_ci case NIC_MBOX_MSG_BGX_LINK_CHANGE: 112562306a36Sopenharmony_ci if (vf >= nic->num_vf_en) { 112662306a36Sopenharmony_ci ret = -1; /* NACK */ 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci nic_link_status_get(nic, vf); 113062306a36Sopenharmony_ci return; 113162306a36Sopenharmony_ci default: 113262306a36Sopenharmony_ci dev_err(&nic->pdev->dev, 113362306a36Sopenharmony_ci "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (!ret) { 113862306a36Sopenharmony_ci nic_mbx_send_ack(nic, vf); 113962306a36Sopenharmony_ci } else if (mbx.msg.msg != NIC_MBOX_MSG_READY) { 114062306a36Sopenharmony_ci dev_err(&nic->pdev->dev, "NACK for MBOX 0x%02x from VF %d\n", 114162306a36Sopenharmony_ci mbx.msg.msg, vf); 114262306a36Sopenharmony_ci nic_mbx_send_nack(nic, vf); 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct nicpf *nic = (struct nicpf *)nic_irq; 114962306a36Sopenharmony_ci int mbx; 115062306a36Sopenharmony_ci u64 intr; 115162306a36Sopenharmony_ci u8 vf; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (irq == nic->irq_allocated[NIC_PF_INTR_ID_MBOX0]) 115462306a36Sopenharmony_ci mbx = 0; 115562306a36Sopenharmony_ci else 115662306a36Sopenharmony_ci mbx = 1; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3)); 115962306a36Sopenharmony_ci dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr); 116062306a36Sopenharmony_ci for (vf = 0; vf < NIC_VF_PER_MBX_REG; vf++) { 116162306a36Sopenharmony_ci if (intr & (1ULL << vf)) { 116262306a36Sopenharmony_ci dev_dbg(&nic->pdev->dev, "Intr from VF %d\n", 116362306a36Sopenharmony_ci vf + (mbx * NIC_VF_PER_MBX_REG)); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci nic_handle_mbx_intr(nic, vf + 116662306a36Sopenharmony_ci (mbx * NIC_VF_PER_MBX_REG)); 116762306a36Sopenharmony_ci nic_clear_mbx_intr(nic, vf, mbx); 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci return IRQ_HANDLED; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cistatic void nic_free_all_interrupts(struct nicpf *nic) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci int irq; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci for (irq = 0; irq < nic->num_vec; irq++) { 117862306a36Sopenharmony_ci if (nic->irq_allocated[irq]) 117962306a36Sopenharmony_ci free_irq(nic->irq_allocated[irq], nic); 118062306a36Sopenharmony_ci nic->irq_allocated[irq] = 0; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic int nic_register_interrupts(struct nicpf *nic) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci int i, ret, irq; 118762306a36Sopenharmony_ci nic->num_vec = pci_msix_vec_count(nic->pdev); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci /* Enable MSI-X */ 119062306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(nic->pdev, nic->num_vec, nic->num_vec, 119162306a36Sopenharmony_ci PCI_IRQ_MSIX); 119262306a36Sopenharmony_ci if (ret < 0) { 119362306a36Sopenharmony_ci dev_err(&nic->pdev->dev, 119462306a36Sopenharmony_ci "Request for #%d msix vectors failed, returned %d\n", 119562306a36Sopenharmony_ci nic->num_vec, ret); 119662306a36Sopenharmony_ci return ret; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* Register mailbox interrupt handler */ 120062306a36Sopenharmony_ci for (i = NIC_PF_INTR_ID_MBOX0; i < nic->num_vec; i++) { 120162306a36Sopenharmony_ci sprintf(nic->irq_name[i], 120262306a36Sopenharmony_ci "NICPF Mbox%d", (i - NIC_PF_INTR_ID_MBOX0)); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci irq = pci_irq_vector(nic->pdev, i); 120562306a36Sopenharmony_ci ret = request_irq(irq, nic_mbx_intr_handler, 0, 120662306a36Sopenharmony_ci nic->irq_name[i], nic); 120762306a36Sopenharmony_ci if (ret) 120862306a36Sopenharmony_ci goto fail; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci nic->irq_allocated[i] = irq; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* Enable mailbox interrupt */ 121462306a36Sopenharmony_ci nic_enable_mbx_intr(nic); 121562306a36Sopenharmony_ci return 0; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cifail: 121862306a36Sopenharmony_ci dev_err(&nic->pdev->dev, "Request irq failed\n"); 121962306a36Sopenharmony_ci nic_free_all_interrupts(nic); 122062306a36Sopenharmony_ci pci_free_irq_vectors(nic->pdev); 122162306a36Sopenharmony_ci nic->num_vec = 0; 122262306a36Sopenharmony_ci return ret; 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic void nic_unregister_interrupts(struct nicpf *nic) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci nic_free_all_interrupts(nic); 122862306a36Sopenharmony_ci pci_free_irq_vectors(nic->pdev); 122962306a36Sopenharmony_ci nic->num_vec = 0; 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic int nic_num_sqs_en(struct nicpf *nic, int vf_en) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci int pos, sqs_per_vf = MAX_SQS_PER_VF_SINGLE_NODE; 123562306a36Sopenharmony_ci u16 total_vf; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* Secondary Qsets are needed only if CPU count is 123862306a36Sopenharmony_ci * morethan MAX_QUEUES_PER_QSET. 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_ci if (num_online_cpus() <= MAX_QUEUES_PER_QSET) 124162306a36Sopenharmony_ci return 0; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* Check if its a multi-node environment */ 124462306a36Sopenharmony_ci if (nr_node_ids > 1) 124562306a36Sopenharmony_ci sqs_per_vf = MAX_SQS_PER_VF; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci pos = pci_find_ext_capability(nic->pdev, PCI_EXT_CAP_ID_SRIOV); 124862306a36Sopenharmony_ci pci_read_config_word(nic->pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf); 124962306a36Sopenharmony_ci return min(total_vf - vf_en, vf_en * sqs_per_vf); 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci int pos = 0; 125562306a36Sopenharmony_ci int vf_en; 125662306a36Sopenharmony_ci int err; 125762306a36Sopenharmony_ci u16 total_vf_cnt; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); 126062306a36Sopenharmony_ci if (!pos) { 126162306a36Sopenharmony_ci dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n"); 126262306a36Sopenharmony_ci return -ENODEV; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt); 126662306a36Sopenharmony_ci if (total_vf_cnt < nic->num_vf_en) 126762306a36Sopenharmony_ci nic->num_vf_en = total_vf_cnt; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (!total_vf_cnt) 127062306a36Sopenharmony_ci return 0; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci vf_en = nic->num_vf_en; 127362306a36Sopenharmony_ci nic->num_sqs_en = nic_num_sqs_en(nic, nic->num_vf_en); 127462306a36Sopenharmony_ci vf_en += nic->num_sqs_en; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci err = pci_enable_sriov(pdev, vf_en); 127762306a36Sopenharmony_ci if (err) { 127862306a36Sopenharmony_ci dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n", 127962306a36Sopenharmony_ci vf_en); 128062306a36Sopenharmony_ci nic->num_vf_en = 0; 128162306a36Sopenharmony_ci return err; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n", 128562306a36Sopenharmony_ci vf_en); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci nic->flags |= NIC_SRIOV_ENABLED; 128862306a36Sopenharmony_ci return 0; 128962306a36Sopenharmony_ci} 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_cistatic int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 129462306a36Sopenharmony_ci struct nicpf *nic; 129562306a36Sopenharmony_ci u8 max_lmac; 129662306a36Sopenharmony_ci int err; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(union nic_mbx) > 16); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci nic = devm_kzalloc(dev, sizeof(*nic), GFP_KERNEL); 130162306a36Sopenharmony_ci if (!nic) 130262306a36Sopenharmony_ci return -ENOMEM; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci nic->hw = devm_kzalloc(dev, sizeof(struct hw_info), GFP_KERNEL); 130562306a36Sopenharmony_ci if (!nic->hw) 130662306a36Sopenharmony_ci return -ENOMEM; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci pci_set_drvdata(pdev, nic); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci nic->pdev = pdev; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci err = pci_enable_device(pdev); 131362306a36Sopenharmony_ci if (err) { 131462306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 131562306a36Sopenharmony_ci return dev_err_probe(dev, err, "Failed to enable PCI device\n"); 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 131962306a36Sopenharmony_ci if (err) { 132062306a36Sopenharmony_ci dev_err(dev, "PCI request regions failed 0x%x\n", err); 132162306a36Sopenharmony_ci goto err_disable_device; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); 132562306a36Sopenharmony_ci if (err) { 132662306a36Sopenharmony_ci dev_err(dev, "Unable to get usable DMA configuration\n"); 132762306a36Sopenharmony_ci goto err_release_regions; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* MAP PF's configuration registers */ 133162306a36Sopenharmony_ci nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); 133262306a36Sopenharmony_ci if (!nic->reg_base) { 133362306a36Sopenharmony_ci dev_err(dev, "Cannot map config register space, aborting\n"); 133462306a36Sopenharmony_ci err = -ENOMEM; 133562306a36Sopenharmony_ci goto err_release_regions; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci nic->node = nic_get_node_id(pdev); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* Get HW capability info */ 134162306a36Sopenharmony_ci nic_get_hw_info(nic); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci /* Allocate memory for LMAC tracking elements */ 134462306a36Sopenharmony_ci err = -ENOMEM; 134562306a36Sopenharmony_ci max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci nic->vf_lmac_map = devm_kmalloc_array(dev, max_lmac, sizeof(u8), 134862306a36Sopenharmony_ci GFP_KERNEL); 134962306a36Sopenharmony_ci if (!nic->vf_lmac_map) 135062306a36Sopenharmony_ci goto err_release_regions; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* Initialize hardware */ 135362306a36Sopenharmony_ci nic_init_hw(nic); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci nic_set_lmac_vf_mapping(nic); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* Register interrupts */ 135862306a36Sopenharmony_ci err = nic_register_interrupts(nic); 135962306a36Sopenharmony_ci if (err) 136062306a36Sopenharmony_ci goto err_release_regions; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* Configure SRIOV */ 136362306a36Sopenharmony_ci err = nic_sriov_init(pdev, nic); 136462306a36Sopenharmony_ci if (err) 136562306a36Sopenharmony_ci goto err_unregister_interrupts; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci return 0; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_cierr_unregister_interrupts: 137062306a36Sopenharmony_ci nic_unregister_interrupts(nic); 137162306a36Sopenharmony_cierr_release_regions: 137262306a36Sopenharmony_ci pci_release_regions(pdev); 137362306a36Sopenharmony_cierr_disable_device: 137462306a36Sopenharmony_ci pci_disable_device(pdev); 137562306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 137662306a36Sopenharmony_ci return err; 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic void nic_remove(struct pci_dev *pdev) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci struct nicpf *nic = pci_get_drvdata(pdev); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (!nic) 138462306a36Sopenharmony_ci return; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (nic->flags & NIC_SRIOV_ENABLED) 138762306a36Sopenharmony_ci pci_disable_sriov(pdev); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci nic_unregister_interrupts(nic); 139062306a36Sopenharmony_ci pci_release_regions(pdev); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci pci_disable_device(pdev); 139362306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic struct pci_driver nic_driver = { 139762306a36Sopenharmony_ci .name = DRV_NAME, 139862306a36Sopenharmony_ci .id_table = nic_id_table, 139962306a36Sopenharmony_ci .probe = nic_probe, 140062306a36Sopenharmony_ci .remove = nic_remove, 140162306a36Sopenharmony_ci}; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic int __init nic_init_module(void) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci return pci_register_driver(&nic_driver); 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_cistatic void __exit nic_cleanup_module(void) 141162306a36Sopenharmony_ci{ 141262306a36Sopenharmony_ci pci_unregister_driver(&nic_driver); 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cimodule_init(nic_init_module); 141662306a36Sopenharmony_cimodule_exit(nic_cleanup_module); 1417