1ba7319e9SDmitry Salychev /*- 2ba7319e9SDmitry Salychev * SPDX-License-Identifier: BSD-2-Clause 3ba7319e9SDmitry Salychev * 4718bdb6aSDmitry Salychev * Copyright © 2021-2023 Dmitry Salychev 5ba7319e9SDmitry Salychev * Copyright © 2022 Mathew McBride 6ba7319e9SDmitry Salychev * 7ba7319e9SDmitry Salychev * Redistribution and use in source and binary forms, with or without 8ba7319e9SDmitry Salychev * modification, are permitted provided that the following conditions 9ba7319e9SDmitry Salychev * are met: 10ba7319e9SDmitry Salychev * 1. Redistributions of source code must retain the above copyright 11ba7319e9SDmitry Salychev * notice, this list of conditions and the following disclaimer. 12ba7319e9SDmitry Salychev * 2. Redistributions in binary form must reproduce the above copyright 13ba7319e9SDmitry Salychev * notice, this list of conditions and the following disclaimer in the 14ba7319e9SDmitry Salychev * documentation and/or other materials provided with the distribution. 15ba7319e9SDmitry Salychev * 16ba7319e9SDmitry Salychev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17ba7319e9SDmitry Salychev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18ba7319e9SDmitry Salychev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ba7319e9SDmitry Salychev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20ba7319e9SDmitry Salychev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21ba7319e9SDmitry Salychev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22ba7319e9SDmitry Salychev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23ba7319e9SDmitry Salychev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24ba7319e9SDmitry Salychev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25ba7319e9SDmitry Salychev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26ba7319e9SDmitry Salychev * SUCH DAMAGE. 27ba7319e9SDmitry Salychev */ 28ba7319e9SDmitry Salychev 29ba7319e9SDmitry Salychev #include <sys/cdefs.h> 30ba7319e9SDmitry Salychev /* 31ba7319e9SDmitry Salychev * The DPAA2 Network Interface (DPNI) driver. 32ba7319e9SDmitry Salychev * 33ba7319e9SDmitry Salychev * The DPNI object is a network interface that is configurable to support a wide 34ba7319e9SDmitry Salychev * range of features from a very basic Ethernet interface up to a 35ba7319e9SDmitry Salychev * high-functioning network interface. The DPNI supports features that are 36ba7319e9SDmitry Salychev * expected by standard network stacks, from basic features to offloads. 37ba7319e9SDmitry Salychev * 38ba7319e9SDmitry Salychev * DPNIs work with Ethernet traffic, starting with the L2 header. Additional 39ba7319e9SDmitry Salychev * functions are provided for standard network protocols (L2, L3, L4, etc.). 40ba7319e9SDmitry Salychev */ 41ba7319e9SDmitry Salychev 42ba7319e9SDmitry Salychev #include <sys/param.h> 43ba7319e9SDmitry Salychev #include <sys/systm.h> 44ba7319e9SDmitry Salychev #include <sys/kernel.h> 45ba7319e9SDmitry Salychev #include <sys/bus.h> 46ba7319e9SDmitry Salychev #include <sys/rman.h> 47ba7319e9SDmitry Salychev #include <sys/module.h> 48ba7319e9SDmitry Salychev #include <sys/malloc.h> 49ba7319e9SDmitry Salychev #include <sys/mutex.h> 50ba7319e9SDmitry Salychev #include <sys/socket.h> 51ba7319e9SDmitry Salychev #include <sys/sockio.h> 52ba7319e9SDmitry Salychev #include <sys/sysctl.h> 53ba7319e9SDmitry Salychev #include <sys/mbuf.h> 54ba7319e9SDmitry Salychev #include <sys/taskqueue.h> 55ba7319e9SDmitry Salychev #include <sys/sysctl.h> 56ba7319e9SDmitry Salychev #include <sys/buf_ring.h> 57ba7319e9SDmitry Salychev #include <sys/smp.h> 58ba7319e9SDmitry Salychev #include <sys/proc.h> 59ba7319e9SDmitry Salychev 60ba7319e9SDmitry Salychev #include <vm/vm.h> 61ba7319e9SDmitry Salychev #include <vm/pmap.h> 62ba7319e9SDmitry Salychev 63ba7319e9SDmitry Salychev #include <machine/bus.h> 64ba7319e9SDmitry Salychev #include <machine/resource.h> 65ba7319e9SDmitry Salychev #include <machine/atomic.h> 66718bdb6aSDmitry Salychev #include <machine/vmparam.h> 67ba7319e9SDmitry Salychev 68ba7319e9SDmitry Salychev #include <net/ethernet.h> 69ba7319e9SDmitry Salychev #include <net/bpf.h> 70ba7319e9SDmitry Salychev #include <net/if.h> 71ba7319e9SDmitry Salychev #include <net/if_dl.h> 72ba7319e9SDmitry Salychev #include <net/if_media.h> 73ba7319e9SDmitry Salychev #include <net/if_types.h> 74ba7319e9SDmitry Salychev #include <net/if_var.h> 75ba7319e9SDmitry Salychev 76ba7319e9SDmitry Salychev #include <dev/pci/pcivar.h> 77ba7319e9SDmitry Salychev #include <dev/mii/mii.h> 78ba7319e9SDmitry Salychev #include <dev/mii/miivar.h> 79ba7319e9SDmitry Salychev #include <dev/mdio/mdio.h> 80ba7319e9SDmitry Salychev 81ba7319e9SDmitry Salychev #include "opt_acpi.h" 82ba7319e9SDmitry Salychev #include "opt_platform.h" 83ba7319e9SDmitry Salychev 84ba7319e9SDmitry Salychev #include "pcib_if.h" 85ba7319e9SDmitry Salychev #include "pci_if.h" 86ba7319e9SDmitry Salychev #include "miibus_if.h" 87ba7319e9SDmitry Salychev #include "memac_mdio_if.h" 88ba7319e9SDmitry Salychev 89ba7319e9SDmitry Salychev #include "dpaa2_types.h" 90ba7319e9SDmitry Salychev #include "dpaa2_mc.h" 91ba7319e9SDmitry Salychev #include "dpaa2_mc_if.h" 92ba7319e9SDmitry Salychev #include "dpaa2_mcp.h" 93ba7319e9SDmitry Salychev #include "dpaa2_swp.h" 94ba7319e9SDmitry Salychev #include "dpaa2_swp_if.h" 95ba7319e9SDmitry Salychev #include "dpaa2_cmd_if.h" 96ba7319e9SDmitry Salychev #include "dpaa2_ni.h" 9758983e4bSDmitry Salychev #include "dpaa2_channel.h" 9858983e4bSDmitry Salychev #include "dpaa2_buf.h" 99ba7319e9SDmitry Salychev 100ba7319e9SDmitry Salychev #define BIT(x) (1ul << (x)) 101ba7319e9SDmitry Salychev #define WRIOP_VERSION(x, y, z) ((x) << 10 | (y) << 5 | (z) << 0) 102ba7319e9SDmitry Salychev #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 103ba7319e9SDmitry Salychev 104ba7319e9SDmitry Salychev /* Frame Dequeue Response status bits. */ 105ba7319e9SDmitry Salychev #define IS_NULL_RESPONSE(stat) ((((stat) >> 4) & 1) == 0) 106ba7319e9SDmitry Salychev 107ba7319e9SDmitry Salychev #define ALIGN_UP(x, y) roundup2((x), (y)) 108ba7319e9SDmitry Salychev #define ALIGN_DOWN(x, y) rounddown2((x), (y)) 109ba7319e9SDmitry Salychev #define CACHE_LINE_ALIGN(x) ALIGN_UP((x), CACHE_LINE_SIZE) 110ba7319e9SDmitry Salychev 111ba7319e9SDmitry Salychev #define DPNI_LOCK(__sc) do { \ 112ba7319e9SDmitry Salychev mtx_assert(&(__sc)->lock, MA_NOTOWNED); \ 113ba7319e9SDmitry Salychev mtx_lock(&(__sc)->lock); \ 114ba7319e9SDmitry Salychev } while (0) 115ba7319e9SDmitry Salychev #define DPNI_UNLOCK(__sc) do { \ 116ba7319e9SDmitry Salychev mtx_assert(&(__sc)->lock, MA_OWNED); \ 117ba7319e9SDmitry Salychev mtx_unlock(&(__sc)->lock); \ 118ba7319e9SDmitry Salychev } while (0) 119964b3408SBjoern A. Zeeb #define DPNI_LOCK_ASSERT(__sc) do { \ 120964b3408SBjoern A. Zeeb mtx_assert(&(__sc)->lock, MA_OWNED); \ 121964b3408SBjoern A. Zeeb } while (0) 122ba7319e9SDmitry Salychev 123ba7319e9SDmitry Salychev #define DPAA2_TX_RING(sc, chan, tc) \ 124ba7319e9SDmitry Salychev (&(sc)->channels[(chan)]->txc_queue.tx_rings[(tc)]) 125ba7319e9SDmitry Salychev 12658983e4bSDmitry Salychev MALLOC_DEFINE(M_DPAA2_TXB, "dpaa2_txb", "DPAA2 DMA-mapped buffer (Tx)"); 12758983e4bSDmitry Salychev 12858983e4bSDmitry Salychev /* 12958983e4bSDmitry Salychev * How many times channel cleanup routine will be repeated if the RX or TX 13058983e4bSDmitry Salychev * budget was depleted. 13158983e4bSDmitry Salychev */ 13258983e4bSDmitry Salychev #define DPAA2_CLEAN_BUDGET 64 /* sysctl(9)? */ 13358983e4bSDmitry Salychev /* TX/RX budget for the channel cleanup task */ 13458983e4bSDmitry Salychev #define DPAA2_TX_BUDGET 128 /* sysctl(9)? */ 13558983e4bSDmitry Salychev #define DPAA2_RX_BUDGET 256 /* sysctl(9)? */ 13658983e4bSDmitry Salychev 137ba7319e9SDmitry Salychev #define DPNI_IRQ_INDEX 0 /* Index of the only DPNI IRQ. */ 138ba7319e9SDmitry Salychev #define DPNI_IRQ_LINK_CHANGED 1 /* Link state changed */ 139ba7319e9SDmitry Salychev #define DPNI_IRQ_EP_CHANGED 2 /* DPAA2 endpoint dis/connected */ 140ba7319e9SDmitry Salychev 141fa3dfeffSBjoern A. Zeeb /* Default maximum RX frame length w/o CRC. */ 142fa3dfeffSBjoern A. Zeeb #define DPAA2_ETH_MFL (ETHER_MAX_LEN_JUMBO + ETHER_VLAN_ENCAP_LEN - \ 143fa3dfeffSBjoern A. Zeeb ETHER_CRC_LEN) 144ba7319e9SDmitry Salychev 145ba7319e9SDmitry Salychev /* Minimally supported version of the DPNI API. */ 146ba7319e9SDmitry Salychev #define DPNI_VER_MAJOR 7 147ba7319e9SDmitry Salychev #define DPNI_VER_MINOR 0 148ba7319e9SDmitry Salychev 149ba7319e9SDmitry Salychev /* Rx/Tx buffers configuration. */ 150ba7319e9SDmitry Salychev #define BUF_ALIGN_V1 256 /* WRIOP v1.0.0 limitation */ 151ba7319e9SDmitry Salychev #define BUF_ALIGN 64 152ba7319e9SDmitry Salychev #define BUF_SWA_SIZE 64 /* SW annotation size */ 153ba7319e9SDmitry Salychev #define BUF_RX_HWA_SIZE 64 /* HW annotation size */ 154ba7319e9SDmitry Salychev #define BUF_TX_HWA_SIZE 128 /* HW annotation size */ 155ba7319e9SDmitry Salychev 15658983e4bSDmitry Salychev #define DPAA2_RX_BUFRING_SZ (4096u) 15758983e4bSDmitry Salychev #define DPAA2_RXE_BUFRING_SZ (1024u) 15858983e4bSDmitry Salychev #define DPAA2_TXC_BUFRING_SZ (4096u) 159ba7319e9SDmitry Salychev #define DPAA2_TX_SEGLIMIT (16u) /* arbitrary number */ 16058983e4bSDmitry Salychev #define DPAA2_TX_SEG_SZ (PAGE_SIZE) 161ba7319e9SDmitry Salychev #define DPAA2_TX_SEGS_MAXSZ (DPAA2_TX_SEGLIMIT * DPAA2_TX_SEG_SZ) 162718bdb6aSDmitry Salychev #define DPAA2_TX_SGT_SZ (PAGE_SIZE) /* bytes */ 163ba7319e9SDmitry Salychev 164ba7319e9SDmitry Salychev /* Size of a buffer to keep a QoS table key configuration. */ 16558983e4bSDmitry Salychev #define ETH_QOS_KCFG_BUF_SIZE (PAGE_SIZE) 166ba7319e9SDmitry Salychev 167ba7319e9SDmitry Salychev /* Required by struct dpni_rx_tc_dist_cfg::key_cfg_iova */ 16858983e4bSDmitry Salychev #define DPAA2_CLASSIFIER_DMA_SIZE (PAGE_SIZE) 169ba7319e9SDmitry Salychev 170ba7319e9SDmitry Salychev /* Buffers layout options. */ 171ba7319e9SDmitry Salychev #define BUF_LOPT_TIMESTAMP 0x1 172ba7319e9SDmitry Salychev #define BUF_LOPT_PARSER_RESULT 0x2 173ba7319e9SDmitry Salychev #define BUF_LOPT_FRAME_STATUS 0x4 174ba7319e9SDmitry Salychev #define BUF_LOPT_PRIV_DATA_SZ 0x8 175ba7319e9SDmitry Salychev #define BUF_LOPT_DATA_ALIGN 0x10 176ba7319e9SDmitry Salychev #define BUF_LOPT_DATA_HEAD_ROOM 0x20 177ba7319e9SDmitry Salychev #define BUF_LOPT_DATA_TAIL_ROOM 0x40 178ba7319e9SDmitry Salychev 179ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_ADDR_MASK (0x1FFFFFFFFFFFFul) /* 49-bit addresses max. */ 180ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_CHAN_MASK (0xFu) 181ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_CHAN_SHIFT (60) 182ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_IDX_MASK (0x7FFFu) 183ba7319e9SDmitry Salychev #define DPAA2_NI_BUF_IDX_SHIFT (49) 184ba7319e9SDmitry Salychev #define DPAA2_NI_TX_IDX_MASK (0x7u) 185ba7319e9SDmitry Salychev #define DPAA2_NI_TX_IDX_SHIFT (57) 186ba7319e9SDmitry Salychev #define DPAA2_NI_TXBUF_IDX_MASK (0xFFu) 187ba7319e9SDmitry Salychev #define DPAA2_NI_TXBUF_IDX_SHIFT (49) 188ba7319e9SDmitry Salychev 189ba7319e9SDmitry Salychev #define DPAA2_NI_FD_FMT_MASK (0x3u) 190ba7319e9SDmitry Salychev #define DPAA2_NI_FD_FMT_SHIFT (12) 191ba7319e9SDmitry Salychev #define DPAA2_NI_FD_ERR_MASK (0xFFu) 192ba7319e9SDmitry Salychev #define DPAA2_NI_FD_ERR_SHIFT (0) 193ba7319e9SDmitry Salychev #define DPAA2_NI_FD_SL_MASK (0x1u) 194ba7319e9SDmitry Salychev #define DPAA2_NI_FD_SL_SHIFT (14) 195ba7319e9SDmitry Salychev #define DPAA2_NI_FD_LEN_MASK (0x3FFFFu) 196ba7319e9SDmitry Salychev #define DPAA2_NI_FD_OFFSET_MASK (0x0FFFu) 197ba7319e9SDmitry Salychev 198ba7319e9SDmitry Salychev /* Enables TCAM for Flow Steering and QoS look-ups. */ 199ba7319e9SDmitry Salychev #define DPNI_OPT_HAS_KEY_MASKING 0x10 200ba7319e9SDmitry Salychev 201ba7319e9SDmitry Salychev /* Unique IDs for the supported Rx classification header fields. */ 202ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ETHDST BIT(0) 203ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ETHSRC BIT(1) 204ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ETHTYPE BIT(2) 205ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_VLAN BIT(3) 206ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_IPSRC BIT(4) 207ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_IPDST BIT(5) 208ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_IPPROTO BIT(6) 209ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_L4SRC BIT(7) 210ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_L4DST BIT(8) 211ba7319e9SDmitry Salychev #define DPAA2_ETH_DIST_ALL (~0ULL) 212ba7319e9SDmitry Salychev 213ba7319e9SDmitry Salychev /* L3-L4 network traffic flow hash options. */ 214ba7319e9SDmitry Salychev #define RXH_L2DA (1 << 1) 215ba7319e9SDmitry Salychev #define RXH_VLAN (1 << 2) 216ba7319e9SDmitry Salychev #define RXH_L3_PROTO (1 << 3) 217ba7319e9SDmitry Salychev #define RXH_IP_SRC (1 << 4) 218ba7319e9SDmitry Salychev #define RXH_IP_DST (1 << 5) 219ba7319e9SDmitry Salychev #define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */ 220ba7319e9SDmitry Salychev #define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */ 221ba7319e9SDmitry Salychev #define RXH_DISCARD (1 << 31) 222ba7319e9SDmitry Salychev 223ba7319e9SDmitry Salychev /* Default Rx hash options, set during attaching. */ 224ba7319e9SDmitry Salychev #define DPAA2_RXH_DEFAULT (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3) 225ba7319e9SDmitry Salychev 226ba7319e9SDmitry Salychev MALLOC_DEFINE(M_DPAA2_NI, "dpaa2_ni", "DPAA2 Network Interface"); 227ba7319e9SDmitry Salychev 22858983e4bSDmitry Salychev /* 22958983e4bSDmitry Salychev * DPAA2 Network Interface resource specification. 23058983e4bSDmitry Salychev * 23158983e4bSDmitry Salychev * NOTE: Don't forget to update macros in dpaa2_ni.h in case of any changes in 23258983e4bSDmitry Salychev * the specification! 23358983e4bSDmitry Salychev */ 234ba7319e9SDmitry Salychev struct resource_spec dpaa2_ni_spec[] = { 235ba7319e9SDmitry Salychev /* 236ba7319e9SDmitry Salychev * DPMCP resources. 237ba7319e9SDmitry Salychev * 238ba7319e9SDmitry Salychev * NOTE: MC command portals (MCPs) are used to send commands to, and 239ba7319e9SDmitry Salychev * receive responses from, the MC firmware. One portal per DPNI. 240ba7319e9SDmitry Salychev */ 24158983e4bSDmitry Salychev { DPAA2_DEV_MCP, DPAA2_NI_MCP_RID(0), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 242ba7319e9SDmitry Salychev /* 243ba7319e9SDmitry Salychev * DPIO resources (software portals). 244ba7319e9SDmitry Salychev * 245ba7319e9SDmitry Salychev * NOTE: One per running core. While DPIOs are the source of data 246ba7319e9SDmitry Salychev * availability interrupts, the DPCONs are used to identify the 247ba7319e9SDmitry Salychev * network interface that has produced ingress data to that core. 248ba7319e9SDmitry Salychev */ 24958983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(0), RF_ACTIVE | RF_SHAREABLE }, 25058983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(1), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25158983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(2), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25258983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(3), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25358983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(4), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25458983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(5), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25558983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(6), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25658983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(7), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25758983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(8), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25858983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(9), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 25958983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(10), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 26058983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(11), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 26158983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(12), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 26258983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(13), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 26358983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(14), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 26458983e4bSDmitry Salychev { DPAA2_DEV_IO, DPAA2_NI_IO_RID(15), RF_ACTIVE | RF_SHAREABLE | RF_OPTIONAL }, 265ba7319e9SDmitry Salychev /* 266ba7319e9SDmitry Salychev * DPBP resources (buffer pools). 267ba7319e9SDmitry Salychev * 268ba7319e9SDmitry Salychev * NOTE: One per network interface. 269ba7319e9SDmitry Salychev */ 27058983e4bSDmitry Salychev { DPAA2_DEV_BP, DPAA2_NI_BP_RID(0), RF_ACTIVE }, 271ba7319e9SDmitry Salychev /* 272ba7319e9SDmitry Salychev * DPCON resources (channels). 273ba7319e9SDmitry Salychev * 274ba7319e9SDmitry Salychev * NOTE: One DPCON per core where Rx or Tx confirmation traffic to be 275ba7319e9SDmitry Salychev * distributed to. 276ba7319e9SDmitry Salychev * NOTE: Since it is necessary to distinguish between traffic from 277ba7319e9SDmitry Salychev * different network interfaces arriving on the same core, the 278ba7319e9SDmitry Salychev * DPCONs must be private to the DPNIs. 279ba7319e9SDmitry Salychev */ 28058983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(0), RF_ACTIVE }, 28158983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(1), RF_ACTIVE | RF_OPTIONAL }, 28258983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(2), RF_ACTIVE | RF_OPTIONAL }, 28358983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(3), RF_ACTIVE | RF_OPTIONAL }, 28458983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(4), RF_ACTIVE | RF_OPTIONAL }, 28558983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(5), RF_ACTIVE | RF_OPTIONAL }, 28658983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(6), RF_ACTIVE | RF_OPTIONAL }, 28758983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(7), RF_ACTIVE | RF_OPTIONAL }, 28858983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(8), RF_ACTIVE | RF_OPTIONAL }, 28958983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(9), RF_ACTIVE | RF_OPTIONAL }, 29058983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(10), RF_ACTIVE | RF_OPTIONAL }, 29158983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(11), RF_ACTIVE | RF_OPTIONAL }, 29258983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(12), RF_ACTIVE | RF_OPTIONAL }, 29358983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(13), RF_ACTIVE | RF_OPTIONAL }, 29458983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(14), RF_ACTIVE | RF_OPTIONAL }, 29558983e4bSDmitry Salychev { DPAA2_DEV_CON, DPAA2_NI_CON_RID(15), RF_ACTIVE | RF_OPTIONAL }, 29658983e4bSDmitry Salychev 297ba7319e9SDmitry Salychev RESOURCE_SPEC_END 298ba7319e9SDmitry Salychev }; 299ba7319e9SDmitry Salychev 300ba7319e9SDmitry Salychev /* Supported header fields for Rx hash distribution key */ 301ba7319e9SDmitry Salychev static const struct dpaa2_eth_dist_fields dist_fields[] = { 302ba7319e9SDmitry Salychev { 303ba7319e9SDmitry Salychev /* L2 header */ 304ba7319e9SDmitry Salychev .rxnfc_field = RXH_L2DA, 305ba7319e9SDmitry Salychev .cls_prot = NET_PROT_ETH, 306ba7319e9SDmitry Salychev .cls_field = NH_FLD_ETH_DA, 307ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_ETHDST, 308ba7319e9SDmitry Salychev .size = 6, 309ba7319e9SDmitry Salychev }, { 310ba7319e9SDmitry Salychev .cls_prot = NET_PROT_ETH, 311ba7319e9SDmitry Salychev .cls_field = NH_FLD_ETH_SA, 312ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_ETHSRC, 313ba7319e9SDmitry Salychev .size = 6, 314ba7319e9SDmitry Salychev }, { 315ba7319e9SDmitry Salychev /* This is the last ethertype field parsed: 316ba7319e9SDmitry Salychev * depending on frame format, it can be the MAC ethertype 317ba7319e9SDmitry Salychev * or the VLAN etype. 318ba7319e9SDmitry Salychev */ 319ba7319e9SDmitry Salychev .cls_prot = NET_PROT_ETH, 320ba7319e9SDmitry Salychev .cls_field = NH_FLD_ETH_TYPE, 321ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_ETHTYPE, 322ba7319e9SDmitry Salychev .size = 2, 323ba7319e9SDmitry Salychev }, { 324ba7319e9SDmitry Salychev /* VLAN header */ 325ba7319e9SDmitry Salychev .rxnfc_field = RXH_VLAN, 326ba7319e9SDmitry Salychev .cls_prot = NET_PROT_VLAN, 327ba7319e9SDmitry Salychev .cls_field = NH_FLD_VLAN_TCI, 328ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_VLAN, 329ba7319e9SDmitry Salychev .size = 2, 330ba7319e9SDmitry Salychev }, { 331ba7319e9SDmitry Salychev /* IP header */ 332ba7319e9SDmitry Salychev .rxnfc_field = RXH_IP_SRC, 333ba7319e9SDmitry Salychev .cls_prot = NET_PROT_IP, 334ba7319e9SDmitry Salychev .cls_field = NH_FLD_IP_SRC, 335ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_IPSRC, 336ba7319e9SDmitry Salychev .size = 4, 337ba7319e9SDmitry Salychev }, { 338ba7319e9SDmitry Salychev .rxnfc_field = RXH_IP_DST, 339ba7319e9SDmitry Salychev .cls_prot = NET_PROT_IP, 340ba7319e9SDmitry Salychev .cls_field = NH_FLD_IP_DST, 341ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_IPDST, 342ba7319e9SDmitry Salychev .size = 4, 343ba7319e9SDmitry Salychev }, { 344ba7319e9SDmitry Salychev .rxnfc_field = RXH_L3_PROTO, 345ba7319e9SDmitry Salychev .cls_prot = NET_PROT_IP, 346ba7319e9SDmitry Salychev .cls_field = NH_FLD_IP_PROTO, 347ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_IPPROTO, 348ba7319e9SDmitry Salychev .size = 1, 349ba7319e9SDmitry Salychev }, { 350ba7319e9SDmitry Salychev /* Using UDP ports, this is functionally equivalent to raw 351ba7319e9SDmitry Salychev * byte pairs from L4 header. 352ba7319e9SDmitry Salychev */ 353ba7319e9SDmitry Salychev .rxnfc_field = RXH_L4_B_0_1, 354ba7319e9SDmitry Salychev .cls_prot = NET_PROT_UDP, 355ba7319e9SDmitry Salychev .cls_field = NH_FLD_UDP_PORT_SRC, 356ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_L4SRC, 357ba7319e9SDmitry Salychev .size = 2, 358ba7319e9SDmitry Salychev }, { 359ba7319e9SDmitry Salychev .rxnfc_field = RXH_L4_B_2_3, 360ba7319e9SDmitry Salychev .cls_prot = NET_PROT_UDP, 361ba7319e9SDmitry Salychev .cls_field = NH_FLD_UDP_PORT_DST, 362ba7319e9SDmitry Salychev .id = DPAA2_ETH_DIST_L4DST, 363ba7319e9SDmitry Salychev .size = 2, 364ba7319e9SDmitry Salychev }, 365ba7319e9SDmitry Salychev }; 366ba7319e9SDmitry Salychev 367ba7319e9SDmitry Salychev static struct dpni_stat { 368ba7319e9SDmitry Salychev int page; 369ba7319e9SDmitry Salychev int cnt; 370ba7319e9SDmitry Salychev char *name; 371ba7319e9SDmitry Salychev char *desc; 372ba7319e9SDmitry Salychev } dpni_stat_sysctls[DPAA2_NI_STAT_SYSCTLS] = { 373ba7319e9SDmitry Salychev /* PAGE, COUNTER, NAME, DESCRIPTION */ 374ba7319e9SDmitry Salychev { 0, 0, "in_all_frames", "All accepted ingress frames" }, 375ba7319e9SDmitry Salychev { 0, 1, "in_all_bytes", "Bytes in all accepted ingress frames" }, 376ba7319e9SDmitry Salychev { 0, 2, "in_multi_frames", "Multicast accepted ingress frames" }, 377ba7319e9SDmitry Salychev { 1, 0, "eg_all_frames", "All egress frames transmitted" }, 378ba7319e9SDmitry Salychev { 1, 1, "eg_all_bytes", "Bytes in all frames transmitted" }, 379ba7319e9SDmitry Salychev { 1, 2, "eg_multi_frames", "Multicast egress frames transmitted" }, 380ba7319e9SDmitry Salychev { 2, 0, "in_filtered_frames", "All ingress frames discarded due to " 381ba7319e9SDmitry Salychev "filtering" }, 382ba7319e9SDmitry Salychev { 2, 1, "in_discarded_frames", "All frames discarded due to errors" }, 383ba7319e9SDmitry Salychev { 2, 2, "in_nobuf_discards", "Discards on ingress side due to buffer " 384ba7319e9SDmitry Salychev "depletion in DPNI buffer pools" }, 385ba7319e9SDmitry Salychev }; 386ba7319e9SDmitry Salychev 38758983e4bSDmitry Salychev struct dpaa2_ni_rx_ctx { 38858983e4bSDmitry Salychev struct mbuf *head; 38958983e4bSDmitry Salychev struct mbuf *tail; 39058983e4bSDmitry Salychev int cnt; 39158983e4bSDmitry Salychev bool last; 39258983e4bSDmitry Salychev }; 39358983e4bSDmitry Salychev 394ba7319e9SDmitry Salychev /* Device interface */ 395ba7319e9SDmitry Salychev static int dpaa2_ni_probe(device_t); 396ba7319e9SDmitry Salychev static int dpaa2_ni_attach(device_t); 397ba7319e9SDmitry Salychev static int dpaa2_ni_detach(device_t); 398ba7319e9SDmitry Salychev 399ba7319e9SDmitry Salychev /* DPAA2 network interface setup and configuration */ 400ba7319e9SDmitry Salychev static int dpaa2_ni_setup(device_t); 401ba7319e9SDmitry Salychev static int dpaa2_ni_setup_channels(device_t); 402ba7319e9SDmitry Salychev static int dpaa2_ni_bind(device_t); 403ba7319e9SDmitry Salychev static int dpaa2_ni_setup_rx_dist(device_t); 404ba7319e9SDmitry Salychev static int dpaa2_ni_setup_irqs(device_t); 405ba7319e9SDmitry Salychev static int dpaa2_ni_setup_msi(struct dpaa2_ni_softc *); 406ba7319e9SDmitry Salychev static int dpaa2_ni_setup_if_caps(struct dpaa2_ni_softc *); 407ba7319e9SDmitry Salychev static int dpaa2_ni_setup_if_flags(struct dpaa2_ni_softc *); 408ba7319e9SDmitry Salychev static int dpaa2_ni_setup_sysctls(struct dpaa2_ni_softc *); 409ba7319e9SDmitry Salychev static int dpaa2_ni_setup_dma(struct dpaa2_ni_softc *); 410ba7319e9SDmitry Salychev 411ba7319e9SDmitry Salychev /* Tx/Rx flow configuration */ 4124cd96614SDmitry Salychev static int dpaa2_ni_setup_rx_flow(device_t, struct dpaa2_ni_fq *); 4134cd96614SDmitry Salychev static int dpaa2_ni_setup_tx_flow(device_t, struct dpaa2_ni_fq *); 4144cd96614SDmitry Salychev static int dpaa2_ni_setup_rx_err_flow(device_t, struct dpaa2_ni_fq *); 415ba7319e9SDmitry Salychev 416ba7319e9SDmitry Salychev /* Configuration subroutines */ 4174cd96614SDmitry Salychev static int dpaa2_ni_set_buf_layout(device_t); 4184cd96614SDmitry Salychev static int dpaa2_ni_set_pause_frame(device_t); 4194cd96614SDmitry Salychev static int dpaa2_ni_set_qos_table(device_t); 4204cd96614SDmitry Salychev static int dpaa2_ni_set_mac_addr(device_t); 421ba7319e9SDmitry Salychev static int dpaa2_ni_set_hash(device_t, uint64_t); 422ba7319e9SDmitry Salychev static int dpaa2_ni_set_dist_key(device_t, enum dpaa2_ni_dist_mode, uint64_t); 423ba7319e9SDmitry Salychev 424ba7319e9SDmitry Salychev /* Frame descriptor routines */ 425ba7319e9SDmitry Salychev static int dpaa2_ni_build_fd(struct dpaa2_ni_softc *, struct dpaa2_ni_tx_ring *, 426ba7319e9SDmitry Salychev struct dpaa2_buf *, bus_dma_segment_t *, int, struct dpaa2_fd *); 427ba7319e9SDmitry Salychev static int dpaa2_ni_fd_err(struct dpaa2_fd *); 428ba7319e9SDmitry Salychev static uint32_t dpaa2_ni_fd_data_len(struct dpaa2_fd *); 429ba7319e9SDmitry Salychev static int dpaa2_ni_fd_format(struct dpaa2_fd *); 430ba7319e9SDmitry Salychev static bool dpaa2_ni_fd_short_len(struct dpaa2_fd *); 431ba7319e9SDmitry Salychev static int dpaa2_ni_fd_offset(struct dpaa2_fd *); 432ba7319e9SDmitry Salychev 433ba7319e9SDmitry Salychev /* Various subroutines */ 434ba7319e9SDmitry Salychev static int dpaa2_ni_cmp_api_version(struct dpaa2_ni_softc *, uint16_t, uint16_t); 435ba7319e9SDmitry Salychev static int dpaa2_ni_prepare_key_cfg(struct dpkg_profile_cfg *, uint8_t *); 436ba7319e9SDmitry Salychev 437ba7319e9SDmitry Salychev /* Network interface routines */ 438ba7319e9SDmitry Salychev static void dpaa2_ni_init(void *); 439d936c29eSJustin Hibbits static int dpaa2_ni_transmit(if_t , struct mbuf *); 440d936c29eSJustin Hibbits static void dpaa2_ni_qflush(if_t ); 441d936c29eSJustin Hibbits static int dpaa2_ni_ioctl(if_t , u_long, caddr_t); 442d936c29eSJustin Hibbits static int dpaa2_ni_update_mac_filters(if_t ); 443ba7319e9SDmitry Salychev static u_int dpaa2_ni_add_maddr(void *, struct sockaddr_dl *, u_int); 444ba7319e9SDmitry Salychev 445ba7319e9SDmitry Salychev /* Interrupt handlers */ 446ba7319e9SDmitry Salychev static void dpaa2_ni_intr(void *); 447ba7319e9SDmitry Salychev 448ba7319e9SDmitry Salychev /* MII handlers */ 449ba7319e9SDmitry Salychev static void dpaa2_ni_miibus_statchg(device_t); 450d936c29eSJustin Hibbits static int dpaa2_ni_media_change(if_t ); 451d936c29eSJustin Hibbits static void dpaa2_ni_media_status(if_t , struct ifmediareq *); 452ba7319e9SDmitry Salychev static void dpaa2_ni_media_tick(void *); 453ba7319e9SDmitry Salychev 454ba7319e9SDmitry Salychev /* Tx/Rx routines. */ 45558983e4bSDmitry Salychev static int dpaa2_ni_rx_cleanup(struct dpaa2_channel *); 45658983e4bSDmitry Salychev static int dpaa2_ni_tx_cleanup(struct dpaa2_channel *); 45758983e4bSDmitry Salychev static void dpaa2_ni_tx(struct dpaa2_ni_softc *, struct dpaa2_channel *, 458ba7319e9SDmitry Salychev struct dpaa2_ni_tx_ring *, struct mbuf *); 45958983e4bSDmitry Salychev static void dpaa2_ni_cleanup_task(void *, int); 460ba7319e9SDmitry Salychev 461ba7319e9SDmitry Salychev /* Tx/Rx subroutines */ 46258983e4bSDmitry Salychev static int dpaa2_ni_consume_frames(struct dpaa2_channel *, struct dpaa2_ni_fq **, 46358983e4bSDmitry Salychev uint32_t *); 46458983e4bSDmitry Salychev static int dpaa2_ni_rx(struct dpaa2_channel *, struct dpaa2_ni_fq *, 46558983e4bSDmitry Salychev struct dpaa2_fd *, struct dpaa2_ni_rx_ctx *); 46658983e4bSDmitry Salychev static int dpaa2_ni_rx_err(struct dpaa2_channel *, struct dpaa2_ni_fq *, 467ba7319e9SDmitry Salychev struct dpaa2_fd *); 46858983e4bSDmitry Salychev static int dpaa2_ni_tx_conf(struct dpaa2_channel *, struct dpaa2_ni_fq *, 469ba7319e9SDmitry Salychev struct dpaa2_fd *); 470ba7319e9SDmitry Salychev 471ba7319e9SDmitry Salychev /* sysctl(9) */ 472ba7319e9SDmitry Salychev static int dpaa2_ni_collect_stats(SYSCTL_HANDLER_ARGS); 473ba7319e9SDmitry Salychev static int dpaa2_ni_collect_buf_num(SYSCTL_HANDLER_ARGS); 474ba7319e9SDmitry Salychev static int dpaa2_ni_collect_buf_free(SYSCTL_HANDLER_ARGS); 475ba7319e9SDmitry Salychev 476ba7319e9SDmitry Salychev static int 477ba7319e9SDmitry Salychev dpaa2_ni_probe(device_t dev) 478ba7319e9SDmitry Salychev { 479ba7319e9SDmitry Salychev /* DPNI device will be added by a parent resource container itself. */ 480ba7319e9SDmitry Salychev device_set_desc(dev, "DPAA2 Network Interface"); 481ba7319e9SDmitry Salychev return (BUS_PROBE_DEFAULT); 482ba7319e9SDmitry Salychev } 483ba7319e9SDmitry Salychev 484ba7319e9SDmitry Salychev static int 485ba7319e9SDmitry Salychev dpaa2_ni_attach(device_t dev) 486ba7319e9SDmitry Salychev { 487ba7319e9SDmitry Salychev device_t pdev = device_get_parent(dev); 488ba7319e9SDmitry Salychev device_t child = dev; 489ba7319e9SDmitry Salychev device_t mcp_dev; 490ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 491ba7319e9SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 492ba7319e9SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 493ba7319e9SDmitry Salychev struct dpaa2_devinfo *mcp_dinfo; 4944cd96614SDmitry Salychev struct dpaa2_cmd cmd; 4954cd96614SDmitry Salychev uint16_t rc_token, ni_token; 496d936c29eSJustin Hibbits if_t ifp; 497ba7319e9SDmitry Salychev char tq_name[32]; 498ba7319e9SDmitry Salychev int error; 499ba7319e9SDmitry Salychev 500ba7319e9SDmitry Salychev sc->dev = dev; 501ba7319e9SDmitry Salychev sc->ifp = NULL; 502ba7319e9SDmitry Salychev sc->miibus = NULL; 503ba7319e9SDmitry Salychev sc->mii = NULL; 504ba7319e9SDmitry Salychev sc->media_status = 0; 505ba7319e9SDmitry Salychev sc->if_flags = 0; 506ba7319e9SDmitry Salychev sc->link_state = LINK_STATE_UNKNOWN; 507ba7319e9SDmitry Salychev sc->buf_align = 0; 508ba7319e9SDmitry Salychev 509ba7319e9SDmitry Salychev /* For debug purposes only! */ 510ba7319e9SDmitry Salychev sc->rx_anomaly_frames = 0; 511ba7319e9SDmitry Salychev sc->rx_single_buf_frames = 0; 512ba7319e9SDmitry Salychev sc->rx_sg_buf_frames = 0; 513ba7319e9SDmitry Salychev sc->rx_enq_rej_frames = 0; 514ba7319e9SDmitry Salychev sc->rx_ieoi_err_frames = 0; 515ba7319e9SDmitry Salychev sc->tx_single_buf_frames = 0; 516ba7319e9SDmitry Salychev sc->tx_sg_frames = 0; 517ba7319e9SDmitry Salychev 518ba7319e9SDmitry Salychev DPAA2_ATOMIC_XCHG(&sc->buf_num, 0); 519ba7319e9SDmitry Salychev DPAA2_ATOMIC_XCHG(&sc->buf_free, 0); 520ba7319e9SDmitry Salychev 521ba7319e9SDmitry Salychev sc->rxd_dmat = NULL; 522ba7319e9SDmitry Salychev sc->qos_dmat = NULL; 523ba7319e9SDmitry Salychev 52458983e4bSDmitry Salychev sc->qos_kcfg.dmap = NULL; 52558983e4bSDmitry Salychev sc->qos_kcfg.paddr = 0; 52658983e4bSDmitry Salychev sc->qos_kcfg.vaddr = NULL; 527ba7319e9SDmitry Salychev 52858983e4bSDmitry Salychev sc->rxd_kcfg.dmap = NULL; 52958983e4bSDmitry Salychev sc->rxd_kcfg.paddr = 0; 53058983e4bSDmitry Salychev sc->rxd_kcfg.vaddr = NULL; 531ba7319e9SDmitry Salychev 532ba7319e9SDmitry Salychev sc->mac.dpmac_id = 0; 533ba7319e9SDmitry Salychev sc->mac.phy_dev = NULL; 534ba7319e9SDmitry Salychev memset(sc->mac.addr, 0, ETHER_ADDR_LEN); 535ba7319e9SDmitry Salychev 536ba7319e9SDmitry Salychev error = bus_alloc_resources(sc->dev, dpaa2_ni_spec, sc->res); 537ba7319e9SDmitry Salychev if (error) { 538ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate resources: " 539ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 5404cd96614SDmitry Salychev goto err_exit; 541ba7319e9SDmitry Salychev } 542ba7319e9SDmitry Salychev 543ba7319e9SDmitry Salychev /* Obtain MC portal. */ 54458983e4bSDmitry Salychev mcp_dev = (device_t) rman_get_start(sc->res[DPAA2_NI_MCP_RID(0)]); 545ba7319e9SDmitry Salychev mcp_dinfo = device_get_ivars(mcp_dev); 546ba7319e9SDmitry Salychev dinfo->portal = mcp_dinfo->portal; 547ba7319e9SDmitry Salychev 548ba7319e9SDmitry Salychev mtx_init(&sc->lock, device_get_nameunit(dev), "dpaa2_ni", MTX_DEF); 549ba7319e9SDmitry Salychev 550ba7319e9SDmitry Salychev /* Allocate network interface */ 551ba7319e9SDmitry Salychev ifp = if_alloc(IFT_ETHER); 552ba7319e9SDmitry Salychev sc->ifp = ifp; 553ba7319e9SDmitry Salychev if_initname(ifp, DPAA2_NI_IFNAME, device_get_unit(sc->dev)); 554ba7319e9SDmitry Salychev 555d936c29eSJustin Hibbits if_setsoftc(ifp, sc); 556d936c29eSJustin Hibbits if_setflags(ifp, IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST); 557d936c29eSJustin Hibbits if_setinitfn(ifp, dpaa2_ni_init); 558d936c29eSJustin Hibbits if_setioctlfn(ifp, dpaa2_ni_ioctl); 559d936c29eSJustin Hibbits if_settransmitfn(ifp, dpaa2_ni_transmit); 560d936c29eSJustin Hibbits if_setqflushfn(ifp, dpaa2_ni_qflush); 561ba7319e9SDmitry Salychev 562d936c29eSJustin Hibbits if_setcapabilities(ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU); 563d936c29eSJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 564ba7319e9SDmitry Salychev 5654cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 566ba7319e9SDmitry Salychev 567ba7319e9SDmitry Salychev /* Open resource container and network interface object. */ 5684cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 569ba7319e9SDmitry Salychev if (error) { 570ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 571ba7319e9SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 5724cd96614SDmitry Salychev goto err_exit; 573ba7319e9SDmitry Salychev } 5744cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 575ba7319e9SDmitry Salychev if (error) { 576ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 577ba7319e9SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 5784cd96614SDmitry Salychev goto close_rc; 579ba7319e9SDmitry Salychev } 580ba7319e9SDmitry Salychev 58158983e4bSDmitry Salychev bzero(tq_name, sizeof(tq_name)); 58258983e4bSDmitry Salychev snprintf(tq_name, sizeof(tq_name), "%s_tqbp", device_get_nameunit(dev)); 58358983e4bSDmitry Salychev 5844cd96614SDmitry Salychev /* 5854cd96614SDmitry Salychev * XXX-DSL: Release new buffers on Buffer Pool State Change Notification 5864cd96614SDmitry Salychev * (BPSCN) returned as a result to the VDQ command instead. 5874cd96614SDmitry Salychev * It is similar to CDAN processed in dpaa2_io_intr(). 5884cd96614SDmitry Salychev */ 589ba7319e9SDmitry Salychev /* Create a taskqueue thread to release new buffers to the pool. */ 590ba7319e9SDmitry Salychev sc->bp_taskq = taskqueue_create(tq_name, M_WAITOK, 591ba7319e9SDmitry Salychev taskqueue_thread_enqueue, &sc->bp_taskq); 592ba7319e9SDmitry Salychev taskqueue_start_threads(&sc->bp_taskq, 1, PI_NET, "%s", tq_name); 593ba7319e9SDmitry Salychev 59458983e4bSDmitry Salychev /* sc->cleanup_taskq = taskqueue_create("dpaa2_ch cleanup", M_WAITOK, */ 59558983e4bSDmitry Salychev /* taskqueue_thread_enqueue, &sc->cleanup_taskq); */ 59658983e4bSDmitry Salychev /* taskqueue_start_threads(&sc->cleanup_taskq, 1, PI_NET, */ 59758983e4bSDmitry Salychev /* "dpaa2_ch cleanup"); */ 59858983e4bSDmitry Salychev 599ba7319e9SDmitry Salychev error = dpaa2_ni_setup(dev); 600ba7319e9SDmitry Salychev if (error) { 601ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup DPNI: error=%d\n", 602ba7319e9SDmitry Salychev __func__, error); 6034cd96614SDmitry Salychev goto close_ni; 604ba7319e9SDmitry Salychev } 605ba7319e9SDmitry Salychev error = dpaa2_ni_setup_channels(dev); 606ba7319e9SDmitry Salychev if (error) { 607ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup QBMan channels: " 608ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 6094cd96614SDmitry Salychev goto close_ni; 610ba7319e9SDmitry Salychev } 611ba7319e9SDmitry Salychev 612ba7319e9SDmitry Salychev error = dpaa2_ni_bind(dev); 613ba7319e9SDmitry Salychev if (error) { 614ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to bind DPNI: error=%d\n", 615ba7319e9SDmitry Salychev __func__, error); 6164cd96614SDmitry Salychev goto close_ni; 617ba7319e9SDmitry Salychev } 618ba7319e9SDmitry Salychev error = dpaa2_ni_setup_irqs(dev); 619ba7319e9SDmitry Salychev if (error) { 620ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup IRQs: error=%d\n", 621ba7319e9SDmitry Salychev __func__, error); 6224cd96614SDmitry Salychev goto close_ni; 623ba7319e9SDmitry Salychev } 624ba7319e9SDmitry Salychev error = dpaa2_ni_setup_sysctls(sc); 625ba7319e9SDmitry Salychev if (error) { 626ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup sysctls: error=%d\n", 627ba7319e9SDmitry Salychev __func__, error); 6284cd96614SDmitry Salychev goto close_ni; 629ba7319e9SDmitry Salychev } 630ba7319e9SDmitry Salychev 631ba7319e9SDmitry Salychev ether_ifattach(sc->ifp, sc->mac.addr); 632ba7319e9SDmitry Salychev callout_init(&sc->mii_callout, 0); 633ba7319e9SDmitry Salychev 634ba7319e9SDmitry Salychev return (0); 635ba7319e9SDmitry Salychev 6364cd96614SDmitry Salychev close_ni: 6374cd96614SDmitry Salychev DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 6384cd96614SDmitry Salychev close_rc: 6394cd96614SDmitry Salychev DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 640ba7319e9SDmitry Salychev err_exit: 641ba7319e9SDmitry Salychev return (ENXIO); 642ba7319e9SDmitry Salychev } 643ba7319e9SDmitry Salychev 644ba7319e9SDmitry Salychev static void 645ba7319e9SDmitry Salychev dpaa2_ni_fixed_media_status(if_t ifp, struct ifmediareq* ifmr) 646ba7319e9SDmitry Salychev { 647d936c29eSJustin Hibbits struct dpaa2_ni_softc *sc = if_getsoftc(ifp); 648ba7319e9SDmitry Salychev 649ba7319e9SDmitry Salychev DPNI_LOCK(sc); 650ba7319e9SDmitry Salychev ifmr->ifm_count = 0; 651ba7319e9SDmitry Salychev ifmr->ifm_mask = 0; 652ba7319e9SDmitry Salychev ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 653ba7319e9SDmitry Salychev ifmr->ifm_current = ifmr->ifm_active = 654ba7319e9SDmitry Salychev sc->fixed_ifmedia.ifm_cur->ifm_media; 655ba7319e9SDmitry Salychev 656ba7319e9SDmitry Salychev /* 657ba7319e9SDmitry Salychev * In non-PHY usecases, we need to signal link state up, otherwise 658ba7319e9SDmitry Salychev * certain things requiring a link event (e.g async DHCP client) from 659ba7319e9SDmitry Salychev * devd do not happen. 660ba7319e9SDmitry Salychev */ 661d936c29eSJustin Hibbits if (if_getlinkstate(ifp) == LINK_STATE_UNKNOWN) { 662ba7319e9SDmitry Salychev if_link_state_change(ifp, LINK_STATE_UP); 663ba7319e9SDmitry Salychev } 664ba7319e9SDmitry Salychev 665ba7319e9SDmitry Salychev /* 666ba7319e9SDmitry Salychev * TODO: Check the status of the link partner (DPMAC, DPNI or other) and 667ba7319e9SDmitry Salychev * reset if down. This is different to the DPAA2_MAC_LINK_TYPE_PHY as 668ba7319e9SDmitry Salychev * the MC firmware sets the status, instead of us telling the MC what 669ba7319e9SDmitry Salychev * it is. 670ba7319e9SDmitry Salychev */ 671ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 672ba7319e9SDmitry Salychev 673ba7319e9SDmitry Salychev return; 674ba7319e9SDmitry Salychev } 675ba7319e9SDmitry Salychev 676ba7319e9SDmitry Salychev static void 677ba7319e9SDmitry Salychev dpaa2_ni_setup_fixed_link(struct dpaa2_ni_softc *sc) 678ba7319e9SDmitry Salychev { 679ba7319e9SDmitry Salychev /* 680ba7319e9SDmitry Salychev * FIXME: When the DPNI is connected to a DPMAC, we can get the 681ba7319e9SDmitry Salychev * 'apparent' speed from it. 682ba7319e9SDmitry Salychev */ 683ba7319e9SDmitry Salychev sc->fixed_link = true; 684ba7319e9SDmitry Salychev 685ba7319e9SDmitry Salychev ifmedia_init(&sc->fixed_ifmedia, 0, dpaa2_ni_media_change, 686ba7319e9SDmitry Salychev dpaa2_ni_fixed_media_status); 687ba7319e9SDmitry Salychev ifmedia_add(&sc->fixed_ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL); 688ba7319e9SDmitry Salychev ifmedia_set(&sc->fixed_ifmedia, IFM_ETHER | IFM_1000_T); 689ba7319e9SDmitry Salychev } 690ba7319e9SDmitry Salychev 691ba7319e9SDmitry Salychev static int 692ba7319e9SDmitry Salychev dpaa2_ni_detach(device_t dev) 693ba7319e9SDmitry Salychev { 6944cd96614SDmitry Salychev /* TBD */ 695ba7319e9SDmitry Salychev return (0); 696ba7319e9SDmitry Salychev } 697ba7319e9SDmitry Salychev 698ba7319e9SDmitry Salychev /** 699ba7319e9SDmitry Salychev * @brief Configure DPAA2 network interface object. 700ba7319e9SDmitry Salychev */ 701ba7319e9SDmitry Salychev static int 702ba7319e9SDmitry Salychev dpaa2_ni_setup(device_t dev) 703ba7319e9SDmitry Salychev { 7044cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 705ba7319e9SDmitry Salychev device_t child = dev; 706ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 7074cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 708ba7319e9SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 709ba7319e9SDmitry Salychev struct dpaa2_ep_desc ep1_desc, ep2_desc; /* endpoint descriptors */ 7104cd96614SDmitry Salychev struct dpaa2_cmd cmd; 711ba7319e9SDmitry Salychev uint8_t eth_bca[ETHER_ADDR_LEN]; /* broadcast physical address */ 7124cd96614SDmitry Salychev uint16_t rc_token, ni_token, mac_token; 713ba7319e9SDmitry Salychev struct dpaa2_mac_attr attr; 714ba7319e9SDmitry Salychev enum dpaa2_mac_link_type link_type; 715ba7319e9SDmitry Salychev uint32_t link; 716ba7319e9SDmitry Salychev int error; 717ba7319e9SDmitry Salychev 7184cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 7194cd96614SDmitry Salychev 7204cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 7214cd96614SDmitry Salychev if (error) { 7224cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 7234cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 7244cd96614SDmitry Salychev goto err_exit; 7254cd96614SDmitry Salychev } 7264cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 7274cd96614SDmitry Salychev if (error) { 7284cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 7294cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 7304cd96614SDmitry Salychev goto close_rc; 7314cd96614SDmitry Salychev } 7324cd96614SDmitry Salychev 733ba7319e9SDmitry Salychev /* Check if we can work with this DPNI object. */ 7344cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_API_VERSION(dev, child, &cmd, &sc->api_major, 7354cd96614SDmitry Salychev &sc->api_minor); 736ba7319e9SDmitry Salychev if (error) { 737ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to get DPNI API version\n", 738ba7319e9SDmitry Salychev __func__); 7394cd96614SDmitry Salychev goto close_ni; 740ba7319e9SDmitry Salychev } 741ba7319e9SDmitry Salychev if (dpaa2_ni_cmp_api_version(sc, DPNI_VER_MAJOR, DPNI_VER_MINOR) < 0) { 742ba7319e9SDmitry Salychev device_printf(dev, "%s: DPNI API version %u.%u not supported, " 743ba7319e9SDmitry Salychev "need >= %u.%u\n", __func__, sc->api_major, sc->api_minor, 744ba7319e9SDmitry Salychev DPNI_VER_MAJOR, DPNI_VER_MINOR); 745ba7319e9SDmitry Salychev error = ENODEV; 7464cd96614SDmitry Salychev goto close_ni; 747ba7319e9SDmitry Salychev } 748ba7319e9SDmitry Salychev 749ba7319e9SDmitry Salychev /* Reset the DPNI object. */ 7504cd96614SDmitry Salychev error = DPAA2_CMD_NI_RESET(dev, child, &cmd); 751ba7319e9SDmitry Salychev if (error) { 752ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to reset DPNI: id=%d\n", 753ba7319e9SDmitry Salychev __func__, dinfo->id); 7544cd96614SDmitry Salychev goto close_ni; 755ba7319e9SDmitry Salychev } 756ba7319e9SDmitry Salychev 757ba7319e9SDmitry Salychev /* Obtain attributes of the DPNI object. */ 7584cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_ATTRIBUTES(dev, child, &cmd, &sc->attr); 759ba7319e9SDmitry Salychev if (error) { 760ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain DPNI attributes: " 761ba7319e9SDmitry Salychev "id=%d\n", __func__, dinfo->id); 7624cd96614SDmitry Salychev goto close_ni; 763ba7319e9SDmitry Salychev } 764ba7319e9SDmitry Salychev if (bootverbose) { 7654cd96614SDmitry Salychev device_printf(dev, "\toptions=0x%#x queues=%d tx_channels=%d " 766ba7319e9SDmitry Salychev "wriop_version=%#x\n", sc->attr.options, sc->attr.num.queues, 767ba7319e9SDmitry Salychev sc->attr.num.channels, sc->attr.wriop_ver); 768ba7319e9SDmitry Salychev device_printf(dev, "\ttraffic classes: rx=%d tx=%d " 769ba7319e9SDmitry Salychev "cgs_groups=%d\n", sc->attr.num.rx_tcs, sc->attr.num.tx_tcs, 770ba7319e9SDmitry Salychev sc->attr.num.cgs); 771ba7319e9SDmitry Salychev device_printf(dev, "\ttable entries: mac=%d vlan=%d qos=%d " 772ba7319e9SDmitry Salychev "fs=%d\n", sc->attr.entries.mac, sc->attr.entries.vlan, 773ba7319e9SDmitry Salychev sc->attr.entries.qos, sc->attr.entries.fs); 774ba7319e9SDmitry Salychev device_printf(dev, "\tkey sizes: qos=%d fs=%d\n", 775ba7319e9SDmitry Salychev sc->attr.key_size.qos, sc->attr.key_size.fs); 776ba7319e9SDmitry Salychev } 777ba7319e9SDmitry Salychev 778ba7319e9SDmitry Salychev /* Configure buffer layouts of the DPNI queues. */ 7794cd96614SDmitry Salychev error = dpaa2_ni_set_buf_layout(dev); 780ba7319e9SDmitry Salychev if (error) { 781ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to configure buffer layout\n", 782ba7319e9SDmitry Salychev __func__); 7834cd96614SDmitry Salychev goto close_ni; 784ba7319e9SDmitry Salychev } 785ba7319e9SDmitry Salychev 786ba7319e9SDmitry Salychev /* Configure DMA resources. */ 787ba7319e9SDmitry Salychev error = dpaa2_ni_setup_dma(sc); 788ba7319e9SDmitry Salychev if (error) { 789ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup DMA\n", __func__); 7904cd96614SDmitry Salychev goto close_ni; 791ba7319e9SDmitry Salychev } 792ba7319e9SDmitry Salychev 793ba7319e9SDmitry Salychev /* Setup link between DPNI and an object it's connected to. */ 794ba7319e9SDmitry Salychev ep1_desc.obj_id = dinfo->id; 795ba7319e9SDmitry Salychev ep1_desc.if_id = 0; /* DPNI has the only endpoint */ 796ba7319e9SDmitry Salychev ep1_desc.type = dinfo->dtype; 797ba7319e9SDmitry Salychev 7984cd96614SDmitry Salychev error = DPAA2_CMD_RC_GET_CONN(dev, child, DPAA2_CMD_TK(&cmd, rc_token), 799ba7319e9SDmitry Salychev &ep1_desc, &ep2_desc, &link); 8004cd96614SDmitry Salychev if (error) { 801ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain an object DPNI is " 802ba7319e9SDmitry Salychev "connected to: error=%d\n", __func__, error); 8034cd96614SDmitry Salychev } else { 804ba7319e9SDmitry Salychev device_printf(dev, "connected to %s (id=%d)\n", 805ba7319e9SDmitry Salychev dpaa2_ttos(ep2_desc.type), ep2_desc.obj_id); 806ba7319e9SDmitry Salychev 8074cd96614SDmitry Salychev error = dpaa2_ni_set_mac_addr(dev); 8084cd96614SDmitry Salychev if (error) { 8094cd96614SDmitry Salychev device_printf(dev, "%s: failed to set MAC address: " 8104cd96614SDmitry Salychev "error=%d\n", __func__, error); 8114cd96614SDmitry Salychev } 812ba7319e9SDmitry Salychev 813ba7319e9SDmitry Salychev if (ep2_desc.type == DPAA2_DEV_MAC) { 814ba7319e9SDmitry Salychev /* 815ba7319e9SDmitry Salychev * This is the simplest case when DPNI is connected to 816ba7319e9SDmitry Salychev * DPMAC directly. 817ba7319e9SDmitry Salychev */ 818ba7319e9SDmitry Salychev sc->mac.dpmac_id = ep2_desc.obj_id; 819ba7319e9SDmitry Salychev 820ba7319e9SDmitry Salychev link_type = DPAA2_MAC_LINK_TYPE_NONE; 821ba7319e9SDmitry Salychev 822ba7319e9SDmitry Salychev /* 823ba7319e9SDmitry Salychev * Need to determine if DPMAC type is PHY (attached to 824ba7319e9SDmitry Salychev * conventional MII PHY) or FIXED (usually SFP/SerDes, 825ba7319e9SDmitry Salychev * link state managed by MC firmware). 826ba7319e9SDmitry Salychev */ 827ba7319e9SDmitry Salychev error = DPAA2_CMD_MAC_OPEN(sc->dev, child, 8284cd96614SDmitry Salychev DPAA2_CMD_TK(&cmd, rc_token), sc->mac.dpmac_id, 8294cd96614SDmitry Salychev &mac_token); 830ba7319e9SDmitry Salychev /* 831ba7319e9SDmitry Salychev * Under VFIO, the DPMAC might be sitting in another 832ba7319e9SDmitry Salychev * container (DPRC) we don't have access to. 833ba7319e9SDmitry Salychev * Assume DPAA2_MAC_LINK_TYPE_FIXED if this is 834ba7319e9SDmitry Salychev * the case. 835ba7319e9SDmitry Salychev */ 836ba7319e9SDmitry Salychev if (error) { 837ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to open " 838ba7319e9SDmitry Salychev "connected DPMAC: %d (assuming in other DPRC)\n", __func__, 839ba7319e9SDmitry Salychev sc->mac.dpmac_id); 840ba7319e9SDmitry Salychev link_type = DPAA2_MAC_LINK_TYPE_FIXED; 841ba7319e9SDmitry Salychev } else { 842ba7319e9SDmitry Salychev error = DPAA2_CMD_MAC_GET_ATTRIBUTES(dev, child, 8434cd96614SDmitry Salychev &cmd, &attr); 8444cd96614SDmitry Salychev if (error) { 845ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to get " 846ba7319e9SDmitry Salychev "DPMAC attributes: id=%d, " 847ba7319e9SDmitry Salychev "error=%d\n", __func__, dinfo->id, 848ba7319e9SDmitry Salychev error); 8494cd96614SDmitry Salychev } else { 850ba7319e9SDmitry Salychev link_type = attr.link_type; 851ba7319e9SDmitry Salychev } 8524cd96614SDmitry Salychev } 8534cd96614SDmitry Salychev DPAA2_CMD_MAC_CLOSE(dev, child, &cmd); 854ba7319e9SDmitry Salychev 855ba7319e9SDmitry Salychev if (link_type == DPAA2_MAC_LINK_TYPE_FIXED) { 856ba7319e9SDmitry Salychev device_printf(dev, "connected DPMAC is in FIXED " 857ba7319e9SDmitry Salychev "mode\n"); 858ba7319e9SDmitry Salychev dpaa2_ni_setup_fixed_link(sc); 859ba7319e9SDmitry Salychev } else if (link_type == DPAA2_MAC_LINK_TYPE_PHY) { 860ba7319e9SDmitry Salychev device_printf(dev, "connected DPMAC is in PHY " 861ba7319e9SDmitry Salychev "mode\n"); 862ba7319e9SDmitry Salychev error = DPAA2_MC_GET_PHY_DEV(dev, 863ba7319e9SDmitry Salychev &sc->mac.phy_dev, sc->mac.dpmac_id); 864ba7319e9SDmitry Salychev if (error == 0) { 865ba7319e9SDmitry Salychev error = MEMAC_MDIO_SET_NI_DEV( 866ba7319e9SDmitry Salychev sc->mac.phy_dev, dev); 8674cd96614SDmitry Salychev if (error != 0) { 868ba7319e9SDmitry Salychev device_printf(dev, "%s: failed " 869ba7319e9SDmitry Salychev "to set dpni dev on memac " 870ba7319e9SDmitry Salychev "mdio dev %s: error=%d\n", 871ba7319e9SDmitry Salychev __func__, 872ba7319e9SDmitry Salychev device_get_nameunit( 873ba7319e9SDmitry Salychev sc->mac.phy_dev), error); 874ba7319e9SDmitry Salychev } 8754cd96614SDmitry Salychev } 876ba7319e9SDmitry Salychev if (error == 0) { 877ba7319e9SDmitry Salychev error = MEMAC_MDIO_GET_PHY_LOC( 878ba7319e9SDmitry Salychev sc->mac.phy_dev, &sc->mac.phy_loc); 8794cd96614SDmitry Salychev if (error == ENODEV) { 880ba7319e9SDmitry Salychev error = 0; 8814cd96614SDmitry Salychev } 8824cd96614SDmitry Salychev if (error != 0) { 883ba7319e9SDmitry Salychev device_printf(dev, "%s: failed " 884ba7319e9SDmitry Salychev "to get phy location from " 885ba7319e9SDmitry Salychev "memac mdio dev %s: error=%d\n", 886ba7319e9SDmitry Salychev __func__, device_get_nameunit( 887ba7319e9SDmitry Salychev sc->mac.phy_dev), error); 888ba7319e9SDmitry Salychev } 8894cd96614SDmitry Salychev } 890ba7319e9SDmitry Salychev if (error == 0) { 891ba7319e9SDmitry Salychev error = mii_attach(sc->mac.phy_dev, 892ba7319e9SDmitry Salychev &sc->miibus, sc->ifp, 893ba7319e9SDmitry Salychev dpaa2_ni_media_change, 894ba7319e9SDmitry Salychev dpaa2_ni_media_status, 895ba7319e9SDmitry Salychev BMSR_DEFCAPMASK, sc->mac.phy_loc, 896ba7319e9SDmitry Salychev MII_OFFSET_ANY, 0); 8974cd96614SDmitry Salychev if (error != 0) { 898ba7319e9SDmitry Salychev device_printf(dev, "%s: failed " 899ba7319e9SDmitry Salychev "to attach to miibus: " 900ba7319e9SDmitry Salychev "error=%d\n", 901ba7319e9SDmitry Salychev __func__, error); 902ba7319e9SDmitry Salychev } 9034cd96614SDmitry Salychev } 9044cd96614SDmitry Salychev if (error == 0) { 905ba7319e9SDmitry Salychev sc->mii = device_get_softc(sc->miibus); 9064cd96614SDmitry Salychev } 907ba7319e9SDmitry Salychev } else { 908ba7319e9SDmitry Salychev device_printf(dev, "%s: DPMAC link type is not " 909ba7319e9SDmitry Salychev "supported\n", __func__); 910ba7319e9SDmitry Salychev } 911ba7319e9SDmitry Salychev } else if (ep2_desc.type == DPAA2_DEV_NI || 912ba7319e9SDmitry Salychev ep2_desc.type == DPAA2_DEV_MUX || 913ba7319e9SDmitry Salychev ep2_desc.type == DPAA2_DEV_SW) { 914ba7319e9SDmitry Salychev dpaa2_ni_setup_fixed_link(sc); 915ba7319e9SDmitry Salychev } 916ba7319e9SDmitry Salychev } 917ba7319e9SDmitry Salychev 918ba7319e9SDmitry Salychev /* Select mode to enqueue frames. */ 919ba7319e9SDmitry Salychev /* ... TBD ... */ 920ba7319e9SDmitry Salychev 921ba7319e9SDmitry Salychev /* 922ba7319e9SDmitry Salychev * Update link configuration to enable Rx/Tx pause frames support. 923ba7319e9SDmitry Salychev * 924ba7319e9SDmitry Salychev * NOTE: MC may generate an interrupt to the DPMAC and request changes 925ba7319e9SDmitry Salychev * in link configuration. It might be necessary to attach miibus 926ba7319e9SDmitry Salychev * and PHY before this point. 927ba7319e9SDmitry Salychev */ 9284cd96614SDmitry Salychev error = dpaa2_ni_set_pause_frame(dev); 929ba7319e9SDmitry Salychev if (error) { 930ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to configure Rx/Tx pause " 931ba7319e9SDmitry Salychev "frames\n", __func__); 9324cd96614SDmitry Salychev goto close_ni; 933ba7319e9SDmitry Salychev } 934ba7319e9SDmitry Salychev 935ba7319e9SDmitry Salychev /* Configure ingress traffic classification. */ 9364cd96614SDmitry Salychev error = dpaa2_ni_set_qos_table(dev); 9374cd96614SDmitry Salychev if (error) { 938ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to configure QoS table: " 939ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 9404cd96614SDmitry Salychev goto close_ni; 9414cd96614SDmitry Salychev } 942ba7319e9SDmitry Salychev 943ba7319e9SDmitry Salychev /* Add broadcast physical address to the MAC filtering table. */ 944ba7319e9SDmitry Salychev memset(eth_bca, 0xff, ETHER_ADDR_LEN); 9454cd96614SDmitry Salychev error = DPAA2_CMD_NI_ADD_MAC_ADDR(dev, child, DPAA2_CMD_TK(&cmd, 9464cd96614SDmitry Salychev ni_token), eth_bca); 947ba7319e9SDmitry Salychev if (error) { 948ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to add broadcast physical " 949ba7319e9SDmitry Salychev "address to the MAC filtering table\n", __func__); 9504cd96614SDmitry Salychev goto close_ni; 951ba7319e9SDmitry Salychev } 952ba7319e9SDmitry Salychev 953ba7319e9SDmitry Salychev /* Set the maximum allowed length for received frames. */ 9544cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_MFL(dev, child, &cmd, DPAA2_ETH_MFL); 955ba7319e9SDmitry Salychev if (error) { 956ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set maximum length for " 957ba7319e9SDmitry Salychev "received frames\n", __func__); 9584cd96614SDmitry Salychev goto close_ni; 959ba7319e9SDmitry Salychev } 960ba7319e9SDmitry Salychev 9614cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 9624cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 963ba7319e9SDmitry Salychev return (0); 9644cd96614SDmitry Salychev 9654cd96614SDmitry Salychev close_ni: 9664cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 9674cd96614SDmitry Salychev close_rc: 9684cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 9694cd96614SDmitry Salychev err_exit: 9704cd96614SDmitry Salychev return (error); 971ba7319e9SDmitry Salychev } 972ba7319e9SDmitry Salychev 973ba7319e9SDmitry Salychev /** 974ba7319e9SDmitry Salychev * @brief Сonfigure QBMan channels and register data availability notifications. 975ba7319e9SDmitry Salychev */ 976ba7319e9SDmitry Salychev static int 977ba7319e9SDmitry Salychev dpaa2_ni_setup_channels(device_t dev) 978ba7319e9SDmitry Salychev { 97958983e4bSDmitry Salychev device_t iodev, condev, bpdev; 980ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 981ba7319e9SDmitry Salychev uint32_t i, num_chan; 9824cd96614SDmitry Salychev int error; 983ba7319e9SDmitry Salychev 98458983e4bSDmitry Salychev /* Calculate number of the channels based on the allocated resources */ 98558983e4bSDmitry Salychev for (i = 0; i < DPAA2_NI_IO_RES_NUM; i++) { 98658983e4bSDmitry Salychev if (!sc->res[DPAA2_NI_IO_RID(i)]) { 987ba7319e9SDmitry Salychev break; 9884cd96614SDmitry Salychev } 9894cd96614SDmitry Salychev } 990ba7319e9SDmitry Salychev num_chan = i; 99158983e4bSDmitry Salychev for (i = 0; i < DPAA2_NI_CON_RES_NUM; i++) { 99258983e4bSDmitry Salychev if (!sc->res[DPAA2_NI_CON_RID(i)]) { 993ba7319e9SDmitry Salychev break; 9944cd96614SDmitry Salychev } 9954cd96614SDmitry Salychev } 996ba7319e9SDmitry Salychev num_chan = i < num_chan ? i : num_chan; 99758983e4bSDmitry Salychev sc->chan_n = num_chan > DPAA2_MAX_CHANNELS 99858983e4bSDmitry Salychev ? DPAA2_MAX_CHANNELS : num_chan; 999ba7319e9SDmitry Salychev sc->chan_n = sc->chan_n > sc->attr.num.queues 1000ba7319e9SDmitry Salychev ? sc->attr.num.queues : sc->chan_n; 1001ba7319e9SDmitry Salychev 100258983e4bSDmitry Salychev KASSERT(sc->chan_n > 0u, ("%s: positive number of channels expected: " 100358983e4bSDmitry Salychev "chan_n=%d", __func__, sc->chan_n)); 100458983e4bSDmitry Salychev 1005ba7319e9SDmitry Salychev device_printf(dev, "channels=%d\n", sc->chan_n); 1006ba7319e9SDmitry Salychev 100758983e4bSDmitry Salychev for (i = 0; i < sc->chan_n; i++) { 100858983e4bSDmitry Salychev iodev = (device_t)rman_get_start(sc->res[DPAA2_NI_IO_RID(i)]); 100958983e4bSDmitry Salychev condev = (device_t)rman_get_start(sc->res[DPAA2_NI_CON_RID(i)]); 101058983e4bSDmitry Salychev /* Only one buffer pool available at the moment */ 101158983e4bSDmitry Salychev bpdev = (device_t)rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]); 1012ba7319e9SDmitry Salychev 101358983e4bSDmitry Salychev error = dpaa2_chan_setup(dev, iodev, condev, bpdev, 101458983e4bSDmitry Salychev &sc->channels[i], i, dpaa2_ni_cleanup_task); 101558983e4bSDmitry Salychev if (error != 0) { 101658983e4bSDmitry Salychev device_printf(dev, "%s: dpaa2_chan_setup() failed: " 101758983e4bSDmitry Salychev "error=%d, chan_id=%d\n", __func__, error, i); 10184cd96614SDmitry Salychev return (error); 10194cd96614SDmitry Salychev } 10204cd96614SDmitry Salychev } 10214cd96614SDmitry Salychev 102258983e4bSDmitry Salychev /* There is exactly one Rx error queue per network interface */ 102358983e4bSDmitry Salychev error = dpaa2_chan_setup_fq(dev, sc->channels[0], DPAA2_NI_QUEUE_RX_ERR); 102458983e4bSDmitry Salychev if (error != 0) { 1025ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to prepare RxError queue: " 1026ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 1027ba7319e9SDmitry Salychev return (error); 1028ba7319e9SDmitry Salychev } 1029ba7319e9SDmitry Salychev 1030ba7319e9SDmitry Salychev return (0); 1031ba7319e9SDmitry Salychev } 1032ba7319e9SDmitry Salychev 1033ba7319e9SDmitry Salychev /** 1034ba7319e9SDmitry Salychev * @brief Bind DPNI to DPBPs, DPIOs, frame queues and channels. 1035ba7319e9SDmitry Salychev */ 1036ba7319e9SDmitry Salychev static int 1037ba7319e9SDmitry Salychev dpaa2_ni_bind(device_t dev) 1038ba7319e9SDmitry Salychev { 10394cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 10404cd96614SDmitry Salychev device_t child = dev; 10414cd96614SDmitry Salychev device_t bp_dev; 1042ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 10434cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 10444cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 1045ba7319e9SDmitry Salychev struct dpaa2_devinfo *bp_info; 10464cd96614SDmitry Salychev struct dpaa2_cmd cmd; 1047ba7319e9SDmitry Salychev struct dpaa2_ni_pools_cfg pools_cfg; 1048ba7319e9SDmitry Salychev struct dpaa2_ni_err_cfg err_cfg; 104958983e4bSDmitry Salychev struct dpaa2_channel *chan; 10504cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1051ba7319e9SDmitry Salychev int error; 1052ba7319e9SDmitry Salychev 10534cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 10544cd96614SDmitry Salychev 10554cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 10564cd96614SDmitry Salychev if (error) { 10574cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 10584cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 10594cd96614SDmitry Salychev goto err_exit; 10604cd96614SDmitry Salychev } 10614cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 10624cd96614SDmitry Salychev if (error) { 10634cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 10644cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 10654cd96614SDmitry Salychev goto close_rc; 10664cd96614SDmitry Salychev } 10674cd96614SDmitry Salychev 1068ba7319e9SDmitry Salychev /* Select buffer pool (only one available at the moment). */ 106958983e4bSDmitry Salychev bp_dev = (device_t) rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]); 1070ba7319e9SDmitry Salychev bp_info = device_get_ivars(bp_dev); 1071ba7319e9SDmitry Salychev 1072ba7319e9SDmitry Salychev /* Configure buffers pool. */ 1073ba7319e9SDmitry Salychev pools_cfg.pools_num = 1; 1074ba7319e9SDmitry Salychev pools_cfg.pools[0].bp_obj_id = bp_info->id; 1075ba7319e9SDmitry Salychev pools_cfg.pools[0].backup_flag = 0; 1076ba7319e9SDmitry Salychev pools_cfg.pools[0].buf_sz = sc->buf_sz; 10774cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_POOLS(dev, child, &cmd, &pools_cfg); 1078ba7319e9SDmitry Salychev if (error) { 1079ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set buffer pools\n", __func__); 10804cd96614SDmitry Salychev goto close_ni; 1081ba7319e9SDmitry Salychev } 1082ba7319e9SDmitry Salychev 1083ba7319e9SDmitry Salychev /* Setup ingress traffic distribution. */ 1084ba7319e9SDmitry Salychev error = dpaa2_ni_setup_rx_dist(dev); 1085ba7319e9SDmitry Salychev if (error && error != EOPNOTSUPP) { 1086ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup ingress traffic " 1087ba7319e9SDmitry Salychev "distribution\n", __func__); 10884cd96614SDmitry Salychev goto close_ni; 1089ba7319e9SDmitry Salychev } 10904cd96614SDmitry Salychev if (bootverbose && error == EOPNOTSUPP) { 1091ba7319e9SDmitry Salychev device_printf(dev, "Ingress traffic distribution not " 1092ba7319e9SDmitry Salychev "supported\n"); 10934cd96614SDmitry Salychev } 1094ba7319e9SDmitry Salychev 1095ba7319e9SDmitry Salychev /* Configure handling of error frames. */ 1096ba7319e9SDmitry Salychev err_cfg.err_mask = DPAA2_NI_FAS_RX_ERR_MASK; 1097ba7319e9SDmitry Salychev err_cfg.set_err_fas = false; 1098ba7319e9SDmitry Salychev err_cfg.action = DPAA2_NI_ERR_DISCARD; 10994cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_ERR_BEHAVIOR(dev, child, &cmd, &err_cfg); 1100ba7319e9SDmitry Salychev if (error) { 1101ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set errors behavior\n", 1102ba7319e9SDmitry Salychev __func__); 11034cd96614SDmitry Salychev goto close_ni; 1104ba7319e9SDmitry Salychev } 1105ba7319e9SDmitry Salychev 1106ba7319e9SDmitry Salychev /* Configure channel queues to generate CDANs. */ 1107ba7319e9SDmitry Salychev for (uint32_t i = 0; i < sc->chan_n; i++) { 1108ba7319e9SDmitry Salychev chan = sc->channels[i]; 1109ba7319e9SDmitry Salychev 1110ba7319e9SDmitry Salychev /* Setup Rx flows. */ 1111ba7319e9SDmitry Salychev for (uint32_t j = 0; j < chan->rxq_n; j++) { 11124cd96614SDmitry Salychev error = dpaa2_ni_setup_rx_flow(dev, &chan->rx_queues[j]); 1113ba7319e9SDmitry Salychev if (error) { 1114ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup Rx " 1115ba7319e9SDmitry Salychev "flow: error=%d\n", __func__, error); 11164cd96614SDmitry Salychev goto close_ni; 1117ba7319e9SDmitry Salychev } 1118ba7319e9SDmitry Salychev } 1119ba7319e9SDmitry Salychev 1120ba7319e9SDmitry Salychev /* Setup Tx flow. */ 11214cd96614SDmitry Salychev error = dpaa2_ni_setup_tx_flow(dev, &chan->txc_queue); 1122ba7319e9SDmitry Salychev if (error) { 1123ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup Tx " 1124ba7319e9SDmitry Salychev "flow: error=%d\n", __func__, error); 11254cd96614SDmitry Salychev goto close_ni; 1126ba7319e9SDmitry Salychev } 1127ba7319e9SDmitry Salychev } 1128ba7319e9SDmitry Salychev 1129ba7319e9SDmitry Salychev /* Configure RxError queue to generate CDAN. */ 11304cd96614SDmitry Salychev error = dpaa2_ni_setup_rx_err_flow(dev, &sc->rxe_queue); 1131ba7319e9SDmitry Salychev if (error) { 1132ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup RxError flow: " 1133ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 11344cd96614SDmitry Salychev goto close_ni; 1135ba7319e9SDmitry Salychev } 1136ba7319e9SDmitry Salychev 1137ba7319e9SDmitry Salychev /* 1138ba7319e9SDmitry Salychev * Get the Queuing Destination ID (QDID) that should be used for frame 1139ba7319e9SDmitry Salychev * enqueue operations. 1140ba7319e9SDmitry Salychev */ 11414cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_QDID(dev, child, &cmd, DPAA2_NI_QUEUE_TX, 1142ba7319e9SDmitry Salychev &sc->tx_qdid); 1143ba7319e9SDmitry Salychev if (error) { 1144ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to get Tx queuing destination " 1145ba7319e9SDmitry Salychev "ID\n", __func__); 11464cd96614SDmitry Salychev goto close_ni; 1147ba7319e9SDmitry Salychev } 1148ba7319e9SDmitry Salychev 11494cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 11504cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 1151ba7319e9SDmitry Salychev return (0); 11524cd96614SDmitry Salychev 11534cd96614SDmitry Salychev close_ni: 11544cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 11554cd96614SDmitry Salychev close_rc: 11564cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 11574cd96614SDmitry Salychev err_exit: 11584cd96614SDmitry Salychev return (error); 1159ba7319e9SDmitry Salychev } 1160ba7319e9SDmitry Salychev 1161ba7319e9SDmitry Salychev /** 1162ba7319e9SDmitry Salychev * @brief Setup ingress traffic distribution. 1163ba7319e9SDmitry Salychev * 1164ba7319e9SDmitry Salychev * NOTE: Ingress traffic distribution is valid only when DPNI_OPT_NO_FS option 1165ba7319e9SDmitry Salychev * hasn't been set for DPNI and a number of DPNI queues > 1. 1166ba7319e9SDmitry Salychev */ 1167ba7319e9SDmitry Salychev static int 1168ba7319e9SDmitry Salychev dpaa2_ni_setup_rx_dist(device_t dev) 1169ba7319e9SDmitry Salychev { 1170ba7319e9SDmitry Salychev /* 1171ba7319e9SDmitry Salychev * Have the interface implicitly distribute traffic based on the default 1172ba7319e9SDmitry Salychev * hash key. 1173ba7319e9SDmitry Salychev */ 1174ba7319e9SDmitry Salychev return (dpaa2_ni_set_hash(dev, DPAA2_RXH_DEFAULT)); 1175ba7319e9SDmitry Salychev } 1176ba7319e9SDmitry Salychev 1177ba7319e9SDmitry Salychev static int 11784cd96614SDmitry Salychev dpaa2_ni_setup_rx_flow(device_t dev, struct dpaa2_ni_fq *fq) 1179ba7319e9SDmitry Salychev { 11804cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 1181ba7319e9SDmitry Salychev device_t child = dev; 11824cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 11834cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 1184ba7319e9SDmitry Salychev struct dpaa2_devinfo *con_info; 11854cd96614SDmitry Salychev struct dpaa2_cmd cmd; 1186ba7319e9SDmitry Salychev struct dpaa2_ni_queue_cfg queue_cfg = {0}; 11874cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1188ba7319e9SDmitry Salychev int error; 1189ba7319e9SDmitry Salychev 11904cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 11914cd96614SDmitry Salychev 11924cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 11934cd96614SDmitry Salychev if (error) { 11944cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 11954cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 11964cd96614SDmitry Salychev goto err_exit; 11974cd96614SDmitry Salychev } 11984cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 11994cd96614SDmitry Salychev if (error) { 12004cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 12014cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 12024cd96614SDmitry Salychev goto close_rc; 12034cd96614SDmitry Salychev } 12044cd96614SDmitry Salychev 1205ba7319e9SDmitry Salychev /* Obtain DPCON associated with the FQ's channel. */ 1206ba7319e9SDmitry Salychev con_info = device_get_ivars(fq->chan->con_dev); 1207ba7319e9SDmitry Salychev 1208ba7319e9SDmitry Salychev queue_cfg.type = DPAA2_NI_QUEUE_RX; 1209ba7319e9SDmitry Salychev queue_cfg.tc = fq->tc; 1210ba7319e9SDmitry Salychev queue_cfg.idx = fq->flowid; 12114cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg); 1212ba7319e9SDmitry Salychev if (error) { 1213ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain Rx queue " 1214ba7319e9SDmitry Salychev "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc, 1215ba7319e9SDmitry Salychev queue_cfg.idx); 12164cd96614SDmitry Salychev goto close_ni; 1217ba7319e9SDmitry Salychev } 1218ba7319e9SDmitry Salychev 1219ba7319e9SDmitry Salychev fq->fqid = queue_cfg.fqid; 1220ba7319e9SDmitry Salychev 1221ba7319e9SDmitry Salychev queue_cfg.dest_id = con_info->id; 1222ba7319e9SDmitry Salychev queue_cfg.dest_type = DPAA2_NI_DEST_DPCON; 1223ba7319e9SDmitry Salychev queue_cfg.priority = 1; 1224ba7319e9SDmitry Salychev queue_cfg.user_ctx = (uint64_t)(uintmax_t) fq; 1225ba7319e9SDmitry Salychev queue_cfg.options = 1226ba7319e9SDmitry Salychev DPAA2_NI_QUEUE_OPT_USER_CTX | 1227ba7319e9SDmitry Salychev DPAA2_NI_QUEUE_OPT_DEST; 12284cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_QUEUE(dev, child, &cmd, &queue_cfg); 1229ba7319e9SDmitry Salychev if (error) { 1230ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to update Rx queue " 1231ba7319e9SDmitry Salychev "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc, 1232ba7319e9SDmitry Salychev queue_cfg.idx); 12334cd96614SDmitry Salychev goto close_ni; 1234ba7319e9SDmitry Salychev } 1235ba7319e9SDmitry Salychev 1236ba7319e9SDmitry Salychev if (bootverbose) { 1237ba7319e9SDmitry Salychev device_printf(dev, "RX queue idx=%d, tc=%d, chan=%d, fqid=%d, " 1238ba7319e9SDmitry Salychev "user_ctx=%#jx\n", fq->flowid, fq->tc, fq->chan->id, 1239ba7319e9SDmitry Salychev fq->fqid, (uint64_t) fq); 1240ba7319e9SDmitry Salychev } 1241ba7319e9SDmitry Salychev 12424cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, &cmd); 12434cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 1244ba7319e9SDmitry Salychev return (0); 12454cd96614SDmitry Salychev 12464cd96614SDmitry Salychev close_ni: 12474cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 12484cd96614SDmitry Salychev close_rc: 12494cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 12504cd96614SDmitry Salychev err_exit: 12514cd96614SDmitry Salychev return (error); 1252ba7319e9SDmitry Salychev } 1253ba7319e9SDmitry Salychev 1254ba7319e9SDmitry Salychev static int 12554cd96614SDmitry Salychev dpaa2_ni_setup_tx_flow(device_t dev, struct dpaa2_ni_fq *fq) 1256ba7319e9SDmitry Salychev { 12574cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 1258ba7319e9SDmitry Salychev device_t child = dev; 1259ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 126058983e4bSDmitry Salychev struct dpaa2_channel *ch = fq->chan; 12614cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 12624cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 1263ba7319e9SDmitry Salychev struct dpaa2_devinfo *con_info; 1264ba7319e9SDmitry Salychev struct dpaa2_ni_queue_cfg queue_cfg = {0}; 1265ba7319e9SDmitry Salychev struct dpaa2_ni_tx_ring *tx; 1266ba7319e9SDmitry Salychev struct dpaa2_buf *buf; 12674cd96614SDmitry Salychev struct dpaa2_cmd cmd; 1268ba7319e9SDmitry Salychev uint32_t tx_rings_n = 0; 12694cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1270ba7319e9SDmitry Salychev int error; 1271ba7319e9SDmitry Salychev 12724cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 12734cd96614SDmitry Salychev 12744cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 12754cd96614SDmitry Salychev if (error) { 12764cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 12774cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 12784cd96614SDmitry Salychev goto err_exit; 12794cd96614SDmitry Salychev } 12804cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 12814cd96614SDmitry Salychev if (error) { 12824cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 12834cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 12844cd96614SDmitry Salychev goto close_rc; 12854cd96614SDmitry Salychev } 12864cd96614SDmitry Salychev 1287ba7319e9SDmitry Salychev /* Obtain DPCON associated with the FQ's channel. */ 1288ba7319e9SDmitry Salychev con_info = device_get_ivars(fq->chan->con_dev); 1289ba7319e9SDmitry Salychev 129058983e4bSDmitry Salychev KASSERT(sc->attr.num.tx_tcs <= DPAA2_MAX_TCS, 1291ba7319e9SDmitry Salychev ("%s: too many Tx traffic classes: tx_tcs=%d\n", __func__, 1292ba7319e9SDmitry Salychev sc->attr.num.tx_tcs)); 1293ba7319e9SDmitry Salychev KASSERT(DPAA2_NI_BUFS_PER_TX <= DPAA2_NI_MAX_BPTX, 1294ba7319e9SDmitry Salychev ("%s: too many Tx buffers (%d): max=%d\n", __func__, 1295ba7319e9SDmitry Salychev DPAA2_NI_BUFS_PER_TX, DPAA2_NI_MAX_BPTX)); 1296ba7319e9SDmitry Salychev 1297ba7319e9SDmitry Salychev /* Setup Tx rings. */ 1298ba7319e9SDmitry Salychev for (int i = 0; i < sc->attr.num.tx_tcs; i++) { 1299ba7319e9SDmitry Salychev queue_cfg.type = DPAA2_NI_QUEUE_TX; 1300ba7319e9SDmitry Salychev queue_cfg.tc = i; 1301ba7319e9SDmitry Salychev queue_cfg.idx = fq->flowid; 1302ba7319e9SDmitry Salychev queue_cfg.chan_id = fq->chan->id; 1303ba7319e9SDmitry Salychev 13044cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg); 1305ba7319e9SDmitry Salychev if (error) { 1306ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain Tx queue " 1307ba7319e9SDmitry Salychev "configuration: tc=%d, flowid=%d\n", __func__, 1308ba7319e9SDmitry Salychev queue_cfg.tc, queue_cfg.idx); 13094cd96614SDmitry Salychev goto close_ni; 1310ba7319e9SDmitry Salychev } 1311ba7319e9SDmitry Salychev 1312ba7319e9SDmitry Salychev tx = &fq->tx_rings[i]; 1313ba7319e9SDmitry Salychev tx->fq = fq; 1314ba7319e9SDmitry Salychev tx->fqid = queue_cfg.fqid; 1315ba7319e9SDmitry Salychev tx->txid = tx_rings_n; 1316ba7319e9SDmitry Salychev 1317ba7319e9SDmitry Salychev if (bootverbose) { 1318ba7319e9SDmitry Salychev device_printf(dev, "TX queue idx=%d, tc=%d, chan=%d, " 1319ba7319e9SDmitry Salychev "fqid=%d\n", fq->flowid, i, fq->chan->id, 1320ba7319e9SDmitry Salychev queue_cfg.fqid); 1321ba7319e9SDmitry Salychev } 1322ba7319e9SDmitry Salychev 1323ba7319e9SDmitry Salychev mtx_init(&tx->lock, "dpaa2_tx_ring", NULL, MTX_DEF); 1324ba7319e9SDmitry Salychev 1325ba7319e9SDmitry Salychev /* Allocate Tx ring buffer. */ 132658983e4bSDmitry Salychev tx->br = buf_ring_alloc(DPAA2_TX_BUFRING_SZ, M_DEVBUF, M_NOWAIT, 132758983e4bSDmitry Salychev &tx->lock); 132858983e4bSDmitry Salychev if (tx->br == NULL) { 1329ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup Tx ring buffer" 1330ba7319e9SDmitry Salychev " (2) fqid=%d\n", __func__, tx->fqid); 13314cd96614SDmitry Salychev goto close_ni; 1332ba7319e9SDmitry Salychev } 1333ba7319e9SDmitry Salychev 133458983e4bSDmitry Salychev /* Configure Tx buffers */ 1335ba7319e9SDmitry Salychev for (uint64_t j = 0; j < DPAA2_NI_BUFS_PER_TX; j++) { 133658983e4bSDmitry Salychev buf = malloc(sizeof(struct dpaa2_buf), M_DPAA2_TXB, 133758983e4bSDmitry Salychev M_WAITOK); 133858983e4bSDmitry Salychev /* Keep DMA tag and Tx ring linked to the buffer */ 133958983e4bSDmitry Salychev DPAA2_BUF_INIT_TAGOPT(buf, ch->tx_dmat, tx); 1340ba7319e9SDmitry Salychev 134158983e4bSDmitry Salychev buf->sgt = malloc(sizeof(struct dpaa2_buf), M_DPAA2_TXB, 134258983e4bSDmitry Salychev M_WAITOK); 134358983e4bSDmitry Salychev /* Link SGT to DMA tag and back to its Tx buffer */ 134458983e4bSDmitry Salychev DPAA2_BUF_INIT_TAGOPT(buf->sgt, ch->sgt_dmat, buf); 1345ba7319e9SDmitry Salychev 134658983e4bSDmitry Salychev error = dpaa2_buf_seed_txb(dev, buf); 134758983e4bSDmitry Salychev 134858983e4bSDmitry Salychev /* Add Tx buffer to the ring */ 134958983e4bSDmitry Salychev buf_ring_enqueue(tx->br, buf); 1350ba7319e9SDmitry Salychev } 1351ba7319e9SDmitry Salychev 1352ba7319e9SDmitry Salychev tx_rings_n++; 1353ba7319e9SDmitry Salychev } 1354ba7319e9SDmitry Salychev 1355ba7319e9SDmitry Salychev /* All Tx queues which belong to the same flowid have the same qdbin. */ 1356ba7319e9SDmitry Salychev fq->tx_qdbin = queue_cfg.qdbin; 1357ba7319e9SDmitry Salychev 1358ba7319e9SDmitry Salychev queue_cfg.type = DPAA2_NI_QUEUE_TX_CONF; 1359ba7319e9SDmitry Salychev queue_cfg.tc = 0; /* ignored for TxConf queue */ 1360ba7319e9SDmitry Salychev queue_cfg.idx = fq->flowid; 13614cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg); 1362ba7319e9SDmitry Salychev if (error) { 1363ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain TxConf queue " 1364ba7319e9SDmitry Salychev "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc, 1365ba7319e9SDmitry Salychev queue_cfg.idx); 13664cd96614SDmitry Salychev goto close_ni; 1367ba7319e9SDmitry Salychev } 1368ba7319e9SDmitry Salychev 1369ba7319e9SDmitry Salychev fq->fqid = queue_cfg.fqid; 1370ba7319e9SDmitry Salychev 1371ba7319e9SDmitry Salychev queue_cfg.dest_id = con_info->id; 1372ba7319e9SDmitry Salychev queue_cfg.dest_type = DPAA2_NI_DEST_DPCON; 1373ba7319e9SDmitry Salychev queue_cfg.priority = 0; 1374ba7319e9SDmitry Salychev queue_cfg.user_ctx = (uint64_t)(uintmax_t) fq; 1375ba7319e9SDmitry Salychev queue_cfg.options = 1376ba7319e9SDmitry Salychev DPAA2_NI_QUEUE_OPT_USER_CTX | 1377ba7319e9SDmitry Salychev DPAA2_NI_QUEUE_OPT_DEST; 13784cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_QUEUE(dev, child, &cmd, &queue_cfg); 1379ba7319e9SDmitry Salychev if (error) { 1380ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to update TxConf queue " 1381ba7319e9SDmitry Salychev "configuration: tc=%d, flowid=%d\n", __func__, queue_cfg.tc, 1382ba7319e9SDmitry Salychev queue_cfg.idx); 13834cd96614SDmitry Salychev goto close_ni; 13844cd96614SDmitry Salychev } 13854cd96614SDmitry Salychev 13864cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 13874cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 13884cd96614SDmitry Salychev return (0); 13894cd96614SDmitry Salychev 13904cd96614SDmitry Salychev close_ni: 13914cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 13924cd96614SDmitry Salychev close_rc: 13934cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 13944cd96614SDmitry Salychev err_exit: 1395ba7319e9SDmitry Salychev return (error); 1396ba7319e9SDmitry Salychev } 1397ba7319e9SDmitry Salychev 1398ba7319e9SDmitry Salychev static int 13994cd96614SDmitry Salychev dpaa2_ni_setup_rx_err_flow(device_t dev, struct dpaa2_ni_fq *fq) 1400ba7319e9SDmitry Salychev { 14014cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 1402ba7319e9SDmitry Salychev device_t child = dev; 14034cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 14044cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 1405ba7319e9SDmitry Salychev struct dpaa2_devinfo *con_info; 1406ba7319e9SDmitry Salychev struct dpaa2_ni_queue_cfg queue_cfg = {0}; 14074cd96614SDmitry Salychev struct dpaa2_cmd cmd; 14084cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1409ba7319e9SDmitry Salychev int error; 1410ba7319e9SDmitry Salychev 14114cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 14124cd96614SDmitry Salychev 14134cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 14144cd96614SDmitry Salychev if (error) { 14154cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 14164cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 14174cd96614SDmitry Salychev goto err_exit; 14184cd96614SDmitry Salychev } 14194cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 14204cd96614SDmitry Salychev if (error) { 14214cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 14224cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 14234cd96614SDmitry Salychev goto close_rc; 14244cd96614SDmitry Salychev } 14254cd96614SDmitry Salychev 1426ba7319e9SDmitry Salychev /* Obtain DPCON associated with the FQ's channel. */ 1427ba7319e9SDmitry Salychev con_info = device_get_ivars(fq->chan->con_dev); 1428ba7319e9SDmitry Salychev 1429ba7319e9SDmitry Salychev queue_cfg.type = DPAA2_NI_QUEUE_RX_ERR; 1430ba7319e9SDmitry Salychev queue_cfg.tc = fq->tc; /* ignored */ 1431ba7319e9SDmitry Salychev queue_cfg.idx = fq->flowid; /* ignored */ 14324cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_QUEUE(dev, child, &cmd, &queue_cfg); 1433ba7319e9SDmitry Salychev if (error) { 1434ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain RxErr queue " 1435ba7319e9SDmitry Salychev "configuration\n", __func__); 14364cd96614SDmitry Salychev goto close_ni; 1437ba7319e9SDmitry Salychev } 1438ba7319e9SDmitry Salychev 1439ba7319e9SDmitry Salychev fq->fqid = queue_cfg.fqid; 1440ba7319e9SDmitry Salychev 1441ba7319e9SDmitry Salychev queue_cfg.dest_id = con_info->id; 1442ba7319e9SDmitry Salychev queue_cfg.dest_type = DPAA2_NI_DEST_DPCON; 1443ba7319e9SDmitry Salychev queue_cfg.priority = 1; 1444ba7319e9SDmitry Salychev queue_cfg.user_ctx = (uint64_t)(uintmax_t) fq; 1445ba7319e9SDmitry Salychev queue_cfg.options = 1446ba7319e9SDmitry Salychev DPAA2_NI_QUEUE_OPT_USER_CTX | 1447ba7319e9SDmitry Salychev DPAA2_NI_QUEUE_OPT_DEST; 14484cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_QUEUE(dev, child, &cmd, &queue_cfg); 1449ba7319e9SDmitry Salychev if (error) { 1450ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to update RxErr queue " 1451ba7319e9SDmitry Salychev "configuration\n", __func__); 14524cd96614SDmitry Salychev goto close_ni; 1453ba7319e9SDmitry Salychev } 1454ba7319e9SDmitry Salychev 14554cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 14564cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 1457ba7319e9SDmitry Salychev return (0); 14584cd96614SDmitry Salychev 14594cd96614SDmitry Salychev close_ni: 14604cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 14614cd96614SDmitry Salychev close_rc: 14624cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 14634cd96614SDmitry Salychev err_exit: 14644cd96614SDmitry Salychev return (error); 1465ba7319e9SDmitry Salychev } 1466ba7319e9SDmitry Salychev 1467ba7319e9SDmitry Salychev /** 1468ba7319e9SDmitry Salychev * @brief Configure DPNI object to generate interrupts. 1469ba7319e9SDmitry Salychev */ 1470ba7319e9SDmitry Salychev static int 1471ba7319e9SDmitry Salychev dpaa2_ni_setup_irqs(device_t dev) 1472ba7319e9SDmitry Salychev { 14734cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 1474ba7319e9SDmitry Salychev device_t child = dev; 1475ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 14764cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 14774cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 14784cd96614SDmitry Salychev struct dpaa2_cmd cmd; 14794cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1480ba7319e9SDmitry Salychev int error; 1481ba7319e9SDmitry Salychev 14824cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 14834cd96614SDmitry Salychev 14844cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 14854cd96614SDmitry Salychev if (error) { 14864cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 14874cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 14884cd96614SDmitry Salychev goto err_exit; 14894cd96614SDmitry Salychev } 14904cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 14914cd96614SDmitry Salychev if (error) { 14924cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 14934cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 14944cd96614SDmitry Salychev goto close_rc; 14954cd96614SDmitry Salychev } 14964cd96614SDmitry Salychev 1497ba7319e9SDmitry Salychev /* Configure IRQs. */ 1498ba7319e9SDmitry Salychev error = dpaa2_ni_setup_msi(sc); 1499ba7319e9SDmitry Salychev if (error) { 1500ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate MSI\n", __func__); 15014cd96614SDmitry Salychev goto close_ni; 1502ba7319e9SDmitry Salychev } 1503ba7319e9SDmitry Salychev if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1504ba7319e9SDmitry Salychev &sc->irq_rid[0], RF_ACTIVE | RF_SHAREABLE)) == NULL) { 1505ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate IRQ resource\n", 1506ba7319e9SDmitry Salychev __func__); 15074cd96614SDmitry Salychev goto close_ni; 1508ba7319e9SDmitry Salychev } 1509ba7319e9SDmitry Salychev if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, 1510ba7319e9SDmitry Salychev NULL, dpaa2_ni_intr, sc, &sc->intr)) { 1511ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to setup IRQ resource\n", 1512ba7319e9SDmitry Salychev __func__); 15134cd96614SDmitry Salychev goto close_ni; 1514ba7319e9SDmitry Salychev } 1515ba7319e9SDmitry Salychev 15164cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_IRQ_MASK(dev, child, &cmd, DPNI_IRQ_INDEX, 1517ba7319e9SDmitry Salychev DPNI_IRQ_LINK_CHANGED | DPNI_IRQ_EP_CHANGED); 1518ba7319e9SDmitry Salychev if (error) { 1519ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set DPNI IRQ mask\n", 1520ba7319e9SDmitry Salychev __func__); 15214cd96614SDmitry Salychev goto close_ni; 1522ba7319e9SDmitry Salychev } 1523ba7319e9SDmitry Salychev 15244cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_IRQ_ENABLE(dev, child, &cmd, DPNI_IRQ_INDEX, 1525ba7319e9SDmitry Salychev true); 1526ba7319e9SDmitry Salychev if (error) { 1527ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to enable DPNI IRQ\n", __func__); 15284cd96614SDmitry Salychev goto close_ni; 1529ba7319e9SDmitry Salychev } 1530ba7319e9SDmitry Salychev 15314cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 15324cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 1533ba7319e9SDmitry Salychev return (0); 15344cd96614SDmitry Salychev 15354cd96614SDmitry Salychev close_ni: 15364cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 15374cd96614SDmitry Salychev close_rc: 15384cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 15394cd96614SDmitry Salychev err_exit: 15404cd96614SDmitry Salychev return (error); 1541ba7319e9SDmitry Salychev } 1542ba7319e9SDmitry Salychev 1543ba7319e9SDmitry Salychev /** 1544ba7319e9SDmitry Salychev * @brief Allocate MSI interrupts for DPNI. 1545ba7319e9SDmitry Salychev */ 1546ba7319e9SDmitry Salychev static int 1547ba7319e9SDmitry Salychev dpaa2_ni_setup_msi(struct dpaa2_ni_softc *sc) 1548ba7319e9SDmitry Salychev { 1549ba7319e9SDmitry Salychev int val; 1550ba7319e9SDmitry Salychev 1551ba7319e9SDmitry Salychev val = pci_msi_count(sc->dev); 1552ba7319e9SDmitry Salychev if (val < DPAA2_NI_MSI_COUNT) 1553ba7319e9SDmitry Salychev device_printf(sc->dev, "MSI: actual=%d, expected=%d\n", val, 1554ba7319e9SDmitry Salychev DPAA2_IO_MSI_COUNT); 1555ba7319e9SDmitry Salychev val = MIN(val, DPAA2_NI_MSI_COUNT); 1556ba7319e9SDmitry Salychev 1557ba7319e9SDmitry Salychev if (pci_alloc_msi(sc->dev, &val) != 0) 1558ba7319e9SDmitry Salychev return (EINVAL); 1559ba7319e9SDmitry Salychev 1560ba7319e9SDmitry Salychev for (int i = 0; i < val; i++) 1561ba7319e9SDmitry Salychev sc->irq_rid[i] = i + 1; 1562ba7319e9SDmitry Salychev 1563ba7319e9SDmitry Salychev return (0); 1564ba7319e9SDmitry Salychev } 1565ba7319e9SDmitry Salychev 1566ba7319e9SDmitry Salychev /** 1567ba7319e9SDmitry Salychev * @brief Update DPNI according to the updated interface capabilities. 1568ba7319e9SDmitry Salychev */ 1569ba7319e9SDmitry Salychev static int 1570ba7319e9SDmitry Salychev dpaa2_ni_setup_if_caps(struct dpaa2_ni_softc *sc) 1571ba7319e9SDmitry Salychev { 1572d936c29eSJustin Hibbits const bool en_rxcsum = if_getcapenable(sc->ifp) & IFCAP_RXCSUM; 1573d936c29eSJustin Hibbits const bool en_txcsum = if_getcapenable(sc->ifp) & IFCAP_TXCSUM; 15744cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 1575ba7319e9SDmitry Salychev device_t dev = sc->dev; 1576ba7319e9SDmitry Salychev device_t child = dev; 15774cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 15784cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 15794cd96614SDmitry Salychev struct dpaa2_cmd cmd; 15804cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1581ba7319e9SDmitry Salychev int error; 1582ba7319e9SDmitry Salychev 15834cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 15844cd96614SDmitry Salychev 15854cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 15864cd96614SDmitry Salychev if (error) { 15874cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 15884cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 15894cd96614SDmitry Salychev goto err_exit; 15904cd96614SDmitry Salychev } 15914cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 15924cd96614SDmitry Salychev if (error) { 15934cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 15944cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 15954cd96614SDmitry Salychev goto close_rc; 15964cd96614SDmitry Salychev } 15974cd96614SDmitry Salychev 1598ba7319e9SDmitry Salychev /* Setup checksums validation. */ 15994cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd, 16004cd96614SDmitry Salychev DPAA2_NI_OFL_RX_L3_CSUM, en_rxcsum); 1601ba7319e9SDmitry Salychev if (error) { 1602ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to %s L3 checksum validation\n", 1603ba7319e9SDmitry Salychev __func__, en_rxcsum ? "enable" : "disable"); 16044cd96614SDmitry Salychev goto close_ni; 1605ba7319e9SDmitry Salychev } 16064cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd, 1607ba7319e9SDmitry Salychev DPAA2_NI_OFL_RX_L4_CSUM, en_rxcsum); 1608ba7319e9SDmitry Salychev if (error) { 1609ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to %s L4 checksum validation\n", 1610ba7319e9SDmitry Salychev __func__, en_rxcsum ? "enable" : "disable"); 16114cd96614SDmitry Salychev goto close_ni; 1612ba7319e9SDmitry Salychev } 1613ba7319e9SDmitry Salychev 1614ba7319e9SDmitry Salychev /* Setup checksums generation. */ 16154cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd, 1616ba7319e9SDmitry Salychev DPAA2_NI_OFL_TX_L3_CSUM, en_txcsum); 1617ba7319e9SDmitry Salychev if (error) { 1618ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to %s L3 checksum generation\n", 1619ba7319e9SDmitry Salychev __func__, en_txcsum ? "enable" : "disable"); 16204cd96614SDmitry Salychev goto close_ni; 1621ba7319e9SDmitry Salychev } 16224cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_OFFLOAD(dev, child, &cmd, 1623ba7319e9SDmitry Salychev DPAA2_NI_OFL_TX_L4_CSUM, en_txcsum); 1624ba7319e9SDmitry Salychev if (error) { 1625ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to %s L4 checksum generation\n", 1626ba7319e9SDmitry Salychev __func__, en_txcsum ? "enable" : "disable"); 16274cd96614SDmitry Salychev goto close_ni; 1628ba7319e9SDmitry Salychev } 1629ba7319e9SDmitry Salychev 16304cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, &cmd); 16314cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 1632ba7319e9SDmitry Salychev return (0); 16334cd96614SDmitry Salychev 16344cd96614SDmitry Salychev close_ni: 16354cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 16364cd96614SDmitry Salychev close_rc: 16374cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 16384cd96614SDmitry Salychev err_exit: 16394cd96614SDmitry Salychev return (error); 1640ba7319e9SDmitry Salychev } 1641ba7319e9SDmitry Salychev 1642ba7319e9SDmitry Salychev /** 1643ba7319e9SDmitry Salychev * @brief Update DPNI according to the updated interface flags. 1644ba7319e9SDmitry Salychev */ 1645ba7319e9SDmitry Salychev static int 1646ba7319e9SDmitry Salychev dpaa2_ni_setup_if_flags(struct dpaa2_ni_softc *sc) 1647ba7319e9SDmitry Salychev { 1648d936c29eSJustin Hibbits const bool en_promisc = if_getflags(sc->ifp) & IFF_PROMISC; 1649d936c29eSJustin Hibbits const bool en_allmulti = if_getflags(sc->ifp) & IFF_ALLMULTI; 16504cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 1651ba7319e9SDmitry Salychev device_t dev = sc->dev; 1652ba7319e9SDmitry Salychev device_t child = dev; 16534cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 16544cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 16554cd96614SDmitry Salychev struct dpaa2_cmd cmd; 16564cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1657ba7319e9SDmitry Salychev int error; 1658ba7319e9SDmitry Salychev 16594cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 16604cd96614SDmitry Salychev 16614cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 16624cd96614SDmitry Salychev if (error) { 16634cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 16644cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 16654cd96614SDmitry Salychev goto err_exit; 16664cd96614SDmitry Salychev } 16674cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 16684cd96614SDmitry Salychev if (error) { 16694cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 16704cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 16714cd96614SDmitry Salychev goto close_rc; 16724cd96614SDmitry Salychev } 16734cd96614SDmitry Salychev 16744cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_MULTI_PROMISC(dev, child, &cmd, 16754cd96614SDmitry Salychev en_promisc ? true : en_allmulti); 1676ba7319e9SDmitry Salychev if (error) { 1677ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to %s multicast promiscuous " 1678ba7319e9SDmitry Salychev "mode\n", __func__, en_allmulti ? "enable" : "disable"); 16794cd96614SDmitry Salychev goto close_ni; 1680ba7319e9SDmitry Salychev } 1681ba7319e9SDmitry Salychev 16824cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_UNI_PROMISC(dev, child, &cmd, en_promisc); 1683ba7319e9SDmitry Salychev if (error) { 1684ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to %s unicast promiscuous mode\n", 1685ba7319e9SDmitry Salychev __func__, en_promisc ? "enable" : "disable"); 16864cd96614SDmitry Salychev goto close_ni; 1687ba7319e9SDmitry Salychev } 1688ba7319e9SDmitry Salychev 16894cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, &cmd); 16904cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 1691ba7319e9SDmitry Salychev return (0); 16924cd96614SDmitry Salychev 16934cd96614SDmitry Salychev close_ni: 16944cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 16954cd96614SDmitry Salychev close_rc: 16964cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 16974cd96614SDmitry Salychev err_exit: 16984cd96614SDmitry Salychev return (error); 1699ba7319e9SDmitry Salychev } 1700ba7319e9SDmitry Salychev 1701ba7319e9SDmitry Salychev static int 1702ba7319e9SDmitry Salychev dpaa2_ni_setup_sysctls(struct dpaa2_ni_softc *sc) 1703ba7319e9SDmitry Salychev { 1704ba7319e9SDmitry Salychev struct sysctl_ctx_list *ctx; 1705ba7319e9SDmitry Salychev struct sysctl_oid *node, *node2; 1706ba7319e9SDmitry Salychev struct sysctl_oid_list *parent, *parent2; 1707ba7319e9SDmitry Salychev char cbuf[128]; 1708ba7319e9SDmitry Salychev int i; 1709ba7319e9SDmitry Salychev 1710ba7319e9SDmitry Salychev ctx = device_get_sysctl_ctx(sc->dev); 1711ba7319e9SDmitry Salychev parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 1712ba7319e9SDmitry Salychev 1713ba7319e9SDmitry Salychev /* Add DPNI statistics. */ 1714ba7319e9SDmitry Salychev node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats", 1715ba7319e9SDmitry Salychev CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "DPNI Statistics"); 1716ba7319e9SDmitry Salychev parent = SYSCTL_CHILDREN(node); 1717ba7319e9SDmitry Salychev for (i = 0; i < DPAA2_NI_STAT_SYSCTLS; ++i) { 1718ba7319e9SDmitry Salychev SYSCTL_ADD_PROC(ctx, parent, i, dpni_stat_sysctls[i].name, 1719ba7319e9SDmitry Salychev CTLTYPE_U64 | CTLFLAG_RD, sc, 0, dpaa2_ni_collect_stats, 1720ba7319e9SDmitry Salychev "IU", dpni_stat_sysctls[i].desc); 1721ba7319e9SDmitry Salychev } 1722ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_anomaly_frames", 1723ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->rx_anomaly_frames, 1724ba7319e9SDmitry Salychev "Rx frames in the buffers outside of the buffer pools"); 1725ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_single_buf_frames", 1726ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->rx_single_buf_frames, 1727ba7319e9SDmitry Salychev "Rx frames in single buffers"); 1728ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_sg_buf_frames", 1729ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->rx_sg_buf_frames, 1730ba7319e9SDmitry Salychev "Rx frames in scatter/gather list"); 1731ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_enq_rej_frames", 1732ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->rx_enq_rej_frames, 1733ba7319e9SDmitry Salychev "Enqueue rejected by QMan"); 1734ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "rx_ieoi_err_frames", 1735ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->rx_ieoi_err_frames, 1736ba7319e9SDmitry Salychev "QMan IEOI error"); 1737ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "tx_single_buf_frames", 1738ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->tx_single_buf_frames, 1739ba7319e9SDmitry Salychev "Tx single buffer frames"); 1740ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent, OID_AUTO, "tx_sg_frames", 1741ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->tx_sg_frames, 1742ba7319e9SDmitry Salychev "Tx S/G frames"); 1743ba7319e9SDmitry Salychev 1744ba7319e9SDmitry Salychev SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "buf_num", 1745ba7319e9SDmitry Salychev CTLTYPE_U32 | CTLFLAG_RD, sc, 0, dpaa2_ni_collect_buf_num, 1746ba7319e9SDmitry Salychev "IU", "number of Rx buffers in the buffer pool"); 1747ba7319e9SDmitry Salychev SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "buf_free", 1748ba7319e9SDmitry Salychev CTLTYPE_U32 | CTLFLAG_RD, sc, 0, dpaa2_ni_collect_buf_free, 1749ba7319e9SDmitry Salychev "IU", "number of free Rx buffers in the buffer pool"); 1750ba7319e9SDmitry Salychev 1751ba7319e9SDmitry Salychev parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 1752ba7319e9SDmitry Salychev 1753ba7319e9SDmitry Salychev /* Add channels statistics. */ 1754ba7319e9SDmitry Salychev node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "channels", 1755ba7319e9SDmitry Salychev CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "DPNI Channels"); 1756ba7319e9SDmitry Salychev parent = SYSCTL_CHILDREN(node); 1757ba7319e9SDmitry Salychev for (int i = 0; i < sc->chan_n; i++) { 1758ba7319e9SDmitry Salychev snprintf(cbuf, sizeof(cbuf), "%d", i); 1759ba7319e9SDmitry Salychev 1760ba7319e9SDmitry Salychev node2 = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, cbuf, 1761ba7319e9SDmitry Salychev CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "DPNI Channel"); 1762ba7319e9SDmitry Salychev parent2 = SYSCTL_CHILDREN(node2); 1763ba7319e9SDmitry Salychev 1764ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent2, OID_AUTO, "tx_frames", 1765ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->channels[i]->tx_frames, 1766ba7319e9SDmitry Salychev "Tx frames counter"); 1767ba7319e9SDmitry Salychev SYSCTL_ADD_UQUAD(ctx, parent2, OID_AUTO, "tx_dropped", 1768ba7319e9SDmitry Salychev CTLFLAG_RD, &sc->channels[i]->tx_dropped, 1769ba7319e9SDmitry Salychev "Tx dropped counter"); 1770ba7319e9SDmitry Salychev } 1771ba7319e9SDmitry Salychev 1772ba7319e9SDmitry Salychev return (0); 1773ba7319e9SDmitry Salychev } 1774ba7319e9SDmitry Salychev 1775ba7319e9SDmitry Salychev static int 1776ba7319e9SDmitry Salychev dpaa2_ni_setup_dma(struct dpaa2_ni_softc *sc) 1777ba7319e9SDmitry Salychev { 1778ba7319e9SDmitry Salychev device_t dev = sc->dev; 1779ba7319e9SDmitry Salychev int error; 1780ba7319e9SDmitry Salychev 1781ba7319e9SDmitry Salychev KASSERT((sc->buf_align == BUF_ALIGN) || (sc->buf_align == BUF_ALIGN_V1), 1782ba7319e9SDmitry Salychev ("unexpected buffer alignment: %d\n", sc->buf_align)); 1783ba7319e9SDmitry Salychev 1784ba7319e9SDmitry Salychev /* DMA tag for Rx distribution key. */ 1785ba7319e9SDmitry Salychev error = bus_dma_tag_create( 1786ba7319e9SDmitry Salychev bus_get_dma_tag(dev), 1787ba7319e9SDmitry Salychev PAGE_SIZE, 0, /* alignment, boundary */ 1788718bdb6aSDmitry Salychev BUS_SPACE_MAXADDR, /* low restricted addr */ 1789ba7319e9SDmitry Salychev BUS_SPACE_MAXADDR, /* high restricted addr */ 1790ba7319e9SDmitry Salychev NULL, NULL, /* filter, filterarg */ 1791ba7319e9SDmitry Salychev DPAA2_CLASSIFIER_DMA_SIZE, 1, /* maxsize, nsegments */ 1792ba7319e9SDmitry Salychev DPAA2_CLASSIFIER_DMA_SIZE, 0, /* maxsegsize, flags */ 1793ba7319e9SDmitry Salychev NULL, NULL, /* lockfunc, lockarg */ 1794ba7319e9SDmitry Salychev &sc->rxd_dmat); 1795ba7319e9SDmitry Salychev if (error) { 1796ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to create DMA tag for Rx " 1797ba7319e9SDmitry Salychev "distribution key\n", __func__); 1798ba7319e9SDmitry Salychev return (error); 1799ba7319e9SDmitry Salychev } 1800ba7319e9SDmitry Salychev 1801ba7319e9SDmitry Salychev error = bus_dma_tag_create( 1802ba7319e9SDmitry Salychev bus_get_dma_tag(dev), 1803ba7319e9SDmitry Salychev PAGE_SIZE, 0, /* alignment, boundary */ 1804718bdb6aSDmitry Salychev BUS_SPACE_MAXADDR, /* low restricted addr */ 1805ba7319e9SDmitry Salychev BUS_SPACE_MAXADDR, /* high restricted addr */ 1806ba7319e9SDmitry Salychev NULL, NULL, /* filter, filterarg */ 1807ba7319e9SDmitry Salychev ETH_QOS_KCFG_BUF_SIZE, 1, /* maxsize, nsegments */ 1808ba7319e9SDmitry Salychev ETH_QOS_KCFG_BUF_SIZE, 0, /* maxsegsize, flags */ 1809ba7319e9SDmitry Salychev NULL, NULL, /* lockfunc, lockarg */ 1810ba7319e9SDmitry Salychev &sc->qos_dmat); 1811ba7319e9SDmitry Salychev if (error) { 1812ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to create DMA tag for QoS key\n", 1813ba7319e9SDmitry Salychev __func__); 1814ba7319e9SDmitry Salychev return (error); 1815ba7319e9SDmitry Salychev } 1816ba7319e9SDmitry Salychev 1817ba7319e9SDmitry Salychev return (0); 1818ba7319e9SDmitry Salychev } 1819ba7319e9SDmitry Salychev 1820ba7319e9SDmitry Salychev /** 1821ba7319e9SDmitry Salychev * @brief Configure buffer layouts of the different DPNI queues. 1822ba7319e9SDmitry Salychev */ 1823ba7319e9SDmitry Salychev static int 18244cd96614SDmitry Salychev dpaa2_ni_set_buf_layout(device_t dev) 1825ba7319e9SDmitry Salychev { 18264cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 1827ba7319e9SDmitry Salychev device_t child = dev; 18284cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 18294cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 1830ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 1831ba7319e9SDmitry Salychev struct dpaa2_ni_buf_layout buf_layout = {0}; 18324cd96614SDmitry Salychev struct dpaa2_cmd cmd; 18334cd96614SDmitry Salychev uint16_t rc_token, ni_token; 1834ba7319e9SDmitry Salychev int error; 1835ba7319e9SDmitry Salychev 18364cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 18374cd96614SDmitry Salychev 18384cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 18394cd96614SDmitry Salychev if (error) { 18404cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 18414cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 18424cd96614SDmitry Salychev goto err_exit; 18434cd96614SDmitry Salychev } 18444cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 18454cd96614SDmitry Salychev if (error) { 18464cd96614SDmitry Salychev device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, " 18474cd96614SDmitry Salychev "error=%d\n", __func__, dinfo->id, error); 18484cd96614SDmitry Salychev goto close_rc; 18494cd96614SDmitry Salychev } 18504cd96614SDmitry Salychev 1851ba7319e9SDmitry Salychev /* 1852ba7319e9SDmitry Salychev * Select Rx/Tx buffer alignment. It's necessary to ensure that the 1853ba7319e9SDmitry Salychev * buffer size seen by WRIOP is a multiple of 64 or 256 bytes depending 1854ba7319e9SDmitry Salychev * on the WRIOP version. 1855ba7319e9SDmitry Salychev */ 1856ba7319e9SDmitry Salychev sc->buf_align = (sc->attr.wriop_ver == WRIOP_VERSION(0, 0, 0) || 1857ba7319e9SDmitry Salychev sc->attr.wriop_ver == WRIOP_VERSION(1, 0, 0)) 1858ba7319e9SDmitry Salychev ? BUF_ALIGN_V1 : BUF_ALIGN; 1859ba7319e9SDmitry Salychev 1860ba7319e9SDmitry Salychev /* 1861ba7319e9SDmitry Salychev * We need to ensure that the buffer size seen by WRIOP is a multiple 1862ba7319e9SDmitry Salychev * of 64 or 256 bytes depending on the WRIOP version. 1863ba7319e9SDmitry Salychev */ 186458983e4bSDmitry Salychev sc->buf_sz = ALIGN_DOWN(DPAA2_RX_BUF_SIZE, sc->buf_align); 1865ba7319e9SDmitry Salychev 18664cd96614SDmitry Salychev if (bootverbose) { 1867ba7319e9SDmitry Salychev device_printf(dev, "Rx/Tx buffers: size=%d, alignment=%d\n", 1868ba7319e9SDmitry Salychev sc->buf_sz, sc->buf_align); 18694cd96614SDmitry Salychev } 1870ba7319e9SDmitry Salychev 1871ba7319e9SDmitry Salychev /* 1872ba7319e9SDmitry Salychev * Frame Descriptor Tx buffer layout 1873ba7319e9SDmitry Salychev * 1874ba7319e9SDmitry Salychev * ADDR -> |---------------------| 1875ba7319e9SDmitry Salychev * | SW FRAME ANNOTATION | BUF_SWA_SIZE bytes 1876ba7319e9SDmitry Salychev * |---------------------| 1877ba7319e9SDmitry Salychev * | HW FRAME ANNOTATION | BUF_TX_HWA_SIZE bytes 1878ba7319e9SDmitry Salychev * |---------------------| 1879ba7319e9SDmitry Salychev * | DATA HEADROOM | 1880ba7319e9SDmitry Salychev * ADDR + OFFSET -> |---------------------| 1881ba7319e9SDmitry Salychev * | | 1882ba7319e9SDmitry Salychev * | | 1883ba7319e9SDmitry Salychev * | FRAME DATA | 1884ba7319e9SDmitry Salychev * | | 1885ba7319e9SDmitry Salychev * | | 1886ba7319e9SDmitry Salychev * |---------------------| 1887ba7319e9SDmitry Salychev * | DATA TAILROOM | 1888ba7319e9SDmitry Salychev * |---------------------| 1889ba7319e9SDmitry Salychev * 1890ba7319e9SDmitry Salychev * NOTE: It's for a single buffer frame only. 1891ba7319e9SDmitry Salychev */ 1892ba7319e9SDmitry Salychev buf_layout.queue_type = DPAA2_NI_QUEUE_TX; 1893ba7319e9SDmitry Salychev buf_layout.pd_size = BUF_SWA_SIZE; 1894ba7319e9SDmitry Salychev buf_layout.pass_timestamp = true; 1895ba7319e9SDmitry Salychev buf_layout.pass_frame_status = true; 1896ba7319e9SDmitry Salychev buf_layout.options = 1897ba7319e9SDmitry Salychev BUF_LOPT_PRIV_DATA_SZ | 1898ba7319e9SDmitry Salychev BUF_LOPT_TIMESTAMP | /* requires 128 bytes in HWA */ 1899ba7319e9SDmitry Salychev BUF_LOPT_FRAME_STATUS; 19004cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_BUF_LAYOUT(dev, child, &cmd, &buf_layout); 1901ba7319e9SDmitry Salychev if (error) { 1902ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set Tx buffer layout\n", 1903ba7319e9SDmitry Salychev __func__); 19044cd96614SDmitry Salychev goto close_ni; 1905ba7319e9SDmitry Salychev } 1906ba7319e9SDmitry Salychev 1907ba7319e9SDmitry Salychev /* Tx-confirmation buffer layout */ 1908ba7319e9SDmitry Salychev buf_layout.queue_type = DPAA2_NI_QUEUE_TX_CONF; 1909ba7319e9SDmitry Salychev buf_layout.options = 1910ba7319e9SDmitry Salychev BUF_LOPT_TIMESTAMP | 1911ba7319e9SDmitry Salychev BUF_LOPT_FRAME_STATUS; 19124cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_BUF_LAYOUT(dev, child, &cmd, &buf_layout); 1913ba7319e9SDmitry Salychev if (error) { 1914ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set TxConf buffer layout\n", 1915ba7319e9SDmitry Salychev __func__); 19164cd96614SDmitry Salychev goto close_ni; 1917ba7319e9SDmitry Salychev } 1918ba7319e9SDmitry Salychev 1919ba7319e9SDmitry Salychev /* 1920ba7319e9SDmitry Salychev * Driver should reserve the amount of space indicated by this command 1921ba7319e9SDmitry Salychev * as headroom in all Tx frames. 1922ba7319e9SDmitry Salychev */ 19234cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_TX_DATA_OFF(dev, child, &cmd, &sc->tx_data_off); 1924ba7319e9SDmitry Salychev if (error) { 1925ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain Tx data offset\n", 1926ba7319e9SDmitry Salychev __func__); 19274cd96614SDmitry Salychev goto close_ni; 1928ba7319e9SDmitry Salychev } 1929ba7319e9SDmitry Salychev 19304cd96614SDmitry Salychev if (bootverbose) { 1931ba7319e9SDmitry Salychev device_printf(dev, "Tx data offset=%d\n", sc->tx_data_off); 19324cd96614SDmitry Salychev } 19334cd96614SDmitry Salychev if ((sc->tx_data_off % 64) != 0) { 1934ba7319e9SDmitry Salychev device_printf(dev, "Tx data offset (%d) is not a multiplication " 1935ba7319e9SDmitry Salychev "of 64 bytes\n", sc->tx_data_off); 19364cd96614SDmitry Salychev } 1937ba7319e9SDmitry Salychev 1938ba7319e9SDmitry Salychev /* 1939ba7319e9SDmitry Salychev * Frame Descriptor Rx buffer layout 1940ba7319e9SDmitry Salychev * 1941ba7319e9SDmitry Salychev * ADDR -> |---------------------| 1942718bdb6aSDmitry Salychev * | SW FRAME ANNOTATION | BUF_SWA_SIZE bytes 1943ba7319e9SDmitry Salychev * |---------------------| 1944ba7319e9SDmitry Salychev * | HW FRAME ANNOTATION | BUF_RX_HWA_SIZE bytes 1945ba7319e9SDmitry Salychev * |---------------------| 1946ba7319e9SDmitry Salychev * | DATA HEADROOM | OFFSET-BUF_RX_HWA_SIZE 1947ba7319e9SDmitry Salychev * ADDR + OFFSET -> |---------------------| 1948ba7319e9SDmitry Salychev * | | 1949ba7319e9SDmitry Salychev * | | 1950ba7319e9SDmitry Salychev * | FRAME DATA | 1951ba7319e9SDmitry Salychev * | | 1952ba7319e9SDmitry Salychev * | | 1953ba7319e9SDmitry Salychev * |---------------------| 1954ba7319e9SDmitry Salychev * | DATA TAILROOM | 0 bytes 1955ba7319e9SDmitry Salychev * |---------------------| 1956ba7319e9SDmitry Salychev * 1957ba7319e9SDmitry Salychev * NOTE: It's for a single buffer frame only. 1958ba7319e9SDmitry Salychev */ 1959ba7319e9SDmitry Salychev buf_layout.queue_type = DPAA2_NI_QUEUE_RX; 1960718bdb6aSDmitry Salychev buf_layout.pd_size = BUF_SWA_SIZE; 1961ba7319e9SDmitry Salychev buf_layout.fd_align = sc->buf_align; 1962718bdb6aSDmitry Salychev buf_layout.head_size = sc->tx_data_off - BUF_RX_HWA_SIZE - BUF_SWA_SIZE; 1963ba7319e9SDmitry Salychev buf_layout.tail_size = 0; 1964ba7319e9SDmitry Salychev buf_layout.pass_frame_status = true; 1965ba7319e9SDmitry Salychev buf_layout.pass_parser_result = true; 1966ba7319e9SDmitry Salychev buf_layout.pass_timestamp = true; 1967ba7319e9SDmitry Salychev buf_layout.options = 1968ba7319e9SDmitry Salychev BUF_LOPT_PRIV_DATA_SZ | 1969ba7319e9SDmitry Salychev BUF_LOPT_DATA_ALIGN | 1970ba7319e9SDmitry Salychev BUF_LOPT_DATA_HEAD_ROOM | 1971ba7319e9SDmitry Salychev BUF_LOPT_DATA_TAIL_ROOM | 1972ba7319e9SDmitry Salychev BUF_LOPT_FRAME_STATUS | 1973ba7319e9SDmitry Salychev BUF_LOPT_PARSER_RESULT | 1974ba7319e9SDmitry Salychev BUF_LOPT_TIMESTAMP; 19754cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_BUF_LAYOUT(dev, child, &cmd, &buf_layout); 1976ba7319e9SDmitry Salychev if (error) { 1977ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set Rx buffer layout\n", 1978ba7319e9SDmitry Salychev __func__); 19794cd96614SDmitry Salychev goto close_ni; 1980ba7319e9SDmitry Salychev } 1981ba7319e9SDmitry Salychev 19824cd96614SDmitry Salychev error = 0; 19834cd96614SDmitry Salychev close_ni: 19844cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 19854cd96614SDmitry Salychev close_rc: 19864cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 19874cd96614SDmitry Salychev err_exit: 19884cd96614SDmitry Salychev return (error); 1989ba7319e9SDmitry Salychev } 1990ba7319e9SDmitry Salychev 1991ba7319e9SDmitry Salychev /** 1992ba7319e9SDmitry Salychev * @brief Enable Rx/Tx pause frames. 1993ba7319e9SDmitry Salychev * 1994ba7319e9SDmitry Salychev * NOTE: DPNI stops sending when a pause frame is received (Rx frame) or DPNI 1995ba7319e9SDmitry Salychev * itself generates pause frames (Tx frame). 1996ba7319e9SDmitry Salychev */ 1997ba7319e9SDmitry Salychev static int 19984cd96614SDmitry Salychev dpaa2_ni_set_pause_frame(device_t dev) 1999ba7319e9SDmitry Salychev { 20004cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 2001ba7319e9SDmitry Salychev device_t child = dev; 20024cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 20034cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 2004ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 2005ba7319e9SDmitry Salychev struct dpaa2_ni_link_cfg link_cfg = {0}; 20064cd96614SDmitry Salychev struct dpaa2_cmd cmd; 20074cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2008ba7319e9SDmitry Salychev int error; 2009ba7319e9SDmitry Salychev 20104cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 20114cd96614SDmitry Salychev 20124cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 20134cd96614SDmitry Salychev if (error) { 20144cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 20154cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 20164cd96614SDmitry Salychev goto err_exit; 20174cd96614SDmitry Salychev } 20184cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 20194cd96614SDmitry Salychev if (error) { 20204cd96614SDmitry Salychev device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, " 20214cd96614SDmitry Salychev "error=%d\n", __func__, dinfo->id, error); 20224cd96614SDmitry Salychev goto close_rc; 20234cd96614SDmitry Salychev } 20244cd96614SDmitry Salychev 20254cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_LINK_CFG(dev, child, &cmd, &link_cfg); 2026ba7319e9SDmitry Salychev if (error) { 2027ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain link configuration: " 2028ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 20294cd96614SDmitry Salychev goto close_ni; 2030ba7319e9SDmitry Salychev } 2031ba7319e9SDmitry Salychev 2032ba7319e9SDmitry Salychev /* Enable both Rx and Tx pause frames by default. */ 2033ba7319e9SDmitry Salychev link_cfg.options |= DPAA2_NI_LINK_OPT_PAUSE; 2034ba7319e9SDmitry Salychev link_cfg.options &= ~DPAA2_NI_LINK_OPT_ASYM_PAUSE; 2035ba7319e9SDmitry Salychev 20364cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_LINK_CFG(dev, child, &cmd, &link_cfg); 2037ba7319e9SDmitry Salychev if (error) { 2038ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set link configuration: " 2039ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 20404cd96614SDmitry Salychev goto close_ni; 2041ba7319e9SDmitry Salychev } 2042ba7319e9SDmitry Salychev 2043ba7319e9SDmitry Salychev sc->link_options = link_cfg.options; 20444cd96614SDmitry Salychev error = 0; 20454cd96614SDmitry Salychev close_ni: 20464cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 20474cd96614SDmitry Salychev close_rc: 20484cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 20494cd96614SDmitry Salychev err_exit: 20504cd96614SDmitry Salychev return (error); 2051ba7319e9SDmitry Salychev } 2052ba7319e9SDmitry Salychev 2053ba7319e9SDmitry Salychev /** 2054ba7319e9SDmitry Salychev * @brief Configure QoS table to determine the traffic class for the received 2055ba7319e9SDmitry Salychev * frame. 2056ba7319e9SDmitry Salychev */ 2057ba7319e9SDmitry Salychev static int 20584cd96614SDmitry Salychev dpaa2_ni_set_qos_table(device_t dev) 2059ba7319e9SDmitry Salychev { 20604cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 2061ba7319e9SDmitry Salychev device_t child = dev; 20624cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 20634cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 2064ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 2065ba7319e9SDmitry Salychev struct dpaa2_ni_qos_table tbl; 2066ba7319e9SDmitry Salychev struct dpaa2_buf *buf = &sc->qos_kcfg; 20674cd96614SDmitry Salychev struct dpaa2_cmd cmd; 20684cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2069ba7319e9SDmitry Salychev int error; 2070ba7319e9SDmitry Salychev 2071ba7319e9SDmitry Salychev if (sc->attr.num.rx_tcs == 1 || 2072ba7319e9SDmitry Salychev !(sc->attr.options & DPNI_OPT_HAS_KEY_MASKING)) { 20734cd96614SDmitry Salychev if (bootverbose) { 2074ba7319e9SDmitry Salychev device_printf(dev, "Ingress traffic classification is " 2075ba7319e9SDmitry Salychev "not supported\n"); 20764cd96614SDmitry Salychev } 2077ba7319e9SDmitry Salychev return (0); 2078ba7319e9SDmitry Salychev } 2079ba7319e9SDmitry Salychev 2080ba7319e9SDmitry Salychev /* 2081ba7319e9SDmitry Salychev * Allocate a buffer visible to the device to hold the QoS table key 2082ba7319e9SDmitry Salychev * configuration. 2083ba7319e9SDmitry Salychev */ 208458983e4bSDmitry Salychev 208558983e4bSDmitry Salychev if (__predict_true(buf->dmat == NULL)) { 208658983e4bSDmitry Salychev buf->dmat = sc->qos_dmat; 20874cd96614SDmitry Salychev } 2088ba7319e9SDmitry Salychev 208958983e4bSDmitry Salychev error = bus_dmamem_alloc(buf->dmat, (void **)&buf->vaddr, 209058983e4bSDmitry Salychev BUS_DMA_ZERO | BUS_DMA_COHERENT, &buf->dmap); 2091ba7319e9SDmitry Salychev if (error) { 2092ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate a buffer for QoS key " 2093ba7319e9SDmitry Salychev "configuration\n", __func__); 20944cd96614SDmitry Salychev goto err_exit; 2095ba7319e9SDmitry Salychev } 2096ba7319e9SDmitry Salychev 209758983e4bSDmitry Salychev error = bus_dmamap_load(buf->dmat, buf->dmap, buf->vaddr, 209858983e4bSDmitry Salychev ETH_QOS_KCFG_BUF_SIZE, dpaa2_dmamap_oneseg_cb, &buf->paddr, 209958983e4bSDmitry Salychev BUS_DMA_NOWAIT); 2100ba7319e9SDmitry Salychev if (error) { 2101ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to map QoS key configuration " 2102ba7319e9SDmitry Salychev "buffer into bus space\n", __func__); 21034cd96614SDmitry Salychev goto err_exit; 21044cd96614SDmitry Salychev } 21054cd96614SDmitry Salychev 21064cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 21074cd96614SDmitry Salychev 21084cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 21094cd96614SDmitry Salychev if (error) { 21104cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 21114cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 21124cd96614SDmitry Salychev goto err_exit; 21134cd96614SDmitry Salychev } 21144cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 21154cd96614SDmitry Salychev if (error) { 21164cd96614SDmitry Salychev device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, " 21174cd96614SDmitry Salychev "error=%d\n", __func__, dinfo->id, error); 21184cd96614SDmitry Salychev goto close_rc; 2119ba7319e9SDmitry Salychev } 2120ba7319e9SDmitry Salychev 2121ba7319e9SDmitry Salychev tbl.default_tc = 0; 2122ba7319e9SDmitry Salychev tbl.discard_on_miss = false; 2123ba7319e9SDmitry Salychev tbl.keep_entries = false; 212458983e4bSDmitry Salychev tbl.kcfg_busaddr = buf->paddr; 21254cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_QOS_TABLE(dev, child, &cmd, &tbl); 2126ba7319e9SDmitry Salychev if (error) { 2127ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set QoS table\n", __func__); 21284cd96614SDmitry Salychev goto close_ni; 2129ba7319e9SDmitry Salychev } 2130ba7319e9SDmitry Salychev 21314cd96614SDmitry Salychev error = DPAA2_CMD_NI_CLEAR_QOS_TABLE(dev, child, &cmd); 2132ba7319e9SDmitry Salychev if (error) { 2133ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to clear QoS table\n", __func__); 21344cd96614SDmitry Salychev goto close_ni; 2135ba7319e9SDmitry Salychev } 2136ba7319e9SDmitry Salychev 21374cd96614SDmitry Salychev error = 0; 21384cd96614SDmitry Salychev close_ni: 21394cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 21404cd96614SDmitry Salychev close_rc: 21414cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 21424cd96614SDmitry Salychev err_exit: 21434cd96614SDmitry Salychev return (error); 2144ba7319e9SDmitry Salychev } 2145ba7319e9SDmitry Salychev 2146ba7319e9SDmitry Salychev static int 21474cd96614SDmitry Salychev dpaa2_ni_set_mac_addr(device_t dev) 2148ba7319e9SDmitry Salychev { 21494cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 2150ba7319e9SDmitry Salychev device_t child = dev; 2151ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 2152d936c29eSJustin Hibbits if_t ifp = sc->ifp; 21534cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 21544cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 21554cd96614SDmitry Salychev struct dpaa2_cmd cmd; 2156ba7319e9SDmitry Salychev struct ether_addr rnd_mac_addr; 21574cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2158ba7319e9SDmitry Salychev uint8_t mac_addr[ETHER_ADDR_LEN]; 2159ba7319e9SDmitry Salychev uint8_t dpni_mac_addr[ETHER_ADDR_LEN]; 2160ba7319e9SDmitry Salychev int error; 2161ba7319e9SDmitry Salychev 21624cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 21634cd96614SDmitry Salychev 21644cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 21654cd96614SDmitry Salychev if (error) { 21664cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 21674cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 21684cd96614SDmitry Salychev goto err_exit; 21694cd96614SDmitry Salychev } 21704cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 21714cd96614SDmitry Salychev if (error) { 21724cd96614SDmitry Salychev device_printf(sc->dev, "%s: failed to open DPMAC: id=%d, " 21734cd96614SDmitry Salychev "error=%d\n", __func__, dinfo->id, error); 21744cd96614SDmitry Salychev goto close_rc; 21754cd96614SDmitry Salychev } 21764cd96614SDmitry Salychev 2177ba7319e9SDmitry Salychev /* 2178ba7319e9SDmitry Salychev * Get the MAC address associated with the physical port, if the DPNI is 2179ba7319e9SDmitry Salychev * connected to a DPMAC directly associated with one of the physical 2180ba7319e9SDmitry Salychev * ports. 2181ba7319e9SDmitry Salychev */ 21824cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_PORT_MAC_ADDR(dev, child, &cmd, mac_addr); 2183ba7319e9SDmitry Salychev if (error) { 2184ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain the MAC address " 2185ba7319e9SDmitry Salychev "associated with the physical port\n", __func__); 21864cd96614SDmitry Salychev goto close_ni; 2187ba7319e9SDmitry Salychev } 2188ba7319e9SDmitry Salychev 2189ba7319e9SDmitry Salychev /* Get primary MAC address from the DPNI attributes. */ 21904cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_PRIM_MAC_ADDR(dev, child, &cmd, dpni_mac_addr); 2191ba7319e9SDmitry Salychev if (error) { 2192ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to obtain primary MAC address\n", 2193ba7319e9SDmitry Salychev __func__); 21944cd96614SDmitry Salychev goto close_ni; 2195ba7319e9SDmitry Salychev } 2196ba7319e9SDmitry Salychev 2197ba7319e9SDmitry Salychev if (!ETHER_IS_ZERO(mac_addr)) { 2198ba7319e9SDmitry Salychev /* Set MAC address of the physical port as DPNI's primary one. */ 21994cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_PRIM_MAC_ADDR(dev, child, &cmd, 2200ba7319e9SDmitry Salychev mac_addr); 2201ba7319e9SDmitry Salychev if (error) { 2202ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set primary MAC " 2203ba7319e9SDmitry Salychev "address\n", __func__); 22044cd96614SDmitry Salychev goto close_ni; 2205ba7319e9SDmitry Salychev } 22064cd96614SDmitry Salychev for (int i = 0; i < ETHER_ADDR_LEN; i++) { 2207ba7319e9SDmitry Salychev sc->mac.addr[i] = mac_addr[i]; 22084cd96614SDmitry Salychev } 2209ba7319e9SDmitry Salychev } else if (ETHER_IS_ZERO(dpni_mac_addr)) { 2210ba7319e9SDmitry Salychev /* Generate random MAC address as DPNI's primary one. */ 2211ba7319e9SDmitry Salychev ether_gen_addr(ifp, &rnd_mac_addr); 22124cd96614SDmitry Salychev for (int i = 0; i < ETHER_ADDR_LEN; i++) { 2213ba7319e9SDmitry Salychev mac_addr[i] = rnd_mac_addr.octet[i]; 22144cd96614SDmitry Salychev } 2215ba7319e9SDmitry Salychev 22164cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_PRIM_MAC_ADDR(dev, child, &cmd, 2217ba7319e9SDmitry Salychev mac_addr); 2218ba7319e9SDmitry Salychev if (error) { 2219ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set random primary " 2220ba7319e9SDmitry Salychev "MAC address\n", __func__); 22214cd96614SDmitry Salychev goto close_ni; 2222ba7319e9SDmitry Salychev } 22234cd96614SDmitry Salychev for (int i = 0; i < ETHER_ADDR_LEN; i++) { 2224ba7319e9SDmitry Salychev sc->mac.addr[i] = mac_addr[i]; 22254cd96614SDmitry Salychev } 2226ba7319e9SDmitry Salychev } else { 22274cd96614SDmitry Salychev for (int i = 0; i < ETHER_ADDR_LEN; i++) { 2228ba7319e9SDmitry Salychev sc->mac.addr[i] = dpni_mac_addr[i]; 2229ba7319e9SDmitry Salychev } 22304cd96614SDmitry Salychev } 2231ba7319e9SDmitry Salychev 22324cd96614SDmitry Salychev error = 0; 22334cd96614SDmitry Salychev close_ni: 22344cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 22354cd96614SDmitry Salychev close_rc: 22364cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 22374cd96614SDmitry Salychev err_exit: 22384cd96614SDmitry Salychev return (error); 2239ba7319e9SDmitry Salychev } 2240ba7319e9SDmitry Salychev 2241ba7319e9SDmitry Salychev static void 2242ba7319e9SDmitry Salychev dpaa2_ni_miibus_statchg(device_t dev) 2243ba7319e9SDmitry Salychev { 22444cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 22454cd96614SDmitry Salychev device_t child = dev; 22464cd96614SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 2247ba7319e9SDmitry Salychev struct dpaa2_mac_link_state mac_link = { 0 }; 22484cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 22494cd96614SDmitry Salychev struct dpaa2_cmd cmd; 22504cd96614SDmitry Salychev uint16_t rc_token, mac_token; 2251ba7319e9SDmitry Salychev int error, link_state; 2252ba7319e9SDmitry Salychev 22534cd96614SDmitry Salychev if (sc->fixed_link || sc->mii == NULL) { 2254ba7319e9SDmitry Salychev return; 22554cd96614SDmitry Salychev } 2256964b3408SBjoern A. Zeeb if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0) { 2257964b3408SBjoern A. Zeeb /* 2258964b3408SBjoern A. Zeeb * We will receive calls and adjust the changes but 2259964b3408SBjoern A. Zeeb * not have setup everything (called before dpaa2_ni_init() 2260964b3408SBjoern A. Zeeb * really). This will then setup the link and internal 2261964b3408SBjoern A. Zeeb * sc->link_state and not trigger the update once needed, 2262964b3408SBjoern A. Zeeb * so basically dpmac never knows about it. 2263964b3408SBjoern A. Zeeb */ 2264964b3408SBjoern A. Zeeb return; 2265964b3408SBjoern A. Zeeb } 2266ba7319e9SDmitry Salychev 2267ba7319e9SDmitry Salychev /* 2268ba7319e9SDmitry Salychev * Note: ifp link state will only be changed AFTER we are called so we 2269ba7319e9SDmitry Salychev * cannot rely on ifp->if_linkstate here. 2270ba7319e9SDmitry Salychev */ 2271ba7319e9SDmitry Salychev if (sc->mii->mii_media_status & IFM_AVALID) { 22724cd96614SDmitry Salychev if (sc->mii->mii_media_status & IFM_ACTIVE) { 2273ba7319e9SDmitry Salychev link_state = LINK_STATE_UP; 22744cd96614SDmitry Salychev } else { 2275ba7319e9SDmitry Salychev link_state = LINK_STATE_DOWN; 22764cd96614SDmitry Salychev } 22774cd96614SDmitry Salychev } else { 2278ba7319e9SDmitry Salychev link_state = LINK_STATE_UNKNOWN; 22794cd96614SDmitry Salychev } 2280ba7319e9SDmitry Salychev 2281ba7319e9SDmitry Salychev if (link_state != sc->link_state) { 2282ba7319e9SDmitry Salychev sc->link_state = link_state; 2283ba7319e9SDmitry Salychev 22844cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 22854cd96614SDmitry Salychev 22864cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, 22874cd96614SDmitry Salychev &rc_token); 22884cd96614SDmitry Salychev if (error) { 22894cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource " 22904cd96614SDmitry Salychev "container: id=%d, error=%d\n", __func__, rcinfo->id, 22914cd96614SDmitry Salychev error); 22924cd96614SDmitry Salychev goto err_exit; 22934cd96614SDmitry Salychev } 22944cd96614SDmitry Salychev error = DPAA2_CMD_MAC_OPEN(dev, child, &cmd, sc->mac.dpmac_id, 22954cd96614SDmitry Salychev &mac_token); 2296ba7319e9SDmitry Salychev if (error) { 2297ba7319e9SDmitry Salychev device_printf(sc->dev, "%s: failed to open DPMAC: " 2298ba7319e9SDmitry Salychev "id=%d, error=%d\n", __func__, sc->mac.dpmac_id, 2299ba7319e9SDmitry Salychev error); 23004cd96614SDmitry Salychev goto close_rc; 2301ba7319e9SDmitry Salychev } 2302ba7319e9SDmitry Salychev 2303ba7319e9SDmitry Salychev if (link_state == LINK_STATE_UP || 2304ba7319e9SDmitry Salychev link_state == LINK_STATE_DOWN) { 2305ba7319e9SDmitry Salychev /* Update DPMAC link state. */ 2306ba7319e9SDmitry Salychev mac_link.supported = sc->mii->mii_media.ifm_media; 2307ba7319e9SDmitry Salychev mac_link.advert = sc->mii->mii_media.ifm_media; 2308ba7319e9SDmitry Salychev mac_link.rate = 1000; /* TODO: Where to get from? */ /* ifmedia_baudrate? */ 2309ba7319e9SDmitry Salychev mac_link.options = 2310ba7319e9SDmitry Salychev DPAA2_MAC_LINK_OPT_AUTONEG | 2311ba7319e9SDmitry Salychev DPAA2_MAC_LINK_OPT_PAUSE; 2312ba7319e9SDmitry Salychev mac_link.up = (link_state == LINK_STATE_UP) ? true : false; 2313ba7319e9SDmitry Salychev mac_link.state_valid = true; 2314ba7319e9SDmitry Salychev 2315ba7319e9SDmitry Salychev /* Inform DPMAC about link state. */ 23164cd96614SDmitry Salychev error = DPAA2_CMD_MAC_SET_LINK_STATE(dev, child, &cmd, 23174cd96614SDmitry Salychev &mac_link); 23184cd96614SDmitry Salychev if (error) { 2319ba7319e9SDmitry Salychev device_printf(sc->dev, "%s: failed to set DPMAC " 2320ba7319e9SDmitry Salychev "link state: id=%d, error=%d\n", __func__, 2321ba7319e9SDmitry Salychev sc->mac.dpmac_id, error); 2322ba7319e9SDmitry Salychev } 2323ba7319e9SDmitry Salychev } 23244cd96614SDmitry Salychev (void)DPAA2_CMD_MAC_CLOSE(dev, child, &cmd); 23254cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, 23264cd96614SDmitry Salychev rc_token)); 23274cd96614SDmitry Salychev } 23284cd96614SDmitry Salychev 23294cd96614SDmitry Salychev return; 23304cd96614SDmitry Salychev 23314cd96614SDmitry Salychev close_rc: 23324cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 23334cd96614SDmitry Salychev err_exit: 23344cd96614SDmitry Salychev return; 2335ba7319e9SDmitry Salychev } 2336ba7319e9SDmitry Salychev 2337ba7319e9SDmitry Salychev /** 2338ba7319e9SDmitry Salychev * @brief Callback function to process media change request. 2339ba7319e9SDmitry Salychev */ 2340ba7319e9SDmitry Salychev static int 2341964b3408SBjoern A. Zeeb dpaa2_ni_media_change_locked(struct dpaa2_ni_softc *sc) 2342ba7319e9SDmitry Salychev { 2343ba7319e9SDmitry Salychev 2344964b3408SBjoern A. Zeeb DPNI_LOCK_ASSERT(sc); 2345ba7319e9SDmitry Salychev if (sc->mii) { 2346ba7319e9SDmitry Salychev mii_mediachg(sc->mii); 2347ba7319e9SDmitry Salychev sc->media_status = sc->mii->mii_media.ifm_media; 2348ba7319e9SDmitry Salychev } else if (sc->fixed_link) { 2349964b3408SBjoern A. Zeeb if_printf(sc->ifp, "%s: can't change media in fixed mode\n", 2350ba7319e9SDmitry Salychev __func__); 2351ba7319e9SDmitry Salychev } 2352ba7319e9SDmitry Salychev 2353ba7319e9SDmitry Salychev return (0); 2354ba7319e9SDmitry Salychev } 2355ba7319e9SDmitry Salychev 2356964b3408SBjoern A. Zeeb static int 2357964b3408SBjoern A. Zeeb dpaa2_ni_media_change(if_t ifp) 2358964b3408SBjoern A. Zeeb { 2359964b3408SBjoern A. Zeeb struct dpaa2_ni_softc *sc = if_getsoftc(ifp); 2360964b3408SBjoern A. Zeeb int error; 2361964b3408SBjoern A. Zeeb 2362964b3408SBjoern A. Zeeb DPNI_LOCK(sc); 2363964b3408SBjoern A. Zeeb error = dpaa2_ni_media_change_locked(sc); 2364964b3408SBjoern A. Zeeb DPNI_UNLOCK(sc); 2365964b3408SBjoern A. Zeeb return (error); 2366964b3408SBjoern A. Zeeb } 2367964b3408SBjoern A. Zeeb 2368ba7319e9SDmitry Salychev /** 2369ba7319e9SDmitry Salychev * @brief Callback function to process media status request. 2370ba7319e9SDmitry Salychev */ 2371ba7319e9SDmitry Salychev static void 2372d936c29eSJustin Hibbits dpaa2_ni_media_status(if_t ifp, struct ifmediareq *ifmr) 2373ba7319e9SDmitry Salychev { 2374d936c29eSJustin Hibbits struct dpaa2_ni_softc *sc = if_getsoftc(ifp); 2375ba7319e9SDmitry Salychev 2376ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2377ba7319e9SDmitry Salychev if (sc->mii) { 2378ba7319e9SDmitry Salychev mii_pollstat(sc->mii); 2379ba7319e9SDmitry Salychev ifmr->ifm_active = sc->mii->mii_media_active; 2380ba7319e9SDmitry Salychev ifmr->ifm_status = sc->mii->mii_media_status; 2381ba7319e9SDmitry Salychev } 2382ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2383ba7319e9SDmitry Salychev } 2384ba7319e9SDmitry Salychev 2385ba7319e9SDmitry Salychev /** 2386ba7319e9SDmitry Salychev * @brief Callout function to check and update media status. 2387ba7319e9SDmitry Salychev */ 2388ba7319e9SDmitry Salychev static void 2389ba7319e9SDmitry Salychev dpaa2_ni_media_tick(void *arg) 2390ba7319e9SDmitry Salychev { 2391ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg; 2392ba7319e9SDmitry Salychev 2393ba7319e9SDmitry Salychev /* Check for media type change */ 2394ba7319e9SDmitry Salychev if (sc->mii) { 2395ba7319e9SDmitry Salychev mii_tick(sc->mii); 2396ba7319e9SDmitry Salychev if (sc->media_status != sc->mii->mii_media.ifm_media) { 2397ba7319e9SDmitry Salychev printf("%s: media type changed (ifm_media=%x)\n", 2398ba7319e9SDmitry Salychev __func__, sc->mii->mii_media.ifm_media); 2399ba7319e9SDmitry Salychev dpaa2_ni_media_change(sc->ifp); 2400ba7319e9SDmitry Salychev } 2401ba7319e9SDmitry Salychev } 2402ba7319e9SDmitry Salychev 2403ba7319e9SDmitry Salychev /* Schedule another timeout one second from now */ 2404ba7319e9SDmitry Salychev callout_reset(&sc->mii_callout, hz, dpaa2_ni_media_tick, sc); 2405ba7319e9SDmitry Salychev } 2406ba7319e9SDmitry Salychev 2407ba7319e9SDmitry Salychev static void 2408ba7319e9SDmitry Salychev dpaa2_ni_init(void *arg) 2409ba7319e9SDmitry Salychev { 2410ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg; 2411d936c29eSJustin Hibbits if_t ifp = sc->ifp; 24124cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 2413ba7319e9SDmitry Salychev device_t dev = sc->dev; 2414ba7319e9SDmitry Salychev device_t child = dev; 24154cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 24164cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 24174cd96614SDmitry Salychev struct dpaa2_cmd cmd; 24184cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2419ba7319e9SDmitry Salychev int error; 2420ba7319e9SDmitry Salychev 2421ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2422d936c29eSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 2423ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2424ba7319e9SDmitry Salychev return; 2425ba7319e9SDmitry Salychev } 2426ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2427ba7319e9SDmitry Salychev 24284cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 24294cd96614SDmitry Salychev 24304cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 24314cd96614SDmitry Salychev if (error) { 24324cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 24334cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 24344cd96614SDmitry Salychev goto err_exit; 24354cd96614SDmitry Salychev } 24364cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 24374cd96614SDmitry Salychev if (error) { 24384cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 24394cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 24404cd96614SDmitry Salychev goto close_rc; 24414cd96614SDmitry Salychev } 24424cd96614SDmitry Salychev 24434cd96614SDmitry Salychev error = DPAA2_CMD_NI_ENABLE(dev, child, &cmd); 24444cd96614SDmitry Salychev if (error) { 2445ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to enable DPNI: error=%d\n", 2446ba7319e9SDmitry Salychev __func__, error); 24474cd96614SDmitry Salychev } 2448ba7319e9SDmitry Salychev 2449ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2450964b3408SBjoern A. Zeeb /* Announce we are up and running and can queue packets. */ 2451964b3408SBjoern A. Zeeb if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 2452964b3408SBjoern A. Zeeb 24534cd96614SDmitry Salychev if (sc->mii) { 2454964b3408SBjoern A. Zeeb /* 2455964b3408SBjoern A. Zeeb * mii_mediachg() will trigger a call into 2456964b3408SBjoern A. Zeeb * dpaa2_ni_miibus_statchg() to setup link state. 2457964b3408SBjoern A. Zeeb */ 2458964b3408SBjoern A. Zeeb dpaa2_ni_media_change_locked(sc); 24594cd96614SDmitry Salychev } 2460ba7319e9SDmitry Salychev callout_reset(&sc->mii_callout, hz, dpaa2_ni_media_tick, sc); 2461ba7319e9SDmitry Salychev 2462ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2463ba7319e9SDmitry Salychev 24644cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 24654cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 24664cd96614SDmitry Salychev return; 24674cd96614SDmitry Salychev 24684cd96614SDmitry Salychev close_rc: 24694cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 24704cd96614SDmitry Salychev err_exit: 2471ba7319e9SDmitry Salychev return; 2472ba7319e9SDmitry Salychev } 2473ba7319e9SDmitry Salychev 2474ba7319e9SDmitry Salychev static int 2475d936c29eSJustin Hibbits dpaa2_ni_transmit(if_t ifp, struct mbuf *m) 2476ba7319e9SDmitry Salychev { 2477d936c29eSJustin Hibbits struct dpaa2_ni_softc *sc = if_getsoftc(ifp); 247858983e4bSDmitry Salychev struct dpaa2_channel *ch; 2479ba7319e9SDmitry Salychev uint32_t fqid; 24801efae8a2SJohn Baldwin bool found = false; 248158983e4bSDmitry Salychev int chidx = 0, error; 2482ba7319e9SDmitry Salychev 248358983e4bSDmitry Salychev if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) { 2484ba7319e9SDmitry Salychev return (0); 248558983e4bSDmitry Salychev } 2486ba7319e9SDmitry Salychev 2487ba7319e9SDmitry Salychev if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 2488ba7319e9SDmitry Salychev fqid = m->m_pkthdr.flowid; 2489ba7319e9SDmitry Salychev for (int i = 0; i < sc->chan_n; i++) { 249058983e4bSDmitry Salychev ch = sc->channels[i]; 249158983e4bSDmitry Salychev for (int j = 0; j < ch->rxq_n; j++) { 249258983e4bSDmitry Salychev if (fqid == ch->rx_queues[j].fqid) { 249358983e4bSDmitry Salychev chidx = ch->flowid; 2494ba7319e9SDmitry Salychev found = true; 2495ba7319e9SDmitry Salychev break; 2496ba7319e9SDmitry Salychev } 2497ba7319e9SDmitry Salychev } 2498ba7319e9SDmitry Salychev if (found) { 2499ba7319e9SDmitry Salychev break; 2500ba7319e9SDmitry Salychev } 2501ba7319e9SDmitry Salychev } 2502ba7319e9SDmitry Salychev } 2503ba7319e9SDmitry Salychev 250458983e4bSDmitry Salychev ch = sc->channels[chidx]; 250558983e4bSDmitry Salychev error = buf_ring_enqueue(ch->xmit_br, m); 250658983e4bSDmitry Salychev if (__predict_false(error != 0)) { 250758983e4bSDmitry Salychev m_freem(m); 250858983e4bSDmitry Salychev } else { 250958983e4bSDmitry Salychev taskqueue_enqueue(ch->cleanup_tq, &ch->cleanup_task); 251058983e4bSDmitry Salychev } 2511ba7319e9SDmitry Salychev 251258983e4bSDmitry Salychev return (error); 2513ba7319e9SDmitry Salychev } 2514ba7319e9SDmitry Salychev 2515ba7319e9SDmitry Salychev static void 2516d936c29eSJustin Hibbits dpaa2_ni_qflush(if_t ifp) 2517ba7319e9SDmitry Salychev { 2518ba7319e9SDmitry Salychev /* TODO: Find a way to drain Tx queues in QBMan. */ 2519ba7319e9SDmitry Salychev if_qflush(ifp); 2520ba7319e9SDmitry Salychev } 2521ba7319e9SDmitry Salychev 2522ba7319e9SDmitry Salychev static int 25234cd96614SDmitry Salychev dpaa2_ni_ioctl(if_t ifp, u_long c, caddr_t data) 2524ba7319e9SDmitry Salychev { 2525d936c29eSJustin Hibbits struct dpaa2_ni_softc *sc = if_getsoftc(ifp); 2526ba7319e9SDmitry Salychev struct ifreq *ifr = (struct ifreq *) data; 25274cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 25284cd96614SDmitry Salychev device_t dev = sc->dev; 25294cd96614SDmitry Salychev device_t child = dev; 25304cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 25314cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 25324cd96614SDmitry Salychev struct dpaa2_cmd cmd; 2533ba7319e9SDmitry Salychev uint32_t changed = 0; 25344cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2535ba7319e9SDmitry Salychev int mtu, error, rc = 0; 2536ba7319e9SDmitry Salychev 25374cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 2538ba7319e9SDmitry Salychev 25394cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 25404cd96614SDmitry Salychev if (error) { 25414cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 25424cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 25434cd96614SDmitry Salychev goto err_exit; 25444cd96614SDmitry Salychev } 25454cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 25464cd96614SDmitry Salychev if (error) { 25474cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 25484cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 25494cd96614SDmitry Salychev goto close_rc; 25504cd96614SDmitry Salychev } 25514cd96614SDmitry Salychev 25524cd96614SDmitry Salychev switch (c) { 2553ba7319e9SDmitry Salychev case SIOCSIFMTU: 2554ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2555ba7319e9SDmitry Salychev mtu = ifr->ifr_mtu; 2556ba7319e9SDmitry Salychev if (mtu < ETHERMIN || mtu > ETHERMTU_JUMBO) { 2557ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 25584cd96614SDmitry Salychev error = EINVAL; 25594cd96614SDmitry Salychev goto close_ni; 2560ba7319e9SDmitry Salychev } 2561d936c29eSJustin Hibbits if_setmtu(ifp, mtu); 2562ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2563ba7319e9SDmitry Salychev 2564ba7319e9SDmitry Salychev /* Update maximum frame length. */ 2565fa3dfeffSBjoern A. Zeeb mtu += ETHER_HDR_LEN; 2566fa3dfeffSBjoern A. Zeeb if (if_getcapenable(ifp) & IFCAP_VLAN_MTU) 2567fa3dfeffSBjoern A. Zeeb mtu += ETHER_VLAN_ENCAP_LEN; 2568fa3dfeffSBjoern A. Zeeb error = DPAA2_CMD_NI_SET_MFL(dev, child, &cmd, mtu); 2569ba7319e9SDmitry Salychev if (error) { 2570ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to update maximum frame " 2571ba7319e9SDmitry Salychev "length: error=%d\n", __func__, error); 25724cd96614SDmitry Salychev goto close_ni; 2573ba7319e9SDmitry Salychev } 2574ba7319e9SDmitry Salychev break; 2575ba7319e9SDmitry Salychev case SIOCSIFCAP: 2576d936c29eSJustin Hibbits changed = if_getcapenable(ifp) ^ ifr->ifr_reqcap; 2577ba7319e9SDmitry Salychev if (changed & IFCAP_HWCSUM) { 25784cd96614SDmitry Salychev if ((ifr->ifr_reqcap & changed) & IFCAP_HWCSUM) { 2579d936c29eSJustin Hibbits if_setcapenablebit(ifp, IFCAP_HWCSUM, 0); 25804cd96614SDmitry Salychev } else { 2581d936c29eSJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_HWCSUM); 2582ba7319e9SDmitry Salychev } 25834cd96614SDmitry Salychev } 2584ba7319e9SDmitry Salychev rc = dpaa2_ni_setup_if_caps(sc); 2585ba7319e9SDmitry Salychev if (rc) { 2586ba7319e9SDmitry Salychev printf("%s: failed to update iface capabilities: " 2587ba7319e9SDmitry Salychev "error=%d\n", __func__, rc); 2588ba7319e9SDmitry Salychev rc = ENXIO; 2589ba7319e9SDmitry Salychev } 2590ba7319e9SDmitry Salychev break; 2591ba7319e9SDmitry Salychev case SIOCSIFFLAGS: 2592ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2593d936c29eSJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 2594d936c29eSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 2595d936c29eSJustin Hibbits changed = if_getflags(ifp) ^ sc->if_flags; 2596ba7319e9SDmitry Salychev if (changed & IFF_PROMISC || 2597ba7319e9SDmitry Salychev changed & IFF_ALLMULTI) { 2598ba7319e9SDmitry Salychev rc = dpaa2_ni_setup_if_flags(sc); 2599ba7319e9SDmitry Salychev } 2600ba7319e9SDmitry Salychev } else { 2601ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2602ba7319e9SDmitry Salychev dpaa2_ni_init(sc); 2603ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2604ba7319e9SDmitry Salychev } 2605d936c29eSJustin Hibbits } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 26064cd96614SDmitry Salychev /* FIXME: Disable DPNI. See dpaa2_ni_init(). */ 2607ba7319e9SDmitry Salychev } 2608ba7319e9SDmitry Salychev 2609d936c29eSJustin Hibbits sc->if_flags = if_getflags(ifp); 2610ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2611ba7319e9SDmitry Salychev break; 2612ba7319e9SDmitry Salychev case SIOCADDMULTI: 2613ba7319e9SDmitry Salychev case SIOCDELMULTI: 2614ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2615d936c29eSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 2616ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2617ba7319e9SDmitry Salychev rc = dpaa2_ni_update_mac_filters(ifp); 26184cd96614SDmitry Salychev if (rc) { 2619ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to update MAC " 2620ba7319e9SDmitry Salychev "filters: error=%d\n", __func__, rc); 26214cd96614SDmitry Salychev } 2622ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2623ba7319e9SDmitry Salychev } 2624ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2625ba7319e9SDmitry Salychev break; 2626ba7319e9SDmitry Salychev case SIOCGIFMEDIA: 2627ba7319e9SDmitry Salychev case SIOCSIFMEDIA: 2628ba7319e9SDmitry Salychev if (sc->mii) 26294cd96614SDmitry Salychev rc = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, c); 2630ba7319e9SDmitry Salychev else if(sc->fixed_link) { 26314cd96614SDmitry Salychev rc = ifmedia_ioctl(ifp, ifr, &sc->fixed_ifmedia, c); 2632ba7319e9SDmitry Salychev } 2633ba7319e9SDmitry Salychev break; 2634ba7319e9SDmitry Salychev default: 26354cd96614SDmitry Salychev rc = ether_ioctl(ifp, c, data); 26364cd96614SDmitry Salychev break; 2637ba7319e9SDmitry Salychev } 2638ba7319e9SDmitry Salychev 26394cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 26404cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 2641ba7319e9SDmitry Salychev return (rc); 26424cd96614SDmitry Salychev 26434cd96614SDmitry Salychev close_ni: 26444cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 26454cd96614SDmitry Salychev close_rc: 26464cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 26474cd96614SDmitry Salychev err_exit: 26484cd96614SDmitry Salychev return (error); 2649ba7319e9SDmitry Salychev } 2650ba7319e9SDmitry Salychev 2651ba7319e9SDmitry Salychev static int 2652d936c29eSJustin Hibbits dpaa2_ni_update_mac_filters(if_t ifp) 2653ba7319e9SDmitry Salychev { 2654d936c29eSJustin Hibbits struct dpaa2_ni_softc *sc = if_getsoftc(ifp); 2655ba7319e9SDmitry Salychev struct dpaa2_ni_mcaddr_ctx ctx; 26564cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 26574cd96614SDmitry Salychev device_t dev = sc->dev; 26584cd96614SDmitry Salychev device_t child = dev; 26594cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 26604cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 26614cd96614SDmitry Salychev struct dpaa2_cmd cmd; 26624cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2663ba7319e9SDmitry Salychev int error; 2664ba7319e9SDmitry Salychev 26654cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 26664cd96614SDmitry Salychev 26674cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 26684cd96614SDmitry Salychev if (error) { 26694cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 26704cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 26714cd96614SDmitry Salychev goto err_exit; 26724cd96614SDmitry Salychev } 26734cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 26744cd96614SDmitry Salychev if (error) { 26754cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 26764cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 26774cd96614SDmitry Salychev goto close_rc; 26784cd96614SDmitry Salychev } 2679ba7319e9SDmitry Salychev 2680ba7319e9SDmitry Salychev /* Remove all multicast MAC filters. */ 26814cd96614SDmitry Salychev error = DPAA2_CMD_NI_CLEAR_MAC_FILTERS(dev, child, &cmd, false, true); 2682ba7319e9SDmitry Salychev if (error) { 2683ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to clear multicast MAC filters: " 2684ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 26854cd96614SDmitry Salychev goto close_ni; 2686ba7319e9SDmitry Salychev } 2687ba7319e9SDmitry Salychev 2688ba7319e9SDmitry Salychev ctx.ifp = ifp; 2689ba7319e9SDmitry Salychev ctx.error = 0; 2690ba7319e9SDmitry Salychev ctx.nent = 0; 2691ba7319e9SDmitry Salychev 2692ba7319e9SDmitry Salychev if_foreach_llmaddr(ifp, dpaa2_ni_add_maddr, &ctx); 2693ba7319e9SDmitry Salychev 26944cd96614SDmitry Salychev error = ctx.error; 26954cd96614SDmitry Salychev close_ni: 26964cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 26974cd96614SDmitry Salychev close_rc: 26984cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 26994cd96614SDmitry Salychev err_exit: 27004cd96614SDmitry Salychev return (error); 2701ba7319e9SDmitry Salychev } 2702ba7319e9SDmitry Salychev 2703ba7319e9SDmitry Salychev static u_int 2704ba7319e9SDmitry Salychev dpaa2_ni_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 2705ba7319e9SDmitry Salychev { 2706ba7319e9SDmitry Salychev struct dpaa2_ni_mcaddr_ctx *ctx = arg; 2707d936c29eSJustin Hibbits struct dpaa2_ni_softc *sc = if_getsoftc(ctx->ifp); 27084cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 27094cd96614SDmitry Salychev device_t dev = sc->dev; 27104cd96614SDmitry Salychev device_t child = dev; 27114cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 27124cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 27134cd96614SDmitry Salychev struct dpaa2_cmd cmd; 27144cd96614SDmitry Salychev uint16_t rc_token, ni_token; 27154cd96614SDmitry Salychev int error; 2716ba7319e9SDmitry Salychev 27174cd96614SDmitry Salychev if (ctx->error != 0) { 2718ba7319e9SDmitry Salychev return (0); 27194cd96614SDmitry Salychev } 2720ba7319e9SDmitry Salychev 2721ba7319e9SDmitry Salychev if (ETHER_IS_MULTICAST(LLADDR(sdl))) { 27224cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 27234cd96614SDmitry Salychev 27244cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, 27254cd96614SDmitry Salychev &rc_token); 27264cd96614SDmitry Salychev if (error) { 27274cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource " 27284cd96614SDmitry Salychev "container: id=%d, error=%d\n", __func__, rcinfo->id, 27294cd96614SDmitry Salychev error); 27304cd96614SDmitry Salychev return (0); 27314cd96614SDmitry Salychev } 27324cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, 27334cd96614SDmitry Salychev &ni_token); 27344cd96614SDmitry Salychev if (error) { 27354cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 27364cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 27374cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, 27384cd96614SDmitry Salychev rc_token)); 27394cd96614SDmitry Salychev return (0); 27404cd96614SDmitry Salychev } 27414cd96614SDmitry Salychev 27424cd96614SDmitry Salychev ctx->error = DPAA2_CMD_NI_ADD_MAC_ADDR(dev, child, &cmd, 27434cd96614SDmitry Salychev LLADDR(sdl)); 27444cd96614SDmitry Salychev 27454cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, 27464cd96614SDmitry Salychev ni_token)); 27474cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, 27484cd96614SDmitry Salychev rc_token)); 27494cd96614SDmitry Salychev 2750ba7319e9SDmitry Salychev if (ctx->error != 0) { 2751ba7319e9SDmitry Salychev device_printf(dev, "%s: can't add more then %d MAC " 2752ba7319e9SDmitry Salychev "addresses, switching to the multicast promiscuous " 2753ba7319e9SDmitry Salychev "mode\n", __func__, ctx->nent); 2754ba7319e9SDmitry Salychev 2755ba7319e9SDmitry Salychev /* Enable multicast promiscuous mode. */ 2756ba7319e9SDmitry Salychev DPNI_LOCK(sc); 2757d936c29eSJustin Hibbits if_setflagbits(ctx->ifp, IFF_ALLMULTI, 0); 2758ba7319e9SDmitry Salychev sc->if_flags |= IFF_ALLMULTI; 2759ba7319e9SDmitry Salychev ctx->error = dpaa2_ni_setup_if_flags(sc); 2760ba7319e9SDmitry Salychev DPNI_UNLOCK(sc); 2761ba7319e9SDmitry Salychev 2762ba7319e9SDmitry Salychev return (0); 2763ba7319e9SDmitry Salychev } 2764ba7319e9SDmitry Salychev ctx->nent++; 2765ba7319e9SDmitry Salychev } 2766ba7319e9SDmitry Salychev 2767ba7319e9SDmitry Salychev return (1); 2768ba7319e9SDmitry Salychev } 2769ba7319e9SDmitry Salychev 2770ba7319e9SDmitry Salychev static void 2771ba7319e9SDmitry Salychev dpaa2_ni_intr(void *arg) 2772ba7319e9SDmitry Salychev { 2773ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg; 27744cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 27754cd96614SDmitry Salychev device_t dev = sc->dev; 27764cd96614SDmitry Salychev device_t child = dev; 27774cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 27784cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 27794cd96614SDmitry Salychev struct dpaa2_cmd cmd; 2780ba7319e9SDmitry Salychev uint32_t status = ~0u; /* clear all IRQ status bits */ 27814cd96614SDmitry Salychev uint16_t rc_token, ni_token; 2782ba7319e9SDmitry Salychev int error; 2783ba7319e9SDmitry Salychev 27844cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 27854cd96614SDmitry Salychev 27864cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 27874cd96614SDmitry Salychev if (error) { 27884cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 27894cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 27904cd96614SDmitry Salychev goto err_exit; 27914cd96614SDmitry Salychev } 27924cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 27934cd96614SDmitry Salychev if (error) { 27944cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 27954cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 27964cd96614SDmitry Salychev goto close_rc; 27974cd96614SDmitry Salychev } 27984cd96614SDmitry Salychev 27994cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_IRQ_STATUS(dev, child, &cmd, DPNI_IRQ_INDEX, 28004cd96614SDmitry Salychev &status); 28014cd96614SDmitry Salychev if (error) { 2802ba7319e9SDmitry Salychev device_printf(sc->dev, "%s: failed to obtain IRQ status: " 2803ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 2804ba7319e9SDmitry Salychev } 2805ba7319e9SDmitry Salychev 28064cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 28074cd96614SDmitry Salychev close_rc: 28084cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 28094cd96614SDmitry Salychev err_exit: 28104cd96614SDmitry Salychev return; 28114cd96614SDmitry Salychev } 28124cd96614SDmitry Salychev 2813ba7319e9SDmitry Salychev /** 281458983e4bSDmitry Salychev * @brief Execute channel's Rx/Tx routines. 281558983e4bSDmitry Salychev * 281658983e4bSDmitry Salychev * NOTE: Should not be re-entrant for the same channel. It is achieved by 281758983e4bSDmitry Salychev * enqueuing the cleanup routine on a single-threaded taskqueue. 2818ba7319e9SDmitry Salychev */ 2819ba7319e9SDmitry Salychev static void 282058983e4bSDmitry Salychev dpaa2_ni_cleanup_task(void *arg, int count) 2821ba7319e9SDmitry Salychev { 282258983e4bSDmitry Salychev struct dpaa2_channel *ch = (struct dpaa2_channel *)arg; 282358983e4bSDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(ch->ni_dev); 282458983e4bSDmitry Salychev int error, rxc, txc; 2825ba7319e9SDmitry Salychev 282658983e4bSDmitry Salychev for (int i = 0; i < DPAA2_CLEAN_BUDGET; i++) { 282758983e4bSDmitry Salychev rxc = dpaa2_ni_rx_cleanup(ch); 282858983e4bSDmitry Salychev txc = dpaa2_ni_tx_cleanup(ch); 2829ba7319e9SDmitry Salychev 283058983e4bSDmitry Salychev if (__predict_false((if_getdrvflags(sc->ifp) & 283158983e4bSDmitry Salychev IFF_DRV_RUNNING) == 0)) { 2832ba7319e9SDmitry Salychev return; 2833ba7319e9SDmitry Salychev } 2834ba7319e9SDmitry Salychev 283558983e4bSDmitry Salychev if ((txc != DPAA2_TX_BUDGET) && (rxc != DPAA2_RX_BUDGET)) { 283658983e4bSDmitry Salychev break; 283758983e4bSDmitry Salychev } 283858983e4bSDmitry Salychev } 283958983e4bSDmitry Salychev 284058983e4bSDmitry Salychev /* Re-arm channel to generate CDAN */ 284158983e4bSDmitry Salychev error = DPAA2_SWP_CONF_WQ_CHANNEL(ch->io_dev, &ch->ctx); 284258983e4bSDmitry Salychev if (error != 0) { 284358983e4bSDmitry Salychev panic("%s: failed to rearm channel: chan_id=%d, error=%d\n", 284458983e4bSDmitry Salychev __func__, ch->id, error); 2845ba7319e9SDmitry Salychev } 2846ba7319e9SDmitry Salychev } 2847ba7319e9SDmitry Salychev 2848ba7319e9SDmitry Salychev /** 2849ba7319e9SDmitry Salychev * @brief Poll frames from a specific channel when CDAN is received. 2850ba7319e9SDmitry Salychev */ 285158983e4bSDmitry Salychev static int 285258983e4bSDmitry Salychev dpaa2_ni_rx_cleanup(struct dpaa2_channel *ch) 2853ba7319e9SDmitry Salychev { 285458983e4bSDmitry Salychev struct dpaa2_io_softc *iosc = device_get_softc(ch->io_dev); 285558983e4bSDmitry Salychev struct dpaa2_swp *swp = iosc->swp; 2856ba7319e9SDmitry Salychev struct dpaa2_ni_fq *fq; 285758983e4bSDmitry Salychev struct dpaa2_buf *buf = &ch->store; 285858983e4bSDmitry Salychev int budget = DPAA2_RX_BUDGET; 2859ba7319e9SDmitry Salychev int error, consumed = 0; 2860ba7319e9SDmitry Salychev 2861ba7319e9SDmitry Salychev do { 286258983e4bSDmitry Salychev error = dpaa2_swp_pull(swp, ch->id, buf, DPAA2_ETH_STORE_FRAMES); 2863ba7319e9SDmitry Salychev if (error) { 286458983e4bSDmitry Salychev device_printf(ch->ni_dev, "%s: failed to pull frames: " 286558983e4bSDmitry Salychev "chan_id=%d, error=%d\n", __func__, ch->id, error); 2866ba7319e9SDmitry Salychev break; 2867ba7319e9SDmitry Salychev } 286858983e4bSDmitry Salychev error = dpaa2_ni_consume_frames(ch, &fq, &consumed); 286958983e4bSDmitry Salychev if (error == ENOENT || error == EALREADY) { 2870ba7319e9SDmitry Salychev break; 2871ba7319e9SDmitry Salychev } 2872ba7319e9SDmitry Salychev if (error == ETIMEDOUT) { 287358983e4bSDmitry Salychev device_printf(ch->ni_dev, "%s: timeout to consume " 287458983e4bSDmitry Salychev "frames: chan_id=%d\n", __func__, ch->id); 2875ba7319e9SDmitry Salychev } 287658983e4bSDmitry Salychev } while (--budget); 2877ba7319e9SDmitry Salychev 287858983e4bSDmitry Salychev return (DPAA2_RX_BUDGET - budget); 2879ba7319e9SDmitry Salychev } 2880ba7319e9SDmitry Salychev 288158983e4bSDmitry Salychev static int 288258983e4bSDmitry Salychev dpaa2_ni_tx_cleanup(struct dpaa2_channel *ch) 2883ba7319e9SDmitry Salychev { 288458983e4bSDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(ch->ni_dev); 288558983e4bSDmitry Salychev struct dpaa2_ni_tx_ring *tx = &ch->txc_queue.tx_rings[0]; 288658983e4bSDmitry Salychev struct mbuf *m = NULL; 288758983e4bSDmitry Salychev int budget = DPAA2_TX_BUDGET; 2888ba7319e9SDmitry Salychev 288958983e4bSDmitry Salychev do { 289058983e4bSDmitry Salychev mtx_assert(&ch->xmit_mtx, MA_NOTOWNED); 289158983e4bSDmitry Salychev mtx_lock(&ch->xmit_mtx); 289258983e4bSDmitry Salychev m = buf_ring_dequeue_sc(ch->xmit_br); 289358983e4bSDmitry Salychev mtx_unlock(&ch->xmit_mtx); 289458983e4bSDmitry Salychev 289558983e4bSDmitry Salychev if (__predict_false(m == NULL)) { 289658983e4bSDmitry Salychev /* TODO: Do not give up easily */ 289758983e4bSDmitry Salychev break; 289858983e4bSDmitry Salychev } else { 289958983e4bSDmitry Salychev dpaa2_ni_tx(sc, ch, tx, m); 290058983e4bSDmitry Salychev } 290158983e4bSDmitry Salychev } while (--budget); 290258983e4bSDmitry Salychev 290358983e4bSDmitry Salychev return (DPAA2_TX_BUDGET - budget); 290458983e4bSDmitry Salychev } 290558983e4bSDmitry Salychev 290658983e4bSDmitry Salychev static void 290758983e4bSDmitry Salychev dpaa2_ni_tx(struct dpaa2_ni_softc *sc, struct dpaa2_channel *ch, 290858983e4bSDmitry Salychev struct dpaa2_ni_tx_ring *tx, struct mbuf *m) 290958983e4bSDmitry Salychev { 291058983e4bSDmitry Salychev device_t dev = sc->dev; 291158983e4bSDmitry Salychev struct dpaa2_ni_fq *fq = tx->fq; 291258983e4bSDmitry Salychev struct dpaa2_buf *buf, *sgt; 291358983e4bSDmitry Salychev struct dpaa2_fd fd; 291458983e4bSDmitry Salychev struct mbuf *md; 291558983e4bSDmitry Salychev bus_dma_segment_t segs[DPAA2_TX_SEGLIMIT]; 291658983e4bSDmitry Salychev int rc, nsegs; 291758983e4bSDmitry Salychev int error; 291858983e4bSDmitry Salychev 291958983e4bSDmitry Salychev mtx_assert(&tx->lock, MA_NOTOWNED); 292058983e4bSDmitry Salychev mtx_lock(&tx->lock); 292158983e4bSDmitry Salychev buf = buf_ring_dequeue_sc(tx->br); 292258983e4bSDmitry Salychev mtx_unlock(&tx->lock); 292358983e4bSDmitry Salychev if (__predict_false(buf == NULL)) { 292458983e4bSDmitry Salychev /* TODO: Do not give up easily */ 2925ba7319e9SDmitry Salychev m_freem(m); 2926ba7319e9SDmitry Salychev return; 2927ba7319e9SDmitry Salychev } else { 292858983e4bSDmitry Salychev DPAA2_BUF_ASSERT_TXREADY(buf); 292958983e4bSDmitry Salychev buf->m = m; 293058983e4bSDmitry Salychev sgt = buf->sgt; 2931ba7319e9SDmitry Salychev } 2932ba7319e9SDmitry Salychev 293358983e4bSDmitry Salychev #if defined(INVARIANTS) 293458983e4bSDmitry Salychev struct dpaa2_ni_tx_ring *btx = (struct dpaa2_ni_tx_ring *)buf->opt; 293558983e4bSDmitry Salychev KASSERT(buf->opt == tx, ("%s: unexpected Tx ring", __func__)); 293658983e4bSDmitry Salychev KASSERT(btx->fq->chan == ch, ("%s: unexpected channel", __func__)); 293758983e4bSDmitry Salychev #endif /* INVARIANTS */ 293858983e4bSDmitry Salychev 2939*e69e172dSBjoern A. Zeeb BPF_MTAP(sc->ifp, m); 2940*e69e172dSBjoern A. Zeeb 294158983e4bSDmitry Salychev error = bus_dmamap_load_mbuf_sg(buf->dmat, buf->dmap, m, segs, &nsegs, 294258983e4bSDmitry Salychev BUS_DMA_NOWAIT); 2943ba7319e9SDmitry Salychev if (__predict_false(error != 0)) { 2944ba7319e9SDmitry Salychev /* Too many fragments, trying to defragment... */ 294558983e4bSDmitry Salychev md = m_collapse(m, M_NOWAIT, DPAA2_TX_SEGLIMIT); 294658983e4bSDmitry Salychev if (md == NULL) { 294758983e4bSDmitry Salychev device_printf(dev, "%s: m_collapse() failed\n", __func__); 2948ba7319e9SDmitry Salychev fq->chan->tx_dropped++; 2949ba7319e9SDmitry Salychev goto err; 2950ba7319e9SDmitry Salychev } 2951ba7319e9SDmitry Salychev 295258983e4bSDmitry Salychev buf->m = m = md; 295358983e4bSDmitry Salychev error = bus_dmamap_load_mbuf_sg(buf->dmat, buf->dmap, m, segs, 295458983e4bSDmitry Salychev &nsegs, BUS_DMA_NOWAIT); 2955ba7319e9SDmitry Salychev if (__predict_false(error != 0)) { 295658983e4bSDmitry Salychev device_printf(dev, "%s: bus_dmamap_load_mbuf_sg() " 295758983e4bSDmitry Salychev "failed: error=%d\n", __func__, error); 2958ba7319e9SDmitry Salychev fq->chan->tx_dropped++; 2959ba7319e9SDmitry Salychev goto err; 2960ba7319e9SDmitry Salychev } 2961ba7319e9SDmitry Salychev } 2962ba7319e9SDmitry Salychev 296358983e4bSDmitry Salychev error = dpaa2_ni_build_fd(sc, tx, buf, segs, nsegs, &fd); 2964ba7319e9SDmitry Salychev if (__predict_false(error != 0)) { 296558983e4bSDmitry Salychev device_printf(dev, "%s: failed to build frame descriptor: " 296658983e4bSDmitry Salychev "error=%d\n", __func__, error); 2967ba7319e9SDmitry Salychev fq->chan->tx_dropped++; 2968ba7319e9SDmitry Salychev goto err_unload; 2969ba7319e9SDmitry Salychev } 2970ba7319e9SDmitry Salychev 297158983e4bSDmitry Salychev /* TODO: Enqueue several frames in a single command */ 2972ba7319e9SDmitry Salychev for (int i = 0; i < DPAA2_NI_ENQUEUE_RETRIES; i++) { 297358983e4bSDmitry Salychev /* TODO: Return error codes instead of # of frames */ 297458983e4bSDmitry Salychev rc = DPAA2_SWP_ENQ_MULTIPLE_FQ(fq->chan->io_dev, tx->fqid, &fd, 1); 2975ba7319e9SDmitry Salychev if (rc == 1) { 2976ba7319e9SDmitry Salychev break; 2977ba7319e9SDmitry Salychev } 2978ba7319e9SDmitry Salychev } 2979ba7319e9SDmitry Salychev 298058983e4bSDmitry Salychev bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_PREWRITE); 298158983e4bSDmitry Salychev bus_dmamap_sync(sgt->dmat, sgt->dmap, BUS_DMASYNC_PREWRITE); 2982ba7319e9SDmitry Salychev 2983ba7319e9SDmitry Salychev if (rc != 1) { 2984ba7319e9SDmitry Salychev fq->chan->tx_dropped++; 2985ba7319e9SDmitry Salychev goto err_unload; 2986ba7319e9SDmitry Salychev } else { 2987ba7319e9SDmitry Salychev fq->chan->tx_frames++; 2988ba7319e9SDmitry Salychev } 2989ba7319e9SDmitry Salychev return; 2990ba7319e9SDmitry Salychev 2991ba7319e9SDmitry Salychev err_unload: 299258983e4bSDmitry Salychev bus_dmamap_unload(buf->dmat, buf->dmap); 299358983e4bSDmitry Salychev if (sgt->paddr != 0) { 299458983e4bSDmitry Salychev bus_dmamap_unload(sgt->dmat, sgt->dmap); 2995ba7319e9SDmitry Salychev } 2996ba7319e9SDmitry Salychev err: 299758983e4bSDmitry Salychev m_freem(buf->m); 299858983e4bSDmitry Salychev buf_ring_enqueue(tx->br, buf); 2999ba7319e9SDmitry Salychev } 3000ba7319e9SDmitry Salychev 3001ba7319e9SDmitry Salychev static int 300258983e4bSDmitry Salychev dpaa2_ni_consume_frames(struct dpaa2_channel *chan, struct dpaa2_ni_fq **src, 3003ba7319e9SDmitry Salychev uint32_t *consumed) 3004ba7319e9SDmitry Salychev { 3005ba7319e9SDmitry Salychev struct dpaa2_ni_fq *fq = NULL; 3006ba7319e9SDmitry Salychev struct dpaa2_dq *dq; 3007ba7319e9SDmitry Salychev struct dpaa2_fd *fd; 300858983e4bSDmitry Salychev struct dpaa2_ni_rx_ctx ctx = { 300958983e4bSDmitry Salychev .head = NULL, 301058983e4bSDmitry Salychev .tail = NULL, 301158983e4bSDmitry Salychev .cnt = 0, 301258983e4bSDmitry Salychev .last = false 301358983e4bSDmitry Salychev }; 3014ba7319e9SDmitry Salychev int rc, frames = 0; 3015ba7319e9SDmitry Salychev 3016ba7319e9SDmitry Salychev do { 301758983e4bSDmitry Salychev rc = dpaa2_chan_next_frame(chan, &dq); 3018ba7319e9SDmitry Salychev if (rc == EINPROGRESS) { 3019ba7319e9SDmitry Salychev if (dq != NULL && !IS_NULL_RESPONSE(dq->fdr.desc.stat)) { 3020ba7319e9SDmitry Salychev fd = &dq->fdr.fd; 3021ba7319e9SDmitry Salychev fq = (struct dpaa2_ni_fq *) dq->fdr.desc.fqd_ctx; 302258983e4bSDmitry Salychev 302358983e4bSDmitry Salychev switch (fq->type) { 302458983e4bSDmitry Salychev case DPAA2_NI_QUEUE_RX: 302558983e4bSDmitry Salychev (void)dpaa2_ni_rx(chan, fq, fd, &ctx); 302658983e4bSDmitry Salychev break; 302758983e4bSDmitry Salychev case DPAA2_NI_QUEUE_RX_ERR: 302858983e4bSDmitry Salychev (void)dpaa2_ni_rx_err(chan, fq, fd); 302958983e4bSDmitry Salychev break; 303058983e4bSDmitry Salychev case DPAA2_NI_QUEUE_TX_CONF: 303158983e4bSDmitry Salychev (void)dpaa2_ni_tx_conf(chan, fq, fd); 303258983e4bSDmitry Salychev break; 303358983e4bSDmitry Salychev default: 303458983e4bSDmitry Salychev panic("%s: unknown queue type (1)", 303558983e4bSDmitry Salychev __func__); 303658983e4bSDmitry Salychev } 3037ba7319e9SDmitry Salychev frames++; 3038ba7319e9SDmitry Salychev } 3039ba7319e9SDmitry Salychev } else if (rc == EALREADY || rc == ENOENT) { 3040ba7319e9SDmitry Salychev if (dq != NULL && !IS_NULL_RESPONSE(dq->fdr.desc.stat)) { 3041ba7319e9SDmitry Salychev fd = &dq->fdr.fd; 3042ba7319e9SDmitry Salychev fq = (struct dpaa2_ni_fq *) dq->fdr.desc.fqd_ctx; 304358983e4bSDmitry Salychev 304458983e4bSDmitry Salychev switch (fq->type) { 304558983e4bSDmitry Salychev case DPAA2_NI_QUEUE_RX: 304658983e4bSDmitry Salychev /* 304758983e4bSDmitry Salychev * Last VDQ response (mbuf) in a chain 304858983e4bSDmitry Salychev * obtained from the Rx queue. 304958983e4bSDmitry Salychev */ 305058983e4bSDmitry Salychev ctx.last = true; 305158983e4bSDmitry Salychev (void)dpaa2_ni_rx(chan, fq, fd, &ctx); 305258983e4bSDmitry Salychev break; 305358983e4bSDmitry Salychev case DPAA2_NI_QUEUE_RX_ERR: 305458983e4bSDmitry Salychev (void)dpaa2_ni_rx_err(chan, fq, fd); 305558983e4bSDmitry Salychev break; 305658983e4bSDmitry Salychev case DPAA2_NI_QUEUE_TX_CONF: 305758983e4bSDmitry Salychev (void)dpaa2_ni_tx_conf(chan, fq, fd); 305858983e4bSDmitry Salychev break; 305958983e4bSDmitry Salychev default: 306058983e4bSDmitry Salychev panic("%s: unknown queue type (2)", 306158983e4bSDmitry Salychev __func__); 306258983e4bSDmitry Salychev } 3063ba7319e9SDmitry Salychev frames++; 3064ba7319e9SDmitry Salychev } 3065ba7319e9SDmitry Salychev break; 3066ba7319e9SDmitry Salychev } else { 306758983e4bSDmitry Salychev panic("%s: should not reach here: rc=%d", __func__, rc); 3068ba7319e9SDmitry Salychev } 3069ba7319e9SDmitry Salychev } while (true); 3070ba7319e9SDmitry Salychev 307158983e4bSDmitry Salychev KASSERT(chan->store_idx < chan->store_sz, ("%s: store_idx(%d) >= " 307258983e4bSDmitry Salychev "store_sz(%d)", __func__, chan->store_idx, chan->store_sz)); 3073ba7319e9SDmitry Salychev 3074ba7319e9SDmitry Salychev /* 307558983e4bSDmitry Salychev * VDQ operation pulls frames from a single queue into the store. 3076ba7319e9SDmitry Salychev * Return the frame queue and a number of consumed frames as an output. 3077ba7319e9SDmitry Salychev */ 307858983e4bSDmitry Salychev if (src != NULL) { 3079ba7319e9SDmitry Salychev *src = fq; 308058983e4bSDmitry Salychev } 308158983e4bSDmitry Salychev if (consumed != NULL) { 3082ba7319e9SDmitry Salychev *consumed = frames; 308358983e4bSDmitry Salychev } 3084ba7319e9SDmitry Salychev 3085ba7319e9SDmitry Salychev return (rc); 3086ba7319e9SDmitry Salychev } 3087ba7319e9SDmitry Salychev 3088ba7319e9SDmitry Salychev /** 3089ba7319e9SDmitry Salychev * @brief Receive frames. 3090ba7319e9SDmitry Salychev */ 3091ba7319e9SDmitry Salychev static int 309258983e4bSDmitry Salychev dpaa2_ni_rx(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, struct dpaa2_fd *fd, 309358983e4bSDmitry Salychev struct dpaa2_ni_rx_ctx *ctx) 3094ba7319e9SDmitry Salychev { 3095ba7319e9SDmitry Salychev bus_addr_t paddr = (bus_addr_t)fd->addr; 309658983e4bSDmitry Salychev struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr); 309758983e4bSDmitry Salychev struct dpaa2_buf *buf = fa->buf; 309858983e4bSDmitry Salychev struct dpaa2_channel *bch = (struct dpaa2_channel *)buf->opt; 309958983e4bSDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(bch->ni_dev); 310058983e4bSDmitry Salychev struct dpaa2_bp_softc *bpsc; 310158983e4bSDmitry Salychev struct mbuf *m; 310258983e4bSDmitry Salychev device_t bpdev; 3103ba7319e9SDmitry Salychev bus_addr_t released[DPAA2_SWP_BUFS_PER_CMD]; 3104ba7319e9SDmitry Salychev void *buf_data; 3105718bdb6aSDmitry Salychev int buf_len, error, released_n = 0; 3106ba7319e9SDmitry Salychev 3107718bdb6aSDmitry Salychev KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__)); 310858983e4bSDmitry Salychev /* 310958983e4bSDmitry Salychev * NOTE: Current channel might not be the same as the "buffer" channel 311058983e4bSDmitry Salychev * and it's fine. It must not be NULL though. 311158983e4bSDmitry Salychev */ 311258983e4bSDmitry Salychev KASSERT(bch != NULL, ("%s: buffer channel is NULL", __func__)); 311358983e4bSDmitry Salychev 311458983e4bSDmitry Salychev if (__predict_false(paddr != buf->paddr)) { 3115ba7319e9SDmitry Salychev panic("%s: unexpected physical address: fd(%#jx) != buf(%#jx)", 311658983e4bSDmitry Salychev __func__, paddr, buf->paddr); 3117ba7319e9SDmitry Salychev } 3118ba7319e9SDmitry Salychev 3119ba7319e9SDmitry Salychev switch (dpaa2_ni_fd_err(fd)) { 3120ba7319e9SDmitry Salychev case 1: /* Enqueue rejected by QMan */ 3121ba7319e9SDmitry Salychev sc->rx_enq_rej_frames++; 3122ba7319e9SDmitry Salychev break; 3123ba7319e9SDmitry Salychev case 2: /* QMan IEOI error */ 3124ba7319e9SDmitry Salychev sc->rx_ieoi_err_frames++; 3125ba7319e9SDmitry Salychev break; 3126ba7319e9SDmitry Salychev default: 3127ba7319e9SDmitry Salychev break; 3128ba7319e9SDmitry Salychev } 3129ba7319e9SDmitry Salychev switch (dpaa2_ni_fd_format(fd)) { 3130ba7319e9SDmitry Salychev case DPAA2_FD_SINGLE: 3131ba7319e9SDmitry Salychev sc->rx_single_buf_frames++; 3132ba7319e9SDmitry Salychev break; 3133ba7319e9SDmitry Salychev case DPAA2_FD_SG: 3134ba7319e9SDmitry Salychev sc->rx_sg_buf_frames++; 3135ba7319e9SDmitry Salychev break; 3136ba7319e9SDmitry Salychev default: 3137ba7319e9SDmitry Salychev break; 3138ba7319e9SDmitry Salychev } 3139ba7319e9SDmitry Salychev 314058983e4bSDmitry Salychev mtx_assert(&bch->dma_mtx, MA_NOTOWNED); 314158983e4bSDmitry Salychev mtx_lock(&bch->dma_mtx); 3142ba7319e9SDmitry Salychev 314358983e4bSDmitry Salychev bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_POSTREAD); 314458983e4bSDmitry Salychev bus_dmamap_unload(buf->dmat, buf->dmap); 314558983e4bSDmitry Salychev m = buf->m; 3146ba7319e9SDmitry Salychev buf_len = dpaa2_ni_fd_data_len(fd); 314758983e4bSDmitry Salychev buf_data = (uint8_t *)buf->vaddr + dpaa2_ni_fd_offset(fd); 314858983e4bSDmitry Salychev /* Prepare buffer to be re-cycled */ 314958983e4bSDmitry Salychev buf->m = NULL; 315058983e4bSDmitry Salychev buf->paddr = 0; 315158983e4bSDmitry Salychev buf->vaddr = NULL; 315258983e4bSDmitry Salychev buf->seg.ds_addr = 0; 315358983e4bSDmitry Salychev buf->seg.ds_len = 0; 315458983e4bSDmitry Salychev buf->nseg = 0; 3155ba7319e9SDmitry Salychev 315658983e4bSDmitry Salychev mtx_unlock(&bch->dma_mtx); 3157ba7319e9SDmitry Salychev 3158ba7319e9SDmitry Salychev m->m_flags |= M_PKTHDR; 3159ba7319e9SDmitry Salychev m->m_data = buf_data; 3160ba7319e9SDmitry Salychev m->m_len = buf_len; 3161ba7319e9SDmitry Salychev m->m_pkthdr.len = buf_len; 316258983e4bSDmitry Salychev m->m_pkthdr.rcvif = sc->ifp; 3163ba7319e9SDmitry Salychev m->m_pkthdr.flowid = fq->fqid; 3164ba7319e9SDmitry Salychev M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 3165ba7319e9SDmitry Salychev 316658983e4bSDmitry Salychev if (ctx->head == NULL) { 316758983e4bSDmitry Salychev KASSERT(ctx->tail == NULL, ("%s: tail already given?", __func__)); 316858983e4bSDmitry Salychev ctx->head = m; 316958983e4bSDmitry Salychev ctx->tail = m; 317058983e4bSDmitry Salychev } else { 317158983e4bSDmitry Salychev KASSERT(ctx->head != NULL, ("%s: head is NULL", __func__)); 317258983e4bSDmitry Salychev ctx->tail->m_nextpkt = m; 317358983e4bSDmitry Salychev ctx->tail = m; 317458983e4bSDmitry Salychev } 317558983e4bSDmitry Salychev ctx->cnt++; 3176ba7319e9SDmitry Salychev 317758983e4bSDmitry Salychev if (ctx->last) { 317858983e4bSDmitry Salychev ctx->tail->m_nextpkt = NULL; 317958983e4bSDmitry Salychev if_input(sc->ifp, ctx->head); 318058983e4bSDmitry Salychev } 3181ba7319e9SDmitry Salychev 318258983e4bSDmitry Salychev /* Keep the buffer to be recycled */ 318358983e4bSDmitry Salychev ch->recycled[ch->recycled_n++] = buf; 3184ba7319e9SDmitry Salychev 318558983e4bSDmitry Salychev /* Re-seed and release recycled buffers back to the pool */ 318658983e4bSDmitry Salychev if (ch->recycled_n == DPAA2_SWP_BUFS_PER_CMD) { 318758983e4bSDmitry Salychev /* Release new buffers to the pool if needed */ 318858983e4bSDmitry Salychev taskqueue_enqueue(sc->bp_taskq, &ch->bp_task); 3189ba7319e9SDmitry Salychev 319058983e4bSDmitry Salychev for (int i = 0; i < ch->recycled_n; i++) { 319158983e4bSDmitry Salychev buf = ch->recycled[i]; 319258983e4bSDmitry Salychev bch = (struct dpaa2_channel *)buf->opt; 319358983e4bSDmitry Salychev 319458983e4bSDmitry Salychev mtx_assert(&bch->dma_mtx, MA_NOTOWNED); 319558983e4bSDmitry Salychev mtx_lock(&bch->dma_mtx); 319658983e4bSDmitry Salychev error = dpaa2_buf_seed_rxb(sc->dev, buf, 319758983e4bSDmitry Salychev DPAA2_RX_BUF_SIZE, &bch->dma_mtx); 319858983e4bSDmitry Salychev mtx_unlock(&bch->dma_mtx); 319958983e4bSDmitry Salychev 3200ba7319e9SDmitry Salychev if (__predict_false(error != 0)) { 320158983e4bSDmitry Salychev /* TODO: What else to do with the buffer? */ 320258983e4bSDmitry Salychev panic("%s: failed to recycle buffer: error=%d", 320358983e4bSDmitry Salychev __func__, error); 3204ba7319e9SDmitry Salychev } 3205ba7319e9SDmitry Salychev 320658983e4bSDmitry Salychev /* Prepare buffer to be released in a single command */ 320758983e4bSDmitry Salychev released[released_n++] = buf->paddr; 3208ba7319e9SDmitry Salychev } 3209ba7319e9SDmitry Salychev 321058983e4bSDmitry Salychev /* There's only one buffer pool for now */ 321158983e4bSDmitry Salychev bpdev = (device_t)rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]); 321258983e4bSDmitry Salychev bpsc = device_get_softc(bpdev); 3213ba7319e9SDmitry Salychev 321458983e4bSDmitry Salychev error = DPAA2_SWP_RELEASE_BUFS(ch->io_dev, bpsc->attr.bpid, 3215ba7319e9SDmitry Salychev released, released_n); 3216ba7319e9SDmitry Salychev if (__predict_false(error != 0)) { 3217ba7319e9SDmitry Salychev device_printf(sc->dev, "%s: failed to release buffers " 3218ba7319e9SDmitry Salychev "to the pool: error=%d\n", __func__, error); 3219ba7319e9SDmitry Salychev return (error); 3220ba7319e9SDmitry Salychev } 322158983e4bSDmitry Salychev ch->recycled_n = 0; 3222ba7319e9SDmitry Salychev } 3223ba7319e9SDmitry Salychev 3224ba7319e9SDmitry Salychev return (0); 3225ba7319e9SDmitry Salychev } 3226ba7319e9SDmitry Salychev 3227ba7319e9SDmitry Salychev /** 3228ba7319e9SDmitry Salychev * @brief Receive Rx error frames. 3229ba7319e9SDmitry Salychev */ 3230ba7319e9SDmitry Salychev static int 323158983e4bSDmitry Salychev dpaa2_ni_rx_err(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, 3232ba7319e9SDmitry Salychev struct dpaa2_fd *fd) 3233ba7319e9SDmitry Salychev { 3234ba7319e9SDmitry Salychev bus_addr_t paddr = (bus_addr_t)fd->addr; 323558983e4bSDmitry Salychev struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr); 323658983e4bSDmitry Salychev struct dpaa2_buf *buf = fa->buf; 323758983e4bSDmitry Salychev struct dpaa2_channel *bch = (struct dpaa2_channel *)buf->opt; 323858983e4bSDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(bch->ni_dev); 323958983e4bSDmitry Salychev device_t bpdev; 324058983e4bSDmitry Salychev struct dpaa2_bp_softc *bpsc; 3241718bdb6aSDmitry Salychev int error; 3242ba7319e9SDmitry Salychev 3243718bdb6aSDmitry Salychev KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__)); 324458983e4bSDmitry Salychev /* 324558983e4bSDmitry Salychev * NOTE: Current channel might not be the same as the "buffer" channel 324658983e4bSDmitry Salychev * and it's fine. It must not be NULL though. 324758983e4bSDmitry Salychev */ 324858983e4bSDmitry Salychev KASSERT(bch != NULL, ("%s: buffer channel is NULL", __func__)); 324958983e4bSDmitry Salychev 325058983e4bSDmitry Salychev if (__predict_false(paddr != buf->paddr)) { 3251ba7319e9SDmitry Salychev panic("%s: unexpected physical address: fd(%#jx) != buf(%#jx)", 325258983e4bSDmitry Salychev __func__, paddr, buf->paddr); 3253ba7319e9SDmitry Salychev } 3254ba7319e9SDmitry Salychev 325558983e4bSDmitry Salychev /* There's only one buffer pool for now */ 325658983e4bSDmitry Salychev bpdev = (device_t)rman_get_start(sc->res[DPAA2_NI_BP_RID(0)]); 325758983e4bSDmitry Salychev bpsc = device_get_softc(bpdev); 3258ba7319e9SDmitry Salychev 325958983e4bSDmitry Salychev /* Release buffer to QBMan buffer pool */ 326058983e4bSDmitry Salychev error = DPAA2_SWP_RELEASE_BUFS(ch->io_dev, bpsc->attr.bpid, &paddr, 1); 3261ba7319e9SDmitry Salychev if (error != 0) { 3262ba7319e9SDmitry Salychev device_printf(sc->dev, "%s: failed to release frame buffer to " 3263ba7319e9SDmitry Salychev "the pool: error=%d\n", __func__, error); 3264ba7319e9SDmitry Salychev return (error); 3265ba7319e9SDmitry Salychev } 3266ba7319e9SDmitry Salychev 3267ba7319e9SDmitry Salychev return (0); 3268ba7319e9SDmitry Salychev } 3269ba7319e9SDmitry Salychev 3270ba7319e9SDmitry Salychev /** 3271ba7319e9SDmitry Salychev * @brief Receive Tx confirmation frames. 3272ba7319e9SDmitry Salychev */ 3273ba7319e9SDmitry Salychev static int 327458983e4bSDmitry Salychev dpaa2_ni_tx_conf(struct dpaa2_channel *ch, struct dpaa2_ni_fq *fq, 3275ba7319e9SDmitry Salychev struct dpaa2_fd *fd) 3276ba7319e9SDmitry Salychev { 3277718bdb6aSDmitry Salychev bus_addr_t paddr = (bus_addr_t)fd->addr; 327858983e4bSDmitry Salychev struct dpaa2_fa *fa = (struct dpaa2_fa *)PHYS_TO_DMAP(paddr); 327958983e4bSDmitry Salychev struct dpaa2_buf *buf = fa->buf; 328058983e4bSDmitry Salychev struct dpaa2_buf *sgt = buf->sgt; 328158983e4bSDmitry Salychev struct dpaa2_ni_tx_ring *tx = (struct dpaa2_ni_tx_ring *)buf->opt; 328258983e4bSDmitry Salychev struct dpaa2_channel *bch = tx->fq->chan; 3283ba7319e9SDmitry Salychev 3284718bdb6aSDmitry Salychev KASSERT(fa->magic == DPAA2_MAGIC, ("%s: wrong magic", __func__)); 328558983e4bSDmitry Salychev KASSERT(tx != NULL, ("%s: Tx ring is NULL", __func__)); 328658983e4bSDmitry Salychev KASSERT(sgt != NULL, ("%s: S/G table is NULL", __func__)); 328758983e4bSDmitry Salychev /* 328858983e4bSDmitry Salychev * NOTE: Current channel might not be the same as the "buffer" channel 328958983e4bSDmitry Salychev * and it's fine. It must not be NULL though. 329058983e4bSDmitry Salychev */ 329158983e4bSDmitry Salychev KASSERT(bch != NULL, ("%s: buffer channel is NULL", __func__)); 329258983e4bSDmitry Salychev 329358983e4bSDmitry Salychev if (paddr != buf->paddr) { 3294ba7319e9SDmitry Salychev panic("%s: unexpected physical address: fd(%#jx) != buf(%#jx)", 329558983e4bSDmitry Salychev __func__, paddr, buf->paddr); 3296ba7319e9SDmitry Salychev } 3297ba7319e9SDmitry Salychev 329858983e4bSDmitry Salychev mtx_assert(&bch->dma_mtx, MA_NOTOWNED); 329958983e4bSDmitry Salychev mtx_lock(&bch->dma_mtx); 3300ba7319e9SDmitry Salychev 330158983e4bSDmitry Salychev bus_dmamap_sync(buf->dmat, buf->dmap, BUS_DMASYNC_POSTWRITE); 330258983e4bSDmitry Salychev bus_dmamap_sync(sgt->dmat, sgt->dmap, BUS_DMASYNC_POSTWRITE); 330358983e4bSDmitry Salychev bus_dmamap_unload(buf->dmat, buf->dmap); 330458983e4bSDmitry Salychev bus_dmamap_unload(sgt->dmat, sgt->dmap); 330558983e4bSDmitry Salychev m_freem(buf->m); 330658983e4bSDmitry Salychev buf->m = NULL; 330758983e4bSDmitry Salychev buf->paddr = 0; 330858983e4bSDmitry Salychev buf->vaddr = NULL; 330958983e4bSDmitry Salychev sgt->paddr = 0; 331058983e4bSDmitry Salychev 331158983e4bSDmitry Salychev mtx_unlock(&bch->dma_mtx); 331258983e4bSDmitry Salychev 331358983e4bSDmitry Salychev /* Return Tx buffer back to the ring */ 331458983e4bSDmitry Salychev buf_ring_enqueue(tx->br, buf); 3315ba7319e9SDmitry Salychev 3316ba7319e9SDmitry Salychev return (0); 3317ba7319e9SDmitry Salychev } 3318ba7319e9SDmitry Salychev 3319ba7319e9SDmitry Salychev /** 3320ba7319e9SDmitry Salychev * @brief Compare versions of the DPAA2 network interface API. 3321ba7319e9SDmitry Salychev */ 3322ba7319e9SDmitry Salychev static int 3323ba7319e9SDmitry Salychev dpaa2_ni_cmp_api_version(struct dpaa2_ni_softc *sc, uint16_t major, 3324ba7319e9SDmitry Salychev uint16_t minor) 3325ba7319e9SDmitry Salychev { 332658983e4bSDmitry Salychev if (sc->api_major == major) { 3327ba7319e9SDmitry Salychev return sc->api_minor - minor; 332858983e4bSDmitry Salychev } 3329ba7319e9SDmitry Salychev return sc->api_major - major; 3330ba7319e9SDmitry Salychev } 3331ba7319e9SDmitry Salychev 3332ba7319e9SDmitry Salychev /** 3333ba7319e9SDmitry Salychev * @brief Build a DPAA2 frame descriptor. 3334ba7319e9SDmitry Salychev */ 3335ba7319e9SDmitry Salychev static int 3336ba7319e9SDmitry Salychev dpaa2_ni_build_fd(struct dpaa2_ni_softc *sc, struct dpaa2_ni_tx_ring *tx, 333758983e4bSDmitry Salychev struct dpaa2_buf *buf, bus_dma_segment_t *segs, int nsegs, struct dpaa2_fd *fd) 3338ba7319e9SDmitry Salychev { 333958983e4bSDmitry Salychev struct dpaa2_buf *sgt = buf->sgt; 334058983e4bSDmitry Salychev struct dpaa2_sg_entry *sge; 3341718bdb6aSDmitry Salychev struct dpaa2_fa *fa; 3342ba7319e9SDmitry Salychev int i, error; 3343ba7319e9SDmitry Salychev 334458983e4bSDmitry Salychev KASSERT(nsegs <= DPAA2_TX_SEGLIMIT, ("%s: too many segments", __func__)); 334558983e4bSDmitry Salychev KASSERT(buf->opt != NULL, ("%s: no Tx ring?", __func__)); 334658983e4bSDmitry Salychev KASSERT(sgt != NULL, ("%s: no S/G table?", __func__)); 334758983e4bSDmitry Salychev KASSERT(sgt->vaddr != NULL, ("%s: no S/G vaddr?", __func__)); 3348ba7319e9SDmitry Salychev 3349ba7319e9SDmitry Salychev memset(fd, 0, sizeof(*fd)); 3350ba7319e9SDmitry Salychev 335158983e4bSDmitry Salychev /* Populate and map S/G table */ 335258983e4bSDmitry Salychev if (__predict_true(nsegs <= DPAA2_TX_SEGLIMIT)) { 335358983e4bSDmitry Salychev sge = (struct dpaa2_sg_entry *)sgt->vaddr + sc->tx_data_off; 335458983e4bSDmitry Salychev for (i = 0; i < nsegs; i++) { 335558983e4bSDmitry Salychev sge[i].addr = (uint64_t)segs[i].ds_addr; 335658983e4bSDmitry Salychev sge[i].len = (uint32_t)segs[i].ds_len; 335758983e4bSDmitry Salychev sge[i].offset_fmt = 0u; 3358ba7319e9SDmitry Salychev } 335958983e4bSDmitry Salychev sge[i-1].offset_fmt |= 0x8000u; /* set final entry flag */ 3360ba7319e9SDmitry Salychev 336158983e4bSDmitry Salychev KASSERT(sgt->paddr == 0, ("%s: paddr(%#jx) != 0", __func__, 336258983e4bSDmitry Salychev sgt->paddr)); 3363ba7319e9SDmitry Salychev 336458983e4bSDmitry Salychev error = bus_dmamap_load(sgt->dmat, sgt->dmap, sgt->vaddr, 336558983e4bSDmitry Salychev DPAA2_TX_SGT_SZ, dpaa2_dmamap_oneseg_cb, &sgt->paddr, 336658983e4bSDmitry Salychev BUS_DMA_NOWAIT); 3367ba7319e9SDmitry Salychev if (__predict_false(error != 0)) { 336858983e4bSDmitry Salychev device_printf(sc->dev, "%s: bus_dmamap_load() failed: " 3369ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 3370ba7319e9SDmitry Salychev return (error); 3371ba7319e9SDmitry Salychev } 3372718bdb6aSDmitry Salychev 337358983e4bSDmitry Salychev buf->paddr = sgt->paddr; 337458983e4bSDmitry Salychev buf->vaddr = sgt->vaddr; 3375ba7319e9SDmitry Salychev sc->tx_sg_frames++; /* for sysctl(9) */ 3376ba7319e9SDmitry Salychev } else { 3377ba7319e9SDmitry Salychev return (EINVAL); 3378ba7319e9SDmitry Salychev } 3379ba7319e9SDmitry Salychev 338058983e4bSDmitry Salychev fa = (struct dpaa2_fa *)sgt->vaddr; 3381718bdb6aSDmitry Salychev fa->magic = DPAA2_MAGIC; 3382718bdb6aSDmitry Salychev fa->buf = buf; 3383ba7319e9SDmitry Salychev 338458983e4bSDmitry Salychev fd->addr = buf->paddr; 338558983e4bSDmitry Salychev fd->data_length = (uint32_t)buf->m->m_pkthdr.len; 3386ba7319e9SDmitry Salychev fd->bpid_ivp_bmt = 0; 3387ba7319e9SDmitry Salychev fd->offset_fmt_sl = 0x2000u | sc->tx_data_off; 3388ba7319e9SDmitry Salychev fd->ctrl = 0x00800000u; 3389ba7319e9SDmitry Salychev 3390ba7319e9SDmitry Salychev return (0); 3391ba7319e9SDmitry Salychev } 3392ba7319e9SDmitry Salychev 3393ba7319e9SDmitry Salychev static int 3394ba7319e9SDmitry Salychev dpaa2_ni_fd_err(struct dpaa2_fd *fd) 3395ba7319e9SDmitry Salychev { 3396ba7319e9SDmitry Salychev return ((fd->ctrl >> DPAA2_NI_FD_ERR_SHIFT) & DPAA2_NI_FD_ERR_MASK); 3397ba7319e9SDmitry Salychev } 3398ba7319e9SDmitry Salychev 3399ba7319e9SDmitry Salychev static uint32_t 3400ba7319e9SDmitry Salychev dpaa2_ni_fd_data_len(struct dpaa2_fd *fd) 3401ba7319e9SDmitry Salychev { 340258983e4bSDmitry Salychev if (dpaa2_ni_fd_short_len(fd)) { 3403ba7319e9SDmitry Salychev return (fd->data_length & DPAA2_NI_FD_LEN_MASK); 340458983e4bSDmitry Salychev } 3405ba7319e9SDmitry Salychev return (fd->data_length); 3406ba7319e9SDmitry Salychev } 3407ba7319e9SDmitry Salychev 3408ba7319e9SDmitry Salychev static int 3409ba7319e9SDmitry Salychev dpaa2_ni_fd_format(struct dpaa2_fd *fd) 3410ba7319e9SDmitry Salychev { 3411ba7319e9SDmitry Salychev return ((enum dpaa2_fd_format)((fd->offset_fmt_sl >> 3412ba7319e9SDmitry Salychev DPAA2_NI_FD_FMT_SHIFT) & DPAA2_NI_FD_FMT_MASK)); 3413ba7319e9SDmitry Salychev } 3414ba7319e9SDmitry Salychev 3415ba7319e9SDmitry Salychev static bool 3416ba7319e9SDmitry Salychev dpaa2_ni_fd_short_len(struct dpaa2_fd *fd) 3417ba7319e9SDmitry Salychev { 3418ba7319e9SDmitry Salychev return (((fd->offset_fmt_sl >> DPAA2_NI_FD_SL_SHIFT) 3419ba7319e9SDmitry Salychev & DPAA2_NI_FD_SL_MASK) == 1); 3420ba7319e9SDmitry Salychev } 3421ba7319e9SDmitry Salychev 3422ba7319e9SDmitry Salychev static int 3423ba7319e9SDmitry Salychev dpaa2_ni_fd_offset(struct dpaa2_fd *fd) 3424ba7319e9SDmitry Salychev { 3425ba7319e9SDmitry Salychev return (fd->offset_fmt_sl & DPAA2_NI_FD_OFFSET_MASK); 3426ba7319e9SDmitry Salychev } 3427ba7319e9SDmitry Salychev 3428ba7319e9SDmitry Salychev /** 3429ba7319e9SDmitry Salychev * @brief Collect statistics of the network interface. 3430ba7319e9SDmitry Salychev */ 3431ba7319e9SDmitry Salychev static int 3432ba7319e9SDmitry Salychev dpaa2_ni_collect_stats(SYSCTL_HANDLER_ARGS) 3433ba7319e9SDmitry Salychev { 3434ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg1; 3435ba7319e9SDmitry Salychev struct dpni_stat *stat = &dpni_stat_sysctls[oidp->oid_number]; 34364cd96614SDmitry Salychev device_t pdev = device_get_parent(sc->dev); 34374cd96614SDmitry Salychev device_t dev = sc->dev; 34384cd96614SDmitry Salychev device_t child = dev; 34394cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 34404cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 34414cd96614SDmitry Salychev struct dpaa2_cmd cmd; 3442ba7319e9SDmitry Salychev uint64_t cnt[DPAA2_NI_STAT_COUNTERS]; 3443ba7319e9SDmitry Salychev uint64_t result = 0; 34444cd96614SDmitry Salychev uint16_t rc_token, ni_token; 3445ba7319e9SDmitry Salychev int error; 3446ba7319e9SDmitry Salychev 34474cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 3448ba7319e9SDmitry Salychev 34494cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token); 34504cd96614SDmitry Salychev if (error) { 34514cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource container: " 34524cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, rcinfo->id, error); 34534cd96614SDmitry Salychev goto exit; 34544cd96614SDmitry Salychev } 34554cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token); 34564cd96614SDmitry Salychev if (error) { 34574cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network interface: " 34584cd96614SDmitry Salychev "id=%d, error=%d\n", __func__, dinfo->id, error); 34594cd96614SDmitry Salychev goto close_rc; 34604cd96614SDmitry Salychev } 34614cd96614SDmitry Salychev 34624cd96614SDmitry Salychev error = DPAA2_CMD_NI_GET_STATISTICS(dev, child, &cmd, stat->page, 0, cnt); 34634cd96614SDmitry Salychev if (!error) { 34644cd96614SDmitry Salychev result = cnt[stat->cnt]; 34654cd96614SDmitry Salychev } 34664cd96614SDmitry Salychev 34674cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token)); 34684cd96614SDmitry Salychev close_rc: 34694cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token)); 34704cd96614SDmitry Salychev exit: 3471ba7319e9SDmitry Salychev return (sysctl_handle_64(oidp, &result, 0, req)); 3472ba7319e9SDmitry Salychev } 3473ba7319e9SDmitry Salychev 3474ba7319e9SDmitry Salychev static int 3475ba7319e9SDmitry Salychev dpaa2_ni_collect_buf_num(SYSCTL_HANDLER_ARGS) 3476ba7319e9SDmitry Salychev { 3477ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg1; 3478ba7319e9SDmitry Salychev uint32_t buf_num = DPAA2_ATOMIC_READ(&sc->buf_num); 3479ba7319e9SDmitry Salychev 3480ba7319e9SDmitry Salychev return (sysctl_handle_32(oidp, &buf_num, 0, req)); 3481ba7319e9SDmitry Salychev } 3482ba7319e9SDmitry Salychev 3483ba7319e9SDmitry Salychev static int 3484ba7319e9SDmitry Salychev dpaa2_ni_collect_buf_free(SYSCTL_HANDLER_ARGS) 3485ba7319e9SDmitry Salychev { 3486ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = (struct dpaa2_ni_softc *) arg1; 3487ba7319e9SDmitry Salychev uint32_t buf_free = DPAA2_ATOMIC_READ(&sc->buf_free); 3488ba7319e9SDmitry Salychev 3489ba7319e9SDmitry Salychev return (sysctl_handle_32(oidp, &buf_free, 0, req)); 3490ba7319e9SDmitry Salychev } 3491ba7319e9SDmitry Salychev 3492ba7319e9SDmitry Salychev static int 3493ba7319e9SDmitry Salychev dpaa2_ni_set_hash(device_t dev, uint64_t flags) 3494ba7319e9SDmitry Salychev { 3495ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 3496ba7319e9SDmitry Salychev uint64_t key = 0; 3497ba7319e9SDmitry Salychev int i; 3498ba7319e9SDmitry Salychev 3499ba7319e9SDmitry Salychev if (!(sc->attr.num.queues > 1)) { 3500ba7319e9SDmitry Salychev return (EOPNOTSUPP); 3501ba7319e9SDmitry Salychev } 3502ba7319e9SDmitry Salychev 3503ba7319e9SDmitry Salychev for (i = 0; i < ARRAY_SIZE(dist_fields); i++) { 3504ba7319e9SDmitry Salychev if (dist_fields[i].rxnfc_field & flags) { 3505ba7319e9SDmitry Salychev key |= dist_fields[i].id; 3506ba7319e9SDmitry Salychev } 3507ba7319e9SDmitry Salychev } 3508ba7319e9SDmitry Salychev 3509ba7319e9SDmitry Salychev return (dpaa2_ni_set_dist_key(dev, DPAA2_NI_DIST_MODE_HASH, key)); 3510ba7319e9SDmitry Salychev } 3511ba7319e9SDmitry Salychev 3512ba7319e9SDmitry Salychev /** 3513ba7319e9SDmitry Salychev * @brief Set Rx distribution (hash or flow classification) key flags is a 3514ba7319e9SDmitry Salychev * combination of RXH_ bits. 3515ba7319e9SDmitry Salychev */ 3516ba7319e9SDmitry Salychev static int 3517ba7319e9SDmitry Salychev dpaa2_ni_set_dist_key(device_t dev, enum dpaa2_ni_dist_mode type, uint64_t flags) 3518ba7319e9SDmitry Salychev { 35194cd96614SDmitry Salychev device_t pdev = device_get_parent(dev); 3520ba7319e9SDmitry Salychev device_t child = dev; 3521ba7319e9SDmitry Salychev struct dpaa2_ni_softc *sc = device_get_softc(dev); 35224cd96614SDmitry Salychev struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev); 35234cd96614SDmitry Salychev struct dpaa2_devinfo *dinfo = device_get_ivars(dev); 3524ba7319e9SDmitry Salychev struct dpkg_profile_cfg cls_cfg; 3525ba7319e9SDmitry Salychev struct dpkg_extract *key; 3526ba7319e9SDmitry Salychev struct dpaa2_buf *buf = &sc->rxd_kcfg; 35274cd96614SDmitry Salychev struct dpaa2_cmd cmd; 35284cd96614SDmitry Salychev uint16_t rc_token, ni_token; 3529ba7319e9SDmitry Salychev int i, error = 0; 3530ba7319e9SDmitry Salychev 353158983e4bSDmitry Salychev if (__predict_true(buf->dmat == NULL)) { 353258983e4bSDmitry Salychev buf->dmat = sc->rxd_dmat; 35334cd96614SDmitry Salychev } 3534ba7319e9SDmitry Salychev 3535ba7319e9SDmitry Salychev memset(&cls_cfg, 0, sizeof(cls_cfg)); 3536ba7319e9SDmitry Salychev 3537ba7319e9SDmitry Salychev /* Configure extracts according to the given flags. */ 3538ba7319e9SDmitry Salychev for (i = 0; i < ARRAY_SIZE(dist_fields); i++) { 3539ba7319e9SDmitry Salychev key = &cls_cfg.extracts[cls_cfg.num_extracts]; 3540ba7319e9SDmitry Salychev 35414cd96614SDmitry Salychev if (!(flags & dist_fields[i].id)) { 3542ba7319e9SDmitry Salychev continue; 35434cd96614SDmitry Salychev } 3544ba7319e9SDmitry Salychev 3545ba7319e9SDmitry Salychev if (cls_cfg.num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) { 3546ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to add key extraction " 3547ba7319e9SDmitry Salychev "rule\n", __func__); 3548ba7319e9SDmitry Salychev return (E2BIG); 3549ba7319e9SDmitry Salychev } 3550ba7319e9SDmitry Salychev 3551ba7319e9SDmitry Salychev key->type = DPKG_EXTRACT_FROM_HDR; 3552ba7319e9SDmitry Salychev key->extract.from_hdr.prot = dist_fields[i].cls_prot; 3553ba7319e9SDmitry Salychev key->extract.from_hdr.type = DPKG_FULL_FIELD; 3554ba7319e9SDmitry Salychev key->extract.from_hdr.field = dist_fields[i].cls_field; 3555ba7319e9SDmitry Salychev cls_cfg.num_extracts++; 3556ba7319e9SDmitry Salychev } 3557ba7319e9SDmitry Salychev 355858983e4bSDmitry Salychev error = bus_dmamem_alloc(buf->dmat, (void **)&buf->vaddr, 355958983e4bSDmitry Salychev BUS_DMA_ZERO | BUS_DMA_COHERENT, &buf->dmap); 3560ba7319e9SDmitry Salychev if (error != 0) { 3561ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to allocate a buffer for Rx " 3562ba7319e9SDmitry Salychev "traffic distribution key configuration\n", __func__); 3563ba7319e9SDmitry Salychev return (error); 3564ba7319e9SDmitry Salychev } 3565ba7319e9SDmitry Salychev 356658983e4bSDmitry Salychev error = dpaa2_ni_prepare_key_cfg(&cls_cfg, (uint8_t *)buf->vaddr); 3567ba7319e9SDmitry Salychev if (error != 0) { 3568ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to prepare key configuration: " 3569ba7319e9SDmitry Salychev "error=%d\n", __func__, error); 3570ba7319e9SDmitry Salychev return (error); 3571ba7319e9SDmitry Salychev } 3572ba7319e9SDmitry Salychev 3573ba7319e9SDmitry Salychev /* Prepare for setting the Rx dist. */ 357458983e4bSDmitry Salychev error = bus_dmamap_load(buf->dmat, buf->dmap, buf->vaddr, 357558983e4bSDmitry Salychev DPAA2_CLASSIFIER_DMA_SIZE, dpaa2_dmamap_oneseg_cb, &buf->paddr, 357658983e4bSDmitry Salychev BUS_DMA_NOWAIT); 3577ba7319e9SDmitry Salychev if (error != 0) { 3578ba7319e9SDmitry Salychev device_printf(sc->dev, "%s: failed to map a buffer for Rx " 3579ba7319e9SDmitry Salychev "traffic distribution key configuration\n", __func__); 3580ba7319e9SDmitry Salychev return (error); 3581ba7319e9SDmitry Salychev } 3582ba7319e9SDmitry Salychev 3583ba7319e9SDmitry Salychev if (type == DPAA2_NI_DIST_MODE_HASH) { 35844cd96614SDmitry Salychev DPAA2_CMD_INIT(&cmd); 35854cd96614SDmitry Salychev 35864cd96614SDmitry Salychev error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, 35874cd96614SDmitry Salychev &rc_token); 35884cd96614SDmitry Salychev if (error) { 35894cd96614SDmitry Salychev device_printf(dev, "%s: failed to open resource " 35904cd96614SDmitry Salychev "container: id=%d, error=%d\n", __func__, rcinfo->id, 35914cd96614SDmitry Salychev error); 35924cd96614SDmitry Salychev goto err_exit; 35934cd96614SDmitry Salychev } 35944cd96614SDmitry Salychev error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, 35954cd96614SDmitry Salychev &ni_token); 35964cd96614SDmitry Salychev if (error) { 35974cd96614SDmitry Salychev device_printf(dev, "%s: failed to open network " 35984cd96614SDmitry Salychev "interface: id=%d, error=%d\n", __func__, dinfo->id, 35994cd96614SDmitry Salychev error); 36004cd96614SDmitry Salychev goto close_rc; 36014cd96614SDmitry Salychev } 36024cd96614SDmitry Salychev 36034cd96614SDmitry Salychev error = DPAA2_CMD_NI_SET_RX_TC_DIST(dev, child, &cmd, 360458983e4bSDmitry Salychev sc->attr.num.queues, 0, DPAA2_NI_DIST_MODE_HASH, buf->paddr); 36054cd96614SDmitry Salychev if (error != 0) { 3606ba7319e9SDmitry Salychev device_printf(dev, "%s: failed to set distribution mode " 3607ba7319e9SDmitry Salychev "and size for the traffic class\n", __func__); 3608ba7319e9SDmitry Salychev } 3609ba7319e9SDmitry Salychev 36104cd96614SDmitry Salychev (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, 36114cd96614SDmitry Salychev ni_token)); 36124cd96614SDmitry Salychev close_rc: 36134cd96614SDmitry Salychev (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, 36144cd96614SDmitry Salychev rc_token)); 36154cd96614SDmitry Salychev } 36164cd96614SDmitry Salychev 36174cd96614SDmitry Salychev err_exit: 3618ba7319e9SDmitry Salychev return (error); 3619ba7319e9SDmitry Salychev } 3620ba7319e9SDmitry Salychev 3621ba7319e9SDmitry Salychev /** 3622ba7319e9SDmitry Salychev * @brief Prepares extract parameters. 3623ba7319e9SDmitry Salychev * 3624ba7319e9SDmitry Salychev * cfg: Defining a full Key Generation profile. 3625ba7319e9SDmitry Salychev * key_cfg_buf: Zeroed 256 bytes of memory before mapping it to DMA. 3626ba7319e9SDmitry Salychev */ 3627ba7319e9SDmitry Salychev static int 3628ba7319e9SDmitry Salychev dpaa2_ni_prepare_key_cfg(struct dpkg_profile_cfg *cfg, uint8_t *key_cfg_buf) 3629ba7319e9SDmitry Salychev { 3630ba7319e9SDmitry Salychev struct dpni_ext_set_rx_tc_dist *dpni_ext; 3631ba7319e9SDmitry Salychev struct dpni_dist_extract *extr; 3632ba7319e9SDmitry Salychev int i, j; 3633ba7319e9SDmitry Salychev 3634ba7319e9SDmitry Salychev if (cfg->num_extracts > DPKG_MAX_NUM_OF_EXTRACTS) 3635ba7319e9SDmitry Salychev return (EINVAL); 3636ba7319e9SDmitry Salychev 3637ba7319e9SDmitry Salychev dpni_ext = (struct dpni_ext_set_rx_tc_dist *) key_cfg_buf; 3638ba7319e9SDmitry Salychev dpni_ext->num_extracts = cfg->num_extracts; 3639ba7319e9SDmitry Salychev 3640ba7319e9SDmitry Salychev for (i = 0; i < cfg->num_extracts; i++) { 3641ba7319e9SDmitry Salychev extr = &dpni_ext->extracts[i]; 3642ba7319e9SDmitry Salychev 3643ba7319e9SDmitry Salychev switch (cfg->extracts[i].type) { 3644ba7319e9SDmitry Salychev case DPKG_EXTRACT_FROM_HDR: 3645ba7319e9SDmitry Salychev extr->prot = cfg->extracts[i].extract.from_hdr.prot; 3646ba7319e9SDmitry Salychev extr->efh_type = 3647ba7319e9SDmitry Salychev cfg->extracts[i].extract.from_hdr.type & 0x0Fu; 3648ba7319e9SDmitry Salychev extr->size = cfg->extracts[i].extract.from_hdr.size; 3649ba7319e9SDmitry Salychev extr->offset = cfg->extracts[i].extract.from_hdr.offset; 3650ba7319e9SDmitry Salychev extr->field = cfg->extracts[i].extract.from_hdr.field; 3651ba7319e9SDmitry Salychev extr->hdr_index = 3652ba7319e9SDmitry Salychev cfg->extracts[i].extract.from_hdr.hdr_index; 3653ba7319e9SDmitry Salychev break; 3654ba7319e9SDmitry Salychev case DPKG_EXTRACT_FROM_DATA: 3655ba7319e9SDmitry Salychev extr->size = cfg->extracts[i].extract.from_data.size; 3656ba7319e9SDmitry Salychev extr->offset = 3657ba7319e9SDmitry Salychev cfg->extracts[i].extract.from_data.offset; 3658ba7319e9SDmitry Salychev break; 3659ba7319e9SDmitry Salychev case DPKG_EXTRACT_FROM_PARSE: 3660ba7319e9SDmitry Salychev extr->size = cfg->extracts[i].extract.from_parse.size; 3661ba7319e9SDmitry Salychev extr->offset = 3662ba7319e9SDmitry Salychev cfg->extracts[i].extract.from_parse.offset; 3663ba7319e9SDmitry Salychev break; 3664ba7319e9SDmitry Salychev default: 3665ba7319e9SDmitry Salychev return (EINVAL); 3666ba7319e9SDmitry Salychev } 3667ba7319e9SDmitry Salychev 3668ba7319e9SDmitry Salychev extr->num_of_byte_masks = cfg->extracts[i].num_of_byte_masks; 3669ba7319e9SDmitry Salychev extr->extract_type = cfg->extracts[i].type & 0x0Fu; 3670ba7319e9SDmitry Salychev 3671ba7319e9SDmitry Salychev for (j = 0; j < DPKG_NUM_OF_MASKS; j++) { 3672ba7319e9SDmitry Salychev extr->masks[j].mask = cfg->extracts[i].masks[j].mask; 3673ba7319e9SDmitry Salychev extr->masks[j].offset = 3674ba7319e9SDmitry Salychev cfg->extracts[i].masks[j].offset; 3675ba7319e9SDmitry Salychev } 3676ba7319e9SDmitry Salychev } 3677ba7319e9SDmitry Salychev 3678ba7319e9SDmitry Salychev return (0); 3679ba7319e9SDmitry Salychev } 3680ba7319e9SDmitry Salychev 3681ba7319e9SDmitry Salychev static device_method_t dpaa2_ni_methods[] = { 3682ba7319e9SDmitry Salychev /* Device interface */ 3683ba7319e9SDmitry Salychev DEVMETHOD(device_probe, dpaa2_ni_probe), 3684ba7319e9SDmitry Salychev DEVMETHOD(device_attach, dpaa2_ni_attach), 3685ba7319e9SDmitry Salychev DEVMETHOD(device_detach, dpaa2_ni_detach), 3686ba7319e9SDmitry Salychev 3687ba7319e9SDmitry Salychev /* mii via memac_mdio */ 3688ba7319e9SDmitry Salychev DEVMETHOD(miibus_statchg, dpaa2_ni_miibus_statchg), 3689ba7319e9SDmitry Salychev 3690ba7319e9SDmitry Salychev DEVMETHOD_END 3691ba7319e9SDmitry Salychev }; 3692ba7319e9SDmitry Salychev 3693ba7319e9SDmitry Salychev static driver_t dpaa2_ni_driver = { 3694ba7319e9SDmitry Salychev "dpaa2_ni", 3695ba7319e9SDmitry Salychev dpaa2_ni_methods, 3696ba7319e9SDmitry Salychev sizeof(struct dpaa2_ni_softc), 3697ba7319e9SDmitry Salychev }; 3698ba7319e9SDmitry Salychev 3699ba7319e9SDmitry Salychev DRIVER_MODULE(miibus, dpaa2_ni, miibus_driver, 0, 0); 3700ba7319e9SDmitry Salychev DRIVER_MODULE(dpaa2_ni, dpaa2_rc, dpaa2_ni_driver, 0, 0); 3701ba7319e9SDmitry Salychev 3702ba7319e9SDmitry Salychev MODULE_DEPEND(dpaa2_ni, miibus, 1, 1, 1); 3703ba7319e9SDmitry Salychev #ifdef DEV_ACPI 3704ba7319e9SDmitry Salychev MODULE_DEPEND(dpaa2_ni, memac_mdio_acpi, 1, 1, 1); 3705ba7319e9SDmitry Salychev #endif 3706ba7319e9SDmitry Salychev #ifdef FDT 3707ba7319e9SDmitry Salychev MODULE_DEPEND(dpaa2_ni, memac_mdio_fdt, 1, 1, 1); 3708ba7319e9SDmitry Salychev #endif 3709