18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Cavium, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "nic_reg.h" 148c2ecf20Sopenharmony_ci#include "nic.h" 158c2ecf20Sopenharmony_ci#include "q_struct.h" 168c2ecf20Sopenharmony_ci#include "thunder_bgx.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DRV_NAME "nicpf" 198c2ecf20Sopenharmony_ci#define DRV_VERSION "1.0" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define NIC_VF_PER_MBX_REG 64 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct hw_info { 248c2ecf20Sopenharmony_ci u8 bgx_cnt; 258c2ecf20Sopenharmony_ci u8 chans_per_lmac; 268c2ecf20Sopenharmony_ci u8 chans_per_bgx; /* Rx/Tx chans */ 278c2ecf20Sopenharmony_ci u8 chans_per_rgx; 288c2ecf20Sopenharmony_ci u8 chans_per_lbk; 298c2ecf20Sopenharmony_ci u16 cpi_cnt; 308c2ecf20Sopenharmony_ci u16 rssi_cnt; 318c2ecf20Sopenharmony_ci u16 rss_ind_tbl_size; 328c2ecf20Sopenharmony_ci u16 tl4_cnt; 338c2ecf20Sopenharmony_ci u16 tl3_cnt; 348c2ecf20Sopenharmony_ci u8 tl2_cnt; 358c2ecf20Sopenharmony_ci u8 tl1_cnt; 368c2ecf20Sopenharmony_ci bool tl1_per_bgx; /* TL1 per BGX or per LMAC */ 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct nicpf { 408c2ecf20Sopenharmony_ci struct pci_dev *pdev; 418c2ecf20Sopenharmony_ci struct hw_info *hw; 428c2ecf20Sopenharmony_ci u8 node; 438c2ecf20Sopenharmony_ci unsigned int flags; 448c2ecf20Sopenharmony_ci u8 num_vf_en; /* No of VF enabled */ 458c2ecf20Sopenharmony_ci bool vf_enabled[MAX_NUM_VFS_SUPPORTED]; 468c2ecf20Sopenharmony_ci void __iomem *reg_base; /* Register start address */ 478c2ecf20Sopenharmony_ci u8 num_sqs_en; /* Secondary qsets enabled */ 488c2ecf20Sopenharmony_ci u64 nicvf[MAX_NUM_VFS_SUPPORTED]; 498c2ecf20Sopenharmony_ci u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF]; 508c2ecf20Sopenharmony_ci u8 pqs_vf[MAX_NUM_VFS_SUPPORTED]; 518c2ecf20Sopenharmony_ci bool sqs_used[MAX_NUM_VFS_SUPPORTED]; 528c2ecf20Sopenharmony_ci struct pkind_cfg pkind; 538c2ecf20Sopenharmony_ci#define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF)) 548c2ecf20Sopenharmony_ci#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) 558c2ecf20Sopenharmony_ci#define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF) 568c2ecf20Sopenharmony_ci u8 *vf_lmac_map; 578c2ecf20Sopenharmony_ci u16 cpi_base[MAX_NUM_VFS_SUPPORTED]; 588c2ecf20Sopenharmony_ci u16 rssi_base[MAX_NUM_VFS_SUPPORTED]; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* MSI-X */ 618c2ecf20Sopenharmony_ci u8 num_vec; 628c2ecf20Sopenharmony_ci bool irq_allocated[NIC_PF_MSIX_VECTORS]; 638c2ecf20Sopenharmony_ci char irq_name[NIC_PF_MSIX_VECTORS][20]; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Supported devices */ 678c2ecf20Sopenharmony_cistatic const struct pci_device_id nic_id_table[] = { 688c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_NIC_PF) }, 698c2ecf20Sopenharmony_ci { 0, } /* end of table */ 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sunil Goutham"); 738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cavium Thunder NIC Physical Function Driver"); 748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 758c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, nic_id_table); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* The Cavium ThunderX network controller can *only* be found in SoCs 798c2ecf20Sopenharmony_ci * containing the ThunderX ARM64 CPU implementation. All accesses to the device 808c2ecf20Sopenharmony_ci * registers on this platform are implicitly strongly ordered with respect 818c2ecf20Sopenharmony_ci * to memory accesses. So writeq_relaxed() and readq_relaxed() are safe to use 828c2ecf20Sopenharmony_ci * with no memory barriers in this driver. The readq()/writeq() functions add 838c2ecf20Sopenharmony_ci * explicit ordering operation which in this case are redundant, and only 848c2ecf20Sopenharmony_ci * add overhead. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Register read/write APIs */ 888c2ecf20Sopenharmony_cistatic void nic_reg_write(struct nicpf *nic, u64 offset, u64 val) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci writeq_relaxed(val, nic->reg_base + offset); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic u64 nic_reg_read(struct nicpf *nic, u64 offset) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return readq_relaxed(nic->reg_base + offset); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* PF -> VF mailbox communication APIs */ 998c2ecf20Sopenharmony_cistatic void nic_enable_mbx_intr(struct nicpf *nic) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci int vf_cnt = pci_sriov_get_totalvfs(nic->pdev); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define INTR_MASK(vfs) ((vfs < 64) ? (BIT_ULL(vfs) - 1) : (~0ull)) 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Clear it, to avoid spurious interrupts (if any) */ 1068c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_INT, INTR_MASK(vf_cnt)); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Enable mailbox interrupt for all VFs */ 1098c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, INTR_MASK(vf_cnt)); 1108c2ecf20Sopenharmony_ci /* One mailbox intr enable reg per 64 VFs */ 1118c2ecf20Sopenharmony_ci if (vf_cnt > 64) { 1128c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_INT + sizeof(u64), 1138c2ecf20Sopenharmony_ci INTR_MASK(vf_cnt - 64)); 1148c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), 1158c2ecf20Sopenharmony_ci INTR_MASK(vf_cnt - 64)); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), BIT_ULL(vf)); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic u64 nic_get_mbx_addr(int vf) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci return NIC_PF_VF_0_127_MAILBOX_0_1 + (vf << NIC_VF_NUM_SHIFT); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Send a mailbox message to VF 1308c2ecf20Sopenharmony_ci * @vf: vf to which this message to be sent 1318c2ecf20Sopenharmony_ci * @mbx: Message to be sent 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic void nic_send_msg_to_vf(struct nicpf *nic, int vf, union nic_mbx *mbx) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci void __iomem *mbx_addr = nic->reg_base + nic_get_mbx_addr(vf); 1368c2ecf20Sopenharmony_ci u64 *msg = (u64 *)mbx; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* In first revision HW, mbox interrupt is triggerred 1398c2ecf20Sopenharmony_ci * when PF writes to MBOX(1), in next revisions when 1408c2ecf20Sopenharmony_ci * PF writes to MBOX(0) 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci if (pass1_silicon(nic->pdev)) { 1438c2ecf20Sopenharmony_ci /* see the comment for nic_reg_write()/nic_reg_read() 1448c2ecf20Sopenharmony_ci * functions above 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci writeq_relaxed(msg[0], mbx_addr); 1478c2ecf20Sopenharmony_ci writeq_relaxed(msg[1], mbx_addr + 8); 1488c2ecf20Sopenharmony_ci } else { 1498c2ecf20Sopenharmony_ci writeq_relaxed(msg[1], mbx_addr + 8); 1508c2ecf20Sopenharmony_ci writeq_relaxed(msg[0], mbx_addr); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* Responds to VF's READY message with VF's 1558c2ecf20Sopenharmony_ci * ID, node, MAC address e.t.c 1568c2ecf20Sopenharmony_ci * @vf: VF which sent READY message 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic void nic_mbx_send_ready(struct nicpf *nic, int vf) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 1618c2ecf20Sopenharmony_ci int bgx_idx, lmac; 1628c2ecf20Sopenharmony_ci const char *mac; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci mbx.nic_cfg.msg = NIC_MBOX_MSG_READY; 1658c2ecf20Sopenharmony_ci mbx.nic_cfg.vf_id = vf; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (vf < nic->num_vf_en) { 1708c2ecf20Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 1718c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); 1748c2ecf20Sopenharmony_ci if (mac) 1758c2ecf20Sopenharmony_ci ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; 1788c2ecf20Sopenharmony_ci mbx.nic_cfg.node_id = nic->node; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci mbx.nic_cfg.loopback_supported = vf < nic->num_vf_en; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* ACKs VF's mailbox message 1868c2ecf20Sopenharmony_ci * @vf: VF to which ACK to be sent 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_cistatic void nic_mbx_send_ack(struct nicpf *nic, int vf) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci mbx.msg.msg = NIC_MBOX_MSG_ACK; 1938c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* NACKs VF's mailbox message that PF is not able to 1978c2ecf20Sopenharmony_ci * complete the action 1988c2ecf20Sopenharmony_ci * @vf: VF to which ACK to be sent 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic void nic_mbx_send_nack(struct nicpf *nic, int vf) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci mbx.msg.msg = NIC_MBOX_MSG_NACK; 2058c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* Flush all in flight receive packets to memory and 2098c2ecf20Sopenharmony_ci * bring down an active RQ 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic int nic_rcv_queue_sw_sync(struct nicpf *nic) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci u16 timeout = ~0x00; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); 2168c2ecf20Sopenharmony_ci /* Wait till sync cycle is finished */ 2178c2ecf20Sopenharmony_ci while (timeout) { 2188c2ecf20Sopenharmony_ci if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci timeout--; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); 2238c2ecf20Sopenharmony_ci if (!timeout) { 2248c2ecf20Sopenharmony_ci dev_err(&nic->pdev->dev, "Receive queue software sync failed"); 2258c2ecf20Sopenharmony_ci return 1; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* Get BGX Rx/Tx stats and respond to VF's request */ 2318c2ecf20Sopenharmony_cistatic void nic_get_bgx_stats(struct nicpf *nic, struct bgx_stats_msg *bgx) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int bgx_idx, lmac; 2348c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 2378c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[bgx->vf_id]); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci mbx.bgx_stats.msg = NIC_MBOX_MSG_BGX_STATS; 2408c2ecf20Sopenharmony_ci mbx.bgx_stats.vf_id = bgx->vf_id; 2418c2ecf20Sopenharmony_ci mbx.bgx_stats.rx = bgx->rx; 2428c2ecf20Sopenharmony_ci mbx.bgx_stats.idx = bgx->idx; 2438c2ecf20Sopenharmony_ci if (bgx->rx) 2448c2ecf20Sopenharmony_ci mbx.bgx_stats.stats = bgx_get_rx_stats(nic->node, bgx_idx, 2458c2ecf20Sopenharmony_ci lmac, bgx->idx); 2468c2ecf20Sopenharmony_ci else 2478c2ecf20Sopenharmony_ci mbx.bgx_stats.stats = bgx_get_tx_stats(nic->node, bgx_idx, 2488c2ecf20Sopenharmony_ci lmac, bgx->idx); 2498c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, bgx->vf_id, &mbx); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* Update hardware min/max frame size */ 2538c2ecf20Sopenharmony_cistatic int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int bgx, lmac, lmac_cnt; 2568c2ecf20Sopenharmony_ci u64 lmac_credits; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) 2598c2ecf20Sopenharmony_ci return 1; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 2628c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 2638c2ecf20Sopenharmony_ci lmac += bgx * MAX_LMAC_PER_BGX; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci new_frs += VLAN_ETH_HLEN + ETH_FCS_LEN + 4; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Update corresponding LMAC credits */ 2688c2ecf20Sopenharmony_ci lmac_cnt = bgx_get_lmac_count(nic->node, bgx); 2698c2ecf20Sopenharmony_ci lmac_credits = nic_reg_read(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8)); 2708c2ecf20Sopenharmony_ci lmac_credits &= ~(0xFFFFFULL << 12); 2718c2ecf20Sopenharmony_ci lmac_credits |= (((((48 * 1024) / lmac_cnt) - new_frs) / 16) << 12); 2728c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credits); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Enforce MTU in HW 2758c2ecf20Sopenharmony_ci * This config is supported only from 88xx pass 2.0 onwards. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (!pass1_silicon(nic->pdev)) 2788c2ecf20Sopenharmony_ci nic_reg_write(nic, 2798c2ecf20Sopenharmony_ci NIC_PF_LMAC_0_7_CFG2 + (lmac * 8), new_frs); 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* Set minimum transmit packet size */ 2848c2ecf20Sopenharmony_cistatic void nic_set_tx_pkt_pad(struct nicpf *nic, int size) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci int lmac, max_lmac; 2878c2ecf20Sopenharmony_ci u16 sdevid; 2888c2ecf20Sopenharmony_ci u64 lmac_cfg; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* There is a issue in HW where-in while sending GSO sized 2918c2ecf20Sopenharmony_ci * pkts as part of TSO, if pkt len falls below this size 2928c2ecf20Sopenharmony_ci * NIC will zero PAD packet and also updates IP total length. 2938c2ecf20Sopenharmony_ci * Hence set this value to lessthan min pkt size of MAC+IP+TCP 2948c2ecf20Sopenharmony_ci * headers, BGX will do the padding to transmit 64 byte pkt. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci if (size > 52) 2978c2ecf20Sopenharmony_ci size = 52; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); 3008c2ecf20Sopenharmony_ci /* 81xx's RGX has only one LMAC */ 3018c2ecf20Sopenharmony_ci if (sdevid == PCI_SUBSYS_DEVID_81XX_NIC_PF) 3028c2ecf20Sopenharmony_ci max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1; 3038c2ecf20Sopenharmony_ci else 3048c2ecf20Sopenharmony_ci max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci for (lmac = 0; lmac < max_lmac; lmac++) { 3078c2ecf20Sopenharmony_ci lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); 3088c2ecf20Sopenharmony_ci lmac_cfg &= ~(0xF << 2); 3098c2ecf20Sopenharmony_ci lmac_cfg |= ((size / 4) << 2); 3108c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* Function to check number of LMACs present and set VF::LMAC mapping. 3158c2ecf20Sopenharmony_ci * Mapping will be used while initializing channels. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic void nic_set_lmac_vf_mapping(struct nicpf *nic) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci unsigned bgx_map = bgx_get_map(nic->node); 3208c2ecf20Sopenharmony_ci int bgx, next_bgx_lmac = 0; 3218c2ecf20Sopenharmony_ci int lmac, lmac_cnt = 0; 3228c2ecf20Sopenharmony_ci u64 lmac_credit; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci nic->num_vf_en = 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) { 3278c2ecf20Sopenharmony_ci if (!(bgx_map & (1 << bgx))) 3288c2ecf20Sopenharmony_ci continue; 3298c2ecf20Sopenharmony_ci lmac_cnt = bgx_get_lmac_count(nic->node, bgx); 3308c2ecf20Sopenharmony_ci for (lmac = 0; lmac < lmac_cnt; lmac++) 3318c2ecf20Sopenharmony_ci nic->vf_lmac_map[next_bgx_lmac++] = 3328c2ecf20Sopenharmony_ci NIC_SET_VF_LMAC_MAP(bgx, lmac); 3338c2ecf20Sopenharmony_ci nic->num_vf_en += lmac_cnt; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Program LMAC credits */ 3368c2ecf20Sopenharmony_ci lmac_credit = (1ull << 1); /* channel credit enable */ 3378c2ecf20Sopenharmony_ci lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ 3388c2ecf20Sopenharmony_ci /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ 3398c2ecf20Sopenharmony_ci lmac_credit |= (((((48 * 1024) / lmac_cnt) - 3408c2ecf20Sopenharmony_ci NIC_HW_MAX_FRS) / 16) << 12); 3418c2ecf20Sopenharmony_ci lmac = bgx * MAX_LMAC_PER_BGX; 3428c2ecf20Sopenharmony_ci for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) 3438c2ecf20Sopenharmony_ci nic_reg_write(nic, 3448c2ecf20Sopenharmony_ci NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), 3458c2ecf20Sopenharmony_ci lmac_credit); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* On CN81XX there are only 8 VFs but max possible no of 3488c2ecf20Sopenharmony_ci * interfaces are 9. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci if (nic->num_vf_en >= pci_sriov_get_totalvfs(nic->pdev)) { 3518c2ecf20Sopenharmony_ci nic->num_vf_en = pci_sriov_get_totalvfs(nic->pdev); 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic void nic_get_hw_info(struct nicpf *nic) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci u16 sdevid; 3608c2ecf20Sopenharmony_ci struct hw_info *hw = nic->hw; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci switch (sdevid) { 3658c2ecf20Sopenharmony_ci case PCI_SUBSYS_DEVID_88XX_NIC_PF: 3668c2ecf20Sopenharmony_ci hw->bgx_cnt = MAX_BGX_PER_CN88XX; 3678c2ecf20Sopenharmony_ci hw->chans_per_lmac = 16; 3688c2ecf20Sopenharmony_ci hw->chans_per_bgx = 128; 3698c2ecf20Sopenharmony_ci hw->cpi_cnt = 2048; 3708c2ecf20Sopenharmony_ci hw->rssi_cnt = 4096; 3718c2ecf20Sopenharmony_ci hw->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE; 3728c2ecf20Sopenharmony_ci hw->tl3_cnt = 256; 3738c2ecf20Sopenharmony_ci hw->tl2_cnt = 64; 3748c2ecf20Sopenharmony_ci hw->tl1_cnt = 2; 3758c2ecf20Sopenharmony_ci hw->tl1_per_bgx = true; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case PCI_SUBSYS_DEVID_81XX_NIC_PF: 3788c2ecf20Sopenharmony_ci hw->bgx_cnt = MAX_BGX_PER_CN81XX; 3798c2ecf20Sopenharmony_ci hw->chans_per_lmac = 8; 3808c2ecf20Sopenharmony_ci hw->chans_per_bgx = 32; 3818c2ecf20Sopenharmony_ci hw->chans_per_rgx = 8; 3828c2ecf20Sopenharmony_ci hw->chans_per_lbk = 24; 3838c2ecf20Sopenharmony_ci hw->cpi_cnt = 512; 3848c2ecf20Sopenharmony_ci hw->rssi_cnt = 256; 3858c2ecf20Sopenharmony_ci hw->rss_ind_tbl_size = 32; /* Max RSSI / Max interfaces */ 3868c2ecf20Sopenharmony_ci hw->tl3_cnt = 64; 3878c2ecf20Sopenharmony_ci hw->tl2_cnt = 16; 3888c2ecf20Sopenharmony_ci hw->tl1_cnt = 10; 3898c2ecf20Sopenharmony_ci hw->tl1_per_bgx = false; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case PCI_SUBSYS_DEVID_83XX_NIC_PF: 3928c2ecf20Sopenharmony_ci hw->bgx_cnt = MAX_BGX_PER_CN83XX; 3938c2ecf20Sopenharmony_ci hw->chans_per_lmac = 8; 3948c2ecf20Sopenharmony_ci hw->chans_per_bgx = 32; 3958c2ecf20Sopenharmony_ci hw->chans_per_lbk = 64; 3968c2ecf20Sopenharmony_ci hw->cpi_cnt = 2048; 3978c2ecf20Sopenharmony_ci hw->rssi_cnt = 1024; 3988c2ecf20Sopenharmony_ci hw->rss_ind_tbl_size = 64; /* Max RSSI / Max interfaces */ 3998c2ecf20Sopenharmony_ci hw->tl3_cnt = 256; 4008c2ecf20Sopenharmony_ci hw->tl2_cnt = 64; 4018c2ecf20Sopenharmony_ci hw->tl1_cnt = 18; 4028c2ecf20Sopenharmony_ci hw->tl1_per_bgx = false; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci hw->tl4_cnt = MAX_QUEUES_PER_QSET * pci_sriov_get_totalvfs(nic->pdev); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci#define BGX0_BLOCK 8 4098c2ecf20Sopenharmony_ci#define BGX1_BLOCK 9 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic void nic_init_hw(struct nicpf *nic) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int i; 4148c2ecf20Sopenharmony_ci u64 cqm_cfg; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Enable NIC HW block */ 4178c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CFG, 0x3); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Enable backpressure */ 4208c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* TNS and TNS bypass modes are present only on 88xx 4238c2ecf20Sopenharmony_ci * Also offset of this CSR has changed in 81xx and 83xx. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { 4268c2ecf20Sopenharmony_ci /* Disable TNS mode on both interfaces */ 4278c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, 4288c2ecf20Sopenharmony_ci (NIC_TNS_BYPASS_MODE << 7) | 4298c2ecf20Sopenharmony_ci BGX0_BLOCK | (1ULL << 16)); 4308c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), 4318c2ecf20Sopenharmony_ci (NIC_TNS_BYPASS_MODE << 7) | 4328c2ecf20Sopenharmony_ci BGX1_BLOCK | (1ULL << 16)); 4338c2ecf20Sopenharmony_ci } else { 4348c2ecf20Sopenharmony_ci /* Configure timestamp generation timeout to 10us */ 4358c2ecf20Sopenharmony_ci for (i = 0; i < nic->hw->bgx_cnt; i++) 4368c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3), 4378c2ecf20Sopenharmony_ci (1ULL << 16)); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, 4418c2ecf20Sopenharmony_ci (1ULL << 63) | BGX0_BLOCK); 4428c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), 4438c2ecf20Sopenharmony_ci (1ULL << 63) | BGX1_BLOCK); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* PKIND configuration */ 4468c2ecf20Sopenharmony_ci nic->pkind.minlen = 0; 4478c2ecf20Sopenharmony_ci nic->pkind.maxlen = NIC_HW_MAX_FRS + VLAN_ETH_HLEN + ETH_FCS_LEN + 4; 4488c2ecf20Sopenharmony_ci nic->pkind.lenerr_en = 1; 4498c2ecf20Sopenharmony_ci nic->pkind.rx_hdr = 0; 4508c2ecf20Sopenharmony_ci nic->pkind.hdr_sl = 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci for (i = 0; i < NIC_MAX_PKIND; i++) 4538c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), 4548c2ecf20Sopenharmony_ci *(u64 *)&nic->pkind); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Timer config */ 4598c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Enable VLAN ethertype matching and stripping */ 4628c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, 4638c2ecf20Sopenharmony_ci (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Check if HW expected value is higher (could be in future chips) */ 4668c2ecf20Sopenharmony_ci cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); 4678c2ecf20Sopenharmony_ci if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) 4688c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* Channel parse index configuration */ 4728c2ecf20Sopenharmony_cistatic void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct hw_info *hw = nic->hw; 4758c2ecf20Sopenharmony_ci u32 vnic, bgx, lmac, chan; 4768c2ecf20Sopenharmony_ci u32 padd, cpi_count = 0; 4778c2ecf20Sopenharmony_ci u64 cpi_base, cpi, rssi_base, rssi; 4788c2ecf20Sopenharmony_ci u8 qset, rq_idx = 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci vnic = cfg->vf_id; 4818c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 4828c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx); 4858c2ecf20Sopenharmony_ci cpi_base = vnic * NIC_MAX_CPI_PER_LMAC; 4868c2ecf20Sopenharmony_ci rssi_base = vnic * hw->rss_ind_tbl_size; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* Rx channel configuration */ 4898c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), 4908c2ecf20Sopenharmony_ci (1ull << 63) | (vnic << 0)); 4918c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), 4928c2ecf20Sopenharmony_ci ((u64)cfg->cpi_alg << 62) | (cpi_base << 48)); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (cfg->cpi_alg == CPI_ALG_NONE) 4958c2ecf20Sopenharmony_ci cpi_count = 1; 4968c2ecf20Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ 4978c2ecf20Sopenharmony_ci cpi_count = 8; 4988c2ecf20Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ 4998c2ecf20Sopenharmony_ci cpi_count = 16; 5008c2ecf20Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ 5018c2ecf20Sopenharmony_ci cpi_count = NIC_MAX_CPI_PER_LMAC; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* RSS Qset, Qidx mapping */ 5048c2ecf20Sopenharmony_ci qset = cfg->vf_id; 5058c2ecf20Sopenharmony_ci rssi = rssi_base; 5068c2ecf20Sopenharmony_ci for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { 5078c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), 5088c2ecf20Sopenharmony_ci (qset << 3) | rq_idx); 5098c2ecf20Sopenharmony_ci rq_idx++; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci rssi = 0; 5138c2ecf20Sopenharmony_ci cpi = cpi_base; 5148c2ecf20Sopenharmony_ci for (; cpi < (cpi_base + cpi_count); cpi++) { 5158c2ecf20Sopenharmony_ci /* Determine port to channel adder */ 5168c2ecf20Sopenharmony_ci if (cfg->cpi_alg != CPI_ALG_DIFF) 5178c2ecf20Sopenharmony_ci padd = cpi % cpi_count; 5188c2ecf20Sopenharmony_ci else 5198c2ecf20Sopenharmony_ci padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Leave RSS_SIZE as '0' to disable RSS */ 5228c2ecf20Sopenharmony_ci if (pass1_silicon(nic->pdev)) { 5238c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 5248c2ecf20Sopenharmony_ci (vnic << 24) | (padd << 16) | 5258c2ecf20Sopenharmony_ci (rssi_base + rssi)); 5268c2ecf20Sopenharmony_ci } else { 5278c2ecf20Sopenharmony_ci /* Set MPI_ALG to '0' to disable MCAM parsing */ 5288c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), 5298c2ecf20Sopenharmony_ci (padd << 16)); 5308c2ecf20Sopenharmony_ci /* MPI index is same as CPI if MPI_ALG is not enabled */ 5318c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3), 5328c2ecf20Sopenharmony_ci (vnic << 24) | (rssi_base + rssi)); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if ((rssi + 1) >= cfg->rq_cnt) 5368c2ecf20Sopenharmony_ci continue; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (cfg->cpi_alg == CPI_ALG_VLAN) 5398c2ecf20Sopenharmony_ci rssi++; 5408c2ecf20Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_VLAN16) 5418c2ecf20Sopenharmony_ci rssi = ((cpi - cpi_base) & 0xe) >> 1; 5428c2ecf20Sopenharmony_ci else if (cfg->cpi_alg == CPI_ALG_DIFF) 5438c2ecf20Sopenharmony_ci rssi = ((cpi - cpi_base) & 0x38) >> 3; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci nic->cpi_base[cfg->vf_id] = cpi_base; 5468c2ecf20Sopenharmony_ci nic->rssi_base[cfg->vf_id] = rssi_base; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/* Responsds to VF with its RSS indirection table size */ 5508c2ecf20Sopenharmony_cistatic void nic_send_rss_size(struct nicpf *nic, int vf) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci mbx.rss_size.msg = NIC_MBOX_MSG_RSS_SIZE; 5558c2ecf20Sopenharmony_ci mbx.rss_size.ind_tbl_size = nic->hw->rss_ind_tbl_size; 5568c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/* Receive side scaling configuration 5608c2ecf20Sopenharmony_ci * configure: 5618c2ecf20Sopenharmony_ci * - RSS index 5628c2ecf20Sopenharmony_ci * - indir table i.e hash::RQ mapping 5638c2ecf20Sopenharmony_ci * - no of hash bits to consider 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_cistatic void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci u8 qset, idx = 0; 5688c2ecf20Sopenharmony_ci u64 cpi_cfg, cpi_base, rssi_base, rssi; 5698c2ecf20Sopenharmony_ci u64 idx_addr; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci rssi_base = nic->rssi_base[cfg->vf_id] + cfg->tbl_offset; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci rssi = rssi_base; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci for (; rssi < (rssi_base + cfg->tbl_len); rssi++) { 5768c2ecf20Sopenharmony_ci u8 svf = cfg->ind_tbl[idx] >> 3; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (svf) 5798c2ecf20Sopenharmony_ci qset = nic->vf_sqs[cfg->vf_id][svf - 1]; 5808c2ecf20Sopenharmony_ci else 5818c2ecf20Sopenharmony_ci qset = cfg->vf_id; 5828c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), 5838c2ecf20Sopenharmony_ci (qset << 3) | (cfg->ind_tbl[idx] & 0x7)); 5848c2ecf20Sopenharmony_ci idx++; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci cpi_base = nic->cpi_base[cfg->vf_id]; 5888c2ecf20Sopenharmony_ci if (pass1_silicon(nic->pdev)) 5898c2ecf20Sopenharmony_ci idx_addr = NIC_PF_CPI_0_2047_CFG; 5908c2ecf20Sopenharmony_ci else 5918c2ecf20Sopenharmony_ci idx_addr = NIC_PF_MPI_0_2047_CFG; 5928c2ecf20Sopenharmony_ci cpi_cfg = nic_reg_read(nic, idx_addr | (cpi_base << 3)); 5938c2ecf20Sopenharmony_ci cpi_cfg &= ~(0xFULL << 20); 5948c2ecf20Sopenharmony_ci cpi_cfg |= (cfg->hash_bits << 20); 5958c2ecf20Sopenharmony_ci nic_reg_write(nic, idx_addr | (cpi_base << 3), cpi_cfg); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/* 4 level transmit side scheduler configutation 5998c2ecf20Sopenharmony_ci * for TNS bypass mode 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci * Sample configuration for SQ0 on 88xx 6028c2ecf20Sopenharmony_ci * VNIC0-SQ0 -> TL4(0) -> TL3[0] -> TL2[0] -> TL1[0] -> BGX0 6038c2ecf20Sopenharmony_ci * VNIC1-SQ0 -> TL4(8) -> TL3[2] -> TL2[0] -> TL1[0] -> BGX0 6048c2ecf20Sopenharmony_ci * VNIC2-SQ0 -> TL4(16) -> TL3[4] -> TL2[1] -> TL1[0] -> BGX0 6058c2ecf20Sopenharmony_ci * VNIC3-SQ0 -> TL4(24) -> TL3[6] -> TL2[1] -> TL1[0] -> BGX0 6068c2ecf20Sopenharmony_ci * VNIC4-SQ0 -> TL4(512) -> TL3[128] -> TL2[32] -> TL1[1] -> BGX1 6078c2ecf20Sopenharmony_ci * VNIC5-SQ0 -> TL4(520) -> TL3[130] -> TL2[32] -> TL1[1] -> BGX1 6088c2ecf20Sopenharmony_ci * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 6098c2ecf20Sopenharmony_ci * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_cistatic void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, 6128c2ecf20Sopenharmony_ci struct sq_cfg_msg *sq) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct hw_info *hw = nic->hw; 6158c2ecf20Sopenharmony_ci u32 bgx, lmac, chan; 6168c2ecf20Sopenharmony_ci u32 tl2, tl3, tl4; 6178c2ecf20Sopenharmony_ci u32 rr_quantum; 6188c2ecf20Sopenharmony_ci u8 sq_idx = sq->sq_num; 6198c2ecf20Sopenharmony_ci u8 pqs_vnic; 6208c2ecf20Sopenharmony_ci int svf; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (sq->sqs_mode) 6238c2ecf20Sopenharmony_ci pqs_vnic = nic->pqs_vf[vnic]; 6248c2ecf20Sopenharmony_ci else 6258c2ecf20Sopenharmony_ci pqs_vnic = vnic; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 6288c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 24 bytes for FCS, IPG and preamble */ 6318c2ecf20Sopenharmony_ci rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* For 88xx 0-511 TL4 transmits via BGX0 and 6348c2ecf20Sopenharmony_ci * 512-1023 TL4s transmit via BGX1. 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci if (hw->tl1_per_bgx) { 6378c2ecf20Sopenharmony_ci tl4 = bgx * (hw->tl4_cnt / hw->bgx_cnt); 6388c2ecf20Sopenharmony_ci if (!sq->sqs_mode) { 6398c2ecf20Sopenharmony_ci tl4 += (lmac * MAX_QUEUES_PER_QSET); 6408c2ecf20Sopenharmony_ci } else { 6418c2ecf20Sopenharmony_ci for (svf = 0; svf < MAX_SQS_PER_VF; svf++) { 6428c2ecf20Sopenharmony_ci if (nic->vf_sqs[pqs_vnic][svf] == vnic) 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci tl4 += (MAX_LMAC_PER_BGX * MAX_QUEUES_PER_QSET); 6468c2ecf20Sopenharmony_ci tl4 += (lmac * MAX_QUEUES_PER_QSET * MAX_SQS_PER_VF); 6478c2ecf20Sopenharmony_ci tl4 += (svf * MAX_QUEUES_PER_QSET); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci tl4 = (vnic * MAX_QUEUES_PER_QSET); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci tl4 += sq_idx; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci tl3 = tl4 / (hw->tl4_cnt / hw->tl3_cnt); 6558c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | 6568c2ecf20Sopenharmony_ci ((u64)vnic << NIC_QS_ID_SHIFT) | 6578c2ecf20Sopenharmony_ci ((u32)sq_idx << NIC_Q_NUM_SHIFT), tl4); 6588c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL4_0_1023_CFG | (tl4 << 3), 6598c2ecf20Sopenharmony_ci ((u64)vnic << 27) | ((u32)sq_idx << 24) | rr_quantum); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3_0_255_CFG | (tl3 << 3), rr_quantum); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* On 88xx 0-127 channels are for BGX0 and 6648c2ecf20Sopenharmony_ci * 127-255 channels for BGX1. 6658c2ecf20Sopenharmony_ci * 6668c2ecf20Sopenharmony_ci * On 81xx/83xx TL3_CHAN reg should be configured with channel 6678c2ecf20Sopenharmony_ci * within LMAC i.e 0-7 and not the actual channel number like on 88xx 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci chan = (lmac * hw->chans_per_lmac) + (bgx * hw->chans_per_bgx); 6708c2ecf20Sopenharmony_ci if (hw->tl1_per_bgx) 6718c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), chan); 6728c2ecf20Sopenharmony_ci else 6738c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3_0_255_CHAN | (tl3 << 3), 0); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* Enable backpressure on the channel */ 6768c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CHAN_0_255_TX_CFG | (chan << 3), 1); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci tl2 = tl3 >> 2; 6798c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL3A_0_63_CFG | (tl2 << 3), tl2); 6808c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL2_0_63_CFG | (tl2 << 3), rr_quantum); 6818c2ecf20Sopenharmony_ci /* No priorities as of now */ 6828c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Unlike 88xx where TL2s 0-31 transmits to TL1 '0' and rest to TL1 '1' 6858c2ecf20Sopenharmony_ci * on 81xx/83xx TL2 needs to be configured to transmit to one of the 6868c2ecf20Sopenharmony_ci * possible LMACs. 6878c2ecf20Sopenharmony_ci * 6888c2ecf20Sopenharmony_ci * This register doesn't exist on 88xx. 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_ci if (!hw->tl1_per_bgx) 6918c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_TL2_LMAC | (tl2 << 3), 6928c2ecf20Sopenharmony_ci lmac + (bgx * MAX_LMAC_PER_BGX)); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci/* Send primary nicvf pointer to secondary QS's VF */ 6968c2ecf20Sopenharmony_cistatic void nic_send_pnicvf(struct nicpf *nic, int sqs) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci mbx.nicvf.msg = NIC_MBOX_MSG_PNICVF_PTR; 7018c2ecf20Sopenharmony_ci mbx.nicvf.nicvf = nic->nicvf[nic->pqs_vf[sqs]]; 7028c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, sqs, &mbx); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* Send SQS's nicvf pointer to primary QS's VF */ 7068c2ecf20Sopenharmony_cistatic void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 7098c2ecf20Sopenharmony_ci int sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id]; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR; 7128c2ecf20Sopenharmony_ci mbx.nicvf.sqs_id = nicvf->sqs_id; 7138c2ecf20Sopenharmony_ci mbx.nicvf.nicvf = nic->nicvf[sqs_id]; 7148c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, nicvf->vf_id, &mbx); 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci/* Find next available Qset that can be assigned as a 7188c2ecf20Sopenharmony_ci * secondary Qset to a VF. 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_cistatic int nic_nxt_avail_sqs(struct nicpf *nic) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci int sqs; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci for (sqs = 0; sqs < nic->num_sqs_en; sqs++) { 7258c2ecf20Sopenharmony_ci if (!nic->sqs_used[sqs]) 7268c2ecf20Sopenharmony_ci nic->sqs_used[sqs] = true; 7278c2ecf20Sopenharmony_ci else 7288c2ecf20Sopenharmony_ci continue; 7298c2ecf20Sopenharmony_ci return sqs + nic->num_vf_en; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci return -1; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci/* Allocate additional Qsets for requested VF */ 7358c2ecf20Sopenharmony_cistatic void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 7388c2ecf20Sopenharmony_ci int idx, alloc_qs = 0; 7398c2ecf20Sopenharmony_ci int sqs_id; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!nic->num_sqs_en) 7428c2ecf20Sopenharmony_ci goto send_mbox; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci for (idx = 0; idx < sqs->qs_count; idx++) { 7458c2ecf20Sopenharmony_ci sqs_id = nic_nxt_avail_sqs(nic); 7468c2ecf20Sopenharmony_ci if (sqs_id < 0) 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci nic->vf_sqs[sqs->vf_id][idx] = sqs_id; 7498c2ecf20Sopenharmony_ci nic->pqs_vf[sqs_id] = sqs->vf_id; 7508c2ecf20Sopenharmony_ci alloc_qs++; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cisend_mbox: 7548c2ecf20Sopenharmony_ci mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS; 7558c2ecf20Sopenharmony_ci mbx.sqs_alloc.vf_id = sqs->vf_id; 7568c2ecf20Sopenharmony_ci mbx.sqs_alloc.qs_count = alloc_qs; 7578c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci int bgx_idx, lmac_idx; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (lbk->vf_id >= nic->num_vf_en) 7658c2ecf20Sopenharmony_ci return -1; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 7688c2ecf20Sopenharmony_ci lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* Enable moving average calculation. 7738c2ecf20Sopenharmony_ci * Keep the LVL/AVG delay to HW enforced minimum so that, not too many 7748c2ecf20Sopenharmony_ci * packets sneek in between average calculations. 7758c2ecf20Sopenharmony_ci */ 7768c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_CQ_AVG_CFG, 7778c2ecf20Sopenharmony_ci (BIT_ULL(20) | 0x2ull << 14 | 0x1)); 7788c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RRM_AVG_CFG, 7798c2ecf20Sopenharmony_ci (BIT_ULL(20) | 0x3ull << 14 | 0x1)); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci/* Reset statistics counters */ 7858c2ecf20Sopenharmony_cistatic int nic_reset_stat_counters(struct nicpf *nic, 7868c2ecf20Sopenharmony_ci int vf, struct reset_stat_cfg *cfg) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci int i, stat, qnum; 7898c2ecf20Sopenharmony_ci u64 reg_addr; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci for (i = 0; i < RX_STATS_ENUM_LAST; i++) { 7928c2ecf20Sopenharmony_ci if (cfg->rx_stat_mask & BIT(i)) { 7938c2ecf20Sopenharmony_ci reg_addr = NIC_PF_VNIC_0_127_RX_STAT_0_13 | 7948c2ecf20Sopenharmony_ci (vf << NIC_QS_ID_SHIFT) | 7958c2ecf20Sopenharmony_ci (i << 3); 7968c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci for (i = 0; i < TX_STATS_ENUM_LAST; i++) { 8018c2ecf20Sopenharmony_ci if (cfg->tx_stat_mask & BIT(i)) { 8028c2ecf20Sopenharmony_ci reg_addr = NIC_PF_VNIC_0_127_TX_STAT_0_4 | 8038c2ecf20Sopenharmony_ci (vf << NIC_QS_ID_SHIFT) | 8048c2ecf20Sopenharmony_ci (i << 3); 8058c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci for (i = 0; i <= 15; i++) { 8108c2ecf20Sopenharmony_ci qnum = i >> 1; 8118c2ecf20Sopenharmony_ci stat = i & 1 ? 1 : 0; 8128c2ecf20Sopenharmony_ci reg_addr = (vf << NIC_QS_ID_SHIFT) | 8138c2ecf20Sopenharmony_ci (qnum << NIC_Q_NUM_SHIFT) | (stat << 3); 8148c2ecf20Sopenharmony_ci if (cfg->rq_stat_mask & BIT(i)) { 8158c2ecf20Sopenharmony_ci reg_addr |= NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1; 8168c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci if (cfg->sq_stat_mask & BIT(i)) { 8198c2ecf20Sopenharmony_ci reg_addr |= NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1; 8208c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, 0); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic void nic_enable_tunnel_parsing(struct nicpf *nic, int vf) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci u64 prot_def = (IPV6_PROT << 32) | (IPV4_PROT << 16) | ET_PROT; 8308c2ecf20Sopenharmony_ci u64 vxlan_prot_def = (IPV6_PROT_DEF << 32) | 8318c2ecf20Sopenharmony_ci (IPV4_PROT_DEF) << 16 | ET_PROT_DEF; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* Configure tunnel parsing parameters */ 8348c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_GENEVE_DEF, 8358c2ecf20Sopenharmony_ci (1ULL << 63 | UDP_GENEVE_PORT_NUM)); 8368c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_GENEVE_PROT_DEF, 8378c2ecf20Sopenharmony_ci ((7ULL << 61) | prot_def)); 8388c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_NVGRE_PROT_DEF, 8398c2ecf20Sopenharmony_ci ((7ULL << 61) | prot_def)); 8408c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_VXLAN_DEF_0_1, 8418c2ecf20Sopenharmony_ci ((1ULL << 63) | UDP_VXLAN_PORT_NUM)); 8428c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_VXLAN_PROT_DEF, 8438c2ecf20Sopenharmony_ci ((0xfULL << 60) | vxlan_prot_def)); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic void nic_enable_vf(struct nicpf *nic, int vf, bool enable) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci int bgx, lmac; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci nic->vf_enabled[vf] = enable; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) 8538c2ecf20Sopenharmony_ci return; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 8568c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci int bgx, lmac; 8648c2ecf20Sopenharmony_ci struct pfc pfc; 8658c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) 8688c2ecf20Sopenharmony_ci return; 8698c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 8708c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (cfg->get) { 8738c2ecf20Sopenharmony_ci bgx_lmac_get_pfc(nic->node, bgx, lmac, &pfc); 8748c2ecf20Sopenharmony_ci mbx.pfc.msg = NIC_MBOX_MSG_PFC; 8758c2ecf20Sopenharmony_ci mbx.pfc.autoneg = pfc.autoneg; 8768c2ecf20Sopenharmony_ci mbx.pfc.fc_rx = pfc.fc_rx; 8778c2ecf20Sopenharmony_ci mbx.pfc.fc_tx = pfc.fc_tx; 8788c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 8798c2ecf20Sopenharmony_ci } else { 8808c2ecf20Sopenharmony_ci bgx_lmac_set_pfc(nic->node, bgx, lmac, cfg); 8818c2ecf20Sopenharmony_ci nic_mbx_send_ack(nic, vf); 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci/* Enable or disable HW timestamping by BGX for pkts received on a LMAC */ 8868c2ecf20Sopenharmony_cistatic void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct pkind_cfg *pkind; 8898c2ecf20Sopenharmony_ci u8 lmac, bgx_idx; 8908c2ecf20Sopenharmony_ci u64 pkind_val, pkind_idx; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) 8938c2ecf20Sopenharmony_ci return; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 8968c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX; 8998c2ecf20Sopenharmony_ci pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3)); 9008c2ecf20Sopenharmony_ci pkind = (struct pkind_cfg *)&pkind_val; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (ptp->enable && !pkind->hdr_sl) { 9038c2ecf20Sopenharmony_ci /* Skiplen to exclude 8byte timestamp while parsing pkt 9048c2ecf20Sopenharmony_ci * If not configured, will result in L2 errors. 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_ci pkind->hdr_sl = 4; 9078c2ecf20Sopenharmony_ci /* Adjust max packet length allowed */ 9088c2ecf20Sopenharmony_ci pkind->maxlen += (pkind->hdr_sl * 2); 9098c2ecf20Sopenharmony_ci bgx_config_timestamping(nic->node, bgx_idx, lmac, true); 9108c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3), 9118c2ecf20Sopenharmony_ci (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588); 9128c2ecf20Sopenharmony_ci } else if (!ptp->enable && pkind->hdr_sl) { 9138c2ecf20Sopenharmony_ci pkind->maxlen -= (pkind->hdr_sl * 2); 9148c2ecf20Sopenharmony_ci pkind->hdr_sl = 0; 9158c2ecf20Sopenharmony_ci bgx_config_timestamping(nic->node, bgx_idx, lmac, false); 9168c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7 | (1 << 3), 9178c2ecf20Sopenharmony_ci (ETYPE_ALG_SKIP << 16) | ETH_P_8021Q); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val); 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci/* Get BGX LMAC link status and update corresponding VF 9248c2ecf20Sopenharmony_ci * if there is a change, valid only if internal L2 switch 9258c2ecf20Sopenharmony_ci * is not present otherwise VF link is always treated as up 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_cistatic void nic_link_status_get(struct nicpf *nic, u8 vf) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 9308c2ecf20Sopenharmony_ci struct bgx_link_status link; 9318c2ecf20Sopenharmony_ci u8 bgx, lmac; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Get BGX, LMAC indices for the VF */ 9368c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 9378c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* Get interface link status */ 9408c2ecf20Sopenharmony_ci bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Send a mbox message to VF with current link status */ 9438c2ecf20Sopenharmony_ci mbx.link_status.link_up = link.link_up; 9448c2ecf20Sopenharmony_ci mbx.link_status.duplex = link.duplex; 9458c2ecf20Sopenharmony_ci mbx.link_status.speed = link.speed; 9468c2ecf20Sopenharmony_ci mbx.link_status.mac_type = link.mac_type; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* reply with link status */ 9498c2ecf20Sopenharmony_ci nic_send_msg_to_vf(nic, vf, &mbx); 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci/* Interrupt handler to handle mailbox messages from VFs */ 9538c2ecf20Sopenharmony_cistatic void nic_handle_mbx_intr(struct nicpf *nic, int vf) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci union nic_mbx mbx = {}; 9568c2ecf20Sopenharmony_ci u64 *mbx_data; 9578c2ecf20Sopenharmony_ci u64 mbx_addr; 9588c2ecf20Sopenharmony_ci u64 reg_addr; 9598c2ecf20Sopenharmony_ci u64 cfg; 9608c2ecf20Sopenharmony_ci int bgx, lmac; 9618c2ecf20Sopenharmony_ci int i; 9628c2ecf20Sopenharmony_ci int ret = 0; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci mbx_addr = nic_get_mbx_addr(vf); 9658c2ecf20Sopenharmony_ci mbx_data = (u64 *)&mbx; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { 9688c2ecf20Sopenharmony_ci *mbx_data = nic_reg_read(nic, mbx_addr); 9698c2ecf20Sopenharmony_ci mbx_data++; 9708c2ecf20Sopenharmony_ci mbx_addr += sizeof(u64); 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci dev_dbg(&nic->pdev->dev, "%s: Mailbox msg 0x%02x from VF%d\n", 9748c2ecf20Sopenharmony_ci __func__, mbx.msg.msg, vf); 9758c2ecf20Sopenharmony_ci switch (mbx.msg.msg) { 9768c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_READY: 9778c2ecf20Sopenharmony_ci nic_mbx_send_ready(nic, vf); 9788c2ecf20Sopenharmony_ci return; 9798c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_QS_CFG: 9808c2ecf20Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_CFG | 9818c2ecf20Sopenharmony_ci (mbx.qs.num << NIC_QS_ID_SHIFT); 9828c2ecf20Sopenharmony_ci cfg = mbx.qs.cfg; 9838c2ecf20Sopenharmony_ci /* Check if its a secondary Qset */ 9848c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) { 9858c2ecf20Sopenharmony_ci cfg = cfg & (~0x7FULL); 9868c2ecf20Sopenharmony_ci /* Assign this Qset to primary Qset's VF */ 9878c2ecf20Sopenharmony_ci cfg |= nic->pqs_vf[vf]; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, cfg); 9908c2ecf20Sopenharmony_ci break; 9918c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RQ_CFG: 9928c2ecf20Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | 9938c2ecf20Sopenharmony_ci (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 9948c2ecf20Sopenharmony_ci (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 9958c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.rq.cfg); 9968c2ecf20Sopenharmony_ci /* Enable CQE_RX2_S extension in CQE_RX descriptor. 9978c2ecf20Sopenharmony_ci * This gets appended by default on 81xx/83xx chips, 9988c2ecf20Sopenharmony_ci * for consistency enabling the same on 88xx pass2 9998c2ecf20Sopenharmony_ci * where this is introduced. 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_ci if (pass2_silicon(nic->pdev)) 10028c2ecf20Sopenharmony_ci nic_reg_write(nic, NIC_PF_RX_CFG, 0x01); 10038c2ecf20Sopenharmony_ci if (!pass1_silicon(nic->pdev)) 10048c2ecf20Sopenharmony_ci nic_enable_tunnel_parsing(nic, vf); 10058c2ecf20Sopenharmony_ci break; 10068c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RQ_BP_CFG: 10078c2ecf20Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_RQ_0_7_BP_CFG | 10088c2ecf20Sopenharmony_ci (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 10098c2ecf20Sopenharmony_ci (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 10108c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.rq.cfg); 10118c2ecf20Sopenharmony_ci break; 10128c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RQ_SW_SYNC: 10138c2ecf20Sopenharmony_ci ret = nic_rcv_queue_sw_sync(nic); 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RQ_DROP_CFG: 10168c2ecf20Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_RQ_0_7_DROP_CFG | 10178c2ecf20Sopenharmony_ci (mbx.rq.qs_num << NIC_QS_ID_SHIFT) | 10188c2ecf20Sopenharmony_ci (mbx.rq.rq_num << NIC_Q_NUM_SHIFT); 10198c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.rq.cfg); 10208c2ecf20Sopenharmony_ci break; 10218c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_SQ_CFG: 10228c2ecf20Sopenharmony_ci reg_addr = NIC_PF_QSET_0_127_SQ_0_7_CFG | 10238c2ecf20Sopenharmony_ci (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | 10248c2ecf20Sopenharmony_ci (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); 10258c2ecf20Sopenharmony_ci nic_reg_write(nic, reg_addr, mbx.sq.cfg); 10268c2ecf20Sopenharmony_ci nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_SET_MAC: 10298c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) { 10308c2ecf20Sopenharmony_ci ret = -1; /* NACK */ 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci lmac = mbx.mac.vf_id; 10348c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 10358c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); 10368c2ecf20Sopenharmony_ci bgx_set_lmac_mac(nic->node, bgx, lmac, mbx.mac.mac_addr); 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_SET_MAX_FRS: 10398c2ecf20Sopenharmony_ci ret = nic_update_hw_frs(nic, mbx.frs.max_frs, 10408c2ecf20Sopenharmony_ci mbx.frs.vf_id); 10418c2ecf20Sopenharmony_ci break; 10428c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_CPI_CFG: 10438c2ecf20Sopenharmony_ci nic_config_cpi(nic, &mbx.cpi_cfg); 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RSS_SIZE: 10468c2ecf20Sopenharmony_ci nic_send_rss_size(nic, vf); 10478c2ecf20Sopenharmony_ci return; 10488c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RSS_CFG: 10498c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RSS_CFG_CONT: 10508c2ecf20Sopenharmony_ci nic_config_rss(nic, &mbx.rss_cfg); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_CFG_DONE: 10538c2ecf20Sopenharmony_ci /* Last message of VF config msg sequence */ 10548c2ecf20Sopenharmony_ci nic_enable_vf(nic, vf, true); 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_SHUTDOWN: 10578c2ecf20Sopenharmony_ci /* First msg in VF teardown sequence */ 10588c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) 10598c2ecf20Sopenharmony_ci nic->sqs_used[vf - nic->num_vf_en] = false; 10608c2ecf20Sopenharmony_ci nic->pqs_vf[vf] = 0; 10618c2ecf20Sopenharmony_ci nic_enable_vf(nic, vf, false); 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_ALLOC_SQS: 10648c2ecf20Sopenharmony_ci nic_alloc_sqs(nic, &mbx.sqs_alloc); 10658c2ecf20Sopenharmony_ci return; 10668c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_NICVF_PTR: 10678c2ecf20Sopenharmony_ci nic->nicvf[vf] = mbx.nicvf.nicvf; 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_PNICVF_PTR: 10708c2ecf20Sopenharmony_ci nic_send_pnicvf(nic, vf); 10718c2ecf20Sopenharmony_ci return; 10728c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_SNICVF_PTR: 10738c2ecf20Sopenharmony_ci nic_send_snicvf(nic, &mbx.nicvf); 10748c2ecf20Sopenharmony_ci return; 10758c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_BGX_STATS: 10768c2ecf20Sopenharmony_ci nic_get_bgx_stats(nic, &mbx.bgx_stats); 10778c2ecf20Sopenharmony_ci return; 10788c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_LOOPBACK: 10798c2ecf20Sopenharmony_ci ret = nic_config_loopback(nic, &mbx.lbk); 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RESET_STAT_COUNTER: 10828c2ecf20Sopenharmony_ci ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat); 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_PFC: 10858c2ecf20Sopenharmony_ci nic_pause_frame(nic, vf, &mbx.pfc); 10868c2ecf20Sopenharmony_ci return; 10878c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_PTP_CFG: 10888c2ecf20Sopenharmony_ci nic_config_timestamp(nic, vf, &mbx.ptp); 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_RESET_XCAST: 10918c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) { 10928c2ecf20Sopenharmony_ci ret = -1; /* NACK */ 10938c2ecf20Sopenharmony_ci break; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 10968c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 10978c2ecf20Sopenharmony_ci bgx_reset_xcast_mode(nic->node, bgx, lmac, 10988c2ecf20Sopenharmony_ci vf < NIC_VF_PER_MBX_REG ? vf : 10998c2ecf20Sopenharmony_ci vf - NIC_VF_PER_MBX_REG); 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_ADD_MCAST: 11038c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) { 11048c2ecf20Sopenharmony_ci ret = -1; /* NACK */ 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 11088c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 11098c2ecf20Sopenharmony_ci bgx_set_dmac_cam_filter(nic->node, bgx, lmac, 11108c2ecf20Sopenharmony_ci mbx.xcast.mac, 11118c2ecf20Sopenharmony_ci vf < NIC_VF_PER_MBX_REG ? vf : 11128c2ecf20Sopenharmony_ci vf - NIC_VF_PER_MBX_REG); 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_SET_XCAST: 11168c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) { 11178c2ecf20Sopenharmony_ci ret = -1; /* NACK */ 11188c2ecf20Sopenharmony_ci break; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 11218c2ecf20Sopenharmony_ci lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); 11228c2ecf20Sopenharmony_ci bgx_set_xcast_mode(nic->node, bgx, lmac, mbx.xcast.mode); 11238c2ecf20Sopenharmony_ci break; 11248c2ecf20Sopenharmony_ci case NIC_MBOX_MSG_BGX_LINK_CHANGE: 11258c2ecf20Sopenharmony_ci if (vf >= nic->num_vf_en) { 11268c2ecf20Sopenharmony_ci ret = -1; /* NACK */ 11278c2ecf20Sopenharmony_ci break; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci nic_link_status_get(nic, vf); 11308c2ecf20Sopenharmony_ci return; 11318c2ecf20Sopenharmony_ci default: 11328c2ecf20Sopenharmony_ci dev_err(&nic->pdev->dev, 11338c2ecf20Sopenharmony_ci "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (!ret) { 11388c2ecf20Sopenharmony_ci nic_mbx_send_ack(nic, vf); 11398c2ecf20Sopenharmony_ci } else if (mbx.msg.msg != NIC_MBOX_MSG_READY) { 11408c2ecf20Sopenharmony_ci dev_err(&nic->pdev->dev, "NACK for MBOX 0x%02x from VF %d\n", 11418c2ecf20Sopenharmony_ci mbx.msg.msg, vf); 11428c2ecf20Sopenharmony_ci nic_mbx_send_nack(nic, vf); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci struct nicpf *nic = (struct nicpf *)nic_irq; 11498c2ecf20Sopenharmony_ci int mbx; 11508c2ecf20Sopenharmony_ci u64 intr; 11518c2ecf20Sopenharmony_ci u8 vf; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (irq == pci_irq_vector(nic->pdev, NIC_PF_INTR_ID_MBOX0)) 11548c2ecf20Sopenharmony_ci mbx = 0; 11558c2ecf20Sopenharmony_ci else 11568c2ecf20Sopenharmony_ci mbx = 1; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci intr = nic_reg_read(nic, NIC_PF_MAILBOX_INT + (mbx << 3)); 11598c2ecf20Sopenharmony_ci dev_dbg(&nic->pdev->dev, "PF interrupt Mbox%d 0x%llx\n", mbx, intr); 11608c2ecf20Sopenharmony_ci for (vf = 0; vf < NIC_VF_PER_MBX_REG; vf++) { 11618c2ecf20Sopenharmony_ci if (intr & (1ULL << vf)) { 11628c2ecf20Sopenharmony_ci dev_dbg(&nic->pdev->dev, "Intr from VF %d\n", 11638c2ecf20Sopenharmony_ci vf + (mbx * NIC_VF_PER_MBX_REG)); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci nic_handle_mbx_intr(nic, vf + 11668c2ecf20Sopenharmony_ci (mbx * NIC_VF_PER_MBX_REG)); 11678c2ecf20Sopenharmony_ci nic_clear_mbx_intr(nic, vf, mbx); 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic void nic_free_all_interrupts(struct nicpf *nic) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci int irq; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci for (irq = 0; irq < nic->num_vec; irq++) { 11788c2ecf20Sopenharmony_ci if (nic->irq_allocated[irq]) 11798c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(nic->pdev, irq), nic); 11808c2ecf20Sopenharmony_ci nic->irq_allocated[irq] = false; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic int nic_register_interrupts(struct nicpf *nic) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci int i, ret; 11878c2ecf20Sopenharmony_ci nic->num_vec = pci_msix_vec_count(nic->pdev); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* Enable MSI-X */ 11908c2ecf20Sopenharmony_ci ret = pci_alloc_irq_vectors(nic->pdev, nic->num_vec, nic->num_vec, 11918c2ecf20Sopenharmony_ci PCI_IRQ_MSIX); 11928c2ecf20Sopenharmony_ci if (ret < 0) { 11938c2ecf20Sopenharmony_ci dev_err(&nic->pdev->dev, 11948c2ecf20Sopenharmony_ci "Request for #%d msix vectors failed, returned %d\n", 11958c2ecf20Sopenharmony_ci nic->num_vec, ret); 11968c2ecf20Sopenharmony_ci return ret; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Register mailbox interrupt handler */ 12008c2ecf20Sopenharmony_ci for (i = NIC_PF_INTR_ID_MBOX0; i < nic->num_vec; i++) { 12018c2ecf20Sopenharmony_ci sprintf(nic->irq_name[i], 12028c2ecf20Sopenharmony_ci "NICPF Mbox%d", (i - NIC_PF_INTR_ID_MBOX0)); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci ret = request_irq(pci_irq_vector(nic->pdev, i), 12058c2ecf20Sopenharmony_ci nic_mbx_intr_handler, 0, 12068c2ecf20Sopenharmony_ci nic->irq_name[i], nic); 12078c2ecf20Sopenharmony_ci if (ret) 12088c2ecf20Sopenharmony_ci goto fail; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci nic->irq_allocated[i] = true; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* Enable mailbox interrupt */ 12148c2ecf20Sopenharmony_ci nic_enable_mbx_intr(nic); 12158c2ecf20Sopenharmony_ci return 0; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cifail: 12188c2ecf20Sopenharmony_ci dev_err(&nic->pdev->dev, "Request irq failed\n"); 12198c2ecf20Sopenharmony_ci nic_free_all_interrupts(nic); 12208c2ecf20Sopenharmony_ci pci_free_irq_vectors(nic->pdev); 12218c2ecf20Sopenharmony_ci nic->num_vec = 0; 12228c2ecf20Sopenharmony_ci return ret; 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic void nic_unregister_interrupts(struct nicpf *nic) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci nic_free_all_interrupts(nic); 12288c2ecf20Sopenharmony_ci pci_free_irq_vectors(nic->pdev); 12298c2ecf20Sopenharmony_ci nic->num_vec = 0; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic int nic_num_sqs_en(struct nicpf *nic, int vf_en) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci int pos, sqs_per_vf = MAX_SQS_PER_VF_SINGLE_NODE; 12358c2ecf20Sopenharmony_ci u16 total_vf; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* Secondary Qsets are needed only if CPU count is 12388c2ecf20Sopenharmony_ci * morethan MAX_QUEUES_PER_QSET. 12398c2ecf20Sopenharmony_ci */ 12408c2ecf20Sopenharmony_ci if (num_online_cpus() <= MAX_QUEUES_PER_QSET) 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci /* Check if its a multi-node environment */ 12448c2ecf20Sopenharmony_ci if (nr_node_ids > 1) 12458c2ecf20Sopenharmony_ci sqs_per_vf = MAX_SQS_PER_VF; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci pos = pci_find_ext_capability(nic->pdev, PCI_EXT_CAP_ID_SRIOV); 12488c2ecf20Sopenharmony_ci pci_read_config_word(nic->pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf); 12498c2ecf20Sopenharmony_ci return min(total_vf - vf_en, vf_en * sqs_per_vf); 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci int pos = 0; 12558c2ecf20Sopenharmony_ci int vf_en; 12568c2ecf20Sopenharmony_ci int err; 12578c2ecf20Sopenharmony_ci u16 total_vf_cnt; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); 12608c2ecf20Sopenharmony_ci if (!pos) { 12618c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "SRIOV capability is not found in PCIe config space\n"); 12628c2ecf20Sopenharmony_ci return -ENODEV; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci pci_read_config_word(pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf_cnt); 12668c2ecf20Sopenharmony_ci if (total_vf_cnt < nic->num_vf_en) 12678c2ecf20Sopenharmony_ci nic->num_vf_en = total_vf_cnt; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (!total_vf_cnt) 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci vf_en = nic->num_vf_en; 12738c2ecf20Sopenharmony_ci nic->num_sqs_en = nic_num_sqs_en(nic, nic->num_vf_en); 12748c2ecf20Sopenharmony_ci vf_en += nic->num_sqs_en; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci err = pci_enable_sriov(pdev, vf_en); 12778c2ecf20Sopenharmony_ci if (err) { 12788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n", 12798c2ecf20Sopenharmony_ci vf_en); 12808c2ecf20Sopenharmony_ci nic->num_vf_en = 0; 12818c2ecf20Sopenharmony_ci return err; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n", 12858c2ecf20Sopenharmony_ci vf_en); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci nic->flags |= NIC_SRIOV_ENABLED; 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 12948c2ecf20Sopenharmony_ci struct nicpf *nic; 12958c2ecf20Sopenharmony_ci u8 max_lmac; 12968c2ecf20Sopenharmony_ci int err; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(union nic_mbx) > 16); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci nic = devm_kzalloc(dev, sizeof(*nic), GFP_KERNEL); 13018c2ecf20Sopenharmony_ci if (!nic) 13028c2ecf20Sopenharmony_ci return -ENOMEM; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci nic->hw = devm_kzalloc(dev, sizeof(struct hw_info), GFP_KERNEL); 13058c2ecf20Sopenharmony_ci if (!nic->hw) 13068c2ecf20Sopenharmony_ci return -ENOMEM; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, nic); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci nic->pdev = pdev; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 13138c2ecf20Sopenharmony_ci if (err) { 13148c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable PCI device\n"); 13158c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 13168c2ecf20Sopenharmony_ci return err; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 13208c2ecf20Sopenharmony_ci if (err) { 13218c2ecf20Sopenharmony_ci dev_err(dev, "PCI request regions failed 0x%x\n", err); 13228c2ecf20Sopenharmony_ci goto err_disable_device; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(48)); 13268c2ecf20Sopenharmony_ci if (err) { 13278c2ecf20Sopenharmony_ci dev_err(dev, "Unable to get usable DMA configuration\n"); 13288c2ecf20Sopenharmony_ci goto err_release_regions; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48)); 13328c2ecf20Sopenharmony_ci if (err) { 13338c2ecf20Sopenharmony_ci dev_err(dev, "Unable to get 48-bit DMA for consistent allocations\n"); 13348c2ecf20Sopenharmony_ci goto err_release_regions; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* MAP PF's configuration registers */ 13388c2ecf20Sopenharmony_ci nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); 13398c2ecf20Sopenharmony_ci if (!nic->reg_base) { 13408c2ecf20Sopenharmony_ci dev_err(dev, "Cannot map config register space, aborting\n"); 13418c2ecf20Sopenharmony_ci err = -ENOMEM; 13428c2ecf20Sopenharmony_ci goto err_release_regions; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci nic->node = nic_get_node_id(pdev); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci /* Get HW capability info */ 13488c2ecf20Sopenharmony_ci nic_get_hw_info(nic); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* Allocate memory for LMAC tracking elements */ 13518c2ecf20Sopenharmony_ci err = -ENOMEM; 13528c2ecf20Sopenharmony_ci max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci nic->vf_lmac_map = devm_kmalloc_array(dev, max_lmac, sizeof(u8), 13558c2ecf20Sopenharmony_ci GFP_KERNEL); 13568c2ecf20Sopenharmony_ci if (!nic->vf_lmac_map) 13578c2ecf20Sopenharmony_ci goto err_release_regions; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Initialize hardware */ 13608c2ecf20Sopenharmony_ci nic_init_hw(nic); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci nic_set_lmac_vf_mapping(nic); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* Register interrupts */ 13658c2ecf20Sopenharmony_ci err = nic_register_interrupts(nic); 13668c2ecf20Sopenharmony_ci if (err) 13678c2ecf20Sopenharmony_ci goto err_release_regions; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* Configure SRIOV */ 13708c2ecf20Sopenharmony_ci err = nic_sriov_init(pdev, nic); 13718c2ecf20Sopenharmony_ci if (err) 13728c2ecf20Sopenharmony_ci goto err_unregister_interrupts; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return 0; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cierr_unregister_interrupts: 13778c2ecf20Sopenharmony_ci nic_unregister_interrupts(nic); 13788c2ecf20Sopenharmony_cierr_release_regions: 13798c2ecf20Sopenharmony_ci pci_release_regions(pdev); 13808c2ecf20Sopenharmony_cierr_disable_device: 13818c2ecf20Sopenharmony_ci pci_disable_device(pdev); 13828c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 13838c2ecf20Sopenharmony_ci return err; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic void nic_remove(struct pci_dev *pdev) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct nicpf *nic = pci_get_drvdata(pdev); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if (!nic) 13918c2ecf20Sopenharmony_ci return; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (nic->flags & NIC_SRIOV_ENABLED) 13948c2ecf20Sopenharmony_ci pci_disable_sriov(pdev); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci nic_unregister_interrupts(nic); 13978c2ecf20Sopenharmony_ci pci_release_regions(pdev); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci pci_disable_device(pdev); 14008c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 14018c2ecf20Sopenharmony_ci} 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_cistatic struct pci_driver nic_driver = { 14048c2ecf20Sopenharmony_ci .name = DRV_NAME, 14058c2ecf20Sopenharmony_ci .id_table = nic_id_table, 14068c2ecf20Sopenharmony_ci .probe = nic_probe, 14078c2ecf20Sopenharmony_ci .remove = nic_remove, 14088c2ecf20Sopenharmony_ci}; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic int __init nic_init_module(void) 14118c2ecf20Sopenharmony_ci{ 14128c2ecf20Sopenharmony_ci pr_info("%s, ver %s\n", DRV_NAME, DRV_VERSION); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci return pci_register_driver(&nic_driver); 14158c2ecf20Sopenharmony_ci} 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_cistatic void __exit nic_cleanup_module(void) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci pci_unregister_driver(&nic_driver); 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cimodule_init(nic_init_module); 14238c2ecf20Sopenharmony_cimodule_exit(nic_cleanup_module); 1424