1ce110ea1SWei Hu /*- 2ce110ea1SWei Hu * SPDX-License-Identifier: BSD-2-Clause 3ce110ea1SWei Hu * 4ce110ea1SWei Hu * Copyright (c) 2021 Microsoft Corp. 5ce110ea1SWei Hu * All rights reserved. 6ce110ea1SWei Hu * 7ce110ea1SWei Hu * Redistribution and use in source and binary forms, with or without 8ce110ea1SWei Hu * modification, are permitted provided that the following conditions 9ce110ea1SWei Hu * are met: 10ce110ea1SWei Hu * 11ce110ea1SWei Hu * 1. Redistributions of source code must retain the above copyright 12ce110ea1SWei Hu * notice, this list of conditions and the following disclaimer. 13ce110ea1SWei Hu * 14ce110ea1SWei Hu * 2. Redistributions in binary form must reproduce the above copyright 15ce110ea1SWei Hu * notice, this list of conditions and the following disclaimer in the 16ce110ea1SWei Hu * documentation and/or other materials provided with the distribution. 17ce110ea1SWei Hu * 18ce110ea1SWei Hu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19ce110ea1SWei Hu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20ce110ea1SWei Hu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21ce110ea1SWei Hu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22ce110ea1SWei Hu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23ce110ea1SWei Hu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24ce110ea1SWei Hu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25ce110ea1SWei Hu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26ce110ea1SWei Hu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27ce110ea1SWei Hu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28ce110ea1SWei Hu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29ce110ea1SWei Hu */ 30fdafd315SWarner Losh 31ce110ea1SWei Hu #include <sys/param.h> 32ce110ea1SWei Hu #include <sys/systm.h> 33ce110ea1SWei Hu #include <sys/bus.h> 34ce110ea1SWei Hu #include <sys/kernel.h> 35ce110ea1SWei Hu #include <sys/kthread.h> 36ce110ea1SWei Hu #include <sys/malloc.h> 37ce110ea1SWei Hu #include <sys/mbuf.h> 38ce110ea1SWei Hu #include <sys/smp.h> 39ce110ea1SWei Hu #include <sys/socket.h> 40ce110ea1SWei Hu #include <sys/sockio.h> 41ce110ea1SWei Hu #include <sys/time.h> 42ce110ea1SWei Hu #include <sys/eventhandler.h> 43ce110ea1SWei Hu 44ce110ea1SWei Hu #include <machine/bus.h> 45ce110ea1SWei Hu #include <machine/resource.h> 46ce110ea1SWei Hu #include <machine/in_cksum.h> 47ce110ea1SWei Hu 48ce110ea1SWei Hu #include <net/if.h> 49ce110ea1SWei Hu #include <net/if_var.h> 50ce110ea1SWei Hu #include <net/if_types.h> 51ce110ea1SWei Hu #include <net/if_vlan_var.h> 52ce110ea1SWei Hu #ifdef RSS 53ce110ea1SWei Hu #include <net/rss_config.h> 54ce110ea1SWei Hu #endif 55ce110ea1SWei Hu 56ce110ea1SWei Hu #include <netinet/in_systm.h> 57ce110ea1SWei Hu #include <netinet/in.h> 58ce110ea1SWei Hu #include <netinet/if_ether.h> 59ce110ea1SWei Hu #include <netinet/ip.h> 60ce110ea1SWei Hu #include <netinet/ip6.h> 61ce110ea1SWei Hu #include <netinet/tcp.h> 62ce110ea1SWei Hu #include <netinet/udp.h> 63ce110ea1SWei Hu 64ce110ea1SWei Hu #include "mana.h" 65ce110ea1SWei Hu #include "mana_sysctl.h" 66ce110ea1SWei Hu 67ce110ea1SWei Hu static int mana_up(struct mana_port_context *apc); 68ce110ea1SWei Hu static int mana_down(struct mana_port_context *apc); 69ce110ea1SWei Hu 70ce110ea1SWei Hu static void 71ce110ea1SWei Hu mana_rss_key_fill(void *k, size_t size) 72ce110ea1SWei Hu { 73ce110ea1SWei Hu static bool rss_key_generated = false; 74ce110ea1SWei Hu static uint8_t rss_key[MANA_HASH_KEY_SIZE]; 75ce110ea1SWei Hu 76ce110ea1SWei Hu KASSERT(size <= MANA_HASH_KEY_SIZE, 77ce110ea1SWei Hu ("Request more buytes than MANA RSS key can hold")); 78ce110ea1SWei Hu 79ce110ea1SWei Hu if (!rss_key_generated) { 80ce110ea1SWei Hu arc4random_buf(rss_key, MANA_HASH_KEY_SIZE); 81ce110ea1SWei Hu rss_key_generated = true; 82ce110ea1SWei Hu } 83ce110ea1SWei Hu memcpy(k, rss_key, size); 84ce110ea1SWei Hu } 85ce110ea1SWei Hu 86ce110ea1SWei Hu static int 8737d22ce0SJustin Hibbits mana_ifmedia_change(if_t ifp __unused) 88ce110ea1SWei Hu { 89ce110ea1SWei Hu return EOPNOTSUPP; 90ce110ea1SWei Hu } 91ce110ea1SWei Hu 92ce110ea1SWei Hu static void 9337d22ce0SJustin Hibbits mana_ifmedia_status(if_t ifp, struct ifmediareq *ifmr) 94ce110ea1SWei Hu { 95ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ifp); 96ce110ea1SWei Hu 97ce110ea1SWei Hu if (!apc) { 98ce110ea1SWei Hu if_printf(ifp, "Port not available\n"); 99ce110ea1SWei Hu return; 100ce110ea1SWei Hu } 101ce110ea1SWei Hu 102ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 103ce110ea1SWei Hu 104ce110ea1SWei Hu ifmr->ifm_status = IFM_AVALID; 105ce110ea1SWei Hu ifmr->ifm_active = IFM_ETHER; 106ce110ea1SWei Hu 107ce110ea1SWei Hu if (!apc->port_is_up) { 108ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 1091833cf13SWei Hu mana_dbg(NULL, "Port %u link is down\n", apc->port_idx); 110ce110ea1SWei Hu return; 111ce110ea1SWei Hu } 112ce110ea1SWei Hu 113ce110ea1SWei Hu ifmr->ifm_status |= IFM_ACTIVE; 114ce110ea1SWei Hu ifmr->ifm_active |= IFM_100G_DR | IFM_FDX; 115ce110ea1SWei Hu 116ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 117ce110ea1SWei Hu } 118ce110ea1SWei Hu 119ce110ea1SWei Hu static uint64_t 12037d22ce0SJustin Hibbits mana_get_counter(if_t ifp, ift_counter cnt) 121ce110ea1SWei Hu { 122ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ifp); 123ce110ea1SWei Hu struct mana_port_stats *stats = &apc->port_stats; 124ce110ea1SWei Hu 125ce110ea1SWei Hu switch (cnt) { 126ce110ea1SWei Hu case IFCOUNTER_IPACKETS: 127ce110ea1SWei Hu return (counter_u64_fetch(stats->rx_packets)); 128ce110ea1SWei Hu case IFCOUNTER_OPACKETS: 129ce110ea1SWei Hu return (counter_u64_fetch(stats->tx_packets)); 130ce110ea1SWei Hu case IFCOUNTER_IBYTES: 131ce110ea1SWei Hu return (counter_u64_fetch(stats->rx_bytes)); 132ce110ea1SWei Hu case IFCOUNTER_OBYTES: 133ce110ea1SWei Hu return (counter_u64_fetch(stats->tx_bytes)); 134ce110ea1SWei Hu case IFCOUNTER_IQDROPS: 135ce110ea1SWei Hu return (counter_u64_fetch(stats->rx_drops)); 136ce110ea1SWei Hu case IFCOUNTER_OQDROPS: 137ce110ea1SWei Hu return (counter_u64_fetch(stats->tx_drops)); 138ce110ea1SWei Hu default: 139ce110ea1SWei Hu return (if_get_counter_default(ifp, cnt)); 140ce110ea1SWei Hu } 141ce110ea1SWei Hu } 142ce110ea1SWei Hu 143ce110ea1SWei Hu static void 14437d22ce0SJustin Hibbits mana_qflush(if_t ifp) 145ce110ea1SWei Hu { 146ce110ea1SWei Hu if_qflush(ifp); 147ce110ea1SWei Hu } 148ce110ea1SWei Hu 149ce110ea1SWei Hu int 150ce110ea1SWei Hu mana_restart(struct mana_port_context *apc) 151ce110ea1SWei Hu { 152ce110ea1SWei Hu int rc = 0; 153ce110ea1SWei Hu 154ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 155ce110ea1SWei Hu if (apc->port_is_up) 156ce110ea1SWei Hu mana_down(apc); 157ce110ea1SWei Hu 158ce110ea1SWei Hu rc = mana_up(apc); 159ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 160ce110ea1SWei Hu 161ce110ea1SWei Hu return (rc); 162ce110ea1SWei Hu } 163ce110ea1SWei Hu 164ce110ea1SWei Hu static int 16537d22ce0SJustin Hibbits mana_ioctl(if_t ifp, u_long command, caddr_t data) 166ce110ea1SWei Hu { 167ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ifp); 168ce110ea1SWei Hu struct ifrsskey *ifrk; 169ce110ea1SWei Hu struct ifrsshash *ifrh; 170ce110ea1SWei Hu struct ifreq *ifr; 171ce110ea1SWei Hu uint16_t new_mtu; 172ab7dc1ceSWei Hu int rc = 0, mask; 173ce110ea1SWei Hu 174ce110ea1SWei Hu switch (command) { 175ce110ea1SWei Hu case SIOCSIFMTU: 176ce110ea1SWei Hu ifr = (struct ifreq *)data; 177ce110ea1SWei Hu new_mtu = ifr->ifr_mtu; 17837d22ce0SJustin Hibbits if (if_getmtu(ifp) == new_mtu) 179ce110ea1SWei Hu break; 180ce110ea1SWei Hu if ((new_mtu + 18 > MAX_FRAME_SIZE) || 181ce110ea1SWei Hu (new_mtu + 18 < MIN_FRAME_SIZE)) { 182ce110ea1SWei Hu if_printf(ifp, "Invalid MTU. new_mtu: %d, " 183ce110ea1SWei Hu "max allowed: %d, min allowed: %d\n", 184ce110ea1SWei Hu new_mtu, MAX_FRAME_SIZE - 18, MIN_FRAME_SIZE - 18); 185ce110ea1SWei Hu return EINVAL; 186ce110ea1SWei Hu } 187ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 188ce110ea1SWei Hu if (apc->port_is_up) 189ce110ea1SWei Hu mana_down(apc); 190ce110ea1SWei Hu 191ce110ea1SWei Hu apc->frame_size = new_mtu + 18; 192ce110ea1SWei Hu if_setmtu(ifp, new_mtu); 193ce110ea1SWei Hu mana_dbg(NULL, "Set MTU to %d\n", new_mtu); 194ce110ea1SWei Hu 195ce110ea1SWei Hu rc = mana_up(apc); 196ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 197ce110ea1SWei Hu break; 198ce110ea1SWei Hu 199ce110ea1SWei Hu case SIOCSIFFLAGS: 20037d22ce0SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 20137d22ce0SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 202ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 203ce110ea1SWei Hu if (!apc->port_is_up) 204ce110ea1SWei Hu rc = mana_up(apc); 205ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 206ce110ea1SWei Hu } 207ce110ea1SWei Hu } else { 20837d22ce0SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 209ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 210ce110ea1SWei Hu if (apc->port_is_up) 211ce110ea1SWei Hu mana_down(apc); 212ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 213ce110ea1SWei Hu } 214ce110ea1SWei Hu } 215ce110ea1SWei Hu break; 216ce110ea1SWei Hu 217ab7dc1ceSWei Hu case SIOCSIFCAP: 218ab7dc1ceSWei Hu MANA_APC_LOCK_LOCK(apc); 219ab7dc1ceSWei Hu ifr = (struct ifreq *)data; 220ab7dc1ceSWei Hu /* 221ab7dc1ceSWei Hu * Fix up requested capabilities w/ supported capabilities, 222ab7dc1ceSWei Hu * since the supported capabilities could have been changed. 223ab7dc1ceSWei Hu */ 224ab7dc1ceSWei Hu mask = (ifr->ifr_reqcap & if_getcapabilities(ifp)) ^ 225ab7dc1ceSWei Hu if_getcapenable(ifp); 226ab7dc1ceSWei Hu 227ab7dc1ceSWei Hu if (mask & IFCAP_TXCSUM) { 228ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_TXCSUM); 229ab7dc1ceSWei Hu if_togglehwassist(ifp, (CSUM_TCP | CSUM_UDP | CSUM_IP)); 230ab7dc1ceSWei Hu 231ab7dc1ceSWei Hu if ((IFCAP_TSO4 & if_getcapenable(ifp)) && 232ab7dc1ceSWei Hu !(IFCAP_TXCSUM & if_getcapenable(ifp))) { 233ab7dc1ceSWei Hu mask &= ~IFCAP_TSO4; 234ab7dc1ceSWei Hu if_setcapenablebit(ifp, 0, IFCAP_TSO4); 235ab7dc1ceSWei Hu if_sethwassistbits(ifp, 0, CSUM_IP_TSO); 236ab7dc1ceSWei Hu mana_warn(NULL, 237ab7dc1ceSWei Hu "Also disabled tso4 due to -txcsum.\n"); 238ab7dc1ceSWei Hu } 239ab7dc1ceSWei Hu } 240ab7dc1ceSWei Hu 241ab7dc1ceSWei Hu if (mask & IFCAP_TXCSUM_IPV6) { 242ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6); 243ab7dc1ceSWei Hu if_togglehwassist(ifp, (CSUM_UDP_IPV6 | CSUM_TCP_IPV6)); 244ab7dc1ceSWei Hu 245ab7dc1ceSWei Hu if ((IFCAP_TSO6 & if_getcapenable(ifp)) && 246ab7dc1ceSWei Hu !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) { 247ab7dc1ceSWei Hu mask &= ~IFCAP_TSO6; 248ab7dc1ceSWei Hu if_setcapenablebit(ifp, 0, IFCAP_TSO6); 249ab7dc1ceSWei Hu if_sethwassistbits(ifp, 0, CSUM_IP6_TSO); 250ab7dc1ceSWei Hu mana_warn(ifp, 251ab7dc1ceSWei Hu "Also disabled tso6 due to -txcsum6.\n"); 252ab7dc1ceSWei Hu } 253ab7dc1ceSWei Hu } 254ab7dc1ceSWei Hu 255ab7dc1ceSWei Hu if (mask & IFCAP_RXCSUM) 256ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_RXCSUM); 257ab7dc1ceSWei Hu /* We can't diff IPv6 packets from IPv4 packets on RX path. */ 258ab7dc1ceSWei Hu if (mask & IFCAP_RXCSUM_IPV6) 259ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6); 260ab7dc1ceSWei Hu 261ab7dc1ceSWei Hu if (mask & IFCAP_LRO) 262ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_LRO); 263ab7dc1ceSWei Hu 264ab7dc1ceSWei Hu if (mask & IFCAP_TSO4) { 265ab7dc1ceSWei Hu if (!(IFCAP_TSO4 & if_getcapenable(ifp)) && 266ab7dc1ceSWei Hu !(IFCAP_TXCSUM & if_getcapenable(ifp))) { 267ab7dc1ceSWei Hu MANA_APC_LOCK_UNLOCK(apc); 268ab7dc1ceSWei Hu if_printf(ifp, "Enable txcsum first.\n"); 269ab7dc1ceSWei Hu rc = EAGAIN; 270ab7dc1ceSWei Hu goto out; 271ab7dc1ceSWei Hu } 272ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_TSO4); 273ab7dc1ceSWei Hu if_togglehwassist(ifp, CSUM_IP_TSO); 274ab7dc1ceSWei Hu } 275ab7dc1ceSWei Hu 276ab7dc1ceSWei Hu if (mask & IFCAP_TSO6) { 277ab7dc1ceSWei Hu if (!(IFCAP_TSO6 & if_getcapenable(ifp)) && 278ab7dc1ceSWei Hu !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) { 279ab7dc1ceSWei Hu MANA_APC_LOCK_UNLOCK(apc); 280ab7dc1ceSWei Hu if_printf(ifp, "Enable txcsum6 first.\n"); 281ab7dc1ceSWei Hu rc = EAGAIN; 282ab7dc1ceSWei Hu goto out; 283ab7dc1ceSWei Hu } 284ab7dc1ceSWei Hu if_togglecapenable(ifp, IFCAP_TSO6); 285ab7dc1ceSWei Hu if_togglehwassist(ifp, CSUM_IP6_TSO); 286ab7dc1ceSWei Hu } 287ab7dc1ceSWei Hu 288ab7dc1ceSWei Hu MANA_APC_LOCK_UNLOCK(apc); 289ab7dc1ceSWei Hu out: 290ab7dc1ceSWei Hu break; 291ab7dc1ceSWei Hu 292ce110ea1SWei Hu case SIOCSIFMEDIA: 293ce110ea1SWei Hu case SIOCGIFMEDIA: 294ce110ea1SWei Hu case SIOCGIFXMEDIA: 295ce110ea1SWei Hu ifr = (struct ifreq *)data; 296ce110ea1SWei Hu rc = ifmedia_ioctl(ifp, ifr, &apc->media, command); 297ce110ea1SWei Hu break; 298ce110ea1SWei Hu 299ce110ea1SWei Hu case SIOCGIFRSSKEY: 300ce110ea1SWei Hu ifrk = (struct ifrsskey *)data; 301ce110ea1SWei Hu ifrk->ifrk_func = RSS_FUNC_TOEPLITZ; 302ce110ea1SWei Hu ifrk->ifrk_keylen = MANA_HASH_KEY_SIZE; 303ce110ea1SWei Hu memcpy(ifrk->ifrk_key, apc->hashkey, MANA_HASH_KEY_SIZE); 304ce110ea1SWei Hu break; 305ce110ea1SWei Hu 306ce110ea1SWei Hu case SIOCGIFRSSHASH: 307ce110ea1SWei Hu ifrh = (struct ifrsshash *)data; 308ce110ea1SWei Hu ifrh->ifrh_func = RSS_FUNC_TOEPLITZ; 309ce110ea1SWei Hu ifrh->ifrh_types = 310ce110ea1SWei Hu RSS_TYPE_TCP_IPV4 | 311ce110ea1SWei Hu RSS_TYPE_UDP_IPV4 | 312ce110ea1SWei Hu RSS_TYPE_TCP_IPV6 | 313ce110ea1SWei Hu RSS_TYPE_UDP_IPV6; 314ce110ea1SWei Hu break; 315ce110ea1SWei Hu 316ce110ea1SWei Hu default: 317ce110ea1SWei Hu rc = ether_ioctl(ifp, command, data); 318ce110ea1SWei Hu break; 319ce110ea1SWei Hu } 320ce110ea1SWei Hu 321ce110ea1SWei Hu return (rc); 322ce110ea1SWei Hu } 323ce110ea1SWei Hu 324ce110ea1SWei Hu static inline void 325ce110ea1SWei Hu mana_alloc_counters(counter_u64_t *begin, int size) 326ce110ea1SWei Hu { 327ce110ea1SWei Hu counter_u64_t *end = (counter_u64_t *)((char *)begin + size); 328ce110ea1SWei Hu 329ce110ea1SWei Hu for (; begin < end; ++begin) 330ce110ea1SWei Hu *begin = counter_u64_alloc(M_WAITOK); 331ce110ea1SWei Hu } 332ce110ea1SWei Hu 333ce110ea1SWei Hu static inline void 334ce110ea1SWei Hu mana_free_counters(counter_u64_t *begin, int size) 335ce110ea1SWei Hu { 336ce110ea1SWei Hu counter_u64_t *end = (counter_u64_t *)((char *)begin + size); 337ce110ea1SWei Hu 338ce110ea1SWei Hu for (; begin < end; ++begin) 339ce110ea1SWei Hu counter_u64_free(*begin); 340ce110ea1SWei Hu } 341ce110ea1SWei Hu 342ce110ea1SWei Hu static bool 343ce110ea1SWei Hu mana_can_tx(struct gdma_queue *wq) 344ce110ea1SWei Hu { 345ce110ea1SWei Hu return mana_gd_wq_avail_space(wq) >= MAX_TX_WQE_SIZE; 346ce110ea1SWei Hu } 347ce110ea1SWei Hu 348ce110ea1SWei Hu static inline int 349ce110ea1SWei Hu mana_tx_map_mbuf(struct mana_port_context *apc, 350ce110ea1SWei Hu struct mana_send_buf_info *tx_info, 351ce110ea1SWei Hu struct mbuf **m_head, struct mana_tx_package *tp, 352ce110ea1SWei Hu struct mana_stats *tx_stats) 353ce110ea1SWei Hu { 354ce110ea1SWei Hu struct gdma_dev *gd = apc->ac->gdma_dev; 355ce110ea1SWei Hu bus_dma_segment_t segs[MAX_MBUF_FRAGS]; 356ce110ea1SWei Hu struct mbuf *m = *m_head; 357ce110ea1SWei Hu int err, nsegs, i; 358ce110ea1SWei Hu 359ce110ea1SWei Hu err = bus_dmamap_load_mbuf_sg(apc->tx_buf_tag, tx_info->dma_map, 360ce110ea1SWei Hu m, segs, &nsegs, BUS_DMA_NOWAIT); 361ce110ea1SWei Hu if (err == EFBIG) { 362ce110ea1SWei Hu struct mbuf *m_new; 363ce110ea1SWei Hu 364ce110ea1SWei Hu counter_u64_add(tx_stats->collapse, 1); 365ce110ea1SWei Hu m_new = m_collapse(m, M_NOWAIT, MAX_MBUF_FRAGS); 366ce110ea1SWei Hu if (unlikely(m_new == NULL)) { 367ce110ea1SWei Hu counter_u64_add(tx_stats->collapse_err, 1); 368ce110ea1SWei Hu return ENOBUFS; 369ce110ea1SWei Hu } else { 370ce110ea1SWei Hu *m_head = m = m_new; 371ce110ea1SWei Hu } 372ce110ea1SWei Hu 373ce110ea1SWei Hu mana_warn(NULL, 374ce110ea1SWei Hu "Too many segs in orig mbuf, m_collapse called\n"); 375ce110ea1SWei Hu 376ce110ea1SWei Hu err = bus_dmamap_load_mbuf_sg(apc->tx_buf_tag, 377ce110ea1SWei Hu tx_info->dma_map, m, segs, &nsegs, BUS_DMA_NOWAIT); 378ce110ea1SWei Hu } 379ce110ea1SWei Hu if (!err) { 380ce110ea1SWei Hu for (i = 0; i < nsegs; i++) { 381ce110ea1SWei Hu tp->wqe_req.sgl[i].address = segs[i].ds_addr; 382ce110ea1SWei Hu tp->wqe_req.sgl[i].mem_key = gd->gpa_mkey; 383ce110ea1SWei Hu tp->wqe_req.sgl[i].size = segs[i].ds_len; 384ce110ea1SWei Hu } 385ce110ea1SWei Hu tp->wqe_req.num_sge = nsegs; 386ce110ea1SWei Hu 387ce110ea1SWei Hu tx_info->mbuf = *m_head; 388ce110ea1SWei Hu 389ce110ea1SWei Hu bus_dmamap_sync(apc->tx_buf_tag, tx_info->dma_map, 390ce110ea1SWei Hu BUS_DMASYNC_PREWRITE); 391ce110ea1SWei Hu } 392ce110ea1SWei Hu 393ce110ea1SWei Hu return err; 394ce110ea1SWei Hu } 395ce110ea1SWei Hu 396ce110ea1SWei Hu static inline void 397ce110ea1SWei Hu mana_tx_unmap_mbuf(struct mana_port_context *apc, 398ce110ea1SWei Hu struct mana_send_buf_info *tx_info) 399ce110ea1SWei Hu { 400ce110ea1SWei Hu bus_dmamap_sync(apc->tx_buf_tag, tx_info->dma_map, 401ce110ea1SWei Hu BUS_DMASYNC_POSTWRITE); 402ce110ea1SWei Hu bus_dmamap_unload(apc->tx_buf_tag, tx_info->dma_map); 403ce110ea1SWei Hu if (tx_info->mbuf) { 404ce110ea1SWei Hu m_freem(tx_info->mbuf); 405ce110ea1SWei Hu tx_info->mbuf = NULL; 406ce110ea1SWei Hu } 407ce110ea1SWei Hu } 408ce110ea1SWei Hu 409ce110ea1SWei Hu static inline int 410ce110ea1SWei Hu mana_load_rx_mbuf(struct mana_port_context *apc, struct mana_rxq *rxq, 411ce110ea1SWei Hu struct mana_recv_buf_oob *rx_oob, bool alloc_mbuf) 412ce110ea1SWei Hu { 413ce110ea1SWei Hu bus_dma_segment_t segs[1]; 414ce110ea1SWei Hu struct mbuf *mbuf; 415ce110ea1SWei Hu int nsegs, err; 416ce110ea1SWei Hu uint32_t mlen; 417ce110ea1SWei Hu 418ce110ea1SWei Hu if (alloc_mbuf) { 419ce110ea1SWei Hu mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, rxq->datasize); 420ce110ea1SWei Hu if (unlikely(mbuf == NULL)) { 421ce110ea1SWei Hu mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 422ce110ea1SWei Hu if (unlikely(mbuf == NULL)) { 423ce110ea1SWei Hu return ENOMEM; 424ce110ea1SWei Hu } 425ce110ea1SWei Hu mlen = MCLBYTES; 426ce110ea1SWei Hu } else { 427ce110ea1SWei Hu mlen = rxq->datasize; 428ce110ea1SWei Hu } 429ce110ea1SWei Hu 430ce110ea1SWei Hu mbuf->m_pkthdr.len = mbuf->m_len = mlen; 431ce110ea1SWei Hu } else { 432ce110ea1SWei Hu if (rx_oob->mbuf) { 433ce110ea1SWei Hu mbuf = rx_oob->mbuf; 434ce110ea1SWei Hu mlen = rx_oob->mbuf->m_pkthdr.len; 435ce110ea1SWei Hu } else { 436ce110ea1SWei Hu return ENOMEM; 437ce110ea1SWei Hu } 438ce110ea1SWei Hu } 439ce110ea1SWei Hu 440ce110ea1SWei Hu err = bus_dmamap_load_mbuf_sg(apc->rx_buf_tag, rx_oob->dma_map, 441ce110ea1SWei Hu mbuf, segs, &nsegs, BUS_DMA_NOWAIT); 442ce110ea1SWei Hu 443ce110ea1SWei Hu if (unlikely((err != 0) || (nsegs != 1))) { 444ce110ea1SWei Hu mana_warn(NULL, "Failed to map mbuf, error: %d, " 445ce110ea1SWei Hu "nsegs: %d\n", err, nsegs); 446ce110ea1SWei Hu counter_u64_add(rxq->stats.dma_mapping_err, 1); 447ce110ea1SWei Hu goto error; 448ce110ea1SWei Hu } 449ce110ea1SWei Hu 450ce110ea1SWei Hu bus_dmamap_sync(apc->rx_buf_tag, rx_oob->dma_map, 451ce110ea1SWei Hu BUS_DMASYNC_PREREAD); 452ce110ea1SWei Hu 453ce110ea1SWei Hu rx_oob->mbuf = mbuf; 454ce110ea1SWei Hu rx_oob->num_sge = 1; 455ce110ea1SWei Hu rx_oob->sgl[0].address = segs[0].ds_addr; 456ce110ea1SWei Hu rx_oob->sgl[0].size = mlen; 457ce110ea1SWei Hu rx_oob->sgl[0].mem_key = apc->ac->gdma_dev->gpa_mkey; 458ce110ea1SWei Hu 459ce110ea1SWei Hu return 0; 460ce110ea1SWei Hu 461ce110ea1SWei Hu error: 462ce110ea1SWei Hu m_freem(mbuf); 463ce110ea1SWei Hu return EFAULT; 464ce110ea1SWei Hu } 465ce110ea1SWei Hu 466ce110ea1SWei Hu static inline void 467ce110ea1SWei Hu mana_unload_rx_mbuf(struct mana_port_context *apc, struct mana_rxq *rxq, 468ce110ea1SWei Hu struct mana_recv_buf_oob *rx_oob, bool free_mbuf) 469ce110ea1SWei Hu { 470ce110ea1SWei Hu bus_dmamap_sync(apc->rx_buf_tag, rx_oob->dma_map, 471ce110ea1SWei Hu BUS_DMASYNC_POSTREAD); 472ce110ea1SWei Hu bus_dmamap_unload(apc->rx_buf_tag, rx_oob->dma_map); 473ce110ea1SWei Hu 474ce110ea1SWei Hu if (free_mbuf && rx_oob->mbuf) { 475ce110ea1SWei Hu m_freem(rx_oob->mbuf); 476ce110ea1SWei Hu rx_oob->mbuf = NULL; 477ce110ea1SWei Hu } 478ce110ea1SWei Hu } 479ce110ea1SWei Hu 480ce110ea1SWei Hu 481ce110ea1SWei Hu /* Use couple mbuf PH_loc spaces for l3 and l4 protocal type */ 482ce110ea1SWei Hu #define MANA_L3_PROTO(_mbuf) ((_mbuf)->m_pkthdr.PH_loc.sixteen[0]) 483ce110ea1SWei Hu #define MANA_L4_PROTO(_mbuf) ((_mbuf)->m_pkthdr.PH_loc.sixteen[1]) 484ce110ea1SWei Hu 485ce110ea1SWei Hu #define MANA_TXQ_FULL (IFF_DRV_RUNNING | IFF_DRV_OACTIVE) 486ce110ea1SWei Hu 487ce110ea1SWei Hu static void 488ce110ea1SWei Hu mana_xmit(struct mana_txq *txq) 489ce110ea1SWei Hu { 490ce110ea1SWei Hu enum mana_tx_pkt_format pkt_fmt = MANA_SHORT_PKT_FMT; 491ce110ea1SWei Hu struct mana_send_buf_info *tx_info; 49237d22ce0SJustin Hibbits if_t ndev = txq->ndev; 493ce110ea1SWei Hu struct mbuf *mbuf; 494ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ndev); 495ce110ea1SWei Hu struct mana_port_stats *port_stats = &apc->port_stats; 496ce110ea1SWei Hu struct gdma_dev *gd = apc->ac->gdma_dev; 497ce110ea1SWei Hu uint64_t packets, bytes; 498ce110ea1SWei Hu uint16_t next_to_use; 499ce110ea1SWei Hu struct mana_tx_package pkg = {}; 500ce110ea1SWei Hu struct mana_stats *tx_stats; 501ce110ea1SWei Hu struct gdma_queue *gdma_sq; 502ce110ea1SWei Hu struct mana_cq *cq; 503ce110ea1SWei Hu int err, len; 504b167e449SWei Hu bool is_tso; 505ce110ea1SWei Hu 506ce110ea1SWei Hu gdma_sq = txq->gdma_sq; 507ce110ea1SWei Hu cq = &apc->tx_qp[txq->idx].tx_cq; 508ce110ea1SWei Hu tx_stats = &txq->stats; 509ce110ea1SWei Hu 510ce110ea1SWei Hu packets = 0; 511ce110ea1SWei Hu bytes = 0; 512ce110ea1SWei Hu next_to_use = txq->next_to_use; 513ce110ea1SWei Hu 514ce110ea1SWei Hu while ((mbuf = drbr_peek(ndev, txq->txq_br)) != NULL) { 515ce110ea1SWei Hu if (!apc->port_is_up || 516ce110ea1SWei Hu (if_getdrvflags(ndev) & MANA_TXQ_FULL) != IFF_DRV_RUNNING) { 517ce110ea1SWei Hu drbr_putback(ndev, txq->txq_br, mbuf); 518ce110ea1SWei Hu break; 519ce110ea1SWei Hu } 520ce110ea1SWei Hu 521ce110ea1SWei Hu if (!mana_can_tx(gdma_sq)) { 522ce110ea1SWei Hu /* SQ is full. Set the IFF_DRV_OACTIVE flag */ 523ce110ea1SWei Hu if_setdrvflagbits(apc->ndev, IFF_DRV_OACTIVE, 0); 524ce110ea1SWei Hu counter_u64_add(tx_stats->stop, 1); 525ce110ea1SWei Hu uint64_t stops = counter_u64_fetch(tx_stats->stop); 526ce110ea1SWei Hu uint64_t wakeups = counter_u64_fetch(tx_stats->wakeup); 527ce110ea1SWei Hu #define MANA_TXQ_STOP_THRESHOLD 50 528ce110ea1SWei Hu if (stops > MANA_TXQ_STOP_THRESHOLD && wakeups > 0 && 529ce110ea1SWei Hu stops > wakeups && txq->alt_txq_idx == txq->idx) { 530ce110ea1SWei Hu txq->alt_txq_idx = 531ce110ea1SWei Hu (txq->idx + (stops / wakeups)) 532ce110ea1SWei Hu % apc->num_queues; 533ce110ea1SWei Hu counter_u64_add(tx_stats->alt_chg, 1); 534ce110ea1SWei Hu } 535ce110ea1SWei Hu 536ce110ea1SWei Hu drbr_putback(ndev, txq->txq_br, mbuf); 537ce110ea1SWei Hu 5381833cf13SWei Hu taskqueue_enqueue(cq->cleanup_tq, &cq->cleanup_task); 539ce110ea1SWei Hu break; 540ce110ea1SWei Hu } 541ce110ea1SWei Hu 542ce110ea1SWei Hu tx_info = &txq->tx_buf_info[next_to_use]; 543ce110ea1SWei Hu 544ce110ea1SWei Hu memset(&pkg, 0, sizeof(struct mana_tx_package)); 545ce110ea1SWei Hu pkg.wqe_req.sgl = pkg.sgl_array; 546ce110ea1SWei Hu 547ce110ea1SWei Hu err = mana_tx_map_mbuf(apc, tx_info, &mbuf, &pkg, tx_stats); 548ce110ea1SWei Hu if (unlikely(err)) { 549ce110ea1SWei Hu mana_dbg(NULL, 550ce110ea1SWei Hu "Failed to map tx mbuf, err %d\n", err); 551ce110ea1SWei Hu 552ce110ea1SWei Hu counter_u64_add(tx_stats->dma_mapping_err, 1); 553ce110ea1SWei Hu 554ce110ea1SWei Hu /* The mbuf is still there. Free it */ 555ce110ea1SWei Hu m_freem(mbuf); 556ce110ea1SWei Hu /* Advance the drbr queue */ 557ce110ea1SWei Hu drbr_advance(ndev, txq->txq_br); 558ce110ea1SWei Hu continue; 559ce110ea1SWei Hu } 560ce110ea1SWei Hu 561ce110ea1SWei Hu pkg.tx_oob.s_oob.vcq_num = cq->gdma_id; 562ce110ea1SWei Hu pkg.tx_oob.s_oob.vsq_frame = txq->vsq_frame; 563ce110ea1SWei Hu 564ce110ea1SWei Hu if (txq->vp_offset > MANA_SHORT_VPORT_OFFSET_MAX) { 565ce110ea1SWei Hu pkg.tx_oob.l_oob.long_vp_offset = txq->vp_offset; 566ce110ea1SWei Hu pkt_fmt = MANA_LONG_PKT_FMT; 567ce110ea1SWei Hu } else { 568ce110ea1SWei Hu pkg.tx_oob.s_oob.short_vp_offset = txq->vp_offset; 569ce110ea1SWei Hu } 570ce110ea1SWei Hu 571ce110ea1SWei Hu pkg.tx_oob.s_oob.pkt_fmt = pkt_fmt; 572ce110ea1SWei Hu 573ce110ea1SWei Hu if (pkt_fmt == MANA_SHORT_PKT_FMT) 574ce110ea1SWei Hu pkg.wqe_req.inline_oob_size = sizeof(struct mana_tx_short_oob); 575ce110ea1SWei Hu else 576ce110ea1SWei Hu pkg.wqe_req.inline_oob_size = sizeof(struct mana_tx_oob); 577ce110ea1SWei Hu 578ce110ea1SWei Hu pkg.wqe_req.inline_oob_data = &pkg.tx_oob; 579ce110ea1SWei Hu pkg.wqe_req.flags = 0; 580ce110ea1SWei Hu pkg.wqe_req.client_data_unit = 0; 581ce110ea1SWei Hu 582b167e449SWei Hu is_tso = false; 583ce110ea1SWei Hu if (mbuf->m_pkthdr.csum_flags & CSUM_TSO) { 584b167e449SWei Hu is_tso = true; 585b167e449SWei Hu 586ce110ea1SWei Hu if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IP) 587ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv4 = 1; 588ce110ea1SWei Hu else 589ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv6 = 1; 590ce110ea1SWei Hu 591ce110ea1SWei Hu pkg.tx_oob.s_oob.comp_iphdr_csum = 1; 592ce110ea1SWei Hu pkg.tx_oob.s_oob.comp_tcp_csum = 1; 593ce110ea1SWei Hu pkg.tx_oob.s_oob.trans_off = mbuf->m_pkthdr.l3hlen; 594ce110ea1SWei Hu 595ce110ea1SWei Hu pkg.wqe_req.client_data_unit = mbuf->m_pkthdr.tso_segsz; 596ce110ea1SWei Hu pkg.wqe_req.flags = GDMA_WR_OOB_IN_SGL | GDMA_WR_PAD_BY_SGE0; 597ce110ea1SWei Hu } else if (mbuf->m_pkthdr.csum_flags & 598ce110ea1SWei Hu (CSUM_IP_UDP | CSUM_IP_TCP | CSUM_IP6_UDP | CSUM_IP6_TCP)) { 599ce110ea1SWei Hu if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IP) { 600ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv4 = 1; 601ce110ea1SWei Hu pkg.tx_oob.s_oob.comp_iphdr_csum = 1; 602ce110ea1SWei Hu } else { 603ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv6 = 1; 604ce110ea1SWei Hu } 605ce110ea1SWei Hu 606ce110ea1SWei Hu if (MANA_L4_PROTO(mbuf) == IPPROTO_TCP) { 607ce110ea1SWei Hu pkg.tx_oob.s_oob.comp_tcp_csum = 1; 608ce110ea1SWei Hu pkg.tx_oob.s_oob.trans_off = 609ce110ea1SWei Hu mbuf->m_pkthdr.l3hlen; 610ce110ea1SWei Hu } else { 611ce110ea1SWei Hu pkg.tx_oob.s_oob.comp_udp_csum = 1; 612ce110ea1SWei Hu } 613ce110ea1SWei Hu } else if (mbuf->m_pkthdr.csum_flags & CSUM_IP) { 614ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv4 = 1; 615ce110ea1SWei Hu pkg.tx_oob.s_oob.comp_iphdr_csum = 1; 616ce110ea1SWei Hu } else { 617ce110ea1SWei Hu if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IP) 618ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv4 = 1; 619ce110ea1SWei Hu else if (MANA_L3_PROTO(mbuf) == ETHERTYPE_IPV6) 620ce110ea1SWei Hu pkg.tx_oob.s_oob.is_outer_ipv6 = 1; 621ce110ea1SWei Hu } 622ce110ea1SWei Hu 623ce110ea1SWei Hu len = mbuf->m_pkthdr.len; 624ce110ea1SWei Hu 625ce110ea1SWei Hu err = mana_gd_post_work_request(gdma_sq, &pkg.wqe_req, 626ce110ea1SWei Hu (struct gdma_posted_wqe_info *)&tx_info->wqe_inf); 627ce110ea1SWei Hu if (unlikely(err)) { 628ce110ea1SWei Hu /* Should not happen */ 629ce110ea1SWei Hu if_printf(ndev, "Failed to post TX OOB: %d\n", err); 630ce110ea1SWei Hu 631ce110ea1SWei Hu mana_tx_unmap_mbuf(apc, tx_info); 632ce110ea1SWei Hu 633ce110ea1SWei Hu drbr_advance(ndev, txq->txq_br); 634ce110ea1SWei Hu continue; 635ce110ea1SWei Hu } 636ce110ea1SWei Hu 637ce110ea1SWei Hu next_to_use = 638ce110ea1SWei Hu (next_to_use + 1) % MAX_SEND_BUFFERS_PER_QUEUE; 639ce110ea1SWei Hu 6400def501dSJohn Baldwin (void)atomic_inc_return(&txq->pending_sends); 641ce110ea1SWei Hu 642ce110ea1SWei Hu drbr_advance(ndev, txq->txq_br); 643ce110ea1SWei Hu 644ce110ea1SWei Hu mana_gd_wq_ring_doorbell(gd->gdma_context, gdma_sq); 645ce110ea1SWei Hu 646ce110ea1SWei Hu packets++; 647ce110ea1SWei Hu bytes += len; 648b167e449SWei Hu 649b167e449SWei Hu if (is_tso) { 650b167e449SWei Hu txq->tso_pkts++; 651b167e449SWei Hu txq->tso_bytes += len; 652b167e449SWei Hu } 653ce110ea1SWei Hu } 654ce110ea1SWei Hu 655ce110ea1SWei Hu counter_enter(); 656ce110ea1SWei Hu counter_u64_add_protected(tx_stats->packets, packets); 657ce110ea1SWei Hu counter_u64_add_protected(port_stats->tx_packets, packets); 658ce110ea1SWei Hu counter_u64_add_protected(tx_stats->bytes, bytes); 659ce110ea1SWei Hu counter_u64_add_protected(port_stats->tx_bytes, bytes); 660ce110ea1SWei Hu counter_exit(); 661ce110ea1SWei Hu 662ce110ea1SWei Hu txq->next_to_use = next_to_use; 663ce110ea1SWei Hu } 664ce110ea1SWei Hu 665ce110ea1SWei Hu static void 666ce110ea1SWei Hu mana_xmit_taskfunc(void *arg, int pending) 667ce110ea1SWei Hu { 668ce110ea1SWei Hu struct mana_txq *txq = (struct mana_txq *)arg; 66937d22ce0SJustin Hibbits if_t ndev = txq->ndev; 670ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ndev); 671ce110ea1SWei Hu 672ce110ea1SWei Hu while (!drbr_empty(ndev, txq->txq_br) && apc->port_is_up && 673ce110ea1SWei Hu (if_getdrvflags(ndev) & MANA_TXQ_FULL) == IFF_DRV_RUNNING) { 674ce110ea1SWei Hu mtx_lock(&txq->txq_mtx); 675ce110ea1SWei Hu mana_xmit(txq); 676ce110ea1SWei Hu mtx_unlock(&txq->txq_mtx); 677ce110ea1SWei Hu } 678ce110ea1SWei Hu } 679ce110ea1SWei Hu 680ce110ea1SWei Hu #define PULLUP_HDR(m, len) \ 681ce110ea1SWei Hu do { \ 682ce110ea1SWei Hu if (unlikely((m)->m_len < (len))) { \ 683ce110ea1SWei Hu (m) = m_pullup((m), (len)); \ 684ce110ea1SWei Hu if ((m) == NULL) \ 685ce110ea1SWei Hu return (NULL); \ 686ce110ea1SWei Hu } \ 687ce110ea1SWei Hu } while (0) 688ce110ea1SWei Hu 689ce110ea1SWei Hu /* 690ce110ea1SWei Hu * If this function failed, the mbuf would be freed. 691ce110ea1SWei Hu */ 692ce110ea1SWei Hu static inline struct mbuf * 693ce110ea1SWei Hu mana_tso_fixup(struct mbuf *mbuf) 694ce110ea1SWei Hu { 695ce110ea1SWei Hu struct ether_vlan_header *eh = mtod(mbuf, struct ether_vlan_header *); 696ce110ea1SWei Hu struct tcphdr *th; 697ce110ea1SWei Hu uint16_t etype; 698ce110ea1SWei Hu int ehlen; 699ce110ea1SWei Hu 700ce110ea1SWei Hu if (eh->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) { 701ce110ea1SWei Hu etype = ntohs(eh->evl_proto); 702ce110ea1SWei Hu ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 703ce110ea1SWei Hu } else { 704ce110ea1SWei Hu etype = ntohs(eh->evl_encap_proto); 705ce110ea1SWei Hu ehlen = ETHER_HDR_LEN; 706ce110ea1SWei Hu } 707ce110ea1SWei Hu 708ce110ea1SWei Hu if (etype == ETHERTYPE_IP) { 709ce110ea1SWei Hu struct ip *ip; 710ce110ea1SWei Hu int iphlen; 711ce110ea1SWei Hu 712ce110ea1SWei Hu PULLUP_HDR(mbuf, ehlen + sizeof(*ip)); 713ce110ea1SWei Hu ip = mtodo(mbuf, ehlen); 714ce110ea1SWei Hu iphlen = ip->ip_hl << 2; 715ce110ea1SWei Hu mbuf->m_pkthdr.l3hlen = ehlen + iphlen; 716ce110ea1SWei Hu 717ce110ea1SWei Hu PULLUP_HDR(mbuf, ehlen + iphlen + sizeof(*th)); 718ce110ea1SWei Hu th = mtodo(mbuf, ehlen + iphlen); 719ce110ea1SWei Hu 720ce110ea1SWei Hu ip->ip_len = 0; 721ce110ea1SWei Hu ip->ip_sum = 0; 722ce110ea1SWei Hu th->th_sum = in_pseudo(ip->ip_src.s_addr, 723ce110ea1SWei Hu ip->ip_dst.s_addr, htons(IPPROTO_TCP)); 724ce110ea1SWei Hu } else if (etype == ETHERTYPE_IPV6) { 725ce110ea1SWei Hu struct ip6_hdr *ip6; 726ce110ea1SWei Hu 727ce110ea1SWei Hu PULLUP_HDR(mbuf, ehlen + sizeof(*ip6) + sizeof(*th)); 728ce110ea1SWei Hu ip6 = mtodo(mbuf, ehlen); 729ce110ea1SWei Hu if (ip6->ip6_nxt != IPPROTO_TCP) { 730ce110ea1SWei Hu /* Realy something wrong, just return */ 731ce110ea1SWei Hu mana_dbg(NULL, "TSO mbuf not TCP, freed.\n"); 732ce110ea1SWei Hu m_freem(mbuf); 733ce110ea1SWei Hu return NULL; 734ce110ea1SWei Hu } 735ce110ea1SWei Hu mbuf->m_pkthdr.l3hlen = ehlen + sizeof(*ip6); 736ce110ea1SWei Hu 737ce110ea1SWei Hu th = mtodo(mbuf, ehlen + sizeof(*ip6)); 738ce110ea1SWei Hu 739ce110ea1SWei Hu ip6->ip6_plen = 0; 740ce110ea1SWei Hu th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); 741ce110ea1SWei Hu } else { 742ce110ea1SWei Hu /* CSUM_TSO is set but not IP protocol. */ 743ce110ea1SWei Hu mana_warn(NULL, "TSO mbuf not right, freed.\n"); 744ce110ea1SWei Hu m_freem(mbuf); 745ce110ea1SWei Hu return NULL; 746ce110ea1SWei Hu } 747ce110ea1SWei Hu 748ce110ea1SWei Hu MANA_L3_PROTO(mbuf) = etype; 749ce110ea1SWei Hu 750ce110ea1SWei Hu return (mbuf); 751ce110ea1SWei Hu } 752ce110ea1SWei Hu 753ce110ea1SWei Hu /* 754ce110ea1SWei Hu * If this function failed, the mbuf would be freed. 755ce110ea1SWei Hu */ 756ce110ea1SWei Hu static inline struct mbuf * 757ce110ea1SWei Hu mana_mbuf_csum_check(struct mbuf *mbuf) 758ce110ea1SWei Hu { 759ce110ea1SWei Hu struct ether_vlan_header *eh = mtod(mbuf, struct ether_vlan_header *); 760ce110ea1SWei Hu struct mbuf *mbuf_next; 761ce110ea1SWei Hu uint16_t etype; 762ce110ea1SWei Hu int offset; 763ce110ea1SWei Hu int ehlen; 764ce110ea1SWei Hu 765ce110ea1SWei Hu if (eh->evl_encap_proto == ntohs(ETHERTYPE_VLAN)) { 766ce110ea1SWei Hu etype = ntohs(eh->evl_proto); 767ce110ea1SWei Hu ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 768ce110ea1SWei Hu } else { 769ce110ea1SWei Hu etype = ntohs(eh->evl_encap_proto); 770ce110ea1SWei Hu ehlen = ETHER_HDR_LEN; 771ce110ea1SWei Hu } 772ce110ea1SWei Hu 773ce110ea1SWei Hu mbuf_next = m_getptr(mbuf, ehlen, &offset); 774ce110ea1SWei Hu 775ce110ea1SWei Hu MANA_L4_PROTO(mbuf) = 0; 776ce110ea1SWei Hu if (etype == ETHERTYPE_IP) { 777ce110ea1SWei Hu const struct ip *ip; 778ce110ea1SWei Hu int iphlen; 779ce110ea1SWei Hu 780ce110ea1SWei Hu ip = (struct ip *)(mtodo(mbuf_next, offset)); 781ce110ea1SWei Hu iphlen = ip->ip_hl << 2; 782ce110ea1SWei Hu mbuf->m_pkthdr.l3hlen = ehlen + iphlen; 783ce110ea1SWei Hu 784ce110ea1SWei Hu MANA_L4_PROTO(mbuf) = ip->ip_p; 785ce110ea1SWei Hu } else if (etype == ETHERTYPE_IPV6) { 786ce110ea1SWei Hu const struct ip6_hdr *ip6; 787ce110ea1SWei Hu 788ce110ea1SWei Hu ip6 = (struct ip6_hdr *)(mtodo(mbuf_next, offset)); 789ce110ea1SWei Hu mbuf->m_pkthdr.l3hlen = ehlen + sizeof(*ip6); 790ce110ea1SWei Hu 791ce110ea1SWei Hu MANA_L4_PROTO(mbuf) = ip6->ip6_nxt; 792ce110ea1SWei Hu } else { 793ce110ea1SWei Hu MANA_L4_PROTO(mbuf) = 0; 794ce110ea1SWei Hu } 795ce110ea1SWei Hu 796ce110ea1SWei Hu MANA_L3_PROTO(mbuf) = etype; 797ce110ea1SWei Hu 798ce110ea1SWei Hu return (mbuf); 799ce110ea1SWei Hu } 800ce110ea1SWei Hu 801ce110ea1SWei Hu static int 80237d22ce0SJustin Hibbits mana_start_xmit(if_t ifp, struct mbuf *m) 803ce110ea1SWei Hu { 804ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ifp); 805ce110ea1SWei Hu struct mana_txq *txq; 806ce110ea1SWei Hu int is_drbr_empty; 807ce110ea1SWei Hu uint16_t txq_id; 808ce110ea1SWei Hu int err; 809ce110ea1SWei Hu 810ce110ea1SWei Hu if (unlikely((!apc->port_is_up) || 811ce110ea1SWei Hu (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)) 812ce110ea1SWei Hu return ENODEV; 813ce110ea1SWei Hu 814ce110ea1SWei Hu if (m->m_pkthdr.csum_flags & CSUM_TSO) { 815ce110ea1SWei Hu m = mana_tso_fixup(m); 816ce110ea1SWei Hu if (unlikely(m == NULL)) { 817ce110ea1SWei Hu counter_enter(); 818ce110ea1SWei Hu counter_u64_add_protected(apc->port_stats.tx_drops, 1); 819ce110ea1SWei Hu counter_exit(); 820ce110ea1SWei Hu return EIO; 821ce110ea1SWei Hu } 822ce110ea1SWei Hu } else { 823ce110ea1SWei Hu m = mana_mbuf_csum_check(m); 824ce110ea1SWei Hu if (unlikely(m == NULL)) { 825ce110ea1SWei Hu counter_enter(); 826ce110ea1SWei Hu counter_u64_add_protected(apc->port_stats.tx_drops, 1); 827ce110ea1SWei Hu counter_exit(); 828ce110ea1SWei Hu return EIO; 829ce110ea1SWei Hu } 830ce110ea1SWei Hu } 831ce110ea1SWei Hu 832ce110ea1SWei Hu if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 833ce110ea1SWei Hu uint32_t hash = m->m_pkthdr.flowid; 834ce110ea1SWei Hu txq_id = apc->indir_table[(hash) & MANA_INDIRECT_TABLE_MASK] % 835ce110ea1SWei Hu apc->num_queues; 836ce110ea1SWei Hu } else { 837ce110ea1SWei Hu txq_id = m->m_pkthdr.flowid % apc->num_queues; 838ce110ea1SWei Hu } 839ce110ea1SWei Hu 840ce110ea1SWei Hu if (apc->enable_tx_altq) 841ce110ea1SWei Hu txq_id = apc->tx_qp[txq_id].txq.alt_txq_idx; 842ce110ea1SWei Hu 843ce110ea1SWei Hu txq = &apc->tx_qp[txq_id].txq; 844ce110ea1SWei Hu 845ce110ea1SWei Hu is_drbr_empty = drbr_empty(ifp, txq->txq_br); 846ce110ea1SWei Hu err = drbr_enqueue(ifp, txq->txq_br, m); 847ce110ea1SWei Hu if (unlikely(err)) { 848ce110ea1SWei Hu mana_warn(NULL, "txq %u failed to enqueue: %d\n", 849ce110ea1SWei Hu txq_id, err); 850ce110ea1SWei Hu taskqueue_enqueue(txq->enqueue_tq, &txq->enqueue_task); 851ce110ea1SWei Hu return err; 852ce110ea1SWei Hu } 853ce110ea1SWei Hu 854ce110ea1SWei Hu if (is_drbr_empty && mtx_trylock(&txq->txq_mtx)) { 855ce110ea1SWei Hu mana_xmit(txq); 856ce110ea1SWei Hu mtx_unlock(&txq->txq_mtx); 857ce110ea1SWei Hu } else { 858ce110ea1SWei Hu taskqueue_enqueue(txq->enqueue_tq, &txq->enqueue_task); 859ce110ea1SWei Hu } 860ce110ea1SWei Hu 861ce110ea1SWei Hu return 0; 862ce110ea1SWei Hu } 863ce110ea1SWei Hu 864ce110ea1SWei Hu static void 865ce110ea1SWei Hu mana_cleanup_port_context(struct mana_port_context *apc) 866ce110ea1SWei Hu { 867ce110ea1SWei Hu bus_dma_tag_destroy(apc->tx_buf_tag); 868ce110ea1SWei Hu bus_dma_tag_destroy(apc->rx_buf_tag); 869ce110ea1SWei Hu apc->rx_buf_tag = NULL; 870ce110ea1SWei Hu 871ce110ea1SWei Hu free(apc->rxqs, M_DEVBUF); 872ce110ea1SWei Hu apc->rxqs = NULL; 873ce110ea1SWei Hu 874ce110ea1SWei Hu mana_free_counters((counter_u64_t *)&apc->port_stats, 875ce110ea1SWei Hu sizeof(struct mana_port_stats)); 876ce110ea1SWei Hu } 877ce110ea1SWei Hu 878ce110ea1SWei Hu static int 879ce110ea1SWei Hu mana_init_port_context(struct mana_port_context *apc) 880ce110ea1SWei Hu { 881ce110ea1SWei Hu device_t dev = apc->ac->gdma_dev->gdma_context->dev; 882ce110ea1SWei Hu uint32_t tso_maxsize; 883ce110ea1SWei Hu int err; 884ce110ea1SWei Hu 885643fd7b4SWei Hu tso_maxsize = MANA_TSO_MAX_SZ; 886ce110ea1SWei Hu 887ce110ea1SWei Hu /* Create DMA tag for tx bufs */ 888ce110ea1SWei Hu err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 889ce110ea1SWei Hu 1, 0, /* alignment, boundary */ 890ce110ea1SWei Hu BUS_SPACE_MAXADDR, /* lowaddr */ 891ce110ea1SWei Hu BUS_SPACE_MAXADDR, /* highaddr */ 892ce110ea1SWei Hu NULL, NULL, /* filter, filterarg */ 893ce110ea1SWei Hu tso_maxsize, /* maxsize */ 894ce110ea1SWei Hu MAX_MBUF_FRAGS, /* nsegments */ 895ce110ea1SWei Hu tso_maxsize, /* maxsegsize */ 896ce110ea1SWei Hu 0, /* flags */ 897ce110ea1SWei Hu NULL, NULL, /* lockfunc, lockfuncarg*/ 898ce110ea1SWei Hu &apc->tx_buf_tag); 899ce110ea1SWei Hu if (unlikely(err)) { 900ce110ea1SWei Hu device_printf(dev, "Feiled to create TX DMA tag\n"); 901ce110ea1SWei Hu return err; 902ce110ea1SWei Hu } 903ce110ea1SWei Hu 904ce110ea1SWei Hu /* Create DMA tag for rx bufs */ 905ce110ea1SWei Hu err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 906ce110ea1SWei Hu 64, 0, /* alignment, boundary */ 907ce110ea1SWei Hu BUS_SPACE_MAXADDR, /* lowaddr */ 908ce110ea1SWei Hu BUS_SPACE_MAXADDR, /* highaddr */ 909ce110ea1SWei Hu NULL, NULL, /* filter, filterarg */ 910ce110ea1SWei Hu MJUMPAGESIZE, /* maxsize */ 911ce110ea1SWei Hu 1, /* nsegments */ 912ce110ea1SWei Hu MJUMPAGESIZE, /* maxsegsize */ 913ce110ea1SWei Hu 0, /* flags */ 914ce110ea1SWei Hu NULL, NULL, /* lockfunc, lockfuncarg*/ 915ce110ea1SWei Hu &apc->rx_buf_tag); 916ce110ea1SWei Hu if (unlikely(err)) { 917ce110ea1SWei Hu device_printf(dev, "Feiled to create RX DMA tag\n"); 918ce110ea1SWei Hu return err; 919ce110ea1SWei Hu } 920ce110ea1SWei Hu 921ce110ea1SWei Hu apc->rxqs = mallocarray(apc->num_queues, sizeof(struct mana_rxq *), 922ce110ea1SWei Hu M_DEVBUF, M_WAITOK | M_ZERO); 923ce110ea1SWei Hu 924ce110ea1SWei Hu return 0; 925ce110ea1SWei Hu } 926ce110ea1SWei Hu 927ce110ea1SWei Hu static int 928ce110ea1SWei Hu mana_send_request(struct mana_context *ac, void *in_buf, 929ce110ea1SWei Hu uint32_t in_len, void *out_buf, uint32_t out_len) 930ce110ea1SWei Hu { 931ce110ea1SWei Hu struct gdma_context *gc = ac->gdma_dev->gdma_context; 932ce110ea1SWei Hu struct gdma_resp_hdr *resp = out_buf; 933ce110ea1SWei Hu struct gdma_req_hdr *req = in_buf; 934ce110ea1SWei Hu device_t dev = gc->dev; 935ce110ea1SWei Hu static atomic_t activity_id; 936ce110ea1SWei Hu int err; 937ce110ea1SWei Hu 938ce110ea1SWei Hu req->dev_id = gc->mana.dev_id; 939ce110ea1SWei Hu req->activity_id = atomic_inc_return(&activity_id); 940ce110ea1SWei Hu 941ce110ea1SWei Hu mana_dbg(NULL, "activity_id = %u\n", activity_id); 942ce110ea1SWei Hu 943ce110ea1SWei Hu err = mana_gd_send_request(gc, in_len, in_buf, out_len, 944ce110ea1SWei Hu out_buf); 945ce110ea1SWei Hu if (err || resp->status) { 946ce110ea1SWei Hu device_printf(dev, "Failed to send mana message: %d, 0x%x\n", 947ce110ea1SWei Hu err, resp->status); 948ce110ea1SWei Hu return err ? err : EPROTO; 949ce110ea1SWei Hu } 950ce110ea1SWei Hu 951ce110ea1SWei Hu if (req->dev_id.as_uint32 != resp->dev_id.as_uint32 || 952ce110ea1SWei Hu req->activity_id != resp->activity_id) { 953ce110ea1SWei Hu device_printf(dev, 954ce110ea1SWei Hu "Unexpected mana message response: %x,%x,%x,%x\n", 955ce110ea1SWei Hu req->dev_id.as_uint32, resp->dev_id.as_uint32, 956ce110ea1SWei Hu req->activity_id, resp->activity_id); 957ce110ea1SWei Hu return EPROTO; 958ce110ea1SWei Hu } 959ce110ea1SWei Hu 960ce110ea1SWei Hu return 0; 961ce110ea1SWei Hu } 962ce110ea1SWei Hu 963ce110ea1SWei Hu static int 964ce110ea1SWei Hu mana_verify_resp_hdr(const struct gdma_resp_hdr *resp_hdr, 965ce110ea1SWei Hu const enum mana_command_code expected_code, 966ce110ea1SWei Hu const uint32_t min_size) 967ce110ea1SWei Hu { 968ce110ea1SWei Hu if (resp_hdr->response.msg_type != expected_code) 969ce110ea1SWei Hu return EPROTO; 970ce110ea1SWei Hu 971ce110ea1SWei Hu if (resp_hdr->response.msg_version < GDMA_MESSAGE_V1) 972ce110ea1SWei Hu return EPROTO; 973ce110ea1SWei Hu 974ce110ea1SWei Hu if (resp_hdr->response.msg_size < min_size) 975ce110ea1SWei Hu return EPROTO; 976ce110ea1SWei Hu 977ce110ea1SWei Hu return 0; 978ce110ea1SWei Hu } 979ce110ea1SWei Hu 980ce110ea1SWei Hu static int 981ce110ea1SWei Hu mana_query_device_cfg(struct mana_context *ac, uint32_t proto_major_ver, 982ce110ea1SWei Hu uint32_t proto_minor_ver, uint32_t proto_micro_ver, 983ce110ea1SWei Hu uint16_t *max_num_vports) 984ce110ea1SWei Hu { 985ce110ea1SWei Hu struct gdma_context *gc = ac->gdma_dev->gdma_context; 986ce110ea1SWei Hu struct mana_query_device_cfg_resp resp = {}; 987ce110ea1SWei Hu struct mana_query_device_cfg_req req = {}; 988ce110ea1SWei Hu device_t dev = gc->dev; 989ce110ea1SWei Hu int err = 0; 990ce110ea1SWei Hu 991ce110ea1SWei Hu mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_DEV_CONFIG, 992ce110ea1SWei Hu sizeof(req), sizeof(resp)); 993ce110ea1SWei Hu req.proto_major_ver = proto_major_ver; 994ce110ea1SWei Hu req.proto_minor_ver = proto_minor_ver; 995ce110ea1SWei Hu req.proto_micro_ver = proto_micro_ver; 996ce110ea1SWei Hu 997ce110ea1SWei Hu err = mana_send_request(ac, &req, sizeof(req), &resp, sizeof(resp)); 998ce110ea1SWei Hu if (err) { 999ce110ea1SWei Hu device_printf(dev, "Failed to query config: %d", err); 1000ce110ea1SWei Hu return err; 1001ce110ea1SWei Hu } 1002ce110ea1SWei Hu 1003ce110ea1SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_DEV_CONFIG, 1004ce110ea1SWei Hu sizeof(resp)); 1005ce110ea1SWei Hu if (err || resp.hdr.status) { 1006ce110ea1SWei Hu device_printf(dev, "Invalid query result: %d, 0x%x\n", err, 1007ce110ea1SWei Hu resp.hdr.status); 1008ce110ea1SWei Hu if (!err) 1009ce110ea1SWei Hu err = EPROTO; 1010ce110ea1SWei Hu return err; 1011ce110ea1SWei Hu } 1012ce110ea1SWei Hu 1013ce110ea1SWei Hu *max_num_vports = resp.max_num_vports; 1014ce110ea1SWei Hu 1015ce110ea1SWei Hu mana_dbg(NULL, "mana max_num_vports from device = %d\n", 1016ce110ea1SWei Hu *max_num_vports); 1017ce110ea1SWei Hu 1018ce110ea1SWei Hu return 0; 1019ce110ea1SWei Hu } 1020ce110ea1SWei Hu 1021ce110ea1SWei Hu static int 1022ce110ea1SWei Hu mana_query_vport_cfg(struct mana_port_context *apc, uint32_t vport_index, 1023ce110ea1SWei Hu uint32_t *max_sq, uint32_t *max_rq, uint32_t *num_indir_entry) 1024ce110ea1SWei Hu { 1025ce110ea1SWei Hu struct mana_query_vport_cfg_resp resp = {}; 1026ce110ea1SWei Hu struct mana_query_vport_cfg_req req = {}; 1027ce110ea1SWei Hu int err; 1028ce110ea1SWei Hu 1029ce110ea1SWei Hu mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_VPORT_CONFIG, 1030ce110ea1SWei Hu sizeof(req), sizeof(resp)); 1031ce110ea1SWei Hu 1032ce110ea1SWei Hu req.vport_index = vport_index; 1033ce110ea1SWei Hu 1034ce110ea1SWei Hu err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 1035ce110ea1SWei Hu sizeof(resp)); 1036ce110ea1SWei Hu if (err) 1037ce110ea1SWei Hu return err; 1038ce110ea1SWei Hu 1039ce110ea1SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_VPORT_CONFIG, 1040ce110ea1SWei Hu sizeof(resp)); 1041ce110ea1SWei Hu if (err) 1042ce110ea1SWei Hu return err; 1043ce110ea1SWei Hu 1044ce110ea1SWei Hu if (resp.hdr.status) 1045ce110ea1SWei Hu return EPROTO; 1046ce110ea1SWei Hu 1047ce110ea1SWei Hu *max_sq = resp.max_num_sq; 1048ce110ea1SWei Hu *max_rq = resp.max_num_rq; 1049ce110ea1SWei Hu *num_indir_entry = resp.num_indirection_ent; 1050ce110ea1SWei Hu 1051ce110ea1SWei Hu apc->port_handle = resp.vport; 1052ce110ea1SWei Hu memcpy(apc->mac_addr, resp.mac_addr, ETHER_ADDR_LEN); 1053ce110ea1SWei Hu 1054ce110ea1SWei Hu return 0; 1055ce110ea1SWei Hu } 1056ce110ea1SWei Hu 1057b685df31SWei Hu void 1058b685df31SWei Hu mana_uncfg_vport(struct mana_port_context *apc) 1059b685df31SWei Hu { 1060b685df31SWei Hu apc->vport_use_count--; 1061b685df31SWei Hu if (apc->vport_use_count < 0) { 1062b685df31SWei Hu mana_err(NULL, 1063b685df31SWei Hu "WARNING: vport_use_count less than 0: %u\n", 1064b685df31SWei Hu apc->vport_use_count); 1065b685df31SWei Hu } 1066b685df31SWei Hu } 1067b685df31SWei Hu 1068b685df31SWei Hu int 1069ce110ea1SWei Hu mana_cfg_vport(struct mana_port_context *apc, uint32_t protection_dom_id, 1070ce110ea1SWei Hu uint32_t doorbell_pg_id) 1071ce110ea1SWei Hu { 1072ce110ea1SWei Hu struct mana_config_vport_resp resp = {}; 1073ce110ea1SWei Hu struct mana_config_vport_req req = {}; 1074ce110ea1SWei Hu int err; 1075ce110ea1SWei Hu 1076b685df31SWei Hu /* This function is used to program the Ethernet port in the hardware 1077b685df31SWei Hu * table. It can be called from the Ethernet driver or the RDMA driver. 1078b685df31SWei Hu * 1079b685df31SWei Hu * For Ethernet usage, the hardware supports only one active user on a 1080b685df31SWei Hu * physical port. The driver checks on the port usage before programming 1081b685df31SWei Hu * the hardware when creating the RAW QP (RDMA driver) or exposing the 1082b685df31SWei Hu * device to kernel NET layer (Ethernet driver). 1083b685df31SWei Hu * 1084b685df31SWei Hu * Because the RDMA driver doesn't know in advance which QP type the 1085b685df31SWei Hu * user will create, it exposes the device with all its ports. The user 1086b685df31SWei Hu * may not be able to create RAW QP on a port if this port is already 1087b685df31SWei Hu * in used by the Ethernet driver from the kernel. 1088b685df31SWei Hu * 1089b685df31SWei Hu * This physical port limitation only applies to the RAW QP. For RC QP, 1090b685df31SWei Hu * the hardware doesn't have this limitation. The user can create RC 1091b685df31SWei Hu * QPs on a physical port up to the hardware limits independent of the 1092b685df31SWei Hu * Ethernet usage on the same port. 1093b685df31SWei Hu */ 1094b685df31SWei Hu if (apc->vport_use_count > 0) { 1095b685df31SWei Hu return EBUSY; 1096b685df31SWei Hu } 1097b685df31SWei Hu apc->vport_use_count++; 1098b685df31SWei Hu 1099ce110ea1SWei Hu mana_gd_init_req_hdr(&req.hdr, MANA_CONFIG_VPORT_TX, 1100ce110ea1SWei Hu sizeof(req), sizeof(resp)); 1101ce110ea1SWei Hu req.vport = apc->port_handle; 1102ce110ea1SWei Hu req.pdid = protection_dom_id; 1103ce110ea1SWei Hu req.doorbell_pageid = doorbell_pg_id; 1104ce110ea1SWei Hu 1105ce110ea1SWei Hu err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 1106ce110ea1SWei Hu sizeof(resp)); 1107ce110ea1SWei Hu if (err) { 1108ce110ea1SWei Hu if_printf(apc->ndev, "Failed to configure vPort: %d\n", err); 1109ce110ea1SWei Hu goto out; 1110ce110ea1SWei Hu } 1111ce110ea1SWei Hu 1112ce110ea1SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_CONFIG_VPORT_TX, 1113ce110ea1SWei Hu sizeof(resp)); 1114ce110ea1SWei Hu if (err || resp.hdr.status) { 1115ce110ea1SWei Hu if_printf(apc->ndev, "Failed to configure vPort: %d, 0x%x\n", 1116ce110ea1SWei Hu err, resp.hdr.status); 1117ce110ea1SWei Hu if (!err) 1118ce110ea1SWei Hu err = EPROTO; 1119ce110ea1SWei Hu 1120ce110ea1SWei Hu goto out; 1121ce110ea1SWei Hu } 1122ce110ea1SWei Hu 1123ce110ea1SWei Hu apc->tx_shortform_allowed = resp.short_form_allowed; 1124ce110ea1SWei Hu apc->tx_vp_offset = resp.tx_vport_offset; 1125b685df31SWei Hu 1126d0b5e4a3SLi-Wen Hsu if_printf(apc->ndev, "Configured vPort %ju PD %u DB %u\n", 1127b685df31SWei Hu apc->port_handle, protection_dom_id, doorbell_pg_id); 11289e772f20SWei Hu 1129ce110ea1SWei Hu out: 1130b685df31SWei Hu if (err) 1131b685df31SWei Hu mana_uncfg_vport(apc); 1132b685df31SWei Hu 1133ce110ea1SWei Hu return err; 1134ce110ea1SWei Hu } 1135ce110ea1SWei Hu 1136ce110ea1SWei Hu static int 1137ce110ea1SWei Hu mana_cfg_vport_steering(struct mana_port_context *apc, 1138ce110ea1SWei Hu enum TRI_STATE rx, 1139ce110ea1SWei Hu bool update_default_rxobj, bool update_key, 1140ce110ea1SWei Hu bool update_tab) 1141ce110ea1SWei Hu { 1142ce110ea1SWei Hu uint16_t num_entries = MANA_INDIRECT_TABLE_SIZE; 1143ce110ea1SWei Hu struct mana_cfg_rx_steer_req *req = NULL; 1144ce110ea1SWei Hu struct mana_cfg_rx_steer_resp resp = {}; 114537d22ce0SJustin Hibbits if_t ndev = apc->ndev; 1146ce110ea1SWei Hu mana_handle_t *req_indir_tab; 1147ce110ea1SWei Hu uint32_t req_buf_size; 1148ce110ea1SWei Hu int err; 1149ce110ea1SWei Hu 1150ce110ea1SWei Hu req_buf_size = sizeof(*req) + sizeof(mana_handle_t) * num_entries; 1151ce110ea1SWei Hu req = malloc(req_buf_size, M_DEVBUF, M_WAITOK | M_ZERO); 1152ce110ea1SWei Hu 1153ce110ea1SWei Hu mana_gd_init_req_hdr(&req->hdr, MANA_CONFIG_VPORT_RX, req_buf_size, 1154ce110ea1SWei Hu sizeof(resp)); 1155ce110ea1SWei Hu 1156ce110ea1SWei Hu req->vport = apc->port_handle; 1157ce110ea1SWei Hu req->num_indir_entries = num_entries; 1158ce110ea1SWei Hu req->indir_tab_offset = sizeof(*req); 1159ce110ea1SWei Hu req->rx_enable = rx; 1160ce110ea1SWei Hu req->rss_enable = apc->rss_state; 1161ce110ea1SWei Hu req->update_default_rxobj = update_default_rxobj; 1162ce110ea1SWei Hu req->update_hashkey = update_key; 1163ce110ea1SWei Hu req->update_indir_tab = update_tab; 1164ce110ea1SWei Hu req->default_rxobj = apc->default_rxobj; 1165ce110ea1SWei Hu 1166ce110ea1SWei Hu if (update_key) 1167ce110ea1SWei Hu memcpy(&req->hashkey, apc->hashkey, MANA_HASH_KEY_SIZE); 1168ce110ea1SWei Hu 1169ce110ea1SWei Hu if (update_tab) { 1170ce110ea1SWei Hu req_indir_tab = (mana_handle_t *)(req + 1); 1171ce110ea1SWei Hu memcpy(req_indir_tab, apc->rxobj_table, 1172ce110ea1SWei Hu req->num_indir_entries * sizeof(mana_handle_t)); 1173ce110ea1SWei Hu } 1174ce110ea1SWei Hu 1175ce110ea1SWei Hu err = mana_send_request(apc->ac, req, req_buf_size, &resp, 1176ce110ea1SWei Hu sizeof(resp)); 1177ce110ea1SWei Hu if (err) { 1178ce110ea1SWei Hu if_printf(ndev, "Failed to configure vPort RX: %d\n", err); 1179ce110ea1SWei Hu goto out; 1180ce110ea1SWei Hu } 1181ce110ea1SWei Hu 1182ce110ea1SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_CONFIG_VPORT_RX, 1183ce110ea1SWei Hu sizeof(resp)); 1184ce110ea1SWei Hu if (err) { 1185ce110ea1SWei Hu if_printf(ndev, "vPort RX configuration failed: %d\n", err); 1186ce110ea1SWei Hu goto out; 1187ce110ea1SWei Hu } 1188ce110ea1SWei Hu 1189ce110ea1SWei Hu if (resp.hdr.status) { 1190ce110ea1SWei Hu if_printf(ndev, "vPort RX configuration failed: 0x%x\n", 1191ce110ea1SWei Hu resp.hdr.status); 1192ce110ea1SWei Hu err = EPROTO; 1193ce110ea1SWei Hu } 1194b685df31SWei Hu 1195d0b5e4a3SLi-Wen Hsu if_printf(ndev, "Configured steering vPort %ju entries %u\n", 1196b685df31SWei Hu apc->port_handle, num_entries); 11979e772f20SWei Hu 1198ce110ea1SWei Hu out: 1199ce110ea1SWei Hu free(req, M_DEVBUF); 1200ce110ea1SWei Hu return err; 1201ce110ea1SWei Hu } 1202ce110ea1SWei Hu 1203b685df31SWei Hu int 1204ce110ea1SWei Hu mana_create_wq_obj(struct mana_port_context *apc, 1205ce110ea1SWei Hu mana_handle_t vport, 1206ce110ea1SWei Hu uint32_t wq_type, struct mana_obj_spec *wq_spec, 1207ce110ea1SWei Hu struct mana_obj_spec *cq_spec, 1208ce110ea1SWei Hu mana_handle_t *wq_obj) 1209ce110ea1SWei Hu { 1210ce110ea1SWei Hu struct mana_create_wqobj_resp resp = {}; 1211ce110ea1SWei Hu struct mana_create_wqobj_req req = {}; 121237d22ce0SJustin Hibbits if_t ndev = apc->ndev; 1213ce110ea1SWei Hu int err; 1214ce110ea1SWei Hu 1215ce110ea1SWei Hu mana_gd_init_req_hdr(&req.hdr, MANA_CREATE_WQ_OBJ, 1216ce110ea1SWei Hu sizeof(req), sizeof(resp)); 1217ce110ea1SWei Hu req.vport = vport; 1218ce110ea1SWei Hu req.wq_type = wq_type; 1219ce110ea1SWei Hu req.wq_gdma_region = wq_spec->gdma_region; 1220ce110ea1SWei Hu req.cq_gdma_region = cq_spec->gdma_region; 1221ce110ea1SWei Hu req.wq_size = wq_spec->queue_size; 1222ce110ea1SWei Hu req.cq_size = cq_spec->queue_size; 1223ce110ea1SWei Hu req.cq_moderation_ctx_id = cq_spec->modr_ctx_id; 1224ce110ea1SWei Hu req.cq_parent_qid = cq_spec->attached_eq; 1225ce110ea1SWei Hu 1226ce110ea1SWei Hu err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 1227ce110ea1SWei Hu sizeof(resp)); 1228ce110ea1SWei Hu if (err) { 1229ce110ea1SWei Hu if_printf(ndev, "Failed to create WQ object: %d\n", err); 1230ce110ea1SWei Hu goto out; 1231ce110ea1SWei Hu } 1232ce110ea1SWei Hu 1233ce110ea1SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_CREATE_WQ_OBJ, 1234ce110ea1SWei Hu sizeof(resp)); 1235ce110ea1SWei Hu if (err || resp.hdr.status) { 1236ce110ea1SWei Hu if_printf(ndev, "Failed to create WQ object: %d, 0x%x\n", err, 1237ce110ea1SWei Hu resp.hdr.status); 1238ce110ea1SWei Hu if (!err) 1239ce110ea1SWei Hu err = EPROTO; 1240ce110ea1SWei Hu goto out; 1241ce110ea1SWei Hu } 1242ce110ea1SWei Hu 1243ce110ea1SWei Hu if (resp.wq_obj == INVALID_MANA_HANDLE) { 1244ce110ea1SWei Hu if_printf(ndev, "Got an invalid WQ object handle\n"); 1245ce110ea1SWei Hu err = EPROTO; 1246ce110ea1SWei Hu goto out; 1247ce110ea1SWei Hu } 1248ce110ea1SWei Hu 1249ce110ea1SWei Hu *wq_obj = resp.wq_obj; 1250ce110ea1SWei Hu wq_spec->queue_index = resp.wq_id; 1251ce110ea1SWei Hu cq_spec->queue_index = resp.cq_id; 1252ce110ea1SWei Hu 1253ce110ea1SWei Hu return 0; 1254ce110ea1SWei Hu out: 1255ce110ea1SWei Hu return err; 1256ce110ea1SWei Hu } 1257ce110ea1SWei Hu 1258b685df31SWei Hu void 1259ce110ea1SWei Hu mana_destroy_wq_obj(struct mana_port_context *apc, uint32_t wq_type, 1260ce110ea1SWei Hu mana_handle_t wq_obj) 1261ce110ea1SWei Hu { 1262ce110ea1SWei Hu struct mana_destroy_wqobj_resp resp = {}; 1263ce110ea1SWei Hu struct mana_destroy_wqobj_req req = {}; 126437d22ce0SJustin Hibbits if_t ndev = apc->ndev; 1265ce110ea1SWei Hu int err; 1266ce110ea1SWei Hu 1267ce110ea1SWei Hu mana_gd_init_req_hdr(&req.hdr, MANA_DESTROY_WQ_OBJ, 1268ce110ea1SWei Hu sizeof(req), sizeof(resp)); 1269ce110ea1SWei Hu req.wq_type = wq_type; 1270ce110ea1SWei Hu req.wq_obj_handle = wq_obj; 1271ce110ea1SWei Hu 1272ce110ea1SWei Hu err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 1273ce110ea1SWei Hu sizeof(resp)); 1274ce110ea1SWei Hu if (err) { 1275ce110ea1SWei Hu if_printf(ndev, "Failed to destroy WQ object: %d\n", err); 1276ce110ea1SWei Hu return; 1277ce110ea1SWei Hu } 1278ce110ea1SWei Hu 1279ce110ea1SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_DESTROY_WQ_OBJ, 1280ce110ea1SWei Hu sizeof(resp)); 1281ce110ea1SWei Hu if (err || resp.hdr.status) 1282ce110ea1SWei Hu if_printf(ndev, "Failed to destroy WQ object: %d, 0x%x\n", 1283ce110ea1SWei Hu err, resp.hdr.status); 1284ce110ea1SWei Hu } 1285ce110ea1SWei Hu 1286ce110ea1SWei Hu static void 12871833cf13SWei Hu mana_destroy_eq(struct mana_context *ac) 1288ce110ea1SWei Hu { 12891833cf13SWei Hu struct gdma_context *gc = ac->gdma_dev->gdma_context; 1290ce110ea1SWei Hu struct gdma_queue *eq; 1291ce110ea1SWei Hu int i; 1292ce110ea1SWei Hu 12931833cf13SWei Hu if (!ac->eqs) 1294ce110ea1SWei Hu return; 1295ce110ea1SWei Hu 12961833cf13SWei Hu for (i = 0; i < gc->max_num_queues; i++) { 12971833cf13SWei Hu eq = ac->eqs[i].eq; 1298ce110ea1SWei Hu if (!eq) 1299ce110ea1SWei Hu continue; 1300ce110ea1SWei Hu 1301ce110ea1SWei Hu mana_gd_destroy_queue(gc, eq); 1302ce110ea1SWei Hu } 1303ce110ea1SWei Hu 13041833cf13SWei Hu free(ac->eqs, M_DEVBUF); 13051833cf13SWei Hu ac->eqs = NULL; 1306ce110ea1SWei Hu } 1307ce110ea1SWei Hu 1308ce110ea1SWei Hu static int 13091833cf13SWei Hu mana_create_eq(struct mana_context *ac) 1310ce110ea1SWei Hu { 13111833cf13SWei Hu struct gdma_dev *gd = ac->gdma_dev; 13121833cf13SWei Hu struct gdma_context *gc = gd->gdma_context; 1313ce110ea1SWei Hu struct gdma_queue_spec spec = {}; 1314ce110ea1SWei Hu int err; 1315ce110ea1SWei Hu int i; 1316ce110ea1SWei Hu 13171833cf13SWei Hu ac->eqs = mallocarray(gc->max_num_queues, sizeof(struct mana_eq), 1318ce110ea1SWei Hu M_DEVBUF, M_WAITOK | M_ZERO); 1319ce110ea1SWei Hu 1320ce110ea1SWei Hu spec.type = GDMA_EQ; 1321ce110ea1SWei Hu spec.monitor_avl_buf = false; 1322ce110ea1SWei Hu spec.queue_size = EQ_SIZE; 1323ce110ea1SWei Hu spec.eq.callback = NULL; 13241833cf13SWei Hu spec.eq.context = ac->eqs; 1325ce110ea1SWei Hu spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE; 1326ce110ea1SWei Hu 13271833cf13SWei Hu for (i = 0; i < gc->max_num_queues; i++) { 13281833cf13SWei Hu err = mana_gd_create_mana_eq(gd, &spec, &ac->eqs[i].eq); 1329ce110ea1SWei Hu if (err) 1330ce110ea1SWei Hu goto out; 1331ce110ea1SWei Hu } 1332ce110ea1SWei Hu 1333ce110ea1SWei Hu return 0; 1334ce110ea1SWei Hu out: 13351833cf13SWei Hu mana_destroy_eq(ac); 1336ce110ea1SWei Hu return err; 1337ce110ea1SWei Hu } 1338ce110ea1SWei Hu 1339ce110ea1SWei Hu static int 1340aa108bc7SWei Hu mana_fence_rq(struct mana_port_context *apc, struct mana_rxq *rxq) 1341aa108bc7SWei Hu { 1342aa108bc7SWei Hu struct mana_fence_rq_resp resp = {}; 1343aa108bc7SWei Hu struct mana_fence_rq_req req = {}; 1344aa108bc7SWei Hu int err; 1345aa108bc7SWei Hu 1346aa108bc7SWei Hu init_completion(&rxq->fence_event); 1347aa108bc7SWei Hu 1348aa108bc7SWei Hu mana_gd_init_req_hdr(&req.hdr, MANA_FENCE_RQ, 1349aa108bc7SWei Hu sizeof(req), sizeof(resp)); 1350aa108bc7SWei Hu req.wq_obj_handle = rxq->rxobj; 1351aa108bc7SWei Hu 1352aa108bc7SWei Hu err = mana_send_request(apc->ac, &req, sizeof(req), &resp, 1353aa108bc7SWei Hu sizeof(resp)); 1354aa108bc7SWei Hu if (err) { 1355aa108bc7SWei Hu if_printf(apc->ndev, "Failed to fence RQ %u: %d\n", 1356aa108bc7SWei Hu rxq->rxq_idx, err); 1357aa108bc7SWei Hu return err; 1358aa108bc7SWei Hu } 1359aa108bc7SWei Hu 1360aa108bc7SWei Hu err = mana_verify_resp_hdr(&resp.hdr, MANA_FENCE_RQ, sizeof(resp)); 1361aa108bc7SWei Hu if (err || resp.hdr.status) { 1362aa108bc7SWei Hu if_printf(apc->ndev, "Failed to fence RQ %u: %d, 0x%x\n", 1363aa108bc7SWei Hu rxq->rxq_idx, err, resp.hdr.status); 1364aa108bc7SWei Hu if (!err) 1365aa108bc7SWei Hu err = EPROTO; 1366aa108bc7SWei Hu 1367aa108bc7SWei Hu return err; 1368aa108bc7SWei Hu } 1369aa108bc7SWei Hu 1370aa108bc7SWei Hu if (wait_for_completion_timeout(&rxq->fence_event, 10 * hz)) { 1371aa108bc7SWei Hu if_printf(apc->ndev, "Failed to fence RQ %u: timed out\n", 1372aa108bc7SWei Hu rxq->rxq_idx); 1373aa108bc7SWei Hu return ETIMEDOUT; 1374aa108bc7SWei Hu } 1375aa108bc7SWei Hu 1376aa108bc7SWei Hu return 0; 1377aa108bc7SWei Hu } 1378aa108bc7SWei Hu 1379aa108bc7SWei Hu static void 1380aa108bc7SWei Hu mana_fence_rqs(struct mana_port_context *apc) 1381aa108bc7SWei Hu { 1382aa108bc7SWei Hu unsigned int rxq_idx; 1383aa108bc7SWei Hu struct mana_rxq *rxq; 1384aa108bc7SWei Hu int err; 1385aa108bc7SWei Hu 1386aa108bc7SWei Hu for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { 1387aa108bc7SWei Hu rxq = apc->rxqs[rxq_idx]; 1388aa108bc7SWei Hu err = mana_fence_rq(apc, rxq); 1389aa108bc7SWei Hu 1390aa108bc7SWei Hu /* In case of any error, use sleep instead. */ 1391aa108bc7SWei Hu if (err) 1392aa108bc7SWei Hu gdma_msleep(100); 1393aa108bc7SWei Hu } 1394aa108bc7SWei Hu } 1395aa108bc7SWei Hu 1396aa108bc7SWei Hu static int 1397ce110ea1SWei Hu mana_move_wq_tail(struct gdma_queue *wq, uint32_t num_units) 1398ce110ea1SWei Hu { 1399ce110ea1SWei Hu uint32_t used_space_old; 1400ce110ea1SWei Hu uint32_t used_space_new; 1401ce110ea1SWei Hu 1402ce110ea1SWei Hu used_space_old = wq->head - wq->tail; 1403ce110ea1SWei Hu used_space_new = wq->head - (wq->tail + num_units); 1404ce110ea1SWei Hu 1405ce110ea1SWei Hu if (used_space_new > used_space_old) { 1406ce110ea1SWei Hu mana_err(NULL, 1407ce110ea1SWei Hu "WARNING: new used space %u greater than old one %u\n", 1408ce110ea1SWei Hu used_space_new, used_space_old); 1409ce110ea1SWei Hu return ERANGE; 1410ce110ea1SWei Hu } 1411ce110ea1SWei Hu 1412ce110ea1SWei Hu wq->tail += num_units; 1413ce110ea1SWei Hu return 0; 1414ce110ea1SWei Hu } 1415ce110ea1SWei Hu 1416ce110ea1SWei Hu static void 1417ce110ea1SWei Hu mana_poll_tx_cq(struct mana_cq *cq) 1418ce110ea1SWei Hu { 1419ce110ea1SWei Hu struct gdma_comp *completions = cq->gdma_comp_buf; 1420ce110ea1SWei Hu struct gdma_posted_wqe_info *wqe_info; 1421ce110ea1SWei Hu struct mana_send_buf_info *tx_info; 1422ce110ea1SWei Hu unsigned int pkt_transmitted = 0; 1423ce110ea1SWei Hu unsigned int wqe_unit_cnt = 0; 1424ce110ea1SWei Hu struct mana_txq *txq = cq->txq; 1425ce110ea1SWei Hu struct mana_port_context *apc; 1426ce110ea1SWei Hu uint16_t next_to_complete; 142737d22ce0SJustin Hibbits if_t ndev; 1428ce110ea1SWei Hu int comp_read; 1429*6ccf4f40SZhenlei Huang int txq_idx = txq->idx; 1430ce110ea1SWei Hu int i; 1431ce110ea1SWei Hu int sa_drop = 0; 1432ce110ea1SWei Hu 1433ce110ea1SWei Hu struct gdma_queue *gdma_wq; 1434ce110ea1SWei Hu unsigned int avail_space; 1435ce110ea1SWei Hu bool txq_full = false; 1436ce110ea1SWei Hu 1437ce110ea1SWei Hu ndev = txq->ndev; 1438ce110ea1SWei Hu apc = if_getsoftc(ndev); 1439ce110ea1SWei Hu 1440ce110ea1SWei Hu comp_read = mana_gd_poll_cq(cq->gdma_cq, completions, 1441ce110ea1SWei Hu CQE_POLLING_BUFFER); 1442ce110ea1SWei Hu 14431833cf13SWei Hu if (comp_read < 1) 14441833cf13SWei Hu return; 14451833cf13SWei Hu 1446ce110ea1SWei Hu next_to_complete = txq->next_to_complete; 1447ce110ea1SWei Hu 1448ce110ea1SWei Hu for (i = 0; i < comp_read; i++) { 1449ce110ea1SWei Hu struct mana_tx_comp_oob *cqe_oob; 1450ce110ea1SWei Hu 1451ce110ea1SWei Hu if (!completions[i].is_sq) { 1452ce110ea1SWei Hu mana_err(NULL, "WARNING: Not for SQ\n"); 1453ce110ea1SWei Hu return; 1454ce110ea1SWei Hu } 1455ce110ea1SWei Hu 1456ce110ea1SWei Hu cqe_oob = (struct mana_tx_comp_oob *)completions[i].cqe_data; 1457ce110ea1SWei Hu if (cqe_oob->cqe_hdr.client_type != 1458ce110ea1SWei Hu MANA_CQE_COMPLETION) { 1459ce110ea1SWei Hu mana_err(NULL, 1460ce110ea1SWei Hu "WARNING: Invalid CQE client type %u\n", 1461ce110ea1SWei Hu cqe_oob->cqe_hdr.client_type); 1462ce110ea1SWei Hu return; 1463ce110ea1SWei Hu } 1464ce110ea1SWei Hu 1465ce110ea1SWei Hu switch (cqe_oob->cqe_hdr.cqe_type) { 1466ce110ea1SWei Hu case CQE_TX_OKAY: 1467ce110ea1SWei Hu break; 1468ce110ea1SWei Hu 1469ce110ea1SWei Hu case CQE_TX_SA_DROP: 1470ce110ea1SWei Hu case CQE_TX_MTU_DROP: 1471ce110ea1SWei Hu case CQE_TX_INVALID_OOB: 1472ce110ea1SWei Hu case CQE_TX_INVALID_ETH_TYPE: 1473ce110ea1SWei Hu case CQE_TX_HDR_PROCESSING_ERROR: 1474ce110ea1SWei Hu case CQE_TX_VF_DISABLED: 1475ce110ea1SWei Hu case CQE_TX_VPORT_IDX_OUT_OF_RANGE: 1476ce110ea1SWei Hu case CQE_TX_VPORT_DISABLED: 1477ce110ea1SWei Hu case CQE_TX_VLAN_TAGGING_VIOLATION: 1478ce110ea1SWei Hu sa_drop ++; 1479516b5059SWei Hu mana_dbg(NULL, 1480ce110ea1SWei Hu "TX: txq %d CQE error %d, ntc = %d, " 1481ce110ea1SWei Hu "pending sends = %d: err ignored.\n", 1482ce110ea1SWei Hu txq_idx, cqe_oob->cqe_hdr.cqe_type, 1483ce110ea1SWei Hu next_to_complete, txq->pending_sends); 1484516b5059SWei Hu counter_u64_add(txq->stats.cqe_err, 1); 1485ce110ea1SWei Hu break; 1486ce110ea1SWei Hu 1487ce110ea1SWei Hu default: 1488516b5059SWei Hu /* If the CQE type is unknown, log a debug msg, 1489516b5059SWei Hu * and still free the mbuf, etc. 1490ce110ea1SWei Hu */ 1491516b5059SWei Hu mana_dbg(NULL, 1492516b5059SWei Hu "ERROR: TX: Unknown CQE type %d\n", 1493ce110ea1SWei Hu cqe_oob->cqe_hdr.cqe_type); 1494516b5059SWei Hu counter_u64_add(txq->stats.cqe_unknown_type, 1); 1495516b5059SWei Hu break; 1496ce110ea1SWei Hu } 1497ce110ea1SWei Hu if (txq->gdma_txq_id != completions[i].wq_num) { 1498ce110ea1SWei Hu mana_dbg(NULL, 1499ce110ea1SWei Hu "txq gdma id not match completion wq num: " 1500ce110ea1SWei Hu "%d != %d\n", 1501ce110ea1SWei Hu txq->gdma_txq_id, completions[i].wq_num); 1502ce110ea1SWei Hu break; 1503ce110ea1SWei Hu } 1504ce110ea1SWei Hu 1505ce110ea1SWei Hu tx_info = &txq->tx_buf_info[next_to_complete]; 1506ce110ea1SWei Hu if (!tx_info->mbuf) { 1507ce110ea1SWei Hu mana_err(NULL, 1508ce110ea1SWei Hu "WARNING: txq %d Empty mbuf on tx_info: %u, " 1509ce110ea1SWei Hu "ntu = %u, pending_sends = %d, " 1510ce110ea1SWei Hu "transmitted = %d, sa_drop = %d, i = %d, comp_read = %d\n", 1511ce110ea1SWei Hu txq_idx, next_to_complete, txq->next_to_use, 1512ce110ea1SWei Hu txq->pending_sends, pkt_transmitted, sa_drop, 1513ce110ea1SWei Hu i, comp_read); 15141833cf13SWei Hu break; 1515ce110ea1SWei Hu } 1516ce110ea1SWei Hu 1517ce110ea1SWei Hu wqe_info = &tx_info->wqe_inf; 1518ce110ea1SWei Hu wqe_unit_cnt += wqe_info->wqe_size_in_bu; 1519ce110ea1SWei Hu 1520ce110ea1SWei Hu mana_tx_unmap_mbuf(apc, tx_info); 1521ce110ea1SWei Hu mb(); 1522ce110ea1SWei Hu 1523ce110ea1SWei Hu next_to_complete = 1524ce110ea1SWei Hu (next_to_complete + 1) % MAX_SEND_BUFFERS_PER_QUEUE; 1525ce110ea1SWei Hu 1526ce110ea1SWei Hu pkt_transmitted++; 1527ce110ea1SWei Hu } 1528ce110ea1SWei Hu 1529ce110ea1SWei Hu txq->next_to_complete = next_to_complete; 1530ce110ea1SWei Hu 1531ce110ea1SWei Hu if (wqe_unit_cnt == 0) { 1532ce110ea1SWei Hu mana_err(NULL, 1533ce110ea1SWei Hu "WARNING: TX ring not proceeding!\n"); 1534ce110ea1SWei Hu return; 1535ce110ea1SWei Hu } 1536ce110ea1SWei Hu 1537ce110ea1SWei Hu mana_move_wq_tail(txq->gdma_sq, wqe_unit_cnt); 1538ce110ea1SWei Hu 1539ce110ea1SWei Hu /* Ensure tail updated before checking q stop */ 1540ce110ea1SWei Hu wmb(); 1541ce110ea1SWei Hu 1542ce110ea1SWei Hu gdma_wq = txq->gdma_sq; 1543ce110ea1SWei Hu avail_space = mana_gd_wq_avail_space(gdma_wq); 1544ce110ea1SWei Hu 1545ce110ea1SWei Hu 1546ce110ea1SWei Hu if ((if_getdrvflags(ndev) & MANA_TXQ_FULL) == MANA_TXQ_FULL) { 1547ce110ea1SWei Hu txq_full = true; 1548ce110ea1SWei Hu } 1549ce110ea1SWei Hu 1550ce110ea1SWei Hu /* Ensure checking txq_full before apc->port_is_up. */ 1551ce110ea1SWei Hu rmb(); 1552ce110ea1SWei Hu 1553ce110ea1SWei Hu if (txq_full && apc->port_is_up && avail_space >= MAX_TX_WQE_SIZE) { 1554ce110ea1SWei Hu /* Grab the txq lock and re-test */ 1555ce110ea1SWei Hu mtx_lock(&txq->txq_mtx); 1556ce110ea1SWei Hu avail_space = mana_gd_wq_avail_space(gdma_wq); 1557ce110ea1SWei Hu 1558ce110ea1SWei Hu if ((if_getdrvflags(ndev) & MANA_TXQ_FULL) == MANA_TXQ_FULL && 1559ce110ea1SWei Hu apc->port_is_up && avail_space >= MAX_TX_WQE_SIZE) { 1560ce110ea1SWei Hu /* Clear the Q full flag */ 1561ce110ea1SWei Hu if_setdrvflagbits(apc->ndev, IFF_DRV_RUNNING, 1562ce110ea1SWei Hu IFF_DRV_OACTIVE); 1563ce110ea1SWei Hu counter_u64_add(txq->stats.wakeup, 1); 1564ce110ea1SWei Hu if (txq->alt_txq_idx != txq->idx) { 1565ce110ea1SWei Hu uint64_t stops = counter_u64_fetch(txq->stats.stop); 1566ce110ea1SWei Hu uint64_t wakeups = counter_u64_fetch(txq->stats.wakeup); 1567ce110ea1SWei Hu /* Reset alt_txq_idx back if it is not overloaded */ 1568ce110ea1SWei Hu if (stops < wakeups) { 1569ce110ea1SWei Hu txq->alt_txq_idx = txq->idx; 1570ce110ea1SWei Hu counter_u64_add(txq->stats.alt_reset, 1); 1571ce110ea1SWei Hu } 1572ce110ea1SWei Hu } 1573ce110ea1SWei Hu rmb(); 1574ce110ea1SWei Hu /* Schedule a tx enqueue task */ 1575ce110ea1SWei Hu taskqueue_enqueue(txq->enqueue_tq, &txq->enqueue_task); 1576ce110ea1SWei Hu } 1577ce110ea1SWei Hu mtx_unlock(&txq->txq_mtx); 1578ce110ea1SWei Hu } 1579ce110ea1SWei Hu 1580ce110ea1SWei Hu if (atomic_sub_return(pkt_transmitted, &txq->pending_sends) < 0) 1581ce110ea1SWei Hu mana_err(NULL, 1582ce110ea1SWei Hu "WARNING: TX %d pending_sends error: %d\n", 1583ce110ea1SWei Hu txq->idx, txq->pending_sends); 15841833cf13SWei Hu 15851833cf13SWei Hu cq->work_done = pkt_transmitted; 1586ce110ea1SWei Hu } 1587ce110ea1SWei Hu 1588ce110ea1SWei Hu static void 1589ce110ea1SWei Hu mana_post_pkt_rxq(struct mana_rxq *rxq) 1590ce110ea1SWei Hu { 1591ce110ea1SWei Hu struct mana_recv_buf_oob *recv_buf_oob; 1592ce110ea1SWei Hu uint32_t curr_index; 1593ce110ea1SWei Hu int err; 1594ce110ea1SWei Hu 1595ce110ea1SWei Hu curr_index = rxq->buf_index++; 1596ce110ea1SWei Hu if (rxq->buf_index == rxq->num_rx_buf) 1597ce110ea1SWei Hu rxq->buf_index = 0; 1598ce110ea1SWei Hu 1599ce110ea1SWei Hu recv_buf_oob = &rxq->rx_oobs[curr_index]; 1600ce110ea1SWei Hu 1601e4e11c1dSWei Hu err = mana_gd_post_work_request(rxq->gdma_rq, &recv_buf_oob->wqe_req, 1602ce110ea1SWei Hu &recv_buf_oob->wqe_inf); 1603ce110ea1SWei Hu if (err) { 1604ce110ea1SWei Hu mana_err(NULL, "WARNING: rxq %u post pkt err %d\n", 1605ce110ea1SWei Hu rxq->rxq_idx, err); 1606ce110ea1SWei Hu return; 1607ce110ea1SWei Hu } 1608ce110ea1SWei Hu 1609ce110ea1SWei Hu if (recv_buf_oob->wqe_inf.wqe_size_in_bu != 1) { 1610ce110ea1SWei Hu mana_err(NULL, "WARNING: rxq %u wqe_size_in_bu %u\n", 1611ce110ea1SWei Hu rxq->rxq_idx, recv_buf_oob->wqe_inf.wqe_size_in_bu); 1612ce110ea1SWei Hu } 1613ce110ea1SWei Hu } 1614ce110ea1SWei Hu 1615ce110ea1SWei Hu static void 1616ce110ea1SWei Hu mana_rx_mbuf(struct mbuf *mbuf, struct mana_rxcomp_oob *cqe, 1617ce110ea1SWei Hu struct mana_rxq *rxq) 1618ce110ea1SWei Hu { 1619ce110ea1SWei Hu struct mana_stats *rx_stats = &rxq->stats; 162037d22ce0SJustin Hibbits if_t ndev = rxq->ndev; 1621ce110ea1SWei Hu uint32_t pkt_len = cqe->ppi[0].pkt_len; 1622ce110ea1SWei Hu uint16_t rxq_idx = rxq->rxq_idx; 1623ce110ea1SWei Hu struct mana_port_context *apc; 1624ce110ea1SWei Hu bool do_lro = false; 1625ce110ea1SWei Hu bool do_if_input; 1626ce110ea1SWei Hu 1627ce110ea1SWei Hu apc = if_getsoftc(ndev); 16281833cf13SWei Hu rxq->rx_cq.work_done++; 1629ce110ea1SWei Hu 1630ce110ea1SWei Hu if (!mbuf) { 1631ce110ea1SWei Hu return; 1632ce110ea1SWei Hu } 1633ce110ea1SWei Hu 1634ce110ea1SWei Hu mbuf->m_flags |= M_PKTHDR; 1635ce110ea1SWei Hu mbuf->m_pkthdr.len = pkt_len; 1636ce110ea1SWei Hu mbuf->m_len = pkt_len; 1637ce110ea1SWei Hu mbuf->m_pkthdr.rcvif = ndev; 1638ce110ea1SWei Hu 163937d22ce0SJustin Hibbits if ((if_getcapenable(ndev) & IFCAP_RXCSUM || 164037d22ce0SJustin Hibbits if_getcapenable(ndev) & IFCAP_RXCSUM_IPV6) && 1641ce110ea1SWei Hu (cqe->rx_iphdr_csum_succeed)) { 1642ce110ea1SWei Hu mbuf->m_pkthdr.csum_flags = CSUM_IP_CHECKED; 1643ce110ea1SWei Hu mbuf->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1644ce110ea1SWei Hu if (cqe->rx_tcp_csum_succeed || cqe->rx_udp_csum_succeed) { 1645ce110ea1SWei Hu mbuf->m_pkthdr.csum_flags |= 1646ce110ea1SWei Hu (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1647ce110ea1SWei Hu mbuf->m_pkthdr.csum_data = 0xffff; 1648ce110ea1SWei Hu 1649ce110ea1SWei Hu if (cqe->rx_tcp_csum_succeed) 1650ce110ea1SWei Hu do_lro = true; 1651ce110ea1SWei Hu } 1652ce110ea1SWei Hu } 1653ce110ea1SWei Hu 1654ce110ea1SWei Hu if (cqe->rx_hashtype != 0) { 1655ce110ea1SWei Hu mbuf->m_pkthdr.flowid = cqe->ppi[0].pkt_hash; 1656ce110ea1SWei Hu 1657ce110ea1SWei Hu uint16_t hashtype = cqe->rx_hashtype; 1658ce110ea1SWei Hu if (hashtype & NDIS_HASH_IPV4_MASK) { 1659ce110ea1SWei Hu hashtype &= NDIS_HASH_IPV4_MASK; 1660ce110ea1SWei Hu switch (hashtype) { 1661ce110ea1SWei Hu case NDIS_HASH_TCP_IPV4: 1662ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV4); 1663ce110ea1SWei Hu break; 1664ce110ea1SWei Hu case NDIS_HASH_UDP_IPV4: 1665ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_UDP_IPV4); 1666ce110ea1SWei Hu break; 1667ce110ea1SWei Hu default: 1668ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV4); 1669ce110ea1SWei Hu } 1670ce110ea1SWei Hu } else if (hashtype & NDIS_HASH_IPV6_MASK) { 1671ce110ea1SWei Hu hashtype &= NDIS_HASH_IPV6_MASK; 1672ce110ea1SWei Hu switch (hashtype) { 1673ce110ea1SWei Hu case NDIS_HASH_TCP_IPV6: 1674ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_TCP_IPV6); 1675ce110ea1SWei Hu break; 1676ce110ea1SWei Hu case NDIS_HASH_TCP_IPV6_EX: 1677ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, 1678ce110ea1SWei Hu M_HASHTYPE_RSS_TCP_IPV6_EX); 1679ce110ea1SWei Hu break; 1680ce110ea1SWei Hu case NDIS_HASH_UDP_IPV6: 1681ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_UDP_IPV6); 1682ce110ea1SWei Hu break; 1683ce110ea1SWei Hu case NDIS_HASH_UDP_IPV6_EX: 1684ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, 1685ce110ea1SWei Hu M_HASHTYPE_RSS_UDP_IPV6_EX); 1686ce110ea1SWei Hu break; 1687ce110ea1SWei Hu default: 1688ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_RSS_IPV6); 1689ce110ea1SWei Hu } 1690ce110ea1SWei Hu } else { 1691ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE_HASH); 1692ce110ea1SWei Hu } 1693ce110ea1SWei Hu } else { 1694ce110ea1SWei Hu mbuf->m_pkthdr.flowid = rxq_idx; 1695ce110ea1SWei Hu M_HASHTYPE_SET(mbuf, M_HASHTYPE_NONE); 1696ce110ea1SWei Hu } 1697ce110ea1SWei Hu 1698ce110ea1SWei Hu do_if_input = true; 169937d22ce0SJustin Hibbits if ((if_getcapenable(ndev) & IFCAP_LRO) && do_lro) { 1700b167e449SWei Hu rxq->lro_tried++; 1701ce110ea1SWei Hu if (rxq->lro.lro_cnt != 0 && 1702ce110ea1SWei Hu tcp_lro_rx(&rxq->lro, mbuf, 0) == 0) 1703ce110ea1SWei Hu do_if_input = false; 1704b167e449SWei Hu else 1705b167e449SWei Hu rxq->lro_failed++; 1706ce110ea1SWei Hu } 1707ce110ea1SWei Hu if (do_if_input) { 170837d22ce0SJustin Hibbits if_input(ndev, mbuf); 1709ce110ea1SWei Hu } 1710ce110ea1SWei Hu 1711ce110ea1SWei Hu counter_enter(); 1712ce110ea1SWei Hu counter_u64_add_protected(rx_stats->packets, 1); 1713ce110ea1SWei Hu counter_u64_add_protected(apc->port_stats.rx_packets, 1); 1714ce110ea1SWei Hu counter_u64_add_protected(rx_stats->bytes, pkt_len); 1715ce110ea1SWei Hu counter_u64_add_protected(apc->port_stats.rx_bytes, pkt_len); 1716ce110ea1SWei Hu counter_exit(); 1717ce110ea1SWei Hu } 1718ce110ea1SWei Hu 1719ce110ea1SWei Hu static void 1720ce110ea1SWei Hu mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, 1721ce110ea1SWei Hu struct gdma_comp *cqe) 1722ce110ea1SWei Hu { 1723ce110ea1SWei Hu struct mana_rxcomp_oob *oob = (struct mana_rxcomp_oob *)cqe->cqe_data; 1724ce110ea1SWei Hu struct mana_recv_buf_oob *rxbuf_oob; 172537d22ce0SJustin Hibbits if_t ndev = rxq->ndev; 1726ce110ea1SWei Hu struct mana_port_context *apc; 1727ce110ea1SWei Hu struct mbuf *old_mbuf; 1728ce110ea1SWei Hu uint32_t curr, pktlen; 1729ce110ea1SWei Hu int err; 1730ce110ea1SWei Hu 1731ce110ea1SWei Hu switch (oob->cqe_hdr.cqe_type) { 1732ce110ea1SWei Hu case CQE_RX_OKAY: 1733ce110ea1SWei Hu break; 1734ce110ea1SWei Hu 1735ce110ea1SWei Hu case CQE_RX_TRUNCATED: 1736de64aa32SWei Hu apc = if_getsoftc(ndev); 1737de64aa32SWei Hu counter_u64_add(apc->port_stats.rx_drops, 1); 1738de64aa32SWei Hu rxbuf_oob = &rxq->rx_oobs[rxq->buf_index]; 1739ce110ea1SWei Hu if_printf(ndev, "Dropped a truncated packet\n"); 1740de64aa32SWei Hu goto drop; 1741ce110ea1SWei Hu 1742ce110ea1SWei Hu case CQE_RX_COALESCED_4: 1743ce110ea1SWei Hu if_printf(ndev, "RX coalescing is unsupported\n"); 1744ce110ea1SWei Hu return; 1745ce110ea1SWei Hu 1746ce110ea1SWei Hu case CQE_RX_OBJECT_FENCE: 1747aa108bc7SWei Hu complete(&rxq->fence_event); 1748ce110ea1SWei Hu return; 1749ce110ea1SWei Hu 1750ce110ea1SWei Hu default: 1751ce110ea1SWei Hu if_printf(ndev, "Unknown RX CQE type = %d\n", 1752ce110ea1SWei Hu oob->cqe_hdr.cqe_type); 1753ce110ea1SWei Hu return; 1754ce110ea1SWei Hu } 1755ce110ea1SWei Hu 1756ce110ea1SWei Hu if (oob->cqe_hdr.cqe_type != CQE_RX_OKAY) 1757ce110ea1SWei Hu return; 1758ce110ea1SWei Hu 1759ce110ea1SWei Hu pktlen = oob->ppi[0].pkt_len; 1760ce110ea1SWei Hu 1761ce110ea1SWei Hu if (pktlen == 0) { 1762ce110ea1SWei Hu /* data packets should never have packetlength of zero */ 1763d0b5e4a3SLi-Wen Hsu if_printf(ndev, "RX pkt len=0, rq=%u, cq=%u, rxobj=0x%jx\n", 1764ce110ea1SWei Hu rxq->gdma_id, cq->gdma_id, rxq->rxobj); 1765ce110ea1SWei Hu return; 1766ce110ea1SWei Hu } 1767ce110ea1SWei Hu 1768ce110ea1SWei Hu curr = rxq->buf_index; 1769ce110ea1SWei Hu rxbuf_oob = &rxq->rx_oobs[curr]; 1770ce110ea1SWei Hu if (rxbuf_oob->wqe_inf.wqe_size_in_bu != 1) { 1771ce110ea1SWei Hu mana_err(NULL, "WARNING: Rx Incorrect complete " 1772ce110ea1SWei Hu "WQE size %u\n", 1773ce110ea1SWei Hu rxbuf_oob->wqe_inf.wqe_size_in_bu); 1774ce110ea1SWei Hu } 1775ce110ea1SWei Hu 1776ce110ea1SWei Hu apc = if_getsoftc(ndev); 1777ce110ea1SWei Hu 1778ce110ea1SWei Hu old_mbuf = rxbuf_oob->mbuf; 1779ce110ea1SWei Hu 1780ce110ea1SWei Hu /* Unload DMA map for the old mbuf */ 1781ce110ea1SWei Hu mana_unload_rx_mbuf(apc, rxq, rxbuf_oob, false); 1782ce110ea1SWei Hu 1783ce110ea1SWei Hu /* Load a new mbuf to replace the old one */ 1784ce110ea1SWei Hu err = mana_load_rx_mbuf(apc, rxq, rxbuf_oob, true); 1785ce110ea1SWei Hu if (err) { 1786ce110ea1SWei Hu mana_dbg(NULL, 1787ce110ea1SWei Hu "failed to load rx mbuf, err = %d, packet dropped.\n", 1788ce110ea1SWei Hu err); 1789ce110ea1SWei Hu counter_u64_add(rxq->stats.mbuf_alloc_fail, 1); 1790ce110ea1SWei Hu /* 1791ce110ea1SWei Hu * Failed to load new mbuf, rxbuf_oob->mbuf is still 1792ce110ea1SWei Hu * pointing to the old one. Drop the packet. 1793ce110ea1SWei Hu */ 1794ce110ea1SWei Hu old_mbuf = NULL; 1795ce110ea1SWei Hu /* Reload the existing mbuf */ 1796ce110ea1SWei Hu mana_load_rx_mbuf(apc, rxq, rxbuf_oob, false); 1797ce110ea1SWei Hu } 1798ce110ea1SWei Hu 1799ce110ea1SWei Hu mana_rx_mbuf(old_mbuf, oob, rxq); 1800ce110ea1SWei Hu 1801de64aa32SWei Hu drop: 1802ce110ea1SWei Hu mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu); 1803ce110ea1SWei Hu 1804ce110ea1SWei Hu mana_post_pkt_rxq(rxq); 1805ce110ea1SWei Hu } 1806ce110ea1SWei Hu 1807ce110ea1SWei Hu static void 1808ce110ea1SWei Hu mana_poll_rx_cq(struct mana_cq *cq) 1809ce110ea1SWei Hu { 1810ce110ea1SWei Hu struct gdma_comp *comp = cq->gdma_comp_buf; 1811ce110ea1SWei Hu int comp_read, i; 1812ce110ea1SWei Hu 1813ce110ea1SWei Hu comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER); 1814ce110ea1SWei Hu KASSERT(comp_read <= CQE_POLLING_BUFFER, 1815ce110ea1SWei Hu ("comp_read %d great than buf size %d", 1816ce110ea1SWei Hu comp_read, CQE_POLLING_BUFFER)); 1817ce110ea1SWei Hu 1818ce110ea1SWei Hu for (i = 0; i < comp_read; i++) { 1819ce110ea1SWei Hu if (comp[i].is_sq == true) { 1820ce110ea1SWei Hu mana_err(NULL, 1821ce110ea1SWei Hu "WARNING: CQE not for receive queue\n"); 1822ce110ea1SWei Hu return; 1823ce110ea1SWei Hu } 1824ce110ea1SWei Hu 1825ce110ea1SWei Hu /* verify recv cqe references the right rxq */ 1826ce110ea1SWei Hu if (comp[i].wq_num != cq->rxq->gdma_id) { 1827ce110ea1SWei Hu mana_err(NULL, 1828ce110ea1SWei Hu "WARNING: Received CQE %d not for " 1829ce110ea1SWei Hu "this receive queue %d\n", 1830ce110ea1SWei Hu comp[i].wq_num, cq->rxq->gdma_id); 1831ce110ea1SWei Hu return; 1832ce110ea1SWei Hu } 1833ce110ea1SWei Hu 1834ce110ea1SWei Hu mana_process_rx_cqe(cq->rxq, cq, &comp[i]); 1835ce110ea1SWei Hu } 1836ce110ea1SWei Hu 1837e4e11c1dSWei Hu if (comp_read > 0) { 1838e4e11c1dSWei Hu struct gdma_context *gc = 1839e4e11c1dSWei Hu cq->rxq->gdma_rq->gdma_dev->gdma_context; 1840e4e11c1dSWei Hu 1841e4e11c1dSWei Hu mana_gd_wq_ring_doorbell(gc, cq->rxq->gdma_rq); 1842e4e11c1dSWei Hu } 1843e4e11c1dSWei Hu 1844ce110ea1SWei Hu tcp_lro_flush_all(&cq->rxq->lro); 1845ce110ea1SWei Hu } 1846ce110ea1SWei Hu 1847ce110ea1SWei Hu static void 1848ce110ea1SWei Hu mana_cq_handler(void *context, struct gdma_queue *gdma_queue) 1849ce110ea1SWei Hu { 1850ce110ea1SWei Hu struct mana_cq *cq = context; 18511833cf13SWei Hu uint8_t arm_bit; 1852ce110ea1SWei Hu 1853ce110ea1SWei Hu KASSERT(cq->gdma_cq == gdma_queue, 1854ce110ea1SWei Hu ("cq do not match %p, %p", cq->gdma_cq, gdma_queue)); 1855ce110ea1SWei Hu 1856ce110ea1SWei Hu if (cq->type == MANA_CQ_TYPE_RX) { 1857ce110ea1SWei Hu mana_poll_rx_cq(cq); 1858ce110ea1SWei Hu } else { 1859ce110ea1SWei Hu mana_poll_tx_cq(cq); 1860ce110ea1SWei Hu } 1861ce110ea1SWei Hu 18621833cf13SWei Hu if (cq->work_done < cq->budget && cq->do_not_ring_db == false) 18631833cf13SWei Hu arm_bit = SET_ARM_BIT; 18641833cf13SWei Hu else 18651833cf13SWei Hu arm_bit = 0; 18661833cf13SWei Hu 18671833cf13SWei Hu mana_gd_ring_cq(gdma_queue, arm_bit); 18681833cf13SWei Hu } 18691833cf13SWei Hu 18701833cf13SWei Hu #define MANA_POLL_BUDGET 8 18711833cf13SWei Hu #define MANA_RX_BUDGET 256 18721833cf13SWei Hu #define MANA_TX_BUDGET MAX_SEND_BUFFERS_PER_QUEUE 18731833cf13SWei Hu 18741833cf13SWei Hu static void 18751833cf13SWei Hu mana_poll(void *arg, int pending) 18761833cf13SWei Hu { 18771833cf13SWei Hu struct mana_cq *cq = arg; 18781833cf13SWei Hu int i; 18791833cf13SWei Hu 18801833cf13SWei Hu cq->work_done = 0; 18811833cf13SWei Hu if (cq->type == MANA_CQ_TYPE_RX) { 18821833cf13SWei Hu cq->budget = MANA_RX_BUDGET; 18831833cf13SWei Hu } else { 18841833cf13SWei Hu cq->budget = MANA_TX_BUDGET; 18851833cf13SWei Hu } 18861833cf13SWei Hu 18871833cf13SWei Hu for (i = 0; i < MANA_POLL_BUDGET; i++) { 18881833cf13SWei Hu /* 18891833cf13SWei Hu * If this is the last loop, set the budget big enough 18901833cf13SWei Hu * so it will arm the CQ any way. 18911833cf13SWei Hu */ 18921833cf13SWei Hu if (i == (MANA_POLL_BUDGET - 1)) 18931833cf13SWei Hu cq->budget = CQE_POLLING_BUFFER + 1; 18941833cf13SWei Hu 18951833cf13SWei Hu mana_cq_handler(cq, cq->gdma_cq); 18961833cf13SWei Hu 18971833cf13SWei Hu if (cq->work_done < cq->budget) 18981833cf13SWei Hu break; 18991833cf13SWei Hu 19001833cf13SWei Hu cq->work_done = 0; 19011833cf13SWei Hu } 19021833cf13SWei Hu } 19031833cf13SWei Hu 19041833cf13SWei Hu static void 19051833cf13SWei Hu mana_schedule_task(void *arg, struct gdma_queue *gdma_queue) 19061833cf13SWei Hu { 19071833cf13SWei Hu struct mana_cq *cq = arg; 19081833cf13SWei Hu 19091833cf13SWei Hu taskqueue_enqueue(cq->cleanup_tq, &cq->cleanup_task); 1910ce110ea1SWei Hu } 1911ce110ea1SWei Hu 1912ce110ea1SWei Hu static void 1913ce110ea1SWei Hu mana_deinit_cq(struct mana_port_context *apc, struct mana_cq *cq) 1914ce110ea1SWei Hu { 1915ce110ea1SWei Hu struct gdma_dev *gd = apc->ac->gdma_dev; 1916ce110ea1SWei Hu 1917ce110ea1SWei Hu if (!cq->gdma_cq) 1918ce110ea1SWei Hu return; 1919ce110ea1SWei Hu 19201833cf13SWei Hu /* Drain cleanup taskqueue */ 19211833cf13SWei Hu if (cq->cleanup_tq) { 19221833cf13SWei Hu while (taskqueue_cancel(cq->cleanup_tq, 19231833cf13SWei Hu &cq->cleanup_task, NULL)) { 19241833cf13SWei Hu taskqueue_drain(cq->cleanup_tq, 19251833cf13SWei Hu &cq->cleanup_task); 19261833cf13SWei Hu } 19271833cf13SWei Hu 19281833cf13SWei Hu taskqueue_free(cq->cleanup_tq); 19291833cf13SWei Hu } 19301833cf13SWei Hu 1931ce110ea1SWei Hu mana_gd_destroy_queue(gd->gdma_context, cq->gdma_cq); 1932ce110ea1SWei Hu } 1933ce110ea1SWei Hu 1934ce110ea1SWei Hu static void 1935ce110ea1SWei Hu mana_deinit_txq(struct mana_port_context *apc, struct mana_txq *txq) 1936ce110ea1SWei Hu { 1937ce110ea1SWei Hu struct gdma_dev *gd = apc->ac->gdma_dev; 1938ce110ea1SWei Hu struct mana_send_buf_info *txbuf_info; 1939ce110ea1SWei Hu uint32_t pending_sends; 1940ce110ea1SWei Hu int i; 1941ce110ea1SWei Hu 1942ce110ea1SWei Hu if (!txq->gdma_sq) 1943ce110ea1SWei Hu return; 1944ce110ea1SWei Hu 1945ce110ea1SWei Hu if ((pending_sends = atomic_read(&txq->pending_sends)) > 0) { 1946ce110ea1SWei Hu mana_err(NULL, 1947ce110ea1SWei Hu "WARNING: txq pending sends not zero: %u\n", 1948ce110ea1SWei Hu pending_sends); 1949ce110ea1SWei Hu } 1950ce110ea1SWei Hu 1951ce110ea1SWei Hu if (txq->next_to_use != txq->next_to_complete) { 1952ce110ea1SWei Hu mana_err(NULL, 1953ce110ea1SWei Hu "WARNING: txq buf not completed, " 1954ce110ea1SWei Hu "next use %u, next complete %u\n", 1955ce110ea1SWei Hu txq->next_to_use, txq->next_to_complete); 1956ce110ea1SWei Hu } 1957ce110ea1SWei Hu 1958ce110ea1SWei Hu /* Flush buf ring. Grab txq mtx lock */ 1959ce110ea1SWei Hu if (txq->txq_br) { 1960ce110ea1SWei Hu mtx_lock(&txq->txq_mtx); 1961ce110ea1SWei Hu drbr_flush(apc->ndev, txq->txq_br); 1962ce110ea1SWei Hu mtx_unlock(&txq->txq_mtx); 1963ce110ea1SWei Hu buf_ring_free(txq->txq_br, M_DEVBUF); 1964ce110ea1SWei Hu } 1965ce110ea1SWei Hu 1966ce110ea1SWei Hu /* Drain taskqueue */ 1967ce110ea1SWei Hu if (txq->enqueue_tq) { 1968ce110ea1SWei Hu while (taskqueue_cancel(txq->enqueue_tq, 1969ce110ea1SWei Hu &txq->enqueue_task, NULL)) { 1970ce110ea1SWei Hu taskqueue_drain(txq->enqueue_tq, 1971ce110ea1SWei Hu &txq->enqueue_task); 1972ce110ea1SWei Hu } 1973ce110ea1SWei Hu 1974ce110ea1SWei Hu taskqueue_free(txq->enqueue_tq); 1975ce110ea1SWei Hu } 1976ce110ea1SWei Hu 1977ce110ea1SWei Hu if (txq->tx_buf_info) { 1978ce110ea1SWei Hu /* Free all mbufs which are still in-flight */ 1979ce110ea1SWei Hu for (i = 0; i < MAX_SEND_BUFFERS_PER_QUEUE; i++) { 1980ce110ea1SWei Hu txbuf_info = &txq->tx_buf_info[i]; 1981ce110ea1SWei Hu if (txbuf_info->mbuf) { 1982ce110ea1SWei Hu mana_tx_unmap_mbuf(apc, txbuf_info); 1983ce110ea1SWei Hu } 1984ce110ea1SWei Hu } 1985ce110ea1SWei Hu 1986ce110ea1SWei Hu free(txq->tx_buf_info, M_DEVBUF); 1987ce110ea1SWei Hu } 1988ce110ea1SWei Hu 1989ce110ea1SWei Hu mana_free_counters((counter_u64_t *)&txq->stats, 1990ce110ea1SWei Hu sizeof(txq->stats)); 1991ce110ea1SWei Hu 1992ce110ea1SWei Hu mana_gd_destroy_queue(gd->gdma_context, txq->gdma_sq); 1993ce110ea1SWei Hu 1994ce110ea1SWei Hu mtx_destroy(&txq->txq_mtx); 1995ce110ea1SWei Hu } 1996ce110ea1SWei Hu 1997ce110ea1SWei Hu static void 1998ce110ea1SWei Hu mana_destroy_txq(struct mana_port_context *apc) 1999ce110ea1SWei Hu { 2000ce110ea1SWei Hu int i; 2001ce110ea1SWei Hu 2002ce110ea1SWei Hu if (!apc->tx_qp) 2003ce110ea1SWei Hu return; 2004ce110ea1SWei Hu 2005ce110ea1SWei Hu for (i = 0; i < apc->num_queues; i++) { 2006ce110ea1SWei Hu mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object); 2007ce110ea1SWei Hu 2008ce110ea1SWei Hu mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq); 2009ce110ea1SWei Hu 2010ce110ea1SWei Hu mana_deinit_txq(apc, &apc->tx_qp[i].txq); 2011ce110ea1SWei Hu } 2012ce110ea1SWei Hu 2013ce110ea1SWei Hu free(apc->tx_qp, M_DEVBUF); 2014ce110ea1SWei Hu apc->tx_qp = NULL; 2015ce110ea1SWei Hu } 2016ce110ea1SWei Hu 2017ce110ea1SWei Hu static int 201837d22ce0SJustin Hibbits mana_create_txq(struct mana_port_context *apc, if_t net) 2019ce110ea1SWei Hu { 20201833cf13SWei Hu struct mana_context *ac = apc->ac; 20211833cf13SWei Hu struct gdma_dev *gd = ac->gdma_dev; 2022ce110ea1SWei Hu struct mana_obj_spec wq_spec; 2023ce110ea1SWei Hu struct mana_obj_spec cq_spec; 2024ce110ea1SWei Hu struct gdma_queue_spec spec; 2025ce110ea1SWei Hu struct gdma_context *gc; 2026ce110ea1SWei Hu struct mana_txq *txq; 2027ce110ea1SWei Hu struct mana_cq *cq; 2028ce110ea1SWei Hu uint32_t txq_size; 2029ce110ea1SWei Hu uint32_t cq_size; 2030ce110ea1SWei Hu int err; 2031ce110ea1SWei Hu int i; 2032ce110ea1SWei Hu 2033ce110ea1SWei Hu apc->tx_qp = mallocarray(apc->num_queues, sizeof(struct mana_tx_qp), 2034ce110ea1SWei Hu M_DEVBUF, M_WAITOK | M_ZERO); 2035ce110ea1SWei Hu 2036ce110ea1SWei Hu /* The minimum size of the WQE is 32 bytes, hence 2037ce110ea1SWei Hu * MAX_SEND_BUFFERS_PER_QUEUE represents the maximum number of WQEs 2038ce110ea1SWei Hu * the SQ can store. This value is then used to size other queues 2039ce110ea1SWei Hu * to prevent overflow. 2040ce110ea1SWei Hu */ 2041ce110ea1SWei Hu txq_size = MAX_SEND_BUFFERS_PER_QUEUE * 32; 2042ce110ea1SWei Hu KASSERT(IS_ALIGNED(txq_size, PAGE_SIZE), 2043ce110ea1SWei Hu ("txq size not page aligned")); 2044ce110ea1SWei Hu 2045ce110ea1SWei Hu cq_size = MAX_SEND_BUFFERS_PER_QUEUE * COMP_ENTRY_SIZE; 2046ce110ea1SWei Hu cq_size = ALIGN(cq_size, PAGE_SIZE); 2047ce110ea1SWei Hu 2048ce110ea1SWei Hu gc = gd->gdma_context; 2049ce110ea1SWei Hu 2050ce110ea1SWei Hu for (i = 0; i < apc->num_queues; i++) { 2051ce110ea1SWei Hu apc->tx_qp[i].tx_object = INVALID_MANA_HANDLE; 2052ce110ea1SWei Hu 2053ce110ea1SWei Hu /* Create SQ */ 2054ce110ea1SWei Hu txq = &apc->tx_qp[i].txq; 2055ce110ea1SWei Hu 2056ce110ea1SWei Hu txq->ndev = net; 2057ce110ea1SWei Hu txq->vp_offset = apc->tx_vp_offset; 2058ce110ea1SWei Hu txq->idx = i; 2059ce110ea1SWei Hu txq->alt_txq_idx = i; 2060ce110ea1SWei Hu 2061ce110ea1SWei Hu memset(&spec, 0, sizeof(spec)); 2062ce110ea1SWei Hu spec.type = GDMA_SQ; 2063ce110ea1SWei Hu spec.monitor_avl_buf = true; 2064ce110ea1SWei Hu spec.queue_size = txq_size; 2065ce110ea1SWei Hu err = mana_gd_create_mana_wq_cq(gd, &spec, &txq->gdma_sq); 2066ce110ea1SWei Hu if (err) 2067ce110ea1SWei Hu goto out; 2068ce110ea1SWei Hu 2069ce110ea1SWei Hu /* Create SQ's CQ */ 2070ce110ea1SWei Hu cq = &apc->tx_qp[i].tx_cq; 2071ce110ea1SWei Hu cq->type = MANA_CQ_TYPE_TX; 2072ce110ea1SWei Hu 2073ce110ea1SWei Hu cq->txq = txq; 2074ce110ea1SWei Hu 2075ce110ea1SWei Hu memset(&spec, 0, sizeof(spec)); 2076ce110ea1SWei Hu spec.type = GDMA_CQ; 2077ce110ea1SWei Hu spec.monitor_avl_buf = false; 2078ce110ea1SWei Hu spec.queue_size = cq_size; 20791833cf13SWei Hu spec.cq.callback = mana_schedule_task; 20801833cf13SWei Hu spec.cq.parent_eq = ac->eqs[i].eq; 2081ce110ea1SWei Hu spec.cq.context = cq; 2082ce110ea1SWei Hu err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq); 2083ce110ea1SWei Hu if (err) 2084ce110ea1SWei Hu goto out; 2085ce110ea1SWei Hu 2086ce110ea1SWei Hu memset(&wq_spec, 0, sizeof(wq_spec)); 2087ce110ea1SWei Hu memset(&cq_spec, 0, sizeof(cq_spec)); 2088ce110ea1SWei Hu 2089b685df31SWei Hu wq_spec.gdma_region = txq->gdma_sq->mem_info.dma_region_handle; 2090ce110ea1SWei Hu wq_spec.queue_size = txq->gdma_sq->queue_size; 2091ce110ea1SWei Hu 2092b685df31SWei Hu cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle; 2093ce110ea1SWei Hu cq_spec.queue_size = cq->gdma_cq->queue_size; 2094ce110ea1SWei Hu cq_spec.modr_ctx_id = 0; 2095ce110ea1SWei Hu cq_spec.attached_eq = cq->gdma_cq->cq.parent->id; 2096ce110ea1SWei Hu 2097ce110ea1SWei Hu err = mana_create_wq_obj(apc, apc->port_handle, GDMA_SQ, 2098ce110ea1SWei Hu &wq_spec, &cq_spec, &apc->tx_qp[i].tx_object); 2099ce110ea1SWei Hu 2100ce110ea1SWei Hu if (err) 2101ce110ea1SWei Hu goto out; 2102ce110ea1SWei Hu 2103ce110ea1SWei Hu txq->gdma_sq->id = wq_spec.queue_index; 2104ce110ea1SWei Hu cq->gdma_cq->id = cq_spec.queue_index; 2105ce110ea1SWei Hu 2106b685df31SWei Hu txq->gdma_sq->mem_info.dma_region_handle = 2107b685df31SWei Hu GDMA_INVALID_DMA_REGION; 2108b685df31SWei Hu cq->gdma_cq->mem_info.dma_region_handle = 2109b685df31SWei Hu GDMA_INVALID_DMA_REGION; 2110ce110ea1SWei Hu 2111ce110ea1SWei Hu txq->gdma_txq_id = txq->gdma_sq->id; 2112ce110ea1SWei Hu 2113ce110ea1SWei Hu cq->gdma_id = cq->gdma_cq->id; 2114ce110ea1SWei Hu 2115ce110ea1SWei Hu mana_dbg(NULL, 2116ce110ea1SWei Hu "txq %d, txq gdma id %d, txq cq gdma id %d\n", 2117*6ccf4f40SZhenlei Huang i, txq->gdma_txq_id, cq->gdma_id); 2118ce110ea1SWei Hu 2119ce110ea1SWei Hu if (cq->gdma_id >= gc->max_num_cqs) { 2120ce110ea1SWei Hu if_printf(net, "CQ id %u too large.\n", cq->gdma_id); 2121027d0c1cSWei Hu err = EINVAL; 2122027d0c1cSWei Hu goto out; 2123ce110ea1SWei Hu } 2124ce110ea1SWei Hu 2125ce110ea1SWei Hu gc->cq_table[cq->gdma_id] = cq->gdma_cq; 2126ce110ea1SWei Hu 2127ce110ea1SWei Hu /* Initialize tx specific data */ 2128ce110ea1SWei Hu txq->tx_buf_info = malloc(MAX_SEND_BUFFERS_PER_QUEUE * 2129ce110ea1SWei Hu sizeof(struct mana_send_buf_info), 2130ce110ea1SWei Hu M_DEVBUF, M_WAITOK | M_ZERO); 2131ce110ea1SWei Hu 2132ce110ea1SWei Hu snprintf(txq->txq_mtx_name, nitems(txq->txq_mtx_name), 2133ce110ea1SWei Hu "mana:tx(%d)", i); 2134ce110ea1SWei Hu mtx_init(&txq->txq_mtx, txq->txq_mtx_name, NULL, MTX_DEF); 2135ce110ea1SWei Hu 2136ce110ea1SWei Hu txq->txq_br = buf_ring_alloc(4 * MAX_SEND_BUFFERS_PER_QUEUE, 2137ce110ea1SWei Hu M_DEVBUF, M_WAITOK, &txq->txq_mtx); 2138ce110ea1SWei Hu 2139ce110ea1SWei Hu /* Allocate taskqueue for deferred send */ 2140ce110ea1SWei Hu TASK_INIT(&txq->enqueue_task, 0, mana_xmit_taskfunc, txq); 2141ce110ea1SWei Hu txq->enqueue_tq = taskqueue_create_fast("mana_tx_enque", 2142ce110ea1SWei Hu M_NOWAIT, taskqueue_thread_enqueue, &txq->enqueue_tq); 2143ce110ea1SWei Hu if (unlikely(txq->enqueue_tq == NULL)) { 2144ce110ea1SWei Hu if_printf(net, 2145ce110ea1SWei Hu "Unable to create tx %d enqueue task queue\n", i); 2146ce110ea1SWei Hu err = ENOMEM; 2147ce110ea1SWei Hu goto out; 2148ce110ea1SWei Hu } 2149ce110ea1SWei Hu taskqueue_start_threads(&txq->enqueue_tq, 1, PI_NET, 21501833cf13SWei Hu "mana txq p%u-tx%d", apc->port_idx, i); 2151ce110ea1SWei Hu 2152ce110ea1SWei Hu mana_alloc_counters((counter_u64_t *)&txq->stats, 2153ce110ea1SWei Hu sizeof(txq->stats)); 2154ce110ea1SWei Hu 21551833cf13SWei Hu /* Allocate and start the cleanup task on CQ */ 21561833cf13SWei Hu cq->do_not_ring_db = false; 21571833cf13SWei Hu 21581833cf13SWei Hu NET_TASK_INIT(&cq->cleanup_task, 0, mana_poll, cq); 21591833cf13SWei Hu cq->cleanup_tq = 21601833cf13SWei Hu taskqueue_create_fast("mana tx cq cleanup", 21611833cf13SWei Hu M_WAITOK, taskqueue_thread_enqueue, 21621833cf13SWei Hu &cq->cleanup_tq); 21631833cf13SWei Hu 21641833cf13SWei Hu if (apc->last_tx_cq_bind_cpu < 0) 21651833cf13SWei Hu apc->last_tx_cq_bind_cpu = CPU_FIRST(); 21661833cf13SWei Hu cq->cpu = apc->last_tx_cq_bind_cpu; 21671833cf13SWei Hu apc->last_tx_cq_bind_cpu = CPU_NEXT(apc->last_tx_cq_bind_cpu); 21681833cf13SWei Hu 21691833cf13SWei Hu if (apc->bind_cleanup_thread_cpu) { 21701833cf13SWei Hu cpuset_t cpu_mask; 21711833cf13SWei Hu CPU_SETOF(cq->cpu, &cpu_mask); 21721833cf13SWei Hu taskqueue_start_threads_cpuset(&cq->cleanup_tq, 21731833cf13SWei Hu 1, PI_NET, &cpu_mask, 21741833cf13SWei Hu "mana cq p%u-tx%u-cpu%d", 21751833cf13SWei Hu apc->port_idx, txq->idx, cq->cpu); 21761833cf13SWei Hu } else { 21771833cf13SWei Hu taskqueue_start_threads(&cq->cleanup_tq, 1, 21781833cf13SWei Hu PI_NET, "mana cq p%u-tx%u", 21791833cf13SWei Hu apc->port_idx, txq->idx); 21801833cf13SWei Hu } 21811833cf13SWei Hu 21821833cf13SWei Hu mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT); 2183ce110ea1SWei Hu } 2184ce110ea1SWei Hu 2185ce110ea1SWei Hu return 0; 2186ce110ea1SWei Hu out: 2187ce110ea1SWei Hu mana_destroy_txq(apc); 2188ce110ea1SWei Hu return err; 2189ce110ea1SWei Hu } 2190ce110ea1SWei Hu 2191ce110ea1SWei Hu static void 2192ce110ea1SWei Hu mana_destroy_rxq(struct mana_port_context *apc, struct mana_rxq *rxq, 2193ce110ea1SWei Hu bool validate_state) 2194ce110ea1SWei Hu { 2195ce110ea1SWei Hu struct gdma_context *gc = apc->ac->gdma_dev->gdma_context; 2196ce110ea1SWei Hu struct mana_recv_buf_oob *rx_oob; 2197ce110ea1SWei Hu int i; 2198ce110ea1SWei Hu 2199ce110ea1SWei Hu if (!rxq) 2200ce110ea1SWei Hu return; 2201ce110ea1SWei Hu 2202ce110ea1SWei Hu if (validate_state) { 2203ce110ea1SWei Hu /* 2204ce110ea1SWei Hu * XXX Cancel and drain cleanup task queue here. 2205ce110ea1SWei Hu */ 2206ce110ea1SWei Hu ; 2207ce110ea1SWei Hu } 2208ce110ea1SWei Hu 2209ce110ea1SWei Hu mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj); 2210ce110ea1SWei Hu 2211ce110ea1SWei Hu mana_deinit_cq(apc, &rxq->rx_cq); 2212ce110ea1SWei Hu 2213ce110ea1SWei Hu mana_free_counters((counter_u64_t *)&rxq->stats, 2214ce110ea1SWei Hu sizeof(rxq->stats)); 2215ce110ea1SWei Hu 2216ce110ea1SWei Hu /* Free LRO resources */ 2217ce110ea1SWei Hu tcp_lro_free(&rxq->lro); 2218ce110ea1SWei Hu 2219ce110ea1SWei Hu for (i = 0; i < rxq->num_rx_buf; i++) { 2220ce110ea1SWei Hu rx_oob = &rxq->rx_oobs[i]; 2221ce110ea1SWei Hu 2222ce110ea1SWei Hu if (rx_oob->mbuf) 2223ce110ea1SWei Hu mana_unload_rx_mbuf(apc, rxq, rx_oob, true); 2224ce110ea1SWei Hu 2225ce110ea1SWei Hu bus_dmamap_destroy(apc->rx_buf_tag, rx_oob->dma_map); 2226ce110ea1SWei Hu } 2227ce110ea1SWei Hu 2228ce110ea1SWei Hu if (rxq->gdma_rq) 2229ce110ea1SWei Hu mana_gd_destroy_queue(gc, rxq->gdma_rq); 2230ce110ea1SWei Hu 2231ce110ea1SWei Hu free(rxq, M_DEVBUF); 2232ce110ea1SWei Hu } 2233ce110ea1SWei Hu 2234ce110ea1SWei Hu #define MANA_WQE_HEADER_SIZE 16 2235ce110ea1SWei Hu #define MANA_WQE_SGE_SIZE 16 2236ce110ea1SWei Hu 2237ce110ea1SWei Hu static int 2238ce110ea1SWei Hu mana_alloc_rx_wqe(struct mana_port_context *apc, 2239ce110ea1SWei Hu struct mana_rxq *rxq, uint32_t *rxq_size, uint32_t *cq_size) 2240ce110ea1SWei Hu { 2241ce110ea1SWei Hu struct mana_recv_buf_oob *rx_oob; 2242ce110ea1SWei Hu uint32_t buf_idx; 2243ce110ea1SWei Hu int err; 2244ce110ea1SWei Hu 2245ce110ea1SWei Hu if (rxq->datasize == 0 || rxq->datasize > PAGE_SIZE) { 2246ce110ea1SWei Hu mana_err(NULL, 2247ce110ea1SWei Hu "WARNING: Invalid rxq datasize %u\n", rxq->datasize); 2248ce110ea1SWei Hu } 2249ce110ea1SWei Hu 2250ce110ea1SWei Hu *rxq_size = 0; 2251ce110ea1SWei Hu *cq_size = 0; 2252ce110ea1SWei Hu 2253ce110ea1SWei Hu for (buf_idx = 0; buf_idx < rxq->num_rx_buf; buf_idx++) { 2254ce110ea1SWei Hu rx_oob = &rxq->rx_oobs[buf_idx]; 2255ce110ea1SWei Hu memset(rx_oob, 0, sizeof(*rx_oob)); 2256ce110ea1SWei Hu 2257ce110ea1SWei Hu err = bus_dmamap_create(apc->rx_buf_tag, 0, 2258ce110ea1SWei Hu &rx_oob->dma_map); 2259ce110ea1SWei Hu if (err) { 2260ce110ea1SWei Hu mana_err(NULL, 2261ce110ea1SWei Hu "Failed to create rx DMA map for buf %d\n", 2262ce110ea1SWei Hu buf_idx); 2263ce110ea1SWei Hu return err; 2264ce110ea1SWei Hu } 2265ce110ea1SWei Hu 2266ce110ea1SWei Hu err = mana_load_rx_mbuf(apc, rxq, rx_oob, true); 2267ce110ea1SWei Hu if (err) { 2268ce110ea1SWei Hu mana_err(NULL, 2269ce110ea1SWei Hu "Failed to create rx DMA map for buf %d\n", 2270ce110ea1SWei Hu buf_idx); 2271ce110ea1SWei Hu bus_dmamap_destroy(apc->rx_buf_tag, rx_oob->dma_map); 2272ce110ea1SWei Hu return err; 2273ce110ea1SWei Hu } 2274ce110ea1SWei Hu 2275ce110ea1SWei Hu rx_oob->wqe_req.sgl = rx_oob->sgl; 2276ce110ea1SWei Hu rx_oob->wqe_req.num_sge = rx_oob->num_sge; 2277ce110ea1SWei Hu rx_oob->wqe_req.inline_oob_size = 0; 2278ce110ea1SWei Hu rx_oob->wqe_req.inline_oob_data = NULL; 2279ce110ea1SWei Hu rx_oob->wqe_req.flags = 0; 2280ce110ea1SWei Hu rx_oob->wqe_req.client_data_unit = 0; 2281ce110ea1SWei Hu 2282ce110ea1SWei Hu *rxq_size += ALIGN(MANA_WQE_HEADER_SIZE + 2283ce110ea1SWei Hu MANA_WQE_SGE_SIZE * rx_oob->num_sge, 32); 2284ce110ea1SWei Hu *cq_size += COMP_ENTRY_SIZE; 2285ce110ea1SWei Hu } 2286ce110ea1SWei Hu 2287ce110ea1SWei Hu return 0; 2288ce110ea1SWei Hu } 2289ce110ea1SWei Hu 2290ce110ea1SWei Hu static int 2291ce110ea1SWei Hu mana_push_wqe(struct mana_rxq *rxq) 2292ce110ea1SWei Hu { 2293ce110ea1SWei Hu struct mana_recv_buf_oob *rx_oob; 2294ce110ea1SWei Hu uint32_t buf_idx; 2295ce110ea1SWei Hu int err; 2296ce110ea1SWei Hu 2297ce110ea1SWei Hu for (buf_idx = 0; buf_idx < rxq->num_rx_buf; buf_idx++) { 2298ce110ea1SWei Hu rx_oob = &rxq->rx_oobs[buf_idx]; 2299ce110ea1SWei Hu 2300ce110ea1SWei Hu err = mana_gd_post_and_ring(rxq->gdma_rq, &rx_oob->wqe_req, 2301ce110ea1SWei Hu &rx_oob->wqe_inf); 2302ce110ea1SWei Hu if (err) 2303ce110ea1SWei Hu return ENOSPC; 2304ce110ea1SWei Hu } 2305ce110ea1SWei Hu 2306ce110ea1SWei Hu return 0; 2307ce110ea1SWei Hu } 2308ce110ea1SWei Hu 2309ce110ea1SWei Hu static struct mana_rxq * 2310ce110ea1SWei Hu mana_create_rxq(struct mana_port_context *apc, uint32_t rxq_idx, 231137d22ce0SJustin Hibbits struct mana_eq *eq, if_t ndev) 2312ce110ea1SWei Hu { 2313ce110ea1SWei Hu struct gdma_dev *gd = apc->ac->gdma_dev; 2314ce110ea1SWei Hu struct mana_obj_spec wq_spec; 2315ce110ea1SWei Hu struct mana_obj_spec cq_spec; 2316ce110ea1SWei Hu struct gdma_queue_spec spec; 2317ce110ea1SWei Hu struct mana_cq *cq = NULL; 2318ce110ea1SWei Hu uint32_t cq_size, rq_size; 2319ce110ea1SWei Hu struct gdma_context *gc; 2320ce110ea1SWei Hu struct mana_rxq *rxq; 2321ce110ea1SWei Hu int err; 2322ce110ea1SWei Hu 2323ce110ea1SWei Hu gc = gd->gdma_context; 2324ce110ea1SWei Hu 2325ce110ea1SWei Hu rxq = malloc(sizeof(*rxq) + 2326ce110ea1SWei Hu RX_BUFFERS_PER_QUEUE * sizeof(struct mana_recv_buf_oob), 2327ce110ea1SWei Hu M_DEVBUF, M_WAITOK | M_ZERO); 2328ce110ea1SWei Hu rxq->ndev = ndev; 2329ce110ea1SWei Hu rxq->num_rx_buf = RX_BUFFERS_PER_QUEUE; 2330ce110ea1SWei Hu rxq->rxq_idx = rxq_idx; 2331ce110ea1SWei Hu /* 2332ce110ea1SWei Hu * Minimum size is MCLBYTES(2048) bytes for a mbuf cluster. 2333a506133aSGordon Bergling * Now we just allow maximum size of 4096. 2334ce110ea1SWei Hu */ 2335ce110ea1SWei Hu rxq->datasize = ALIGN(apc->frame_size, MCLBYTES); 2336ce110ea1SWei Hu if (rxq->datasize > MAX_FRAME_SIZE) 2337ce110ea1SWei Hu rxq->datasize = MAX_FRAME_SIZE; 2338ce110ea1SWei Hu 2339ce110ea1SWei Hu mana_dbg(NULL, "Setting rxq %d datasize %d\n", 2340ce110ea1SWei Hu rxq_idx, rxq->datasize); 2341ce110ea1SWei Hu 2342ce110ea1SWei Hu rxq->rxobj = INVALID_MANA_HANDLE; 2343ce110ea1SWei Hu 2344ce110ea1SWei Hu err = mana_alloc_rx_wqe(apc, rxq, &rq_size, &cq_size); 2345ce110ea1SWei Hu if (err) 2346ce110ea1SWei Hu goto out; 2347ce110ea1SWei Hu 2348ce110ea1SWei Hu /* Create LRO for the RQ */ 234937d22ce0SJustin Hibbits if (if_getcapenable(ndev) & IFCAP_LRO) { 2350ce110ea1SWei Hu err = tcp_lro_init(&rxq->lro); 2351ce110ea1SWei Hu if (err) { 2352ce110ea1SWei Hu if_printf(ndev, "Failed to create LRO for rxq %d\n", 2353ce110ea1SWei Hu rxq_idx); 2354ce110ea1SWei Hu } else { 2355ce110ea1SWei Hu rxq->lro.ifp = ndev; 2356ce110ea1SWei Hu } 2357ce110ea1SWei Hu } 2358ce110ea1SWei Hu 2359ce110ea1SWei Hu mana_alloc_counters((counter_u64_t *)&rxq->stats, 2360ce110ea1SWei Hu sizeof(rxq->stats)); 2361ce110ea1SWei Hu 2362ce110ea1SWei Hu rq_size = ALIGN(rq_size, PAGE_SIZE); 2363ce110ea1SWei Hu cq_size = ALIGN(cq_size, PAGE_SIZE); 2364ce110ea1SWei Hu 2365ce110ea1SWei Hu /* Create RQ */ 2366ce110ea1SWei Hu memset(&spec, 0, sizeof(spec)); 2367ce110ea1SWei Hu spec.type = GDMA_RQ; 2368ce110ea1SWei Hu spec.monitor_avl_buf = true; 2369ce110ea1SWei Hu spec.queue_size = rq_size; 2370ce110ea1SWei Hu err = mana_gd_create_mana_wq_cq(gd, &spec, &rxq->gdma_rq); 2371ce110ea1SWei Hu if (err) 2372ce110ea1SWei Hu goto out; 2373ce110ea1SWei Hu 2374ce110ea1SWei Hu /* Create RQ's CQ */ 2375ce110ea1SWei Hu cq = &rxq->rx_cq; 2376ce110ea1SWei Hu cq->type = MANA_CQ_TYPE_RX; 2377ce110ea1SWei Hu cq->rxq = rxq; 2378ce110ea1SWei Hu 2379ce110ea1SWei Hu memset(&spec, 0, sizeof(spec)); 2380ce110ea1SWei Hu spec.type = GDMA_CQ; 2381ce110ea1SWei Hu spec.monitor_avl_buf = false; 2382ce110ea1SWei Hu spec.queue_size = cq_size; 23831833cf13SWei Hu spec.cq.callback = mana_schedule_task; 2384ce110ea1SWei Hu spec.cq.parent_eq = eq->eq; 2385ce110ea1SWei Hu spec.cq.context = cq; 2386ce110ea1SWei Hu err = mana_gd_create_mana_wq_cq(gd, &spec, &cq->gdma_cq); 2387ce110ea1SWei Hu if (err) 2388ce110ea1SWei Hu goto out; 2389ce110ea1SWei Hu 2390ce110ea1SWei Hu memset(&wq_spec, 0, sizeof(wq_spec)); 2391ce110ea1SWei Hu memset(&cq_spec, 0, sizeof(cq_spec)); 2392b685df31SWei Hu wq_spec.gdma_region = rxq->gdma_rq->mem_info.dma_region_handle; 2393ce110ea1SWei Hu wq_spec.queue_size = rxq->gdma_rq->queue_size; 2394ce110ea1SWei Hu 2395b685df31SWei Hu cq_spec.gdma_region = cq->gdma_cq->mem_info.dma_region_handle; 2396ce110ea1SWei Hu cq_spec.queue_size = cq->gdma_cq->queue_size; 2397ce110ea1SWei Hu cq_spec.modr_ctx_id = 0; 2398ce110ea1SWei Hu cq_spec.attached_eq = cq->gdma_cq->cq.parent->id; 2399ce110ea1SWei Hu 2400ce110ea1SWei Hu err = mana_create_wq_obj(apc, apc->port_handle, GDMA_RQ, 2401ce110ea1SWei Hu &wq_spec, &cq_spec, &rxq->rxobj); 2402ce110ea1SWei Hu if (err) 2403ce110ea1SWei Hu goto out; 2404ce110ea1SWei Hu 2405ce110ea1SWei Hu rxq->gdma_rq->id = wq_spec.queue_index; 2406ce110ea1SWei Hu cq->gdma_cq->id = cq_spec.queue_index; 2407ce110ea1SWei Hu 2408b685df31SWei Hu rxq->gdma_rq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION; 2409b685df31SWei Hu cq->gdma_cq->mem_info.dma_region_handle = GDMA_INVALID_DMA_REGION; 2410ce110ea1SWei Hu 2411ce110ea1SWei Hu rxq->gdma_id = rxq->gdma_rq->id; 2412ce110ea1SWei Hu cq->gdma_id = cq->gdma_cq->id; 2413ce110ea1SWei Hu 2414ce110ea1SWei Hu err = mana_push_wqe(rxq); 2415ce110ea1SWei Hu if (err) 2416ce110ea1SWei Hu goto out; 2417ce110ea1SWei Hu 2418027d0c1cSWei Hu if (cq->gdma_id >= gc->max_num_cqs) { 2419027d0c1cSWei Hu err = EINVAL; 2420ce110ea1SWei Hu goto out; 2421027d0c1cSWei Hu } 2422ce110ea1SWei Hu 2423ce110ea1SWei Hu gc->cq_table[cq->gdma_id] = cq->gdma_cq; 2424ce110ea1SWei Hu 24251833cf13SWei Hu /* Allocate and start the cleanup task on CQ */ 24261833cf13SWei Hu cq->do_not_ring_db = false; 24271833cf13SWei Hu 24281833cf13SWei Hu NET_TASK_INIT(&cq->cleanup_task, 0, mana_poll, cq); 24291833cf13SWei Hu cq->cleanup_tq = 24301833cf13SWei Hu taskqueue_create_fast("mana rx cq cleanup", 24311833cf13SWei Hu M_WAITOK, taskqueue_thread_enqueue, 24321833cf13SWei Hu &cq->cleanup_tq); 24331833cf13SWei Hu 24341833cf13SWei Hu if (apc->last_rx_cq_bind_cpu < 0) 24351833cf13SWei Hu apc->last_rx_cq_bind_cpu = CPU_FIRST(); 24361833cf13SWei Hu cq->cpu = apc->last_rx_cq_bind_cpu; 24371833cf13SWei Hu apc->last_rx_cq_bind_cpu = CPU_NEXT(apc->last_rx_cq_bind_cpu); 24381833cf13SWei Hu 24391833cf13SWei Hu if (apc->bind_cleanup_thread_cpu) { 24401833cf13SWei Hu cpuset_t cpu_mask; 24411833cf13SWei Hu CPU_SETOF(cq->cpu, &cpu_mask); 24421833cf13SWei Hu taskqueue_start_threads_cpuset(&cq->cleanup_tq, 24431833cf13SWei Hu 1, PI_NET, &cpu_mask, 24441833cf13SWei Hu "mana cq p%u-rx%u-cpu%d", 24451833cf13SWei Hu apc->port_idx, rxq->rxq_idx, cq->cpu); 24461833cf13SWei Hu } else { 24471833cf13SWei Hu taskqueue_start_threads(&cq->cleanup_tq, 1, 24481833cf13SWei Hu PI_NET, "mana cq p%u-rx%u", 24491833cf13SWei Hu apc->port_idx, rxq->rxq_idx); 24501833cf13SWei Hu } 24511833cf13SWei Hu 24521833cf13SWei Hu mana_gd_ring_cq(cq->gdma_cq, SET_ARM_BIT); 2453ce110ea1SWei Hu out: 2454ce110ea1SWei Hu if (!err) 2455ce110ea1SWei Hu return rxq; 2456ce110ea1SWei Hu 2457ce110ea1SWei Hu if_printf(ndev, "Failed to create RXQ: err = %d\n", err); 2458ce110ea1SWei Hu 2459ce110ea1SWei Hu mana_destroy_rxq(apc, rxq, false); 2460ce110ea1SWei Hu 2461ce110ea1SWei Hu if (cq) 2462ce110ea1SWei Hu mana_deinit_cq(apc, cq); 2463ce110ea1SWei Hu 2464ce110ea1SWei Hu return NULL; 2465ce110ea1SWei Hu } 2466ce110ea1SWei Hu 2467ce110ea1SWei Hu static int 246837d22ce0SJustin Hibbits mana_add_rx_queues(struct mana_port_context *apc, if_t ndev) 2469ce110ea1SWei Hu { 24701833cf13SWei Hu struct mana_context *ac = apc->ac; 2471ce110ea1SWei Hu struct mana_rxq *rxq; 2472ce110ea1SWei Hu int err = 0; 2473ce110ea1SWei Hu int i; 2474ce110ea1SWei Hu 2475ce110ea1SWei Hu for (i = 0; i < apc->num_queues; i++) { 24761833cf13SWei Hu rxq = mana_create_rxq(apc, i, &ac->eqs[i], ndev); 2477ce110ea1SWei Hu if (!rxq) { 2478ce110ea1SWei Hu err = ENOMEM; 2479ce110ea1SWei Hu goto out; 2480ce110ea1SWei Hu } 2481ce110ea1SWei Hu 2482ce110ea1SWei Hu apc->rxqs[i] = rxq; 2483ce110ea1SWei Hu } 2484ce110ea1SWei Hu 2485ce110ea1SWei Hu apc->default_rxobj = apc->rxqs[0]->rxobj; 2486ce110ea1SWei Hu out: 2487ce110ea1SWei Hu return err; 2488ce110ea1SWei Hu } 2489ce110ea1SWei Hu 2490ce110ea1SWei Hu static void 2491ce110ea1SWei Hu mana_destroy_vport(struct mana_port_context *apc) 2492ce110ea1SWei Hu { 2493ce110ea1SWei Hu struct mana_rxq *rxq; 2494ce110ea1SWei Hu uint32_t rxq_idx; 2495ce110ea1SWei Hu 2496ce110ea1SWei Hu for (rxq_idx = 0; rxq_idx < apc->num_queues; rxq_idx++) { 2497ce110ea1SWei Hu rxq = apc->rxqs[rxq_idx]; 2498ce110ea1SWei Hu if (!rxq) 2499ce110ea1SWei Hu continue; 2500ce110ea1SWei Hu 2501ce110ea1SWei Hu mana_destroy_rxq(apc, rxq, true); 2502ce110ea1SWei Hu apc->rxqs[rxq_idx] = NULL; 2503ce110ea1SWei Hu } 2504ce110ea1SWei Hu 2505ce110ea1SWei Hu mana_destroy_txq(apc); 2506b685df31SWei Hu 2507b685df31SWei Hu mana_uncfg_vport(apc); 2508ce110ea1SWei Hu } 2509ce110ea1SWei Hu 2510ce110ea1SWei Hu static int 251137d22ce0SJustin Hibbits mana_create_vport(struct mana_port_context *apc, if_t net) 2512ce110ea1SWei Hu { 2513ce110ea1SWei Hu struct gdma_dev *gd = apc->ac->gdma_dev; 2514ce110ea1SWei Hu int err; 2515ce110ea1SWei Hu 2516ce110ea1SWei Hu apc->default_rxobj = INVALID_MANA_HANDLE; 2517ce110ea1SWei Hu 2518ce110ea1SWei Hu err = mana_cfg_vport(apc, gd->pdid, gd->doorbell); 2519ce110ea1SWei Hu if (err) 2520ce110ea1SWei Hu return err; 2521ce110ea1SWei Hu 2522ce110ea1SWei Hu return mana_create_txq(apc, net); 2523ce110ea1SWei Hu } 2524ce110ea1SWei Hu 2525ce110ea1SWei Hu 2526ce110ea1SWei Hu static void mana_rss_table_init(struct mana_port_context *apc) 2527ce110ea1SWei Hu { 2528ce110ea1SWei Hu int i; 2529ce110ea1SWei Hu 2530ce110ea1SWei Hu for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) 2531ce110ea1SWei Hu apc->indir_table[i] = i % apc->num_queues; 2532ce110ea1SWei Hu } 2533ce110ea1SWei Hu 2534ce110ea1SWei Hu int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx, 2535ce110ea1SWei Hu bool update_hash, bool update_tab) 2536ce110ea1SWei Hu { 2537ce110ea1SWei Hu uint32_t queue_idx; 2538aa108bc7SWei Hu int err; 2539ce110ea1SWei Hu int i; 2540ce110ea1SWei Hu 2541ce110ea1SWei Hu if (update_tab) { 2542ce110ea1SWei Hu for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) { 2543ce110ea1SWei Hu queue_idx = apc->indir_table[i]; 2544ce110ea1SWei Hu apc->rxobj_table[i] = apc->rxqs[queue_idx]->rxobj; 2545ce110ea1SWei Hu } 2546ce110ea1SWei Hu } 2547ce110ea1SWei Hu 2548aa108bc7SWei Hu err = mana_cfg_vport_steering(apc, rx, true, update_hash, update_tab); 2549aa108bc7SWei Hu if (err) 2550aa108bc7SWei Hu return err; 2551aa108bc7SWei Hu 2552aa108bc7SWei Hu mana_fence_rqs(apc); 2553aa108bc7SWei Hu 2554aa108bc7SWei Hu return 0; 2555ce110ea1SWei Hu } 2556ce110ea1SWei Hu 2557ce110ea1SWei Hu static int 255837d22ce0SJustin Hibbits mana_init_port(if_t ndev) 2559ce110ea1SWei Hu { 2560ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ndev); 2561ce110ea1SWei Hu uint32_t max_txq, max_rxq, max_queues; 2562ce110ea1SWei Hu int port_idx = apc->port_idx; 2563ce110ea1SWei Hu uint32_t num_indirect_entries; 2564ce110ea1SWei Hu int err; 2565ce110ea1SWei Hu 2566ce110ea1SWei Hu err = mana_init_port_context(apc); 2567ce110ea1SWei Hu if (err) 2568ce110ea1SWei Hu return err; 2569ce110ea1SWei Hu 2570ce110ea1SWei Hu err = mana_query_vport_cfg(apc, port_idx, &max_txq, &max_rxq, 2571ce110ea1SWei Hu &num_indirect_entries); 2572ce110ea1SWei Hu if (err) { 2573027d0c1cSWei Hu if_printf(ndev, "Failed to query info for vPort %d\n", 2574027d0c1cSWei Hu port_idx); 2575ce110ea1SWei Hu goto reset_apc; 2576ce110ea1SWei Hu } 2577ce110ea1SWei Hu 2578ce110ea1SWei Hu max_queues = min_t(uint32_t, max_txq, max_rxq); 2579ce110ea1SWei Hu if (apc->max_queues > max_queues) 2580ce110ea1SWei Hu apc->max_queues = max_queues; 2581ce110ea1SWei Hu 2582ce110ea1SWei Hu if (apc->num_queues > apc->max_queues) 2583ce110ea1SWei Hu apc->num_queues = apc->max_queues; 2584ce110ea1SWei Hu 2585ce110ea1SWei Hu return 0; 2586ce110ea1SWei Hu 2587ce110ea1SWei Hu reset_apc: 2588ce110ea1SWei Hu bus_dma_tag_destroy(apc->rx_buf_tag); 2589ce110ea1SWei Hu apc->rx_buf_tag = NULL; 2590ce110ea1SWei Hu free(apc->rxqs, M_DEVBUF); 2591ce110ea1SWei Hu apc->rxqs = NULL; 2592ce110ea1SWei Hu return err; 2593ce110ea1SWei Hu } 2594ce110ea1SWei Hu 2595ce110ea1SWei Hu int 259637d22ce0SJustin Hibbits mana_alloc_queues(if_t ndev) 2597ce110ea1SWei Hu { 2598ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ndev); 2599ce110ea1SWei Hu int err; 2600ce110ea1SWei Hu 2601ce110ea1SWei Hu err = mana_create_vport(apc, ndev); 2602ce110ea1SWei Hu if (err) 26031833cf13SWei Hu return err; 2604ce110ea1SWei Hu 2605ce110ea1SWei Hu err = mana_add_rx_queues(apc, ndev); 2606ce110ea1SWei Hu if (err) 2607ce110ea1SWei Hu goto destroy_vport; 2608ce110ea1SWei Hu 2609ce110ea1SWei Hu apc->rss_state = apc->num_queues > 1 ? TRI_STATE_TRUE : TRI_STATE_FALSE; 2610ce110ea1SWei Hu 2611ce110ea1SWei Hu mana_rss_table_init(apc); 2612ce110ea1SWei Hu 2613ce110ea1SWei Hu err = mana_config_rss(apc, TRI_STATE_TRUE, true, true); 2614ce110ea1SWei Hu if (err) 2615ce110ea1SWei Hu goto destroy_vport; 2616ce110ea1SWei Hu 2617ce110ea1SWei Hu return 0; 2618ce110ea1SWei Hu 2619ce110ea1SWei Hu destroy_vport: 2620ce110ea1SWei Hu mana_destroy_vport(apc); 2621ce110ea1SWei Hu return err; 2622ce110ea1SWei Hu } 2623ce110ea1SWei Hu 2624ce110ea1SWei Hu static int 2625ce110ea1SWei Hu mana_up(struct mana_port_context *apc) 2626ce110ea1SWei Hu { 2627ce110ea1SWei Hu int err; 2628ce110ea1SWei Hu 2629ce110ea1SWei Hu mana_dbg(NULL, "mana_up called\n"); 2630ce110ea1SWei Hu 2631ce110ea1SWei Hu err = mana_alloc_queues(apc->ndev); 2632ce110ea1SWei Hu if (err) { 2633ce110ea1SWei Hu mana_err(NULL, "Faile alloc mana queues: %d\n", err); 2634ce110ea1SWei Hu return err; 2635ce110ea1SWei Hu } 2636ce110ea1SWei Hu 2637ce110ea1SWei Hu /* Add queue specific sysctl */ 2638ce110ea1SWei Hu mana_sysctl_add_queues(apc); 2639ce110ea1SWei Hu 2640ce110ea1SWei Hu apc->port_is_up = true; 2641ce110ea1SWei Hu 2642ce110ea1SWei Hu /* Ensure port state updated before txq state */ 2643ce110ea1SWei Hu wmb(); 2644ce110ea1SWei Hu 2645ce110ea1SWei Hu if_link_state_change(apc->ndev, LINK_STATE_UP); 2646ce110ea1SWei Hu if_setdrvflagbits(apc->ndev, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 2647ce110ea1SWei Hu 2648ce110ea1SWei Hu return 0; 2649ce110ea1SWei Hu } 2650ce110ea1SWei Hu 2651ce110ea1SWei Hu 2652ce110ea1SWei Hu static void 2653ce110ea1SWei Hu mana_init(void *arg) 2654ce110ea1SWei Hu { 2655ce110ea1SWei Hu struct mana_port_context *apc = (struct mana_port_context *)arg; 2656ce110ea1SWei Hu 2657ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 2658ce110ea1SWei Hu if (!apc->port_is_up) { 2659ce110ea1SWei Hu mana_up(apc); 2660ce110ea1SWei Hu } 2661ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 2662ce110ea1SWei Hu } 2663ce110ea1SWei Hu 2664ce110ea1SWei Hu static int 266537d22ce0SJustin Hibbits mana_dealloc_queues(if_t ndev) 2666ce110ea1SWei Hu { 2667ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ndev); 2668ce110ea1SWei Hu struct mana_txq *txq; 2669ce110ea1SWei Hu int i, err; 2670ce110ea1SWei Hu 2671ce110ea1SWei Hu if (apc->port_is_up) 2672ce110ea1SWei Hu return EINVAL; 2673ce110ea1SWei Hu 2674ce110ea1SWei Hu /* No packet can be transmitted now since apc->port_is_up is false. 2675ce110ea1SWei Hu * There is still a tiny chance that mana_poll_tx_cq() can re-enable 2676ce110ea1SWei Hu * a txq because it may not timely see apc->port_is_up being cleared 2677ce110ea1SWei Hu * to false, but it doesn't matter since mana_start_xmit() drops any 2678ce110ea1SWei Hu * new packets due to apc->port_is_up being false. 2679ce110ea1SWei Hu * 2680ce110ea1SWei Hu * Drain all the in-flight TX packets 2681ce110ea1SWei Hu */ 2682ce110ea1SWei Hu for (i = 0; i < apc->num_queues; i++) { 2683ce110ea1SWei Hu txq = &apc->tx_qp[i].txq; 2684ce110ea1SWei Hu 2685ce110ea1SWei Hu struct mana_cq *tx_cq = &apc->tx_qp[i].tx_cq; 26861833cf13SWei Hu struct mana_cq *rx_cq = &(apc->rxqs[i]->rx_cq); 26871833cf13SWei Hu 26881833cf13SWei Hu tx_cq->do_not_ring_db = true; 26891833cf13SWei Hu rx_cq->do_not_ring_db = true; 26901833cf13SWei Hu 2691ce110ea1SWei Hu /* Schedule a cleanup task */ 26921833cf13SWei Hu taskqueue_enqueue(tx_cq->cleanup_tq, &tx_cq->cleanup_task); 2693ce110ea1SWei Hu 2694ce110ea1SWei Hu while (atomic_read(&txq->pending_sends) > 0) 2695ce110ea1SWei Hu usleep_range(1000, 2000); 2696ce110ea1SWei Hu } 2697ce110ea1SWei Hu 2698ce110ea1SWei Hu /* We're 100% sure the queues can no longer be woken up, because 2699ce110ea1SWei Hu * we're sure now mana_poll_tx_cq() can't be running. 2700ce110ea1SWei Hu */ 2701ce110ea1SWei Hu 2702ce110ea1SWei Hu apc->rss_state = TRI_STATE_FALSE; 2703ce110ea1SWei Hu err = mana_config_rss(apc, TRI_STATE_FALSE, false, false); 2704ce110ea1SWei Hu if (err) { 2705ce110ea1SWei Hu if_printf(ndev, "Failed to disable vPort: %d\n", err); 2706ce110ea1SWei Hu return err; 2707ce110ea1SWei Hu } 2708ce110ea1SWei Hu 2709ce110ea1SWei Hu mana_destroy_vport(apc); 2710ce110ea1SWei Hu 2711ce110ea1SWei Hu return 0; 2712ce110ea1SWei Hu } 2713ce110ea1SWei Hu 2714ce110ea1SWei Hu static int 2715ce110ea1SWei Hu mana_down(struct mana_port_context *apc) 2716ce110ea1SWei Hu { 2717ce110ea1SWei Hu int err = 0; 2718ce110ea1SWei Hu 2719ce110ea1SWei Hu apc->port_st_save = apc->port_is_up; 2720ce110ea1SWei Hu apc->port_is_up = false; 2721ce110ea1SWei Hu 2722ce110ea1SWei Hu /* Ensure port state updated before txq state */ 2723ce110ea1SWei Hu wmb(); 2724ce110ea1SWei Hu 2725ce110ea1SWei Hu if (apc->port_st_save) { 2726ce110ea1SWei Hu if_setdrvflagbits(apc->ndev, IFF_DRV_OACTIVE, 2727ce110ea1SWei Hu IFF_DRV_RUNNING); 2728ce110ea1SWei Hu if_link_state_change(apc->ndev, LINK_STATE_DOWN); 2729ce110ea1SWei Hu 2730ce110ea1SWei Hu mana_sysctl_free_queues(apc); 2731ce110ea1SWei Hu 2732ce110ea1SWei Hu err = mana_dealloc_queues(apc->ndev); 2733ce110ea1SWei Hu if (err) { 2734ce110ea1SWei Hu if_printf(apc->ndev, 2735ce110ea1SWei Hu "Failed to bring down mana interface: %d\n", err); 2736ce110ea1SWei Hu } 2737ce110ea1SWei Hu } 2738ce110ea1SWei Hu 2739ce110ea1SWei Hu return err; 2740ce110ea1SWei Hu } 2741ce110ea1SWei Hu 2742ce110ea1SWei Hu int 274337d22ce0SJustin Hibbits mana_detach(if_t ndev) 2744ce110ea1SWei Hu { 2745ce110ea1SWei Hu struct mana_port_context *apc = if_getsoftc(ndev); 2746ce110ea1SWei Hu int err; 2747ce110ea1SWei Hu 2748ce110ea1SWei Hu ether_ifdetach(ndev); 2749ce110ea1SWei Hu 2750ce110ea1SWei Hu if (!apc) 2751ce110ea1SWei Hu return 0; 2752ce110ea1SWei Hu 2753ce110ea1SWei Hu MANA_APC_LOCK_LOCK(apc); 2754ce110ea1SWei Hu err = mana_down(apc); 2755ce110ea1SWei Hu MANA_APC_LOCK_UNLOCK(apc); 2756ce110ea1SWei Hu 2757ce110ea1SWei Hu mana_cleanup_port_context(apc); 2758ce110ea1SWei Hu 2759ce110ea1SWei Hu MANA_APC_LOCK_DESTROY(apc); 2760ce110ea1SWei Hu 2761ce110ea1SWei Hu free(apc, M_DEVBUF); 2762ce110ea1SWei Hu 2763ce110ea1SWei Hu return err; 2764ce110ea1SWei Hu } 2765ce110ea1SWei Hu 2766ce110ea1SWei Hu static int 2767ce110ea1SWei Hu mana_probe_port(struct mana_context *ac, int port_idx, 276837d22ce0SJustin Hibbits if_t *ndev_storage) 2769ce110ea1SWei Hu { 2770ce110ea1SWei Hu struct gdma_context *gc = ac->gdma_dev->gdma_context; 2771ce110ea1SWei Hu struct mana_port_context *apc; 2772643fd7b4SWei Hu uint32_t hwassist; 277337d22ce0SJustin Hibbits if_t ndev; 2774ce110ea1SWei Hu int err; 2775ce110ea1SWei Hu 2776ce110ea1SWei Hu ndev = if_alloc_dev(IFT_ETHER, gc->dev); 2777ce110ea1SWei Hu *ndev_storage = ndev; 2778ce110ea1SWei Hu 2779ce110ea1SWei Hu apc = malloc(sizeof(*apc), M_DEVBUF, M_WAITOK | M_ZERO); 2780ce110ea1SWei Hu apc->ac = ac; 2781ce110ea1SWei Hu apc->ndev = ndev; 2782ce110ea1SWei Hu apc->max_queues = gc->max_num_queues; 2783ce110ea1SWei Hu apc->num_queues = min_t(unsigned int, 2784ce110ea1SWei Hu gc->max_num_queues, MANA_MAX_NUM_QUEUES); 2785ce110ea1SWei Hu apc->port_handle = INVALID_MANA_HANDLE; 2786ce110ea1SWei Hu apc->port_idx = port_idx; 2787ce110ea1SWei Hu apc->frame_size = DEFAULT_FRAME_SIZE; 27881833cf13SWei Hu apc->last_tx_cq_bind_cpu = -1; 27891833cf13SWei Hu apc->last_rx_cq_bind_cpu = -1; 2790b685df31SWei Hu apc->vport_use_count = 0; 2791ce110ea1SWei Hu 2792ce110ea1SWei Hu MANA_APC_LOCK_INIT(apc); 2793ce110ea1SWei Hu 2794ce110ea1SWei Hu if_initname(ndev, device_get_name(gc->dev), port_idx); 2795ce110ea1SWei Hu if_setdev(ndev,gc->dev); 2796ce110ea1SWei Hu if_setsoftc(ndev, apc); 2797ce110ea1SWei Hu 2798ce110ea1SWei Hu if_setflags(ndev, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 2799ce110ea1SWei Hu if_setinitfn(ndev, mana_init); 2800ce110ea1SWei Hu if_settransmitfn(ndev, mana_start_xmit); 2801ce110ea1SWei Hu if_setqflushfn(ndev, mana_qflush); 2802ce110ea1SWei Hu if_setioctlfn(ndev, mana_ioctl); 2803ce110ea1SWei Hu if_setgetcounterfn(ndev, mana_get_counter); 2804ce110ea1SWei Hu 2805ce110ea1SWei Hu if_setmtu(ndev, ETHERMTU); 2806ce110ea1SWei Hu if_setbaudrate(ndev, IF_Gbps(100)); 2807ce110ea1SWei Hu 2808ce110ea1SWei Hu mana_rss_key_fill(apc->hashkey, MANA_HASH_KEY_SIZE); 2809ce110ea1SWei Hu 2810ce110ea1SWei Hu err = mana_init_port(ndev); 2811ce110ea1SWei Hu if (err) 2812ce110ea1SWei Hu goto reset_apc; 2813ce110ea1SWei Hu 281437d22ce0SJustin Hibbits if_setcapabilitiesbit(ndev, 281537d22ce0SJustin Hibbits IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 | 281637d22ce0SJustin Hibbits IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | 281737d22ce0SJustin Hibbits IFCAP_TSO4 | IFCAP_TSO6 | 281837d22ce0SJustin Hibbits IFCAP_LRO | IFCAP_LINKSTATE, 0); 2819ce110ea1SWei Hu 2820ce110ea1SWei Hu /* Enable all available capabilities by default. */ 282137d22ce0SJustin Hibbits if_setcapenable(ndev, if_getcapabilities(ndev)); 2822ce110ea1SWei Hu 2823ce110ea1SWei Hu /* TSO parameters */ 2824643fd7b4SWei Hu if_sethwtsomax(ndev, MANA_TSO_MAX_SZ - 282537d22ce0SJustin Hibbits (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN)); 282637d22ce0SJustin Hibbits if_sethwtsomaxsegcount(ndev, MAX_MBUF_FRAGS); 282737d22ce0SJustin Hibbits if_sethwtsomaxsegsize(ndev, PAGE_SIZE); 2828ce110ea1SWei Hu 2829643fd7b4SWei Hu hwassist = 0; 2830643fd7b4SWei Hu if (if_getcapenable(ndev) & (IFCAP_TSO4 | IFCAP_TSO6)) 2831643fd7b4SWei Hu hwassist |= CSUM_TSO; 2832643fd7b4SWei Hu if (if_getcapenable(ndev) & IFCAP_TXCSUM) 2833643fd7b4SWei Hu hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); 2834643fd7b4SWei Hu if (if_getcapenable(ndev) & IFCAP_TXCSUM_IPV6) 2835643fd7b4SWei Hu hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 2836643fd7b4SWei Hu mana_dbg(NULL, "set hwassist 0x%x\n", hwassist); 2837643fd7b4SWei Hu if_sethwassist(ndev, hwassist); 2838643fd7b4SWei Hu 2839ce110ea1SWei Hu ifmedia_init(&apc->media, IFM_IMASK, 2840ce110ea1SWei Hu mana_ifmedia_change, mana_ifmedia_status); 2841ce110ea1SWei Hu ifmedia_add(&apc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2842ce110ea1SWei Hu ifmedia_set(&apc->media, IFM_ETHER | IFM_AUTO); 2843ce110ea1SWei Hu 2844ce110ea1SWei Hu ether_ifattach(ndev, apc->mac_addr); 2845ce110ea1SWei Hu 2846ce110ea1SWei Hu /* Initialize statistics */ 2847ce110ea1SWei Hu mana_alloc_counters((counter_u64_t *)&apc->port_stats, 2848ce110ea1SWei Hu sizeof(struct mana_port_stats)); 2849ce110ea1SWei Hu mana_sysctl_add_port(apc); 2850ce110ea1SWei Hu 2851ce110ea1SWei Hu /* Tell the stack that the interface is not active */ 2852ce110ea1SWei Hu if_setdrvflagbits(ndev, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 2853ce110ea1SWei Hu 2854ce110ea1SWei Hu return 0; 2855ce110ea1SWei Hu 2856ce110ea1SWei Hu reset_apc: 2857ce110ea1SWei Hu free(apc, M_DEVBUF); 2858ce110ea1SWei Hu *ndev_storage = NULL; 2859ce110ea1SWei Hu if_printf(ndev, "Failed to probe vPort %d: %d\n", port_idx, err); 2860ce110ea1SWei Hu if_free(ndev); 2861ce110ea1SWei Hu return err; 2862ce110ea1SWei Hu } 2863ce110ea1SWei Hu 2864ce110ea1SWei Hu int mana_probe(struct gdma_dev *gd) 2865ce110ea1SWei Hu { 2866ce110ea1SWei Hu struct gdma_context *gc = gd->gdma_context; 2867ce110ea1SWei Hu device_t dev = gc->dev; 2868ce110ea1SWei Hu struct mana_context *ac; 2869ce110ea1SWei Hu int err; 2870ce110ea1SWei Hu int i; 2871ce110ea1SWei Hu 2872ce110ea1SWei Hu device_printf(dev, "%s protocol version: %d.%d.%d\n", DEVICE_NAME, 2873ce110ea1SWei Hu MANA_MAJOR_VERSION, MANA_MINOR_VERSION, MANA_MICRO_VERSION); 2874ce110ea1SWei Hu 2875ce110ea1SWei Hu err = mana_gd_register_device(gd); 2876ce110ea1SWei Hu if (err) 2877ce110ea1SWei Hu return err; 2878ce110ea1SWei Hu 2879ce110ea1SWei Hu ac = malloc(sizeof(*ac), M_DEVBUF, M_WAITOK | M_ZERO); 2880ce110ea1SWei Hu ac->gdma_dev = gd; 2881ce110ea1SWei Hu ac->num_ports = 1; 2882ce110ea1SWei Hu gd->driver_data = ac; 2883ce110ea1SWei Hu 28841833cf13SWei Hu err = mana_create_eq(ac); 28851833cf13SWei Hu if (err) 28861833cf13SWei Hu goto out; 28871833cf13SWei Hu 2888ce110ea1SWei Hu err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION, MANA_MINOR_VERSION, 2889ce110ea1SWei Hu MANA_MICRO_VERSION, &ac->num_ports); 2890ce110ea1SWei Hu if (err) 2891ce110ea1SWei Hu goto out; 2892ce110ea1SWei Hu 2893ce110ea1SWei Hu if (ac->num_ports > MAX_PORTS_IN_MANA_DEV) 2894ce110ea1SWei Hu ac->num_ports = MAX_PORTS_IN_MANA_DEV; 2895ce110ea1SWei Hu 2896ce110ea1SWei Hu for (i = 0; i < ac->num_ports; i++) { 2897ce110ea1SWei Hu err = mana_probe_port(ac, i, &ac->ports[i]); 2898ce110ea1SWei Hu if (err) { 2899ce110ea1SWei Hu device_printf(dev, 2900ce110ea1SWei Hu "Failed to probe mana port %d\n", i); 2901ce110ea1SWei Hu break; 2902ce110ea1SWei Hu } 2903ce110ea1SWei Hu } 2904ce110ea1SWei Hu 2905ce110ea1SWei Hu out: 2906ce110ea1SWei Hu if (err) 2907ce110ea1SWei Hu mana_remove(gd); 2908ce110ea1SWei Hu 2909ce110ea1SWei Hu return err; 2910ce110ea1SWei Hu } 2911ce110ea1SWei Hu 2912ce110ea1SWei Hu void 2913ce110ea1SWei Hu mana_remove(struct gdma_dev *gd) 2914ce110ea1SWei Hu { 2915ce110ea1SWei Hu struct gdma_context *gc = gd->gdma_context; 2916ce110ea1SWei Hu struct mana_context *ac = gd->driver_data; 2917ce110ea1SWei Hu device_t dev = gc->dev; 291837d22ce0SJustin Hibbits if_t ndev; 2919ce110ea1SWei Hu int i; 2920ce110ea1SWei Hu 2921ce110ea1SWei Hu for (i = 0; i < ac->num_ports; i++) { 2922ce110ea1SWei Hu ndev = ac->ports[i]; 2923ce110ea1SWei Hu if (!ndev) { 2924ce110ea1SWei Hu if (i == 0) 2925ce110ea1SWei Hu device_printf(dev, "No net device to remove\n"); 2926ce110ea1SWei Hu goto out; 2927ce110ea1SWei Hu } 2928ce110ea1SWei Hu 2929ce110ea1SWei Hu mana_detach(ndev); 2930ce110ea1SWei Hu 2931ce110ea1SWei Hu if_free(ndev); 2932ce110ea1SWei Hu } 29331833cf13SWei Hu 29341833cf13SWei Hu mana_destroy_eq(ac); 29351833cf13SWei Hu 2936ce110ea1SWei Hu out: 2937ce110ea1SWei Hu mana_gd_deregister_device(gd); 2938ce110ea1SWei Hu gd->driver_data = NULL; 2939ce110ea1SWei Hu gd->gdma_context = NULL; 2940ce110ea1SWei Hu free(ac, M_DEVBUF); 2941ce110ea1SWei Hu } 2942