Shinas Rasheed says: ==================== add octeon_ep_vf driver This driver implements networking functionality of Marvell's Octeon PCI Endpoint NIC VF. This driver support following devices: * Network controller: Cavium, Inc. Device b203 * Network controller: Cavium, Inc. Device b403 * Network controller: Cavium, Inc. Device b103 * Network controller: Cavium, Inc. Device b903 * Network controller: Cavium, Inc. Device ba03 * Network controller: Cavium, Inc. Device bc03 * Network controller: Cavium, Inc. Device bd03 Changes: V2: - Removed linux/version.h header file from inclusion in octep_vf_main.c - Corrected Makefile entry to include building octep_vf_mbox.c in [6/8] patch. - Removed redundant vzalloc pointer cast and vfree pointer check in [6/8] patch. V1: https://lore.kernel.org/all/20231221092844.2885872-1-srasheed@marvell.com/ ====================
Unified · Split
| @@ -42,6 +42,7 @@ Contents: · 41 unmodified lines | |||
| 42 | intel/ice | 42 | intel/ice |
| 43 | marvell/octeontx2 | 43 | marvell/octeontx2 |
| 44 | marvell/octeon_ep | 44 | marvell/octeon_ep |
| 45 | marvell/octeon_ep_vf | ||
| 45 | mellanox/mlx5/index | 46 | mellanox/mlx5/index |
| 46 | microsoft/netvsc | 47 | microsoft/netvsc |
| 47 | neterion/s2io | 48 | neterion/s2io |
| @@ -0,0 +1,24 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | |||
| 3 | ======================================================================= | ||
| 4 | Linux kernel networking driver for Marvell's Octeon PCI Endpoint NIC VF | ||
| 5 | ======================================================================= | ||
| 6 | |||
| 7 | Network driver for Marvell's Octeon PCI EndPoint NIC VF. | ||
| 8 | Copyright (c) 2020 Marvell International Ltd. | ||
| 9 | |||
| 10 | Overview | ||
| 11 | ======== | ||
| 12 | This driver implements networking functionality of Marvell's Octeon PCI | ||
| 13 | EndPoint NIC VF. | ||
| 14 | |||
| 15 | Supported Devices | ||
| 16 | ================= | ||
| 17 | Currently, this driver support following devices: | ||
| 18 | * Network controller: Cavium, Inc. Device b203 | ||
| 19 | * Network controller: Cavium, Inc. Device b403 | ||
| 20 | * Network controller: Cavium, Inc. Device b103 | ||
| 21 | * Network controller: Cavium, Inc. Device b903 | ||
| 22 | * Network controller: Cavium, Inc. Device ba03 | ||
| 23 | * Network controller: Cavium, Inc. Device bc03 | ||
| 24 | * Network controller: Cavium, Inc. Device bd03 | ||
| @@ -12861,6 +12861,15 @@ L: netdev@vger.kernel.org · 12860 unmodified lines | |||
| 12861 | S: Supported | 12861 | S: Supported |
| 12862 | F: drivers/net/ethernet/marvell/octeon_ep | 12862 | F: drivers/net/ethernet/marvell/octeon_ep |
| 12863 | 12863 | ||
| 12864 | MARVELL OCTEON ENDPOINT VF DRIVER | ||
| 12865 | M: Veerasenareddy Burru <vburru@marvell.com> | ||
| 12866 | M: Sathesh Edara <sedara@marvell.com> | ||
| 12867 | M: Shinas Rasheed <srasheed@marvell.com> | ||
| 12868 | M: Satananda Burla <sburla@marvell.com> | ||
| 12869 | L: netdev@vger.kernel.org | ||
| 12870 | S: Supported | ||
| 12871 | F: drivers/net/ethernet/marvell/octeon_ep_vf | ||
| 12872 | |||
| 12864 | MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER | 12873 | MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER |
| 12865 | M: Sunil Goutham <sgoutham@marvell.com> | 12874 | M: Sunil Goutham <sgoutham@marvell.com> |
| 12866 | M: Geetha sowjanya <gakula@marvell.com> | 12875 | M: Geetha sowjanya <gakula@marvell.com> |
| @@ -180,6 +180,7 @@ config SKY2_DEBUG · 179 unmodified lines | |||
| 180 | 180 | ||
| 181 | source "drivers/net/ethernet/marvell/octeontx2/Kconfig" | 181 | source "drivers/net/ethernet/marvell/octeontx2/Kconfig" |
| 182 | source "drivers/net/ethernet/marvell/octeon_ep/Kconfig" | 182 | source "drivers/net/ethernet/marvell/octeon_ep/Kconfig" |
| 183 | source "drivers/net/ethernet/marvell/octeon_ep_vf/Kconfig" | ||
| 183 | source "drivers/net/ethernet/marvell/prestera/Kconfig" | 184 | source "drivers/net/ethernet/marvell/prestera/Kconfig" |
| 184 | 185 | ||
| 185 | endif # NET_VENDOR_MARVELL | 186 | endif # NET_VENDOR_MARVELL |
| @@ -12,5 +12,6 @@ obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o · 11 unmodified lines | |||
| 12 | obj-$(CONFIG_SKGE) += skge.o | 12 | obj-$(CONFIG_SKGE) += skge.o |
| 13 | obj-$(CONFIG_SKY2) += sky2.o | 13 | obj-$(CONFIG_SKY2) += sky2.o |
| 14 | obj-y += octeon_ep/ | 14 | obj-y += octeon_ep/ |
| 15 | obj-y += octeon_ep_vf/ | ||
| 15 | obj-y += octeontx2/ | 16 | obj-y += octeontx2/ |
| 16 | obj-y += prestera/ | 17 | obj-y += prestera/ |
| @@ -0,0 +1,19 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | # | ||
| 3 | # Marvell's Octeon PCI Endpoint NIC VF Driver Configuration | ||
| 4 | # | ||
| 5 | |||
| 6 | config OCTEON_EP_VF | ||
| 7 | tristate "Marvell Octeon PCI Endpoint NIC VF Driver" | ||
| 8 | depends on 64BIT | ||
| 9 | depends on PCI | ||
| 10 | help | ||
| 11 | This driver supports networking functionality of Marvell's | ||
| 12 | Octeon PCI Endpoint NIC VF. | ||
| 13 | |||
| 14 | To know the list of devices supported by this driver, refer | ||
| 15 | documentation in | ||
| 16 | <file:Documentation/networking/device_drivers/ethernet/marvell/octeon_ep_vf.rst>. | ||
| 17 | |||
| 18 | To compile this drivers as a module, choose M here. Name of the | ||
| 19 | module is octeon_ep_vf. | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | # | ||
| 3 | # Network driver for Marvell's Octeon PCI Endpoint NIC VF | ||
| 4 | # | ||
| 5 | |||
| 6 | obj-$(CONFIG_OCTEON_EP_VF) += octeon_ep_vf.o | ||
| 7 | |||
| 8 | octeon_ep_vf-y := octep_vf_main.o octep_vf_cn9k.o octep_vf_cnxk.o \ | ||
| 9 | octep_vf_tx.o octep_vf_rx.o octep_vf_mbox.o \ | ||
| 10 | octep_vf_ethtool.o | ||
| @@ -0,0 +1,488 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/netdevice.h> | ||
| 10 | #include <linux/etherdevice.h> | ||
| 11 | |||
| 12 | #include "octep_vf_config.h" | ||
| 13 | #include "octep_vf_main.h" | ||
| 14 | #include "octep_vf_regs_cn9k.h" | ||
| 15 | |||
| 16 | /* Dump useful hardware IQ/OQ CSRs for debug purpose */ | ||
| 17 | static void cn93_vf_dump_q_regs(struct octep_vf_device *oct, int qno) | ||
| 18 | { | ||
| 19 | struct device *dev = &oct->pdev->dev; | ||
| 20 | |||
| 21 | dev_info(dev, "IQ-%d register dump\n", qno); | ||
| 22 | dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n", | ||
| 23 | qno, CN93_VF_SDP_R_IN_INSTR_DBELL(qno), | ||
| 24 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(qno))); | ||
| 25 | dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n", | ||
| 26 | qno, CN93_VF_SDP_R_IN_CONTROL(qno), | ||
| 27 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(qno))); | ||
| 28 | dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n", | ||
| 29 | qno, CN93_VF_SDP_R_IN_ENABLE(qno), | ||
| 30 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(qno))); | ||
| 31 | dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n", | ||
| 32 | qno, CN93_VF_SDP_R_IN_INSTR_BADDR(qno), | ||
| 33 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(qno))); | ||
| 34 | dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n", | ||
| 35 | qno, CN93_VF_SDP_R_IN_INSTR_RSIZE(qno), | ||
| 36 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(qno))); | ||
| 37 | dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n", | ||
| 38 | qno, CN93_VF_SDP_R_IN_CNTS(qno), | ||
| 39 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CNTS(qno))); | ||
| 40 | dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n", | ||
| 41 | qno, CN93_VF_SDP_R_IN_INT_LEVELS(qno), | ||
| 42 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(qno))); | ||
| 43 | dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n", | ||
| 44 | qno, CN93_VF_SDP_R_IN_PKT_CNT(qno), | ||
| 45 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_PKT_CNT(qno))); | ||
| 46 | dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n", | ||
| 47 | qno, CN93_VF_SDP_R_IN_BYTE_CNT(qno), | ||
| 48 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_BYTE_CNT(qno))); | ||
| 49 | |||
| 50 | dev_info(dev, "OQ-%d register dump\n", qno); | ||
| 51 | dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n", | ||
| 52 | qno, CN93_VF_SDP_R_OUT_SLIST_DBELL(qno), | ||
| 53 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(qno))); | ||
| 54 | dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n", | ||
| 55 | qno, CN93_VF_SDP_R_OUT_CONTROL(qno), | ||
| 56 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(qno))); | ||
| 57 | dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n", | ||
| 58 | qno, CN93_VF_SDP_R_OUT_ENABLE(qno), | ||
| 59 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(qno))); | ||
| 60 | dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n", | ||
| 61 | qno, CN93_VF_SDP_R_OUT_SLIST_BADDR(qno), | ||
| 62 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_BADDR(qno))); | ||
| 63 | dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n", | ||
| 64 | qno, CN93_VF_SDP_R_OUT_SLIST_RSIZE(qno), | ||
| 65 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_RSIZE(qno))); | ||
| 66 | dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n", | ||
| 67 | qno, CN93_VF_SDP_R_OUT_CNTS(qno), | ||
| 68 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CNTS(qno))); | ||
| 69 | dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n", | ||
| 70 | qno, CN93_VF_SDP_R_OUT_INT_LEVELS(qno), | ||
| 71 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(qno))); | ||
| 72 | dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n", | ||
| 73 | qno, CN93_VF_SDP_R_OUT_PKT_CNT(qno), | ||
| 74 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_PKT_CNT(qno))); | ||
| 75 | dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n", | ||
| 76 | qno, CN93_VF_SDP_R_OUT_BYTE_CNT(qno), | ||
| 77 | octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_BYTE_CNT(qno))); | ||
| 78 | } | ||
| 79 | |||
| 80 | /* Reset Hardware Tx queue */ | ||
| 81 | static int cn93_vf_reset_iq(struct octep_vf_device *oct, int q_no) | ||
| 82 | { | ||
| 83 | u64 val = 0ULL; | ||
| 84 | |||
| 85 | dev_dbg(&oct->pdev->dev, "Reset VF IQ-%d\n", q_no); | ||
| 86 | |||
| 87 | /* Disable the Tx/Instruction Ring */ | ||
| 88 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(q_no), val); | ||
| 89 | |||
| 90 | /* clear the Instruction Ring packet/byte counts and doorbell CSRs */ | ||
| 91 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q_no), val); | ||
| 92 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_PKT_CNT(q_no), val); | ||
| 93 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_BYTE_CNT(q_no), val); | ||
| 94 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(q_no), val); | ||
| 95 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(q_no), val); | ||
| 96 | |||
| 97 | val = 0xFFFFFFFF; | ||
| 98 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(q_no), val); | ||
| 99 | |||
| 100 | val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CNTS(q_no)); | ||
| 101 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_CNTS(q_no), val & 0xFFFFFFFF); | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* Reset Hardware Rx queue */ | ||
| 107 | static void cn93_vf_reset_oq(struct octep_vf_device *oct, int q_no) | ||
| 108 | { | ||
| 109 | u64 val = 0ULL; | ||
| 110 | |||
| 111 | /* Disable Output (Rx) Ring */ | ||
| 112 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(q_no), val); | ||
| 113 | |||
| 114 | /* Clear count CSRs */ | ||
| 115 | val = octep_vf_read_csr(oct, CN93_VF_SDP_R_OUT_CNTS(q_no)); | ||
| 116 | octep_vf_write_csr(oct, CN93_VF_SDP_R_OUT_CNTS(q_no), val); | ||
| 117 | |||
| 118 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL); | ||
| 119 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF); | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Reset all hardware Tx/Rx queues */ | ||
| 123 | static void octep_vf_reset_io_queues_cn93(struct octep_vf_device *oct) | ||
| 124 | { | ||
| 125 | struct pci_dev *pdev = oct->pdev; | ||
| 126 | int q; | ||
| 127 | |||
| 128 | dev_dbg(&pdev->dev, "Reset OCTEP_CN93 VF IO Queues\n"); | ||
| 129 | |||
| 130 | for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { | ||
| 131 | cn93_vf_reset_iq(oct, q); | ||
| 132 | cn93_vf_reset_oq(oct, q); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Initialize configuration limits and initial active config */ | ||
| 137 | static void octep_vf_init_config_cn93_vf(struct octep_vf_device *oct) | ||
| 138 | { | ||
| 139 | struct octep_vf_config *conf = oct->conf; | ||
| 140 | u64 reg_val; | ||
| 141 | |||
| 142 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(0)); | ||
| 143 | conf->ring_cfg.max_io_rings = (reg_val >> CN93_VF_R_IN_CTL_RPVF_POS) & | ||
| 144 | CN93_VF_R_IN_CTL_RPVF_MASK; | ||
| 145 | conf->ring_cfg.active_io_rings = conf->ring_cfg.max_io_rings; | ||
| 146 | |||
| 147 | conf->iq.num_descs = OCTEP_VF_IQ_MAX_DESCRIPTORS; | ||
| 148 | conf->iq.instr_type = OCTEP_VF_64BYTE_INSTR; | ||
| 149 | conf->iq.db_min = OCTEP_VF_DB_MIN; | ||
| 150 | conf->iq.intr_threshold = OCTEP_VF_IQ_INTR_THRESHOLD; | ||
| 151 | |||
| 152 | conf->oq.num_descs = OCTEP_VF_OQ_MAX_DESCRIPTORS; | ||
| 153 | conf->oq.buf_size = OCTEP_VF_OQ_BUF_SIZE; | ||
| 154 | conf->oq.refill_threshold = OCTEP_VF_OQ_REFILL_THRESHOLD; | ||
| 155 | conf->oq.oq_intr_pkt = OCTEP_VF_OQ_INTR_PKT_THRESHOLD; | ||
| 156 | conf->oq.oq_intr_time = OCTEP_VF_OQ_INTR_TIME_THRESHOLD; | ||
| 157 | |||
| 158 | conf->msix_cfg.ioq_msix = conf->ring_cfg.active_io_rings; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* Setup registers for a hardware Tx Queue */ | ||
| 162 | static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no) | ||
| 163 | { | ||
| 164 | struct octep_vf_iq *iq = oct->iq[iq_no]; | ||
| 165 | u32 reset_instr_cnt; | ||
| 166 | u64 reg_val; | ||
| 167 | |||
| 168 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no)); | ||
| 169 | |||
| 170 | /* wait for IDLE to set to 1 */ | ||
| 171 | if (!(reg_val & CN93_VF_R_IN_CTL_IDLE)) { | ||
| 172 | do { | ||
| 173 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no)); | ||
| 174 | } while (!(reg_val & CN93_VF_R_IN_CTL_IDLE)); | ||
| 175 | } | ||
| 176 | reg_val |= CN93_VF_R_IN_CTL_RDSIZE; | ||
| 177 | reg_val |= CN93_VF_R_IN_CTL_IS_64B; | ||
| 178 | reg_val |= CN93_VF_R_IN_CTL_ESR; | ||
| 179 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_CONTROL(iq_no), reg_val); | ||
| 180 | |||
| 181 | /* Write the start of the input queue's ring and its size */ | ||
| 182 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_BADDR(iq_no), iq->desc_ring_dma); | ||
| 183 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_RSIZE(iq_no), iq->max_count); | ||
| 184 | |||
| 185 | /* Remember the doorbell & instruction count register addr for this queue */ | ||
| 186 | iq->doorbell_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no); | ||
| 187 | iq->inst_cnt_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_CNTS(iq_no); | ||
| 188 | iq->intr_lvl_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_IN_INT_LEVELS(iq_no); | ||
| 189 | |||
| 190 | /* Store the current instruction counter (used in flush_iq calculation) */ | ||
| 191 | reset_instr_cnt = readl(iq->inst_cnt_reg); | ||
| 192 | writel(reset_instr_cnt, iq->inst_cnt_reg); | ||
| 193 | |||
| 194 | /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */ | ||
| 195 | reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff; | ||
| 196 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); | ||
| 197 | } | ||
| 198 | |||
| 199 | /* Setup registers for a hardware Rx Queue */ | ||
| 200 | static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no) | ||
| 201 | { | ||
| 202 | struct octep_vf_oq *oq = oct->oq[oq_no]; | ||
| 203 | u32 time_threshold = 0; | ||
| 204 | u64 oq_ctl = 0ULL; | ||
| 205 | u64 reg_val; | ||
| 206 | |||
| 207 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no)); | ||
| 208 | |||
| 209 | /* wait for IDLE to set to 1 */ | ||
| 210 | if (!(reg_val & CN93_VF_R_OUT_CTL_IDLE)) { | ||
| 211 | do { | ||
| 212 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no)); | ||
| 213 | } while (!(reg_val & CN93_VF_R_OUT_CTL_IDLE)); | ||
| 214 | } | ||
| 215 | |||
| 216 | reg_val &= ~(CN93_VF_R_OUT_CTL_IMODE); | ||
| 217 | reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_P); | ||
| 218 | reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_P); | ||
| 219 | reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_I); | ||
| 220 | reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_I); | ||
| 221 | reg_val &= ~(CN93_VF_R_OUT_CTL_ES_I); | ||
| 222 | reg_val &= ~(CN93_VF_R_OUT_CTL_ROR_D); | ||
| 223 | reg_val &= ~(CN93_VF_R_OUT_CTL_NSR_D); | ||
| 224 | reg_val &= ~(CN93_VF_R_OUT_CTL_ES_D); | ||
| 225 | reg_val |= (CN93_VF_R_OUT_CTL_ES_P); | ||
| 226 | |||
| 227 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); | ||
| 228 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); | ||
| 229 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); | ||
| 230 | |||
| 231 | oq_ctl = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no)); | ||
| 232 | oq_ctl &= ~0x7fffffULL; //clear the ISIZE and BSIZE (22-0) | ||
| 233 | oq_ctl |= (oq->buffer_size & 0xffff); //populate the BSIZE (15-0) | ||
| 234 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_CONTROL(oq_no), oq_ctl); | ||
| 235 | |||
| 236 | /* Get the mapped address of the pkt_sent and pkts_credit regs */ | ||
| 237 | oq->pkts_sent_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_OUT_CNTS(oq_no); | ||
| 238 | oq->pkts_credit_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_OUT_SLIST_DBELL(oq_no); | ||
| 239 | |||
| 240 | time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); | ||
| 241 | reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); | ||
| 242 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); | ||
| 243 | } | ||
| 244 | |||
| 245 | /* Setup registers for a VF mailbox */ | ||
| 246 | static void octep_vf_setup_mbox_regs_cn93(struct octep_vf_device *oct, int q_no) | ||
| 247 | { | ||
| 248 | struct octep_vf_mbox *mbox = oct->mbox; | ||
| 249 | |||
| 250 | /* PF to VF DATA reg. VF reads from this reg */ | ||
| 251 | mbox->mbox_read_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_PF_VF_DATA(q_no); | ||
| 252 | |||
| 253 | /* VF mbox interrupt reg */ | ||
| 254 | mbox->mbox_int_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_PF_VF_INT(q_no); | ||
| 255 | |||
| 256 | /* VF to PF DATA reg. VF writes into this reg */ | ||
| 257 | mbox->mbox_write_reg = oct->mmio.hw_addr + CN93_VF_SDP_R_MBOX_VF_PF_DATA(q_no); | ||
| 258 | } | ||
| 259 | |||
| 260 | /* Mailbox Interrupt handler */ | ||
| 261 | static void cn93_handle_vf_mbox_intr(struct octep_vf_device *oct) | ||
| 262 | { | ||
| 263 | if (oct->mbox) | ||
| 264 | schedule_work(&oct->mbox->wk.work); | ||
| 265 | else | ||
| 266 | dev_err(&oct->pdev->dev, "cannot schedule work on invalid mbox\n"); | ||
| 267 | } | ||
| 268 | |||
| 269 | /* Tx/Rx queue interrupt handler */ | ||
| 270 | static irqreturn_t octep_vf_ioq_intr_handler_cn93(void *data) | ||
| 271 | { | ||
| 272 | struct octep_vf_ioq_vector *vector = (struct octep_vf_ioq_vector *)data; | ||
| 273 | struct octep_vf_oq *oq = vector->oq; | ||
| 274 | struct octep_vf_device *oct = vector->octep_vf_dev; | ||
| 275 | u64 reg_val = 0ULL; | ||
| 276 | |||
| 277 | /* Mailbox interrupt arrives along with interrupt of tx/rx ring pair 0 */ | ||
| 278 | if (oq->q_no == 0) { | ||
| 279 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0)); | ||
| 280 | if (reg_val & CN93_VF_SDP_R_MBOX_PF_VF_INT_STATUS) { | ||
| 281 | cn93_handle_vf_mbox_intr(oct); | ||
| 282 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), reg_val); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | napi_schedule_irqoff(oq->napi); | ||
| 286 | return IRQ_HANDLED; | ||
| 287 | } | ||
| 288 | |||
| 289 | /* Re-initialize Octeon hardware registers */ | ||
| 290 | static void octep_vf_reinit_regs_cn93(struct octep_vf_device *oct) | ||
| 291 | { | ||
| 292 | u32 i; | ||
| 293 | |||
| 294 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) | ||
| 295 | oct->hw_ops.setup_iq_regs(oct, i); | ||
| 296 | |||
| 297 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) | ||
| 298 | oct->hw_ops.setup_oq_regs(oct, i); | ||
| 299 | |||
| 300 | oct->hw_ops.enable_interrupts(oct); | ||
| 301 | oct->hw_ops.enable_io_queues(oct); | ||
| 302 | |||
| 303 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) | ||
| 304 | writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); | ||
| 305 | } | ||
| 306 | |||
| 307 | /* Enable all interrupts */ | ||
| 308 | static void octep_vf_enable_interrupts_cn93(struct octep_vf_device *oct) | ||
| 309 | { | ||
| 310 | int num_rings, q; | ||
| 311 | u64 reg_val; | ||
| 312 | |||
| 313 | num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 314 | for (q = 0; q < num_rings; q++) { | ||
| 315 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q)); | ||
| 316 | reg_val |= (0x1ULL << 62); | ||
| 317 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q), reg_val); | ||
| 318 | |||
| 319 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q)); | ||
| 320 | reg_val |= (0x1ULL << 62); | ||
| 321 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); | ||
| 322 | } | ||
| 323 | /* Enable PF to VF mbox interrupt by setting 2nd bit*/ | ||
| 324 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), | ||
| 325 | CN93_VF_SDP_R_MBOX_PF_VF_INT_ENAB); | ||
| 326 | } | ||
| 327 | |||
| 328 | /* Disable all interrupts */ | ||
| 329 | static void octep_vf_disable_interrupts_cn93(struct octep_vf_device *oct) | ||
| 330 | { | ||
| 331 | int num_rings, q; | ||
| 332 | u64 reg_val; | ||
| 333 | |||
| 334 | /* Disable PF to VF mbox interrupt by setting 2nd bit*/ | ||
| 335 | if (oct->mbox) | ||
| 336 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_MBOX_PF_VF_INT(0), 0x0); | ||
| 337 | |||
| 338 | num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 339 | for (q = 0; q < num_rings; q++) { | ||
| 340 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q)); | ||
| 341 | reg_val &= ~(0x1ULL << 62); | ||
| 342 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(q), reg_val); | ||
| 343 | |||
| 344 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q)); | ||
| 345 | reg_val &= ~(0x1ULL << 62); | ||
| 346 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | /* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ | ||
| 351 | static u32 octep_vf_update_iq_read_index_cn93(struct octep_vf_iq *iq) | ||
| 352 | { | ||
| 353 | u32 pkt_in_done = readl(iq->inst_cnt_reg); | ||
| 354 | u32 last_done, new_idx; | ||
| 355 | |||
| 356 | last_done = pkt_in_done - iq->pkt_in_done; | ||
| 357 | iq->pkt_in_done = pkt_in_done; | ||
| 358 | |||
| 359 | new_idx = (iq->octep_vf_read_index + last_done) % iq->max_count; | ||
| 360 | |||
| 361 | return new_idx; | ||
| 362 | } | ||
| 363 | |||
| 364 | /* Enable a hardware Tx Queue */ | ||
| 365 | static void octep_vf_enable_iq_cn93(struct octep_vf_device *oct, int iq_no) | ||
| 366 | { | ||
| 367 | u64 loop = HZ; | ||
| 368 | u64 reg_val; | ||
| 369 | |||
| 370 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF); | ||
| 371 | |||
| 372 | while (octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INSTR_DBELL(iq_no)) && | ||
| 373 | loop--) { | ||
| 374 | schedule_timeout_interruptible(1); | ||
| 375 | } | ||
| 376 | |||
| 377 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no)); | ||
| 378 | reg_val |= (0x1ULL << 62); | ||
| 379 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); | ||
| 380 | |||
| 381 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no)); | ||
| 382 | reg_val |= 0x1ULL; | ||
| 383 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no), reg_val); | ||
| 384 | } | ||
| 385 | |||
| 386 | /* Enable a hardware Rx Queue */ | ||
| 387 | static void octep_vf_enable_oq_cn93(struct octep_vf_device *oct, int oq_no) | ||
| 388 | { | ||
| 389 | u64 reg_val = 0ULL; | ||
| 390 | |||
| 391 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no)); | ||
| 392 | reg_val |= (0x1ULL << 62); | ||
| 393 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); | ||
| 394 | |||
| 395 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF); | ||
| 396 | |||
| 397 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no)); | ||
| 398 | reg_val |= 0x1ULL; | ||
| 399 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); | ||
| 400 | } | ||
| 401 | |||
| 402 | /* Enable all hardware Tx/Rx Queues assigned to VF */ | ||
| 403 | static void octep_vf_enable_io_queues_cn93(struct octep_vf_device *oct) | ||
| 404 | { | ||
| 405 | u8 q; | ||
| 406 | |||
| 407 | for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { | ||
| 408 | octep_vf_enable_iq_cn93(oct, q); | ||
| 409 | octep_vf_enable_oq_cn93(oct, q); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | /* Disable a hardware Tx Queue assigned to VF */ | ||
| 414 | static void octep_vf_disable_iq_cn93(struct octep_vf_device *oct, int iq_no) | ||
| 415 | { | ||
| 416 | u64 reg_val = 0ULL; | ||
| 417 | |||
| 418 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no)); | ||
| 419 | reg_val &= ~0x1ULL; | ||
| 420 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_IN_ENABLE(iq_no), reg_val); | ||
| 421 | } | ||
| 422 | |||
| 423 | /* Disable a hardware Rx Queue assigned to VF */ | ||
| 424 | static void octep_vf_disable_oq_cn93(struct octep_vf_device *oct, int oq_no) | ||
| 425 | { | ||
| 426 | u64 reg_val = 0ULL; | ||
| 427 | |||
| 428 | reg_val = octep_vf_read_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no)); | ||
| 429 | reg_val &= ~0x1ULL; | ||
| 430 | octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); | ||
| 431 | } | ||
| 432 | |||
| 433 | /* Disable all hardware Tx/Rx Queues assigned to VF */ | ||
| 434 | static void octep_vf_disable_io_queues_cn93(struct octep_vf_device *oct) | ||
| 435 | { | ||
| 436 | int q = 0; | ||
| 437 | |||
| 438 | for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { | ||
| 439 | octep_vf_disable_iq_cn93(oct, q); | ||
| 440 | octep_vf_disable_oq_cn93(oct, q); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | /* Dump hardware registers (including Tx/Rx queues) for debugging. */ | ||
| 445 | static void octep_vf_dump_registers_cn93(struct octep_vf_device *oct) | ||
| 446 | { | ||
| 447 | u8 num_rings, q; | ||
| 448 | |||
| 449 | num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 450 | for (q = 0; q < num_rings; q++) | ||
| 451 | cn93_vf_dump_q_regs(oct, q); | ||
| 452 | } | ||
| 453 | |||
| 454 | /** | ||
| 455 | * octep_vf_device_setup_cn93() - Setup Octeon device. | ||
| 456 | * | ||
| 457 | * @oct: Octeon device private data structure. | ||
| 458 | * | ||
| 459 | * - initialize hardware operations. | ||
| 460 | * - get target side pcie port number for the device. | ||
| 461 | * - set initial configuration and max limits. | ||
| 462 | */ | ||
| 463 | void octep_vf_device_setup_cn93(struct octep_vf_device *oct) | ||
| 464 | { | ||
| 465 | oct->hw_ops.setup_iq_regs = octep_vf_setup_iq_regs_cn93; | ||
| 466 | oct->hw_ops.setup_oq_regs = octep_vf_setup_oq_regs_cn93; | ||
| 467 | oct->hw_ops.setup_mbox_regs = octep_vf_setup_mbox_regs_cn93; | ||
| 468 | |||
| 469 | oct->hw_ops.ioq_intr_handler = octep_vf_ioq_intr_handler_cn93; | ||
| 470 | oct->hw_ops.reinit_regs = octep_vf_reinit_regs_cn93; | ||
| 471 | |||
| 472 | oct->hw_ops.enable_interrupts = octep_vf_enable_interrupts_cn93; | ||
| 473 | oct->hw_ops.disable_interrupts = octep_vf_disable_interrupts_cn93; | ||
| 474 | |||
| 475 | oct->hw_ops.update_iq_read_idx = octep_vf_update_iq_read_index_cn93; | ||
| 476 | |||
| 477 | oct->hw_ops.enable_iq = octep_vf_enable_iq_cn93; | ||
| 478 | oct->hw_ops.enable_oq = octep_vf_enable_oq_cn93; | ||
| 479 | oct->hw_ops.enable_io_queues = octep_vf_enable_io_queues_cn93; | ||
| 480 | |||
| 481 | oct->hw_ops.disable_iq = octep_vf_disable_iq_cn93; | ||
| 482 | oct->hw_ops.disable_oq = octep_vf_disable_oq_cn93; | ||
| 483 | oct->hw_ops.disable_io_queues = octep_vf_disable_io_queues_cn93; | ||
| 484 | oct->hw_ops.reset_io_queues = octep_vf_reset_io_queues_cn93; | ||
| 485 | |||
| 486 | oct->hw_ops.dump_registers = octep_vf_dump_registers_cn93; | ||
| 487 | octep_vf_init_config_cn93_vf(oct); | ||
| 488 | } | ||
| @@ -0,0 +1,500 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/netdevice.h> | ||
| 10 | #include <linux/etherdevice.h> | ||
| 11 | |||
| 12 | #include "octep_vf_config.h" | ||
| 13 | #include "octep_vf_main.h" | ||
| 14 | #include "octep_vf_regs_cnxk.h" | ||
| 15 | |||
| 16 | /* Dump useful hardware IQ/OQ CSRs for debug purpose */ | ||
| 17 | static void cnxk_vf_dump_q_regs(struct octep_vf_device *oct, int qno) | ||
| 18 | { | ||
| 19 | struct device *dev = &oct->pdev->dev; | ||
| 20 | |||
| 21 | dev_info(dev, "IQ-%d register dump\n", qno); | ||
| 22 | dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n", | ||
| 23 | qno, CNXK_VF_SDP_R_IN_INSTR_DBELL(qno), | ||
| 24 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(qno))); | ||
| 25 | dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n", | ||
| 26 | qno, CNXK_VF_SDP_R_IN_CONTROL(qno), | ||
| 27 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(qno))); | ||
| 28 | dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n", | ||
| 29 | qno, CNXK_VF_SDP_R_IN_ENABLE(qno), | ||
| 30 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(qno))); | ||
| 31 | dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n", | ||
| 32 | qno, CNXK_VF_SDP_R_IN_INSTR_BADDR(qno), | ||
| 33 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(qno))); | ||
| 34 | dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n", | ||
| 35 | qno, CNXK_VF_SDP_R_IN_INSTR_RSIZE(qno), | ||
| 36 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(qno))); | ||
| 37 | dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n", | ||
| 38 | qno, CNXK_VF_SDP_R_IN_CNTS(qno), | ||
| 39 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(qno))); | ||
| 40 | dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n", | ||
| 41 | qno, CNXK_VF_SDP_R_IN_INT_LEVELS(qno), | ||
| 42 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(qno))); | ||
| 43 | dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n", | ||
| 44 | qno, CNXK_VF_SDP_R_IN_PKT_CNT(qno), | ||
| 45 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_PKT_CNT(qno))); | ||
| 46 | dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n", | ||
| 47 | qno, CNXK_VF_SDP_R_IN_BYTE_CNT(qno), | ||
| 48 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_BYTE_CNT(qno))); | ||
| 49 | |||
| 50 | dev_info(dev, "OQ-%d register dump\n", qno); | ||
| 51 | dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n", | ||
| 52 | qno, CNXK_VF_SDP_R_OUT_SLIST_DBELL(qno), | ||
| 53 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(qno))); | ||
| 54 | dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n", | ||
| 55 | qno, CNXK_VF_SDP_R_OUT_CONTROL(qno), | ||
| 56 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(qno))); | ||
| 57 | dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n", | ||
| 58 | qno, CNXK_VF_SDP_R_OUT_ENABLE(qno), | ||
| 59 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(qno))); | ||
| 60 | dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n", | ||
| 61 | qno, CNXK_VF_SDP_R_OUT_SLIST_BADDR(qno), | ||
| 62 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(qno))); | ||
| 63 | dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n", | ||
| 64 | qno, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(qno), | ||
| 65 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(qno))); | ||
| 66 | dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n", | ||
| 67 | qno, CNXK_VF_SDP_R_OUT_CNTS(qno), | ||
| 68 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CNTS(qno))); | ||
| 69 | dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n", | ||
| 70 | qno, CNXK_VF_SDP_R_OUT_INT_LEVELS(qno), | ||
| 71 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(qno))); | ||
| 72 | dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n", | ||
| 73 | qno, CNXK_VF_SDP_R_OUT_PKT_CNT(qno), | ||
| 74 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_PKT_CNT(qno))); | ||
| 75 | dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n", | ||
| 76 | qno, CNXK_VF_SDP_R_OUT_BYTE_CNT(qno), | ||
| 77 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_BYTE_CNT(qno))); | ||
| 78 | dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n", | ||
| 79 | qno, CNXK_VF_SDP_R_ERR_TYPE(qno), | ||
| 80 | octep_vf_read_csr64(oct, CNXK_VF_SDP_R_ERR_TYPE(qno))); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* Reset Hardware Tx queue */ | ||
| 84 | static int cnxk_vf_reset_iq(struct octep_vf_device *oct, int q_no) | ||
| 85 | { | ||
| 86 | u64 val = 0ULL; | ||
| 87 | |||
| 88 | dev_dbg(&oct->pdev->dev, "Reset VF IQ-%d\n", q_no); | ||
| 89 | |||
| 90 | /* Disable the Tx/Instruction Ring */ | ||
| 91 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(q_no), val); | ||
| 92 | |||
| 93 | /* clear the Instruction Ring packet/byte counts and doorbell CSRs */ | ||
| 94 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q_no), val); | ||
| 95 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_PKT_CNT(q_no), val); | ||
| 96 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_BYTE_CNT(q_no), val); | ||
| 97 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(q_no), val); | ||
| 98 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(q_no), val); | ||
| 99 | |||
| 100 | val = 0xFFFFFFFF; | ||
| 101 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(q_no), val); | ||
| 102 | |||
| 103 | val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(q_no)); | ||
| 104 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_CNTS(q_no), val & 0xFFFFFFFF); | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Reset Hardware Rx queue */ | ||
| 110 | static void cnxk_vf_reset_oq(struct octep_vf_device *oct, int q_no) | ||
| 111 | { | ||
| 112 | u64 val = 0ULL; | ||
| 113 | |||
| 114 | /* Disable Output (Rx) Ring */ | ||
| 115 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(q_no), val); | ||
| 116 | |||
| 117 | /* Clear count CSRs */ | ||
| 118 | val = octep_vf_read_csr(oct, CNXK_VF_SDP_R_OUT_CNTS(q_no)); | ||
| 119 | octep_vf_write_csr(oct, CNXK_VF_SDP_R_OUT_CNTS(q_no), val); | ||
| 120 | |||
| 121 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL); | ||
| 122 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF); | ||
| 123 | } | ||
| 124 | |||
| 125 | /* Reset all hardware Tx/Rx queues */ | ||
| 126 | static void octep_vf_reset_io_queues_cnxk(struct octep_vf_device *oct) | ||
| 127 | { | ||
| 128 | struct pci_dev *pdev = oct->pdev; | ||
| 129 | int q; | ||
| 130 | |||
| 131 | dev_dbg(&pdev->dev, "Reset OCTEP_CNXK VF IO Queues\n"); | ||
| 132 | |||
| 133 | for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { | ||
| 134 | cnxk_vf_reset_iq(oct, q); | ||
| 135 | cnxk_vf_reset_oq(oct, q); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /* Initialize configuration limits and initial active config */ | ||
| 140 | static void octep_vf_init_config_cnxk_vf(struct octep_vf_device *oct) | ||
| 141 | { | ||
| 142 | struct octep_vf_config *conf = oct->conf; | ||
| 143 | u64 reg_val; | ||
| 144 | |||
| 145 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(0)); | ||
| 146 | conf->ring_cfg.max_io_rings = (reg_val >> CNXK_VF_R_IN_CTL_RPVF_POS) & | ||
| 147 | CNXK_VF_R_IN_CTL_RPVF_MASK; | ||
| 148 | conf->ring_cfg.active_io_rings = conf->ring_cfg.max_io_rings; | ||
| 149 | |||
| 150 | conf->iq.num_descs = OCTEP_VF_IQ_MAX_DESCRIPTORS; | ||
| 151 | conf->iq.instr_type = OCTEP_VF_64BYTE_INSTR; | ||
| 152 | conf->iq.db_min = OCTEP_VF_DB_MIN; | ||
| 153 | conf->iq.intr_threshold = OCTEP_VF_IQ_INTR_THRESHOLD; | ||
| 154 | |||
| 155 | conf->oq.num_descs = OCTEP_VF_OQ_MAX_DESCRIPTORS; | ||
| 156 | conf->oq.buf_size = OCTEP_VF_OQ_BUF_SIZE; | ||
| 157 | conf->oq.refill_threshold = OCTEP_VF_OQ_REFILL_THRESHOLD; | ||
| 158 | conf->oq.oq_intr_pkt = OCTEP_VF_OQ_INTR_PKT_THRESHOLD; | ||
| 159 | conf->oq.oq_intr_time = OCTEP_VF_OQ_INTR_TIME_THRESHOLD; | ||
| 160 | conf->oq.wmark = OCTEP_VF_OQ_WMARK_MIN; | ||
| 161 | |||
| 162 | conf->msix_cfg.ioq_msix = conf->ring_cfg.active_io_rings; | ||
| 163 | } | ||
| 164 | |||
| 165 | /* Setup registers for a hardware Tx Queue */ | ||
| 166 | static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no) | ||
| 167 | { | ||
| 168 | struct octep_vf_iq *iq = oct->iq[iq_no]; | ||
| 169 | u32 reset_instr_cnt; | ||
| 170 | u64 reg_val; | ||
| 171 | |||
| 172 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no)); | ||
| 173 | |||
| 174 | /* wait for IDLE to set to 1 */ | ||
| 175 | if (!(reg_val & CNXK_VF_R_IN_CTL_IDLE)) { | ||
| 176 | do { | ||
| 177 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no)); | ||
| 178 | } while (!(reg_val & CNXK_VF_R_IN_CTL_IDLE)); | ||
| 179 | } | ||
| 180 | reg_val |= CNXK_VF_R_IN_CTL_RDSIZE; | ||
| 181 | reg_val |= CNXK_VF_R_IN_CTL_IS_64B; | ||
| 182 | reg_val |= CNXK_VF_R_IN_CTL_ESR; | ||
| 183 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_CONTROL(iq_no), reg_val); | ||
| 184 | |||
| 185 | /* Write the start of the input queue's ring and its size */ | ||
| 186 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_BADDR(iq_no), iq->desc_ring_dma); | ||
| 187 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_RSIZE(iq_no), iq->max_count); | ||
| 188 | |||
| 189 | /* Remember the doorbell & instruction count register addr for this queue */ | ||
| 190 | iq->doorbell_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no); | ||
| 191 | iq->inst_cnt_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_CNTS(iq_no); | ||
| 192 | iq->intr_lvl_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no); | ||
| 193 | |||
| 194 | /* Store the current instruction counter (used in flush_iq calculation) */ | ||
| 195 | reset_instr_cnt = readl(iq->inst_cnt_reg); | ||
| 196 | writel(reset_instr_cnt, iq->inst_cnt_reg); | ||
| 197 | |||
| 198 | /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */ | ||
| 199 | reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff; | ||
| 200 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* Setup registers for a hardware Rx Queue */ | ||
| 204 | static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no) | ||
| 205 | { | ||
| 206 | struct octep_vf_oq *oq = oct->oq[oq_no]; | ||
| 207 | u32 time_threshold = 0; | ||
| 208 | u64 oq_ctl = 0ULL; | ||
| 209 | u64 reg_val; | ||
| 210 | |||
| 211 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); | ||
| 212 | |||
| 213 | /* wait for IDLE to set to 1 */ | ||
| 214 | if (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)) { | ||
| 215 | do { | ||
| 216 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); | ||
| 217 | } while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE)); | ||
| 218 | } | ||
| 219 | |||
| 220 | reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE); | ||
| 221 | reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P); | ||
| 222 | reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_P); | ||
| 223 | reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_I); | ||
| 224 | reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_I); | ||
| 225 | reg_val &= ~(CNXK_VF_R_OUT_CTL_ES_I); | ||
| 226 | reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_D); | ||
| 227 | reg_val &= ~(CNXK_VF_R_OUT_CTL_NSR_D); | ||
| 228 | reg_val &= ~(CNXK_VF_R_OUT_CTL_ES_D); | ||
| 229 | reg_val |= (CNXK_VF_R_OUT_CTL_ES_P); | ||
| 230 | |||
| 231 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val); | ||
| 232 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma); | ||
| 233 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count); | ||
| 234 | |||
| 235 | oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no)); | ||
| 236 | /* Clear the ISIZE and BSIZE (22-0) */ | ||
| 237 | oq_ctl &= ~0x7fffffULL; | ||
| 238 | /* Populate the BSIZE (15-0) */ | ||
| 239 | oq_ctl |= (oq->buffer_size & 0xffff); | ||
| 240 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), oq_ctl); | ||
| 241 | |||
| 242 | /* Get the mapped address of the pkt_sent and pkts_credit regs */ | ||
| 243 | oq->pkts_sent_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_OUT_CNTS(oq_no); | ||
| 244 | oq->pkts_credit_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_OUT_SLIST_DBELL(oq_no); | ||
| 245 | |||
| 246 | time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf); | ||
| 247 | reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf); | ||
| 248 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); | ||
| 249 | |||
| 250 | /* set watermark for backpressure */ | ||
| 251 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no)); | ||
| 252 | reg_val &= ~0xFFFFFFFFULL; | ||
| 253 | reg_val |= CFG_GET_OQ_WMARK(oct->conf); | ||
| 254 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val); | ||
| 255 | } | ||
| 256 | |||
| 257 | /* Setup registers for a VF mailbox */ | ||
| 258 | static void octep_vf_setup_mbox_regs_cnxk(struct octep_vf_device *oct, int q_no) | ||
| 259 | { | ||
| 260 | struct octep_vf_mbox *mbox = oct->mbox; | ||
| 261 | |||
| 262 | /* PF to VF DATA reg. VF reads from this reg */ | ||
| 263 | mbox->mbox_read_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_PF_VF_DATA(q_no); | ||
| 264 | |||
| 265 | /* VF mbox interrupt reg */ | ||
| 266 | mbox->mbox_int_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_PF_VF_INT(q_no); | ||
| 267 | |||
| 268 | /* VF to PF DATA reg. VF writes into this reg */ | ||
| 269 | mbox->mbox_write_reg = oct->mmio.hw_addr + CNXK_VF_SDP_R_MBOX_VF_PF_DATA(q_no); | ||
| 270 | } | ||
| 271 | |||
| 272 | /* Mailbox Interrupt handler */ | ||
| 273 | static void cnxk_handle_vf_mbox_intr(struct octep_vf_device *oct) | ||
| 274 | { | ||
| 275 | if (oct->mbox) | ||
| 276 | schedule_work(&oct->mbox->wk.work); | ||
| 277 | else | ||
| 278 | dev_err(&oct->pdev->dev, "cannot schedule work on invalid mbox\n"); | ||
| 279 | } | ||
| 280 | |||
| 281 | /* Tx/Rx queue interrupt handler */ | ||
| 282 | static irqreturn_t octep_vf_ioq_intr_handler_cnxk(void *data) | ||
| 283 | { | ||
| 284 | struct octep_vf_ioq_vector *vector = (struct octep_vf_ioq_vector *)data; | ||
| 285 | struct octep_vf_oq *oq = vector->oq; | ||
| 286 | struct octep_vf_device *oct = vector->octep_vf_dev; | ||
| 287 | u64 reg_val = 0ULL; | ||
| 288 | |||
| 289 | /* Mailbox interrupt arrives along with interrupt of tx/rx ring pair 0 */ | ||
| 290 | if (oq->q_no == 0) { | ||
| 291 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0)); | ||
| 292 | if (reg_val & CNXK_VF_SDP_R_MBOX_PF_VF_INT_STATUS) { | ||
| 293 | cnxk_handle_vf_mbox_intr(oct); | ||
| 294 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), reg_val); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | napi_schedule_irqoff(oq->napi); | ||
| 298 | return IRQ_HANDLED; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* Re-initialize Octeon hardware registers */ | ||
| 302 | static void octep_vf_reinit_regs_cnxk(struct octep_vf_device *oct) | ||
| 303 | { | ||
| 304 | u32 i; | ||
| 305 | |||
| 306 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) | ||
| 307 | oct->hw_ops.setup_iq_regs(oct, i); | ||
| 308 | |||
| 309 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) | ||
| 310 | oct->hw_ops.setup_oq_regs(oct, i); | ||
| 311 | |||
| 312 | oct->hw_ops.enable_interrupts(oct); | ||
| 313 | oct->hw_ops.enable_io_queues(oct); | ||
| 314 | |||
| 315 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) | ||
| 316 | writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); | ||
| 317 | } | ||
| 318 | |||
| 319 | /* Enable all interrupts */ | ||
| 320 | static void octep_vf_enable_interrupts_cnxk(struct octep_vf_device *oct) | ||
| 321 | { | ||
| 322 | int num_rings, q; | ||
| 323 | u64 reg_val; | ||
| 324 | |||
| 325 | num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 326 | for (q = 0; q < num_rings; q++) { | ||
| 327 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q)); | ||
| 328 | reg_val |= (0x1ULL << 62); | ||
| 329 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q), reg_val); | ||
| 330 | |||
| 331 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q)); | ||
| 332 | reg_val |= (0x1ULL << 62); | ||
| 333 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); | ||
| 334 | } | ||
| 335 | /* Enable PF to VF mbox interrupt by setting 2nd bit*/ | ||
| 336 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), | ||
| 337 | CNXK_VF_SDP_R_MBOX_PF_VF_INT_ENAB); | ||
| 338 | } | ||
| 339 | |||
| 340 | /* Disable all interrupts */ | ||
| 341 | static void octep_vf_disable_interrupts_cnxk(struct octep_vf_device *oct) | ||
| 342 | { | ||
| 343 | int num_rings, q; | ||
| 344 | u64 reg_val; | ||
| 345 | |||
| 346 | /* Disable PF to VF mbox interrupt by setting 2nd bit*/ | ||
| 347 | if (oct->mbox) | ||
| 348 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_MBOX_PF_VF_INT(0), 0x0); | ||
| 349 | |||
| 350 | num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 351 | for (q = 0; q < num_rings; q++) { | ||
| 352 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q)); | ||
| 353 | reg_val &= ~(0x1ULL << 62); | ||
| 354 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(q), reg_val); | ||
| 355 | |||
| 356 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q)); | ||
| 357 | reg_val &= ~(0x1ULL << 62); | ||
| 358 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(q), reg_val); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | /* Get new Octeon Read Index: index of descriptor that Octeon reads next. */ | ||
| 363 | static u32 octep_vf_update_iq_read_index_cnxk(struct octep_vf_iq *iq) | ||
| 364 | { | ||
| 365 | u32 pkt_in_done = readl(iq->inst_cnt_reg); | ||
| 366 | u32 last_done, new_idx; | ||
| 367 | |||
| 368 | last_done = pkt_in_done - iq->pkt_in_done; | ||
| 369 | iq->pkt_in_done = pkt_in_done; | ||
| 370 | |||
| 371 | new_idx = (iq->octep_vf_read_index + last_done) % iq->max_count; | ||
| 372 | |||
| 373 | return new_idx; | ||
| 374 | } | ||
| 375 | |||
| 376 | /* Enable a hardware Tx Queue */ | ||
| 377 | static void octep_vf_enable_iq_cnxk(struct octep_vf_device *oct, int iq_no) | ||
| 378 | { | ||
| 379 | u64 loop = HZ; | ||
| 380 | u64 reg_val; | ||
| 381 | |||
| 382 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF); | ||
| 383 | |||
| 384 | while (octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INSTR_DBELL(iq_no)) && | ||
| 385 | loop--) { | ||
| 386 | schedule_timeout_interruptible(1); | ||
| 387 | } | ||
| 388 | |||
| 389 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no)); | ||
| 390 | reg_val |= (0x1ULL << 62); | ||
| 391 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_INT_LEVELS(iq_no), reg_val); | ||
| 392 | |||
| 393 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no)); | ||
| 394 | reg_val |= 0x1ULL; | ||
| 395 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no), reg_val); | ||
| 396 | } | ||
| 397 | |||
| 398 | /* Enable a hardware Rx Queue */ | ||
| 399 | static void octep_vf_enable_oq_cnxk(struct octep_vf_device *oct, int oq_no) | ||
| 400 | { | ||
| 401 | u64 reg_val = 0ULL; | ||
| 402 | |||
| 403 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no)); | ||
| 404 | reg_val |= (0x1ULL << 62); | ||
| 405 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val); | ||
| 406 | |||
| 407 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF); | ||
| 408 | |||
| 409 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no)); | ||
| 410 | reg_val |= 0x1ULL; | ||
| 411 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); | ||
| 412 | } | ||
| 413 | |||
| 414 | /* Enable all hardware Tx/Rx Queues assigned to VF */ | ||
| 415 | static void octep_vf_enable_io_queues_cnxk(struct octep_vf_device *oct) | ||
| 416 | { | ||
| 417 | u8 q; | ||
| 418 | |||
| 419 | for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { | ||
| 420 | octep_vf_enable_iq_cnxk(oct, q); | ||
| 421 | octep_vf_enable_oq_cnxk(oct, q); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | /* Disable a hardware Tx Queue assigned to VF */ | ||
| 426 | static void octep_vf_disable_iq_cnxk(struct octep_vf_device *oct, int iq_no) | ||
| 427 | { | ||
| 428 | u64 reg_val = 0ULL; | ||
| 429 | |||
| 430 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no)); | ||
| 431 | reg_val &= ~0x1ULL; | ||
| 432 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_IN_ENABLE(iq_no), reg_val); | ||
| 433 | } | ||
| 434 | |||
| 435 | /* Disable a hardware Rx Queue assigned to VF */ | ||
| 436 | static void octep_vf_disable_oq_cnxk(struct octep_vf_device *oct, int oq_no) | ||
| 437 | { | ||
| 438 | u64 reg_val = 0ULL; | ||
| 439 | |||
| 440 | reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no)); | ||
| 441 | reg_val &= ~0x1ULL; | ||
| 442 | octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_ENABLE(oq_no), reg_val); | ||
| 443 | } | ||
| 444 | |||
| 445 | /* Disable all hardware Tx/Rx Queues assigned to VF */ | ||
| 446 | static void octep_vf_disable_io_queues_cnxk(struct octep_vf_device *oct) | ||
| 447 | { | ||
| 448 | int q = 0; | ||
| 449 | |||
| 450 | for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) { | ||
| 451 | octep_vf_disable_iq_cnxk(oct, q); | ||
| 452 | octep_vf_disable_oq_cnxk(oct, q); | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | /* Dump hardware registers (including Tx/Rx queues) for debugging. */ | ||
| 457 | static void octep_vf_dump_registers_cnxk(struct octep_vf_device *oct) | ||
| 458 | { | ||
| 459 | u8 num_rings, q; | ||
| 460 | |||
| 461 | num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 462 | for (q = 0; q < num_rings; q++) | ||
| 463 | cnxk_vf_dump_q_regs(oct, q); | ||
| 464 | } | ||
| 465 | |||
| 466 | /** | ||
| 467 | * octep_vf_device_setup_cnxk() - Setup Octeon device. | ||
| 468 | * | ||
| 469 | * @oct: Octeon device private data structure. | ||
| 470 | * | ||
| 471 | * - initialize hardware operations. | ||
| 472 | * - get target side pcie port number for the device. | ||
| 473 | * - set initial configuration and max limits. | ||
| 474 | */ | ||
| 475 | void octep_vf_device_setup_cnxk(struct octep_vf_device *oct) | ||
| 476 | { | ||
| 477 | oct->hw_ops.setup_iq_regs = octep_vf_setup_iq_regs_cnxk; | ||
| 478 | oct->hw_ops.setup_oq_regs = octep_vf_setup_oq_regs_cnxk; | ||
| 479 | oct->hw_ops.setup_mbox_regs = octep_vf_setup_mbox_regs_cnxk; | ||
| 480 | |||
| 481 | oct->hw_ops.ioq_intr_handler = octep_vf_ioq_intr_handler_cnxk; | ||
| 482 | oct->hw_ops.reinit_regs = octep_vf_reinit_regs_cnxk; | ||
| 483 | |||
| 484 | oct->hw_ops.enable_interrupts = octep_vf_enable_interrupts_cnxk; | ||
| 485 | oct->hw_ops.disable_interrupts = octep_vf_disable_interrupts_cnxk; | ||
| 486 | |||
| 487 | oct->hw_ops.update_iq_read_idx = octep_vf_update_iq_read_index_cnxk; | ||
| 488 | |||
| 489 | oct->hw_ops.enable_iq = octep_vf_enable_iq_cnxk; | ||
| 490 | oct->hw_ops.enable_oq = octep_vf_enable_oq_cnxk; | ||
| 491 | oct->hw_ops.enable_io_queues = octep_vf_enable_io_queues_cnxk; | ||
| 492 | |||
| 493 | oct->hw_ops.disable_iq = octep_vf_disable_iq_cnxk; | ||
| 494 | oct->hw_ops.disable_oq = octep_vf_disable_oq_cnxk; | ||
| 495 | oct->hw_ops.disable_io_queues = octep_vf_disable_io_queues_cnxk; | ||
| 496 | oct->hw_ops.reset_io_queues = octep_vf_reset_io_queues_cnxk; | ||
| 497 | |||
| 498 | oct->hw_ops.dump_registers = octep_vf_dump_registers_cnxk; | ||
| 499 | octep_vf_init_config_cnxk_vf(oct); | ||
| 500 | } | ||
| @@ -0,0 +1,160 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _OCTEP_VF_CONFIG_H_ | ||
| 9 | #define _OCTEP_VF_CONFIG_H_ | ||
| 10 | |||
| 11 | /* Tx instruction types by length */ | ||
| 12 | #define OCTEP_VF_32BYTE_INSTR 32 | ||
| 13 | #define OCTEP_VF_64BYTE_INSTR 64 | ||
| 14 | |||
| 15 | /* Tx Queue: maximum descriptors per ring */ | ||
| 16 | #define OCTEP_VF_IQ_MAX_DESCRIPTORS 1024 | ||
| 17 | /* Minimum input (Tx) requests to be enqueued to ring doorbell */ | ||
| 18 | #define OCTEP_VF_DB_MIN 8 | ||
| 19 | /* Packet threshold for Tx queue interrupt */ | ||
| 20 | #define OCTEP_VF_IQ_INTR_THRESHOLD 0x0 | ||
| 21 | |||
| 22 | /* Minimum watermark for backpressure */ | ||
| 23 | #define OCTEP_VF_OQ_WMARK_MIN 256 | ||
| 24 | |||
| 25 | /* Rx Queue: maximum descriptors per ring */ | ||
| 26 | #define OCTEP_VF_OQ_MAX_DESCRIPTORS 1024 | ||
| 27 | |||
| 28 | /* Rx buffer size: Use page size buffers. | ||
| 29 | * Build skb from allocated page buffer once the packet is received. | ||
| 30 | * When a gathered packet is received, make head page as skb head and | ||
| 31 | * page buffers in consecutive Rx descriptors as fragments. | ||
| 32 | */ | ||
| 33 | #define OCTEP_VF_OQ_BUF_SIZE (SKB_WITH_OVERHEAD(PAGE_SIZE)) | ||
| 34 | #define OCTEP_VF_OQ_PKTS_PER_INTR 128 | ||
| 35 | #define OCTEP_VF_OQ_REFILL_THRESHOLD (OCTEP_VF_OQ_MAX_DESCRIPTORS / 4) | ||
| 36 | |||
| 37 | #define OCTEP_VF_OQ_INTR_PKT_THRESHOLD 1 | ||
| 38 | #define OCTEP_VF_OQ_INTR_TIME_THRESHOLD 10 | ||
| 39 | |||
| 40 | #define OCTEP_VF_MSIX_NAME_SIZE (IFNAMSIZ + 32) | ||
| 41 | |||
| 42 | /* Tx Queue wake threshold | ||
| 43 | * wakeup a stopped Tx queue if minimum 2 descriptors are available. | ||
| 44 | * Even a skb with fragments consume only one Tx queue descriptor entry. | ||
| 45 | */ | ||
| 46 | #define OCTEP_VF_WAKE_QUEUE_THRESHOLD 2 | ||
| 47 | |||
| 48 | /* Minimum MTU supported by Octeon network interface */ | ||
| 49 | #define OCTEP_VF_MIN_MTU ETH_MIN_MTU | ||
| 50 | /* Maximum MTU supported by Octeon interface*/ | ||
| 51 | #define OCTEP_VF_MAX_MTU (10000 - (ETH_HLEN + ETH_FCS_LEN)) | ||
| 52 | /* Default MTU */ | ||
| 53 | #define OCTEP_VF_DEFAULT_MTU 1500 | ||
| 54 | |||
| 55 | /* Macros to get octeon config params */ | ||
| 56 | #define CFG_GET_IQ_CFG(cfg) ((cfg)->iq) | ||
| 57 | #define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs) | ||
| 58 | #define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type) | ||
| 59 | #define CFG_GET_IQ_INSTR_SIZE(cfg) (64) | ||
| 60 | #define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min) | ||
| 61 | #define CFG_GET_IQ_INTR_THRESHOLD(cfg) ((cfg)->iq.intr_threshold) | ||
| 62 | |||
| 63 | #define CFG_GET_OQ_NUM_DESC(cfg) ((cfg)->oq.num_descs) | ||
| 64 | #define CFG_GET_OQ_BUF_SIZE(cfg) ((cfg)->oq.buf_size) | ||
| 65 | #define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold) | ||
| 66 | #define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt) | ||
| 67 | #define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time) | ||
| 68 | #define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark) | ||
| 69 | |||
| 70 | #define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->ring_cfg.active_io_rings) | ||
| 71 | #define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->ring_cfg.max_io_rings) | ||
| 72 | |||
| 73 | #define CFG_GET_CORE_TICS_PER_US(cfg) ((cfg)->core_cfg.core_tics_per_us) | ||
| 74 | #define CFG_GET_COPROC_TICS_PER_US(cfg) ((cfg)->core_cfg.coproc_tics_per_us) | ||
| 75 | |||
| 76 | #define CFG_GET_IOQ_MSIX(cfg) ((cfg)->msix_cfg.ioq_msix) | ||
| 77 | |||
| 78 | /* Hardware Tx Queue configuration. */ | ||
| 79 | struct octep_vf_iq_config { | ||
| 80 | /* Size of the Input queue (number of commands) */ | ||
| 81 | u16 num_descs; | ||
| 82 | |||
| 83 | /* Command size - 32 or 64 bytes */ | ||
| 84 | u16 instr_type; | ||
| 85 | |||
| 86 | /* Minimum number of commands pending to be posted to Octeon before driver | ||
| 87 | * hits the Input queue doorbell. | ||
| 88 | */ | ||
| 89 | u16 db_min; | ||
| 90 | |||
| 91 | /* Trigger the IQ interrupt when processed cmd count reaches | ||
| 92 | * this level. | ||
| 93 | */ | ||
| 94 | u32 intr_threshold; | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* Hardware Rx Queue configuration. */ | ||
| 98 | struct octep_vf_oq_config { | ||
| 99 | /* Size of Output queue (number of descriptors) */ | ||
| 100 | u16 num_descs; | ||
| 101 | |||
| 102 | /* Size of buffer in this Output queue. */ | ||
| 103 | u16 buf_size; | ||
| 104 | |||
| 105 | /* The number of buffers that were consumed during packet processing | ||
| 106 | * by the driver on this Output queue before the driver attempts to | ||
| 107 | * replenish the descriptor ring with new buffers. | ||
| 108 | */ | ||
| 109 | u16 refill_threshold; | ||
| 110 | |||
| 111 | /* Interrupt Coalescing (Packet Count). Octeon will interrupt the host | ||
| 112 | * only if it sent as many packets as specified by this field. | ||
| 113 | * The driver usually does not use packet count interrupt coalescing. | ||
| 114 | */ | ||
| 115 | u32 oq_intr_pkt; | ||
| 116 | |||
| 117 | /* Interrupt Coalescing (Time Interval). Octeon will interrupt the host | ||
| 118 | * if at least one packet was sent in the time interval specified by | ||
| 119 | * this field. The driver uses time interval interrupt coalescing by | ||
| 120 | * default. The time is specified in microseconds. | ||
| 121 | */ | ||
| 122 | u32 oq_intr_time; | ||
| 123 | |||
| 124 | /* Water mark for backpressure. | ||
| 125 | * Output queue sends backpressure signal to source when | ||
| 126 | * free buffer count falls below wmark. | ||
| 127 | */ | ||
| 128 | u32 wmark; | ||
| 129 | }; | ||
| 130 | |||
| 131 | /* Tx/Rx configuration */ | ||
| 132 | struct octep_vf_ring_config { | ||
| 133 | /* Max number of IOQs */ | ||
| 134 | u16 max_io_rings; | ||
| 135 | |||
| 136 | /* Number of active IOQs */ | ||
| 137 | u16 active_io_rings; | ||
| 138 | }; | ||
| 139 | |||
| 140 | /* Octeon MSI-x config. */ | ||
| 141 | struct octep_vf_msix_config { | ||
| 142 | /* Number of IOQ interrupts */ | ||
| 143 | u16 ioq_msix; | ||
| 144 | }; | ||
| 145 | |||
| 146 | /* Data Structure to hold configuration limits and active config */ | ||
| 147 | struct octep_vf_config { | ||
| 148 | /* Input Queue attributes. */ | ||
| 149 | struct octep_vf_iq_config iq; | ||
| 150 | |||
| 151 | /* Output Queue attributes. */ | ||
| 152 | struct octep_vf_oq_config oq; | ||
| 153 | |||
| 154 | /* MSI-X interrupt config */ | ||
| 155 | struct octep_vf_msix_config msix_cfg; | ||
| 156 | |||
| 157 | /* NIC VF ring Configuration */ | ||
| 158 | struct octep_vf_ring_config ring_cfg; | ||
| 159 | }; | ||
| 160 | #endif /* _OCTEP_VF_CONFIG_H_ */ | ||
| @@ -0,0 +1,307 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/netdevice.h> | ||
| 10 | #include <linux/ethtool.h> | ||
| 11 | |||
| 12 | #include "octep_vf_config.h" | ||
| 13 | #include "octep_vf_main.h" | ||
| 14 | |||
| 15 | static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = { | ||
| 16 | "rx_packets", | ||
| 17 | "tx_packets", | ||
| 18 | "rx_bytes", | ||
| 19 | "tx_bytes", | ||
| 20 | "rx_alloc_errors", | ||
| 21 | "tx_busy_errors", | ||
| 22 | "rx_dropped", | ||
| 23 | "tx_dropped", | ||
| 24 | "tx_hw_pkts", | ||
| 25 | "tx_hw_octs", | ||
| 26 | "tx_hw_bcast", | ||
| 27 | "tx_hw_mcast", | ||
| 28 | "rx_hw_pkts", | ||
| 29 | "rx_hw_bytes", | ||
| 30 | "rx_hw_bcast", | ||
| 31 | "rx_hw_mcast", | ||
| 32 | "rx_dropped_pkts_fifo_full", | ||
| 33 | "rx_dropped_bytes_fifo_full", | ||
| 34 | "rx_err_pkts", | ||
| 35 | }; | ||
| 36 | |||
| 37 | #define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN) | ||
| 38 | |||
| 39 | static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { | ||
| 40 | "tx_packets_posted[Q-%u]", | ||
| 41 | "tx_packets_completed[Q-%u]", | ||
| 42 | "tx_bytes[Q-%u]", | ||
| 43 | "tx_busy[Q-%u]", | ||
| 44 | }; | ||
| 45 | |||
| 46 | #define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN) | ||
| 47 | |||
| 48 | static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { | ||
| 49 | "rx_packets[Q-%u]", | ||
| 50 | "rx_bytes[Q-%u]", | ||
| 51 | "rx_alloc_errors[Q-%u]", | ||
| 52 | }; | ||
| 53 | |||
| 54 | #define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN) | ||
| 55 | |||
| 56 | static void octep_vf_get_drvinfo(struct net_device *netdev, | ||
| 57 | struct ethtool_drvinfo *info) | ||
| 58 | { | ||
| 59 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 60 | |||
| 61 | strscpy(info->driver, OCTEP_VF_DRV_NAME, sizeof(info->driver)); | ||
| 62 | strscpy(info->bus_info, pci_name(oct->pdev), sizeof(info->bus_info)); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void octep_vf_get_strings(struct net_device *netdev, | ||
| 66 | u32 stringset, u8 *data) | ||
| 67 | { | ||
| 68 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 69 | u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 70 | char *strings = (char *)data; | ||
| 71 | int i, j; | ||
| 72 | |||
| 73 | switch (stringset) { | ||
| 74 | case ETH_SS_STATS: | ||
| 75 | for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) { | ||
| 76 | snprintf(strings, ETH_GSTRING_LEN, | ||
| 77 | octep_vf_gstrings_global_stats[i]); | ||
| 78 | strings += ETH_GSTRING_LEN; | ||
| 79 | } | ||
| 80 | |||
| 81 | for (i = 0; i < num_queues; i++) { | ||
| 82 | for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) { | ||
| 83 | snprintf(strings, ETH_GSTRING_LEN, | ||
| 84 | octep_vf_gstrings_tx_q_stats[j], i); | ||
| 85 | strings += ETH_GSTRING_LEN; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | for (i = 0; i < num_queues; i++) { | ||
| 90 | for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) { | ||
| 91 | snprintf(strings, ETH_GSTRING_LEN, | ||
| 92 | octep_vf_gstrings_rx_q_stats[j], i); | ||
| 93 | strings += ETH_GSTRING_LEN; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | static int octep_vf_get_sset_count(struct net_device *netdev, int sset) | ||
| 103 | { | ||
| 104 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 105 | u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); | ||
| 106 | |||
| 107 | switch (sset) { | ||
| 108 | case ETH_SS_STATS: | ||
| 109 | return OCTEP_VF_GLOBAL_STATS_CNT + (num_queues * | ||
| 110 | (OCTEP_VF_TX_Q_STATS_CNT + OCTEP_VF_RX_Q_STATS_CNT)); | ||
| 111 | break; | ||
| 112 | default: | ||
| 113 | return -EOPNOTSUPP; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | static void octep_vf_get_ethtool_stats(struct net_device *netdev, | ||
| 118 | struct ethtool_stats *stats, u64 *data) | ||
| 119 | { | ||
| 120 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 121 | struct octep_vf_iface_tx_stats *iface_tx_stats; | ||
| 122 | struct octep_vf_iface_rx_stats *iface_rx_stats; | ||
| 123 | u64 rx_alloc_errors, tx_busy_errors; | ||
| 124 | u64 rx_packets, rx_bytes; | ||
| 125 | u64 tx_packets, tx_bytes; | ||
| 126 | int q, i; | ||
| 127 | |||
| 128 | rx_packets = 0; | ||
| 129 | rx_bytes = 0; | ||
| 130 | tx_packets = 0; | ||
| 131 | tx_bytes = 0; | ||
| 132 | rx_alloc_errors = 0; | ||
| 133 | tx_busy_errors = 0; | ||
| 134 | tx_packets = 0; | ||
| 135 | tx_bytes = 0; | ||
| 136 | rx_packets = 0; | ||
| 137 | rx_bytes = 0; | ||
| 138 | |||
| 139 | octep_vf_get_if_stats(oct); | ||
| 140 | iface_tx_stats = &oct->iface_tx_stats; | ||
| 141 | iface_rx_stats = &oct->iface_rx_stats; | ||
| 142 | |||
| 143 | for (q = 0; q < oct->num_oqs; q++) { | ||
| 144 | struct octep_vf_iq *iq = oct->iq[q]; | ||
| 145 | struct octep_vf_oq *oq = oct->oq[q]; | ||
| 146 | |||
| 147 | tx_packets += iq->stats.instr_completed; | ||
| 148 | tx_bytes += iq->stats.bytes_sent; | ||
| 149 | tx_busy_errors += iq->stats.tx_busy; | ||
| 150 | |||
| 151 | rx_packets += oq->stats.packets; | ||
| 152 | rx_bytes += oq->stats.bytes; | ||
| 153 | rx_alloc_errors += oq->stats.alloc_failures; | ||
| 154 | } | ||
| 155 | i = 0; | ||
| 156 | data[i++] = rx_packets; | ||
| 157 | data[i++] = tx_packets; | ||
| 158 | data[i++] = rx_bytes; | ||
| 159 | data[i++] = tx_bytes; | ||
| 160 | data[i++] = rx_alloc_errors; | ||
| 161 | data[i++] = tx_busy_errors; | ||
| 162 | data[i++] = iface_rx_stats->dropped_pkts_fifo_full + | ||
| 163 | iface_rx_stats->err_pkts; | ||
| 164 | data[i++] = iface_tx_stats->dropped; | ||
| 165 | data[i++] = iface_tx_stats->pkts; | ||
| 166 | data[i++] = iface_tx_stats->octs; | ||
| 167 | data[i++] = iface_tx_stats->bcst; | ||
| 168 | data[i++] = iface_tx_stats->mcst; | ||
| 169 | data[i++] = iface_rx_stats->pkts; | ||
| 170 | data[i++] = iface_rx_stats->octets; | ||
| 171 | data[i++] = iface_rx_stats->mcast_pkts; | ||
| 172 | data[i++] = iface_rx_stats->bcast_pkts; | ||
| 173 | data[i++] = iface_rx_stats->dropped_pkts_fifo_full; | ||
| 174 | data[i++] = iface_rx_stats->dropped_octets_fifo_full; | ||
| 175 | data[i++] = iface_rx_stats->err_pkts; | ||
| 176 | |||
| 177 | /* Per Tx Queue stats */ | ||
| 178 | for (q = 0; q < oct->num_iqs; q++) { | ||
| 179 | struct octep_vf_iq *iq = oct->iq[q]; | ||
| 180 | |||
| 181 | data[i++] = iq->stats.instr_posted; | ||
| 182 | data[i++] = iq->stats.instr_completed; | ||
| 183 | data[i++] = iq->stats.bytes_sent; | ||
| 184 | data[i++] = iq->stats.tx_busy; | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Per Rx Queue stats */ | ||
| 188 | for (q = 0; q < oct->num_oqs; q++) { | ||
| 189 | struct octep_vf_oq *oq = oct->oq[q]; | ||
| 190 | |||
| 191 | data[i++] = oq->stats.packets; | ||
| 192 | data[i++] = oq->stats.bytes; | ||
| 193 | data[i++] = oq->stats.alloc_failures; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | #define OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(octep_vf_speeds, ksettings, name) \ | ||
| 198 | { \ | ||
| 199 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_T)) \ | ||
| 200 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseT_Full); \ | ||
| 201 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_R)) \ | ||
| 202 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseR_FEC); \ | ||
| 203 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_CR)) \ | ||
| 204 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseCR_Full); \ | ||
| 205 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_KR)) \ | ||
| 206 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseKR_Full); \ | ||
| 207 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_LR)) \ | ||
| 208 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseLR_Full); \ | ||
| 209 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_10GBASE_SR)) \ | ||
| 210 | ethtool_link_ksettings_add_link_mode(ksettings, name, 10000baseSR_Full); \ | ||
| 211 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_CR)) \ | ||
| 212 | ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseCR_Full); \ | ||
| 213 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_KR)) \ | ||
| 214 | ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseKR_Full); \ | ||
| 215 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_25GBASE_SR)) \ | ||
| 216 | ethtool_link_ksettings_add_link_mode(ksettings, name, 25000baseSR_Full); \ | ||
| 217 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_CR4)) \ | ||
| 218 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseCR4_Full); \ | ||
| 219 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_KR4)) \ | ||
| 220 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseKR4_Full); \ | ||
| 221 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_LR4)) \ | ||
| 222 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseLR4_Full); \ | ||
| 223 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_40GBASE_SR4)) \ | ||
| 224 | ethtool_link_ksettings_add_link_mode(ksettings, name, 40000baseSR4_Full); \ | ||
| 225 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR2)) \ | ||
| 226 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR2_Full); \ | ||
| 227 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR2)) \ | ||
| 228 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR2_Full); \ | ||
| 229 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR2)) \ | ||
| 230 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR2_Full); \ | ||
| 231 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_CR)) \ | ||
| 232 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseCR_Full); \ | ||
| 233 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_KR)) \ | ||
| 234 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseKR_Full); \ | ||
| 235 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_LR)) \ | ||
| 236 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseLR_ER_FR_Full); \ | ||
| 237 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_50GBASE_SR)) \ | ||
| 238 | ethtool_link_ksettings_add_link_mode(ksettings, name, 50000baseSR_Full); \ | ||
| 239 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_CR4)) \ | ||
| 240 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseCR4_Full); \ | ||
| 241 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_KR4)) \ | ||
| 242 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseKR4_Full); \ | ||
| 243 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_LR4)) \ | ||
| 244 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseLR4_ER4_Full); \ | ||
| 245 | if ((octep_vf_speeds) & BIT(OCTEP_VF_LINK_MODE_100GBASE_SR4)) \ | ||
| 246 | ethtool_link_ksettings_add_link_mode(ksettings, name, 100000baseSR4_Full); \ | ||
| 247 | } | ||
| 248 | |||
| 249 | static int octep_vf_get_link_ksettings(struct net_device *netdev, | ||
| 250 | struct ethtool_link_ksettings *cmd) | ||
| 251 | { | ||
| 252 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 253 | struct octep_vf_iface_link_info *link_info; | ||
| 254 | u32 advertised_modes, supported_modes; | ||
| 255 | |||
| 256 | ethtool_link_ksettings_zero_link_mode(cmd, supported); | ||
| 257 | ethtool_link_ksettings_zero_link_mode(cmd, advertising); | ||
| 258 | |||
| 259 | octep_vf_get_link_info(oct); | ||
| 260 | |||
| 261 | advertised_modes = oct->link_info.advertised_modes; | ||
| 262 | supported_modes = oct->link_info.supported_modes; | ||
| 263 | link_info = &oct->link_info; | ||
| 264 | |||
| 265 | OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(supported_modes, cmd, supported); | ||
| 266 | OCTEP_VF_SET_ETHTOOL_LINK_MODES_BITMAP(advertised_modes, cmd, advertising); | ||
| 267 | |||
| 268 | if (link_info->autoneg) { | ||
| 269 | if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED) | ||
| 270 | ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); | ||
| 271 | if (link_info->autoneg & OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED) { | ||
| 272 | ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); | ||
| 273 | cmd->base.autoneg = AUTONEG_ENABLE; | ||
| 274 | } else { | ||
| 275 | cmd->base.autoneg = AUTONEG_DISABLE; | ||
| 276 | } | ||
| 277 | } else { | ||
| 278 | cmd->base.autoneg = AUTONEG_DISABLE; | ||
| 279 | } | ||
| 280 | |||
| 281 | cmd->base.port = PORT_FIBRE; | ||
| 282 | ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); | ||
| 283 | ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); | ||
| 284 | |||
| 285 | if (netif_carrier_ok(netdev)) { | ||
| 286 | cmd->base.speed = link_info->speed; | ||
| 287 | cmd->base.duplex = DUPLEX_FULL; | ||
| 288 | } else { | ||
| 289 | cmd->base.speed = SPEED_UNKNOWN; | ||
| 290 | cmd->base.duplex = DUPLEX_UNKNOWN; | ||
| 291 | } | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | static const struct ethtool_ops octep_vf_ethtool_ops = { | ||
| 296 | .get_drvinfo = octep_vf_get_drvinfo, | ||
| 297 | .get_link = ethtool_op_get_link, | ||
| 298 | .get_strings = octep_vf_get_strings, | ||
| 299 | .get_sset_count = octep_vf_get_sset_count, | ||
| 300 | .get_ethtool_stats = octep_vf_get_ethtool_stats, | ||
| 301 | .get_link_ksettings = octep_vf_get_link_ksettings, | ||
| 302 | }; | ||
| 303 | |||
| 304 | void octep_vf_set_ethtool_ops(struct net_device *netdev) | ||
| 305 | { | ||
| 306 | netdev->ethtool_ops = &octep_vf_ethtool_ops; | ||
| 307 | } | ||
| @@ -0,0 +1,1230 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/types.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/pci.h> | ||
| 11 | #include <linux/aer.h> | ||
| 12 | #include <linux/netdevice.h> | ||
| 13 | #include <linux/etherdevice.h> | ||
| 14 | #include <linux/rtnetlink.h> | ||
| 15 | #include <linux/vmalloc.h> | ||
| 16 | |||
| 17 | #include "octep_vf_config.h" | ||
| 18 | #include "octep_vf_main.h" | ||
| 19 | |||
| 20 | struct workqueue_struct *octep_vf_wq; | ||
| 21 | |||
| 22 | /* Supported Devices */ | ||
| 23 | static const struct pci_device_id octep_vf_pci_id_tbl[] = { | ||
| 24 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_VF)}, | ||
| 25 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_VF)}, | ||
| 26 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN98_VF)}, | ||
| 27 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_VF)}, | ||
| 28 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KA_VF)}, | ||
| 29 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KB_VF)}, | ||
| 30 | {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KB_VF)}, | ||
| 31 | {0, }, | ||
| 32 | }; | ||
| 33 | MODULE_DEVICE_TABLE(pci, octep_vf_pci_id_tbl); | ||
| 34 | |||
| 35 | MODULE_AUTHOR("Veerasenareddy Burru <vburru@marvell.com>"); | ||
| 36 | MODULE_DESCRIPTION(OCTEP_VF_DRV_STRING); | ||
| 37 | MODULE_LICENSE("GPL"); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * octep_vf_alloc_ioq_vectors() - Allocate Tx/Rx Queue interrupt info. | ||
| 41 | * | ||
| 42 | * @oct: Octeon device private data structure. | ||
| 43 | * | ||
| 44 | * Allocate resources to hold per Tx/Rx queue interrupt info. | ||
| 45 | * This is the information passed to interrupt handler, from which napi poll | ||
| 46 | * is scheduled and includes quick access to private data of Tx/Rx queue | ||
| 47 | * corresponding to the interrupt being handled. | ||
| 48 | * | ||
| 49 | * Return: 0, on successful allocation of resources for all queue interrupts. | ||
| 50 | * -1, if failed to allocate any resource. | ||
| 51 | */ | ||
| 52 | static int octep_vf_alloc_ioq_vectors(struct octep_vf_device *oct) | ||
| 53 | { | ||
| 54 | struct octep_vf_ioq_vector *ioq_vector; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 58 | oct->ioq_vector[i] = vzalloc(sizeof(*oct->ioq_vector[i])); | ||
| 59 | if (!oct->ioq_vector[i]) | ||
| 60 | goto free_ioq_vector; | ||
| 61 | |||
| 62 | ioq_vector = oct->ioq_vector[i]; | ||
| 63 | ioq_vector->iq = oct->iq[i]; | ||
| 64 | ioq_vector->oq = oct->oq[i]; | ||
| 65 | ioq_vector->octep_vf_dev = oct; | ||
| 66 | } | ||
| 67 | |||
| 68 | dev_info(&oct->pdev->dev, "Allocated %d IOQ vectors\n", oct->num_oqs); | ||
| 69 | return 0; | ||
| 70 | |||
| 71 | free_ioq_vector: | ||
| 72 | while (i) { | ||
| 73 | i--; | ||
| 74 | vfree(oct->ioq_vector[i]); | ||
| 75 | oct->ioq_vector[i] = NULL; | ||
| 76 | } | ||
| 77 | return -1; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * octep_vf_free_ioq_vectors() - Free Tx/Rx Queue interrupt vector info. | ||
| 82 | * | ||
| 83 | * @oct: Octeon device private data structure. | ||
| 84 | */ | ||
| 85 | static void octep_vf_free_ioq_vectors(struct octep_vf_device *oct) | ||
| 86 | { | ||
| 87 | int i; | ||
| 88 | |||
| 89 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 90 | if (oct->ioq_vector[i]) { | ||
| 91 | vfree(oct->ioq_vector[i]); | ||
| 92 | oct->ioq_vector[i] = NULL; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | netdev_info(oct->netdev, "Freed IOQ Vectors\n"); | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * octep_vf_enable_msix_range() - enable MSI-x interrupts. | ||
| 100 | * | ||
| 101 | * @oct: Octeon device private data structure. | ||
| 102 | * | ||
| 103 | * Allocate and enable all MSI-x interrupts (queue and non-queue interrupts) | ||
| 104 | * for the Octeon device. | ||
| 105 | * | ||
| 106 | * Return: 0, on successfully enabling all MSI-x interrupts. | ||
| 107 | * -1, if failed to enable any MSI-x interrupt. | ||
| 108 | */ | ||
| 109 | static int octep_vf_enable_msix_range(struct octep_vf_device *oct) | ||
| 110 | { | ||
| 111 | int num_msix, msix_allocated; | ||
| 112 | int i; | ||
| 113 | |||
| 114 | /* Generic interrupts apart from input/output queues */ | ||
| 115 | //num_msix = oct->num_oqs + CFG_GET_NON_IOQ_MSIX(oct->conf); | ||
| 116 | num_msix = oct->num_oqs; | ||
| 117 | oct->msix_entries = kcalloc(num_msix, sizeof(struct msix_entry), GFP_KERNEL); | ||
| 118 | if (!oct->msix_entries) | ||
| 119 | goto msix_alloc_err; | ||
| 120 | |||
| 121 | for (i = 0; i < num_msix; i++) | ||
| 122 | oct->msix_entries[i].entry = i; | ||
| 123 | |||
| 124 | msix_allocated = pci_enable_msix_range(oct->pdev, oct->msix_entries, | ||
| 125 | num_msix, num_msix); | ||
| 126 | if (msix_allocated != num_msix) { | ||
| 127 | dev_err(&oct->pdev->dev, | ||
| 128 | "Failed to enable %d msix irqs; got only %d\n", | ||
| 129 | num_msix, msix_allocated); | ||
| 130 | goto enable_msix_err; | ||
| 131 | } | ||
| 132 | oct->num_irqs = msix_allocated; | ||
| 133 | dev_info(&oct->pdev->dev, "MSI-X enabled successfully\n"); | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | |||
| 137 | enable_msix_err: | ||
| 138 | if (msix_allocated > 0) | ||
| 139 | pci_disable_msix(oct->pdev); | ||
| 140 | kfree(oct->msix_entries); | ||
| 141 | oct->msix_entries = NULL; | ||
| 142 | msix_alloc_err: | ||
| 143 | return -1; | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * octep_vf_disable_msix() - disable MSI-x interrupts. | ||
| 148 | * | ||
| 149 | * @oct: Octeon device private data structure. | ||
| 150 | * | ||
| 151 | * Disable MSI-x on the Octeon device. | ||
| 152 | */ | ||
| 153 | static void octep_vf_disable_msix(struct octep_vf_device *oct) | ||
| 154 | { | ||
| 155 | pci_disable_msix(oct->pdev); | ||
| 156 | kfree(oct->msix_entries); | ||
| 157 | oct->msix_entries = NULL; | ||
| 158 | dev_info(&oct->pdev->dev, "Disabled MSI-X\n"); | ||
| 159 | } | ||
| 160 | |||
| 161 | /** | ||
| 162 | * octep_vf_ioq_intr_handler() - handler for all Tx/Rx queue interrupts. | ||
| 163 | * | ||
| 164 | * @irq: Interrupt number. | ||
| 165 | * @data: interrupt data contains pointers to Tx/Rx queue private data | ||
| 166 | * and correspong NAPI context. | ||
| 167 | * | ||
| 168 | * this is common handler for all non-queue (generic) interrupts. | ||
| 169 | */ | ||
| 170 | static irqreturn_t octep_vf_ioq_intr_handler(int irq, void *data) | ||
| 171 | { | ||
| 172 | struct octep_vf_ioq_vector *ioq_vector = data; | ||
| 173 | struct octep_vf_device *oct = ioq_vector->octep_vf_dev; | ||
| 174 | |||
| 175 | return oct->hw_ops.ioq_intr_handler(ioq_vector); | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * octep_vf_request_irqs() - Register interrupt handlers. | ||
| 180 | * | ||
| 181 | * @oct: Octeon device private data structure. | ||
| 182 | * | ||
| 183 | * Register handlers for all queue and non-queue interrupts. | ||
| 184 | * | ||
| 185 | * Return: 0, on successful registration of all interrupt handlers. | ||
| 186 | * -1, on any error. | ||
| 187 | */ | ||
| 188 | static int octep_vf_request_irqs(struct octep_vf_device *oct) | ||
| 189 | { | ||
| 190 | struct net_device *netdev = oct->netdev; | ||
| 191 | struct octep_vf_ioq_vector *ioq_vector; | ||
| 192 | struct msix_entry *msix_entry; | ||
| 193 | int ret, i; | ||
| 194 | |||
| 195 | /* Request IRQs for Tx/Rx queues */ | ||
| 196 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 197 | ioq_vector = oct->ioq_vector[i]; | ||
| 198 | msix_entry = &oct->msix_entries[i]; | ||
| 199 | |||
| 200 | snprintf(ioq_vector->name, sizeof(ioq_vector->name), | ||
| 201 | "%s-q%d", netdev->name, i); | ||
| 202 | ret = request_irq(msix_entry->vector, | ||
| 203 | octep_vf_ioq_intr_handler, 0, | ||
| 204 | ioq_vector->name, ioq_vector); | ||
| 205 | if (ret) { | ||
| 206 | netdev_err(netdev, | ||
| 207 | "request_irq failed for Q-%d; err=%d", | ||
| 208 | i, ret); | ||
| 209 | goto ioq_irq_err; | ||
| 210 | } | ||
| 211 | |||
| 212 | cpumask_set_cpu(i % num_online_cpus(), | ||
| 213 | &ioq_vector->affinity_mask); | ||
| 214 | irq_set_affinity_hint(msix_entry->vector, | ||
| 215 | &ioq_vector->affinity_mask); | ||
| 216 | } | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | ioq_irq_err: | ||
| 220 | while (i) { | ||
| 221 | --i; | ||
| 222 | free_irq(oct->msix_entries[i].vector, oct); | ||
| 223 | } | ||
| 224 | return -1; | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * octep_vf_free_irqs() - free all registered interrupts. | ||
| 229 | * | ||
| 230 | * @oct: Octeon device private data structure. | ||
| 231 | * | ||
| 232 | * Free all queue and non-queue interrupts of the Octeon device. | ||
| 233 | */ | ||
| 234 | static void octep_vf_free_irqs(struct octep_vf_device *oct) | ||
| 235 | { | ||
| 236 | int i; | ||
| 237 | |||
| 238 | for (i = 0; i < oct->num_irqs; i++) { | ||
| 239 | irq_set_affinity_hint(oct->msix_entries[i].vector, NULL); | ||
| 240 | free_irq(oct->msix_entries[i].vector, oct->ioq_vector[i]); | ||
| 241 | } | ||
| 242 | netdev_info(oct->netdev, "IRQs freed\n"); | ||
| 243 | } | ||
| 244 | |||
| 245 | /** | ||
| 246 | * octep_vf_setup_irqs() - setup interrupts for the Octeon device. | ||
| 247 | * | ||
| 248 | * @oct: Octeon device private data structure. | ||
| 249 | * | ||
| 250 | * Allocate data structures to hold per interrupt information, allocate/enable | ||
| 251 | * MSI-x interrupt and register interrupt handlers. | ||
| 252 | * | ||
| 253 | * Return: 0, on successful allocation and registration of all interrupts. | ||
| 254 | * -1, on any error. | ||
| 255 | */ | ||
| 256 | static int octep_vf_setup_irqs(struct octep_vf_device *oct) | ||
| 257 | { | ||
| 258 | if (octep_vf_alloc_ioq_vectors(oct)) | ||
| 259 | goto ioq_vector_err; | ||
| 260 | |||
| 261 | if (octep_vf_enable_msix_range(oct)) | ||
| 262 | goto enable_msix_err; | ||
| 263 | |||
| 264 | if (octep_vf_request_irqs(oct)) | ||
| 265 | goto request_irq_err; | ||
| 266 | |||
| 267 | return 0; | ||
| 268 | |||
| 269 | request_irq_err: | ||
| 270 | octep_vf_disable_msix(oct); | ||
| 271 | enable_msix_err: | ||
| 272 | octep_vf_free_ioq_vectors(oct); | ||
| 273 | ioq_vector_err: | ||
| 274 | return -1; | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * octep_vf_clean_irqs() - free all interrupts and its resources. | ||
| 279 | * | ||
| 280 | * @oct: Octeon device private data structure. | ||
| 281 | */ | ||
| 282 | static void octep_vf_clean_irqs(struct octep_vf_device *oct) | ||
| 283 | { | ||
| 284 | octep_vf_free_irqs(oct); | ||
| 285 | octep_vf_disable_msix(oct); | ||
| 286 | octep_vf_free_ioq_vectors(oct); | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue. | ||
| 291 | * | ||
| 292 | * @iq: Octeon Tx queue data structure. | ||
| 293 | * @oq: Octeon Rx queue data structure. | ||
| 294 | */ | ||
| 295 | static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq) | ||
| 296 | { | ||
| 297 | u32 pkts_pend = oq->pkts_pending; | ||
| 298 | |||
| 299 | netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no); | ||
| 300 | if (iq->pkts_processed) { | ||
| 301 | writel(iq->pkts_processed, iq->inst_cnt_reg); | ||
| 302 | iq->pkt_in_done -= iq->pkts_processed; | ||
| 303 | iq->pkts_processed = 0; | ||
| 304 | } | ||
| 305 | if (oq->last_pkt_count - pkts_pend) { | ||
| 306 | writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg); | ||
| 307 | oq->last_pkt_count = pkts_pend; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* Flush the previous wrties before writing to RESEND bit */ | ||
| 311 | smp_wmb(); | ||
| 312 | writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg); | ||
| 313 | writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg); | ||
| 314 | } | ||
| 315 | |||
| 316 | /** | ||
| 317 | * octep_vf_napi_poll() - NAPI poll function for Tx/Rx. | ||
| 318 | * | ||
| 319 | * @napi: pointer to napi context. | ||
| 320 | * @budget: max number of packets to be processed in single invocation. | ||
| 321 | */ | ||
| 322 | static int octep_vf_napi_poll(struct napi_struct *napi, int budget) | ||
| 323 | { | ||
| 324 | struct octep_vf_ioq_vector *ioq_vector = | ||
| 325 | container_of(napi, struct octep_vf_ioq_vector, napi); | ||
| 326 | u32 tx_pending, rx_done; | ||
| 327 | |||
| 328 | tx_pending = octep_vf_iq_process_completions(ioq_vector->iq, budget); | ||
| 329 | rx_done = octep_vf_oq_process_rx(ioq_vector->oq, budget); | ||
| 330 | |||
| 331 | /* need more polling if tx completion processing is still pending or | ||
| 332 | * processed at least 'budget' number of rx packets. | ||
| 333 | */ | ||
| 334 | if (tx_pending || rx_done >= budget) | ||
| 335 | return budget; | ||
| 336 | |||
| 337 | napi_complete(napi); | ||
| 338 | octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq); | ||
| 339 | return rx_done; | ||
| 340 | } | ||
| 341 | |||
| 342 | /** | ||
| 343 | * octep_vf_napi_add() - Add NAPI poll for all Tx/Rx queues. | ||
| 344 | * | ||
| 345 | * @oct: Octeon device private data structure. | ||
| 346 | */ | ||
| 347 | static void octep_vf_napi_add(struct octep_vf_device *oct) | ||
| 348 | { | ||
| 349 | int i; | ||
| 350 | |||
| 351 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 352 | netdev_dbg(oct->netdev, "Adding NAPI on Q-%d\n", i); | ||
| 353 | netif_napi_add(oct->netdev, &oct->ioq_vector[i]->napi, octep_vf_napi_poll); | ||
| 354 | oct->oq[i]->napi = &oct->ioq_vector[i]->napi; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | /** | ||
| 359 | * octep_vf_napi_delete() - delete NAPI poll callback for all Tx/Rx queues. | ||
| 360 | * | ||
| 361 | * @oct: Octeon device private data structure. | ||
| 362 | */ | ||
| 363 | static void octep_vf_napi_delete(struct octep_vf_device *oct) | ||
| 364 | { | ||
| 365 | int i; | ||
| 366 | |||
| 367 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 368 | netdev_dbg(oct->netdev, "Deleting NAPI on Q-%d\n", i); | ||
| 369 | netif_napi_del(&oct->ioq_vector[i]->napi); | ||
| 370 | oct->oq[i]->napi = NULL; | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | /** | ||
| 375 | * octep_vf_napi_enable() - enable NAPI for all Tx/Rx queues. | ||
| 376 | * | ||
| 377 | * @oct: Octeon device private data structure. | ||
| 378 | */ | ||
| 379 | static void octep_vf_napi_enable(struct octep_vf_device *oct) | ||
| 380 | { | ||
| 381 | int i; | ||
| 382 | |||
| 383 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 384 | netdev_dbg(oct->netdev, "Enabling NAPI on Q-%d\n", i); | ||
| 385 | napi_enable(&oct->ioq_vector[i]->napi); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | /** | ||
| 390 | * octep_vf_napi_disable() - disable NAPI for all Tx/Rx queues. | ||
| 391 | * | ||
| 392 | * @oct: Octeon device private data structure. | ||
| 393 | */ | ||
| 394 | static void octep_vf_napi_disable(struct octep_vf_device *oct) | ||
| 395 | { | ||
| 396 | int i; | ||
| 397 | |||
| 398 | for (i = 0; i < oct->num_oqs; i++) { | ||
| 399 | netdev_dbg(oct->netdev, "Disabling NAPI on Q-%d\n", i); | ||
| 400 | napi_disable(&oct->ioq_vector[i]->napi); | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | static void octep_vf_link_up(struct net_device *netdev) | ||
| 405 | { | ||
| 406 | netif_carrier_on(netdev); | ||
| 407 | netif_tx_start_all_queues(netdev); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void octep_vf_set_rx_state(struct octep_vf_device *oct, bool up) | ||
| 411 | { | ||
| 412 | int err; | ||
| 413 | |||
| 414 | err = octep_vf_mbox_set_rx_state(oct, up); | ||
| 415 | if (err) | ||
| 416 | netdev_err(oct->netdev, "Set Rx state to %d failed with err:%d\n", up, err); | ||
| 417 | } | ||
| 418 | |||
| 419 | static int octep_vf_get_link_status(struct octep_vf_device *oct) | ||
| 420 | { | ||
| 421 | int err; | ||
| 422 | |||
| 423 | err = octep_vf_mbox_get_link_status(oct, &oct->link_info.oper_up); | ||
| 424 | if (err) | ||
| 425 | netdev_err(oct->netdev, "Get link status failed with err:%d\n", err); | ||
| 426 | return oct->link_info.oper_up; | ||
| 427 | } | ||
| 428 | |||
| 429 | static void octep_vf_set_link_status(struct octep_vf_device *oct, bool up) | ||
| 430 | { | ||
| 431 | int err; | ||
| 432 | |||
| 433 | err = octep_vf_mbox_set_link_status(oct, up); | ||
| 434 | if (err) { | ||
| 435 | netdev_err(oct->netdev, "Set link status to %d failed with err:%d\n", up, err); | ||
| 436 | return; | ||
| 437 | } | ||
| 438 | oct->link_info.oper_up = up; | ||
| 439 | } | ||
| 440 | |||
| 441 | /** | ||
| 442 | * octep_vf_open() - start the octeon network device. | ||
| 443 | * | ||
| 444 | * @netdev: pointer to kernel network device. | ||
| 445 | * | ||
| 446 | * setup Tx/Rx queues, interrupts and enable hardware operation of Tx/Rx queues | ||
| 447 | * and interrupts.. | ||
| 448 | * | ||
| 449 | * Return: 0, on successfully setting up device and bring it up. | ||
| 450 | * -1, on any error. | ||
| 451 | */ | ||
| 452 | static int octep_vf_open(struct net_device *netdev) | ||
| 453 | { | ||
| 454 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 455 | int err, ret; | ||
| 456 | |||
| 457 | netdev_info(netdev, "Starting netdev ...\n"); | ||
| 458 | netif_carrier_off(netdev); | ||
| 459 | |||
| 460 | oct->hw_ops.reset_io_queues(oct); | ||
| 461 | |||
| 462 | if (octep_vf_setup_iqs(oct)) | ||
| 463 | goto setup_iq_err; | ||
| 464 | if (octep_vf_setup_oqs(oct)) | ||
| 465 | goto setup_oq_err; | ||
| 466 | if (octep_vf_setup_irqs(oct)) | ||
| 467 | goto setup_irq_err; | ||
| 468 | |||
| 469 | err = netif_set_real_num_tx_queues(netdev, oct->num_oqs); | ||
| 470 | if (err) | ||
| 471 | goto set_queues_err; | ||
| 472 | err = netif_set_real_num_rx_queues(netdev, oct->num_iqs); | ||
| 473 | if (err) | ||
| 474 | goto set_queues_err; | ||
| 475 | |||
| 476 | octep_vf_napi_add(oct); | ||
| 477 | octep_vf_napi_enable(oct); | ||
| 478 | |||
| 479 | oct->link_info.admin_up = 1; | ||
| 480 | octep_vf_set_rx_state(oct, true); | ||
| 481 | |||
| 482 | ret = octep_vf_get_link_status(oct); | ||
| 483 | if (!ret) | ||
| 484 | octep_vf_set_link_status(oct, true); | ||
| 485 | |||
| 486 | /* Enable the input and output queues for this Octeon device */ | ||
| 487 | oct->hw_ops.enable_io_queues(oct); | ||
| 488 | |||
| 489 | /* Enable Octeon device interrupts */ | ||
| 490 | oct->hw_ops.enable_interrupts(oct); | ||
| 491 | |||
| 492 | octep_vf_oq_dbell_init(oct); | ||
| 493 | |||
| 494 | ret = octep_vf_get_link_status(oct); | ||
| 495 | if (ret) | ||
| 496 | octep_vf_link_up(netdev); | ||
| 497 | |||
| 498 | return 0; | ||
| 499 | |||
| 500 | set_queues_err: | ||
| 501 | octep_vf_napi_disable(oct); | ||
| 502 | octep_vf_napi_delete(oct); | ||
| 503 | octep_vf_clean_irqs(oct); | ||
| 504 | setup_irq_err: | ||
| 505 | octep_vf_free_oqs(oct); | ||
| 506 | setup_oq_err: | ||
| 507 | octep_vf_free_iqs(oct); | ||
| 508 | setup_iq_err: | ||
| 509 | return -1; | ||
| 510 | } | ||
| 511 | |||
| 512 | /** | ||
| 513 | * octep_vf_stop() - stop the octeon network device. | ||
| 514 | * | ||
| 515 | * @netdev: pointer to kernel network device. | ||
| 516 | * | ||
| 517 | * stop the device Tx/Rx operations, bring down the link and | ||
| 518 | * free up all resources allocated for Tx/Rx queues and interrupts. | ||
| 519 | */ | ||
| 520 | static int octep_vf_stop(struct net_device *netdev) | ||
| 521 | { | ||
| 522 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 523 | |||
| 524 | netdev_info(netdev, "Stopping the device ...\n"); | ||
| 525 | |||
| 526 | /* Stop Tx from stack */ | ||
| 527 | netif_tx_stop_all_queues(netdev); | ||
| 528 | netif_carrier_off(netdev); | ||
| 529 | netif_tx_disable(netdev); | ||
| 530 | |||
| 531 | octep_vf_set_link_status(oct, false); | ||
| 532 | octep_vf_set_rx_state(oct, false); | ||
| 533 | |||
| 534 | oct->link_info.admin_up = 0; | ||
| 535 | oct->link_info.oper_up = 0; | ||
| 536 | |||
| 537 | oct->hw_ops.disable_interrupts(oct); | ||
| 538 | octep_vf_napi_disable(oct); | ||
| 539 | octep_vf_napi_delete(oct); | ||
| 540 | |||
| 541 | octep_vf_clean_irqs(oct); | ||
| 542 | octep_vf_clean_iqs(oct); | ||
| 543 | |||
| 544 | oct->hw_ops.disable_io_queues(oct); | ||
| 545 | oct->hw_ops.reset_io_queues(oct); | ||
| 546 | octep_vf_free_oqs(oct); | ||
| 547 | octep_vf_free_iqs(oct); | ||
| 548 | netdev_info(netdev, "Device stopped !!\n"); | ||
| 549 | return 0; | ||
| 550 | } | ||
| 551 | |||
| 552 | /** | ||
| 553 | * octep_vf_iq_full_check() - check if a Tx queue is full. | ||
| 554 | * | ||
| 555 | * @iq: Octeon Tx queue data structure. | ||
| 556 | * | ||
| 557 | * Return: 0, if the Tx queue is not full. | ||
| 558 | * 1, if the Tx queue is full. | ||
| 559 | */ | ||
| 560 | static int octep_vf_iq_full_check(struct octep_vf_iq *iq) | ||
| 561 | { | ||
| 562 | if (likely((IQ_INSTR_SPACE(iq)) > | ||
| 563 | OCTEP_VF_WAKE_QUEUE_THRESHOLD)) | ||
| 564 | return 0; | ||
| 565 | |||
| 566 | /* Stop the queue if unable to send */ | ||
| 567 | netif_stop_subqueue(iq->netdev, iq->q_no); | ||
| 568 | |||
| 569 | /* check again and restart the queue, in case NAPI has just freed | ||
| 570 | * enough Tx ring entries. | ||
| 571 | */ | ||
| 572 | if (unlikely(IQ_INSTR_SPACE(iq) > | ||
| 573 | OCTEP_VF_WAKE_QUEUE_THRESHOLD)) { | ||
| 574 | netif_start_subqueue(iq->netdev, iq->q_no); | ||
| 575 | iq->stats.restart_cnt++; | ||
| 576 | return 0; | ||
| 577 | } | ||
| 578 | |||
| 579 | return 1; | ||
| 580 | } | ||
| 581 | |||
| 582 | /** | ||
| 583 | * octep_vf_start_xmit() - Enqueue packet to Octoen hardware Tx Queue. | ||
| 584 | * | ||
| 585 | * @skb: packet skbuff pointer. | ||
| 586 | * @netdev: kernel network device. | ||
| 587 | * | ||
| 588 | * Return: NETDEV_TX_BUSY, if Tx Queue is full. | ||
| 589 | * NETDEV_TX_OK, if successfully enqueued to hardware Tx queue. | ||
| 590 | */ | ||
| 591 | static netdev_tx_t octep_vf_start_xmit(struct sk_buff *skb, | ||
| 592 | struct net_device *netdev) | ||
| 593 | { | ||
| 594 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 595 | netdev_features_t feat = netdev->features; | ||
| 596 | struct octep_vf_tx_sglist_desc *sglist; | ||
| 597 | struct octep_vf_tx_buffer *tx_buffer; | ||
| 598 | struct octep_vf_tx_desc_hw *hw_desc; | ||
| 599 | struct skb_shared_info *shinfo; | ||
| 600 | struct octep_vf_instr_hdr *ih; | ||
| 601 | struct octep_vf_iq *iq; | ||
| 602 | skb_frag_t *frag; | ||
| 603 | u16 nr_frags, si; | ||
| 604 | int xmit_more; | ||
| 605 | u16 q_no, wi; | ||
| 606 | |||
| 607 | if (skb_put_padto(skb, ETH_ZLEN)) | ||
| 608 | return NETDEV_TX_OK; | ||
| 609 | |||
| 610 | q_no = skb_get_queue_mapping(skb); | ||
| 611 | if (q_no >= oct->num_iqs) { | ||
| 612 | netdev_err(netdev, "Invalid Tx skb->queue_mapping=%d\n", q_no); | ||
| 613 | q_no = q_no % oct->num_iqs; | ||
| 614 | } | ||
| 615 | |||
| 616 | iq = oct->iq[q_no]; | ||
| 617 | if (octep_vf_iq_full_check(iq)) { | ||
| 618 | iq->stats.tx_busy++; | ||
| 619 | return NETDEV_TX_BUSY; | ||
| 620 | } | ||
| 621 | |||
| 622 | shinfo = skb_shinfo(skb); | ||
| 623 | nr_frags = shinfo->nr_frags; | ||
| 624 | |||
| 625 | wi = iq->host_write_index; | ||
| 626 | hw_desc = &iq->desc_ring[wi]; | ||
| 627 | hw_desc->ih64 = 0; | ||
| 628 | |||
| 629 | tx_buffer = iq->buff_info + wi; | ||
| 630 | tx_buffer->skb = skb; | ||
| 631 | |||
| 632 | ih = &hw_desc->ih; | ||
| 633 | ih->tlen = skb->len; | ||
| 634 | ih->pkind = oct->fw_info.pkind; | ||
| 635 | ih->fsz = oct->fw_info.fsz; | ||
| 636 | ih->tlen = skb->len + ih->fsz; | ||
| 637 | |||
| 638 | if (!nr_frags) { | ||
| 639 | tx_buffer->gather = 0; | ||
| 640 | tx_buffer->dma = dma_map_single(iq->dev, skb->data, | ||
| 641 | skb->len, DMA_TO_DEVICE); | ||
| 642 | if (dma_mapping_error(iq->dev, tx_buffer->dma)) | ||
| 643 | goto dma_map_err; | ||
| 644 | hw_desc->dptr = tx_buffer->dma; | ||
| 645 | } else { | ||
| 646 | /* Scatter/Gather */ | ||
| 647 | dma_addr_t dma; | ||
| 648 | u16 len; | ||
| 649 | |||
| 650 | sglist = tx_buffer->sglist; | ||
| 651 | |||
| 652 | ih->gsz = nr_frags + 1; | ||
| 653 | ih->gather = 1; | ||
| 654 | tx_buffer->gather = 1; | ||
| 655 | |||
| 656 | len = skb_headlen(skb); | ||
| 657 | dma = dma_map_single(iq->dev, skb->data, len, DMA_TO_DEVICE); | ||
| 658 | if (dma_mapping_error(iq->dev, dma)) | ||
| 659 | goto dma_map_err; | ||
| 660 | |||
| 661 | memset(sglist, 0, OCTEP_VF_SGLIST_SIZE_PER_PKT); | ||
| 662 | sglist[0].len[3] = len; | ||
| 663 | sglist[0].dma_ptr[0] = dma; | ||
| 664 | |||
| 665 | si = 1; /* entry 0 is main skb, mapped above */ | ||
| 666 | frag = &shinfo->frags[0]; | ||
| 667 | while (nr_frags--) { | ||
| 668 | len = skb_frag_size(frag); | ||
| 669 | dma = skb_frag_dma_map(iq->dev, frag, 0, | ||
| 670 | len, DMA_TO_DEVICE); | ||
| 671 | if (dma_mapping_error(iq->dev, dma)) | ||
| 672 | goto dma_map_sg_err; | ||
| 673 | |||
| 674 | sglist[si >> 2].len[3 - (si & 3)] = len; | ||
| 675 | sglist[si >> 2].dma_ptr[si & 3] = dma; | ||
| 676 | |||
| 677 | frag++; | ||
| 678 | si++; | ||
| 679 | } | ||
| 680 | hw_desc->dptr = tx_buffer->sglist_dma; | ||
| 681 | } | ||
| 682 | if (oct->fw_info.tx_ol_flags) { | ||
| 683 | if ((feat & (NETIF_F_TSO)) && (skb_is_gso(skb))) { | ||
| 684 | hw_desc->txm.ol_flags = OCTEP_VF_TX_OFFLOAD_CKSUM; | ||
| 685 | hw_desc->txm.ol_flags |= OCTEP_VF_TX_OFFLOAD_TSO; | ||
| 686 | hw_desc->txm.gso_size = skb_shinfo(skb)->gso_size; | ||
| 687 | hw_desc->txm.gso_segs = skb_shinfo(skb)->gso_segs; | ||
| 688 | } else if (feat & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { | ||
| 689 | hw_desc->txm.ol_flags = OCTEP_VF_TX_OFFLOAD_CKSUM; | ||
| 690 | } | ||
| 691 | /* due to ESR txm will be swappeed by hw */ | ||
| 692 | hw_desc->txm64[0] = (__force u64)cpu_to_be64(hw_desc->txm64[0]); | ||
| 693 | } | ||
| 694 | |||
| 695 | netdev_tx_sent_queue(iq->netdev_q, skb->len); | ||
| 696 | |||
| 697 | xmit_more = netdev_xmit_more(); | ||
| 698 | |||
| 699 | skb_tx_timestamp(skb); | ||
| 700 | iq->fill_cnt++; | ||
| 701 | wi++; | ||
| 702 | iq->host_write_index = wi & iq->ring_size_mask; | ||
| 703 | if (xmit_more && | ||
| 704 | (IQ_INSTR_PENDING(iq) < | ||
| 705 | (iq->max_count - OCTEP_VF_WAKE_QUEUE_THRESHOLD)) && | ||
| 706 | iq->fill_cnt < iq->fill_threshold) | ||
| 707 | return NETDEV_TX_OK; | ||
| 708 | |||
| 709 | /* Flush the hw descriptors before writing to doorbell */ | ||
| 710 | smp_wmb(); | ||
| 711 | writel(iq->fill_cnt, iq->doorbell_reg); | ||
| 712 | iq->stats.instr_posted += iq->fill_cnt; | ||
| 713 | iq->fill_cnt = 0; | ||
| 714 | return NETDEV_TX_OK; | ||
| 715 | |||
| 716 | dma_map_sg_err: | ||
| 717 | if (si > 0) { | ||
| 718 | dma_unmap_single(iq->dev, sglist[0].dma_ptr[0], | ||
| 719 | sglist[0].len[0], DMA_TO_DEVICE); | ||
| 720 | sglist[0].len[0] = 0; | ||
| 721 | } | ||
| 722 | while (si > 1) { | ||
| 723 | dma_unmap_page(iq->dev, sglist[si >> 2].dma_ptr[si & 3], | ||
| 724 | sglist[si >> 2].len[si & 3], DMA_TO_DEVICE); | ||
| 725 | sglist[si >> 2].len[si & 3] = 0; | ||
| 726 | si--; | ||
| 727 | } | ||
| 728 | tx_buffer->gather = 0; | ||
| 729 | dma_map_err: | ||
| 730 | dev_kfree_skb_any(skb); | ||
| 731 | return NETDEV_TX_OK; | ||
| 732 | } | ||
| 733 | |||
| 734 | int octep_vf_get_if_stats(struct octep_vf_device *oct) | ||
| 735 | { | ||
| 736 | struct octep_vf_iface_rxtx_stats vf_stats; | ||
| 737 | int ret, size; | ||
| 738 | |||
| 739 | memset(&vf_stats, 0, sizeof(struct octep_vf_iface_rxtx_stats)); | ||
| 740 | ret = octep_vf_mbox_bulk_read(oct, OCTEP_PFVF_MBOX_CMD_GET_STATS, | ||
| 741 | (u8 *)&vf_stats, &size); | ||
| 742 | if (!ret) { | ||
| 743 | memcpy(&oct->iface_rx_stats, &vf_stats.iface_rx_stats, | ||
| 744 | sizeof(struct octep_vf_iface_rx_stats)); | ||
| 745 | memcpy(&oct->iface_tx_stats, &vf_stats.iface_tx_stats, | ||
| 746 | sizeof(struct octep_vf_iface_tx_stats)); | ||
| 747 | } | ||
| 748 | return ret; | ||
| 749 | } | ||
| 750 | |||
| 751 | int octep_vf_get_link_info(struct octep_vf_device *oct) | ||
| 752 | { | ||
| 753 | int ret, size; | ||
| 754 | |||
| 755 | ret = octep_vf_mbox_bulk_read(oct, OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO, | ||
| 756 | (u8 *)&oct->link_info, &size); | ||
| 757 | if (ret) { | ||
| 758 | dev_err(&oct->pdev->dev, "Get VF link info failed via VF Mbox\n"); | ||
| 759 | return ret; | ||
| 760 | } | ||
| 761 | return 0; | ||
| 762 | } | ||
| 763 | |||
| 764 | /** | ||
| 765 | * octep_vf_get_stats64() - Get Octeon network device statistics. | ||
| 766 | * | ||
| 767 | * @netdev: kernel network device. | ||
| 768 | * @stats: pointer to stats structure to be filled in. | ||
| 769 | */ | ||
| 770 | static void octep_vf_get_stats64(struct net_device *netdev, | ||
| 771 | struct rtnl_link_stats64 *stats) | ||
| 772 | { | ||
| 773 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 774 | u64 tx_packets, tx_bytes, rx_packets, rx_bytes; | ||
| 775 | int q; | ||
| 776 | |||
| 777 | tx_packets = 0; | ||
| 778 | tx_bytes = 0; | ||
| 779 | rx_packets = 0; | ||
| 780 | rx_bytes = 0; | ||
| 781 | for (q = 0; q < oct->num_oqs; q++) { | ||
| 782 | struct octep_vf_iq *iq = oct->iq[q]; | ||
| 783 | struct octep_vf_oq *oq = oct->oq[q]; | ||
| 784 | |||
| 785 | tx_packets += iq->stats.instr_completed; | ||
| 786 | tx_bytes += iq->stats.bytes_sent; | ||
| 787 | rx_packets += oq->stats.packets; | ||
| 788 | rx_bytes += oq->stats.bytes; | ||
| 789 | } | ||
| 790 | stats->tx_packets = tx_packets; | ||
| 791 | stats->tx_bytes = tx_bytes; | ||
| 792 | stats->rx_packets = rx_packets; | ||
| 793 | stats->rx_bytes = rx_bytes; | ||
| 794 | if (!octep_vf_get_if_stats(oct)) { | ||
| 795 | stats->multicast = oct->iface_rx_stats.mcast_pkts; | ||
| 796 | stats->rx_errors = oct->iface_rx_stats.err_pkts; | ||
| 797 | } | ||
| 798 | } | ||
| 799 | |||
| 800 | /** | ||
| 801 | * octep_vf_tx_timeout_task - work queue task to Handle Tx queue timeout. | ||
| 802 | * | ||
| 803 | * @work: pointer to Tx queue timeout work_struct | ||
| 804 | * | ||
| 805 | * Stop and start the device so that it frees up all queue resources | ||
| 806 | * and restarts the queues, that potentially clears a Tx queue timeout | ||
| 807 | * condition. | ||
| 808 | **/ | ||
| 809 | static void octep_vf_tx_timeout_task(struct work_struct *work) | ||
| 810 | { | ||
| 811 | struct octep_vf_device *oct = container_of(work, struct octep_vf_device, | ||
| 812 | tx_timeout_task); | ||
| 813 | struct net_device *netdev = oct->netdev; | ||
| 814 | |||
| 815 | rtnl_lock(); | ||
| 816 | if (netif_running(netdev)) { | ||
| 817 | octep_vf_stop(netdev); | ||
| 818 | octep_vf_open(netdev); | ||
| 819 | } | ||
| 820 | rtnl_unlock(); | ||
| 821 | } | ||
| 822 | |||
| 823 | /** | ||
| 824 | * octep_vf_tx_timeout() - Handle Tx Queue timeout. | ||
| 825 | * | ||
| 826 | * @netdev: pointer to kernel network device. | ||
| 827 | * @txqueue: Timed out Tx queue number. | ||
| 828 | * | ||
| 829 | * Schedule a work to handle Tx queue timeout. | ||
| 830 | */ | ||
| 831 | static void octep_vf_tx_timeout(struct net_device *netdev, unsigned int txqueue) | ||
| 832 | { | ||
| 833 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 834 | |||
| 835 | queue_work(octep_vf_wq, &oct->tx_timeout_task); | ||
| 836 | } | ||
| 837 | |||
| 838 | static int octep_vf_set_mac(struct net_device *netdev, void *p) | ||
| 839 | { | ||
| 840 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 841 | struct sockaddr *addr = (struct sockaddr *)p; | ||
| 842 | int err; | ||
| 843 | |||
| 844 | if (!is_valid_ether_addr(addr->sa_data)) | ||
| 845 | return -EADDRNOTAVAIL; | ||
| 846 | |||
| 847 | err = octep_vf_mbox_set_mac_addr(oct, addr->sa_data); | ||
| 848 | if (err) | ||
| 849 | return err; | ||
| 850 | |||
| 851 | memcpy(oct->mac_addr, addr->sa_data, ETH_ALEN); | ||
| 852 | eth_hw_addr_set(netdev, addr->sa_data); | ||
| 853 | |||
| 854 | return 0; | ||
| 855 | } | ||
| 856 | |||
| 857 | static int octep_vf_change_mtu(struct net_device *netdev, int new_mtu) | ||
| 858 | { | ||
| 859 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 860 | struct octep_vf_iface_link_info *link_info; | ||
| 861 | int err; | ||
| 862 | |||
| 863 | link_info = &oct->link_info; | ||
| 864 | if (link_info->mtu == new_mtu) | ||
| 865 | return 0; | ||
| 866 | |||
| 867 | err = octep_vf_mbox_set_mtu(oct, new_mtu); | ||
| 868 | if (!err) { | ||
| 869 | oct->link_info.mtu = new_mtu; | ||
| 870 | netdev->mtu = new_mtu; | ||
| 871 | } | ||
| 872 | return err; | ||
| 873 | } | ||
| 874 | |||
| 875 | static int octep_vf_set_features(struct net_device *netdev, | ||
| 876 | netdev_features_t features) | ||
| 877 | { | ||
| 878 | struct octep_vf_device *oct = netdev_priv(netdev); | ||
| 879 | u16 rx_offloads = 0, tx_offloads = 0; | ||
| 880 | int err; | ||
| 881 | |||
| 882 | /* We only support features received from firmware */ | ||
| 883 | if ((features & netdev->hw_features) != features) | ||
| 884 | return -EINVAL; | ||
| 885 | |||
| 886 | if (features & NETIF_F_TSO) | ||
| 887 | tx_offloads |= OCTEP_VF_TX_OFFLOAD_TSO; | ||
| 888 | |||
| 889 | if (features & NETIF_F_TSO6) | ||
| 890 | tx_offloads |= OCTEP_VF_TX_OFFLOAD_TSO; | ||
| 891 | |||
| 892 | if (features & NETIF_F_IP_CSUM) | ||
| 893 | tx_offloads |= OCTEP_VF_TX_OFFLOAD_CKSUM; | ||
| 894 | |||
| 895 | if (features & NETIF_F_IPV6_CSUM) | ||
| 896 | tx_offloads |= OCTEP_VF_TX_OFFLOAD_CKSUM; | ||
| 897 | |||
| 898 | if (features & NETIF_F_RXCSUM) | ||
| 899 | rx_offloads |= OCTEP_VF_RX_OFFLOAD_CKSUM; | ||
| 900 | |||
| 901 | err = octep_vf_mbox_set_offloads(oct, tx_offloads, rx_offloads); | ||
| 902 | if (!err) | ||
| 903 | netdev->features = features; | ||
| 904 | |||
| 905 | return err; | ||
| 906 | } | ||
| 907 | |||
| 908 | static const struct net_device_ops octep_vf_netdev_ops = { | ||
| 909 | .ndo_open = octep_vf_open, | ||
| 910 | .ndo_stop = octep_vf_stop, | ||
| 911 | .ndo_start_xmit = octep_vf_start_xmit, | ||
| 912 | .ndo_get_stats64 = octep_vf_get_stats64, | ||
| 913 | .ndo_tx_timeout = octep_vf_tx_timeout, | ||
| 914 | .ndo_set_mac_address = octep_vf_set_mac, | ||
| 915 | .ndo_change_mtu = octep_vf_change_mtu, | ||
| 916 | .ndo_set_features = octep_vf_set_features, | ||
| 917 | }; | ||
| 918 | |||
| 919 | static const char *octep_vf_devid_to_str(struct octep_vf_device *oct) | ||
| 920 | { | ||
| 921 | switch (oct->chip_id) { | ||
| 922 | case OCTEP_PCI_DEVICE_ID_CN93_VF: | ||
| 923 | return "CN93XX"; | ||
| 924 | case OCTEP_PCI_DEVICE_ID_CNF95N_VF: | ||
| 925 | return "CNF95N"; | ||
| 926 | case OCTEP_PCI_DEVICE_ID_CN10KA_VF: | ||
| 927 | return "CN10KA"; | ||
| 928 | case OCTEP_PCI_DEVICE_ID_CNF10KA_VF: | ||
| 929 | return "CNF10KA"; | ||
| 930 | case OCTEP_PCI_DEVICE_ID_CNF10KB_VF: | ||
| 931 | return "CNF10KB"; | ||
| 932 | case OCTEP_PCI_DEVICE_ID_CN10KB_VF: | ||
| 933 | return "CN10KB"; | ||
| 934 | default: | ||
| 935 | return "Unsupported"; | ||
| 936 | } | ||
| 937 | } | ||
| 938 | |||
| 939 | /** | ||
| 940 | * octep_vf_device_setup() - Setup Octeon Device. | ||
| 941 | * | ||
| 942 | * @oct: Octeon device private data structure. | ||
| 943 | * | ||
| 944 | * Setup Octeon device hardware operations, configuration, etc ... | ||
| 945 | */ | ||
| 946 | int octep_vf_device_setup(struct octep_vf_device *oct) | ||
| 947 | { | ||
| 948 | struct pci_dev *pdev = oct->pdev; | ||
| 949 | |||
| 950 | /* allocate memory for oct->conf */ | ||
| 951 | oct->conf = kzalloc(sizeof(*oct->conf), GFP_KERNEL); | ||
| 952 | if (!oct->conf) | ||
| 953 | return -ENOMEM; | ||
| 954 | |||
| 955 | /* Map BAR region 0 */ | ||
| 956 | oct->mmio.hw_addr = ioremap(pci_resource_start(oct->pdev, 0), | ||
| 957 | pci_resource_len(oct->pdev, 0)); | ||
| 958 | if (!oct->mmio.hw_addr) { | ||
| 959 | dev_err(&pdev->dev, | ||
| 960 | "Failed to remap BAR0; start=0x%llx len=0x%llx\n", | ||
| 961 | pci_resource_start(oct->pdev, 0), | ||
| 962 | pci_resource_len(oct->pdev, 0)); | ||
| 963 | goto ioremap_err; | ||
| 964 | } | ||
| 965 | oct->mmio.mapped = 1; | ||
| 966 | |||
| 967 | oct->chip_id = pdev->device; | ||
| 968 | oct->rev_id = pdev->revision; | ||
| 969 | dev_info(&pdev->dev, "chip_id = 0x%x\n", pdev->device); | ||
| 970 | |||
| 971 | switch (oct->chip_id) { | ||
| 972 | case OCTEP_PCI_DEVICE_ID_CN93_VF: | ||
| 973 | case OCTEP_PCI_DEVICE_ID_CNF95N_VF: | ||
| 974 | case OCTEP_PCI_DEVICE_ID_CN98_VF: | ||
| 975 | dev_info(&pdev->dev, "Setting up OCTEON %s VF PASS%d.%d\n", | ||
| 976 | octep_vf_devid_to_str(oct), OCTEP_VF_MAJOR_REV(oct), | ||
| 977 | OCTEP_VF_MINOR_REV(oct)); | ||
| 978 | octep_vf_device_setup_cn93(oct); | ||
| 979 | break; | ||
| 980 | case OCTEP_PCI_DEVICE_ID_CNF10KA_VF: | ||
| 981 | case OCTEP_PCI_DEVICE_ID_CN10KA_VF: | ||
| 982 | case OCTEP_PCI_DEVICE_ID_CNF10KB_VF: | ||
| 983 | case OCTEP_PCI_DEVICE_ID_CN10KB_VF: | ||
| 984 | dev_info(&pdev->dev, "Setting up OCTEON %s VF PASS%d.%d\n", | ||
| 985 | octep_vf_devid_to_str(oct), OCTEP_VF_MAJOR_REV(oct), | ||
| 986 | OCTEP_VF_MINOR_REV(oct)); | ||
| 987 | octep_vf_device_setup_cnxk(oct); | ||
| 988 | break; | ||
| 989 | default: | ||
| 990 | dev_err(&pdev->dev, "Unsupported device\n"); | ||
| 991 | goto unsupported_dev; | ||
| 992 | } | ||
| 993 | |||
| 994 | return 0; | ||
| 995 | |||
| 996 | unsupported_dev: | ||
| 997 | iounmap(oct->mmio.hw_addr); | ||
| 998 | ioremap_err: | ||
| 999 | kfree(oct->conf); | ||
| 1000 | return -EOPNOTSUPP; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | /** | ||
| 1004 | * octep_vf_device_cleanup() - Cleanup Octeon Device. | ||
| 1005 | * | ||
| 1006 | * @oct: Octeon device private data structure. | ||
| 1007 | * | ||
| 1008 | * Cleanup Octeon device allocated resources. | ||
| 1009 | */ | ||
| 1010 | static void octep_vf_device_cleanup(struct octep_vf_device *oct) | ||
| 1011 | { | ||
| 1012 | dev_info(&oct->pdev->dev, "Cleaning up Octeon Device ...\n"); | ||
| 1013 | |||
| 1014 | if (oct->mmio.mapped) | ||
| 1015 | iounmap(oct->mmio.hw_addr); | ||
| 1016 | |||
| 1017 | kfree(oct->conf); | ||
| 1018 | oct->conf = NULL; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | static int octep_vf_get_mac_addr(struct octep_vf_device *oct, u8 *addr) | ||
| 1022 | { | ||
| 1023 | return octep_vf_mbox_get_mac_addr(oct, addr); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /** | ||
| 1027 | * octep_vf_probe() - Octeon PCI device probe handler. | ||
| 1028 | * | ||
| 1029 | * @pdev: PCI device structure. | ||
| 1030 | * @ent: entry in Octeon PCI device ID table. | ||
| 1031 | * | ||
| 1032 | * Initializes and enables the Octeon PCI device for network operations. | ||
| 1033 | * Initializes Octeon private data structure and registers a network device. | ||
| 1034 | */ | ||
| 1035 | static int octep_vf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
| 1036 | { | ||
| 1037 | struct octep_vf_device *octep_vf_dev; | ||
| 1038 | struct net_device *netdev; | ||
| 1039 | int err; | ||
| 1040 | |||
| 1041 | err = pci_enable_device(pdev); | ||
| 1042 | if (err) { | ||
| 1043 | dev_err(&pdev->dev, "Failed to enable PCI device\n"); | ||
| 1044 | return err; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); | ||
| 1048 | if (err) { | ||
| 1049 | dev_err(&pdev->dev, "Failed to set DMA mask !!\n"); | ||
| 1050 | goto err_dma_mask; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | err = pci_request_mem_regions(pdev, OCTEP_VF_DRV_NAME); | ||
| 1054 | if (err) { | ||
| 1055 | dev_err(&pdev->dev, "Failed to map PCI memory regions\n"); | ||
| 1056 | goto err_pci_regions; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | pci_set_master(pdev); | ||
| 1060 | |||
| 1061 | netdev = alloc_etherdev_mq(sizeof(struct octep_vf_device), | ||
| 1062 | OCTEP_VF_MAX_QUEUES); | ||
| 1063 | if (!netdev) { | ||
| 1064 | dev_err(&pdev->dev, "Failed to allocate netdev\n"); | ||
| 1065 | err = -ENOMEM; | ||
| 1066 | goto err_alloc_netdev; | ||
| 1067 | } | ||
| 1068 | SET_NETDEV_DEV(netdev, &pdev->dev); | ||
| 1069 | |||
| 1070 | octep_vf_dev = netdev_priv(netdev); | ||
| 1071 | octep_vf_dev->netdev = netdev; | ||
| 1072 | octep_vf_dev->pdev = pdev; | ||
| 1073 | octep_vf_dev->dev = &pdev->dev; | ||
| 1074 | pci_set_drvdata(pdev, octep_vf_dev); | ||
| 1075 | |||
| 1076 | err = octep_vf_device_setup(octep_vf_dev); | ||
| 1077 | if (err) { | ||
| 1078 | dev_err(&pdev->dev, "Device setup failed\n"); | ||
| 1079 | goto err_octep_vf_config; | ||
| 1080 | } | ||
| 1081 | INIT_WORK(&octep_vf_dev->tx_timeout_task, octep_vf_tx_timeout_task); | ||
| 1082 | |||
| 1083 | netdev->netdev_ops = &octep_vf_netdev_ops; | ||
| 1084 | octep_vf_set_ethtool_ops(netdev); | ||
| 1085 | netif_carrier_off(netdev); | ||
| 1086 | |||
| 1087 | if (octep_vf_setup_mbox(octep_vf_dev)) { | ||
| 1088 | dev_err(&pdev->dev, "VF Mailbox setup failed\n"); | ||
| 1089 | err = -ENOMEM; | ||
| 1090 | goto err_setup_mbox; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | if (octep_vf_mbox_version_check(octep_vf_dev)) { | ||
| 1094 | dev_err(&pdev->dev, "PF VF Mailbox version mismatch\n"); | ||
| 1095 | err = -EINVAL; | ||
| 1096 | goto err_mbox_version; | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | if (octep_vf_mbox_get_fw_info(octep_vf_dev)) { | ||
| 1100 | dev_err(&pdev->dev, "unable to get fw info\n"); | ||
| 1101 | err = -EINVAL; | ||
| 1102 | goto err_mbox_version; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | netdev->hw_features = NETIF_F_SG; | ||
| 1106 | if (OCTEP_VF_TX_IP_CSUM(octep_vf_dev->fw_info.tx_ol_flags)) | ||
| 1107 | netdev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); | ||
| 1108 | |||
| 1109 | if (OCTEP_VF_RX_IP_CSUM(octep_vf_dev->fw_info.rx_ol_flags)) | ||
| 1110 | netdev->hw_features |= NETIF_F_RXCSUM; | ||
| 1111 | |||
| 1112 | netdev->min_mtu = OCTEP_VF_MIN_MTU; | ||
| 1113 | netdev->max_mtu = OCTEP_VF_MAX_MTU; | ||
| 1114 | netdev->mtu = OCTEP_VF_DEFAULT_MTU; | ||
| 1115 | |||
| 1116 | if (OCTEP_VF_TX_TSO(octep_vf_dev->fw_info.tx_ol_flags)) { | ||
| 1117 | netdev->hw_features |= NETIF_F_TSO; | ||
| 1118 | netif_set_tso_max_size(netdev, netdev->max_mtu); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | netdev->features |= netdev->hw_features; | ||
| 1122 | octep_vf_get_mac_addr(octep_vf_dev, octep_vf_dev->mac_addr); | ||
| 1123 | eth_hw_addr_set(netdev, octep_vf_dev->mac_addr); | ||
| 1124 | err = register_netdev(netdev); | ||
| 1125 | if (err) { | ||
| 1126 | dev_err(&pdev->dev, "Failed to register netdev\n"); | ||
| 1127 | goto err_register_dev; | ||
| 1128 | } | ||
| 1129 | dev_info(&pdev->dev, "Device probe successful\n"); | ||
| 1130 | return 0; | ||
| 1131 | |||
| 1132 | err_register_dev: | ||
| 1133 | err_mbox_version: | ||
| 1134 | octep_vf_delete_mbox(octep_vf_dev); | ||
| 1135 | err_setup_mbox: | ||
| 1136 | octep_vf_device_cleanup(octep_vf_dev); | ||
| 1137 | err_octep_vf_config: | ||
| 1138 | free_netdev(netdev); | ||
| 1139 | err_alloc_netdev: | ||
| 1140 | pci_release_mem_regions(pdev); | ||
| 1141 | err_pci_regions: | ||
| 1142 | err_dma_mask: | ||
| 1143 | pci_disable_device(pdev); | ||
| 1144 | dev_err(&pdev->dev, "Device probe failed\n"); | ||
| 1145 | return err; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | /** | ||
| 1149 | * octep_vf_remove() - Remove Octeon PCI device from driver control. | ||
| 1150 | * | ||
| 1151 | * @pdev: PCI device structure of the Octeon device. | ||
| 1152 | * | ||
| 1153 | * Cleanup all resources allocated for the Octeon device. | ||
| 1154 | * Unregister from network device and disable the PCI device. | ||
| 1155 | */ | ||
| 1156 | static void octep_vf_remove(struct pci_dev *pdev) | ||
| 1157 | { | ||
| 1158 | struct octep_vf_device *oct = pci_get_drvdata(pdev); | ||
| 1159 | struct net_device *netdev; | ||
| 1160 | |||
| 1161 | if (!oct) | ||
| 1162 | return; | ||
| 1163 | |||
| 1164 | octep_vf_mbox_dev_remove(oct); | ||
| 1165 | cancel_work_sync(&oct->tx_timeout_task); | ||
| 1166 | netdev = oct->netdev; | ||
| 1167 | if (netdev->reg_state == NETREG_REGISTERED) | ||
| 1168 | unregister_netdev(netdev); | ||
| 1169 | octep_vf_delete_mbox(oct); | ||
| 1170 | octep_vf_device_cleanup(oct); | ||
| 1171 | pci_release_mem_regions(pdev); | ||
| 1172 | free_netdev(netdev); | ||
| 1173 | pci_disable_device(pdev); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | static struct pci_driver octep_vf_driver = { | ||
| 1177 | .name = OCTEP_VF_DRV_NAME, | ||
| 1178 | .id_table = octep_vf_pci_id_tbl, | ||
| 1179 | .probe = octep_vf_probe, | ||
| 1180 | .remove = octep_vf_remove, | ||
| 1181 | }; | ||
| 1182 | |||
| 1183 | /** | ||
| 1184 | * octep_vf_init_module() - Module initialization. | ||
| 1185 | * | ||
| 1186 | * create common resource for the driver and register PCI driver. | ||
| 1187 | */ | ||
| 1188 | static int __init octep_vf_init_module(void) | ||
| 1189 | { | ||
| 1190 | int ret; | ||
| 1191 | |||
| 1192 | pr_info("%s: Loading %s ...\n", OCTEP_VF_DRV_NAME, OCTEP_VF_DRV_STRING); | ||
| 1193 | |||
| 1194 | /* work queue for all deferred tasks */ | ||
| 1195 | octep_vf_wq = create_singlethread_workqueue(OCTEP_VF_DRV_NAME); | ||
| 1196 | if (!octep_vf_wq) { | ||
| 1197 | pr_err("%s: Failed to create common workqueue\n", | ||
| 1198 | OCTEP_VF_DRV_NAME); | ||
| 1199 | return -ENOMEM; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | ret = pci_register_driver(&octep_vf_driver); | ||
| 1203 | if (ret < 0) { | ||
| 1204 | pr_err("%s: Failed to register PCI driver; err=%d\n", | ||
| 1205 | OCTEP_VF_DRV_NAME, ret); | ||
| 1206 | return ret; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | pr_info("%s: Loaded successfully !\n", OCTEP_VF_DRV_NAME); | ||
| 1210 | |||
| 1211 | return ret; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | /** | ||
| 1215 | * octep_vf_exit_module() - Module exit routine. | ||
| 1216 | * | ||
| 1217 | * unregister the driver with PCI subsystem and cleanup common resources. | ||
| 1218 | */ | ||
| 1219 | static void __exit octep_vf_exit_module(void) | ||
| 1220 | { | ||
| 1221 | pr_info("%s: Unloading ...\n", OCTEP_VF_DRV_NAME); | ||
| 1222 | |||
| 1223 | pci_unregister_driver(&octep_vf_driver); | ||
| 1224 | destroy_workqueue(octep_vf_wq); | ||
| 1225 | |||
| 1226 | pr_info("%s: Unloading complete\n", OCTEP_VF_DRV_NAME); | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | module_init(octep_vf_init_module); | ||
| 1230 | module_exit(octep_vf_exit_module); | ||
| @@ -0,0 +1,338 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _OCTEP_VF_MAIN_H_ | ||
| 9 | #define _OCTEP_VF_MAIN_H_ | ||
| 10 | |||
| 11 | #include "octep_vf_tx.h" | ||
| 12 | #include "octep_vf_rx.h" | ||
| 13 | #include "octep_vf_mbox.h" | ||
| 14 | |||
| 15 | #define OCTEP_VF_DRV_NAME "octeon_ep_vf" | ||
| 16 | #define OCTEP_VF_DRV_STRING "Marvell Octeon EndPoint NIC VF Driver" | ||
| 17 | |||
| 18 | #define OCTEP_PCI_DEVICE_ID_CN93_VF 0xB203 //93xx VF | ||
| 19 | #define OCTEP_PCI_DEVICE_ID_CNF95N_VF 0xB403 //95N VF | ||
| 20 | #define OCTEP_PCI_DEVICE_ID_CN98_VF 0xB103 | ||
| 21 | #define OCTEP_PCI_DEVICE_ID_CN10KA_VF 0xB903 | ||
| 22 | #define OCTEP_PCI_DEVICE_ID_CNF10KA_VF 0xBA03 | ||
| 23 | #define OCTEP_PCI_DEVICE_ID_CNF10KB_VF 0xBC03 | ||
| 24 | #define OCTEP_PCI_DEVICE_ID_CN10KB_VF 0xBD03 | ||
| 25 | |||
| 26 | #define OCTEP_VF_MAX_QUEUES 63 | ||
| 27 | #define OCTEP_VF_MAX_IQ OCTEP_VF_MAX_QUEUES | ||
| 28 | #define OCTEP_VF_MAX_OQ OCTEP_VF_MAX_QUEUES | ||
| 29 | |||
| 30 | #define OCTEP_VF_MAX_MSIX_VECTORS OCTEP_VF_MAX_OQ | ||
| 31 | |||
| 32 | #define OCTEP_VF_IQ_INTR_RESEND_BIT 59 | ||
| 33 | #define OCTEP_VF_OQ_INTR_RESEND_BIT 59 | ||
| 34 | |||
| 35 | #define IQ_INSTR_PENDING(iq) ({ typeof(iq) iq__ = (iq); \ | ||
| 36 | ((iq__)->host_write_index - (iq__)->flush_index) & \ | ||
| 37 | (iq__)->ring_size_mask; \ | ||
| 38 | }) | ||
| 39 | #define IQ_INSTR_SPACE(iq) ({ typeof(iq) iq_ = (iq); \ | ||
| 40 | (iq_)->max_count - IQ_INSTR_PENDING(iq_); \ | ||
| 41 | }) | ||
| 42 | |||
| 43 | #ifndef UINT64_MAX | ||
| 44 | #define UINT64_MAX ((u64)(~((u64)0))) /* 0xFFFFFFFFFFFFFFFF */ | ||
| 45 | #endif | ||
| 46 | |||
| 47 | /* PCI address space mapping information. | ||
| 48 | * Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of | ||
| 49 | * Octeon gets mapped to different physical address spaces in | ||
| 50 | * the kernel. | ||
| 51 | */ | ||
| 52 | struct octep_vf_mmio { | ||
| 53 | /* The physical address to which the PCI address space is mapped. */ | ||
| 54 | u8 __iomem *hw_addr; | ||
| 55 | |||
| 56 | /* Flag indicating the mapping was successful. */ | ||
| 57 | int mapped; | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct octep_vf_hw_ops { | ||
| 61 | void (*setup_iq_regs)(struct octep_vf_device *oct, int q); | ||
| 62 | void (*setup_oq_regs)(struct octep_vf_device *oct, int q); | ||
| 63 | void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox); | ||
| 64 | |||
| 65 | irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector); | ||
| 66 | irqreturn_t (*ioq_intr_handler)(void *ioq_vector); | ||
| 67 | void (*reinit_regs)(struct octep_vf_device *oct); | ||
| 68 | u32 (*update_iq_read_idx)(struct octep_vf_iq *iq); | ||
| 69 | |||
| 70 | void (*enable_interrupts)(struct octep_vf_device *oct); | ||
| 71 | void (*disable_interrupts)(struct octep_vf_device *oct); | ||
| 72 | |||
| 73 | void (*enable_io_queues)(struct octep_vf_device *oct); | ||
| 74 | void (*disable_io_queues)(struct octep_vf_device *oct); | ||
| 75 | void (*enable_iq)(struct octep_vf_device *oct, int q); | ||
| 76 | void (*disable_iq)(struct octep_vf_device *oct, int q); | ||
| 77 | void (*enable_oq)(struct octep_vf_device *oct, int q); | ||
| 78 | void (*disable_oq)(struct octep_vf_device *oct, int q); | ||
| 79 | void (*reset_io_queues)(struct octep_vf_device *oct); | ||
| 80 | void (*dump_registers)(struct octep_vf_device *oct); | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* Octeon mailbox data */ | ||
| 84 | struct octep_vf_mbox_data { | ||
| 85 | /* Holds the offset of received data via mailbox. */ | ||
| 86 | u32 data_index; | ||
| 87 | |||
| 88 | /* Holds the received data via mailbox. */ | ||
| 89 | u8 recv_data[OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE]; | ||
| 90 | }; | ||
| 91 | |||
| 92 | /* wrappers around work structs */ | ||
| 93 | struct octep_vf_mbox_wk { | ||
| 94 | struct work_struct work; | ||
| 95 | void *ctxptr; | ||
| 96 | }; | ||
| 97 | |||
| 98 | /* Octeon device mailbox */ | ||
| 99 | struct octep_vf_mbox { | ||
| 100 | /* A mutex to protect access to this q_mbox. */ | ||
| 101 | struct mutex lock; | ||
| 102 | |||
| 103 | u32 state; | ||
| 104 | |||
| 105 | /* SLI_MAC_PF_MBOX_INT for PF, SLI_PKT_MBOX_INT for VF. */ | ||
| 106 | u8 __iomem *mbox_int_reg; | ||
| 107 | |||
| 108 | /* SLI_PKT_PF_VF_MBOX_SIG(0) for PF, | ||
| 109 | * SLI_PKT_PF_VF_MBOX_SIG(1) for VF. | ||
| 110 | */ | ||
| 111 | u8 __iomem *mbox_write_reg; | ||
| 112 | |||
| 113 | /* SLI_PKT_PF_VF_MBOX_SIG(1) for PF, | ||
| 114 | * SLI_PKT_PF_VF_MBOX_SIG(0) for VF. | ||
| 115 | */ | ||
| 116 | u8 __iomem *mbox_read_reg; | ||
| 117 | |||
| 118 | /* Octeon mailbox data */ | ||
| 119 | struct octep_vf_mbox_data mbox_data; | ||
| 120 | |||
| 121 | /* Octeon mailbox work handler to process Mbox messages */ | ||
| 122 | struct octep_vf_mbox_wk wk; | ||
| 123 | }; | ||
| 124 | |||
| 125 | /* Tx/Rx queue vector per interrupt. */ | ||
| 126 | struct octep_vf_ioq_vector { | ||
| 127 | char name[OCTEP_VF_MSIX_NAME_SIZE]; | ||
| 128 | struct napi_struct napi; | ||
| 129 | struct octep_vf_device *octep_vf_dev; | ||
| 130 | struct octep_vf_iq *iq; | ||
| 131 | struct octep_vf_oq *oq; | ||
| 132 | cpumask_t affinity_mask; | ||
| 133 | }; | ||
| 134 | |||
| 135 | /* Octeon hardware/firmware offload capability flags. */ | ||
| 136 | #define OCTEP_VF_CAP_TX_CHECKSUM BIT(0) | ||
| 137 | #define OCTEP_VF_CAP_RX_CHECKSUM BIT(1) | ||
| 138 | #define OCTEP_VF_CAP_TSO BIT(2) | ||
| 139 | |||
| 140 | /* Link modes */ | ||
| 141 | enum octep_vf_link_mode_bit_indices { | ||
| 142 | OCTEP_VF_LINK_MODE_10GBASE_T = 0, | ||
| 143 | OCTEP_VF_LINK_MODE_10GBASE_R, | ||
| 144 | OCTEP_VF_LINK_MODE_10GBASE_CR, | ||
| 145 | OCTEP_VF_LINK_MODE_10GBASE_KR, | ||
| 146 | OCTEP_VF_LINK_MODE_10GBASE_LR, | ||
| 147 | OCTEP_VF_LINK_MODE_10GBASE_SR, | ||
| 148 | OCTEP_VF_LINK_MODE_25GBASE_CR, | ||
| 149 | OCTEP_VF_LINK_MODE_25GBASE_KR, | ||
| 150 | OCTEP_VF_LINK_MODE_25GBASE_SR, | ||
| 151 | OCTEP_VF_LINK_MODE_40GBASE_CR4, | ||
| 152 | OCTEP_VF_LINK_MODE_40GBASE_KR4, | ||
| 153 | OCTEP_VF_LINK_MODE_40GBASE_LR4, | ||
| 154 | OCTEP_VF_LINK_MODE_40GBASE_SR4, | ||
| 155 | OCTEP_VF_LINK_MODE_50GBASE_CR2, | ||
| 156 | OCTEP_VF_LINK_MODE_50GBASE_KR2, | ||
| 157 | OCTEP_VF_LINK_MODE_50GBASE_SR2, | ||
| 158 | OCTEP_VF_LINK_MODE_50GBASE_CR, | ||
| 159 | OCTEP_VF_LINK_MODE_50GBASE_KR, | ||
| 160 | OCTEP_VF_LINK_MODE_50GBASE_LR, | ||
| 161 | OCTEP_VF_LINK_MODE_50GBASE_SR, | ||
| 162 | OCTEP_VF_LINK_MODE_100GBASE_CR4, | ||
| 163 | OCTEP_VF_LINK_MODE_100GBASE_KR4, | ||
| 164 | OCTEP_VF_LINK_MODE_100GBASE_LR4, | ||
| 165 | OCTEP_VF_LINK_MODE_100GBASE_SR4, | ||
| 166 | OCTEP_VF_LINK_MODE_NBITS | ||
| 167 | }; | ||
| 168 | |||
| 169 | /* Hardware interface link state information. */ | ||
| 170 | struct octep_vf_iface_link_info { | ||
| 171 | /* Bitmap of Supported link speeds/modes. */ | ||
| 172 | u64 supported_modes; | ||
| 173 | |||
| 174 | /* Bitmap of Advertised link speeds/modes. */ | ||
| 175 | u64 advertised_modes; | ||
| 176 | |||
| 177 | /* Negotiated link speed in Mbps. */ | ||
| 178 | u32 speed; | ||
| 179 | |||
| 180 | /* MTU */ | ||
| 181 | u16 mtu; | ||
| 182 | |||
| 183 | /* Autonegotiation state. */ | ||
| 184 | #define OCTEP_VF_LINK_MODE_AUTONEG_SUPPORTED BIT(0) | ||
| 185 | #define OCTEP_VF_LINK_MODE_AUTONEG_ADVERTISED BIT(1) | ||
| 186 | u8 autoneg; | ||
| 187 | |||
| 188 | /* Pause frames setting. */ | ||
| 189 | #define OCTEP_VF_LINK_MODE_PAUSE_SUPPORTED BIT(0) | ||
| 190 | #define OCTEP_VF_LINK_MODE_PAUSE_ADVERTISED BIT(1) | ||
| 191 | u8 pause; | ||
| 192 | |||
| 193 | /* Admin state of the link (ifconfig <iface> up/down */ | ||
| 194 | u8 admin_up; | ||
| 195 | |||
| 196 | /* Operational state of the link: physical link is up down */ | ||
| 197 | u8 oper_up; | ||
| 198 | }; | ||
| 199 | |||
| 200 | /* Hardware interface stats information. */ | ||
| 201 | struct octep_vf_iface_rxtx_stats { | ||
| 202 | /* Hardware Interface Rx statistics */ | ||
| 203 | struct octep_vf_iface_rx_stats iface_rx_stats; | ||
| 204 | |||
| 205 | /* Hardware Interface Tx statistics */ | ||
| 206 | struct octep_vf_iface_tx_stats iface_tx_stats; | ||
| 207 | }; | ||
| 208 | |||
| 209 | struct octep_vf_fw_info { | ||
| 210 | /* pkind value to be used in every Tx hardware descriptor */ | ||
| 211 | u8 pkind; | ||
| 212 | /* front size data */ | ||
| 213 | u8 fsz; | ||
| 214 | /* supported rx offloads OCTEP_VF_RX_OFFLOAD_* */ | ||
| 215 | u16 rx_ol_flags; | ||
| 216 | /* supported tx offloads OCTEP_VF_TX_OFFLOAD_* */ | ||
| 217 | u16 tx_ol_flags; | ||
| 218 | }; | ||
| 219 | |||
| 220 | /* The Octeon device specific private data structure. | ||
| 221 | * Each Octeon device has this structure to represent all its components. | ||
| 222 | */ | ||
| 223 | struct octep_vf_device { | ||
| 224 | struct octep_vf_config *conf; | ||
| 225 | |||
| 226 | /* Octeon Chip type. */ | ||
| 227 | u16 chip_id; | ||
| 228 | u16 rev_id; | ||
| 229 | |||
| 230 | /* Device capabilities enabled */ | ||
| 231 | u64 caps_enabled; | ||
| 232 | /* Device capabilities supported */ | ||
| 233 | u64 caps_supported; | ||
| 234 | |||
| 235 | /* Pointer to basic Linux device */ | ||
| 236 | struct device *dev; | ||
| 237 | /* Linux PCI device pointer */ | ||
| 238 | struct pci_dev *pdev; | ||
| 239 | /* Netdev corresponding to the Octeon device */ | ||
| 240 | struct net_device *netdev; | ||
| 241 | |||
| 242 | /* memory mapped io range */ | ||
| 243 | struct octep_vf_mmio mmio; | ||
| 244 | |||
| 245 | /* MAC address */ | ||
| 246 | u8 mac_addr[ETH_ALEN]; | ||
| 247 | |||
| 248 | /* Tx queues (IQ: Instruction Queue) */ | ||
| 249 | u16 num_iqs; | ||
| 250 | /* Pointers to Octeon Tx queues */ | ||
| 251 | struct octep_vf_iq *iq[OCTEP_VF_MAX_IQ]; | ||
| 252 | |||
| 253 | /* Rx queues (OQ: Output Queue) */ | ||
| 254 | u16 num_oqs; | ||
| 255 | /* Pointers to Octeon Rx queues */ | ||
| 256 | struct octep_vf_oq *oq[OCTEP_VF_MAX_OQ]; | ||
| 257 | |||
| 258 | /* Hardware port number of the PCIe interface */ | ||
| 259 | u16 pcie_port; | ||
| 260 | |||
| 261 | /* Hardware operations */ | ||
| 262 | struct octep_vf_hw_ops hw_ops; | ||
| 263 | |||
| 264 | /* IRQ info */ | ||
| 265 | u16 num_irqs; | ||
| 266 | u16 num_non_ioq_irqs; | ||
| 267 | char *non_ioq_irq_names; | ||
| 268 | struct msix_entry *msix_entries; | ||
| 269 | /* IOq information of it's corresponding MSI-X interrupt. */ | ||
| 270 | struct octep_vf_ioq_vector *ioq_vector[OCTEP_VF_MAX_QUEUES]; | ||
| 271 | |||
| 272 | /* Hardware Interface Tx statistics */ | ||
| 273 | struct octep_vf_iface_tx_stats iface_tx_stats; | ||
| 274 | /* Hardware Interface Rx statistics */ | ||
| 275 | struct octep_vf_iface_rx_stats iface_rx_stats; | ||
| 276 | |||
| 277 | /* Hardware Interface Link info like supported modes, aneg support */ | ||
| 278 | struct octep_vf_iface_link_info link_info; | ||
| 279 | |||
| 280 | /* Mailbox to talk to VFs */ | ||
| 281 | struct octep_vf_mbox *mbox; | ||
| 282 | |||
| 283 | /* Work entry to handle Tx timeout */ | ||
| 284 | struct work_struct tx_timeout_task; | ||
| 285 | |||
| 286 | /* offset for iface stats */ | ||
| 287 | u32 ctrl_mbox_ifstats_offset; | ||
| 288 | |||
| 289 | /* Negotiated Mbox version */ | ||
| 290 | u32 mbox_neg_ver; | ||
| 291 | |||
| 292 | /* firmware info */ | ||
| 293 | struct octep_vf_fw_info fw_info; | ||
| 294 | }; | ||
| 295 | |||
| 296 | static inline u16 OCTEP_VF_MAJOR_REV(struct octep_vf_device *oct) | ||
| 297 | { | ||
| 298 | u16 rev = (oct->rev_id & 0xC) >> 2; | ||
| 299 | |||
| 300 | return (rev == 0) ? 1 : rev; | ||
| 301 | } | ||
| 302 | |||
| 303 | static inline u16 OCTEP_VF_MINOR_REV(struct octep_vf_device *oct) | ||
| 304 | { | ||
| 305 | return (oct->rev_id & 0x3); | ||
| 306 | } | ||
| 307 | |||
| 308 | /* Octeon CSR read/write access APIs */ | ||
| 309 | #define octep_vf_write_csr(octep_vf_dev, reg_off, value) \ | ||
| 310 | writel(value, (octep_vf_dev)->mmio.hw_addr + (reg_off)) | ||
| 311 | |||
| 312 | #define octep_vf_write_csr64(octep_vf_dev, reg_off, val64) \ | ||
| 313 | writeq(val64, (octep_vf_dev)->mmio.hw_addr + (reg_off)) | ||
| 314 | |||
| 315 | #define octep_vf_read_csr(octep_vf_dev, reg_off) \ | ||
| 316 | readl((octep_vf_dev)->mmio.hw_addr + (reg_off)) | ||
| 317 | |||
| 318 | #define octep_vf_read_csr64(octep_vf_dev, reg_off) \ | ||
| 319 | readq((octep_vf_dev)->mmio.hw_addr + (reg_off)) | ||
| 320 | |||
| 321 | extern struct workqueue_struct *octep_vf_wq; | ||
| 322 | |||
| 323 | int octep_vf_device_setup(struct octep_vf_device *oct); | ||
| 324 | int octep_vf_setup_iqs(struct octep_vf_device *oct); | ||
| 325 | void octep_vf_free_iqs(struct octep_vf_device *oct); | ||
| 326 | void octep_vf_clean_iqs(struct octep_vf_device *oct); | ||
| 327 | int octep_vf_setup_oqs(struct octep_vf_device *oct); | ||
| 328 | void octep_vf_free_oqs(struct octep_vf_device *oct); | ||
| 329 | void octep_vf_oq_dbell_init(struct octep_vf_device *oct); | ||
| 330 | void octep_vf_device_setup_cn93(struct octep_vf_device *oct); | ||
| 331 | void octep_vf_device_setup_cnxk(struct octep_vf_device *oct); | ||
| 332 | int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget); | ||
| 333 | int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget); | ||
| 334 | void octep_vf_set_ethtool_ops(struct net_device *netdev); | ||
| 335 | int octep_vf_get_link_info(struct octep_vf_device *oct); | ||
| 336 | int octep_vf_get_if_stats(struct octep_vf_device *oct); | ||
| 337 | void octep_vf_mbox_work(struct work_struct *work); | ||
| 338 | #endif /* _OCTEP_VF_MAIN_H_ */ | ||
| @@ -0,0 +1,430 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | #include <linux/types.h> | ||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/netdevice.h> | ||
| 10 | #include "octep_vf_config.h" | ||
| 11 | #include "octep_vf_main.h" | ||
| 12 | |||
| 13 | /* When a new command is implemented, the below table should be updated | ||
| 14 | * with new command and it's version info. | ||
| 15 | */ | ||
| 16 | static u32 pfvf_cmd_versions[OCTEP_PFVF_MBOX_CMD_MAX] = { | ||
| 17 | [0 ... OCTEP_PFVF_MBOX_CMD_DEV_REMOVE] = OCTEP_PFVF_MBOX_VERSION_V1, | ||
| 18 | [OCTEP_PFVF_MBOX_CMD_GET_FW_INFO ... OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS] = | ||
| 19 | OCTEP_PFVF_MBOX_VERSION_V2 | ||
| 20 | }; | ||
| 21 | |||
| 22 | int octep_vf_setup_mbox(struct octep_vf_device *oct) | ||
| 23 | { | ||
| 24 | int ring = 0; | ||
| 25 | |||
| 26 | oct->mbox = vzalloc(sizeof(*oct->mbox)); | ||
| 27 | if (!oct->mbox) | ||
| 28 | return -1; | ||
| 29 | |||
| 30 | mutex_init(&oct->mbox->lock); | ||
| 31 | |||
| 32 | oct->hw_ops.setup_mbox_regs(oct, ring); | ||
| 33 | INIT_WORK(&oct->mbox->wk.work, octep_vf_mbox_work); | ||
| 34 | oct->mbox->wk.ctxptr = oct; | ||
| 35 | oct->mbox_neg_ver = OCTEP_PFVF_MBOX_VERSION_CURRENT; | ||
| 36 | dev_info(&oct->pdev->dev, "setup vf mbox successfully\n"); | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | void octep_vf_delete_mbox(struct octep_vf_device *oct) | ||
| 41 | { | ||
| 42 | if (oct->mbox) { | ||
| 43 | if (work_pending(&oct->mbox->wk.work)) | ||
| 44 | cancel_work_sync(&oct->mbox->wk.work); | ||
| 45 | |||
| 46 | mutex_destroy(&oct->mbox->lock); | ||
| 47 | vfree(oct->mbox); | ||
| 48 | oct->mbox = NULL; | ||
| 49 | dev_info(&oct->pdev->dev, "Deleted vf mbox successfully\n"); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | int octep_vf_mbox_version_check(struct octep_vf_device *oct) | ||
| 54 | { | ||
| 55 | union octep_pfvf_mbox_word cmd; | ||
| 56 | union octep_pfvf_mbox_word rsp; | ||
| 57 | int ret; | ||
| 58 | |||
| 59 | cmd.u64 = 0; | ||
| 60 | cmd.s_version.opcode = OCTEP_PFVF_MBOX_CMD_VERSION; | ||
| 61 | cmd.s_version.version = OCTEP_PFVF_MBOX_VERSION_CURRENT; | ||
| 62 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 63 | if (ret == OCTEP_PFVF_MBOX_CMD_STATUS_NACK) { | ||
| 64 | dev_err(&oct->pdev->dev, | ||
| 65 | "VF Mbox version is incompatible with PF\n"); | ||
| 66 | return -EINVAL; | ||
| 67 | } | ||
| 68 | oct->mbox_neg_ver = (u32)rsp.s_version.version; | ||
| 69 | dev_dbg(&oct->pdev->dev, | ||
| 70 | "VF Mbox version:%u Negotiated VF version with PF:%u\n", | ||
| 71 | (u32)cmd.s_version.version, | ||
| 72 | (u32)rsp.s_version.version); | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | |||
| 76 | void octep_vf_mbox_work(struct work_struct *work) | ||
| 77 | { | ||
| 78 | struct octep_vf_mbox_wk *wk = container_of(work, struct octep_vf_mbox_wk, work); | ||
| 79 | struct octep_vf_iface_link_info *link_info; | ||
| 80 | struct octep_vf_device *oct = NULL; | ||
| 81 | struct octep_vf_mbox *mbox = NULL; | ||
| 82 | union octep_pfvf_mbox_word *notif; | ||
| 83 | u64 pf_vf_data; | ||
| 84 | |||
| 85 | oct = (struct octep_vf_device *)wk->ctxptr; | ||
| 86 | link_info = &oct->link_info; | ||
| 87 | mbox = oct->mbox; | ||
| 88 | pf_vf_data = readq(mbox->mbox_read_reg); | ||
| 89 | |||
| 90 | notif = (union octep_pfvf_mbox_word *)&pf_vf_data; | ||
| 91 | |||
| 92 | switch (notif->s.opcode) { | ||
| 93 | case OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS: | ||
| 94 | if (notif->s_link_status.status) { | ||
| 95 | link_info->oper_up = OCTEP_PFVF_LINK_STATUS_UP; | ||
| 96 | netif_carrier_on(oct->netdev); | ||
| 97 | dev_info(&oct->pdev->dev, "netif_carrier_on\n"); | ||
| 98 | } else { | ||
| 99 | link_info->oper_up = OCTEP_PFVF_LINK_STATUS_DOWN; | ||
| 100 | netif_carrier_off(oct->netdev); | ||
| 101 | dev_info(&oct->pdev->dev, "netif_carrier_off\n"); | ||
| 102 | } | ||
| 103 | break; | ||
| 104 | default: | ||
| 105 | dev_err(&oct->pdev->dev, | ||
| 106 | "Received unsupported notif %d\n", notif->s.opcode); | ||
| 107 | break; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | static int __octep_vf_mbox_send_cmd(struct octep_vf_device *oct, | ||
| 112 | union octep_pfvf_mbox_word cmd, | ||
| 113 | union octep_pfvf_mbox_word *rsp) | ||
| 114 | { | ||
| 115 | struct octep_vf_mbox *mbox = oct->mbox; | ||
| 116 | u64 reg_val = 0ull; | ||
| 117 | int count = 0; | ||
| 118 | |||
| 119 | if (!mbox) | ||
| 120 | return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP; | ||
| 121 | |||
| 122 | cmd.s.type = OCTEP_PFVF_MBOX_TYPE_CMD; | ||
| 123 | writeq(cmd.u64, mbox->mbox_write_reg); | ||
| 124 | |||
| 125 | /* No response for notification messages */ | ||
| 126 | if (!rsp) | ||
| 127 | return 0; | ||
| 128 | |||
| 129 | for (count = 0; count < OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT; count++) { | ||
| 130 | usleep_range(1000, 1500); | ||
| 131 | reg_val = readq(mbox->mbox_write_reg); | ||
| 132 | if (reg_val != cmd.u64) { | ||
| 133 | rsp->u64 = reg_val; | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | if (count == OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT) { | ||
| 138 | dev_err(&oct->pdev->dev, "mbox send command timed out\n"); | ||
| 139 | return OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT; | ||
| 140 | } | ||
| 141 | if (rsp->s.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 142 | dev_err(&oct->pdev->dev, "mbox_send: Received NACK\n"); | ||
| 143 | return OCTEP_PFVF_MBOX_CMD_STATUS_NACK; | ||
| 144 | } | ||
| 145 | rsp->u64 = reg_val; | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd, | ||
| 150 | union octep_pfvf_mbox_word *rsp) | ||
| 151 | { | ||
| 152 | struct octep_vf_mbox *mbox = oct->mbox; | ||
| 153 | int ret; | ||
| 154 | |||
| 155 | if (!mbox) | ||
| 156 | return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP; | ||
| 157 | mutex_lock(&mbox->lock); | ||
| 158 | if (pfvf_cmd_versions[cmd.s.opcode] > oct->mbox_neg_ver) { | ||
| 159 | dev_dbg(&oct->pdev->dev, "CMD:%d not supported in Version:%d\n", | ||
| 160 | cmd.s.opcode, oct->mbox_neg_ver); | ||
| 161 | mutex_unlock(&mbox->lock); | ||
| 162 | return -EOPNOTSUPP; | ||
| 163 | } | ||
| 164 | ret = __octep_vf_mbox_send_cmd(oct, cmd, rsp); | ||
| 165 | mutex_unlock(&mbox->lock); | ||
| 166 | return ret; | ||
| 167 | } | ||
| 168 | |||
| 169 | int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode, | ||
| 170 | u8 *data, int *size) | ||
| 171 | { | ||
| 172 | struct octep_vf_mbox *mbox = oct->mbox; | ||
| 173 | union octep_pfvf_mbox_word cmd; | ||
| 174 | union octep_pfvf_mbox_word rsp; | ||
| 175 | int data_len = 0, tmp_len = 0; | ||
| 176 | int read_cnt, i = 0, ret; | ||
| 177 | |||
| 178 | if (!mbox) | ||
| 179 | return OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP; | ||
| 180 | |||
| 181 | mutex_lock(&mbox->lock); | ||
| 182 | cmd.u64 = 0; | ||
| 183 | cmd.s_data.opcode = opcode; | ||
| 184 | cmd.s_data.frag = 0; | ||
| 185 | /* Send cmd to read data from PF */ | ||
| 186 | ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 187 | if (ret) { | ||
| 188 | dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n"); | ||
| 189 | mutex_unlock(&mbox->lock); | ||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | /* PF sends the data length of requested CMD | ||
| 193 | * in ACK | ||
| 194 | */ | ||
| 195 | data_len = *((int32_t *)rsp.s_data.data); | ||
| 196 | tmp_len = data_len; | ||
| 197 | cmd.u64 = 0; | ||
| 198 | rsp.u64 = 0; | ||
| 199 | cmd.s_data.opcode = opcode; | ||
| 200 | cmd.s_data.frag = 1; | ||
| 201 | while (data_len) { | ||
| 202 | ret = __octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 203 | if (ret) { | ||
| 204 | dev_err(&oct->pdev->dev, "send mbox cmd fail for data request\n"); | ||
| 205 | mutex_unlock(&mbox->lock); | ||
| 206 | mbox->mbox_data.data_index = 0; | ||
| 207 | memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE); | ||
| 208 | return ret; | ||
| 209 | } | ||
| 210 | if (data_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE) { | ||
| 211 | data_len -= OCTEP_PFVF_MBOX_MAX_DATA_SIZE; | ||
| 212 | read_cnt = OCTEP_PFVF_MBOX_MAX_DATA_SIZE; | ||
| 213 | } else { | ||
| 214 | read_cnt = data_len; | ||
| 215 | data_len = 0; | ||
| 216 | } | ||
| 217 | for (i = 0; i < read_cnt; i++) { | ||
| 218 | mbox->mbox_data.recv_data[mbox->mbox_data.data_index] = | ||
| 219 | rsp.s_data.data[i]; | ||
| 220 | mbox->mbox_data.data_index++; | ||
| 221 | } | ||
| 222 | cmd.u64 = 0; | ||
| 223 | rsp.u64 = 0; | ||
| 224 | cmd.s_data.opcode = opcode; | ||
| 225 | cmd.s_data.frag = 1; | ||
| 226 | } | ||
| 227 | memcpy(data, mbox->mbox_data.recv_data, tmp_len); | ||
| 228 | *size = tmp_len; | ||
| 229 | mbox->mbox_data.data_index = 0; | ||
| 230 | memset(mbox->mbox_data.recv_data, 0, OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE); | ||
| 231 | mutex_unlock(&mbox->lock); | ||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu) | ||
| 236 | { | ||
| 237 | int frame_size = mtu + ETH_HLEN + ETH_FCS_LEN; | ||
| 238 | union octep_pfvf_mbox_word cmd; | ||
| 239 | union octep_pfvf_mbox_word rsp; | ||
| 240 | int ret = 0; | ||
| 241 | |||
| 242 | if (mtu < ETH_MIN_MTU || frame_size > ETH_MAX_MTU) { | ||
| 243 | dev_err(&oct->pdev->dev, | ||
| 244 | "Failed to set MTU to %d MIN MTU:%d MAX MTU:%d\n", | ||
| 245 | mtu, ETH_MIN_MTU, ETH_MAX_MTU); | ||
| 246 | return -EINVAL; | ||
| 247 | } | ||
| 248 | |||
| 249 | cmd.u64 = 0; | ||
| 250 | cmd.s_set_mtu.opcode = OCTEP_PFVF_MBOX_CMD_SET_MTU; | ||
| 251 | cmd.s_set_mtu.mtu = mtu; | ||
| 252 | |||
| 253 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 254 | if (ret) { | ||
| 255 | dev_err(&oct->pdev->dev, "Mbox send failed; err=%d\n", ret); | ||
| 256 | return ret; | ||
| 257 | } | ||
| 258 | if (rsp.s_set_mtu.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 259 | dev_err(&oct->pdev->dev, "Received Mbox NACK from PF for MTU:%d\n", mtu); | ||
| 260 | return -EINVAL; | ||
| 261 | } | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr) | ||
| 267 | { | ||
| 268 | union octep_pfvf_mbox_word cmd; | ||
| 269 | union octep_pfvf_mbox_word rsp; | ||
| 270 | int i, ret; | ||
| 271 | |||
| 272 | cmd.u64 = 0; | ||
| 273 | cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR; | ||
| 274 | for (i = 0; i < ETH_ALEN; i++) | ||
| 275 | cmd.s_set_mac.mac_addr[i] = mac_addr[i]; | ||
| 276 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 277 | if (ret) { | ||
| 278 | dev_err(&oct->pdev->dev, "Mbox send failed; err = %d\n", ret); | ||
| 279 | return ret; | ||
| 280 | } | ||
| 281 | if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 282 | dev_err(&oct->pdev->dev, "received NACK\n"); | ||
| 283 | return -EINVAL; | ||
| 284 | } | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr) | ||
| 289 | { | ||
| 290 | union octep_pfvf_mbox_word cmd; | ||
| 291 | union octep_pfvf_mbox_word rsp; | ||
| 292 | int i, ret; | ||
| 293 | |||
| 294 | cmd.u64 = 0; | ||
| 295 | cmd.s_set_mac.opcode = OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR; | ||
| 296 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 297 | if (ret) { | ||
| 298 | dev_err(&oct->pdev->dev, "get_mac: mbox send failed; err = %d\n", ret); | ||
| 299 | return ret; | ||
| 300 | } | ||
| 301 | if (rsp.s_set_mac.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 302 | dev_err(&oct->pdev->dev, "get_mac: received NACK\n"); | ||
| 303 | return -EINVAL; | ||
| 304 | } | ||
| 305 | for (i = 0; i < ETH_ALEN; i++) | ||
| 306 | mac_addr[i] = rsp.s_set_mac.mac_addr[i]; | ||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state) | ||
| 311 | { | ||
| 312 | union octep_pfvf_mbox_word cmd; | ||
| 313 | union octep_pfvf_mbox_word rsp; | ||
| 314 | int ret; | ||
| 315 | |||
| 316 | cmd.u64 = 0; | ||
| 317 | cmd.s_link_state.opcode = OCTEP_PFVF_MBOX_CMD_SET_RX_STATE; | ||
| 318 | cmd.s_link_state.state = state; | ||
| 319 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 320 | if (ret) { | ||
| 321 | dev_err(&oct->pdev->dev, "Set Rx state via VF Mbox send failed\n"); | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 325 | dev_err(&oct->pdev->dev, "Set Rx state received NACK\n"); | ||
| 326 | return -EINVAL; | ||
| 327 | } | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status) | ||
| 332 | { | ||
| 333 | union octep_pfvf_mbox_word cmd; | ||
| 334 | union octep_pfvf_mbox_word rsp; | ||
| 335 | int ret; | ||
| 336 | |||
| 337 | cmd.u64 = 0; | ||
| 338 | cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS; | ||
| 339 | cmd.s_link_status.status = status; | ||
| 340 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 341 | if (ret) { | ||
| 342 | dev_err(&oct->pdev->dev, "Set link status via VF Mbox send failed\n"); | ||
| 343 | return ret; | ||
| 344 | } | ||
| 345 | if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 346 | dev_err(&oct->pdev->dev, "Set link status received NACK\n"); | ||
| 347 | return -EINVAL; | ||
| 348 | } | ||
| 349 | return 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up) | ||
| 353 | { | ||
| 354 | union octep_pfvf_mbox_word cmd; | ||
| 355 | union octep_pfvf_mbox_word rsp; | ||
| 356 | int ret; | ||
| 357 | |||
| 358 | cmd.u64 = 0; | ||
| 359 | cmd.s_link_status.opcode = OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS; | ||
| 360 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 361 | if (ret) { | ||
| 362 | dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n"); | ||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | if (rsp.s_link_status.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 366 | dev_err(&oct->pdev->dev, "Get link status received NACK\n"); | ||
| 367 | return -EINVAL; | ||
| 368 | } | ||
| 369 | *oper_up = rsp.s_link_status.status; | ||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 373 | int octep_vf_mbox_dev_remove(struct octep_vf_device *oct) | ||
| 374 | { | ||
| 375 | union octep_pfvf_mbox_word cmd; | ||
| 376 | int ret; | ||
| 377 | |||
| 378 | cmd.u64 = 0; | ||
| 379 | cmd.s.opcode = OCTEP_PFVF_MBOX_CMD_DEV_REMOVE; | ||
| 380 | ret = octep_vf_mbox_send_cmd(oct, cmd, NULL); | ||
| 381 | return ret; | ||
| 382 | } | ||
| 383 | |||
| 384 | int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct) | ||
| 385 | { | ||
| 386 | union octep_pfvf_mbox_word cmd; | ||
| 387 | union octep_pfvf_mbox_word rsp; | ||
| 388 | int ret; | ||
| 389 | |||
| 390 | cmd.u64 = 0; | ||
| 391 | cmd.s_fw_info.opcode = OCTEP_PFVF_MBOX_CMD_GET_FW_INFO; | ||
| 392 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 393 | if (ret) { | ||
| 394 | dev_err(&oct->pdev->dev, "Get link status via VF Mbox send failed\n"); | ||
| 395 | return ret; | ||
| 396 | } | ||
| 397 | if (rsp.s_fw_info.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 398 | dev_err(&oct->pdev->dev, "Get link status received NACK\n"); | ||
| 399 | return -EINVAL; | ||
| 400 | } | ||
| 401 | oct->fw_info.pkind = rsp.s_fw_info.pkind; | ||
| 402 | oct->fw_info.fsz = rsp.s_fw_info.fsz; | ||
| 403 | oct->fw_info.rx_ol_flags = rsp.s_fw_info.rx_ol_flags; | ||
| 404 | oct->fw_info.tx_ol_flags = rsp.s_fw_info.tx_ol_flags; | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads, | ||
| 410 | u16 rx_offloads) | ||
| 411 | { | ||
| 412 | union octep_pfvf_mbox_word cmd; | ||
| 413 | union octep_pfvf_mbox_word rsp; | ||
| 414 | int ret; | ||
| 415 | |||
| 416 | cmd.u64 = 0; | ||
| 417 | cmd.s_offloads.opcode = OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS; | ||
| 418 | cmd.s_offloads.rx_ol_flags = rx_offloads; | ||
| 419 | cmd.s_offloads.tx_ol_flags = tx_offloads; | ||
| 420 | ret = octep_vf_mbox_send_cmd(oct, cmd, &rsp); | ||
| 421 | if (ret) { | ||
| 422 | dev_err(&oct->pdev->dev, "Set offloads via VF Mbox send failed\n"); | ||
| 423 | return ret; | ||
| 424 | } | ||
| 425 | if (rsp.s_link_state.type != OCTEP_PFVF_MBOX_TYPE_RSP_ACK) { | ||
| 426 | dev_err(&oct->pdev->dev, "Set offloads received NACK\n"); | ||
| 427 | return -EINVAL; | ||
| 428 | } | ||
| 429 | return 0; | ||
| 430 | } | ||
| @@ -0,0 +1,166 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | #ifndef _OCTEP_VF_MBOX_H_ | ||
| 8 | #define _OCTEP_VF_MBOX_H_ | ||
| 9 | |||
| 10 | /* When a new command is implemented, VF Mbox version should be bumped. | ||
| 11 | */ | ||
| 12 | enum octep_pfvf_mbox_version { | ||
| 13 | OCTEP_PFVF_MBOX_VERSION_V0, | ||
| 14 | OCTEP_PFVF_MBOX_VERSION_V1, | ||
| 15 | OCTEP_PFVF_MBOX_VERSION_V2 | ||
| 16 | }; | ||
| 17 | |||
| 18 | #define OCTEP_PFVF_MBOX_VERSION_CURRENT OCTEP_PFVF_MBOX_VERSION_V2 | ||
| 19 | |||
| 20 | enum octep_pfvf_mbox_opcode { | ||
| 21 | OCTEP_PFVF_MBOX_CMD_VERSION, | ||
| 22 | OCTEP_PFVF_MBOX_CMD_SET_MTU, | ||
| 23 | OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR, | ||
| 24 | OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR, | ||
| 25 | OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO, | ||
| 26 | OCTEP_PFVF_MBOX_CMD_GET_STATS, | ||
| 27 | OCTEP_PFVF_MBOX_CMD_SET_RX_STATE, | ||
| 28 | OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS, | ||
| 29 | OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS, | ||
| 30 | OCTEP_PFVF_MBOX_CMD_GET_MTU, | ||
| 31 | OCTEP_PFVF_MBOX_CMD_DEV_REMOVE, | ||
| 32 | OCTEP_PFVF_MBOX_CMD_GET_FW_INFO, | ||
| 33 | OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS, | ||
| 34 | OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS, | ||
| 35 | OCTEP_PFVF_MBOX_CMD_MAX, | ||
| 36 | }; | ||
| 37 | |||
| 38 | enum octep_pfvf_mbox_word_type { | ||
| 39 | OCTEP_PFVF_MBOX_TYPE_CMD, | ||
| 40 | OCTEP_PFVF_MBOX_TYPE_RSP_ACK, | ||
| 41 | OCTEP_PFVF_MBOX_TYPE_RSP_NACK, | ||
| 42 | }; | ||
| 43 | |||
| 44 | enum octep_pfvf_mbox_cmd_status { | ||
| 45 | OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP = 1, | ||
| 46 | OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT = 2, | ||
| 47 | OCTEP_PFVF_MBOX_CMD_STATUS_NACK = 3, | ||
| 48 | OCTEP_PFVF_MBOX_CMD_STATUS_BUSY = 4, | ||
| 49 | OCTEP_PFVF_MBOX_CMD_STATUS_ERR = 5 | ||
| 50 | }; | ||
| 51 | |||
| 52 | enum octep_pfvf_link_status { | ||
| 53 | OCTEP_PFVF_LINK_STATUS_DOWN, | ||
| 54 | OCTEP_PFVF_LINK_STATUS_UP, | ||
| 55 | }; | ||
| 56 | |||
| 57 | enum octep_pfvf_link_speed { | ||
| 58 | OCTEP_PFVF_LINK_SPEED_NONE, | ||
| 59 | OCTEP_PFVF_LINK_SPEED_1000, | ||
| 60 | OCTEP_PFVF_LINK_SPEED_10000, | ||
| 61 | OCTEP_PFVF_LINK_SPEED_25000, | ||
| 62 | OCTEP_PFVF_LINK_SPEED_40000, | ||
| 63 | OCTEP_PFVF_LINK_SPEED_50000, | ||
| 64 | OCTEP_PFVF_LINK_SPEED_100000, | ||
| 65 | OCTEP_PFVF_LINK_SPEED_LAST, | ||
| 66 | }; | ||
| 67 | |||
| 68 | enum octep_pfvf_link_duplex { | ||
| 69 | OCTEP_PFVF_LINK_HALF_DUPLEX, | ||
| 70 | OCTEP_PFVF_LINK_FULL_DUPLEX, | ||
| 71 | }; | ||
| 72 | |||
| 73 | enum octep_pfvf_link_autoneg { | ||
| 74 | OCTEP_PFVF_LINK_AUTONEG, | ||
| 75 | OCTEP_PFVF_LINK_FIXED, | ||
| 76 | }; | ||
| 77 | |||
| 78 | #define OCTEP_PFVF_MBOX_TIMEOUT_WAIT_COUNT 8000 | ||
| 79 | #define OCTEP_PFVF_MBOX_TIMEOUT_WAIT_UDELAY 1000 | ||
| 80 | #define OCTEP_PFVF_MBOX_MAX_RETRIES 2 | ||
| 81 | #define OCTEP_PFVF_MBOX_VERSION 0 | ||
| 82 | #define OCTEP_PFVF_MBOX_MAX_DATA_SIZE 6 | ||
| 83 | #define OCTEP_PFVF_MBOX_MAX_DATA_BUF_SIZE 320 | ||
| 84 | #define OCTEP_PFVF_MBOX_MORE_FRAG_FLAG 1 | ||
| 85 | |||
| 86 | union octep_pfvf_mbox_word { | ||
| 87 | u64 u64; | ||
| 88 | struct { | ||
| 89 | u64 opcode:8; | ||
| 90 | u64 type:2; | ||
| 91 | u64 rsvd:6; | ||
| 92 | u64 data:48; | ||
| 93 | } s; | ||
| 94 | struct { | ||
| 95 | u64 opcode:8; | ||
| 96 | u64 type:2; | ||
| 97 | u64 frag:1; | ||
| 98 | u64 rsvd:5; | ||
| 99 | u8 data[6]; | ||
| 100 | } s_data; | ||
| 101 | struct { | ||
| 102 | u64 opcode:8; | ||
| 103 | u64 type:2; | ||
| 104 | u64 rsvd:6; | ||
| 105 | u64 version:48; | ||
| 106 | } s_version; | ||
| 107 | struct { | ||
| 108 | u64 opcode:8; | ||
| 109 | u64 type:2; | ||
| 110 | u64 rsvd:6; | ||
| 111 | u8 mac_addr[6]; | ||
| 112 | } s_set_mac; | ||
| 113 | struct { | ||
| 114 | u64 opcode:8; | ||
| 115 | u64 type:2; | ||
| 116 | u64 rsvd:6; | ||
| 117 | u64 mtu:48; | ||
| 118 | } s_set_mtu; | ||
| 119 | struct { | ||
| 120 | u64 opcode:8; | ||
| 121 | u64 type:2; | ||
| 122 | u64 state:1; | ||
| 123 | u64 rsvd:53; | ||
| 124 | } s_link_state; | ||
| 125 | struct { | ||
| 126 | u64 opcode:8; | ||
| 127 | u64 type:2; | ||
| 128 | u64 status:1; | ||
| 129 | u64 rsvd:53; | ||
| 130 | } s_link_status; | ||
| 131 | struct { | ||
| 132 | u64 opcode:8; | ||
| 133 | u64 type:2; | ||
| 134 | u64 pkind:8; | ||
| 135 | u64 fsz:8; | ||
| 136 | u64 rx_ol_flags:16; | ||
| 137 | u64 tx_ol_flags:16; | ||
| 138 | u64 rsvd:6; | ||
| 139 | } s_fw_info; | ||
| 140 | struct { | ||
| 141 | u64 opcode:8; | ||
| 142 | u64 type:2; | ||
| 143 | u64 rsvd:22; | ||
| 144 | u64 rx_ol_flags:16; | ||
| 145 | u64 tx_ol_flags:16; | ||
| 146 | } s_offloads; | ||
| 147 | } __packed; | ||
| 148 | |||
| 149 | int octep_vf_setup_mbox(struct octep_vf_device *oct); | ||
| 150 | void octep_vf_delete_mbox(struct octep_vf_device *oct); | ||
| 151 | int octep_vf_mbox_send_cmd(struct octep_vf_device *oct, union octep_pfvf_mbox_word cmd, | ||
| 152 | union octep_pfvf_mbox_word *rsp); | ||
| 153 | int octep_vf_mbox_bulk_read(struct octep_vf_device *oct, enum octep_pfvf_mbox_opcode opcode, | ||
| 154 | u8 *data, int *size); | ||
| 155 | int octep_vf_mbox_set_mtu(struct octep_vf_device *oct, int mtu); | ||
| 156 | int octep_vf_mbox_set_mac_addr(struct octep_vf_device *oct, char *mac_addr); | ||
| 157 | int octep_vf_mbox_get_mac_addr(struct octep_vf_device *oct, char *mac_addr); | ||
| 158 | int octep_vf_mbox_version_check(struct octep_vf_device *oct); | ||
| 159 | int octep_vf_mbox_set_rx_state(struct octep_vf_device *oct, bool state); | ||
| 160 | int octep_vf_mbox_set_link_status(struct octep_vf_device *oct, bool status); | ||
| 161 | int octep_vf_mbox_get_link_status(struct octep_vf_device *oct, u8 *oper_up); | ||
| 162 | int octep_vf_mbox_dev_remove(struct octep_vf_device *oct); | ||
| 163 | int octep_vf_mbox_get_fw_info(struct octep_vf_device *oct); | ||
| 164 | int octep_vf_mbox_set_offloads(struct octep_vf_device *oct, u16 tx_offloads, u16 rx_offloads); | ||
| 165 | |||
| 166 | #endif | ||
| @@ -0,0 +1,154 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | #ifndef _OCTEP_VF_REGS_CN9K_H_ | ||
| 8 | #define _OCTEP_VF_REGS_CN9K_H_ | ||
| 9 | |||
| 10 | /*############################ RST #########################*/ | ||
| 11 | #define CN93_VF_CONFIG_XPANSION_BAR 0x38 | ||
| 12 | #define CN93_VF_CONFIG_PCIE_CAP 0x70 | ||
| 13 | #define CN93_VF_CONFIG_PCIE_DEVCAP 0x74 | ||
| 14 | #define CN93_VF_CONFIG_PCIE_DEVCTL 0x78 | ||
| 15 | #define CN93_VF_CONFIG_PCIE_LINKCAP 0x7C | ||
| 16 | #define CN93_VF_CONFIG_PCIE_LINKCTL 0x80 | ||
| 17 | #define CN93_VF_CONFIG_PCIE_SLOTCAP 0x84 | ||
| 18 | #define CN93_VF_CONFIG_PCIE_SLOTCTL 0x88 | ||
| 19 | |||
| 20 | #define CN93_VF_RING_OFFSET BIT_ULL(17) | ||
| 21 | |||
| 22 | /*###################### RING IN REGISTERS #########################*/ | ||
| 23 | #define CN93_VF_SDP_R_IN_CONTROL_START 0x10000 | ||
| 24 | #define CN93_VF_SDP_R_IN_ENABLE_START 0x10010 | ||
| 25 | #define CN93_VF_SDP_R_IN_INSTR_BADDR_START 0x10020 | ||
| 26 | #define CN93_VF_SDP_R_IN_INSTR_RSIZE_START 0x10030 | ||
| 27 | #define CN93_VF_SDP_R_IN_INSTR_DBELL_START 0x10040 | ||
| 28 | #define CN93_VF_SDP_R_IN_CNTS_START 0x10050 | ||
| 29 | #define CN93_VF_SDP_R_IN_INT_LEVELS_START 0x10060 | ||
| 30 | #define CN93_VF_SDP_R_IN_PKT_CNT_START 0x10080 | ||
| 31 | #define CN93_VF_SDP_R_IN_BYTE_CNT_START 0x10090 | ||
| 32 | |||
| 33 | #define CN93_VF_SDP_R_IN_CONTROL(ring) \ | ||
| 34 | (CN93_VF_SDP_R_IN_CONTROL_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 35 | |||
| 36 | #define CN93_VF_SDP_R_IN_ENABLE(ring) \ | ||
| 37 | (CN93_VF_SDP_R_IN_ENABLE_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 38 | |||
| 39 | #define CN93_VF_SDP_R_IN_INSTR_BADDR(ring) \ | ||
| 40 | (CN93_VF_SDP_R_IN_INSTR_BADDR_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 41 | |||
| 42 | #define CN93_VF_SDP_R_IN_INSTR_RSIZE(ring) \ | ||
| 43 | (CN93_VF_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 44 | |||
| 45 | #define CN93_VF_SDP_R_IN_INSTR_DBELL(ring) \ | ||
| 46 | (CN93_VF_SDP_R_IN_INSTR_DBELL_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 47 | |||
| 48 | #define CN93_VF_SDP_R_IN_CNTS(ring) \ | ||
| 49 | (CN93_VF_SDP_R_IN_CNTS_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 50 | |||
| 51 | #define CN93_VF_SDP_R_IN_INT_LEVELS(ring) \ | ||
| 52 | (CN93_VF_SDP_R_IN_INT_LEVELS_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 53 | |||
| 54 | #define CN93_VF_SDP_R_IN_PKT_CNT(ring) \ | ||
| 55 | (CN93_VF_SDP_R_IN_PKT_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 56 | |||
| 57 | #define CN93_VF_SDP_R_IN_BYTE_CNT(ring) \ | ||
| 58 | (CN93_VF_SDP_R_IN_BYTE_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 59 | |||
| 60 | /*------------------ R_IN Masks ----------------*/ | ||
| 61 | |||
| 62 | /** Rings per Virtual Function **/ | ||
| 63 | #define CN93_VF_R_IN_CTL_RPVF_MASK (0xF) | ||
| 64 | #define CN93_VF_R_IN_CTL_RPVF_POS (48) | ||
| 65 | |||
| 66 | /* Number of instructions to be read in one MAC read request. | ||
| 67 | * setting to Max value(4) | ||
| 68 | **/ | ||
| 69 | #define CN93_VF_R_IN_CTL_IDLE BIT_ULL(28) | ||
| 70 | #define CN93_VF_R_IN_CTL_RDSIZE (0x3ULL << 25) | ||
| 71 | #define CN93_VF_R_IN_CTL_IS_64B BIT_ULL(24) | ||
| 72 | #define CN93_VF_R_IN_CTL_D_NSR BIT_ULL(8) | ||
| 73 | #define CN93_VF_R_IN_CTL_D_ESR BIT_ULL(6) | ||
| 74 | #define CN93_VF_R_IN_CTL_D_ROR BIT_ULL(5) | ||
| 75 | #define CN93_VF_R_IN_CTL_NSR BIT_ULL(3) | ||
| 76 | #define CN93_VF_R_IN_CTL_ESR BIT_ULL(1) | ||
| 77 | #define CN93_VF_R_IN_CTL_ROR BIT_ULL(0) | ||
| 78 | |||
| 79 | #define CN93_VF_R_IN_CTL_MASK (CN93_VF_R_IN_CTL_RDSIZE | CN93_VF_R_IN_CTL_IS_64B) | ||
| 80 | |||
| 81 | /*###################### RING OUT REGISTERS #########################*/ | ||
| 82 | #define CN93_VF_SDP_R_OUT_CNTS_START 0x10100 | ||
| 83 | #define CN93_VF_SDP_R_OUT_INT_LEVELS_START 0x10110 | ||
| 84 | #define CN93_VF_SDP_R_OUT_SLIST_BADDR_START 0x10120 | ||
| 85 | #define CN93_VF_SDP_R_OUT_SLIST_RSIZE_START 0x10130 | ||
| 86 | #define CN93_VF_SDP_R_OUT_SLIST_DBELL_START 0x10140 | ||
| 87 | #define CN93_VF_SDP_R_OUT_CONTROL_START 0x10150 | ||
| 88 | #define CN93_VF_SDP_R_OUT_ENABLE_START 0x10160 | ||
| 89 | #define CN93_VF_SDP_R_OUT_PKT_CNT_START 0x10180 | ||
| 90 | #define CN93_VF_SDP_R_OUT_BYTE_CNT_START 0x10190 | ||
| 91 | |||
| 92 | #define CN93_VF_SDP_R_OUT_CONTROL(ring) \ | ||
| 93 | (CN93_VF_SDP_R_OUT_CONTROL_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 94 | |||
| 95 | #define CN93_VF_SDP_R_OUT_ENABLE(ring) \ | ||
| 96 | (CN93_VF_SDP_R_OUT_ENABLE_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 97 | |||
| 98 | #define CN93_VF_SDP_R_OUT_SLIST_BADDR(ring) \ | ||
| 99 | (CN93_VF_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 100 | |||
| 101 | #define CN93_VF_SDP_R_OUT_SLIST_RSIZE(ring) \ | ||
| 102 | (CN93_VF_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 103 | |||
| 104 | #define CN93_VF_SDP_R_OUT_SLIST_DBELL(ring) \ | ||
| 105 | (CN93_VF_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 106 | |||
| 107 | #define CN93_VF_SDP_R_OUT_CNTS(ring) \ | ||
| 108 | (CN93_VF_SDP_R_OUT_CNTS_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 109 | |||
| 110 | #define CN93_VF_SDP_R_OUT_INT_LEVELS(ring) \ | ||
| 111 | (CN93_VF_SDP_R_OUT_INT_LEVELS_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 112 | |||
| 113 | #define CN93_VF_SDP_R_OUT_PKT_CNT(ring) \ | ||
| 114 | (CN93_VF_SDP_R_OUT_PKT_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 115 | |||
| 116 | #define CN93_VF_SDP_R_OUT_BYTE_CNT(ring) \ | ||
| 117 | (CN93_VF_SDP_R_OUT_BYTE_CNT_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 118 | |||
| 119 | /*------------------ R_OUT Masks ----------------*/ | ||
| 120 | #define CN93_VF_R_OUT_INT_LEVELS_BMODE BIT_ULL(63) | ||
| 121 | #define CN93_VF_R_OUT_INT_LEVELS_TIMET (32) | ||
| 122 | |||
| 123 | #define CN93_VF_R_OUT_CTL_IDLE BIT_ULL(40) | ||
| 124 | #define CN93_VF_R_OUT_CTL_ES_I BIT_ULL(34) | ||
| 125 | #define CN93_VF_R_OUT_CTL_NSR_I BIT_ULL(33) | ||
| 126 | #define CN93_VF_R_OUT_CTL_ROR_I BIT_ULL(32) | ||
| 127 | #define CN93_VF_R_OUT_CTL_ES_D BIT_ULL(30) | ||
| 128 | #define CN93_VF_R_OUT_CTL_NSR_D BIT_ULL(29) | ||
| 129 | #define CN93_VF_R_OUT_CTL_ROR_D BIT_ULL(28) | ||
| 130 | #define CN93_VF_R_OUT_CTL_ES_P BIT_ULL(26) | ||
| 131 | #define CN93_VF_R_OUT_CTL_NSR_P BIT_ULL(25) | ||
| 132 | #define CN93_VF_R_OUT_CTL_ROR_P BIT_ULL(24) | ||
| 133 | #define CN93_VF_R_OUT_CTL_IMODE BIT_ULL(23) | ||
| 134 | |||
| 135 | /* ##################### Mail Box Registers ########################## */ | ||
| 136 | /* SDP PF to VF Mailbox Data Register */ | ||
| 137 | #define CN93_VF_SDP_R_MBOX_PF_VF_DATA_START 0x10210 | ||
| 138 | /* SDP Packet PF to VF Mailbox Interrupt Register */ | ||
| 139 | #define CN93_VF_SDP_R_MBOX_PF_VF_INT_START 0x10220 | ||
| 140 | /* SDP VF to PF Mailbox Data Register */ | ||
| 141 | #define CN93_VF_SDP_R_MBOX_VF_PF_DATA_START 0x10230 | ||
| 142 | |||
| 143 | #define CN93_VF_SDP_R_MBOX_PF_VF_INT_ENAB BIT_ULL(1) | ||
| 144 | #define CN93_VF_SDP_R_MBOX_PF_VF_INT_STATUS BIT_ULL(0) | ||
| 145 | |||
| 146 | #define CN93_VF_SDP_R_MBOX_PF_VF_DATA(ring) \ | ||
| 147 | (CN93_VF_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 148 | |||
| 149 | #define CN93_VF_SDP_R_MBOX_PF_VF_INT(ring) \ | ||
| 150 | (CN93_VF_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 151 | |||
| 152 | #define CN93_VF_SDP_R_MBOX_VF_PF_DATA(ring) \ | ||
| 153 | (CN93_VF_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CN93_VF_RING_OFFSET)) | ||
| 154 | #endif /* _OCTEP_VF_REGS_CN9K_H_ */ | ||
| @@ -0,0 +1,162 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | #ifndef _OCTEP_VF_REGS_CNXK_H_ | ||
| 8 | #define _OCTEP_VF_REGS_CNXK_H_ | ||
| 9 | |||
| 10 | /*############################ RST #########################*/ | ||
| 11 | #define CNXK_VF_CONFIG_XPANSION_BAR 0x38 | ||
| 12 | #define CNXK_VF_CONFIG_PCIE_CAP 0x70 | ||
| 13 | #define CNXK_VF_CONFIG_PCIE_DEVCAP 0x74 | ||
| 14 | #define CNXK_VF_CONFIG_PCIE_DEVCTL 0x78 | ||
| 15 | #define CNXK_VF_CONFIG_PCIE_LINKCAP 0x7C | ||
| 16 | #define CNXK_VF_CONFIG_PCIE_LINKCTL 0x80 | ||
| 17 | #define CNXK_VF_CONFIG_PCIE_SLOTCAP 0x84 | ||
| 18 | #define CNXK_VF_CONFIG_PCIE_SLOTCTL 0x88 | ||
| 19 | |||
| 20 | #define CNXK_VF_RING_OFFSET (0x1ULL << 17) | ||
| 21 | |||
| 22 | /*###################### RING IN REGISTERS #########################*/ | ||
| 23 | #define CNXK_VF_SDP_R_IN_CONTROL_START 0x10000 | ||
| 24 | #define CNXK_VF_SDP_R_IN_ENABLE_START 0x10010 | ||
| 25 | #define CNXK_VF_SDP_R_IN_INSTR_BADDR_START 0x10020 | ||
| 26 | #define CNXK_VF_SDP_R_IN_INSTR_RSIZE_START 0x10030 | ||
| 27 | #define CNXK_VF_SDP_R_IN_INSTR_DBELL_START 0x10040 | ||
| 28 | #define CNXK_VF_SDP_R_IN_CNTS_START 0x10050 | ||
| 29 | #define CNXK_VF_SDP_R_IN_INT_LEVELS_START 0x10060 | ||
| 30 | #define CNXK_VF_SDP_R_IN_PKT_CNT_START 0x10080 | ||
| 31 | #define CNXK_VF_SDP_R_IN_BYTE_CNT_START 0x10090 | ||
| 32 | #define CNXK_VF_SDP_R_ERR_TYPE_START 0x10400 | ||
| 33 | |||
| 34 | #define CNXK_VF_SDP_R_ERR_TYPE(ring) \ | ||
| 35 | (CNXK_VF_SDP_R_ERR_TYPE_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 36 | |||
| 37 | #define CNXK_VF_SDP_R_IN_CONTROL(ring) \ | ||
| 38 | (CNXK_VF_SDP_R_IN_CONTROL_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 39 | |||
| 40 | #define CNXK_VF_SDP_R_IN_ENABLE(ring) \ | ||
| 41 | (CNXK_VF_SDP_R_IN_ENABLE_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 42 | |||
| 43 | #define CNXK_VF_SDP_R_IN_INSTR_BADDR(ring) \ | ||
| 44 | (CNXK_VF_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 45 | |||
| 46 | #define CNXK_VF_SDP_R_IN_INSTR_RSIZE(ring) \ | ||
| 47 | (CNXK_VF_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 48 | |||
| 49 | #define CNXK_VF_SDP_R_IN_INSTR_DBELL(ring) \ | ||
| 50 | (CNXK_VF_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 51 | |||
| 52 | #define CNXK_VF_SDP_R_IN_CNTS(ring) \ | ||
| 53 | (CNXK_VF_SDP_R_IN_CNTS_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 54 | |||
| 55 | #define CNXK_VF_SDP_R_IN_INT_LEVELS(ring) \ | ||
| 56 | (CNXK_VF_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 57 | |||
| 58 | #define CNXK_VF_SDP_R_IN_PKT_CNT(ring) \ | ||
| 59 | (CNXK_VF_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 60 | |||
| 61 | #define CNXK_VF_SDP_R_IN_BYTE_CNT(ring) \ | ||
| 62 | (CNXK_VF_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 63 | |||
| 64 | /*------------------ R_IN Masks ----------------*/ | ||
| 65 | |||
| 66 | /** Rings per Virtual Function **/ | ||
| 67 | #define CNXK_VF_R_IN_CTL_RPVF_MASK (0xF) | ||
| 68 | #define CNXK_VF_R_IN_CTL_RPVF_POS (48) | ||
| 69 | |||
| 70 | /* Number of instructions to be read in one MAC read request. | ||
| 71 | * setting to Max value(4) | ||
| 72 | **/ | ||
| 73 | #define CNXK_VF_R_IN_CTL_IDLE (0x1ULL << 28) | ||
| 74 | #define CNXK_VF_R_IN_CTL_RDSIZE (0x3ULL << 25) | ||
| 75 | #define CNXK_VF_R_IN_CTL_IS_64B (0x1ULL << 24) | ||
| 76 | #define CNXK_VF_R_IN_CTL_D_NSR (0x1ULL << 8) | ||
| 77 | #define CNXK_VF_R_IN_CTL_D_ESR (0x1ULL << 6) | ||
| 78 | #define CNXK_VF_R_IN_CTL_D_ROR (0x1ULL << 5) | ||
| 79 | #define CNXK_VF_R_IN_CTL_NSR (0x1ULL << 3) | ||
| 80 | #define CNXK_VF_R_IN_CTL_ESR (0x1ULL << 1) | ||
| 81 | #define CNXK_VF_R_IN_CTL_ROR (0x1ULL << 0) | ||
| 82 | |||
| 83 | #define CNXK_VF_R_IN_CTL_MASK (CNXK_VF_R_IN_CTL_RDSIZE | CNXK_VF_R_IN_CTL_IS_64B) | ||
| 84 | |||
| 85 | /*###################### RING OUT REGISTERS #########################*/ | ||
| 86 | #define CNXK_VF_SDP_R_OUT_CNTS_START 0x10100 | ||
| 87 | #define CNXK_VF_SDP_R_OUT_INT_LEVELS_START 0x10110 | ||
| 88 | #define CNXK_VF_SDP_R_OUT_SLIST_BADDR_START 0x10120 | ||
| 89 | #define CNXK_VF_SDP_R_OUT_SLIST_RSIZE_START 0x10130 | ||
| 90 | #define CNXK_VF_SDP_R_OUT_SLIST_DBELL_START 0x10140 | ||
| 91 | #define CNXK_VF_SDP_R_OUT_CONTROL_START 0x10150 | ||
| 92 | #define CNXK_VF_SDP_R_OUT_WMARK_START 0x10160 | ||
| 93 | #define CNXK_VF_SDP_R_OUT_ENABLE_START 0x10170 | ||
| 94 | #define CNXK_VF_SDP_R_OUT_PKT_CNT_START 0x10180 | ||
| 95 | #define CNXK_VF_SDP_R_OUT_BYTE_CNT_START 0x10190 | ||
| 96 | |||
| 97 | #define CNXK_VF_SDP_R_OUT_CONTROL(ring) \ | ||
| 98 | (CNXK_VF_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 99 | |||
| 100 | #define CNXK_VF_SDP_R_OUT_ENABLE(ring) \ | ||
| 101 | (CNXK_VF_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 102 | |||
| 103 | #define CNXK_VF_SDP_R_OUT_SLIST_BADDR(ring) \ | ||
| 104 | (CNXK_VF_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 105 | |||
| 106 | #define CNXK_VF_SDP_R_OUT_SLIST_RSIZE(ring) \ | ||
| 107 | (CNXK_VF_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 108 | |||
| 109 | #define CNXK_VF_SDP_R_OUT_SLIST_DBELL(ring) \ | ||
| 110 | (CNXK_VF_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 111 | |||
| 112 | #define CNXK_VF_SDP_R_OUT_WMARK(ring) \ | ||
| 113 | (CNXK_VF_SDP_R_OUT_WMARK_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 114 | |||
| 115 | #define CNXK_VF_SDP_R_OUT_CNTS(ring) \ | ||
| 116 | (CNXK_VF_SDP_R_OUT_CNTS_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 117 | |||
| 118 | #define CNXK_VF_SDP_R_OUT_INT_LEVELS(ring) \ | ||
| 119 | (CNXK_VF_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 120 | |||
| 121 | #define CNXK_VF_SDP_R_OUT_PKT_CNT(ring) \ | ||
| 122 | (CNXK_VF_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 123 | |||
| 124 | #define CNXK_VF_SDP_R_OUT_BYTE_CNT(ring) \ | ||
| 125 | (CNXK_VF_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 126 | |||
| 127 | /*------------------ R_OUT Masks ----------------*/ | ||
| 128 | #define CNXK_VF_R_OUT_INT_LEVELS_BMODE BIT_ULL(63) | ||
| 129 | #define CNXK_VF_R_OUT_INT_LEVELS_TIMET (32) | ||
| 130 | |||
| 131 | #define CNXK_VF_R_OUT_CTL_IDLE BIT_ULL(40) | ||
| 132 | #define CNXK_VF_R_OUT_CTL_ES_I BIT_ULL(34) | ||
| 133 | #define CNXK_VF_R_OUT_CTL_NSR_I BIT_ULL(33) | ||
| 134 | #define CNXK_VF_R_OUT_CTL_ROR_I BIT_ULL(32) | ||
| 135 | #define CNXK_VF_R_OUT_CTL_ES_D BIT_ULL(30) | ||
| 136 | #define CNXK_VF_R_OUT_CTL_NSR_D BIT_ULL(29) | ||
| 137 | #define CNXK_VF_R_OUT_CTL_ROR_D BIT_ULL(28) | ||
| 138 | #define CNXK_VF_R_OUT_CTL_ES_P BIT_ULL(26) | ||
| 139 | #define CNXK_VF_R_OUT_CTL_NSR_P BIT_ULL(25) | ||
| 140 | #define CNXK_VF_R_OUT_CTL_ROR_P BIT_ULL(24) | ||
| 141 | #define CNXK_VF_R_OUT_CTL_IMODE BIT_ULL(23) | ||
| 142 | |||
| 143 | /* ##################### Mail Box Registers ########################## */ | ||
| 144 | /* SDP PF to VF Mailbox Data Register */ | ||
| 145 | #define CNXK_VF_SDP_R_MBOX_PF_VF_DATA_START 0x10210 | ||
| 146 | /* SDP Packet PF to VF Mailbox Interrupt Register */ | ||
| 147 | #define CNXK_VF_SDP_R_MBOX_PF_VF_INT_START 0x10220 | ||
| 148 | /* SDP VF to PF Mailbox Data Register */ | ||
| 149 | #define CNXK_VF_SDP_R_MBOX_VF_PF_DATA_START 0x10230 | ||
| 150 | |||
| 151 | #define CNXK_VF_SDP_R_MBOX_PF_VF_INT_ENAB BIT_ULL(1) | ||
| 152 | #define CNXK_VF_SDP_R_MBOX_PF_VF_INT_STATUS BIT_ULL(0) | ||
| 153 | |||
| 154 | #define CNXK_VF_SDP_R_MBOX_PF_VF_DATA(ring) \ | ||
| 155 | (CNXK_VF_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 156 | |||
| 157 | #define CNXK_VF_SDP_R_MBOX_PF_VF_INT(ring) \ | ||
| 158 | (CNXK_VF_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 159 | |||
| 160 | #define CNXK_VF_SDP_R_MBOX_VF_PF_DATA(ring) \ | ||
| 161 | (CNXK_VF_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_VF_RING_OFFSET)) | ||
| 162 | #endif /* _OCTEP_VF_REGS_CNXK_H_ */ | ||
| @@ -0,0 +1,511 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/etherdevice.h> | ||
| 10 | #include <linux/vmalloc.h> | ||
| 11 | |||
| 12 | #include "octep_vf_config.h" | ||
| 13 | #include "octep_vf_main.h" | ||
| 14 | |||
| 15 | static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq) | ||
| 16 | { | ||
| 17 | oq->host_read_idx = 0; | ||
| 18 | oq->host_refill_idx = 0; | ||
| 19 | oq->refill_count = 0; | ||
| 20 | oq->last_pkt_count = 0; | ||
| 21 | oq->pkts_pending = 0; | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * octep_vf_oq_fill_ring_buffers() - fill initial receive buffers for Rx ring. | ||
| 26 | * | ||
| 27 | * @oq: Octeon Rx queue data structure. | ||
| 28 | * | ||
| 29 | * Return: 0, if successfully filled receive buffers for all descriptors. | ||
| 30 | * -1, if failed to allocate a buffer or failed to map for DMA. | ||
| 31 | */ | ||
| 32 | static int octep_vf_oq_fill_ring_buffers(struct octep_vf_oq *oq) | ||
| 33 | { | ||
| 34 | struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring; | ||
| 35 | struct page *page; | ||
| 36 | u32 i; | ||
| 37 | |||
| 38 | for (i = 0; i < oq->max_count; i++) { | ||
| 39 | page = dev_alloc_page(); | ||
| 40 | if (unlikely(!page)) { | ||
| 41 | dev_err(oq->dev, "Rx buffer alloc failed\n"); | ||
| 42 | goto rx_buf_alloc_err; | ||
| 43 | } | ||
| 44 | desc_ring[i].buffer_ptr = dma_map_page(oq->dev, page, 0, | ||
| 45 | PAGE_SIZE, | ||
| 46 | DMA_FROM_DEVICE); | ||
| 47 | if (dma_mapping_error(oq->dev, desc_ring[i].buffer_ptr)) { | ||
| 48 | dev_err(oq->dev, | ||
| 49 | "OQ-%d buffer alloc: DMA mapping error!\n", | ||
| 50 | oq->q_no); | ||
| 51 | put_page(page); | ||
| 52 | goto dma_map_err; | ||
| 53 | } | ||
| 54 | oq->buff_info[i].page = page; | ||
| 55 | } | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | |||
| 59 | dma_map_err: | ||
| 60 | rx_buf_alloc_err: | ||
| 61 | while (i) { | ||
| 62 | i--; | ||
| 63 | dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr, PAGE_SIZE, DMA_FROM_DEVICE); | ||
| 64 | put_page(oq->buff_info[i].page); | ||
| 65 | oq->buff_info[i].page = NULL; | ||
| 66 | } | ||
| 67 | |||
| 68 | return -1; | ||
| 69 | } | ||
| 70 | |||
| 71 | /** | ||
| 72 | * octep_vf_oq_refill() - refill buffers for used Rx ring descriptors. | ||
| 73 | * | ||
| 74 | * @oct: Octeon device private data structure. | ||
| 75 | * @oq: Octeon Rx queue data structure. | ||
| 76 | * | ||
| 77 | * Return: number of descriptors successfully refilled with receive buffers. | ||
| 78 | */ | ||
| 79 | static int octep_vf_oq_refill(struct octep_vf_device *oct, struct octep_vf_oq *oq) | ||
| 80 | { | ||
| 81 | struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring; | ||
| 82 | struct page *page; | ||
| 83 | u32 refill_idx, i; | ||
| 84 | |||
| 85 | refill_idx = oq->host_refill_idx; | ||
| 86 | for (i = 0; i < oq->refill_count; i++) { | ||
| 87 | page = dev_alloc_page(); | ||
| 88 | if (unlikely(!page)) { | ||
| 89 | dev_err(oq->dev, "refill: rx buffer alloc failed\n"); | ||
| 90 | oq->stats.alloc_failures++; | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | |||
| 94 | desc_ring[refill_idx].buffer_ptr = dma_map_page(oq->dev, page, 0, | ||
| 95 | PAGE_SIZE, DMA_FROM_DEVICE); | ||
| 96 | if (dma_mapping_error(oq->dev, desc_ring[refill_idx].buffer_ptr)) { | ||
| 97 | dev_err(oq->dev, | ||
| 98 | "OQ-%d buffer refill: DMA mapping error!\n", | ||
| 99 | oq->q_no); | ||
| 100 | put_page(page); | ||
| 101 | oq->stats.alloc_failures++; | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | oq->buff_info[refill_idx].page = page; | ||
| 105 | refill_idx++; | ||
| 106 | if (refill_idx == oq->max_count) | ||
| 107 | refill_idx = 0; | ||
| 108 | } | ||
| 109 | oq->host_refill_idx = refill_idx; | ||
| 110 | oq->refill_count -= i; | ||
| 111 | |||
| 112 | return i; | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * octep_vf_setup_oq() - Setup a Rx queue. | ||
| 117 | * | ||
| 118 | * @oct: Octeon device private data structure. | ||
| 119 | * @q_no: Rx queue number to be setup. | ||
| 120 | * | ||
| 121 | * Allocate resources for a Rx queue. | ||
| 122 | */ | ||
| 123 | static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no) | ||
| 124 | { | ||
| 125 | struct octep_vf_oq *oq; | ||
| 126 | u32 desc_ring_size; | ||
| 127 | |||
| 128 | oq = vzalloc(sizeof(*oq)); | ||
| 129 | if (!oq) | ||
| 130 | goto create_oq_fail; | ||
| 131 | oct->oq[q_no] = oq; | ||
| 132 | |||
| 133 | oq->octep_vf_dev = oct; | ||
| 134 | oq->netdev = oct->netdev; | ||
| 135 | oq->dev = &oct->pdev->dev; | ||
| 136 | oq->q_no = q_no; | ||
| 137 | oq->max_count = CFG_GET_OQ_NUM_DESC(oct->conf); | ||
| 138 | oq->ring_size_mask = oq->max_count - 1; | ||
| 139 | oq->buffer_size = CFG_GET_OQ_BUF_SIZE(oct->conf); | ||
| 140 | oq->max_single_buffer_size = oq->buffer_size - OCTEP_VF_OQ_RESP_HW_SIZE; | ||
| 141 | |||
| 142 | /* When the hardware/firmware supports additional capabilities, | ||
| 143 | * additional header is filled-in by Octeon after length field in | ||
| 144 | * Rx packets. this header contains additional packet information. | ||
| 145 | */ | ||
| 146 | if (oct->fw_info.rx_ol_flags) | ||
| 147 | oq->max_single_buffer_size -= OCTEP_VF_OQ_RESP_HW_EXT_SIZE; | ||
| 148 | |||
| 149 | oq->refill_threshold = CFG_GET_OQ_REFILL_THRESHOLD(oct->conf); | ||
| 150 | |||
| 151 | desc_ring_size = oq->max_count * OCTEP_VF_OQ_DESC_SIZE; | ||
| 152 | oq->desc_ring = dma_alloc_coherent(oq->dev, desc_ring_size, | ||
| 153 | &oq->desc_ring_dma, GFP_KERNEL); | ||
| 154 | |||
| 155 | if (unlikely(!oq->desc_ring)) { | ||
| 156 | dev_err(oq->dev, | ||
| 157 | "Failed to allocate DMA memory for OQ-%d !!\n", q_no); | ||
| 158 | goto desc_dma_alloc_err; | ||
| 159 | } | ||
| 160 | |||
| 161 | oq->buff_info = vzalloc(oq->max_count * OCTEP_VF_OQ_RECVBUF_SIZE); | ||
| 162 | |||
| 163 | if (unlikely(!oq->buff_info)) { | ||
| 164 | dev_err(&oct->pdev->dev, | ||
| 165 | "Failed to allocate buffer info for OQ-%d\n", q_no); | ||
| 166 | goto buf_list_err; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (octep_vf_oq_fill_ring_buffers(oq)) | ||
| 170 | goto oq_fill_buff_err; | ||
| 171 | |||
| 172 | octep_vf_oq_reset_indices(oq); | ||
| 173 | oct->hw_ops.setup_oq_regs(oct, q_no); | ||
| 174 | oct->num_oqs++; | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | |||
| 178 | oq_fill_buff_err: | ||
| 179 | vfree(oq->buff_info); | ||
| 180 | oq->buff_info = NULL; | ||
| 181 | buf_list_err: | ||
| 182 | dma_free_coherent(oq->dev, desc_ring_size, | ||
| 183 | oq->desc_ring, oq->desc_ring_dma); | ||
| 184 | oq->desc_ring = NULL; | ||
| 185 | desc_dma_alloc_err: | ||
| 186 | vfree(oq); | ||
| 187 | oct->oq[q_no] = NULL; | ||
| 188 | create_oq_fail: | ||
| 189 | return -1; | ||
| 190 | } | ||
| 191 | |||
| 192 | /** | ||
| 193 | * octep_vf_oq_free_ring_buffers() - Free ring buffers. | ||
| 194 | * | ||
| 195 | * @oq: Octeon Rx queue data structure. | ||
| 196 | * | ||
| 197 | * Free receive buffers in unused Rx queue descriptors. | ||
| 198 | */ | ||
| 199 | static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq) | ||
| 200 | { | ||
| 201 | struct octep_vf_oq_desc_hw *desc_ring = oq->desc_ring; | ||
| 202 | int i; | ||
| 203 | |||
| 204 | if (!oq->desc_ring || !oq->buff_info) | ||
| 205 | return; | ||
| 206 | |||
| 207 | for (i = 0; i < oq->max_count; i++) { | ||
| 208 | if (oq->buff_info[i].page) { | ||
| 209 | dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr, | ||
| 210 | PAGE_SIZE, DMA_FROM_DEVICE); | ||
| 211 | put_page(oq->buff_info[i].page); | ||
| 212 | oq->buff_info[i].page = NULL; | ||
| 213 | desc_ring[i].buffer_ptr = 0; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | octep_vf_oq_reset_indices(oq); | ||
| 217 | } | ||
| 218 | |||
| 219 | /** | ||
| 220 | * octep_vf_free_oq() - Free Rx queue resources. | ||
| 221 | * | ||
| 222 | * @oq: Octeon Rx queue data structure. | ||
| 223 | * | ||
| 224 | * Free all resources of a Rx queue. | ||
| 225 | */ | ||
| 226 | static int octep_vf_free_oq(struct octep_vf_oq *oq) | ||
| 227 | { | ||
| 228 | struct octep_vf_device *oct = oq->octep_vf_dev; | ||
| 229 | int q_no = oq->q_no; | ||
| 230 | |||
| 231 | octep_vf_oq_free_ring_buffers(oq); | ||
| 232 | |||
| 233 | if (oq->buff_info) | ||
| 234 | vfree(oq->buff_info); | ||
| 235 | |||
| 236 | if (oq->desc_ring) | ||
| 237 | dma_free_coherent(oq->dev, | ||
| 238 | oq->max_count * OCTEP_VF_OQ_DESC_SIZE, | ||
| 239 | oq->desc_ring, oq->desc_ring_dma); | ||
| 240 | |||
| 241 | vfree(oq); | ||
| 242 | oct->oq[q_no] = NULL; | ||
| 243 | oct->num_oqs--; | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * octep_vf_setup_oqs() - setup resources for all Rx queues. | ||
| 249 | * | ||
| 250 | * @oct: Octeon device private data structure. | ||
| 251 | */ | ||
| 252 | int octep_vf_setup_oqs(struct octep_vf_device *oct) | ||
| 253 | { | ||
| 254 | int i, retval = 0; | ||
| 255 | |||
| 256 | oct->num_oqs = 0; | ||
| 257 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { | ||
| 258 | retval = octep_vf_setup_oq(oct, i); | ||
| 259 | if (retval) { | ||
| 260 | dev_err(&oct->pdev->dev, | ||
| 261 | "Failed to setup OQ(RxQ)-%d.\n", i); | ||
| 262 | goto oq_setup_err; | ||
| 263 | } | ||
| 264 | dev_dbg(&oct->pdev->dev, "Successfully setup OQ(RxQ)-%d.\n", i); | ||
| 265 | } | ||
| 266 | |||
| 267 | return 0; | ||
| 268 | |||
| 269 | oq_setup_err: | ||
| 270 | while (i) { | ||
| 271 | i--; | ||
| 272 | octep_vf_free_oq(oct->oq[i]); | ||
| 273 | } | ||
| 274 | return -1; | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * octep_vf_oq_dbell_init() - Initialize Rx queue doorbell. | ||
| 279 | * | ||
| 280 | * @oct: Octeon device private data structure. | ||
| 281 | * | ||
| 282 | * Write number of descriptors to Rx queue doorbell register. | ||
| 283 | */ | ||
| 284 | void octep_vf_oq_dbell_init(struct octep_vf_device *oct) | ||
| 285 | { | ||
| 286 | int i; | ||
| 287 | |||
| 288 | for (i = 0; i < oct->num_oqs; i++) | ||
| 289 | writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg); | ||
| 290 | } | ||
| 291 | |||
| 292 | /** | ||
| 293 | * octep_vf_free_oqs() - Free resources of all Rx queues. | ||
| 294 | * | ||
| 295 | * @oct: Octeon device private data structure. | ||
| 296 | */ | ||
| 297 | void octep_vf_free_oqs(struct octep_vf_device *oct) | ||
| 298 | { | ||
| 299 | int i; | ||
| 300 | |||
| 301 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { | ||
| 302 | if (!oct->oq[i]) | ||
| 303 | continue; | ||
| 304 | octep_vf_free_oq(oct->oq[i]); | ||
| 305 | dev_dbg(&oct->pdev->dev, | ||
| 306 | "Successfully freed OQ(RxQ)-%d.\n", i); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | /** | ||
| 311 | * octep_vf_oq_check_hw_for_pkts() - Check for new Rx packets. | ||
| 312 | * | ||
| 313 | * @oct: Octeon device private data structure. | ||
| 314 | * @oq: Octeon Rx queue data structure. | ||
| 315 | * | ||
| 316 | * Return: packets received after previous check. | ||
| 317 | */ | ||
| 318 | static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct, | ||
| 319 | struct octep_vf_oq *oq) | ||
| 320 | { | ||
| 321 | u32 pkt_count, new_pkts; | ||
| 322 | |||
| 323 | pkt_count = readl(oq->pkts_sent_reg); | ||
| 324 | new_pkts = pkt_count - oq->last_pkt_count; | ||
| 325 | |||
| 326 | /* Clear the hardware packets counter register if the rx queue is | ||
| 327 | * being processed continuously with-in a single interrupt and | ||
| 328 | * reached half its max value. | ||
| 329 | * this counter is not cleared every time read, to save write cycles. | ||
| 330 | */ | ||
| 331 | if (unlikely(pkt_count > 0xF0000000U)) { | ||
| 332 | writel(pkt_count, oq->pkts_sent_reg); | ||
| 333 | pkt_count = readl(oq->pkts_sent_reg); | ||
| 334 | new_pkts += pkt_count; | ||
| 335 | } | ||
| 336 | oq->last_pkt_count = pkt_count; | ||
| 337 | oq->pkts_pending += new_pkts; | ||
| 338 | return new_pkts; | ||
| 339 | } | ||
| 340 | |||
| 341 | /** | ||
| 342 | * __octep_vf_oq_process_rx() - Process hardware Rx queue and push to stack. | ||
| 343 | * | ||
| 344 | * @oct: Octeon device private data structure. | ||
| 345 | * @oq: Octeon Rx queue data structure. | ||
| 346 | * @pkts_to_process: number of packets to be processed. | ||
| 347 | * | ||
| 348 | * Process the new packets in Rx queue. | ||
| 349 | * Packets larger than single Rx buffer arrive in consecutive descriptors. | ||
| 350 | * But, count returned by the API only accounts full packets, not fragments. | ||
| 351 | * | ||
| 352 | * Return: number of packets processed and pushed to stack. | ||
| 353 | */ | ||
| 354 | static int __octep_vf_oq_process_rx(struct octep_vf_device *oct, | ||
| 355 | struct octep_vf_oq *oq, u16 pkts_to_process) | ||
| 356 | { | ||
| 357 | struct octep_vf_oq_resp_hw_ext *resp_hw_ext = NULL; | ||
| 358 | netdev_features_t feat = oq->netdev->features; | ||
| 359 | struct octep_vf_rx_buffer *buff_info; | ||
| 360 | struct octep_vf_oq_resp_hw *resp_hw; | ||
| 361 | u32 pkt, rx_bytes, desc_used; | ||
| 362 | u16 data_offset, rx_ol_flags; | ||
| 363 | struct sk_buff *skb; | ||
| 364 | u32 read_idx; | ||
| 365 | |||
| 366 | read_idx = oq->host_read_idx; | ||
| 367 | rx_bytes = 0; | ||
| 368 | desc_used = 0; | ||
| 369 | for (pkt = 0; pkt < pkts_to_process; pkt++) { | ||
| 370 | buff_info = (struct octep_vf_rx_buffer *)&oq->buff_info[read_idx]; | ||
| 371 | dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr, | ||
| 372 | PAGE_SIZE, DMA_FROM_DEVICE); | ||
| 373 | resp_hw = page_address(buff_info->page); | ||
| 374 | buff_info->page = NULL; | ||
| 375 | |||
| 376 | /* Swap the length field that is in Big-Endian to CPU */ | ||
| 377 | buff_info->len = be64_to_cpu(resp_hw->length); | ||
| 378 | if (oct->fw_info.rx_ol_flags) { | ||
| 379 | /* Extended response header is immediately after | ||
| 380 | * response header (resp_hw) | ||
| 381 | */ | ||
| 382 | resp_hw_ext = (struct octep_vf_oq_resp_hw_ext *) | ||
| 383 | (resp_hw + 1); | ||
| 384 | buff_info->len -= OCTEP_VF_OQ_RESP_HW_EXT_SIZE; | ||
| 385 | /* Packet Data is immediately after | ||
| 386 | * extended response header. | ||
| 387 | */ | ||
| 388 | data_offset = OCTEP_VF_OQ_RESP_HW_SIZE + | ||
| 389 | OCTEP_VF_OQ_RESP_HW_EXT_SIZE; | ||
| 390 | rx_ol_flags = resp_hw_ext->rx_ol_flags; | ||
| 391 | } else { | ||
| 392 | /* Data is immediately after | ||
| 393 | * Hardware Rx response header. | ||
| 394 | */ | ||
| 395 | data_offset = OCTEP_VF_OQ_RESP_HW_SIZE; | ||
| 396 | rx_ol_flags = 0; | ||
| 397 | } | ||
| 398 | rx_bytes += buff_info->len; | ||
| 399 | |||
| 400 | if (buff_info->len <= oq->max_single_buffer_size) { | ||
| 401 | skb = build_skb((void *)resp_hw, PAGE_SIZE); | ||
| 402 | skb_reserve(skb, data_offset); | ||
| 403 | skb_put(skb, buff_info->len); | ||
| 404 | read_idx++; | ||
| 405 | desc_used++; | ||
| 406 | if (read_idx == oq->max_count) | ||
| 407 | read_idx = 0; | ||
| 408 | } else { | ||
| 409 | struct skb_shared_info *shinfo; | ||
| 410 | u16 data_len; | ||
| 411 | |||
| 412 | skb = build_skb((void *)resp_hw, PAGE_SIZE); | ||
| 413 | skb_reserve(skb, data_offset); | ||
| 414 | /* Head fragment includes response header(s); | ||
| 415 | * subsequent fragments contains only data. | ||
| 416 | */ | ||
| 417 | skb_put(skb, oq->max_single_buffer_size); | ||
| 418 | read_idx++; | ||
| 419 | desc_used++; | ||
| 420 | if (read_idx == oq->max_count) | ||
| 421 | read_idx = 0; | ||
| 422 | |||
| 423 | shinfo = skb_shinfo(skb); | ||
| 424 | data_len = buff_info->len - oq->max_single_buffer_size; | ||
| 425 | while (data_len) { | ||
| 426 | dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr, | ||
| 427 | PAGE_SIZE, DMA_FROM_DEVICE); | ||
| 428 | buff_info = (struct octep_vf_rx_buffer *) | ||
| 429 | &oq->buff_info[read_idx]; | ||
| 430 | if (data_len < oq->buffer_size) { | ||
| 431 | buff_info->len = data_len; | ||
| 432 | data_len = 0; | ||
| 433 | } else { | ||
| 434 | buff_info->len = oq->buffer_size; | ||
| 435 | data_len -= oq->buffer_size; | ||
| 436 | } | ||
| 437 | |||
| 438 | skb_add_rx_frag(skb, shinfo->nr_frags, | ||
| 439 | buff_info->page, 0, | ||
| 440 | buff_info->len, | ||
| 441 | buff_info->len); | ||
| 442 | buff_info->page = NULL; | ||
| 443 | read_idx++; | ||
| 444 | desc_used++; | ||
| 445 | if (read_idx == oq->max_count) | ||
| 446 | read_idx = 0; | ||
| 447 | } | ||
| 448 | } | ||
| 449 | |||
| 450 | skb->dev = oq->netdev; | ||
| 451 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
| 452 | if (feat & NETIF_F_RXCSUM && | ||
| 453 | OCTEP_VF_RX_CSUM_VERIFIED(rx_ol_flags)) | ||
| 454 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 455 | else | ||
| 456 | skb->ip_summed = CHECKSUM_NONE; | ||
| 457 | napi_gro_receive(oq->napi, skb); | ||
| 458 | } | ||
| 459 | |||
| 460 | oq->host_read_idx = read_idx; | ||
| 461 | oq->refill_count += desc_used; | ||
| 462 | oq->stats.packets += pkt; | ||
| 463 | oq->stats.bytes += rx_bytes; | ||
| 464 | |||
| 465 | return pkt; | ||
| 466 | } | ||
| 467 | |||
| 468 | /** | ||
| 469 | * octep_vf_oq_process_rx() - Process Rx queue. | ||
| 470 | * | ||
| 471 | * @oq: Octeon Rx queue data structure. | ||
| 472 | * @budget: max number of packets can be processed in one invocation. | ||
| 473 | * | ||
| 474 | * Check for newly received packets and process them. | ||
| 475 | * Keeps checking for new packets until budget is used or no new packets seen. | ||
| 476 | * | ||
| 477 | * Return: number of packets processed. | ||
| 478 | */ | ||
| 479 | int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget) | ||
| 480 | { | ||
| 481 | u32 pkts_available, pkts_processed, total_pkts_processed; | ||
| 482 | struct octep_vf_device *oct = oq->octep_vf_dev; | ||
| 483 | |||
| 484 | pkts_available = 0; | ||
| 485 | pkts_processed = 0; | ||
| 486 | total_pkts_processed = 0; | ||
| 487 | while (total_pkts_processed < budget) { | ||
| 488 | /* update pending count only when current one exhausted */ | ||
| 489 | if (oq->pkts_pending == 0) | ||
| 490 | octep_vf_oq_check_hw_for_pkts(oct, oq); | ||
| 491 | pkts_available = min(budget - total_pkts_processed, | ||
| 492 | oq->pkts_pending); | ||
| 493 | if (!pkts_available) | ||
| 494 | break; | ||
| 495 | |||
| 496 | pkts_processed = __octep_vf_oq_process_rx(oct, oq, | ||
| 497 | pkts_available); | ||
| 498 | oq->pkts_pending -= pkts_processed; | ||
| 499 | total_pkts_processed += pkts_processed; | ||
| 500 | } | ||
| 501 | |||
| 502 | if (oq->refill_count >= oq->refill_threshold) { | ||
| 503 | u32 desc_refilled = octep_vf_oq_refill(oct, oq); | ||
| 504 | |||
| 505 | /* flush pending writes before updating credits */ | ||
| 506 | smp_wmb(); | ||
| 507 | writel(desc_refilled, oq->pkts_credit_reg); | ||
| 508 | } | ||
| 509 | |||
| 510 | return total_pkts_processed; | ||
| 511 | } | ||
| @@ -0,0 +1,224 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _OCTEP_VF_RX_H_ | ||
| 9 | #define _OCTEP_VF_RX_H_ | ||
| 10 | |||
| 11 | /* struct octep_vf_oq_desc_hw - Octeon Hardware OQ descriptor format. | ||
| 12 | * | ||
| 13 | * The descriptor ring is made of descriptors which have 2 64-bit values: | ||
| 14 | * | ||
| 15 | * @buffer_ptr: DMA address of the skb->data | ||
| 16 | * @info_ptr: DMA address of host memory, used to update pkt count by hw. | ||
| 17 | * This is currently unused to save pci writes. | ||
| 18 | */ | ||
| 19 | struct octep_vf_oq_desc_hw { | ||
| 20 | dma_addr_t buffer_ptr; | ||
| 21 | u64 info_ptr; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static_assert(sizeof(struct octep_vf_oq_desc_hw) == 16); | ||
| 25 | |||
| 26 | #define OCTEP_VF_OQ_DESC_SIZE (sizeof(struct octep_vf_oq_desc_hw)) | ||
| 27 | |||
| 28 | /* Rx offload flags */ | ||
| 29 | #define OCTEP_VF_RX_OFFLOAD_VLAN_STRIP BIT(0) | ||
| 30 | #define OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM BIT(1) | ||
| 31 | #define OCTEP_VF_RX_OFFLOAD_UDP_CKSUM BIT(2) | ||
| 32 | #define OCTEP_VF_RX_OFFLOAD_TCP_CKSUM BIT(3) | ||
| 33 | |||
| 34 | #define OCTEP_VF_RX_OFFLOAD_CKSUM (OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM | \ | ||
| 35 | OCTEP_VF_RX_OFFLOAD_UDP_CKSUM | \ | ||
| 36 | OCTEP_VF_RX_OFFLOAD_TCP_CKSUM) | ||
| 37 | |||
| 38 | #define OCTEP_VF_RX_IP_CSUM(flags) ((flags) & \ | ||
| 39 | (OCTEP_VF_RX_OFFLOAD_IPV4_CKSUM | \ | ||
| 40 | OCTEP_VF_RX_OFFLOAD_TCP_CKSUM | \ | ||
| 41 | OCTEP_VF_RX_OFFLOAD_UDP_CKSUM)) | ||
| 42 | |||
| 43 | /* bit 0 is vlan strip */ | ||
| 44 | #define OCTEP_VF_RX_CSUM_IP_VERIFIED BIT(1) | ||
| 45 | #define OCTEP_VF_RX_CSUM_L4_VERIFIED BIT(2) | ||
| 46 | |||
| 47 | #define OCTEP_VF_RX_CSUM_VERIFIED(flags) ((flags) & \ | ||
| 48 | (OCTEP_VF_RX_CSUM_L4_VERIFIED | \ | ||
| 49 | OCTEP_VF_RX_CSUM_IP_VERIFIED)) | ||
| 50 | |||
| 51 | /* Extended Response Header in packet data received from Hardware. | ||
| 52 | * Includes metadata like checksum status. | ||
| 53 | * this is valid only if hardware/firmware published support for this. | ||
| 54 | * This is at offset 0 of packet data (skb->data). | ||
| 55 | */ | ||
| 56 | struct octep_vf_oq_resp_hw_ext { | ||
| 57 | /* Reserved. */ | ||
| 58 | u64 rsvd:48; | ||
| 59 | |||
| 60 | /* rx offload flags */ | ||
| 61 | u16 rx_ol_flags; | ||
| 62 | }; | ||
| 63 | |||
| 64 | static_assert(sizeof(struct octep_vf_oq_resp_hw_ext) == 8); | ||
| 65 | |||
| 66 | #define OCTEP_VF_OQ_RESP_HW_EXT_SIZE (sizeof(struct octep_vf_oq_resp_hw_ext)) | ||
| 67 | |||
| 68 | /* Length of Rx packet DMA'ed by Octeon to Host. | ||
| 69 | * this is in bigendian; so need to be converted to cpu endian. | ||
| 70 | * Octeon writes this at the beginning of Rx buffer (skb->data). | ||
| 71 | */ | ||
| 72 | struct octep_vf_oq_resp_hw { | ||
| 73 | /* The Length of the packet. */ | ||
| 74 | __be64 length; | ||
| 75 | }; | ||
| 76 | |||
| 77 | static_assert(sizeof(struct octep_vf_oq_resp_hw) == 8); | ||
| 78 | |||
| 79 | #define OCTEP_VF_OQ_RESP_HW_SIZE (sizeof(struct octep_vf_oq_resp_hw)) | ||
| 80 | |||
| 81 | /* Pointer to data buffer. | ||
| 82 | * Driver keeps a pointer to the data buffer that it made available to | ||
| 83 | * the Octeon device. Since the descriptor ring keeps physical (bus) | ||
| 84 | * addresses, this field is required for the driver to keep track of | ||
| 85 | * the virtual address pointers. The fields are operated by | ||
| 86 | * OS-dependent routines. | ||
| 87 | */ | ||
| 88 | struct octep_vf_rx_buffer { | ||
| 89 | struct page *page; | ||
| 90 | |||
| 91 | /* length from rx hardware descriptor after converting to cpu endian */ | ||
| 92 | u64 len; | ||
| 93 | }; | ||
| 94 | |||
| 95 | #define OCTEP_VF_OQ_RECVBUF_SIZE (sizeof(struct octep_vf_rx_buffer)) | ||
| 96 | |||
| 97 | /* Output Queue statistics. Each output queue has four stats fields. */ | ||
| 98 | struct octep_vf_oq_stats { | ||
| 99 | /* Number of packets received from the Device. */ | ||
| 100 | u64 packets; | ||
| 101 | |||
| 102 | /* Number of bytes received from the Device. */ | ||
| 103 | u64 bytes; | ||
| 104 | |||
| 105 | /* Number of times failed to allocate buffers. */ | ||
| 106 | u64 alloc_failures; | ||
| 107 | }; | ||
| 108 | |||
| 109 | #define OCTEP_VF_OQ_STATS_SIZE (sizeof(struct octep_vf_oq_stats)) | ||
| 110 | |||
| 111 | /* Hardware interface Rx statistics */ | ||
| 112 | struct octep_vf_iface_rx_stats { | ||
| 113 | /* Received packets */ | ||
| 114 | u64 pkts; | ||
| 115 | |||
| 116 | /* Octets of received packets */ | ||
| 117 | u64 octets; | ||
| 118 | |||
| 119 | /* Received PAUSE and Control packets */ | ||
| 120 | u64 pause_pkts; | ||
| 121 | |||
| 122 | /* Received PAUSE and Control octets */ | ||
| 123 | u64 pause_octets; | ||
| 124 | |||
| 125 | /* Filtered DMAC0 packets */ | ||
| 126 | u64 dmac0_pkts; | ||
| 127 | |||
| 128 | /* Filtered DMAC0 octets */ | ||
| 129 | u64 dmac0_octets; | ||
| 130 | |||
| 131 | /* Packets dropped due to RX FIFO full */ | ||
| 132 | u64 dropped_pkts_fifo_full; | ||
| 133 | |||
| 134 | /* Octets dropped due to RX FIFO full */ | ||
| 135 | u64 dropped_octets_fifo_full; | ||
| 136 | |||
| 137 | /* Error packets */ | ||
| 138 | u64 err_pkts; | ||
| 139 | |||
| 140 | /* Filtered DMAC1 packets */ | ||
| 141 | u64 dmac1_pkts; | ||
| 142 | |||
| 143 | /* Filtered DMAC1 octets */ | ||
| 144 | u64 dmac1_octets; | ||
| 145 | |||
| 146 | /* NCSI-bound packets dropped */ | ||
| 147 | u64 ncsi_dropped_pkts; | ||
| 148 | |||
| 149 | /* NCSI-bound octets dropped */ | ||
| 150 | u64 ncsi_dropped_octets; | ||
| 151 | |||
| 152 | /* Multicast packets received. */ | ||
| 153 | u64 mcast_pkts; | ||
| 154 | |||
| 155 | /* Broadcast packets received. */ | ||
| 156 | u64 bcast_pkts; | ||
| 157 | |||
| 158 | }; | ||
| 159 | |||
| 160 | /* The Descriptor Ring Output Queue structure. | ||
| 161 | * This structure has all the information required to implement a | ||
| 162 | * Octeon OQ. | ||
| 163 | */ | ||
| 164 | struct octep_vf_oq { | ||
| 165 | u32 q_no; | ||
| 166 | |||
| 167 | struct octep_vf_device *octep_vf_dev; | ||
| 168 | struct net_device *netdev; | ||
| 169 | struct device *dev; | ||
| 170 | |||
| 171 | struct napi_struct *napi; | ||
| 172 | |||
| 173 | /* The receive buffer list. This list has the virtual addresses | ||
| 174 | * of the buffers. | ||
| 175 | */ | ||
| 176 | struct octep_vf_rx_buffer *buff_info; | ||
| 177 | |||
| 178 | /* Pointer to the mapped packet credit register. | ||
| 179 | * Host writes number of info/buffer ptrs available to this register | ||
| 180 | */ | ||
| 181 | u8 __iomem *pkts_credit_reg; | ||
| 182 | |||
| 183 | /* Pointer to the mapped packet sent register. | ||
| 184 | * Octeon writes the number of packets DMA'ed to host memory | ||
| 185 | * in this register. | ||
| 186 | */ | ||
| 187 | u8 __iomem *pkts_sent_reg; | ||
| 188 | |||
| 189 | /* Statistics for this OQ. */ | ||
| 190 | struct octep_vf_oq_stats stats; | ||
| 191 | |||
| 192 | /* Packets pending to be processed */ | ||
| 193 | u32 pkts_pending; | ||
| 194 | u32 last_pkt_count; | ||
| 195 | |||
| 196 | /* Index in the ring where the driver should read the next packet */ | ||
| 197 | u32 host_read_idx; | ||
| 198 | |||
| 199 | /* Number of descriptors in this ring. */ | ||
| 200 | u32 max_count; | ||
| 201 | u32 ring_size_mask; | ||
| 202 | |||
| 203 | /* The number of descriptors pending refill. */ | ||
| 204 | u32 refill_count; | ||
| 205 | |||
| 206 | /* Index in the ring where the driver will refill the | ||
| 207 | * descriptor's buffer | ||
| 208 | */ | ||
| 209 | u32 host_refill_idx; | ||
| 210 | u32 refill_threshold; | ||
| 211 | |||
| 212 | /* The size of each buffer pointed by the buffer pointer. */ | ||
| 213 | u32 buffer_size; | ||
| 214 | u32 max_single_buffer_size; | ||
| 215 | |||
| 216 | /* The 8B aligned descriptor ring starts at this address. */ | ||
| 217 | struct octep_vf_oq_desc_hw *desc_ring; | ||
| 218 | |||
| 219 | /* DMA mapped address of the OQ descriptor ring. */ | ||
| 220 | dma_addr_t desc_ring_dma; | ||
| 221 | }; | ||
| 222 | |||
| 223 | #define OCTEP_VF_OQ_SIZE (sizeof(struct octep_vf_oq)) | ||
| 224 | #endif /* _OCTEP_VF_RX_H_ */ | ||
| @@ -0,0 +1,331 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/pci.h> | ||
| 9 | #include <linux/etherdevice.h> | ||
| 10 | #include <linux/vmalloc.h> | ||
| 11 | |||
| 12 | #include "octep_vf_config.h" | ||
| 13 | #include "octep_vf_main.h" | ||
| 14 | |||
| 15 | /* Reset various index of Tx queue data structure. */ | ||
| 16 | static void octep_vf_iq_reset_indices(struct octep_vf_iq *iq) | ||
| 17 | { | ||
| 18 | iq->fill_cnt = 0; | ||
| 19 | iq->host_write_index = 0; | ||
| 20 | iq->octep_vf_read_index = 0; | ||
| 21 | iq->flush_index = 0; | ||
| 22 | iq->pkts_processed = 0; | ||
| 23 | iq->pkt_in_done = 0; | ||
| 24 | } | ||
| 25 | |||
| 26 | /** | ||
| 27 | * octep_vf_iq_process_completions() - Process Tx queue completions. | ||
| 28 | * | ||
| 29 | * @iq: Octeon Tx queue data structure. | ||
| 30 | * @budget: max number of completions to be processed in one invocation. | ||
| 31 | */ | ||
| 32 | int octep_vf_iq_process_completions(struct octep_vf_iq *iq, u16 budget) | ||
| 33 | { | ||
| 34 | u32 compl_pkts, compl_bytes, compl_sg; | ||
| 35 | struct octep_vf_device *oct = iq->octep_vf_dev; | ||
| 36 | struct octep_vf_tx_buffer *tx_buffer; | ||
| 37 | struct skb_shared_info *shinfo; | ||
| 38 | u32 fi = iq->flush_index; | ||
| 39 | struct sk_buff *skb; | ||
| 40 | u8 frags, i; | ||
| 41 | |||
| 42 | compl_pkts = 0; | ||
| 43 | compl_sg = 0; | ||
| 44 | compl_bytes = 0; | ||
| 45 | iq->octep_vf_read_index = oct->hw_ops.update_iq_read_idx(iq); | ||
| 46 | |||
| 47 | while (likely(budget && (fi != iq->octep_vf_read_index))) { | ||
| 48 | tx_buffer = iq->buff_info + fi; | ||
| 49 | skb = tx_buffer->skb; | ||
| 50 | |||
| 51 | fi++; | ||
| 52 | if (unlikely(fi == iq->max_count)) | ||
| 53 | fi = 0; | ||
| 54 | compl_bytes += skb->len; | ||
| 55 | compl_pkts++; | ||
| 56 | budget--; | ||
| 57 | |||
| 58 | if (!tx_buffer->gather) { | ||
| 59 | dma_unmap_single(iq->dev, tx_buffer->dma, | ||
| 60 | tx_buffer->skb->len, DMA_TO_DEVICE); | ||
| 61 | dev_kfree_skb_any(skb); | ||
| 62 | continue; | ||
| 63 | } | ||
| 64 | |||
| 65 | /* Scatter/Gather */ | ||
| 66 | shinfo = skb_shinfo(skb); | ||
| 67 | frags = shinfo->nr_frags; | ||
| 68 | compl_sg++; | ||
| 69 | |||
| 70 | dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0], | ||
| 71 | tx_buffer->sglist[0].len[3], DMA_TO_DEVICE); | ||
| 72 | |||
| 73 | i = 1; /* entry 0 is main skb, unmapped above */ | ||
| 74 | while (frags--) { | ||
| 75 | dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], | ||
| 76 | tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE); | ||
| 77 | i++; | ||
| 78 | } | ||
| 79 | |||
| 80 | dev_kfree_skb_any(skb); | ||
| 81 | } | ||
| 82 | |||
| 83 | iq->pkts_processed += compl_pkts; | ||
| 84 | iq->stats.instr_completed += compl_pkts; | ||
| 85 | iq->stats.bytes_sent += compl_bytes; | ||
| 86 | iq->stats.sgentry_sent += compl_sg; | ||
| 87 | iq->flush_index = fi; | ||
| 88 | |||
| 89 | netdev_tx_completed_queue(iq->netdev_q, compl_pkts, compl_bytes); | ||
| 90 | |||
| 91 | if (unlikely(__netif_subqueue_stopped(iq->netdev, iq->q_no)) && | ||
| 92 | (IQ_INSTR_SPACE(iq) > | ||
| 93 | OCTEP_VF_WAKE_QUEUE_THRESHOLD)) | ||
| 94 | netif_wake_subqueue(iq->netdev, iq->q_no); | ||
| 95 | return !budget; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * octep_vf_iq_free_pending() - Free Tx buffers for pending completions. | ||
| 100 | * | ||
| 101 | * @iq: Octeon Tx queue data structure. | ||
| 102 | */ | ||
| 103 | static void octep_vf_iq_free_pending(struct octep_vf_iq *iq) | ||
| 104 | { | ||
| 105 | struct octep_vf_tx_buffer *tx_buffer; | ||
| 106 | struct skb_shared_info *shinfo; | ||
| 107 | u32 fi = iq->flush_index; | ||
| 108 | struct sk_buff *skb; | ||
| 109 | u8 frags, i; | ||
| 110 | |||
| 111 | while (fi != iq->host_write_index) { | ||
| 112 | tx_buffer = iq->buff_info + fi; | ||
| 113 | skb = tx_buffer->skb; | ||
| 114 | |||
| 115 | fi++; | ||
| 116 | if (unlikely(fi == iq->max_count)) | ||
| 117 | fi = 0; | ||
| 118 | |||
| 119 | if (!tx_buffer->gather) { | ||
| 120 | dma_unmap_single(iq->dev, tx_buffer->dma, | ||
| 121 | tx_buffer->skb->len, DMA_TO_DEVICE); | ||
| 122 | dev_kfree_skb_any(skb); | ||
| 123 | continue; | ||
| 124 | } | ||
| 125 | |||
| 126 | /* Scatter/Gather */ | ||
| 127 | shinfo = skb_shinfo(skb); | ||
| 128 | frags = shinfo->nr_frags; | ||
| 129 | |||
| 130 | dma_unmap_single(iq->dev, | ||
| 131 | tx_buffer->sglist[0].dma_ptr[0], | ||
| 132 | tx_buffer->sglist[0].len[0], | ||
| 133 | DMA_TO_DEVICE); | ||
| 134 | |||
| 135 | i = 1; /* entry 0 is main skb, unmapped above */ | ||
| 136 | while (frags--) { | ||
| 137 | dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], | ||
| 138 | tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE); | ||
| 139 | i++; | ||
| 140 | } | ||
| 141 | |||
| 142 | dev_kfree_skb_any(skb); | ||
| 143 | } | ||
| 144 | |||
| 145 | iq->flush_index = fi; | ||
| 146 | netdev_tx_reset_queue(netdev_get_tx_queue(iq->netdev, iq->q_no)); | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * octep_vf_clean_iqs() - Clean Tx queues to shutdown the device. | ||
| 151 | * | ||
| 152 | * @oct: Octeon device private data structure. | ||
| 153 | * | ||
| 154 | * Free the buffers in Tx queue descriptors pending completion and | ||
| 155 | * reset queue indices | ||
| 156 | */ | ||
| 157 | void octep_vf_clean_iqs(struct octep_vf_device *oct) | ||
| 158 | { | ||
| 159 | int i; | ||
| 160 | |||
| 161 | for (i = 0; i < oct->num_iqs; i++) { | ||
| 162 | octep_vf_iq_free_pending(oct->iq[i]); | ||
| 163 | octep_vf_iq_reset_indices(oct->iq[i]); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * octep_vf_setup_iq() - Setup a Tx queue. | ||
| 169 | * | ||
| 170 | * @oct: Octeon device private data structure. | ||
| 171 | * @q_no: Tx queue number to be setup. | ||
| 172 | * | ||
| 173 | * Allocate resources for a Tx queue. | ||
| 174 | */ | ||
| 175 | static int octep_vf_setup_iq(struct octep_vf_device *oct, int q_no) | ||
| 176 | { | ||
| 177 | u32 desc_ring_size, buff_info_size, sglist_size; | ||
| 178 | struct octep_vf_iq *iq; | ||
| 179 | int i; | ||
| 180 | |||
| 181 | iq = vzalloc(sizeof(*iq)); | ||
| 182 | if (!iq) | ||
| 183 | goto iq_alloc_err; | ||
| 184 | oct->iq[q_no] = iq; | ||
| 185 | |||
| 186 | iq->octep_vf_dev = oct; | ||
| 187 | iq->netdev = oct->netdev; | ||
| 188 | iq->dev = &oct->pdev->dev; | ||
| 189 | iq->q_no = q_no; | ||
| 190 | iq->max_count = CFG_GET_IQ_NUM_DESC(oct->conf); | ||
| 191 | iq->ring_size_mask = iq->max_count - 1; | ||
| 192 | iq->fill_threshold = CFG_GET_IQ_DB_MIN(oct->conf); | ||
| 193 | iq->netdev_q = netdev_get_tx_queue(iq->netdev, q_no); | ||
| 194 | |||
| 195 | /* Allocate memory for hardware queue descriptors */ | ||
| 196 | desc_ring_size = OCTEP_VF_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf); | ||
| 197 | iq->desc_ring = dma_alloc_coherent(iq->dev, desc_ring_size, | ||
| 198 | &iq->desc_ring_dma, GFP_KERNEL); | ||
| 199 | if (unlikely(!iq->desc_ring)) { | ||
| 200 | dev_err(iq->dev, | ||
| 201 | "Failed to allocate DMA memory for IQ-%d\n", q_no); | ||
| 202 | goto desc_dma_alloc_err; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* Allocate memory for hardware SGLIST descriptors */ | ||
| 206 | sglist_size = OCTEP_VF_SGLIST_SIZE_PER_PKT * | ||
| 207 | CFG_GET_IQ_NUM_DESC(oct->conf); | ||
| 208 | iq->sglist = dma_alloc_coherent(iq->dev, sglist_size, | ||
| 209 | &iq->sglist_dma, GFP_KERNEL); | ||
| 210 | if (unlikely(!iq->sglist)) { | ||
| 211 | dev_err(iq->dev, | ||
| 212 | "Failed to allocate DMA memory for IQ-%d SGLIST\n", | ||
| 213 | q_no); | ||
| 214 | goto sglist_alloc_err; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* allocate memory to manage Tx packets pending completion */ | ||
| 218 | buff_info_size = OCTEP_VF_IQ_TXBUFF_INFO_SIZE * iq->max_count; | ||
| 219 | iq->buff_info = vzalloc(buff_info_size); | ||
| 220 | if (!iq->buff_info) { | ||
| 221 | dev_err(iq->dev, | ||
| 222 | "Failed to allocate buff info for IQ-%d\n", q_no); | ||
| 223 | goto buff_info_err; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* Setup sglist addresses in tx_buffer entries */ | ||
| 227 | for (i = 0; i < CFG_GET_IQ_NUM_DESC(oct->conf); i++) { | ||
| 228 | struct octep_vf_tx_buffer *tx_buffer; | ||
| 229 | |||
| 230 | tx_buffer = &iq->buff_info[i]; | ||
| 231 | tx_buffer->sglist = | ||
| 232 | &iq->sglist[i * OCTEP_VF_SGLIST_ENTRIES_PER_PKT]; | ||
| 233 | tx_buffer->sglist_dma = | ||
| 234 | iq->sglist_dma + (i * OCTEP_VF_SGLIST_SIZE_PER_PKT); | ||
| 235 | } | ||
| 236 | |||
| 237 | octep_vf_iq_reset_indices(iq); | ||
| 238 | oct->hw_ops.setup_iq_regs(oct, q_no); | ||
| 239 | |||
| 240 | oct->num_iqs++; | ||
| 241 | return 0; | ||
| 242 | |||
| 243 | buff_info_err: | ||
| 244 | dma_free_coherent(iq->dev, sglist_size, iq->sglist, iq->sglist_dma); | ||
| 245 | sglist_alloc_err: | ||
| 246 | dma_free_coherent(iq->dev, desc_ring_size, | ||
| 247 | iq->desc_ring, iq->desc_ring_dma); | ||
| 248 | desc_dma_alloc_err: | ||
| 249 | vfree(iq); | ||
| 250 | oct->iq[q_no] = NULL; | ||
| 251 | iq_alloc_err: | ||
| 252 | return -1; | ||
| 253 | } | ||
| 254 | |||
| 255 | /** | ||
| 256 | * octep_vf_free_iq() - Free Tx queue resources. | ||
| 257 | * | ||
| 258 | * @iq: Octeon Tx queue data structure. | ||
| 259 | * | ||
| 260 | * Free all the resources allocated for a Tx queue. | ||
| 261 | */ | ||
| 262 | static void octep_vf_free_iq(struct octep_vf_iq *iq) | ||
| 263 | { | ||
| 264 | struct octep_vf_device *oct = iq->octep_vf_dev; | ||
| 265 | u64 desc_ring_size, sglist_size; | ||
| 266 | int q_no = iq->q_no; | ||
| 267 | |||
| 268 | desc_ring_size = OCTEP_VF_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf); | ||
| 269 | |||
| 270 | vfree(iq->buff_info); | ||
| 271 | |||
| 272 | if (iq->desc_ring) | ||
| 273 | dma_free_coherent(iq->dev, desc_ring_size, | ||
| 274 | iq->desc_ring, iq->desc_ring_dma); | ||
| 275 | |||
| 276 | sglist_size = OCTEP_VF_SGLIST_SIZE_PER_PKT * | ||
| 277 | CFG_GET_IQ_NUM_DESC(oct->conf); | ||
| 278 | if (iq->sglist) | ||
| 279 | dma_free_coherent(iq->dev, sglist_size, | ||
| 280 | iq->sglist, iq->sglist_dma); | ||
| 281 | |||
| 282 | vfree(iq); | ||
| 283 | oct->iq[q_no] = NULL; | ||
| 284 | oct->num_iqs--; | ||
| 285 | } | ||
| 286 | |||
| 287 | /** | ||
| 288 | * octep_vf_setup_iqs() - setup resources for all Tx queues. | ||
| 289 | * | ||
| 290 | * @oct: Octeon device private data structure. | ||
| 291 | */ | ||
| 292 | int octep_vf_setup_iqs(struct octep_vf_device *oct) | ||
| 293 | { | ||
| 294 | int i; | ||
| 295 | |||
| 296 | oct->num_iqs = 0; | ||
| 297 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { | ||
| 298 | if (octep_vf_setup_iq(oct, i)) { | ||
| 299 | dev_err(&oct->pdev->dev, | ||
| 300 | "Failed to setup IQ(TxQ)-%d.\n", i); | ||
| 301 | goto iq_setup_err; | ||
| 302 | } | ||
| 303 | dev_dbg(&oct->pdev->dev, "Successfully setup IQ(TxQ)-%d.\n", i); | ||
| 304 | } | ||
| 305 | |||
| 306 | return 0; | ||
| 307 | |||
| 308 | iq_setup_err: | ||
| 309 | while (i) { | ||
| 310 | i--; | ||
| 311 | octep_vf_free_iq(oct->iq[i]); | ||
| 312 | } | ||
| 313 | return -1; | ||
| 314 | } | ||
| 315 | |||
| 316 | /** | ||
| 317 | * octep_vf_free_iqs() - Free resources of all Tx queues. | ||
| 318 | * | ||
| 319 | * @oct: Octeon device private data structure. | ||
| 320 | */ | ||
| 321 | void octep_vf_free_iqs(struct octep_vf_device *oct) | ||
| 322 | { | ||
| 323 | int i; | ||
| 324 | |||
| 325 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { | ||
| 326 | octep_vf_free_iq(oct->iq[i]); | ||
| 327 | dev_dbg(&oct->pdev->dev, | ||
| 328 | "Successfully destroyed IQ(TxQ)-%d.\n", i); | ||
| 329 | } | ||
| 330 | oct->num_iqs = 0; | ||
| 331 | } | ||
| @@ -0,0 +1,276 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* Marvell Octeon EP (EndPoint) VF Ethernet Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2020 Marvell. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _OCTEP_VF_TX_H_ | ||
| 9 | #define _OCTEP_VF_TX_H_ | ||
| 10 | |||
| 11 | #define IQ_SEND_OK 0 | ||
| 12 | #define IQ_SEND_STOP 1 | ||
| 13 | #define IQ_SEND_FAILED -1 | ||
| 14 | |||
| 15 | #define TX_BUFTYPE_NONE 0 | ||
| 16 | #define TX_BUFTYPE_NET 1 | ||
| 17 | #define TX_BUFTYPE_NET_SG 2 | ||
| 18 | #define NUM_TX_BUFTYPES 3 | ||
| 19 | |||
| 20 | /* Hardware format for Scatter/Gather list | ||
| 21 | * | ||
| 22 | * 63 48|47 32|31 16|15 0 | ||
| 23 | * ----------------------------------------- | ||
| 24 | * | Len 0 | Len 1 | Len 2 | Len 3 | | ||
| 25 | * ----------------------------------------- | ||
| 26 | * | Ptr 0 | | ||
| 27 | * ----------------------------------------- | ||
| 28 | * | Ptr 1 | | ||
| 29 | * ----------------------------------------- | ||
| 30 | * | Ptr 2 | | ||
| 31 | * ----------------------------------------- | ||
| 32 | * | Ptr 3 | | ||
| 33 | * ----------------------------------------- | ||
| 34 | */ | ||
| 35 | struct octep_vf_tx_sglist_desc { | ||
| 36 | u16 len[4]; | ||
| 37 | dma_addr_t dma_ptr[4]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static_assert(sizeof(struct octep_vf_tx_sglist_desc) == 40); | ||
| 41 | |||
| 42 | /* Each Scatter/Gather entry sent to hardwar hold four pointers. | ||
| 43 | * So, number of entries required is (MAX_SKB_FRAGS + 1)/4, where '+1' | ||
| 44 | * is for main skb which also goes as a gather buffer to Octeon hardware. | ||
| 45 | * To allocate sufficient SGLIST entries for a packet with max fragments, | ||
| 46 | * align by adding 3 before calcuating max SGLIST entries per packet. | ||
| 47 | */ | ||
| 48 | #define OCTEP_VF_SGLIST_ENTRIES_PER_PKT ((MAX_SKB_FRAGS + 1 + 3) / 4) | ||
| 49 | #define OCTEP_VF_SGLIST_SIZE_PER_PKT \ | ||
| 50 | (OCTEP_VF_SGLIST_ENTRIES_PER_PKT * sizeof(struct octep_vf_tx_sglist_desc)) | ||
| 51 | |||
| 52 | struct octep_vf_tx_buffer { | ||
| 53 | struct sk_buff *skb; | ||
| 54 | dma_addr_t dma; | ||
| 55 | struct octep_vf_tx_sglist_desc *sglist; | ||
| 56 | dma_addr_t sglist_dma; | ||
| 57 | u8 gather; | ||
| 58 | }; | ||
| 59 | |||
| 60 | #define OCTEP_VF_IQ_TXBUFF_INFO_SIZE (sizeof(struct octep_vf_tx_buffer)) | ||
| 61 | |||
| 62 | /* VF Hardware interface Tx statistics */ | ||
| 63 | struct octep_vf_iface_tx_stats { | ||
| 64 | /* Total frames sent on the interface */ | ||
| 65 | u64 pkts; | ||
| 66 | |||
| 67 | /* Total octets sent on the interface */ | ||
| 68 | u64 octs; | ||
| 69 | |||
| 70 | /* Packets sent to a broadcast DMAC */ | ||
| 71 | u64 bcst; | ||
| 72 | |||
| 73 | /* Packets sent to the multicast DMAC */ | ||
| 74 | u64 mcst; | ||
| 75 | |||
| 76 | /* Packets dropped */ | ||
| 77 | u64 dropped; | ||
| 78 | |||
| 79 | /* Reserved */ | ||
| 80 | u64 reserved[13]; | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* VF Input Queue statistics */ | ||
| 84 | struct octep_vf_iq_stats { | ||
| 85 | /* Instructions posted to this queue. */ | ||
| 86 | u64 instr_posted; | ||
| 87 | |||
| 88 | /* Instructions copied by hardware for processing. */ | ||
| 89 | u64 instr_completed; | ||
| 90 | |||
| 91 | /* Instructions that could not be processed. */ | ||
| 92 | u64 instr_dropped; | ||
| 93 | |||
| 94 | /* Bytes sent through this queue. */ | ||
| 95 | u64 bytes_sent; | ||
| 96 | |||
| 97 | /* Gather entries sent through this queue. */ | ||
| 98 | u64 sgentry_sent; | ||
| 99 | |||
| 100 | /* Number of transmit failures due to TX_BUSY */ | ||
| 101 | u64 tx_busy; | ||
| 102 | |||
| 103 | /* Number of times the queue is restarted */ | ||
| 104 | u64 restart_cnt; | ||
| 105 | }; | ||
| 106 | |||
| 107 | /* The instruction (input) queue. | ||
| 108 | * The input queue is used to post raw (instruction) mode data or packet | ||
| 109 | * data to Octeon device from the host. Each input queue (up to 4) for | ||
| 110 | * a Octeon device has one such structure to represent it. | ||
| 111 | */ | ||
| 112 | struct octep_vf_iq { | ||
| 113 | u32 q_no; | ||
| 114 | |||
| 115 | struct octep_vf_device *octep_vf_dev; | ||
| 116 | struct net_device *netdev; | ||
| 117 | struct device *dev; | ||
| 118 | struct netdev_queue *netdev_q; | ||
| 119 | |||
| 120 | /* Index in input ring where driver should write the next packet */ | ||
| 121 | u16 host_write_index; | ||
| 122 | |||
| 123 | /* Index in input ring where Octeon is expected to read next packet */ | ||
| 124 | u16 octep_vf_read_index; | ||
| 125 | |||
| 126 | /* This index aids in finding the window in the queue where Octeon | ||
| 127 | * has read the commands. | ||
| 128 | */ | ||
| 129 | u16 flush_index; | ||
| 130 | |||
| 131 | /* Statistics for this input queue. */ | ||
| 132 | struct octep_vf_iq_stats stats; | ||
| 133 | |||
| 134 | /* Pointer to the Virtual Base addr of the input ring. */ | ||
| 135 | struct octep_vf_tx_desc_hw *desc_ring; | ||
| 136 | |||
| 137 | /* DMA mapped base address of the input descriptor ring. */ | ||
| 138 | dma_addr_t desc_ring_dma; | ||
| 139 | |||
| 140 | /* Info of Tx buffers pending completion. */ | ||
| 141 | struct octep_vf_tx_buffer *buff_info; | ||
| 142 | |||
| 143 | /* Base pointer to Scatter/Gather lists for all ring descriptors. */ | ||
| 144 | struct octep_vf_tx_sglist_desc *sglist; | ||
| 145 | |||
| 146 | /* DMA mapped addr of Scatter Gather Lists */ | ||
| 147 | dma_addr_t sglist_dma; | ||
| 148 | |||
| 149 | /* Octeon doorbell register for the ring. */ | ||
| 150 | u8 __iomem *doorbell_reg; | ||
| 151 | |||
| 152 | /* Octeon instruction count register for this ring. */ | ||
| 153 | u8 __iomem *inst_cnt_reg; | ||
| 154 | |||
| 155 | /* interrupt level register for this ring */ | ||
| 156 | u8 __iomem *intr_lvl_reg; | ||
| 157 | |||
| 158 | /* Maximum no. of instructions in this queue. */ | ||
| 159 | u32 max_count; | ||
| 160 | u32 ring_size_mask; | ||
| 161 | |||
| 162 | u32 pkt_in_done; | ||
| 163 | u32 pkts_processed; | ||
| 164 | |||
| 165 | u32 status; | ||
| 166 | |||
| 167 | /* Number of instructions pending to be posted to Octeon. */ | ||
| 168 | u32 fill_cnt; | ||
| 169 | |||
| 170 | /* The max. number of instructions that can be held pending by the | ||
| 171 | * driver before ringing doorbell. | ||
| 172 | */ | ||
| 173 | u32 fill_threshold; | ||
| 174 | }; | ||
| 175 | |||
| 176 | /* Hardware Tx Instruction Header */ | ||
| 177 | struct octep_vf_instr_hdr { | ||
| 178 | /* Data Len */ | ||
| 179 | u64 tlen:16; | ||
| 180 | |||
| 181 | /* Reserved */ | ||
| 182 | u64 rsvd:20; | ||
| 183 | |||
| 184 | /* PKIND for SDP */ | ||
| 185 | u64 pkind:6; | ||
| 186 | |||
| 187 | /* Front Data size */ | ||
| 188 | u64 fsz:6; | ||
| 189 | |||
| 190 | /* No. of entries in gather list */ | ||
| 191 | u64 gsz:14; | ||
| 192 | |||
| 193 | /* Gather indicator 1=gather*/ | ||
| 194 | u64 gather:1; | ||
| 195 | |||
| 196 | /* Reserved3 */ | ||
| 197 | u64 reserved3:1; | ||
| 198 | }; | ||
| 199 | |||
| 200 | static_assert(sizeof(struct octep_vf_instr_hdr) == 8); | ||
| 201 | |||
| 202 | /* Tx offload flags */ | ||
| 203 | #define OCTEP_VF_TX_OFFLOAD_VLAN_INSERT BIT(0) | ||
| 204 | #define OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM BIT(1) | ||
| 205 | #define OCTEP_VF_TX_OFFLOAD_UDP_CKSUM BIT(2) | ||
| 206 | #define OCTEP_VF_TX_OFFLOAD_TCP_CKSUM BIT(3) | ||
| 207 | #define OCTEP_VF_TX_OFFLOAD_SCTP_CKSUM BIT(4) | ||
| 208 | #define OCTEP_VF_TX_OFFLOAD_TCP_TSO BIT(5) | ||
| 209 | #define OCTEP_VF_TX_OFFLOAD_UDP_TSO BIT(6) | ||
| 210 | |||
| 211 | #define OCTEP_VF_TX_OFFLOAD_CKSUM (OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM | \ | ||
| 212 | OCTEP_VF_TX_OFFLOAD_UDP_CKSUM | \ | ||
| 213 | OCTEP_VF_TX_OFFLOAD_TCP_CKSUM) | ||
| 214 | |||
| 215 | #define OCTEP_VF_TX_OFFLOAD_TSO (OCTEP_VF_TX_OFFLOAD_TCP_TSO | \ | ||
| 216 | OCTEP_VF_TX_OFFLOAD_UDP_TSO) | ||
| 217 | |||
| 218 | #define OCTEP_VF_TX_IP_CSUM(flags) ((flags) & \ | ||
| 219 | (OCTEP_VF_TX_OFFLOAD_IPV4_CKSUM | \ | ||
| 220 | OCTEP_VF_TX_OFFLOAD_TCP_CKSUM | \ | ||
| 221 | OCTEP_VF_TX_OFFLOAD_UDP_CKSUM)) | ||
| 222 | |||
| 223 | #define OCTEP_VF_TX_TSO(flags) ((flags) & \ | ||
| 224 | (OCTEP_VF_TX_OFFLOAD_TCP_TSO | \ | ||
| 225 | OCTEP_VF_TX_OFFLOAD_UDP_TSO)) | ||
| 226 | |||
| 227 | struct tx_mdata { | ||
| 228 | /* offload flags */ | ||
| 229 | u16 ol_flags; | ||
| 230 | |||
| 231 | /* gso size */ | ||
| 232 | u16 gso_size; | ||
| 233 | |||
| 234 | /* gso flags */ | ||
| 235 | u16 gso_segs; | ||
| 236 | |||
| 237 | /* reserved */ | ||
| 238 | u16 rsvd1; | ||
| 239 | |||
| 240 | /* reserved */ | ||
| 241 | u64 rsvd2; | ||
| 242 | }; | ||
| 243 | |||
| 244 | static_assert(sizeof(struct tx_mdata) == 16); | ||
| 245 | |||
| 246 | /* 64-byte Tx instruction format. | ||
| 247 | * Format of instruction for a 64-byte mode input queue. | ||
| 248 | * | ||
| 249 | * only first 16-bytes (dptr and ih) are mandatory; rest are optional | ||
| 250 | * and filled by the driver based on firmware/hardware capabilities. | ||
| 251 | * These optional headers together called Front Data and its size is | ||
| 252 | * described by ih->fsz. | ||
| 253 | */ | ||
| 254 | struct octep_vf_tx_desc_hw { | ||
| 255 | /* Pointer where the input data is available. */ | ||
| 256 | u64 dptr; | ||
| 257 | |||
| 258 | /* Instruction Header. */ | ||
| 259 | union { | ||
| 260 | struct octep_vf_instr_hdr ih; | ||
| 261 | u64 ih64; | ||
| 262 | }; | ||
| 263 | |||
| 264 | union { | ||
| 265 | u64 txm64[2]; | ||
| 266 | struct tx_mdata txm; | ||
| 267 | }; | ||
| 268 | |||
| 269 | /* Additional headers available in a 64-byte instruction. */ | ||
| 270 | u64 exhdr[4]; | ||
| 271 | }; | ||
| 272 | |||
| 273 | static_assert(sizeof(struct octep_vf_tx_desc_hw) == 64); | ||
| 274 | |||
| 275 | #define OCTEP_VF_IQ_DESC_SIZE (sizeof(struct octep_vf_tx_desc_hw)) | ||
| 276 | #endif /* _OCTEP_VF_TX_H_ */ | ||