1*51248bbdSyasuoka /* $OpenBSD: if_iavf.c,v 1.18 2024/11/27 02:40:53 yasuoka Exp $ */ 24ccba60fSjmatthew 34ccba60fSjmatthew /* 44ccba60fSjmatthew * Copyright (c) 2013-2015, Intel Corporation 54ccba60fSjmatthew * All rights reserved. 64ccba60fSjmatthew 74ccba60fSjmatthew * Redistribution and use in source and binary forms, with or without 84ccba60fSjmatthew * modification, are permitted provided that the following conditions are met: 94ccba60fSjmatthew * 104ccba60fSjmatthew * 1. Redistributions of source code must retain the above copyright notice, 114ccba60fSjmatthew * this list of conditions and the following disclaimer. 124ccba60fSjmatthew * 134ccba60fSjmatthew * 2. Redistributions in binary form must reproduce the above copyright 144ccba60fSjmatthew * notice, this list of conditions and the following disclaimer in the 154ccba60fSjmatthew * documentation and/or other materials provided with the distribution. 164ccba60fSjmatthew * 174ccba60fSjmatthew * 3. Neither the name of the Intel Corporation nor the names of its 184ccba60fSjmatthew * contributors may be used to endorse or promote products derived from 194ccba60fSjmatthew * this software without specific prior written permission. 204ccba60fSjmatthew * 214ccba60fSjmatthew * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 224ccba60fSjmatthew * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 234ccba60fSjmatthew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 244ccba60fSjmatthew * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 254ccba60fSjmatthew * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 264ccba60fSjmatthew * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 274ccba60fSjmatthew * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 284ccba60fSjmatthew * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 294ccba60fSjmatthew * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 304ccba60fSjmatthew * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 314ccba60fSjmatthew * POSSIBILITY OF SUCH DAMAGE. 324ccba60fSjmatthew */ 334ccba60fSjmatthew 344ccba60fSjmatthew /* 354ccba60fSjmatthew * Copyright (c) 2016,2017 David Gwynne <dlg@openbsd.org> 364ccba60fSjmatthew * Copyright (c) 2019 Jonathan Matthew <jmatthew@openbsd.org> 374ccba60fSjmatthew * 384ccba60fSjmatthew * Permission to use, copy, modify, and distribute this software for any 394ccba60fSjmatthew * purpose with or without fee is hereby granted, provided that the above 404ccba60fSjmatthew * copyright notice and this permission notice appear in all copies. 414ccba60fSjmatthew * 424ccba60fSjmatthew * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 434ccba60fSjmatthew * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 444ccba60fSjmatthew * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 454ccba60fSjmatthew * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 464ccba60fSjmatthew * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 474ccba60fSjmatthew * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 484ccba60fSjmatthew * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 494ccba60fSjmatthew */ 504ccba60fSjmatthew 514ccba60fSjmatthew #include "bpfilter.h" 52*51248bbdSyasuoka #include "vlan.h" 534ccba60fSjmatthew 544ccba60fSjmatthew #include <sys/param.h> 554ccba60fSjmatthew #include <sys/systm.h> 564ccba60fSjmatthew #include <sys/proc.h> 574ccba60fSjmatthew #include <sys/sockio.h> 584ccba60fSjmatthew #include <sys/mbuf.h> 594ccba60fSjmatthew #include <sys/socket.h> 604ccba60fSjmatthew #include <sys/device.h> 614ccba60fSjmatthew #include <sys/pool.h> 624ccba60fSjmatthew #include <sys/queue.h> 634ccba60fSjmatthew #include <sys/timeout.h> 644ccba60fSjmatthew #include <sys/task.h> 654ccba60fSjmatthew #include <sys/syslog.h> 664ccba60fSjmatthew 674ccba60fSjmatthew #include <machine/bus.h> 684ccba60fSjmatthew #include <machine/intr.h> 694ccba60fSjmatthew 704ccba60fSjmatthew #include <net/if.h> 714ccba60fSjmatthew #include <net/if_media.h> 724ccba60fSjmatthew 734ccba60fSjmatthew #if NBPFILTER > 0 744ccba60fSjmatthew #include <net/bpf.h> 754ccba60fSjmatthew #endif 764ccba60fSjmatthew 774ccba60fSjmatthew #include <netinet/in.h> 784ccba60fSjmatthew #include <netinet/if_ether.h> 79*51248bbdSyasuoka #include <netinet/udp.h> 804ccba60fSjmatthew 814ccba60fSjmatthew #include <dev/pci/pcireg.h> 824ccba60fSjmatthew #include <dev/pci/pcivar.h> 834ccba60fSjmatthew #include <dev/pci/pcidevs.h> 844ccba60fSjmatthew 854ccba60fSjmatthew #define I40E_MASK(mask, shift) ((mask) << (shift)) 864ccba60fSjmatthew #define I40E_AQ_LARGE_BUF 512 874ccba60fSjmatthew 882fa30b92Sjmatthew #define IAVF_REG_VFR 0xdeadbeef 892fa30b92Sjmatthew 904ccba60fSjmatthew #define IAVF_VFR_INPROGRESS 0 914ccba60fSjmatthew #define IAVF_VFR_COMPLETED 1 924ccba60fSjmatthew #define IAVF_VFR_VFACTIVE 2 934ccba60fSjmatthew 944ccba60fSjmatthew #include <dev/pci/if_ixlreg.h> 954ccba60fSjmatthew 964ccba60fSjmatthew struct iavf_aq_desc { 974ccba60fSjmatthew uint16_t iaq_flags; 984ccba60fSjmatthew #define IAVF_AQ_DD (1U << 0) 994ccba60fSjmatthew #define IAVF_AQ_CMP (1U << 1) 1004ccba60fSjmatthew #define IAVF_AQ_ERR (1U << 2) 1014ccba60fSjmatthew #define IAVF_AQ_VFE (1U << 3) 1024ccba60fSjmatthew #define IAVF_AQ_LB (1U << 9) 1034ccba60fSjmatthew #define IAVF_AQ_RD (1U << 10) 1044ccba60fSjmatthew #define IAVF_AQ_VFC (1U << 11) 1054ccba60fSjmatthew #define IAVF_AQ_BUF (1U << 12) 1064ccba60fSjmatthew #define IAVF_AQ_SI (1U << 13) 1074ccba60fSjmatthew #define IAVF_AQ_EI (1U << 14) 1084ccba60fSjmatthew #define IAVF_AQ_FE (1U << 15) 1094ccba60fSjmatthew 1104ccba60fSjmatthew #define IAVF_AQ_FLAGS_FMT "\020" "\020FE" "\017EI" "\016SI" "\015BUF" \ 1114ccba60fSjmatthew "\014VFC" "\013DB" "\012LB" "\004VFE" \ 1124ccba60fSjmatthew "\003ERR" "\002CMP" "\001DD" 1134ccba60fSjmatthew 1144ccba60fSjmatthew uint16_t iaq_opcode; 1154ccba60fSjmatthew 1164ccba60fSjmatthew uint16_t iaq_datalen; 1174ccba60fSjmatthew uint16_t iaq_retval; 1184ccba60fSjmatthew 1194ccba60fSjmatthew uint32_t iaq_vc_opcode; 1204ccba60fSjmatthew uint32_t iaq_vc_retval; 1214ccba60fSjmatthew 1224ccba60fSjmatthew uint32_t iaq_param[4]; 1234ccba60fSjmatthew /* iaq_vfid iaq_param[0] */ 1244ccba60fSjmatthew /* iaq_data_hi iaq_param[2] */ 1254ccba60fSjmatthew /* iaq_data_lo iaq_param[3] */ 1264ccba60fSjmatthew } __packed __aligned(8); 1274ccba60fSjmatthew 1284ccba60fSjmatthew /* aq commands */ 1294ccba60fSjmatthew #define IAVF_AQ_OP_SEND_TO_PF 0x0801 1304ccba60fSjmatthew #define IAVF_AQ_OP_MSG_FROM_PF 0x0802 1314ccba60fSjmatthew #define IAVF_AQ_OP_SHUTDOWN 0x0803 1324ccba60fSjmatthew 1334ccba60fSjmatthew /* virt channel messages */ 1344ccba60fSjmatthew #define IAVF_VC_OP_VERSION 1 1354ccba60fSjmatthew #define IAVF_VC_OP_RESET_VF 2 1364ccba60fSjmatthew #define IAVF_VC_OP_GET_VF_RESOURCES 3 1374ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_TX_QUEUE 4 1384ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_RX_QUEUE 5 1394ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_VSI_QUEUES 6 1404ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_IRQ_MAP 7 1414ccba60fSjmatthew #define IAVF_VC_OP_ENABLE_QUEUES 8 1424ccba60fSjmatthew #define IAVF_VC_OP_DISABLE_QUEUES 9 1434ccba60fSjmatthew #define IAVF_VC_OP_ADD_ETH_ADDR 10 1444ccba60fSjmatthew #define IAVF_VC_OP_DEL_ETH_ADDR 11 1454ccba60fSjmatthew #define IAVF_VC_OP_ADD_VLAN 12 1464ccba60fSjmatthew #define IAVF_VC_OP_DEL_VLAN 13 1474ccba60fSjmatthew #define IAVF_VC_OP_CONFIG_PROMISC 14 1484ccba60fSjmatthew #define IAVF_VC_OP_GET_STATS 15 1494ccba60fSjmatthew #define IAVF_VC_OP_EVENT 17 1504ccba60fSjmatthew #define IAVF_VC_OP_GET_RSS_HENA_CAPS 25 1514ccba60fSjmatthew #define IAVF_VC_OP_SET_RSS_HENA 26 1524ccba60fSjmatthew 1534ccba60fSjmatthew /* virt channel response codes */ 1544ccba60fSjmatthew #define IAVF_VC_RC_SUCCESS 0 1554ccba60fSjmatthew #define IAVF_VC_RC_ERR_PARAM -5 1564ccba60fSjmatthew #define IAVF_VC_RC_ERR_OPCODE -38 1574ccba60fSjmatthew #define IAVF_VC_RC_ERR_CQP_COMPL -39 1584ccba60fSjmatthew #define IAVF_VC_RC_ERR_VF_ID -40 1594ccba60fSjmatthew #define IAVF_VC_RC_ERR_NOT_SUP -64 1604ccba60fSjmatthew 1614ccba60fSjmatthew /* virt channel events */ 1624ccba60fSjmatthew #define IAVF_VC_EVENT_LINK_CHANGE 1 1634ccba60fSjmatthew #define IAVF_VC_EVENT_RESET_IMPENDING 2 1644ccba60fSjmatthew #define IAVF_VC_EVENT_PF_DRIVER_CLOSE 3 1654ccba60fSjmatthew 1664ccba60fSjmatthew /* virt channel offloads */ 1674ccba60fSjmatthew #define IAVF_VC_OFFLOAD_L2 0x00000001 1684ccba60fSjmatthew #define IAVF_VC_OFFLOAD_IWARP 0x00000002 1694ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSVD 0x00000004 1704ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_AQ 0x00000008 1714ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_REG 0x00000010 1724ccba60fSjmatthew #define IAVF_VC_OFFLOAD_WB_ON_ITR 0x00000020 1734ccba60fSjmatthew #define IAVF_VC_OFFLOAD_VLAN 0x00010000 1744ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RX_POLLING 0x00020000 1754ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_PCTYPE_V2 0x00040000 1764ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RSS_PF 0x00080000 1774ccba60fSjmatthew #define IAVF_VC_OFFLOAD_ENCAP 0x00100000 1784ccba60fSjmatthew #define IAVF_VC_OFFLOAD_ENCAP_CSUM 0x00200000 1794ccba60fSjmatthew #define IAVF_VC_OFFLOAD_RX_ENCAP_CSUM 0x00400000 1804ccba60fSjmatthew 1814ccba60fSjmatthew /* link speeds */ 1824ccba60fSjmatthew #define IAVF_VC_LINK_SPEED_100MB 0x1 1834ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_1000MB 0x2 1844ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_10GB 0x3 1854ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_40GB 0x4 1864ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_20GB 0x5 1874ccba60fSjmatthew #define IAVC_VC_LINK_SPEED_25GB 0x6 1884ccba60fSjmatthew 189baed872eSjmatthew struct iavf_link_speed { 190baed872eSjmatthew uint64_t baudrate; 191baed872eSjmatthew uint64_t media; 192baed872eSjmatthew }; 193baed872eSjmatthew 194baed872eSjmatthew static const struct iavf_link_speed iavf_link_speeds[] = { 195baed872eSjmatthew { 0, 0 }, 196baed872eSjmatthew { IF_Mbps(100), IFM_100_TX }, 197baed872eSjmatthew { IF_Mbps(1000), IFM_1000_T }, 198baed872eSjmatthew { IF_Gbps(10), IFM_10G_T }, 199baed872eSjmatthew { IF_Gbps(40), IFM_40G_CR4 }, 200baed872eSjmatthew { IF_Gbps(20), IFM_20G_KR2 }, 201baed872eSjmatthew { IF_Gbps(25), IFM_25G_CR } 202baed872eSjmatthew }; 203baed872eSjmatthew 2044ccba60fSjmatthew 2054ccba60fSjmatthew struct iavf_vc_version_info { 2064ccba60fSjmatthew uint32_t major; 2074ccba60fSjmatthew uint32_t minor; 2084ccba60fSjmatthew } __packed; 2094ccba60fSjmatthew 2104ccba60fSjmatthew struct iavf_vc_txq_info { 2114ccba60fSjmatthew uint16_t vsi_id; 2124ccba60fSjmatthew uint16_t queue_id; 2134ccba60fSjmatthew uint16_t ring_len; 2144ccba60fSjmatthew uint16_t headwb_ena; /* deprecated */ 2154ccba60fSjmatthew uint64_t dma_ring_addr; 2164ccba60fSjmatthew uint64_t dma_headwb_addr; /* deprecated */ 2174ccba60fSjmatthew } __packed; 2184ccba60fSjmatthew 2194ccba60fSjmatthew struct iavf_vc_rxq_info { 2204ccba60fSjmatthew uint16_t vsi_id; 2214ccba60fSjmatthew uint16_t queue_id; 2224ccba60fSjmatthew uint32_t ring_len; 2234ccba60fSjmatthew uint16_t hdr_size; 2244ccba60fSjmatthew uint16_t splithdr_ena; 2254ccba60fSjmatthew uint32_t databuf_size; 2264ccba60fSjmatthew uint32_t max_pkt_size; 2274ccba60fSjmatthew uint32_t pad1; 2284ccba60fSjmatthew uint64_t dma_ring_addr; 2294ccba60fSjmatthew uint32_t rx_split_pos; 2304ccba60fSjmatthew uint32_t pad2; 2314ccba60fSjmatthew } __packed; 2324ccba60fSjmatthew 2334ccba60fSjmatthew struct iavf_vc_queue_pair_info { 2344ccba60fSjmatthew struct iavf_vc_txq_info txq; 2354ccba60fSjmatthew struct iavf_vc_rxq_info rxq; 2364ccba60fSjmatthew } __packed; 2374ccba60fSjmatthew 2384ccba60fSjmatthew struct iavf_vc_queue_config_info { 2394ccba60fSjmatthew uint16_t vsi_id; 2404ccba60fSjmatthew uint16_t num_queue_pairs; 2414ccba60fSjmatthew uint32_t pad; 2424ccba60fSjmatthew struct iavf_vc_queue_pair_info qpair[1]; 2434ccba60fSjmatthew } __packed; 2444ccba60fSjmatthew 2454ccba60fSjmatthew struct iavf_vc_vector_map { 2464ccba60fSjmatthew uint16_t vsi_id; 2474ccba60fSjmatthew uint16_t vector_id; 2484ccba60fSjmatthew uint16_t rxq_map; 2494ccba60fSjmatthew uint16_t txq_map; 2504ccba60fSjmatthew uint16_t rxitr_idx; 2514ccba60fSjmatthew uint16_t txitr_idx; 2524ccba60fSjmatthew } __packed; 2534ccba60fSjmatthew 2544ccba60fSjmatthew struct iavf_vc_irq_map_info { 2554ccba60fSjmatthew uint16_t num_vectors; 2564ccba60fSjmatthew struct iavf_vc_vector_map vecmap[1]; 2574ccba60fSjmatthew } __packed; 2584ccba60fSjmatthew 2594ccba60fSjmatthew struct iavf_vc_queue_select { 2604ccba60fSjmatthew uint16_t vsi_id; 2614ccba60fSjmatthew uint16_t pad; 2624ccba60fSjmatthew uint32_t rx_queues; 2634ccba60fSjmatthew uint32_t tx_queues; 2644ccba60fSjmatthew } __packed; 2654ccba60fSjmatthew 2664ccba60fSjmatthew struct iavf_vc_vsi_resource { 2674ccba60fSjmatthew uint16_t vsi_id; 2684ccba60fSjmatthew uint16_t num_queue_pairs; 2694ccba60fSjmatthew uint32_t vsi_type; 2704ccba60fSjmatthew uint16_t qset_handle; 2714ccba60fSjmatthew uint8_t default_mac[ETHER_ADDR_LEN]; 2724ccba60fSjmatthew } __packed; 2734ccba60fSjmatthew 2744ccba60fSjmatthew struct iavf_vc_vf_resource { 2754ccba60fSjmatthew uint16_t num_vsis; 2764ccba60fSjmatthew uint16_t num_qp; 2774ccba60fSjmatthew uint16_t max_vectors; 2784ccba60fSjmatthew uint16_t max_mtu; 2794ccba60fSjmatthew uint32_t offload_flags; 2804ccba60fSjmatthew uint32_t rss_key_size; 2814ccba60fSjmatthew uint32_t rss_lut_size; 2824ccba60fSjmatthew struct iavf_vc_vsi_resource vsi_res[1]; 2834ccba60fSjmatthew } __packed; 2844ccba60fSjmatthew 2854ccba60fSjmatthew struct iavf_vc_eth_addr { 2864ccba60fSjmatthew uint8_t addr[ETHER_ADDR_LEN]; 2874ccba60fSjmatthew uint8_t pad[2]; 2884ccba60fSjmatthew } __packed; 2894ccba60fSjmatthew 2904ccba60fSjmatthew struct iavf_vc_eth_addr_list { 2914ccba60fSjmatthew uint16_t vsi_id; 2924ccba60fSjmatthew uint16_t num_elements; 2934ccba60fSjmatthew struct iavf_vc_eth_addr list[1]; 2944ccba60fSjmatthew } __packed; 2954ccba60fSjmatthew 2964ccba60fSjmatthew struct iavf_vc_vlan_list { 2974ccba60fSjmatthew uint16_t vsi_id; 2984ccba60fSjmatthew uint16_t num_elements; 2994ccba60fSjmatthew uint16_t vlan_id[1]; 3004ccba60fSjmatthew } __packed; 3014ccba60fSjmatthew 3024ccba60fSjmatthew struct iavf_vc_promisc_info { 3034ccba60fSjmatthew uint16_t vsi_id; 3044ccba60fSjmatthew uint16_t flags; 3054ccba60fSjmatthew #define IAVF_FLAG_VF_UNICAST_PROMISC 0x0001 3064ccba60fSjmatthew #define IAVF_FLAG_VF_MULTICAST_PROMISC 0x0002 3074ccba60fSjmatthew } __packed; 3084ccba60fSjmatthew 3094ccba60fSjmatthew struct iavf_vc_pf_event { 3104ccba60fSjmatthew uint32_t event; 3114ccba60fSjmatthew uint32_t link_speed; 3124ccba60fSjmatthew uint8_t link_status; 3134ccba60fSjmatthew uint8_t pad[3]; 3144ccba60fSjmatthew uint32_t severity; 3154ccba60fSjmatthew } __packed; 3164ccba60fSjmatthew 3174ccba60fSjmatthew /* aq response codes */ 3184ccba60fSjmatthew #define IAVF_AQ_RC_OK 0 /* success */ 3194ccba60fSjmatthew #define IAVF_AQ_RC_EPERM 1 /* Operation not permitted */ 3204ccba60fSjmatthew #define IAVF_AQ_RC_ENOENT 2 /* No such element */ 3214ccba60fSjmatthew #define IAVF_AQ_RC_ESRCH 3 /* Bad opcode */ 3224ccba60fSjmatthew #define IAVF_AQ_RC_EINTR 4 /* operation interrupted */ 3234ccba60fSjmatthew #define IAVF_AQ_RC_EIO 5 /* I/O error */ 3244ccba60fSjmatthew #define IAVF_AQ_RC_ENXIO 6 /* No such resource */ 3254ccba60fSjmatthew #define IAVF_AQ_RC_E2BIG 7 /* Arg too long */ 3264ccba60fSjmatthew #define IAVF_AQ_RC_EAGAIN 8 /* Try again */ 3274ccba60fSjmatthew #define IAVF_AQ_RC_ENOMEM 9 /* Out of memory */ 3284ccba60fSjmatthew #define IAVF_AQ_RC_EACCES 10 /* Permission denied */ 3294ccba60fSjmatthew #define IAVF_AQ_RC_EFAULT 11 /* Bad address */ 3304ccba60fSjmatthew #define IAVF_AQ_RC_EBUSY 12 /* Device or resource busy */ 3314ccba60fSjmatthew #define IAVF_AQ_RC_EEXIST 13 /* object already exists */ 3324ccba60fSjmatthew #define IAVF_AQ_RC_EINVAL 14 /* invalid argument */ 3334ccba60fSjmatthew #define IAVF_AQ_RC_ENOTTY 15 /* not a typewriter */ 3344ccba60fSjmatthew #define IAVF_AQ_RC_ENOSPC 16 /* No space or alloc failure */ 3354ccba60fSjmatthew #define IAVF_AQ_RC_ENOSYS 17 /* function not implemented */ 3364ccba60fSjmatthew #define IAVF_AQ_RC_ERANGE 18 /* parameter out of range */ 3374ccba60fSjmatthew #define IAVF_AQ_RC_EFLUSHED 19 /* cmd flushed due to prev error */ 3384ccba60fSjmatthew #define IAVF_AQ_RC_BAD_ADDR 20 /* contains a bad pointer */ 3394ccba60fSjmatthew #define IAVF_AQ_RC_EMODE 21 /* not allowed in current mode */ 3404ccba60fSjmatthew #define IAVF_AQ_RC_EFBIG 22 /* file too large */ 3414ccba60fSjmatthew 3424ccba60fSjmatthew struct iavf_tx_desc { 3434ccba60fSjmatthew uint64_t addr; 3444ccba60fSjmatthew uint64_t cmd; 3454ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_SHIFT 0 3464ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_MASK (0xfULL << IAVF_TX_DESC_DTYPE_SHIFT) 3474ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_DATA (0x0ULL << IAVF_TX_DESC_DTYPE_SHIFT) 3484ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_NOP (0x1ULL << IAVF_TX_DESC_DTYPE_SHIFT) 3494ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_CONTEXT (0x1ULL << IAVF_TX_DESC_DTYPE_SHIFT) 3504ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FCOE_CTX (0x2ULL << IAVF_TX_DESC_DTYPE_SHIFT) 3514ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FD (0x8ULL << IAVF_TX_DESC_DTYPE_SHIFT) 3524ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_DDP_CTX (0x9ULL << IAVF_TX_DESC_DTYPE_SHIFT) 3534ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FLEX_DATA (0xbULL << IAVF_TX_DESC_DTYPE_SHIFT) 3544ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FLEX_CTX_1 (0xcULL << IAVF_TX_DESC_DTYPE_SHIFT) 3554ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_FLEX_CTX_2 (0xdULL << IAVF_TX_DESC_DTYPE_SHIFT) 3564ccba60fSjmatthew #define IAVF_TX_DESC_DTYPE_DONE (0xfULL << IAVF_TX_DESC_DTYPE_SHIFT) 3574ccba60fSjmatthew 3584ccba60fSjmatthew #define IAVF_TX_DESC_CMD_SHIFT 4 3594ccba60fSjmatthew #define IAVF_TX_DESC_CMD_MASK (0x3ffULL << IAVF_TX_DESC_CMD_SHIFT) 3604ccba60fSjmatthew #define IAVF_TX_DESC_CMD_EOP (0x001 << IAVF_TX_DESC_CMD_SHIFT) 3614ccba60fSjmatthew #define IAVF_TX_DESC_CMD_RS (0x002 << IAVF_TX_DESC_CMD_SHIFT) 3624ccba60fSjmatthew #define IAVF_TX_DESC_CMD_ICRC (0x004 << IAVF_TX_DESC_CMD_SHIFT) 3634ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IL2TAG1 (0x008 << IAVF_TX_DESC_CMD_SHIFT) 3644ccba60fSjmatthew #define IAVF_TX_DESC_CMD_DUMMY (0x010 << IAVF_TX_DESC_CMD_SHIFT) 3654ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_MASK (0x060 << IAVF_TX_DESC_CMD_SHIFT) 3664ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_NONIP (0x000 << IAVF_TX_DESC_CMD_SHIFT) 3674ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_IPV6 (0x020 << IAVF_TX_DESC_CMD_SHIFT) 3684ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_IPV4 (0x040 << IAVF_TX_DESC_CMD_SHIFT) 3694ccba60fSjmatthew #define IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM (0x060 << IAVF_TX_DESC_CMD_SHIFT) 3704ccba60fSjmatthew #define IAVF_TX_DESC_CMD_FCOET (0x080 << IAVF_TX_DESC_CMD_SHIFT) 3714ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_MASK (0x300 << IAVF_TX_DESC_CMD_SHIFT) 3724ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_UNK (0x000 << IAVF_TX_DESC_CMD_SHIFT) 3734ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_TCP (0x100 << IAVF_TX_DESC_CMD_SHIFT) 3744ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_SCTP (0x200 << IAVF_TX_DESC_CMD_SHIFT) 3754ccba60fSjmatthew #define IAVF_TX_DESC_CMD_L4T_EOFT_UDP (0x300 << IAVF_TX_DESC_CMD_SHIFT) 3764ccba60fSjmatthew 3774ccba60fSjmatthew #define IAVF_TX_DESC_MACLEN_SHIFT 16 3784ccba60fSjmatthew #define IAVF_TX_DESC_MACLEN_MASK (0x7fULL << IAVF_TX_DESC_MACLEN_SHIFT) 3794ccba60fSjmatthew #define IAVF_TX_DESC_IPLEN_SHIFT 23 3804ccba60fSjmatthew #define IAVF_TX_DESC_IPLEN_MASK (0x7fULL << IAVF_TX_DESC_IPLEN_SHIFT) 3814ccba60fSjmatthew #define IAVF_TX_DESC_L4LEN_SHIFT 30 3824ccba60fSjmatthew #define IAVF_TX_DESC_L4LEN_MASK (0xfULL << IAVF_TX_DESC_L4LEN_SHIFT) 3834ccba60fSjmatthew #define IAVF_TX_DESC_FCLEN_SHIFT 30 3844ccba60fSjmatthew #define IAVF_TX_DESC_FCLEN_MASK (0xfULL << IAVF_TX_DESC_FCLEN_SHIFT) 3854ccba60fSjmatthew 3864ccba60fSjmatthew #define IAVF_TX_DESC_BSIZE_SHIFT 34 3874ccba60fSjmatthew #define IAVF_TX_DESC_BSIZE_MAX 0x3fffULL 3884ccba60fSjmatthew #define IAVF_TX_DESC_BSIZE_MASK \ 3894ccba60fSjmatthew (IAVF_TX_DESC_BSIZE_MAX << IAVF_TX_DESC_BSIZE_SHIFT) 3903e0b52e8Sjmatthew 3913e0b52e8Sjmatthew #define IAVF_TX_DESC_L2TAG1_SHIFT 48 3923e0b52e8Sjmatthew #define IAVF_TX_DESC_L2TAG1_MASK (0xffff << IAVF_TX_DESC_L2TAG1_SHIFT) 3934ccba60fSjmatthew } __packed __aligned(16); 3944ccba60fSjmatthew 3954ccba60fSjmatthew struct iavf_rx_rd_desc_16 { 3964ccba60fSjmatthew uint64_t paddr; /* packet addr */ 3974ccba60fSjmatthew uint64_t haddr; /* header addr */ 3984ccba60fSjmatthew } __packed __aligned(16); 3994ccba60fSjmatthew 4004ccba60fSjmatthew struct iavf_rx_rd_desc_32 { 4014ccba60fSjmatthew uint64_t paddr; /* packet addr */ 4024ccba60fSjmatthew uint64_t haddr; /* header addr */ 4034ccba60fSjmatthew uint64_t _reserved1; 4044ccba60fSjmatthew uint64_t _reserved2; 4054ccba60fSjmatthew } __packed __aligned(16); 4064ccba60fSjmatthew 4074ccba60fSjmatthew struct iavf_rx_wb_desc_16 { 4084ccba60fSjmatthew uint64_t qword0; 4093e0b52e8Sjmatthew #define IAVF_RX_DESC_L2TAG1_SHIFT 16 4103e0b52e8Sjmatthew #define IAVF_RX_DESC_L2TAG1_MASK (0xffff << IAVF_RX_DESC_L2TAG1_SHIFT) 4114ccba60fSjmatthew uint64_t qword1; 4124ccba60fSjmatthew #define IAVF_RX_DESC_DD (1 << 0) 4134ccba60fSjmatthew #define IAVF_RX_DESC_EOP (1 << 1) 4144ccba60fSjmatthew #define IAVF_RX_DESC_L2TAG1P (1 << 2) 4154ccba60fSjmatthew #define IAVF_RX_DESC_L3L4P (1 << 3) 4164ccba60fSjmatthew #define IAVF_RX_DESC_CRCP (1 << 4) 4174ccba60fSjmatthew #define IAVF_RX_DESC_TSYNINDX_SHIFT 5 /* TSYNINDX */ 4184ccba60fSjmatthew #define IAVF_RX_DESC_TSYNINDX_MASK (7 << IAVF_RX_DESC_TSYNINDX_SHIFT) 4194ccba60fSjmatthew #define IAVF_RX_DESC_UMB_SHIFT 9 4204ccba60fSjmatthew #define IAVF_RX_DESC_UMB_MASK (0x3 << IAVF_RX_DESC_UMB_SHIFT) 4214ccba60fSjmatthew #define IAVF_RX_DESC_UMB_UCAST (0x0 << IAVF_RX_DESC_UMB_SHIFT) 4224ccba60fSjmatthew #define IAVF_RX_DESC_UMB_MCAST (0x1 << IAVF_RX_DESC_UMB_SHIFT) 4234ccba60fSjmatthew #define IAVF_RX_DESC_UMB_BCAST (0x2 << IAVF_RX_DESC_UMB_SHIFT) 4244ccba60fSjmatthew #define IAVF_RX_DESC_UMB_MIRROR (0x3 << IAVF_RX_DESC_UMB_SHIFT) 4254ccba60fSjmatthew #define IAVF_RX_DESC_FLM (1 << 11) 4264ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_SHIFT 12 4274ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_MASK (0x3 << IAVF_RX_DESC_FLTSTAT_SHIFT) 4284ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_NODATA (0x0 << IAVF_RX_DESC_FLTSTAT_SHIFT) 4294ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_FDFILTID (0x1 << IAVF_RX_DESC_FLTSTAT_SHIFT) 4304ccba60fSjmatthew #define IAVF_RX_DESC_FLTSTAT_RSS (0x3 << IAVF_RX_DESC_FLTSTAT_SHIFT) 4314ccba60fSjmatthew #define IAVF_RX_DESC_LPBK (1 << 14) 4324ccba60fSjmatthew #define IAVF_RX_DESC_IPV6EXTADD (1 << 15) 4334ccba60fSjmatthew #define IAVF_RX_DESC_INT_UDP_0 (1 << 18) 4344ccba60fSjmatthew 4354ccba60fSjmatthew #define IAVF_RX_DESC_RXE (1 << 19) 4364ccba60fSjmatthew #define IAVF_RX_DESC_HBO (1 << 21) 4374ccba60fSjmatthew #define IAVF_RX_DESC_IPE (1 << 22) 4384ccba60fSjmatthew #define IAVF_RX_DESC_L4E (1 << 23) 4394ccba60fSjmatthew #define IAVF_RX_DESC_EIPE (1 << 24) 4404ccba60fSjmatthew #define IAVF_RX_DESC_OVERSIZE (1 << 25) 4414ccba60fSjmatthew 4424ccba60fSjmatthew #define IAVF_RX_DESC_PTYPE_SHIFT 30 4434ccba60fSjmatthew #define IAVF_RX_DESC_PTYPE_MASK (0xffULL << IAVF_RX_DESC_PTYPE_SHIFT) 4444ccba60fSjmatthew 4454ccba60fSjmatthew #define IAVF_RX_DESC_PLEN_SHIFT 38 4464ccba60fSjmatthew #define IAVF_RX_DESC_PLEN_MASK (0x3fffULL << IAVF_RX_DESC_PLEN_SHIFT) 4474ccba60fSjmatthew #define IAVF_RX_DESC_HLEN_SHIFT 42 4484ccba60fSjmatthew #define IAVF_RX_DESC_HLEN_MASK (0x7ffULL << IAVF_RX_DESC_HLEN_SHIFT) 4494ccba60fSjmatthew } __packed __aligned(16); 4504ccba60fSjmatthew 4514ccba60fSjmatthew struct iavf_rx_wb_desc_32 { 4524ccba60fSjmatthew uint64_t qword0; 4534ccba60fSjmatthew uint64_t qword1; 4544ccba60fSjmatthew uint64_t qword2; 4554ccba60fSjmatthew uint64_t qword3; 4564ccba60fSjmatthew } __packed __aligned(16); 4574ccba60fSjmatthew 4584ccba60fSjmatthew 4594ccba60fSjmatthew #define IAVF_VF_MAJOR 1 4604ccba60fSjmatthew #define IAVF_VF_MINOR 1 4614ccba60fSjmatthew 4624ccba60fSjmatthew #define IAVF_TX_PKT_DESCS 8 4634ccba60fSjmatthew #define IAVF_TX_QUEUE_ALIGN 128 4644ccba60fSjmatthew #define IAVF_RX_QUEUE_ALIGN 128 4654ccba60fSjmatthew 4664ccba60fSjmatthew #define IAVF_HARDMTU 9712 /* 9726 - ETHER_HDR_LEN */ 4674ccba60fSjmatthew 4684ccba60fSjmatthew #define IAVF_PCIREG PCI_MAPREG_START 4694ccba60fSjmatthew 4704ccba60fSjmatthew #define IAVF_ITR0 0x0 4714ccba60fSjmatthew #define IAVF_ITR1 0x1 4724ccba60fSjmatthew #define IAVF_ITR2 0x2 4734ccba60fSjmatthew #define IAVF_NOITR 0x3 4744ccba60fSjmatthew 4754ccba60fSjmatthew #define IAVF_AQ_NUM 256 4764ccba60fSjmatthew #define IAVF_AQ_MASK (IAVF_AQ_NUM - 1) 4774ccba60fSjmatthew #define IAVF_AQ_ALIGN 64 /* lol */ 4784ccba60fSjmatthew #define IAVF_AQ_BUFLEN 4096 4794ccba60fSjmatthew 4804ccba60fSjmatthew struct iavf_aq_regs { 4814ccba60fSjmatthew bus_size_t atq_tail; 4824ccba60fSjmatthew bus_size_t atq_head; 4834ccba60fSjmatthew bus_size_t atq_len; 4844ccba60fSjmatthew bus_size_t atq_bal; 4854ccba60fSjmatthew bus_size_t atq_bah; 4864ccba60fSjmatthew 4874ccba60fSjmatthew bus_size_t arq_tail; 4884ccba60fSjmatthew bus_size_t arq_head; 4894ccba60fSjmatthew bus_size_t arq_len; 4904ccba60fSjmatthew bus_size_t arq_bal; 4914ccba60fSjmatthew bus_size_t arq_bah; 4924ccba60fSjmatthew 4934ccba60fSjmatthew uint32_t atq_len_enable; 4944ccba60fSjmatthew uint32_t atq_tail_mask; 4954ccba60fSjmatthew uint32_t atq_head_mask; 4964ccba60fSjmatthew 4974ccba60fSjmatthew uint32_t arq_len_enable; 4984ccba60fSjmatthew uint32_t arq_tail_mask; 4994ccba60fSjmatthew uint32_t arq_head_mask; 5004ccba60fSjmatthew }; 5014ccba60fSjmatthew 5024ccba60fSjmatthew struct iavf_aq_buf { 5034ccba60fSjmatthew SIMPLEQ_ENTRY(iavf_aq_buf) 5044ccba60fSjmatthew aqb_entry; 5054ccba60fSjmatthew void *aqb_data; 5064ccba60fSjmatthew bus_dmamap_t aqb_map; 5074ccba60fSjmatthew }; 5084ccba60fSjmatthew SIMPLEQ_HEAD(iavf_aq_bufs, iavf_aq_buf); 5094ccba60fSjmatthew 5104ccba60fSjmatthew struct iavf_dmamem { 5114ccba60fSjmatthew bus_dmamap_t ixm_map; 5124ccba60fSjmatthew bus_dma_segment_t ixm_seg; 5134ccba60fSjmatthew int ixm_nsegs; 5144ccba60fSjmatthew size_t ixm_size; 5154ccba60fSjmatthew caddr_t ixm_kva; 5164ccba60fSjmatthew }; 5174ccba60fSjmatthew #define IAVF_DMA_MAP(_ixm) ((_ixm)->ixm_map) 5184ccba60fSjmatthew #define IAVF_DMA_DVA(_ixm) ((_ixm)->ixm_map->dm_segs[0].ds_addr) 5194ccba60fSjmatthew #define IAVF_DMA_KVA(_ixm) ((void *)(_ixm)->ixm_kva) 5204ccba60fSjmatthew #define IAVF_DMA_LEN(_ixm) ((_ixm)->ixm_size) 5214ccba60fSjmatthew 5224ccba60fSjmatthew struct iavf_tx_map { 5234ccba60fSjmatthew struct mbuf *txm_m; 5244ccba60fSjmatthew bus_dmamap_t txm_map; 5254ccba60fSjmatthew unsigned int txm_eop; 5264ccba60fSjmatthew }; 5274ccba60fSjmatthew 5284ccba60fSjmatthew struct iavf_tx_ring { 5294ccba60fSjmatthew unsigned int txr_prod; 5304ccba60fSjmatthew unsigned int txr_cons; 5314ccba60fSjmatthew 5324ccba60fSjmatthew struct iavf_tx_map *txr_maps; 5334ccba60fSjmatthew struct iavf_dmamem txr_mem; 5344ccba60fSjmatthew 5354ccba60fSjmatthew bus_size_t txr_tail; 5364ccba60fSjmatthew unsigned int txr_qid; 5374ccba60fSjmatthew }; 5384ccba60fSjmatthew 5394ccba60fSjmatthew struct iavf_rx_map { 5404ccba60fSjmatthew struct mbuf *rxm_m; 5414ccba60fSjmatthew bus_dmamap_t rxm_map; 5424ccba60fSjmatthew }; 5434ccba60fSjmatthew 5444ccba60fSjmatthew struct iavf_rx_ring { 5454ccba60fSjmatthew struct iavf_softc *rxr_sc; 5464ccba60fSjmatthew 5474ccba60fSjmatthew struct if_rxring rxr_acct; 5484ccba60fSjmatthew struct timeout rxr_refill; 5494ccba60fSjmatthew 5504ccba60fSjmatthew unsigned int rxr_prod; 5514ccba60fSjmatthew unsigned int rxr_cons; 5524ccba60fSjmatthew 5534ccba60fSjmatthew struct iavf_rx_map *rxr_maps; 5544ccba60fSjmatthew struct iavf_dmamem rxr_mem; 5554ccba60fSjmatthew 5564ccba60fSjmatthew struct mbuf *rxr_m_head; 5574ccba60fSjmatthew struct mbuf **rxr_m_tail; 5584ccba60fSjmatthew 5594ccba60fSjmatthew bus_size_t rxr_tail; 5604ccba60fSjmatthew unsigned int rxr_qid; 5614ccba60fSjmatthew }; 5624ccba60fSjmatthew 5634ccba60fSjmatthew struct iavf_softc { 5644ccba60fSjmatthew struct device sc_dev; 5654ccba60fSjmatthew struct arpcom sc_ac; 5664ccba60fSjmatthew struct ifmedia sc_media; 5674ccba60fSjmatthew uint64_t sc_media_status; 5684ccba60fSjmatthew uint64_t sc_media_active; 5694ccba60fSjmatthew 5704ccba60fSjmatthew pci_chipset_tag_t sc_pc; 5714ccba60fSjmatthew pci_intr_handle_t sc_ih; 5724ccba60fSjmatthew void *sc_ihc; 5734ccba60fSjmatthew pcitag_t sc_tag; 5744ccba60fSjmatthew 5754ccba60fSjmatthew bus_dma_tag_t sc_dmat; 5764ccba60fSjmatthew bus_space_tag_t sc_memt; 5774ccba60fSjmatthew bus_space_handle_t sc_memh; 5784ccba60fSjmatthew bus_size_t sc_mems; 5794ccba60fSjmatthew 5804ccba60fSjmatthew uint32_t sc_major_ver; 5814ccba60fSjmatthew uint32_t sc_minor_ver; 5824ccba60fSjmatthew 5834ccba60fSjmatthew int sc_got_vf_resources; 5844ccba60fSjmatthew int sc_got_irq_map; 5854ccba60fSjmatthew uint32_t sc_vf_id; 5864ccba60fSjmatthew uint16_t sc_vsi_id; 5874ccba60fSjmatthew uint16_t sc_qset_handle; 5884ccba60fSjmatthew unsigned int sc_base_queue; 5894ccba60fSjmatthew 5904ccba60fSjmatthew struct cond sc_admin_cond; 5914ccba60fSjmatthew int sc_admin_result; 5924ccba60fSjmatthew struct timeout sc_admin_timeout; 5934ccba60fSjmatthew 5944ccba60fSjmatthew struct iavf_dmamem sc_scratch; 5954ccba60fSjmatthew 5964ccba60fSjmatthew const struct iavf_aq_regs * 5974ccba60fSjmatthew sc_aq_regs; 5984ccba60fSjmatthew 5994ccba60fSjmatthew struct mutex sc_atq_mtx; 6004ccba60fSjmatthew struct iavf_dmamem sc_atq; 6014ccba60fSjmatthew unsigned int sc_atq_prod; 6024ccba60fSjmatthew unsigned int sc_atq_cons; 6034ccba60fSjmatthew 6044ccba60fSjmatthew struct iavf_dmamem sc_arq; 6054ccba60fSjmatthew struct iavf_aq_bufs sc_arq_idle; 6064ccba60fSjmatthew struct iavf_aq_bufs sc_arq_live; 6074ccba60fSjmatthew struct if_rxring sc_arq_ring; 6084ccba60fSjmatthew unsigned int sc_arq_prod; 6094ccba60fSjmatthew unsigned int sc_arq_cons; 6104ccba60fSjmatthew 6112fa30b92Sjmatthew struct task sc_reset_task; 6122fa30b92Sjmatthew int sc_resetting; 6134ccba60fSjmatthew 6144ccba60fSjmatthew unsigned int sc_tx_ring_ndescs; 6154ccba60fSjmatthew unsigned int sc_rx_ring_ndescs; 6164ccba60fSjmatthew unsigned int sc_nqueues; /* 1 << sc_nqueues */ 6174ccba60fSjmatthew 6184ccba60fSjmatthew struct rwlock sc_cfg_lock; 6194ccba60fSjmatthew unsigned int sc_dead; 6204ccba60fSjmatthew 6214ccba60fSjmatthew uint8_t sc_enaddr[ETHER_ADDR_LEN]; 6224ccba60fSjmatthew }; 6234ccba60fSjmatthew #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname) 6244ccba60fSjmatthew 6254ccba60fSjmatthew #define delaymsec(_ms) delay(1000 * (_ms)) 6264ccba60fSjmatthew 6274ccba60fSjmatthew static int iavf_dmamem_alloc(struct iavf_softc *, struct iavf_dmamem *, 6284ccba60fSjmatthew bus_size_t, u_int); 6294ccba60fSjmatthew static void iavf_dmamem_free(struct iavf_softc *, struct iavf_dmamem *); 6304ccba60fSjmatthew 631e13657b7Sjmatthew static int iavf_arq_fill(struct iavf_softc *, int); 6324ccba60fSjmatthew static void iavf_arq_unfill(struct iavf_softc *); 6334ccba60fSjmatthew static void iavf_arq_timeout(void *); 6344ccba60fSjmatthew static int iavf_arq_wait(struct iavf_softc *, int); 6354ccba60fSjmatthew 6364ccba60fSjmatthew static int iavf_atq_post(struct iavf_softc *, struct iavf_aq_desc *); 6374ccba60fSjmatthew static void iavf_atq_done(struct iavf_softc *); 6384ccba60fSjmatthew 6392fa30b92Sjmatthew static void iavf_init_admin_queue(struct iavf_softc *); 6402fa30b92Sjmatthew 6414ccba60fSjmatthew static int iavf_get_version(struct iavf_softc *); 6424ccba60fSjmatthew static int iavf_get_vf_resources(struct iavf_softc *); 6434ccba60fSjmatthew static int iavf_config_irq_map(struct iavf_softc *); 6444ccba60fSjmatthew 6454ccba60fSjmatthew static int iavf_add_del_addr(struct iavf_softc *, uint8_t *, int); 646e13657b7Sjmatthew static int iavf_process_arq(struct iavf_softc *, int); 6474ccba60fSjmatthew 6484ccba60fSjmatthew static int iavf_match(struct device *, void *, void *); 6494ccba60fSjmatthew static void iavf_attach(struct device *, struct device *, void *); 6504ccba60fSjmatthew 6514ccba60fSjmatthew static int iavf_media_change(struct ifnet *); 6524ccba60fSjmatthew static void iavf_media_status(struct ifnet *, struct ifmediareq *); 6534ccba60fSjmatthew static void iavf_watchdog(struct ifnet *); 6544ccba60fSjmatthew static int iavf_ioctl(struct ifnet *, u_long, caddr_t); 6554ccba60fSjmatthew static void iavf_start(struct ifqueue *); 6564ccba60fSjmatthew static int iavf_intr(void *); 6574ccba60fSjmatthew static int iavf_up(struct iavf_softc *); 6584ccba60fSjmatthew static int iavf_down(struct iavf_softc *); 6594ccba60fSjmatthew static int iavf_iff(struct iavf_softc *); 6602fa30b92Sjmatthew static void iavf_reset(void *); 6614ccba60fSjmatthew 6624ccba60fSjmatthew static struct iavf_tx_ring * 6634ccba60fSjmatthew iavf_txr_alloc(struct iavf_softc *, unsigned int); 6644ccba60fSjmatthew static void iavf_txr_clean(struct iavf_softc *, struct iavf_tx_ring *); 6654ccba60fSjmatthew static void iavf_txr_free(struct iavf_softc *, struct iavf_tx_ring *); 6664ccba60fSjmatthew static int iavf_txeof(struct iavf_softc *, struct ifqueue *); 6674ccba60fSjmatthew 6684ccba60fSjmatthew static struct iavf_rx_ring * 6694ccba60fSjmatthew iavf_rxr_alloc(struct iavf_softc *, unsigned int); 6704ccba60fSjmatthew static void iavf_rxr_clean(struct iavf_softc *, struct iavf_rx_ring *); 6714ccba60fSjmatthew static void iavf_rxr_free(struct iavf_softc *, struct iavf_rx_ring *); 6724ccba60fSjmatthew static int iavf_rxeof(struct iavf_softc *, struct ifiqueue *); 6734ccba60fSjmatthew static void iavf_rxfill(struct iavf_softc *, struct iavf_rx_ring *); 6744ccba60fSjmatthew static void iavf_rxrefill(void *); 6754ccba60fSjmatthew static int iavf_rxrinfo(struct iavf_softc *, struct if_rxrinfo *); 6764ccba60fSjmatthew 6774ccba60fSjmatthew struct cfdriver iavf_cd = { 6784ccba60fSjmatthew NULL, 6794ccba60fSjmatthew "iavf", 6804ccba60fSjmatthew DV_IFNET, 6814ccba60fSjmatthew }; 6824ccba60fSjmatthew 6838d2c75e4Smpi const struct cfattach iavf_ca = { 6844ccba60fSjmatthew sizeof(struct iavf_softc), 6854ccba60fSjmatthew iavf_match, 6864ccba60fSjmatthew iavf_attach, 6874ccba60fSjmatthew }; 6884ccba60fSjmatthew 6894ccba60fSjmatthew static const struct iavf_aq_regs iavf_aq_regs = { 6904ccba60fSjmatthew .atq_tail = I40E_VF_ATQT1, 6914ccba60fSjmatthew .atq_tail_mask = I40E_VF_ATQT1_ATQT_MASK, 6924ccba60fSjmatthew .atq_head = I40E_VF_ATQH1, 6934ccba60fSjmatthew .atq_head_mask = I40E_VF_ARQH1_ARQH_MASK, 6944ccba60fSjmatthew .atq_len = I40E_VF_ATQLEN1, 6954ccba60fSjmatthew .atq_bal = I40E_VF_ATQBAL1, 6964ccba60fSjmatthew .atq_bah = I40E_VF_ATQBAH1, 6974ccba60fSjmatthew .atq_len_enable = I40E_VF_ATQLEN1_ATQENABLE_MASK, 6984ccba60fSjmatthew 6994ccba60fSjmatthew .arq_tail = I40E_VF_ARQT1, 7004ccba60fSjmatthew .arq_tail_mask = I40E_VF_ARQT1_ARQT_MASK, 7014ccba60fSjmatthew .arq_head = I40E_VF_ARQH1, 7024ccba60fSjmatthew .arq_head_mask = I40E_VF_ARQH1_ARQH_MASK, 7034ccba60fSjmatthew .arq_len = I40E_VF_ARQLEN1, 7044ccba60fSjmatthew .arq_bal = I40E_VF_ARQBAL1, 7054ccba60fSjmatthew .arq_bah = I40E_VF_ARQBAH1, 7064ccba60fSjmatthew .arq_len_enable = I40E_VF_ARQLEN1_ARQENABLE_MASK, 7074ccba60fSjmatthew }; 7084ccba60fSjmatthew 7094ccba60fSjmatthew #define iavf_rd(_s, _r) \ 7104ccba60fSjmatthew bus_space_read_4((_s)->sc_memt, (_s)->sc_memh, (_r)) 7114ccba60fSjmatthew #define iavf_wr(_s, _r, _v) \ 7124ccba60fSjmatthew bus_space_write_4((_s)->sc_memt, (_s)->sc_memh, (_r), (_v)) 7134ccba60fSjmatthew #define iavf_barrier(_s, _r, _l, _o) \ 7144ccba60fSjmatthew bus_space_barrier((_s)->sc_memt, (_s)->sc_memh, (_r), (_l), (_o)) 7154ccba60fSjmatthew #define iavf_intr_enable(_s) \ 7164ccba60fSjmatthew iavf_wr((_s), I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL0_INTENA_MASK | \ 7174ccba60fSjmatthew I40E_VFINT_DYN_CTL0_CLEARPBA_MASK | \ 7184ccba60fSjmatthew (IAVF_NOITR << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT)); \ 7194ccba60fSjmatthew iavf_wr((_s), I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK) 7204ccba60fSjmatthew 7214ccba60fSjmatthew #define iavf_nqueues(_sc) (1 << (_sc)->sc_nqueues) 7221f28ec92Sjmatthew #define iavf_allqueues(_sc) ((1 << ((_sc)->sc_nqueues+1)) - 1) 7234ccba60fSjmatthew 7244ccba60fSjmatthew #ifdef __LP64__ 7254ccba60fSjmatthew #define iavf_dmamem_hi(_ixm) (uint32_t)(IAVF_DMA_DVA(_ixm) >> 32) 7264ccba60fSjmatthew #else 7274ccba60fSjmatthew #define iavf_dmamem_hi(_ixm) 0 7284ccba60fSjmatthew #endif 7294ccba60fSjmatthew 7304ccba60fSjmatthew #define iavf_dmamem_lo(_ixm) (uint32_t)IAVF_DMA_DVA(_ixm) 7314ccba60fSjmatthew 7324ccba60fSjmatthew static inline void 7334ccba60fSjmatthew iavf_aq_dva(struct iavf_aq_desc *iaq, bus_addr_t addr) 7344ccba60fSjmatthew { 7354ccba60fSjmatthew #ifdef __LP64__ 7364ccba60fSjmatthew htolem32(&iaq->iaq_param[2], addr >> 32); 7374ccba60fSjmatthew #else 7384ccba60fSjmatthew iaq->iaq_param[2] = htole32(0); 7394ccba60fSjmatthew #endif 7404ccba60fSjmatthew htolem32(&iaq->iaq_param[3], addr); 7414ccba60fSjmatthew } 7424ccba60fSjmatthew 7434ccba60fSjmatthew #if _BYTE_ORDER == _BIG_ENDIAN 7444ccba60fSjmatthew #define HTOLE16(_x) (uint16_t)(((_x) & 0xff) << 8 | ((_x) & 0xff00) >> 8) 7454ccba60fSjmatthew #else 7464ccba60fSjmatthew #define HTOLE16(_x) (_x) 7474ccba60fSjmatthew #endif 7484ccba60fSjmatthew 7494ccba60fSjmatthew static const struct pci_matchid iavf_devices[] = { 7504ccba60fSjmatthew { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_VF }, 7514ccba60fSjmatthew { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_XL710_VF_HV }, 7524ccba60fSjmatthew { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X722_VF }, 7534ccba60fSjmatthew { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ADAPTIVE_VF }, 7544ccba60fSjmatthew }; 7554ccba60fSjmatthew 7564ccba60fSjmatthew static int 7574ccba60fSjmatthew iavf_match(struct device *parent, void *match, void *aux) 7584ccba60fSjmatthew { 7594ccba60fSjmatthew return (pci_matchbyid(aux, iavf_devices, nitems(iavf_devices))); 7604ccba60fSjmatthew } 7614ccba60fSjmatthew 7624ccba60fSjmatthew void 7634ccba60fSjmatthew iavf_attach(struct device *parent, struct device *self, void *aux) 7644ccba60fSjmatthew { 7654ccba60fSjmatthew struct iavf_softc *sc = (struct iavf_softc *)self; 7664ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 7674ccba60fSjmatthew struct pci_attach_args *pa = aux; 7684ccba60fSjmatthew pcireg_t memtype; 7694ccba60fSjmatthew int tries; 7704ccba60fSjmatthew 7714ccba60fSjmatthew rw_init(&sc->sc_cfg_lock, "iavfcfg"); 7724ccba60fSjmatthew 7734ccba60fSjmatthew sc->sc_pc = pa->pa_pc; 7744ccba60fSjmatthew sc->sc_tag = pa->pa_tag; 7754ccba60fSjmatthew sc->sc_dmat = pa->pa_dmat; 7764ccba60fSjmatthew sc->sc_aq_regs = &iavf_aq_regs; 7774ccba60fSjmatthew 7784ccba60fSjmatthew sc->sc_nqueues = 0; /* 1 << 0 is 1 queue */ 7794ccba60fSjmatthew sc->sc_tx_ring_ndescs = 1024; 7804ccba60fSjmatthew sc->sc_rx_ring_ndescs = 1024; 7814ccba60fSjmatthew 7824ccba60fSjmatthew memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, IAVF_PCIREG); 7834ccba60fSjmatthew if (pci_mapreg_map(pa, IAVF_PCIREG, memtype, 0, 7844ccba60fSjmatthew &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) { 7854ccba60fSjmatthew printf(": unable to map registers\n"); 7864ccba60fSjmatthew return; 7874ccba60fSjmatthew } 7884ccba60fSjmatthew 7894ccba60fSjmatthew for (tries = 0; tries < 100; tries++) { 7904ccba60fSjmatthew uint32_t reg; 7914ccba60fSjmatthew reg = iavf_rd(sc, I40E_VFGEN_RSTAT) & 7924ccba60fSjmatthew I40E_VFGEN_RSTAT_VFR_STATE_MASK; 7934ccba60fSjmatthew if (reg == IAVF_VFR_VFACTIVE || 7944ccba60fSjmatthew reg == IAVF_VFR_COMPLETED) 7954ccba60fSjmatthew break; 7964ccba60fSjmatthew 7974ccba60fSjmatthew delay(10000); 7984ccba60fSjmatthew } 7994ccba60fSjmatthew if (tries == 100) { 8004ccba60fSjmatthew printf(": VF reset timed out\n"); 8014ccba60fSjmatthew return; 8024ccba60fSjmatthew } 8032fa30b92Sjmatthew task_set(&sc->sc_reset_task, iavf_reset, sc); 8044ccba60fSjmatthew 8054ccba60fSjmatthew mtx_init(&sc->sc_atq_mtx, IPL_NET); 8064ccba60fSjmatthew 8074ccba60fSjmatthew if (iavf_dmamem_alloc(sc, &sc->sc_atq, 8084ccba60fSjmatthew sizeof(struct iavf_aq_desc) * IAVF_AQ_NUM, IAVF_AQ_ALIGN) != 0) { 8094ccba60fSjmatthew printf("\n" "%s: unable to allocate atq\n", DEVNAME(sc)); 8104ccba60fSjmatthew goto unmap; 8114ccba60fSjmatthew } 8124ccba60fSjmatthew 8134ccba60fSjmatthew SIMPLEQ_INIT(&sc->sc_arq_idle); 8144ccba60fSjmatthew SIMPLEQ_INIT(&sc->sc_arq_live); 8154ccba60fSjmatthew if_rxr_init(&sc->sc_arq_ring, 2, IAVF_AQ_NUM - 1); 8164ccba60fSjmatthew sc->sc_arq_cons = 0; 8174ccba60fSjmatthew sc->sc_arq_prod = 0; 8184ccba60fSjmatthew 8194ccba60fSjmatthew if (iavf_dmamem_alloc(sc, &sc->sc_arq, 8204ccba60fSjmatthew sizeof(struct iavf_aq_desc) * IAVF_AQ_NUM, IAVF_AQ_ALIGN) != 0) { 8214ccba60fSjmatthew printf("\n" "%s: unable to allocate arq\n", DEVNAME(sc)); 8224ccba60fSjmatthew goto free_atq; 8234ccba60fSjmatthew } 8244ccba60fSjmatthew 825e13657b7Sjmatthew if (!iavf_arq_fill(sc, 0)) { 8264ccba60fSjmatthew printf("\n" "%s: unable to fill arq descriptors\n", 8274ccba60fSjmatthew DEVNAME(sc)); 8284ccba60fSjmatthew goto free_arq; 8294ccba60fSjmatthew } 8304ccba60fSjmatthew timeout_set(&sc->sc_admin_timeout, iavf_arq_timeout, sc); 8314ccba60fSjmatthew 8324ccba60fSjmatthew if (iavf_dmamem_alloc(sc, &sc->sc_scratch, PAGE_SIZE, IAVF_AQ_ALIGN) != 0) { 8334ccba60fSjmatthew printf("\n" "%s: unable to allocate scratch\n", DEVNAME(sc)); 8344ccba60fSjmatthew goto shutdown; 8354ccba60fSjmatthew } 8364ccba60fSjmatthew 8374ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq), 8384ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_atq), 8394ccba60fSjmatthew BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 8404ccba60fSjmatthew 8414ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq), 8424ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_arq), 8434ccba60fSjmatthew BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 8444ccba60fSjmatthew 8452fa30b92Sjmatthew iavf_init_admin_queue(sc); 8464ccba60fSjmatthew 8474ccba60fSjmatthew if (iavf_get_version(sc) != 0) { 8484ccba60fSjmatthew printf(", unable to get VF interface version\n"); 8494ccba60fSjmatthew goto free_scratch; 8504ccba60fSjmatthew } 8514ccba60fSjmatthew 8524ccba60fSjmatthew if (iavf_get_vf_resources(sc) != 0) { 853e13657b7Sjmatthew printf(", timed out waiting for VF resources\n"); 8544ccba60fSjmatthew goto free_scratch; 8554ccba60fSjmatthew } 8564ccba60fSjmatthew 8574ccba60fSjmatthew if (iavf_config_irq_map(sc) != 0) { 858e13657b7Sjmatthew printf(", timeout waiting for IRQ map response"); 8594ccba60fSjmatthew goto free_scratch; 8604ccba60fSjmatthew } 8614ccba60fSjmatthew 8624ccba60fSjmatthew /* msix only? */ 8634ccba60fSjmatthew if (pci_intr_map_msix(pa, 0, &sc->sc_ih) != 0) { 8644ccba60fSjmatthew printf(", unable to map interrupt\n"); 8654ccba60fSjmatthew goto free_scratch; 8664ccba60fSjmatthew } 8674ccba60fSjmatthew 8684ccba60fSjmatthew /* generate an address if the pf didn't give us one */ 8694ccba60fSjmatthew memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 8704ccba60fSjmatthew if (memcmp(sc->sc_ac.ac_enaddr, etheranyaddr, ETHER_ADDR_LEN) == 0) 8714ccba60fSjmatthew ether_fakeaddr(ifp); 8724ccba60fSjmatthew 8734ccba60fSjmatthew printf(", %s, address %s\n", pci_intr_string(sc->sc_pc, sc->sc_ih), 8744ccba60fSjmatthew ether_sprintf(sc->sc_ac.ac_enaddr)); 8754ccba60fSjmatthew 8764ccba60fSjmatthew sc->sc_ihc = pci_intr_establish(sc->sc_pc, sc->sc_ih, 8774ccba60fSjmatthew IPL_NET | IPL_MPSAFE, iavf_intr, sc, DEVNAME(sc)); 8784ccba60fSjmatthew if (sc->sc_ihc == NULL) { 8794ccba60fSjmatthew printf("%s: unable to establish interrupt handler\n", 8804ccba60fSjmatthew DEVNAME(sc)); 8814ccba60fSjmatthew goto free_scratch; 8824ccba60fSjmatthew } 8834ccba60fSjmatthew 8844ccba60fSjmatthew ifp->if_softc = sc; 8854ccba60fSjmatthew ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 8864ccba60fSjmatthew ifp->if_xflags = IFXF_MPSAFE; 8874ccba60fSjmatthew ifp->if_ioctl = iavf_ioctl; 8884ccba60fSjmatthew ifp->if_qstart = iavf_start; 8894ccba60fSjmatthew ifp->if_watchdog = iavf_watchdog; 8904ccba60fSjmatthew if (ifp->if_hardmtu == 0) 8914ccba60fSjmatthew ifp->if_hardmtu = IAVF_HARDMTU; 8924ccba60fSjmatthew strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 893cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, sc->sc_tx_ring_ndescs); 8944ccba60fSjmatthew 895*51248bbdSyasuoka ifp->if_capabilities = IFCAP_VLAN_MTU; 896*51248bbdSyasuoka #if NVLAN > 0 897*51248bbdSyasuoka ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 8984ccba60fSjmatthew #endif 899*51248bbdSyasuoka ifp->if_capabilities |= IFCAP_CSUM_IPv4 | 900*51248bbdSyasuoka IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 | 901*51248bbdSyasuoka IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6; 9024ccba60fSjmatthew 9034ccba60fSjmatthew ifmedia_init(&sc->sc_media, 0, iavf_media_change, iavf_media_status); 9044ccba60fSjmatthew 9054ccba60fSjmatthew ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 9064ccba60fSjmatthew ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 9074ccba60fSjmatthew 9084ccba60fSjmatthew if_attach(ifp); 9094ccba60fSjmatthew ether_ifattach(ifp); 9104ccba60fSjmatthew 9114ccba60fSjmatthew if_attach_queues(ifp, iavf_nqueues(sc)); 9124ccba60fSjmatthew if_attach_iqueues(ifp, iavf_nqueues(sc)); 9134ccba60fSjmatthew 9144ccba60fSjmatthew iavf_intr_enable(sc); 9154ccba60fSjmatthew 9164ccba60fSjmatthew return; 9174ccba60fSjmatthew free_scratch: 9184ccba60fSjmatthew iavf_dmamem_free(sc, &sc->sc_scratch); 9194ccba60fSjmatthew shutdown: 9204ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_head, 0); 9214ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_head, 0); 9224ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_tail, 0); 9234ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_tail, 0); 9244ccba60fSjmatthew 9254ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_bal, 0); 9264ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_bah, 0); 9274ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_len, 0); 9284ccba60fSjmatthew 9294ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_bal, 0); 9304ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_bah, 0); 9314ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_len, 0); 9324ccba60fSjmatthew 9334ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq), 9344ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_arq), 9354ccba60fSjmatthew BUS_DMASYNC_POSTREAD); 9364ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq), 9374ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_atq), 9384ccba60fSjmatthew BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 9394ccba60fSjmatthew 9404ccba60fSjmatthew iavf_arq_unfill(sc); 9414ccba60fSjmatthew free_arq: 9424ccba60fSjmatthew iavf_dmamem_free(sc, &sc->sc_arq); 9434ccba60fSjmatthew free_atq: 9444ccba60fSjmatthew iavf_dmamem_free(sc, &sc->sc_atq); 9454ccba60fSjmatthew unmap: 9464ccba60fSjmatthew bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems); 9474ccba60fSjmatthew sc->sc_mems = 0; 9484ccba60fSjmatthew } 9494ccba60fSjmatthew 9504ccba60fSjmatthew static int 9514ccba60fSjmatthew iavf_media_change(struct ifnet *ifp) 9524ccba60fSjmatthew { 9534ccba60fSjmatthew return (EOPNOTSUPP); 9544ccba60fSjmatthew } 9554ccba60fSjmatthew 9564ccba60fSjmatthew static void 9574ccba60fSjmatthew iavf_media_status(struct ifnet *ifp, struct ifmediareq *ifm) 9584ccba60fSjmatthew { 9594ccba60fSjmatthew struct iavf_softc *sc = ifp->if_softc; 9604ccba60fSjmatthew 96104e5e978Sjmatthew KERNEL_ASSERT_LOCKED(); 9624ccba60fSjmatthew 9634ccba60fSjmatthew ifm->ifm_status = sc->sc_media_status; 9644ccba60fSjmatthew ifm->ifm_active = sc->sc_media_active; 9654ccba60fSjmatthew } 9664ccba60fSjmatthew 9674ccba60fSjmatthew static void 9684ccba60fSjmatthew iavf_watchdog(struct ifnet *ifp) 9694ccba60fSjmatthew { 9704ccba60fSjmatthew 9714ccba60fSjmatthew } 9724ccba60fSjmatthew 9734ccba60fSjmatthew int 9744ccba60fSjmatthew iavf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 9754ccba60fSjmatthew { 9764ccba60fSjmatthew struct iavf_softc *sc = (struct iavf_softc *)ifp->if_softc; 9774ccba60fSjmatthew struct ifreq *ifr = (struct ifreq *)data; 9784ccba60fSjmatthew uint8_t addrhi[ETHER_ADDR_LEN], addrlo[ETHER_ADDR_LEN]; 9794ccba60fSjmatthew int /*aqerror,*/ error = 0; 9804ccba60fSjmatthew 9814ccba60fSjmatthew switch (cmd) { 9824ccba60fSjmatthew case SIOCSIFADDR: 9834ccba60fSjmatthew ifp->if_flags |= IFF_UP; 9844ccba60fSjmatthew /* FALLTHROUGH */ 9854ccba60fSjmatthew 9864ccba60fSjmatthew case SIOCSIFFLAGS: 9874ccba60fSjmatthew if (ISSET(ifp->if_flags, IFF_UP)) { 9884ccba60fSjmatthew if (ISSET(ifp->if_flags, IFF_RUNNING)) 9894ccba60fSjmatthew error = ENETRESET; 9904ccba60fSjmatthew else 9914ccba60fSjmatthew error = iavf_up(sc); 9924ccba60fSjmatthew } else { 9934ccba60fSjmatthew if (ISSET(ifp->if_flags, IFF_RUNNING)) 9944ccba60fSjmatthew error = iavf_down(sc); 9954ccba60fSjmatthew } 9964ccba60fSjmatthew break; 9974ccba60fSjmatthew 9984ccba60fSjmatthew case SIOCGIFMEDIA: 9994ccba60fSjmatthew case SIOCSIFMEDIA: 10004ccba60fSjmatthew error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 10014ccba60fSjmatthew break; 10024ccba60fSjmatthew 10034ccba60fSjmatthew case SIOCGIFRXR: 10044ccba60fSjmatthew error = iavf_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data); 10054ccba60fSjmatthew break; 10064ccba60fSjmatthew 10074ccba60fSjmatthew case SIOCADDMULTI: 10084ccba60fSjmatthew if (ether_addmulti(ifr, &sc->sc_ac) == ENETRESET) { 10094ccba60fSjmatthew error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 10104ccba60fSjmatthew if (error != 0) 10114ccba60fSjmatthew return (error); 10124ccba60fSjmatthew 10134ccba60fSjmatthew iavf_add_del_addr(sc, addrlo, 1); 10144ccba60fSjmatthew /* check result i guess? */ 10154ccba60fSjmatthew 10164ccba60fSjmatthew if (sc->sc_ac.ac_multirangecnt > 0) { 10174ccba60fSjmatthew SET(ifp->if_flags, IFF_ALLMULTI); 10184ccba60fSjmatthew error = ENETRESET; 10194ccba60fSjmatthew } 10204ccba60fSjmatthew } 10214ccba60fSjmatthew break; 10224ccba60fSjmatthew 10234ccba60fSjmatthew case SIOCDELMULTI: 10244ccba60fSjmatthew if (ether_delmulti(ifr, &sc->sc_ac) == ENETRESET) { 10254ccba60fSjmatthew error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi); 10264ccba60fSjmatthew if (error != 0) 10274ccba60fSjmatthew return (error); 10284ccba60fSjmatthew 10294ccba60fSjmatthew iavf_add_del_addr(sc, addrlo, 0); 10304ccba60fSjmatthew 10314ccba60fSjmatthew if (ISSET(ifp->if_flags, IFF_ALLMULTI) && 10324ccba60fSjmatthew sc->sc_ac.ac_multirangecnt == 0) { 10334ccba60fSjmatthew CLR(ifp->if_flags, IFF_ALLMULTI); 10344ccba60fSjmatthew error = ENETRESET; 10354ccba60fSjmatthew } 10364ccba60fSjmatthew } 10374ccba60fSjmatthew break; 10384ccba60fSjmatthew 10394ccba60fSjmatthew default: 10404ccba60fSjmatthew error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 10414ccba60fSjmatthew break; 10424ccba60fSjmatthew } 10434ccba60fSjmatthew 10444ccba60fSjmatthew if (error == ENETRESET) 10454ccba60fSjmatthew error = iavf_iff(sc); 10464ccba60fSjmatthew 10474ccba60fSjmatthew return (error); 10484ccba60fSjmatthew } 10494ccba60fSjmatthew 10504ccba60fSjmatthew static int 10514ccba60fSjmatthew iavf_config_vsi_queues(struct iavf_softc *sc) 10524ccba60fSjmatthew { 10534ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 10544ccba60fSjmatthew struct iavf_aq_desc iaq; 10554ccba60fSjmatthew struct iavf_vc_queue_config_info *config; 10564ccba60fSjmatthew struct iavf_vc_txq_info *txq; 10574ccba60fSjmatthew struct iavf_vc_rxq_info *rxq; 10584ccba60fSjmatthew struct iavf_rx_ring *rxr; 10594ccba60fSjmatthew struct iavf_tx_ring *txr; 10604ccba60fSjmatthew int rv, i; 10614ccba60fSjmatthew 10624ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 10634ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 10644ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 10654ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_CONFIG_VSI_QUEUES); 10664ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(*config) + 10674ccba60fSjmatthew iavf_nqueues(sc) * sizeof(struct iavf_vc_queue_pair_info)); 10684ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 10694ccba60fSjmatthew 10704ccba60fSjmatthew config = IAVF_DMA_KVA(&sc->sc_scratch); 10714ccba60fSjmatthew config->vsi_id = htole16(sc->sc_vsi_id); 10724ccba60fSjmatthew config->num_queue_pairs = htole16(iavf_nqueues(sc)); 10734ccba60fSjmatthew 10744ccba60fSjmatthew for (i = 0; i < iavf_nqueues(sc); i++) { 10754ccba60fSjmatthew rxr = ifp->if_iqs[i]->ifiq_softc; 10764ccba60fSjmatthew txr = ifp->if_ifqs[i]->ifq_softc; 10774ccba60fSjmatthew 10784ccba60fSjmatthew txq = &config->qpair[i].txq; 10794ccba60fSjmatthew txq->vsi_id = htole16(sc->sc_vsi_id); 10804ccba60fSjmatthew txq->queue_id = htole16(i); 10814ccba60fSjmatthew txq->ring_len = sc->sc_tx_ring_ndescs; 10824ccba60fSjmatthew txq->headwb_ena = 0; 10834ccba60fSjmatthew htolem64(&txq->dma_ring_addr, IAVF_DMA_DVA(&txr->txr_mem)); 10844ccba60fSjmatthew txq->dma_headwb_addr = 0; 10854ccba60fSjmatthew 10864ccba60fSjmatthew rxq = &config->qpair[i].rxq; 10874ccba60fSjmatthew rxq->vsi_id = htole16(sc->sc_vsi_id); 10884ccba60fSjmatthew rxq->queue_id = htole16(i); 10894ccba60fSjmatthew rxq->ring_len = sc->sc_rx_ring_ndescs; 10904ccba60fSjmatthew rxq->splithdr_ena = 0; 10914ccba60fSjmatthew rxq->databuf_size = htole32(MCLBYTES); 10924ccba60fSjmatthew rxq->max_pkt_size = htole32(IAVF_HARDMTU); 10934ccba60fSjmatthew htolem64(&rxq->dma_ring_addr, IAVF_DMA_DVA(&rxr->rxr_mem)); 10944ccba60fSjmatthew rxq->rx_split_pos = 0; 10954ccba60fSjmatthew } 10964ccba60fSjmatthew 10974ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, 10984ccba60fSjmatthew IAVF_DMA_LEN(&sc->sc_scratch), 10994ccba60fSjmatthew BUS_DMASYNC_PREREAD); 11004ccba60fSjmatthew 11014ccba60fSjmatthew iavf_atq_post(sc, &iaq); 11024ccba60fSjmatthew rv = iavf_arq_wait(sc, 250); 11034ccba60fSjmatthew if (rv != IAVF_VC_RC_SUCCESS) { 11044ccba60fSjmatthew printf("%s: CONFIG_VSI_QUEUES failed: %d\n", DEVNAME(sc), rv); 11054ccba60fSjmatthew return (1); 11064ccba60fSjmatthew } 11074ccba60fSjmatthew 11084ccba60fSjmatthew return (0); 11094ccba60fSjmatthew } 11104ccba60fSjmatthew 11114ccba60fSjmatthew static int 11124ccba60fSjmatthew iavf_config_hena(struct iavf_softc *sc) 11134ccba60fSjmatthew { 11144ccba60fSjmatthew struct iavf_aq_desc iaq; 11154ccba60fSjmatthew uint64_t *caps; 11164ccba60fSjmatthew int rv; 11174ccba60fSjmatthew 11184ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 11194ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 11204ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 11214ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_SET_RSS_HENA); 112226c48d9fSjmatthew iaq.iaq_datalen = htole16(sizeof(*caps)); 11234ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 11244ccba60fSjmatthew 11254ccba60fSjmatthew caps = IAVF_DMA_KVA(&sc->sc_scratch); 11264ccba60fSjmatthew *caps = 0; 11274ccba60fSjmatthew 11284ccba60fSjmatthew iavf_atq_post(sc, &iaq); 11294ccba60fSjmatthew rv = iavf_arq_wait(sc, 250); 11304ccba60fSjmatthew if (rv != IAVF_VC_RC_SUCCESS) { 11314ccba60fSjmatthew printf("%s: SET_RSS_HENA failed: %d\n", DEVNAME(sc), rv); 11324ccba60fSjmatthew return (1); 11334ccba60fSjmatthew } 11344ccba60fSjmatthew 11354ccba60fSjmatthew caps = IAVF_DMA_KVA(&sc->sc_scratch); 11364ccba60fSjmatthew 11374ccba60fSjmatthew return (0); 11384ccba60fSjmatthew } 11394ccba60fSjmatthew 11404ccba60fSjmatthew static int 11411f28ec92Sjmatthew iavf_queue_select(struct iavf_softc *sc, int opcode) 11424ccba60fSjmatthew { 11434ccba60fSjmatthew struct iavf_aq_desc iaq; 11444ccba60fSjmatthew struct iavf_vc_queue_select *qsel; 11454ccba60fSjmatthew int rv; 11464ccba60fSjmatthew 11474ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 11484ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 11494ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 11501f28ec92Sjmatthew iaq.iaq_vc_opcode = htole32(opcode); 11514ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(*qsel)); 11524ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 11534ccba60fSjmatthew 11544ccba60fSjmatthew qsel = IAVF_DMA_KVA(&sc->sc_scratch); 11554ccba60fSjmatthew qsel->vsi_id = htole16(sc->sc_vsi_id); 11561f28ec92Sjmatthew qsel->rx_queues = htole32(iavf_allqueues(sc)); 11571f28ec92Sjmatthew qsel->tx_queues = htole32(iavf_allqueues(sc)); 11584ccba60fSjmatthew 11594ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, 11604ccba60fSjmatthew IAVF_DMA_LEN(&sc->sc_scratch), 11614ccba60fSjmatthew BUS_DMASYNC_PREREAD); 11624ccba60fSjmatthew 11634ccba60fSjmatthew iavf_atq_post(sc, &iaq); 11644ccba60fSjmatthew rv = iavf_arq_wait(sc, 250); 11654ccba60fSjmatthew if (rv != IAVF_VC_RC_SUCCESS) { 11661f28ec92Sjmatthew printf("%s: queue op %d failed: %d\n", DEVNAME(sc), opcode, rv); 11674ccba60fSjmatthew return (1); 11684ccba60fSjmatthew } 11694ccba60fSjmatthew 11704ccba60fSjmatthew return (0); 11714ccba60fSjmatthew } 11724ccba60fSjmatthew 11734ccba60fSjmatthew static int 11744ccba60fSjmatthew iavf_up(struct iavf_softc *sc) 11754ccba60fSjmatthew { 11764ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 11774ccba60fSjmatthew struct iavf_rx_ring *rxr; 11784ccba60fSjmatthew struct iavf_tx_ring *txr; 11794ccba60fSjmatthew unsigned int nqueues, i; 11804ccba60fSjmatthew int rv = ENOMEM; 11814ccba60fSjmatthew 11824ccba60fSjmatthew nqueues = iavf_nqueues(sc); 11834ccba60fSjmatthew KASSERT(nqueues == 1); /* XXX */ 11844ccba60fSjmatthew 11854ccba60fSjmatthew rw_enter_write(&sc->sc_cfg_lock); 11864ccba60fSjmatthew if (sc->sc_dead) { 11874ccba60fSjmatthew rw_exit_write(&sc->sc_cfg_lock); 11884ccba60fSjmatthew return (ENXIO); 11894ccba60fSjmatthew } 11904ccba60fSjmatthew 11914ccba60fSjmatthew for (i = 0; i < nqueues; i++) { 11924ccba60fSjmatthew rxr = iavf_rxr_alloc(sc, i); 11934ccba60fSjmatthew if (rxr == NULL) 11944ccba60fSjmatthew goto free; 11954ccba60fSjmatthew 11964ccba60fSjmatthew txr = iavf_txr_alloc(sc, i); 11974ccba60fSjmatthew if (txr == NULL) { 11984ccba60fSjmatthew iavf_rxr_free(sc, rxr); 11994ccba60fSjmatthew goto free; 12004ccba60fSjmatthew } 12014ccba60fSjmatthew 12024ccba60fSjmatthew ifp->if_iqs[i]->ifiq_softc = rxr; 12034ccba60fSjmatthew ifp->if_ifqs[i]->ifq_softc = txr; 12044ccba60fSjmatthew 12054ccba60fSjmatthew iavf_rxfill(sc, rxr); 12064ccba60fSjmatthew } 12074ccba60fSjmatthew 12084ccba60fSjmatthew if (iavf_config_vsi_queues(sc) != 0) 12094ccba60fSjmatthew goto down; 12104ccba60fSjmatthew 12114ccba60fSjmatthew if (iavf_config_hena(sc) != 0) 12124ccba60fSjmatthew goto down; 12134ccba60fSjmatthew 12141f28ec92Sjmatthew if (iavf_queue_select(sc, IAVF_VC_OP_ENABLE_QUEUES) != 0) 12154ccba60fSjmatthew goto down; 12164ccba60fSjmatthew 12174ccba60fSjmatthew SET(ifp->if_flags, IFF_RUNNING); 12184ccba60fSjmatthew 12194ccba60fSjmatthew iavf_wr(sc, I40E_VFINT_ITR01(0), 0x7a); 12204ccba60fSjmatthew iavf_wr(sc, I40E_VFINT_ITR01(1), 0x7a); 12214ccba60fSjmatthew iavf_wr(sc, I40E_VFINT_ITR01(2), 0); 12224ccba60fSjmatthew 12234ccba60fSjmatthew rw_exit_write(&sc->sc_cfg_lock); 12244ccba60fSjmatthew 12254ccba60fSjmatthew return (ENETRESET); 12264ccba60fSjmatthew 12274ccba60fSjmatthew free: 12284ccba60fSjmatthew for (i = 0; i < nqueues; i++) { 12294ccba60fSjmatthew rxr = ifp->if_iqs[i]->ifiq_softc; 12304ccba60fSjmatthew txr = ifp->if_ifqs[i]->ifq_softc; 12314ccba60fSjmatthew 12324ccba60fSjmatthew if (rxr == NULL) { 12334ccba60fSjmatthew /* 12344ccba60fSjmatthew * tx and rx get set at the same time, so if one 12354ccba60fSjmatthew * is NULL, the other is too. 12364ccba60fSjmatthew */ 12374ccba60fSjmatthew continue; 12384ccba60fSjmatthew } 12394ccba60fSjmatthew 12404ccba60fSjmatthew iavf_txr_free(sc, txr); 12414ccba60fSjmatthew iavf_rxr_free(sc, rxr); 12424ccba60fSjmatthew } 12434ccba60fSjmatthew rw_exit_write(&sc->sc_cfg_lock); 12444ccba60fSjmatthew return (rv); 12454ccba60fSjmatthew down: 12464ccba60fSjmatthew rw_exit_write(&sc->sc_cfg_lock); 12474ccba60fSjmatthew iavf_down(sc); 12484ccba60fSjmatthew return (ETIMEDOUT); 12494ccba60fSjmatthew } 12504ccba60fSjmatthew 12514ccba60fSjmatthew static int 12524ccba60fSjmatthew iavf_config_promisc_mode(struct iavf_softc *sc, int unicast, int multicast) 12534ccba60fSjmatthew { 12544ccba60fSjmatthew struct iavf_aq_desc iaq; 12554ccba60fSjmatthew struct iavf_vc_promisc_info *promisc; 12564ccba60fSjmatthew int rv, flags; 12574ccba60fSjmatthew 12584ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 12594ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 12604ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 12614ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_CONFIG_PROMISC); 12624ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(*promisc)); 12634ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 12644ccba60fSjmatthew 12654ccba60fSjmatthew flags = 0; 12664ccba60fSjmatthew if (unicast) 12674ccba60fSjmatthew flags |= IAVF_FLAG_VF_UNICAST_PROMISC; 12684ccba60fSjmatthew if (multicast) 12694ccba60fSjmatthew flags |= IAVF_FLAG_VF_MULTICAST_PROMISC; 12704ccba60fSjmatthew 12714ccba60fSjmatthew promisc = IAVF_DMA_KVA(&sc->sc_scratch); 12724ccba60fSjmatthew promisc->vsi_id = htole16(sc->sc_vsi_id); 12734ccba60fSjmatthew promisc->flags = htole16(flags); 12744ccba60fSjmatthew 12754ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, 12764ccba60fSjmatthew IAVF_DMA_LEN(&sc->sc_scratch), 12774ccba60fSjmatthew BUS_DMASYNC_PREREAD); 12784ccba60fSjmatthew 12794ccba60fSjmatthew iavf_atq_post(sc, &iaq); 12804ccba60fSjmatthew rv = iavf_arq_wait(sc, 250); 12814ccba60fSjmatthew if (rv != IAVF_VC_RC_SUCCESS) { 12824ccba60fSjmatthew printf("%s: CONFIG_PROMISC_MODE failed: %d\n", DEVNAME(sc), rv); 12834ccba60fSjmatthew return (1); 12844ccba60fSjmatthew } 12854ccba60fSjmatthew 12864ccba60fSjmatthew return (0); 12874ccba60fSjmatthew } 12884ccba60fSjmatthew 12894ccba60fSjmatthew static int 12904ccba60fSjmatthew iavf_add_del_addr(struct iavf_softc *sc, uint8_t *addr, int add) 12914ccba60fSjmatthew { 12924ccba60fSjmatthew struct iavf_aq_desc iaq; 12934ccba60fSjmatthew struct iavf_vc_eth_addr_list *addrs; 12944ccba60fSjmatthew struct iavf_vc_eth_addr *vcaddr; 12954ccba60fSjmatthew int rv; 12964ccba60fSjmatthew 12974ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 12984ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 12994ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 13004ccba60fSjmatthew if (add) 13014ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_ADD_ETH_ADDR); 13024ccba60fSjmatthew else 13034ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_DEL_ETH_ADDR); 13044ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(*addrs) + sizeof(*vcaddr)); 13054ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 13064ccba60fSjmatthew 13074ccba60fSjmatthew addrs = IAVF_DMA_KVA(&sc->sc_scratch); 13084ccba60fSjmatthew addrs->vsi_id = htole16(sc->sc_vsi_id); 13094ccba60fSjmatthew addrs->num_elements = htole16(1); 13104ccba60fSjmatthew 13114ccba60fSjmatthew vcaddr = addrs->list; 13124ccba60fSjmatthew memcpy(vcaddr->addr, addr, ETHER_ADDR_LEN); 13134ccba60fSjmatthew 13144ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, 13154ccba60fSjmatthew IAVF_DMA_LEN(&sc->sc_scratch), 13164ccba60fSjmatthew BUS_DMASYNC_PREREAD); 13174ccba60fSjmatthew 13184ccba60fSjmatthew iavf_atq_post(sc, &iaq); 13194ccba60fSjmatthew rv = iavf_arq_wait(sc, 250); 13204ccba60fSjmatthew if (rv != IAVF_VC_RC_SUCCESS) { 13214ccba60fSjmatthew printf("%s: ADD/DEL_ETH_ADDR failed: %d\n", DEVNAME(sc), rv); 13224ccba60fSjmatthew return (1); 13234ccba60fSjmatthew } 13244ccba60fSjmatthew 13254ccba60fSjmatthew return (0); 13264ccba60fSjmatthew } 13274ccba60fSjmatthew 13284ccba60fSjmatthew static int 13294ccba60fSjmatthew iavf_iff(struct iavf_softc *sc) 13304ccba60fSjmatthew { 13314ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 1332ec60c50dSjmatthew int unicast, multicast; 13334ccba60fSjmatthew 13344ccba60fSjmatthew if (!ISSET(ifp->if_flags, IFF_RUNNING)) 13354ccba60fSjmatthew return (0); 13364ccba60fSjmatthew 13374ccba60fSjmatthew rw_enter_write(&sc->sc_cfg_lock); 13384ccba60fSjmatthew 1339ec60c50dSjmatthew unicast = 0; 1340ec60c50dSjmatthew multicast = 0; 1341ec60c50dSjmatthew if (ISSET(ifp->if_flags, IFF_PROMISC)) { 1342ec60c50dSjmatthew unicast = 1; 1343ec60c50dSjmatthew multicast = 1; 1344ec60c50dSjmatthew } else if (ISSET(ifp->if_flags, IFF_ALLMULTI)) { 1345ec60c50dSjmatthew multicast = 1; 1346ec60c50dSjmatthew } 1347ec60c50dSjmatthew iavf_config_promisc_mode(sc, unicast, multicast); 13484ccba60fSjmatthew 13494ccba60fSjmatthew if (memcmp(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN) != 0) { 13504ccba60fSjmatthew if (memcmp(sc->sc_enaddr, etheranyaddr, ETHER_ADDR_LEN) != 0) 13514ccba60fSjmatthew iavf_add_del_addr(sc, sc->sc_enaddr, 0); 13524ccba60fSjmatthew memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 13534ccba60fSjmatthew iavf_add_del_addr(sc, sc->sc_enaddr, 1); 13544ccba60fSjmatthew } 13554ccba60fSjmatthew 13564ccba60fSjmatthew rw_exit_write(&sc->sc_cfg_lock); 13574ccba60fSjmatthew return (0); 13584ccba60fSjmatthew } 13594ccba60fSjmatthew 13604ccba60fSjmatthew static int 13614ccba60fSjmatthew iavf_down(struct iavf_softc *sc) 13624ccba60fSjmatthew { 13634ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 13644ccba60fSjmatthew struct iavf_rx_ring *rxr; 13654ccba60fSjmatthew struct iavf_tx_ring *txr; 13664ccba60fSjmatthew unsigned int nqueues, i; 13671f28ec92Sjmatthew uint32_t reg; 13684ccba60fSjmatthew int error = 0; 13694ccba60fSjmatthew 13704ccba60fSjmatthew nqueues = iavf_nqueues(sc); 13714ccba60fSjmatthew 13724ccba60fSjmatthew rw_enter_write(&sc->sc_cfg_lock); 13734ccba60fSjmatthew 13744ccba60fSjmatthew CLR(ifp->if_flags, IFF_RUNNING); 13754ccba60fSjmatthew 13764ccba60fSjmatthew NET_UNLOCK(); 13774ccba60fSjmatthew 13782fa30b92Sjmatthew if (sc->sc_resetting == 0) { 13794ccba60fSjmatthew /* disable queues */ 13801f28ec92Sjmatthew if (iavf_queue_select(sc, IAVF_VC_OP_DISABLE_QUEUES) != 0) 13811f28ec92Sjmatthew goto die; 13822fa30b92Sjmatthew } 13834ccba60fSjmatthew 13841f28ec92Sjmatthew /* mask interrupts */ 13851f28ec92Sjmatthew reg = iavf_rd(sc, I40E_VFINT_DYN_CTL01); 13861f28ec92Sjmatthew reg |= I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK | 13871f28ec92Sjmatthew (IAVF_NOITR << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT); 13881f28ec92Sjmatthew iavf_wr(sc, I40E_VFINT_DYN_CTL01, reg); 13891f28ec92Sjmatthew 13901f28ec92Sjmatthew /* make sure no hw generated work is still in flight */ 13914ccba60fSjmatthew intr_barrier(sc->sc_ihc); 13924ccba60fSjmatthew for (i = 0; i < nqueues; i++) { 13934ccba60fSjmatthew rxr = ifp->if_iqs[i]->ifiq_softc; 13944ccba60fSjmatthew txr = ifp->if_ifqs[i]->ifq_softc; 13954ccba60fSjmatthew 13964ccba60fSjmatthew ifq_barrier(ifp->if_ifqs[i]); 13974ccba60fSjmatthew 13984ccba60fSjmatthew timeout_del_barrier(&rxr->rxr_refill); 13994ccba60fSjmatthew } 14004ccba60fSjmatthew 14014ccba60fSjmatthew for (i = 0; i < nqueues; i++) { 14024ccba60fSjmatthew rxr = ifp->if_iqs[i]->ifiq_softc; 14034ccba60fSjmatthew txr = ifp->if_ifqs[i]->ifq_softc; 14044ccba60fSjmatthew 14054ccba60fSjmatthew iavf_txr_clean(sc, txr); 14064ccba60fSjmatthew iavf_rxr_clean(sc, rxr); 14074ccba60fSjmatthew 14084ccba60fSjmatthew iavf_txr_free(sc, txr); 14094ccba60fSjmatthew iavf_rxr_free(sc, rxr); 14104ccba60fSjmatthew 14114ccba60fSjmatthew ifp->if_iqs[i]->ifiq_softc = NULL; 14124ccba60fSjmatthew ifp->if_ifqs[i]->ifq_softc = NULL; 14134ccba60fSjmatthew } 14144ccba60fSjmatthew 14151f28ec92Sjmatthew /* unmask */ 14161f28ec92Sjmatthew reg = iavf_rd(sc, I40E_VFINT_DYN_CTL01); 14171f28ec92Sjmatthew reg |= (IAVF_NOITR << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT); 14181f28ec92Sjmatthew iavf_wr(sc, I40E_VFINT_DYN_CTL01, reg); 14191f28ec92Sjmatthew 14204ccba60fSjmatthew out: 14214ccba60fSjmatthew rw_exit_write(&sc->sc_cfg_lock); 14224ccba60fSjmatthew NET_LOCK(); 14234ccba60fSjmatthew return (error); 14241f28ec92Sjmatthew die: 14254ccba60fSjmatthew sc->sc_dead = 1; 14264ccba60fSjmatthew log(LOG_CRIT, "%s: failed to shut down rings", DEVNAME(sc)); 14274ccba60fSjmatthew error = ETIMEDOUT; 14284ccba60fSjmatthew goto out; 14294ccba60fSjmatthew } 14304ccba60fSjmatthew 14312fa30b92Sjmatthew static void 14322fa30b92Sjmatthew iavf_reset(void *xsc) 14332fa30b92Sjmatthew { 14342fa30b92Sjmatthew struct iavf_softc *sc = xsc; 14352fa30b92Sjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 14362fa30b92Sjmatthew int tries, up, link_state; 14372fa30b92Sjmatthew 14382fa30b92Sjmatthew NET_LOCK(); 14392fa30b92Sjmatthew 14402fa30b92Sjmatthew /* treat the reset as a loss of link */ 14412fa30b92Sjmatthew link_state = ifp->if_link_state; 14422fa30b92Sjmatthew if (ifp->if_link_state != LINK_STATE_DOWN) { 14432fa30b92Sjmatthew ifp->if_link_state = LINK_STATE_DOWN; 14442fa30b92Sjmatthew if_link_state_change(ifp); 14452fa30b92Sjmatthew } 14462fa30b92Sjmatthew 14472fa30b92Sjmatthew up = 0; 14482fa30b92Sjmatthew if (ISSET(ifp->if_flags, IFF_RUNNING)) { 14492fa30b92Sjmatthew iavf_down(sc); 14502fa30b92Sjmatthew up = 1; 14512fa30b92Sjmatthew } 14522fa30b92Sjmatthew 14532fa30b92Sjmatthew rw_enter_write(&sc->sc_cfg_lock); 14542fa30b92Sjmatthew 14552fa30b92Sjmatthew sc->sc_major_ver = UINT_MAX; 14562fa30b92Sjmatthew sc->sc_minor_ver = UINT_MAX; 14572fa30b92Sjmatthew sc->sc_got_vf_resources = 0; 14582fa30b92Sjmatthew sc->sc_got_irq_map = 0; 14592fa30b92Sjmatthew 14602fa30b92Sjmatthew for (tries = 0; tries < 100; tries++) { 14612fa30b92Sjmatthew uint32_t reg; 14622fa30b92Sjmatthew reg = iavf_rd(sc, I40E_VFGEN_RSTAT) & 14632fa30b92Sjmatthew I40E_VFGEN_RSTAT_VFR_STATE_MASK; 14642fa30b92Sjmatthew if (reg == IAVF_VFR_VFACTIVE || 14652fa30b92Sjmatthew reg == IAVF_VFR_COMPLETED) 14662fa30b92Sjmatthew break; 14672fa30b92Sjmatthew 14682fa30b92Sjmatthew delay(10000); 14692fa30b92Sjmatthew } 14702fa30b92Sjmatthew if (tries == 100) { 14712fa30b92Sjmatthew printf("%s: VF reset timed out\n", DEVNAME(sc)); 14722fa30b92Sjmatthew goto failed; 14732fa30b92Sjmatthew } 14742fa30b92Sjmatthew 14752fa30b92Sjmatthew iavf_arq_unfill(sc); 14762fa30b92Sjmatthew sc->sc_arq_cons = 0; 14772fa30b92Sjmatthew sc->sc_arq_prod = 0; 14782fa30b92Sjmatthew if (!iavf_arq_fill(sc, 0)) { 14792fa30b92Sjmatthew printf("\n" "%s: unable to fill arq descriptors\n", 14802fa30b92Sjmatthew DEVNAME(sc)); 14812fa30b92Sjmatthew goto failed; 14822fa30b92Sjmatthew } 14832fa30b92Sjmatthew 14842fa30b92Sjmatthew iavf_init_admin_queue(sc); 14852fa30b92Sjmatthew 14862fa30b92Sjmatthew if (iavf_get_version(sc) != 0) { 14872fa30b92Sjmatthew printf("%s: unable to get VF interface version\n", 14882fa30b92Sjmatthew DEVNAME(sc)); 14892fa30b92Sjmatthew goto failed; 14902fa30b92Sjmatthew } 14912fa30b92Sjmatthew 14922fa30b92Sjmatthew if (iavf_get_vf_resources(sc) != 0) { 14932fa30b92Sjmatthew printf("%s: timed out waiting for VF resources\n", 14942fa30b92Sjmatthew DEVNAME(sc)); 14952fa30b92Sjmatthew goto failed; 14962fa30b92Sjmatthew } 14972fa30b92Sjmatthew 14982fa30b92Sjmatthew if (iavf_config_irq_map(sc) != 0) { 14992fa30b92Sjmatthew printf("%s: timed out configuring IRQ map\n", DEVNAME(sc)); 15002fa30b92Sjmatthew goto failed; 15012fa30b92Sjmatthew } 15022fa30b92Sjmatthew 15032fa30b92Sjmatthew /* do we need to re-add mac addresses here? */ 15042fa30b92Sjmatthew 15052fa30b92Sjmatthew sc->sc_resetting = 0; 15062fa30b92Sjmatthew iavf_intr_enable(sc); 15072fa30b92Sjmatthew rw_exit_write(&sc->sc_cfg_lock); 15082fa30b92Sjmatthew 15092fa30b92Sjmatthew /* the PF-assigned MAC address might have changed */ 15102fa30b92Sjmatthew if ((memcmp(sc->sc_ac.ac_enaddr, etheranyaddr, ETHER_ADDR_LEN) != 0) && 15112fa30b92Sjmatthew (memcmp(sc->sc_ac.ac_enaddr, sc->sc_enaddr, ETHER_ADDR_LEN) != 0)) { 15122fa30b92Sjmatthew memcpy(sc->sc_enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); 15132fa30b92Sjmatthew if_setlladdr(ifp, sc->sc_ac.ac_enaddr); 15142fa30b92Sjmatthew ifnewlladdr(ifp); 15152fa30b92Sjmatthew } 15162fa30b92Sjmatthew 15172fa30b92Sjmatthew /* restore link state */ 15182fa30b92Sjmatthew if (link_state != LINK_STATE_DOWN) { 15192fa30b92Sjmatthew ifp->if_link_state = link_state; 15202fa30b92Sjmatthew if_link_state_change(ifp); 15212fa30b92Sjmatthew } 15222fa30b92Sjmatthew 15232fa30b92Sjmatthew if (up) { 15242fa30b92Sjmatthew int i; 15252fa30b92Sjmatthew 15262fa30b92Sjmatthew iavf_up(sc); 15272fa30b92Sjmatthew 15282fa30b92Sjmatthew for (i = 0; i < iavf_nqueues(sc); i++) { 15292fa30b92Sjmatthew if (ifq_is_oactive(ifp->if_ifqs[i])) 15302fa30b92Sjmatthew ifq_restart(ifp->if_ifqs[i]); 15312fa30b92Sjmatthew } 15322fa30b92Sjmatthew } 15332fa30b92Sjmatthew 15342fa30b92Sjmatthew NET_UNLOCK(); 15352fa30b92Sjmatthew return; 15362fa30b92Sjmatthew failed: 15372fa30b92Sjmatthew sc->sc_dead = 1; 15382fa30b92Sjmatthew sc->sc_resetting = 0; 15392fa30b92Sjmatthew rw_exit_write(&sc->sc_cfg_lock); 15402fa30b92Sjmatthew NET_UNLOCK(); 15412fa30b92Sjmatthew } 15422fa30b92Sjmatthew 15434ccba60fSjmatthew static struct iavf_tx_ring * 15444ccba60fSjmatthew iavf_txr_alloc(struct iavf_softc *sc, unsigned int qid) 15454ccba60fSjmatthew { 15464ccba60fSjmatthew struct iavf_tx_ring *txr; 15474ccba60fSjmatthew struct iavf_tx_map *maps, *txm; 15484ccba60fSjmatthew unsigned int i; 15494ccba60fSjmatthew 15504ccba60fSjmatthew txr = malloc(sizeof(*txr), M_DEVBUF, M_WAITOK|M_CANFAIL); 15514ccba60fSjmatthew if (txr == NULL) 15524ccba60fSjmatthew return (NULL); 15534ccba60fSjmatthew 15544ccba60fSjmatthew maps = mallocarray(sizeof(*maps), 15554ccba60fSjmatthew sc->sc_tx_ring_ndescs, M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 15564ccba60fSjmatthew if (maps == NULL) 15574ccba60fSjmatthew goto free; 15584ccba60fSjmatthew 15594ccba60fSjmatthew if (iavf_dmamem_alloc(sc, &txr->txr_mem, 15604ccba60fSjmatthew sizeof(struct iavf_tx_desc) * sc->sc_tx_ring_ndescs, 15614ccba60fSjmatthew IAVF_TX_QUEUE_ALIGN) != 0) 15624ccba60fSjmatthew goto freemap; 15634ccba60fSjmatthew 15644ccba60fSjmatthew for (i = 0; i < sc->sc_tx_ring_ndescs; i++) { 15654ccba60fSjmatthew txm = &maps[i]; 15664ccba60fSjmatthew 15674ccba60fSjmatthew if (bus_dmamap_create(sc->sc_dmat, 15684ccba60fSjmatthew IAVF_HARDMTU, IAVF_TX_PKT_DESCS, IAVF_HARDMTU, 0, 15694ccba60fSjmatthew BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, 15704ccba60fSjmatthew &txm->txm_map) != 0) 15714ccba60fSjmatthew goto uncreate; 15724ccba60fSjmatthew 15734ccba60fSjmatthew txm->txm_eop = -1; 15744ccba60fSjmatthew txm->txm_m = NULL; 15754ccba60fSjmatthew } 15764ccba60fSjmatthew 15774ccba60fSjmatthew txr->txr_cons = txr->txr_prod = 0; 15784ccba60fSjmatthew txr->txr_maps = maps; 15794ccba60fSjmatthew 15804ccba60fSjmatthew txr->txr_tail = I40E_QTX_TAIL1(qid); 15814ccba60fSjmatthew txr->txr_qid = qid; 15824ccba60fSjmatthew 15834ccba60fSjmatthew return (txr); 15844ccba60fSjmatthew 15854ccba60fSjmatthew uncreate: 15864ccba60fSjmatthew for (i = 0; i < sc->sc_tx_ring_ndescs; i++) { 15874ccba60fSjmatthew txm = &maps[i]; 15884ccba60fSjmatthew 15894ccba60fSjmatthew if (txm->txm_map == NULL) 15904ccba60fSjmatthew continue; 15914ccba60fSjmatthew 15924ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, txm->txm_map); 15934ccba60fSjmatthew } 15944ccba60fSjmatthew 15954ccba60fSjmatthew iavf_dmamem_free(sc, &txr->txr_mem); 15964ccba60fSjmatthew freemap: 15974ccba60fSjmatthew free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_tx_ring_ndescs); 15984ccba60fSjmatthew free: 15994ccba60fSjmatthew free(txr, M_DEVBUF, sizeof(*txr)); 16004ccba60fSjmatthew return (NULL); 16014ccba60fSjmatthew } 16024ccba60fSjmatthew 16034ccba60fSjmatthew static void 16044ccba60fSjmatthew iavf_txr_clean(struct iavf_softc *sc, struct iavf_tx_ring *txr) 16054ccba60fSjmatthew { 16064ccba60fSjmatthew struct iavf_tx_map *maps, *txm; 16074ccba60fSjmatthew bus_dmamap_t map; 16084ccba60fSjmatthew unsigned int i; 16094ccba60fSjmatthew 16104ccba60fSjmatthew maps = txr->txr_maps; 16114ccba60fSjmatthew for (i = 0; i < sc->sc_tx_ring_ndescs; i++) { 16124ccba60fSjmatthew txm = &maps[i]; 16134ccba60fSjmatthew 16144ccba60fSjmatthew if (txm->txm_m == NULL) 16154ccba60fSjmatthew continue; 16164ccba60fSjmatthew 16174ccba60fSjmatthew map = txm->txm_map; 16184ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 16194ccba60fSjmatthew BUS_DMASYNC_POSTWRITE); 16204ccba60fSjmatthew bus_dmamap_unload(sc->sc_dmat, map); 16214ccba60fSjmatthew 16224ccba60fSjmatthew m_freem(txm->txm_m); 16234ccba60fSjmatthew txm->txm_m = NULL; 16244ccba60fSjmatthew } 16254ccba60fSjmatthew } 16264ccba60fSjmatthew 16274ccba60fSjmatthew static void 16284ccba60fSjmatthew iavf_txr_free(struct iavf_softc *sc, struct iavf_tx_ring *txr) 16294ccba60fSjmatthew { 16304ccba60fSjmatthew struct iavf_tx_map *maps, *txm; 16314ccba60fSjmatthew unsigned int i; 16324ccba60fSjmatthew 16334ccba60fSjmatthew maps = txr->txr_maps; 16344ccba60fSjmatthew for (i = 0; i < sc->sc_tx_ring_ndescs; i++) { 16354ccba60fSjmatthew txm = &maps[i]; 16364ccba60fSjmatthew 16374ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, txm->txm_map); 16384ccba60fSjmatthew } 16394ccba60fSjmatthew 16404ccba60fSjmatthew iavf_dmamem_free(sc, &txr->txr_mem); 16414ccba60fSjmatthew free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_tx_ring_ndescs); 16424ccba60fSjmatthew free(txr, M_DEVBUF, sizeof(*txr)); 16434ccba60fSjmatthew } 16444ccba60fSjmatthew 16454ccba60fSjmatthew static inline int 16464ccba60fSjmatthew iavf_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m) 16474ccba60fSjmatthew { 16484ccba60fSjmatthew int error; 16494ccba60fSjmatthew 16504ccba60fSjmatthew error = bus_dmamap_load_mbuf(dmat, map, m, 16514ccba60fSjmatthew BUS_DMA_STREAMING | BUS_DMA_NOWAIT); 16524ccba60fSjmatthew if (error != EFBIG) 16534ccba60fSjmatthew return (error); 16544ccba60fSjmatthew 16554ccba60fSjmatthew error = m_defrag(m, M_DONTWAIT); 16564ccba60fSjmatthew if (error != 0) 16574ccba60fSjmatthew return (error); 16584ccba60fSjmatthew 16594ccba60fSjmatthew return (bus_dmamap_load_mbuf(dmat, map, m, 16604ccba60fSjmatthew BUS_DMA_STREAMING | BUS_DMA_NOWAIT)); 16614ccba60fSjmatthew } 16624ccba60fSjmatthew 1663*51248bbdSyasuoka static uint64_t 1664*51248bbdSyasuoka iavf_tx_offload(struct mbuf *m) 1665*51248bbdSyasuoka { 1666*51248bbdSyasuoka struct ether_extracted ext; 1667*51248bbdSyasuoka uint64_t hlen; 1668*51248bbdSyasuoka uint64_t offload = 0; 1669*51248bbdSyasuoka 1670*51248bbdSyasuoka #if NVLAN > 0 1671*51248bbdSyasuoka if (ISSET(m->m_flags, M_VLANTAG)) { 1672*51248bbdSyasuoka uint64_t vtag = m->m_pkthdr.ether_vtag; 1673*51248bbdSyasuoka offload |= IAVF_TX_DESC_CMD_IL2TAG1; 1674*51248bbdSyasuoka offload |= vtag << IAVF_TX_DESC_L2TAG1_SHIFT; 1675*51248bbdSyasuoka } 1676*51248bbdSyasuoka #endif 1677*51248bbdSyasuoka 1678*51248bbdSyasuoka if (!ISSET(m->m_pkthdr.csum_flags, 1679*51248bbdSyasuoka M_IPV4_CSUM_OUT|M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) 1680*51248bbdSyasuoka return (offload); 1681*51248bbdSyasuoka 1682*51248bbdSyasuoka ether_extract_headers(m, &ext); 1683*51248bbdSyasuoka 1684*51248bbdSyasuoka if (ext.ip4) { 1685*51248bbdSyasuoka offload |= ISSET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_OUT) ? 1686*51248bbdSyasuoka IAVF_TX_DESC_CMD_IIPT_IPV4_CSUM : 1687*51248bbdSyasuoka IAVF_TX_DESC_CMD_IIPT_IPV4; 1688*51248bbdSyasuoka #ifdef INET6 1689*51248bbdSyasuoka } else if (ext.ip6) { 1690*51248bbdSyasuoka offload |= IAVF_TX_DESC_CMD_IIPT_IPV6; 1691*51248bbdSyasuoka #endif 1692*51248bbdSyasuoka } else { 1693*51248bbdSyasuoka panic("CSUM_OUT set for non-IP packet"); 1694*51248bbdSyasuoka /* NOTREACHED */ 1695*51248bbdSyasuoka } 1696*51248bbdSyasuoka hlen = ext.iphlen; 1697*51248bbdSyasuoka 1698*51248bbdSyasuoka offload |= (ETHER_HDR_LEN >> 1) << IAVF_TX_DESC_MACLEN_SHIFT; 1699*51248bbdSyasuoka offload |= (hlen >> 2) << IAVF_TX_DESC_IPLEN_SHIFT; 1700*51248bbdSyasuoka 1701*51248bbdSyasuoka if (ext.tcp && ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT)) { 1702*51248bbdSyasuoka offload |= IAVF_TX_DESC_CMD_L4T_EOFT_TCP; 1703*51248bbdSyasuoka offload |= (uint64_t)(ext.tcphlen >> 2) 1704*51248bbdSyasuoka << IAVF_TX_DESC_L4LEN_SHIFT; 1705*51248bbdSyasuoka } else if (ext.udp && ISSET(m->m_pkthdr.csum_flags, M_UDP_CSUM_OUT)) { 1706*51248bbdSyasuoka offload |= IAVF_TX_DESC_CMD_L4T_EOFT_UDP; 1707*51248bbdSyasuoka offload |= (uint64_t)(sizeof(*ext.udp) >> 2) 1708*51248bbdSyasuoka << IAVF_TX_DESC_L4LEN_SHIFT; 1709*51248bbdSyasuoka } 1710*51248bbdSyasuoka 1711*51248bbdSyasuoka return offload; 1712*51248bbdSyasuoka } 1713*51248bbdSyasuoka 17144ccba60fSjmatthew static void 17154ccba60fSjmatthew iavf_start(struct ifqueue *ifq) 17164ccba60fSjmatthew { 17174ccba60fSjmatthew struct ifnet *ifp = ifq->ifq_if; 17184ccba60fSjmatthew struct iavf_softc *sc = ifp->if_softc; 17194ccba60fSjmatthew struct iavf_tx_ring *txr = ifq->ifq_softc; 17204ccba60fSjmatthew struct iavf_tx_desc *ring, *txd; 17214ccba60fSjmatthew struct iavf_tx_map *txm; 17224ccba60fSjmatthew bus_dmamap_t map; 17234ccba60fSjmatthew struct mbuf *m; 17244ccba60fSjmatthew uint64_t cmd; 1725*51248bbdSyasuoka uint64_t offload; 17264ccba60fSjmatthew unsigned int prod, free, last, i; 17274ccba60fSjmatthew unsigned int mask; 17284ccba60fSjmatthew int post = 0; 17294ccba60fSjmatthew #if NBPFILTER > 0 17304ccba60fSjmatthew caddr_t if_bpf; 17314ccba60fSjmatthew #endif 17324ccba60fSjmatthew 17334ccba60fSjmatthew if (!LINK_STATE_IS_UP(ifp->if_link_state)) { 17344ccba60fSjmatthew ifq_purge(ifq); 17354ccba60fSjmatthew return; 17364ccba60fSjmatthew } 17374ccba60fSjmatthew 17384ccba60fSjmatthew prod = txr->txr_prod; 17394ccba60fSjmatthew free = txr->txr_cons; 17404ccba60fSjmatthew if (free <= prod) 17414ccba60fSjmatthew free += sc->sc_tx_ring_ndescs; 17424ccba60fSjmatthew free -= prod; 17434ccba60fSjmatthew 17444ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem), 17454ccba60fSjmatthew 0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_POSTWRITE); 17464ccba60fSjmatthew 17474ccba60fSjmatthew ring = IAVF_DMA_KVA(&txr->txr_mem); 17484ccba60fSjmatthew mask = sc->sc_tx_ring_ndescs - 1; 17494ccba60fSjmatthew 17504ccba60fSjmatthew for (;;) { 17514ccba60fSjmatthew if (free <= IAVF_TX_PKT_DESCS) { 17524ccba60fSjmatthew ifq_set_oactive(ifq); 17534ccba60fSjmatthew break; 17544ccba60fSjmatthew } 17554ccba60fSjmatthew 17564ccba60fSjmatthew m = ifq_dequeue(ifq); 17574ccba60fSjmatthew if (m == NULL) 17584ccba60fSjmatthew break; 17594ccba60fSjmatthew 1760*51248bbdSyasuoka offload = iavf_tx_offload(m); 1761*51248bbdSyasuoka 17624ccba60fSjmatthew txm = &txr->txr_maps[prod]; 17634ccba60fSjmatthew map = txm->txm_map; 17644ccba60fSjmatthew 17654ccba60fSjmatthew if (iavf_load_mbuf(sc->sc_dmat, map, m) != 0) { 17664ccba60fSjmatthew ifq->ifq_errors++; 17674ccba60fSjmatthew m_freem(m); 17684ccba60fSjmatthew continue; 17694ccba60fSjmatthew } 17704ccba60fSjmatthew 17714ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, 17724ccba60fSjmatthew map->dm_mapsize, BUS_DMASYNC_PREWRITE); 17734ccba60fSjmatthew 17744ccba60fSjmatthew for (i = 0; i < map->dm_nsegs; i++) { 17754ccba60fSjmatthew txd = &ring[prod]; 17764ccba60fSjmatthew 17774ccba60fSjmatthew cmd = (uint64_t)map->dm_segs[i].ds_len << 17784ccba60fSjmatthew IAVF_TX_DESC_BSIZE_SHIFT; 1779*51248bbdSyasuoka cmd |= IAVF_TX_DESC_DTYPE_DATA | IAVF_TX_DESC_CMD_ICRC; 1780*51248bbdSyasuoka cmd |= offload; 17814ccba60fSjmatthew 17824ccba60fSjmatthew htolem64(&txd->addr, map->dm_segs[i].ds_addr); 17834ccba60fSjmatthew htolem64(&txd->cmd, cmd); 17844ccba60fSjmatthew 17854ccba60fSjmatthew last = prod; 17864ccba60fSjmatthew 17874ccba60fSjmatthew prod++; 17884ccba60fSjmatthew prod &= mask; 17894ccba60fSjmatthew } 17904ccba60fSjmatthew cmd |= IAVF_TX_DESC_CMD_EOP | IAVF_TX_DESC_CMD_RS; 17914ccba60fSjmatthew htolem64(&txd->cmd, cmd); 17924ccba60fSjmatthew 17934ccba60fSjmatthew txm->txm_m = m; 17944ccba60fSjmatthew txm->txm_eop = last; 17954ccba60fSjmatthew 17964ccba60fSjmatthew #if NBPFILTER > 0 17974ccba60fSjmatthew if_bpf = ifp->if_bpf; 17984ccba60fSjmatthew if (if_bpf) 17994ccba60fSjmatthew bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT); 18004ccba60fSjmatthew #endif 18014ccba60fSjmatthew 18024ccba60fSjmatthew free -= i; 18034ccba60fSjmatthew post = 1; 18044ccba60fSjmatthew } 18054ccba60fSjmatthew 18064ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem), 18074ccba60fSjmatthew 0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_PREWRITE); 18084ccba60fSjmatthew 18094ccba60fSjmatthew if (post) { 18104ccba60fSjmatthew txr->txr_prod = prod; 18114ccba60fSjmatthew iavf_wr(sc, txr->txr_tail, prod); 18124ccba60fSjmatthew } 18134ccba60fSjmatthew } 18144ccba60fSjmatthew 18154ccba60fSjmatthew static int 18164ccba60fSjmatthew iavf_txeof(struct iavf_softc *sc, struct ifqueue *ifq) 18174ccba60fSjmatthew { 18184ccba60fSjmatthew struct iavf_tx_ring *txr = ifq->ifq_softc; 18194ccba60fSjmatthew struct iavf_tx_desc *ring, *txd; 18204ccba60fSjmatthew struct iavf_tx_map *txm; 18214ccba60fSjmatthew bus_dmamap_t map; 18224ccba60fSjmatthew unsigned int cons, prod, last; 18234ccba60fSjmatthew unsigned int mask; 18244ccba60fSjmatthew uint64_t dtype; 18254ccba60fSjmatthew int done = 0; 18264ccba60fSjmatthew 18274ccba60fSjmatthew prod = txr->txr_prod; 18284ccba60fSjmatthew cons = txr->txr_cons; 18294ccba60fSjmatthew 18304ccba60fSjmatthew if (cons == prod) 18314ccba60fSjmatthew return (0); 18324ccba60fSjmatthew 18334ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem), 18344ccba60fSjmatthew 0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_POSTREAD); 18354ccba60fSjmatthew 18364ccba60fSjmatthew ring = IAVF_DMA_KVA(&txr->txr_mem); 18374ccba60fSjmatthew mask = sc->sc_tx_ring_ndescs - 1; 18384ccba60fSjmatthew 18394ccba60fSjmatthew do { 18404ccba60fSjmatthew txm = &txr->txr_maps[cons]; 18414ccba60fSjmatthew last = txm->txm_eop; 18424ccba60fSjmatthew txd = &ring[last]; 18434ccba60fSjmatthew 18444ccba60fSjmatthew dtype = txd->cmd & htole64(IAVF_TX_DESC_DTYPE_MASK); 18454ccba60fSjmatthew if (dtype != htole64(IAVF_TX_DESC_DTYPE_DONE)) 18464ccba60fSjmatthew break; 18474ccba60fSjmatthew 18484ccba60fSjmatthew map = txm->txm_map; 18494ccba60fSjmatthew 18504ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 18514ccba60fSjmatthew BUS_DMASYNC_POSTWRITE); 18524ccba60fSjmatthew bus_dmamap_unload(sc->sc_dmat, map); 18534ccba60fSjmatthew m_freem(txm->txm_m); 18544ccba60fSjmatthew 18554ccba60fSjmatthew txm->txm_m = NULL; 18564ccba60fSjmatthew txm->txm_eop = -1; 18574ccba60fSjmatthew 18584ccba60fSjmatthew cons = last + 1; 18594ccba60fSjmatthew cons &= mask; 18604ccba60fSjmatthew 18614ccba60fSjmatthew done = 1; 18624ccba60fSjmatthew } while (cons != prod); 18634ccba60fSjmatthew 18644ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&txr->txr_mem), 18654ccba60fSjmatthew 0, IAVF_DMA_LEN(&txr->txr_mem), BUS_DMASYNC_PREREAD); 18664ccba60fSjmatthew 18674ccba60fSjmatthew txr->txr_cons = cons; 18684ccba60fSjmatthew 18694ccba60fSjmatthew //ixl_enable(sc, txr->txr_msix); 18704ccba60fSjmatthew 18714ccba60fSjmatthew if (ifq_is_oactive(ifq)) 18724ccba60fSjmatthew ifq_restart(ifq); 18734ccba60fSjmatthew 18744ccba60fSjmatthew return (done); 18754ccba60fSjmatthew } 18764ccba60fSjmatthew 18774ccba60fSjmatthew static struct iavf_rx_ring * 18784ccba60fSjmatthew iavf_rxr_alloc(struct iavf_softc *sc, unsigned int qid) 18794ccba60fSjmatthew { 18804ccba60fSjmatthew struct iavf_rx_ring *rxr; 18814ccba60fSjmatthew struct iavf_rx_map *maps, *rxm; 18824ccba60fSjmatthew unsigned int i; 18834ccba60fSjmatthew 18844ccba60fSjmatthew rxr = malloc(sizeof(*rxr), M_DEVBUF, M_WAITOK|M_CANFAIL); 18854ccba60fSjmatthew if (rxr == NULL) 18864ccba60fSjmatthew return (NULL); 18874ccba60fSjmatthew 18884ccba60fSjmatthew maps = mallocarray(sizeof(*maps), 18894ccba60fSjmatthew sc->sc_rx_ring_ndescs, M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 18904ccba60fSjmatthew if (maps == NULL) 18914ccba60fSjmatthew goto free; 18924ccba60fSjmatthew 18934ccba60fSjmatthew if (iavf_dmamem_alloc(sc, &rxr->rxr_mem, 18944ccba60fSjmatthew sizeof(struct iavf_rx_rd_desc_32) * sc->sc_rx_ring_ndescs, 18954ccba60fSjmatthew IAVF_RX_QUEUE_ALIGN) != 0) 18964ccba60fSjmatthew goto freemap; 18974ccba60fSjmatthew 18984ccba60fSjmatthew for (i = 0; i < sc->sc_rx_ring_ndescs; i++) { 18994ccba60fSjmatthew rxm = &maps[i]; 19004ccba60fSjmatthew 19014ccba60fSjmatthew if (bus_dmamap_create(sc->sc_dmat, 19024ccba60fSjmatthew IAVF_HARDMTU, 1, IAVF_HARDMTU, 0, 19034ccba60fSjmatthew BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, 19044ccba60fSjmatthew &rxm->rxm_map) != 0) 19054ccba60fSjmatthew goto uncreate; 19064ccba60fSjmatthew 19074ccba60fSjmatthew rxm->rxm_m = NULL; 19084ccba60fSjmatthew } 19094ccba60fSjmatthew 19104ccba60fSjmatthew rxr->rxr_sc = sc; 19114ccba60fSjmatthew if_rxr_init(&rxr->rxr_acct, 17, sc->sc_rx_ring_ndescs - 1); 19124ccba60fSjmatthew timeout_set(&rxr->rxr_refill, iavf_rxrefill, rxr); 19134ccba60fSjmatthew rxr->rxr_cons = rxr->rxr_prod = 0; 19144ccba60fSjmatthew rxr->rxr_m_head = NULL; 19154ccba60fSjmatthew rxr->rxr_m_tail = &rxr->rxr_m_head; 19164ccba60fSjmatthew rxr->rxr_maps = maps; 19174ccba60fSjmatthew 19184ccba60fSjmatthew rxr->rxr_tail = I40E_QRX_TAIL1(qid); 19194ccba60fSjmatthew rxr->rxr_qid = qid; 19204ccba60fSjmatthew 19214ccba60fSjmatthew return (rxr); 19224ccba60fSjmatthew 19234ccba60fSjmatthew uncreate: 19244ccba60fSjmatthew for (i = 0; i < sc->sc_rx_ring_ndescs; i++) { 19254ccba60fSjmatthew rxm = &maps[i]; 19264ccba60fSjmatthew 19274ccba60fSjmatthew if (rxm->rxm_map == NULL) 19284ccba60fSjmatthew continue; 19294ccba60fSjmatthew 19304ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, rxm->rxm_map); 19314ccba60fSjmatthew } 19324ccba60fSjmatthew 19334ccba60fSjmatthew iavf_dmamem_free(sc, &rxr->rxr_mem); 19344ccba60fSjmatthew freemap: 19354ccba60fSjmatthew free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_rx_ring_ndescs); 19364ccba60fSjmatthew free: 19374ccba60fSjmatthew free(rxr, M_DEVBUF, sizeof(*rxr)); 19384ccba60fSjmatthew return (NULL); 19394ccba60fSjmatthew } 19404ccba60fSjmatthew 19414ccba60fSjmatthew static void 19424ccba60fSjmatthew iavf_rxr_clean(struct iavf_softc *sc, struct iavf_rx_ring *rxr) 19434ccba60fSjmatthew { 19444ccba60fSjmatthew struct iavf_rx_map *maps, *rxm; 19454ccba60fSjmatthew bus_dmamap_t map; 19464ccba60fSjmatthew unsigned int i; 19474ccba60fSjmatthew 19484ccba60fSjmatthew timeout_del_barrier(&rxr->rxr_refill); 19494ccba60fSjmatthew 19504ccba60fSjmatthew maps = rxr->rxr_maps; 19514ccba60fSjmatthew for (i = 0; i < sc->sc_rx_ring_ndescs; i++) { 19524ccba60fSjmatthew rxm = &maps[i]; 19534ccba60fSjmatthew 19544ccba60fSjmatthew if (rxm->rxm_m == NULL) 19554ccba60fSjmatthew continue; 19564ccba60fSjmatthew 19574ccba60fSjmatthew map = rxm->rxm_map; 19584ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 19594ccba60fSjmatthew BUS_DMASYNC_POSTWRITE); 19604ccba60fSjmatthew bus_dmamap_unload(sc->sc_dmat, map); 19614ccba60fSjmatthew 19624ccba60fSjmatthew m_freem(rxm->rxm_m); 19634ccba60fSjmatthew rxm->rxm_m = NULL; 19644ccba60fSjmatthew } 19654ccba60fSjmatthew 19664ccba60fSjmatthew m_freem(rxr->rxr_m_head); 19674ccba60fSjmatthew rxr->rxr_m_head = NULL; 19684ccba60fSjmatthew rxr->rxr_m_tail = &rxr->rxr_m_head; 19694ccba60fSjmatthew 19704ccba60fSjmatthew rxr->rxr_prod = rxr->rxr_cons = 0; 19714ccba60fSjmatthew } 19724ccba60fSjmatthew 19734ccba60fSjmatthew static void 19744ccba60fSjmatthew iavf_rxr_free(struct iavf_softc *sc, struct iavf_rx_ring *rxr) 19754ccba60fSjmatthew { 19764ccba60fSjmatthew struct iavf_rx_map *maps, *rxm; 19774ccba60fSjmatthew unsigned int i; 19784ccba60fSjmatthew 19794ccba60fSjmatthew maps = rxr->rxr_maps; 19804ccba60fSjmatthew for (i = 0; i < sc->sc_rx_ring_ndescs; i++) { 19814ccba60fSjmatthew rxm = &maps[i]; 19824ccba60fSjmatthew 19834ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, rxm->rxm_map); 19844ccba60fSjmatthew } 19854ccba60fSjmatthew 19864ccba60fSjmatthew iavf_dmamem_free(sc, &rxr->rxr_mem); 19874ccba60fSjmatthew free(maps, M_DEVBUF, sizeof(*maps) * sc->sc_rx_ring_ndescs); 19884ccba60fSjmatthew free(rxr, M_DEVBUF, sizeof(*rxr)); 19894ccba60fSjmatthew } 19904ccba60fSjmatthew 1991*51248bbdSyasuoka static void 1992*51248bbdSyasuoka iavf_rx_checksum(struct mbuf *m, uint64_t word) 1993*51248bbdSyasuoka { 1994*51248bbdSyasuoka if (!ISSET(word, IAVF_RX_DESC_L3L4P)) 1995*51248bbdSyasuoka return; 1996*51248bbdSyasuoka 1997*51248bbdSyasuoka if (ISSET(word, IAVF_RX_DESC_IPE)) 1998*51248bbdSyasuoka return; 1999*51248bbdSyasuoka 2000*51248bbdSyasuoka m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 2001*51248bbdSyasuoka 2002*51248bbdSyasuoka if (ISSET(word, IAVF_RX_DESC_L4E)) 2003*51248bbdSyasuoka return; 2004*51248bbdSyasuoka 2005*51248bbdSyasuoka m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK; 2006*51248bbdSyasuoka } 2007*51248bbdSyasuoka 2008*51248bbdSyasuoka 20094ccba60fSjmatthew static int 20104ccba60fSjmatthew iavf_rxeof(struct iavf_softc *sc, struct ifiqueue *ifiq) 20114ccba60fSjmatthew { 20124ccba60fSjmatthew struct iavf_rx_ring *rxr = ifiq->ifiq_softc; 20134ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 20144ccba60fSjmatthew struct iavf_rx_wb_desc_32 *ring, *rxd; 20154ccba60fSjmatthew struct iavf_rx_map *rxm; 20164ccba60fSjmatthew bus_dmamap_t map; 20174ccba60fSjmatthew unsigned int cons, prod; 20184ccba60fSjmatthew struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 20194ccba60fSjmatthew struct mbuf *m; 20204ccba60fSjmatthew uint64_t word; 20213e0b52e8Sjmatthew uint16_t vlan; 20224ccba60fSjmatthew unsigned int len; 20234ccba60fSjmatthew unsigned int mask; 20244ccba60fSjmatthew int done = 0; 20254ccba60fSjmatthew 20264ccba60fSjmatthew if (!ISSET(ifp->if_flags, IFF_RUNNING)) 20274ccba60fSjmatthew return (0); 20284ccba60fSjmatthew 20294ccba60fSjmatthew prod = rxr->rxr_prod; 20304ccba60fSjmatthew cons = rxr->rxr_cons; 20314ccba60fSjmatthew 20324ccba60fSjmatthew if (cons == prod) 20334ccba60fSjmatthew return (0); 20344ccba60fSjmatthew 20354ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&rxr->rxr_mem), 20364ccba60fSjmatthew 0, IAVF_DMA_LEN(&rxr->rxr_mem), 20374ccba60fSjmatthew BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 20384ccba60fSjmatthew 20394ccba60fSjmatthew ring = IAVF_DMA_KVA(&rxr->rxr_mem); 20404ccba60fSjmatthew mask = sc->sc_rx_ring_ndescs - 1; 20414ccba60fSjmatthew 20424ccba60fSjmatthew do { 20434ccba60fSjmatthew rxd = &ring[cons]; 20444ccba60fSjmatthew 20454ccba60fSjmatthew word = lemtoh64(&rxd->qword1); 20464ccba60fSjmatthew if (!ISSET(word, IAVF_RX_DESC_DD)) 20474ccba60fSjmatthew break; 20484ccba60fSjmatthew 20494ccba60fSjmatthew if_rxr_put(&rxr->rxr_acct, 1); 20504ccba60fSjmatthew 20514ccba60fSjmatthew rxm = &rxr->rxr_maps[cons]; 20524ccba60fSjmatthew 20534ccba60fSjmatthew map = rxm->rxm_map; 20544ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 20554ccba60fSjmatthew BUS_DMASYNC_POSTREAD); 20564ccba60fSjmatthew bus_dmamap_unload(sc->sc_dmat, map); 20574ccba60fSjmatthew 20584ccba60fSjmatthew m = rxm->rxm_m; 20594ccba60fSjmatthew rxm->rxm_m = NULL; 20604ccba60fSjmatthew 20614ccba60fSjmatthew len = (word & IAVF_RX_DESC_PLEN_MASK) >> IAVF_RX_DESC_PLEN_SHIFT; 20624ccba60fSjmatthew m->m_len = len; 20634ccba60fSjmatthew m->m_pkthdr.len = 0; 20644ccba60fSjmatthew 20654ccba60fSjmatthew m->m_next = NULL; 20664ccba60fSjmatthew *rxr->rxr_m_tail = m; 20674ccba60fSjmatthew rxr->rxr_m_tail = &m->m_next; 20684ccba60fSjmatthew 20694ccba60fSjmatthew m = rxr->rxr_m_head; 20704ccba60fSjmatthew m->m_pkthdr.len += len; 20714ccba60fSjmatthew 20724ccba60fSjmatthew if (ISSET(word, IAVF_RX_DESC_EOP)) { 2073*51248bbdSyasuoka #if NVLAN > 0 20743e0b52e8Sjmatthew if (ISSET(word, IAVF_RX_DESC_L2TAG1P)) { 20753e0b52e8Sjmatthew vlan = (lemtoh64(&rxd->qword0) & 20763e0b52e8Sjmatthew IAVF_RX_DESC_L2TAG1_MASK) 20773e0b52e8Sjmatthew >> IAVF_RX_DESC_L2TAG1_SHIFT; 20783e0b52e8Sjmatthew m->m_pkthdr.ether_vtag = vlan; 20793e0b52e8Sjmatthew m->m_flags |= M_VLANTAG; 20803e0b52e8Sjmatthew } 2081*51248bbdSyasuoka #endif 20824ccba60fSjmatthew if (!ISSET(word, 20834ccba60fSjmatthew IAVF_RX_DESC_RXE | IAVF_RX_DESC_OVERSIZE)) { 2084*51248bbdSyasuoka iavf_rx_checksum(m, word); 20854ccba60fSjmatthew ml_enqueue(&ml, m); 20864ccba60fSjmatthew } else { 20874ccba60fSjmatthew ifp->if_ierrors++; /* XXX */ 20884ccba60fSjmatthew m_freem(m); 20894ccba60fSjmatthew } 20904ccba60fSjmatthew 20914ccba60fSjmatthew rxr->rxr_m_head = NULL; 20924ccba60fSjmatthew rxr->rxr_m_tail = &rxr->rxr_m_head; 20934ccba60fSjmatthew } 20944ccba60fSjmatthew 20954ccba60fSjmatthew cons++; 20964ccba60fSjmatthew cons &= mask; 20974ccba60fSjmatthew 20984ccba60fSjmatthew done = 1; 20994ccba60fSjmatthew } while (cons != prod); 21004ccba60fSjmatthew 21014ccba60fSjmatthew if (done) { 21024ccba60fSjmatthew rxr->rxr_cons = cons; 21034ccba60fSjmatthew if (ifiq_input(ifiq, &ml)) 21044ccba60fSjmatthew if_rxr_livelocked(&rxr->rxr_acct); 21054ccba60fSjmatthew iavf_rxfill(sc, rxr); 21064ccba60fSjmatthew } 21074ccba60fSjmatthew 21084ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&rxr->rxr_mem), 21094ccba60fSjmatthew 0, IAVF_DMA_LEN(&rxr->rxr_mem), 21104ccba60fSjmatthew BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 21114ccba60fSjmatthew 21124ccba60fSjmatthew return (done); 21134ccba60fSjmatthew } 21144ccba60fSjmatthew 21154ccba60fSjmatthew static void 21164ccba60fSjmatthew iavf_rxfill(struct iavf_softc *sc, struct iavf_rx_ring *rxr) 21174ccba60fSjmatthew { 21184ccba60fSjmatthew struct iavf_rx_rd_desc_32 *ring, *rxd; 21194ccba60fSjmatthew struct iavf_rx_map *rxm; 21204ccba60fSjmatthew bus_dmamap_t map; 21214ccba60fSjmatthew struct mbuf *m; 21224ccba60fSjmatthew unsigned int prod; 21234ccba60fSjmatthew unsigned int slots; 21244ccba60fSjmatthew unsigned int mask; 21254ccba60fSjmatthew int post = 0; 21264ccba60fSjmatthew 21274ccba60fSjmatthew slots = if_rxr_get(&rxr->rxr_acct, sc->sc_rx_ring_ndescs); 21284ccba60fSjmatthew if (slots == 0) 21294ccba60fSjmatthew return; 21304ccba60fSjmatthew 21314ccba60fSjmatthew prod = rxr->rxr_prod; 21324ccba60fSjmatthew 21334ccba60fSjmatthew ring = IAVF_DMA_KVA(&rxr->rxr_mem); 21344ccba60fSjmatthew mask = sc->sc_rx_ring_ndescs - 1; 21354ccba60fSjmatthew 21364ccba60fSjmatthew do { 21374ccba60fSjmatthew rxm = &rxr->rxr_maps[prod]; 21384ccba60fSjmatthew 2139471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES + ETHER_ALIGN); 21404ccba60fSjmatthew if (m == NULL) 21414ccba60fSjmatthew break; 21424ccba60fSjmatthew m->m_data += (m->m_ext.ext_size - (MCLBYTES + ETHER_ALIGN)); 21434ccba60fSjmatthew m->m_len = m->m_pkthdr.len = MCLBYTES + ETHER_ALIGN; 21444ccba60fSjmatthew 21454ccba60fSjmatthew map = rxm->rxm_map; 21464ccba60fSjmatthew 21474ccba60fSjmatthew if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, 21484ccba60fSjmatthew BUS_DMA_NOWAIT) != 0) { 21494ccba60fSjmatthew m_freem(m); 21504ccba60fSjmatthew break; 21514ccba60fSjmatthew } 21524ccba60fSjmatthew 21534ccba60fSjmatthew rxm->rxm_m = m; 21544ccba60fSjmatthew 21554ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 21564ccba60fSjmatthew BUS_DMASYNC_PREREAD); 21574ccba60fSjmatthew 21584ccba60fSjmatthew rxd = &ring[prod]; 21594ccba60fSjmatthew 21604ccba60fSjmatthew htolem64(&rxd->paddr, map->dm_segs[0].ds_addr); 21614ccba60fSjmatthew rxd->haddr = htole64(0); 21624ccba60fSjmatthew 21634ccba60fSjmatthew prod++; 21644ccba60fSjmatthew prod &= mask; 21654ccba60fSjmatthew 21664ccba60fSjmatthew post = 1; 21674ccba60fSjmatthew } while (--slots); 21684ccba60fSjmatthew 21694ccba60fSjmatthew if_rxr_put(&rxr->rxr_acct, slots); 21704ccba60fSjmatthew 21714ccba60fSjmatthew if (if_rxr_inuse(&rxr->rxr_acct) == 0) 21724ccba60fSjmatthew timeout_add(&rxr->rxr_refill, 1); 21734ccba60fSjmatthew else if (post) { 21744ccba60fSjmatthew rxr->rxr_prod = prod; 21754ccba60fSjmatthew iavf_wr(sc, rxr->rxr_tail, prod); 21764ccba60fSjmatthew } 21774ccba60fSjmatthew } 21784ccba60fSjmatthew 21794ccba60fSjmatthew void 21804ccba60fSjmatthew iavf_rxrefill(void *arg) 21814ccba60fSjmatthew { 21824ccba60fSjmatthew struct iavf_rx_ring *rxr = arg; 21834ccba60fSjmatthew struct iavf_softc *sc = rxr->rxr_sc; 21844ccba60fSjmatthew 21854ccba60fSjmatthew iavf_rxfill(sc, rxr); 21864ccba60fSjmatthew } 21874ccba60fSjmatthew 21884ccba60fSjmatthew static int 21894ccba60fSjmatthew iavf_rxrinfo(struct iavf_softc *sc, struct if_rxrinfo *ifri) 21904ccba60fSjmatthew { 21914ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 21924ccba60fSjmatthew struct if_rxring_info *ifr; 21934ccba60fSjmatthew struct iavf_rx_ring *ring; 21944ccba60fSjmatthew int i, rv; 21954ccba60fSjmatthew 21964ccba60fSjmatthew if (!ISSET(ifp->if_flags, IFF_RUNNING)) 21974ccba60fSjmatthew return (ENOTTY); 21984ccba60fSjmatthew 21994ccba60fSjmatthew ifr = mallocarray(sizeof(*ifr), iavf_nqueues(sc), M_TEMP, 22004ccba60fSjmatthew M_WAITOK|M_CANFAIL|M_ZERO); 22014ccba60fSjmatthew if (ifr == NULL) 22024ccba60fSjmatthew return (ENOMEM); 22034ccba60fSjmatthew 22044ccba60fSjmatthew for (i = 0; i < iavf_nqueues(sc); i++) { 22054ccba60fSjmatthew ring = ifp->if_iqs[i]->ifiq_softc; 22064ccba60fSjmatthew ifr[i].ifr_size = MCLBYTES; 22074ccba60fSjmatthew ifr[i].ifr_info = ring->rxr_acct; 22084ccba60fSjmatthew } 22094ccba60fSjmatthew 22104ccba60fSjmatthew rv = if_rxr_info_ioctl(ifri, iavf_nqueues(sc), ifr); 22114ccba60fSjmatthew free(ifr, M_TEMP, iavf_nqueues(sc) * sizeof(*ifr)); 22124ccba60fSjmatthew 22134ccba60fSjmatthew return (rv); 22144ccba60fSjmatthew } 22154ccba60fSjmatthew 22164ccba60fSjmatthew static int 22174ccba60fSjmatthew iavf_intr(void *xsc) 22184ccba60fSjmatthew { 22194ccba60fSjmatthew struct iavf_softc *sc = xsc; 22204ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 22214ccba60fSjmatthew uint32_t icr, ena; 22224ccba60fSjmatthew int i, rv = 0; 22234ccba60fSjmatthew 22244ccba60fSjmatthew ena = iavf_rd(sc, I40E_VFINT_ICR0_ENA1); 22254ccba60fSjmatthew iavf_intr_enable(sc); 22264ccba60fSjmatthew icr = iavf_rd(sc, I40E_VFINT_ICR01); 22274ccba60fSjmatthew 22282fa30b92Sjmatthew if (icr == IAVF_REG_VFR) { 22292fa30b92Sjmatthew printf("%s: VF reset in progress\n", DEVNAME(sc)); 22302fa30b92Sjmatthew sc->sc_resetting = 1; 22312fa30b92Sjmatthew task_add(systq, &sc->sc_reset_task); 22322fa30b92Sjmatthew return (1); 22332fa30b92Sjmatthew } 22342fa30b92Sjmatthew 22354ccba60fSjmatthew if (ISSET(icr, I40E_VFINT_ICR01_ADMINQ_MASK)) { 22364ccba60fSjmatthew iavf_atq_done(sc); 2237e13657b7Sjmatthew iavf_process_arq(sc, 0); 22384ccba60fSjmatthew rv = 1; 22394ccba60fSjmatthew } 22404ccba60fSjmatthew 22414ccba60fSjmatthew if (ISSET(icr, I40E_VFINT_ICR01_QUEUE_0_MASK)) { 22424ccba60fSjmatthew for (i = 0; i < iavf_nqueues(sc); i++) { 22434ccba60fSjmatthew rv |= iavf_rxeof(sc, ifp->if_iqs[i]); 22444ccba60fSjmatthew rv |= iavf_txeof(sc, ifp->if_ifqs[i]); 22454ccba60fSjmatthew } 22464ccba60fSjmatthew } 22474ccba60fSjmatthew 22484ccba60fSjmatthew return (rv); 22494ccba60fSjmatthew } 22504ccba60fSjmatthew 22514ccba60fSjmatthew static void 22524ccba60fSjmatthew iavf_process_vf_resources(struct iavf_softc *sc, struct iavf_aq_desc *desc, 22534ccba60fSjmatthew struct iavf_aq_buf *buf) 22544ccba60fSjmatthew { 22554ccba60fSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 22564ccba60fSjmatthew struct iavf_vc_vf_resource *vf_res; 22574ccba60fSjmatthew struct iavf_vc_vsi_resource *vsi_res; 22584ccba60fSjmatthew int mtu; 22594ccba60fSjmatthew 22604ccba60fSjmatthew sc->sc_got_vf_resources = 1; 22614ccba60fSjmatthew 22624ccba60fSjmatthew vf_res = buf->aqb_data; 22634ccba60fSjmatthew if (letoh16(vf_res->num_vsis) == 0) { 22644ccba60fSjmatthew printf(", no VSI available\n"); 22654ccba60fSjmatthew /* set vsi number to something */ 22664ccba60fSjmatthew return; 22674ccba60fSjmatthew } 22684ccba60fSjmatthew 22694ccba60fSjmatthew mtu = letoh16(vf_res->max_mtu); 22704ccba60fSjmatthew if (mtu != 0) 22714ccba60fSjmatthew ifp->if_hardmtu = MIN(IAVF_HARDMTU, mtu); 22724ccba60fSjmatthew 22734ccba60fSjmatthew /* limit vectors to what we got here? */ 22744ccba60fSjmatthew 22754ccba60fSjmatthew /* just take the first vsi */ 22764ccba60fSjmatthew vsi_res = &vf_res->vsi_res[0]; 22774ccba60fSjmatthew sc->sc_vsi_id = letoh16(vsi_res->vsi_id); 22784ccba60fSjmatthew sc->sc_qset_handle = letoh16(vsi_res->qset_handle); 22794ccba60fSjmatthew /* limit number of queues to what we got here */ 22804ccba60fSjmatthew /* is vsi type interesting? */ 22814ccba60fSjmatthew 22824ccba60fSjmatthew sc->sc_vf_id = letoh32(desc->iaq_param[0]); 22834ccba60fSjmatthew 22844ccba60fSjmatthew memcpy(sc->sc_ac.ac_enaddr, vsi_res->default_mac, ETHER_ADDR_LEN); 22852fa30b92Sjmatthew 22862fa30b92Sjmatthew if (sc->sc_resetting == 0) 22874ccba60fSjmatthew printf(", VF %d VSI %d", sc->sc_vf_id, sc->sc_vsi_id); 22884ccba60fSjmatthew } 22894ccba60fSjmatthew 2290baed872eSjmatthew static const struct iavf_link_speed * 2291baed872eSjmatthew iavf_find_link_speed(struct iavf_softc *sc, uint32_t link_speed) 2292baed872eSjmatthew { 2293baed872eSjmatthew int i; 2294baed872eSjmatthew for (i = 0; i < nitems(iavf_link_speeds); i++) { 2295baed872eSjmatthew if (link_speed & (1 << i)) 2296baed872eSjmatthew return (&iavf_link_speeds[i]); 2297baed872eSjmatthew } 2298baed872eSjmatthew 2299baed872eSjmatthew return (NULL); 2300baed872eSjmatthew } 2301baed872eSjmatthew 23024ccba60fSjmatthew static void 23034ccba60fSjmatthew iavf_process_vc_event(struct iavf_softc *sc, struct iavf_aq_desc *desc, 23044ccba60fSjmatthew struct iavf_aq_buf *buf) 23054ccba60fSjmatthew { 23064ccba60fSjmatthew struct iavf_vc_pf_event *event; 2307baed872eSjmatthew struct ifnet *ifp = &sc->sc_ac.ac_if; 2308baed872eSjmatthew const struct iavf_link_speed *speed; 2309baed872eSjmatthew int link; 23104ccba60fSjmatthew 23114ccba60fSjmatthew event = buf->aqb_data; 23124ccba60fSjmatthew switch (event->event) { 23134ccba60fSjmatthew case IAVF_VC_EVENT_LINK_CHANGE: 2314baed872eSjmatthew sc->sc_media_status = IFM_AVALID; 2315baed872eSjmatthew sc->sc_media_active = IFM_ETHER; 2316baed872eSjmatthew link = LINK_STATE_DOWN; 2317baed872eSjmatthew if (event->link_status) { 2318baed872eSjmatthew link = LINK_STATE_UP; 2319baed872eSjmatthew sc->sc_media_status |= IFM_ACTIVE; 2320baed872eSjmatthew 2321baed872eSjmatthew ifp->if_baudrate = 0; 2322baed872eSjmatthew speed = iavf_find_link_speed(sc, event->link_speed); 2323baed872eSjmatthew if (speed != NULL) { 2324baed872eSjmatthew sc->sc_media_active |= speed->media; 2325baed872eSjmatthew ifp->if_baudrate = speed->baudrate; 2326baed872eSjmatthew } 2327baed872eSjmatthew } 2328baed872eSjmatthew 2329baed872eSjmatthew if (ifp->if_link_state != link) { 2330baed872eSjmatthew ifp->if_link_state = link; 2331baed872eSjmatthew if_link_state_change(ifp); 2332baed872eSjmatthew } 23334ccba60fSjmatthew break; 23344ccba60fSjmatthew 23354ccba60fSjmatthew default: 23364ccba60fSjmatthew break; 23374ccba60fSjmatthew } 23384ccba60fSjmatthew } 23394ccba60fSjmatthew 23404ccba60fSjmatthew static void 23414ccba60fSjmatthew iavf_process_irq_map(struct iavf_softc *sc, struct iavf_aq_desc *desc) 23424ccba60fSjmatthew { 23434ccba60fSjmatthew if (letoh32(desc->iaq_vc_retval) != IAVF_VC_RC_SUCCESS) { 23444ccba60fSjmatthew printf("config irq map failed: %d\n", letoh32(desc->iaq_vc_retval)); 23454ccba60fSjmatthew } 23464ccba60fSjmatthew sc->sc_got_irq_map = 1; 23474ccba60fSjmatthew } 23484ccba60fSjmatthew 23492fa30b92Sjmatthew static void 23502fa30b92Sjmatthew iavf_init_admin_queue(struct iavf_softc *sc) 23512fa30b92Sjmatthew { 23522fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_head, 0); 23532fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_head, 0); 23542fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_tail, 0); 23552fa30b92Sjmatthew 23562fa30b92Sjmatthew iavf_barrier(sc, 0, sc->sc_mems, BUS_SPACE_BARRIER_WRITE); 23572fa30b92Sjmatthew 23582fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_bal, 23592fa30b92Sjmatthew iavf_dmamem_lo(&sc->sc_atq)); 23602fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_bah, 23612fa30b92Sjmatthew iavf_dmamem_hi(&sc->sc_atq)); 23622fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_len, 23632fa30b92Sjmatthew sc->sc_aq_regs->atq_len_enable | IAVF_AQ_NUM); 23642fa30b92Sjmatthew 23652fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_bal, 23662fa30b92Sjmatthew iavf_dmamem_lo(&sc->sc_arq)); 23672fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_bah, 23682fa30b92Sjmatthew iavf_dmamem_hi(&sc->sc_arq)); 23692fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_len, 23702fa30b92Sjmatthew sc->sc_aq_regs->arq_len_enable | IAVF_AQ_NUM); 23712fa30b92Sjmatthew 23722fa30b92Sjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod); 23732fa30b92Sjmatthew } 23742fa30b92Sjmatthew 23754ccba60fSjmatthew static int 2376e13657b7Sjmatthew iavf_process_arq(struct iavf_softc *sc, int fill) 23774ccba60fSjmatthew { 23784ccba60fSjmatthew struct iavf_aq_desc *arq, *iaq; 23794ccba60fSjmatthew struct iavf_aq_buf *aqb; 23804ccba60fSjmatthew struct iavf_vc_version_info *ver; 23814ccba60fSjmatthew unsigned int cons = sc->sc_arq_cons; 23824ccba60fSjmatthew unsigned int prod; 23834ccba60fSjmatthew int done = 0; 23844ccba60fSjmatthew 23854ccba60fSjmatthew prod = iavf_rd(sc, sc->sc_aq_regs->arq_head) & 23864ccba60fSjmatthew sc->sc_aq_regs->arq_head_mask; 23874ccba60fSjmatthew 23884ccba60fSjmatthew if (cons == prod) 23894ccba60fSjmatthew return (0); 23904ccba60fSjmatthew 23914ccba60fSjmatthew arq = IAVF_DMA_KVA(&sc->sc_arq); 23924ccba60fSjmatthew 23934ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq), 23944ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_arq), 23954ccba60fSjmatthew BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 23964ccba60fSjmatthew 23974ccba60fSjmatthew do { 23984ccba60fSjmatthew iaq = &arq[cons]; 23994ccba60fSjmatthew 24004ccba60fSjmatthew aqb = SIMPLEQ_FIRST(&sc->sc_arq_live); 24014ccba60fSjmatthew SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_live, aqb_entry); 24024ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN, 24034ccba60fSjmatthew BUS_DMASYNC_POSTREAD); 24044ccba60fSjmatthew 24054ccba60fSjmatthew switch (letoh32(iaq->iaq_vc_opcode)) { 24064ccba60fSjmatthew case IAVF_VC_OP_VERSION: 24074ccba60fSjmatthew ver = aqb->aqb_data; 24084ccba60fSjmatthew sc->sc_major_ver = letoh32(ver->major); 24094ccba60fSjmatthew sc->sc_minor_ver = letoh32(ver->minor); 24104ccba60fSjmatthew break; 24114ccba60fSjmatthew 24124ccba60fSjmatthew case IAVF_VC_OP_GET_VF_RESOURCES: 24134ccba60fSjmatthew iavf_process_vf_resources(sc, iaq, aqb); 24144ccba60fSjmatthew break; 24154ccba60fSjmatthew 24164ccba60fSjmatthew case IAVF_VC_OP_EVENT: 24174ccba60fSjmatthew iavf_process_vc_event(sc, iaq, aqb); 24184ccba60fSjmatthew break; 24194ccba60fSjmatthew 24204ccba60fSjmatthew case IAVF_VC_OP_CONFIG_IRQ_MAP: 24214ccba60fSjmatthew iavf_process_irq_map(sc, iaq); 24224ccba60fSjmatthew break; 24234ccba60fSjmatthew 24244ccba60fSjmatthew case IAVF_VC_OP_CONFIG_TX_QUEUE: 24254ccba60fSjmatthew case IAVF_VC_OP_CONFIG_RX_QUEUE: 24264ccba60fSjmatthew case IAVF_VC_OP_CONFIG_VSI_QUEUES: 24274ccba60fSjmatthew case IAVF_VC_OP_ENABLE_QUEUES: 24284ccba60fSjmatthew case IAVF_VC_OP_DISABLE_QUEUES: 24294ccba60fSjmatthew case IAVF_VC_OP_GET_RSS_HENA_CAPS: 24304ccba60fSjmatthew case IAVF_VC_OP_SET_RSS_HENA: 24314ccba60fSjmatthew case IAVF_VC_OP_ADD_ETH_ADDR: 24324ccba60fSjmatthew case IAVF_VC_OP_DEL_ETH_ADDR: 24334ccba60fSjmatthew case IAVF_VC_OP_CONFIG_PROMISC: 24344ccba60fSjmatthew sc->sc_admin_result = letoh32(iaq->iaq_vc_retval); 24354ccba60fSjmatthew cond_signal(&sc->sc_admin_cond); 24364ccba60fSjmatthew break; 24374ccba60fSjmatthew } 24384ccba60fSjmatthew 24394ccba60fSjmatthew memset(iaq, 0, sizeof(*iaq)); 24404ccba60fSjmatthew SIMPLEQ_INSERT_TAIL(&sc->sc_arq_idle, aqb, aqb_entry); 24414ccba60fSjmatthew if_rxr_put(&sc->sc_arq_ring, 1); 24424ccba60fSjmatthew 24434ccba60fSjmatthew cons++; 24444ccba60fSjmatthew cons &= IAVF_AQ_MASK; 24454ccba60fSjmatthew 24464ccba60fSjmatthew done = 1; 24474ccba60fSjmatthew } while (cons != prod); 24484ccba60fSjmatthew 2449e13657b7Sjmatthew if (fill) 2450e13657b7Sjmatthew iavf_arq_fill(sc, 1); 24514ccba60fSjmatthew 24524ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq), 24534ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_arq), 24544ccba60fSjmatthew BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 24554ccba60fSjmatthew 24564ccba60fSjmatthew sc->sc_arq_cons = cons; 24574ccba60fSjmatthew return (done); 24584ccba60fSjmatthew } 24594ccba60fSjmatthew 24604ccba60fSjmatthew static void 24614ccba60fSjmatthew iavf_atq_done(struct iavf_softc *sc) 24624ccba60fSjmatthew { 24634ccba60fSjmatthew struct iavf_aq_desc *atq, *slot; 24644ccba60fSjmatthew unsigned int cons; 24654ccba60fSjmatthew unsigned int prod; 24664ccba60fSjmatthew 2467bd6a7abaSjmatthew mtx_enter(&sc->sc_atq_mtx); 2468bd6a7abaSjmatthew 24694ccba60fSjmatthew prod = sc->sc_atq_prod; 24704ccba60fSjmatthew cons = sc->sc_atq_cons; 24714ccba60fSjmatthew 2472bd6a7abaSjmatthew if (prod == cons) { 2473bd6a7abaSjmatthew mtx_leave(&sc->sc_atq_mtx); 24744ccba60fSjmatthew return; 2475bd6a7abaSjmatthew } 24764ccba60fSjmatthew 24774ccba60fSjmatthew atq = IAVF_DMA_KVA(&sc->sc_atq); 24784ccba60fSjmatthew 24794ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq), 24804ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_atq), 24814ccba60fSjmatthew BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 24824ccba60fSjmatthew 24834ccba60fSjmatthew do { 24844ccba60fSjmatthew slot = &atq[cons]; 24854ccba60fSjmatthew if (!ISSET(slot->iaq_flags, htole16(IAVF_AQ_DD))) 24864ccba60fSjmatthew break; 24874ccba60fSjmatthew 24884ccba60fSjmatthew memset(slot, 0, sizeof(*slot)); 24894ccba60fSjmatthew 24904ccba60fSjmatthew cons++; 24914ccba60fSjmatthew cons &= IAVF_AQ_MASK; 24924ccba60fSjmatthew } while (cons != prod); 24934ccba60fSjmatthew 24944ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq), 24954ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_atq), 24964ccba60fSjmatthew BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 24974ccba60fSjmatthew 24984ccba60fSjmatthew sc->sc_atq_cons = cons; 2499bd6a7abaSjmatthew 2500bd6a7abaSjmatthew mtx_leave(&sc->sc_atq_mtx); 25014ccba60fSjmatthew } 25024ccba60fSjmatthew 25034ccba60fSjmatthew static int 25044ccba60fSjmatthew iavf_atq_post(struct iavf_softc *sc, struct iavf_aq_desc *iaq) 25054ccba60fSjmatthew { 25064ccba60fSjmatthew struct iavf_aq_desc *atq, *slot; 25074ccba60fSjmatthew unsigned int prod; 25084ccba60fSjmatthew 2509bd6a7abaSjmatthew mtx_enter(&sc->sc_atq_mtx); 2510bd6a7abaSjmatthew 25114ccba60fSjmatthew atq = IAVF_DMA_KVA(&sc->sc_atq); 25124ccba60fSjmatthew prod = sc->sc_atq_prod; 25134ccba60fSjmatthew slot = atq + prod; 25144ccba60fSjmatthew 25154ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq), 25164ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_POSTWRITE); 25174ccba60fSjmatthew 25184ccba60fSjmatthew *slot = *iaq; 25194ccba60fSjmatthew slot->iaq_flags |= htole16(IAVF_AQ_SI); 25204ccba60fSjmatthew 25214ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_atq), 25224ccba60fSjmatthew 0, IAVF_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_PREWRITE); 25234ccba60fSjmatthew 25244ccba60fSjmatthew prod++; 25254ccba60fSjmatthew prod &= IAVF_AQ_MASK; 25264ccba60fSjmatthew sc->sc_atq_prod = prod; 25274ccba60fSjmatthew iavf_wr(sc, sc->sc_aq_regs->atq_tail, prod); 2528bd6a7abaSjmatthew 2529bd6a7abaSjmatthew mtx_leave(&sc->sc_atq_mtx); 2530bd6a7abaSjmatthew 25314ccba60fSjmatthew return (prod); 25324ccba60fSjmatthew } 25334ccba60fSjmatthew 25344ccba60fSjmatthew static int 25354ccba60fSjmatthew iavf_get_version(struct iavf_softc *sc) 25364ccba60fSjmatthew { 25374ccba60fSjmatthew struct iavf_aq_desc iaq; 25384ccba60fSjmatthew struct iavf_vc_version_info *ver; 25394ccba60fSjmatthew int tries; 25404ccba60fSjmatthew 25414ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 25424ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 25434ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 25444ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_VERSION); 25454ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(struct iavf_vc_version_info)); 25464ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 25474ccba60fSjmatthew 25484ccba60fSjmatthew ver = IAVF_DMA_KVA(&sc->sc_scratch); 25494ccba60fSjmatthew ver->major = htole32(IAVF_VF_MAJOR); 25504ccba60fSjmatthew ver->minor = htole32(IAVF_VF_MINOR); 25514ccba60fSjmatthew sc->sc_major_ver = UINT_MAX; 25524ccba60fSjmatthew sc->sc_minor_ver = UINT_MAX; 25534ccba60fSjmatthew 25544ccba60fSjmatthew membar_sync(); 25554ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, IAVF_DMA_LEN(&sc->sc_scratch), 25564ccba60fSjmatthew BUS_DMASYNC_PREREAD); 25574ccba60fSjmatthew 25584ccba60fSjmatthew iavf_atq_post(sc, &iaq); 25594ccba60fSjmatthew 25604ccba60fSjmatthew for (tries = 0; tries < 100; tries++) { 2561e13657b7Sjmatthew iavf_process_arq(sc, 1); 25624ccba60fSjmatthew if (sc->sc_major_ver != -1) 25634ccba60fSjmatthew break; 25644ccba60fSjmatthew 25654ccba60fSjmatthew delaymsec(1); 25664ccba60fSjmatthew } 25674ccba60fSjmatthew if (tries == 100) { 25684ccba60fSjmatthew printf(", timeout waiting for VF version"); 25694ccba60fSjmatthew return (1); 25704ccba60fSjmatthew } 25714ccba60fSjmatthew 25724ccba60fSjmatthew if (sc->sc_major_ver != IAVF_VF_MAJOR) { 25734ccba60fSjmatthew printf(", unsupported VF version %d", sc->sc_major_ver); 25744ccba60fSjmatthew return (1); 25754ccba60fSjmatthew } 25764ccba60fSjmatthew 25772fa30b92Sjmatthew if (sc->sc_resetting == 0) { 25782fa30b92Sjmatthew printf(", VF version %d.%d%s", sc->sc_major_ver, 25792fa30b92Sjmatthew sc->sc_minor_ver, 25804ccba60fSjmatthew (sc->sc_minor_ver > IAVF_VF_MINOR) ? " (minor mismatch)" : ""); 25812fa30b92Sjmatthew } 25824ccba60fSjmatthew 25834ccba60fSjmatthew return (0); 25844ccba60fSjmatthew } 25854ccba60fSjmatthew 25864ccba60fSjmatthew static int 25874ccba60fSjmatthew iavf_get_vf_resources(struct iavf_softc *sc) 25884ccba60fSjmatthew { 25894ccba60fSjmatthew struct iavf_aq_desc iaq; 25904ccba60fSjmatthew uint32_t *cap; 25914ccba60fSjmatthew int tries; 25924ccba60fSjmatthew 25934ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 25944ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 25954ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 25964ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_GET_VF_RESOURCES); 25974ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 25984ccba60fSjmatthew 25994ccba60fSjmatthew if (sc->sc_minor_ver > 0) { 26004ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(uint32_t)); 26014ccba60fSjmatthew cap = IAVF_DMA_KVA(&sc->sc_scratch); 26024ccba60fSjmatthew *cap = htole32(IAVF_VC_OFFLOAD_L2 | IAVF_VC_OFFLOAD_VLAN | 26034ccba60fSjmatthew IAVF_VC_OFFLOAD_RSS_PF); 26044ccba60fSjmatthew } 26054ccba60fSjmatthew 26064ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, IAVF_DMA_LEN(&sc->sc_scratch), 26074ccba60fSjmatthew BUS_DMASYNC_PREREAD); 26084ccba60fSjmatthew 26094ccba60fSjmatthew sc->sc_got_vf_resources = 0; 26104ccba60fSjmatthew iavf_atq_post(sc, &iaq); 26114ccba60fSjmatthew 26124ccba60fSjmatthew for (tries = 0; tries < 100; tries++) { 2613e13657b7Sjmatthew iavf_process_arq(sc, 1); 26144ccba60fSjmatthew if (sc->sc_got_vf_resources != 0) 2615e13657b7Sjmatthew return (0); 26164ccba60fSjmatthew 26174ccba60fSjmatthew delaymsec(1); 26184ccba60fSjmatthew } 26194ccba60fSjmatthew 2620e13657b7Sjmatthew return (1); 26214ccba60fSjmatthew } 26224ccba60fSjmatthew 26234ccba60fSjmatthew static int 26244ccba60fSjmatthew iavf_config_irq_map(struct iavf_softc *sc) 26254ccba60fSjmatthew { 26264ccba60fSjmatthew struct iavf_aq_desc iaq; 26274ccba60fSjmatthew struct iavf_vc_vector_map *vec; 26284ccba60fSjmatthew struct iavf_vc_irq_map_info *map; 26294ccba60fSjmatthew int tries; 26304ccba60fSjmatthew 26314ccba60fSjmatthew memset(&iaq, 0, sizeof(iaq)); 26324ccba60fSjmatthew iaq.iaq_flags = htole16(IAVF_AQ_BUF | IAVF_AQ_RD); 26334ccba60fSjmatthew iaq.iaq_opcode = htole16(IAVF_AQ_OP_SEND_TO_PF); 26344ccba60fSjmatthew iaq.iaq_vc_opcode = htole32(IAVF_VC_OP_CONFIG_IRQ_MAP); 26354ccba60fSjmatthew iaq.iaq_datalen = htole16(sizeof(*map) + sizeof(*vec)); 26364ccba60fSjmatthew iavf_aq_dva(&iaq, IAVF_DMA_DVA(&sc->sc_scratch)); 26374ccba60fSjmatthew 26384ccba60fSjmatthew map = IAVF_DMA_KVA(&sc->sc_scratch); 26392c4469d1Sjmatthew map->num_vectors = htole16(1); 26404ccba60fSjmatthew 26414ccba60fSjmatthew vec = map->vecmap; 26422c4469d1Sjmatthew vec[0].vsi_id = htole16(sc->sc_vsi_id); 26434ccba60fSjmatthew vec[0].vector_id = 0; 26442c4469d1Sjmatthew vec[0].rxq_map = htole16(iavf_allqueues(sc)); 26452c4469d1Sjmatthew vec[0].txq_map = htole16(iavf_allqueues(sc)); 26462c4469d1Sjmatthew vec[0].rxitr_idx = htole16(IAVF_NOITR); 26472c4469d1Sjmatthew vec[0].txitr_idx = htole16(IAVF_NOITR); 26484ccba60fSjmatthew 26494ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_scratch), 0, IAVF_DMA_LEN(&sc->sc_scratch), 26504ccba60fSjmatthew BUS_DMASYNC_PREREAD); 26514ccba60fSjmatthew 26524ccba60fSjmatthew sc->sc_got_irq_map = 0; 26534ccba60fSjmatthew iavf_atq_post(sc, &iaq); 26544ccba60fSjmatthew 26554ccba60fSjmatthew for (tries = 0; tries < 100; tries++) { 2656e13657b7Sjmatthew iavf_process_arq(sc, 1); 26574ccba60fSjmatthew if (sc->sc_got_irq_map != 0) 2658e13657b7Sjmatthew return (0); 26594ccba60fSjmatthew 26604ccba60fSjmatthew delaymsec(1); 26614ccba60fSjmatthew } 26624ccba60fSjmatthew 2663e13657b7Sjmatthew return (1); 26644ccba60fSjmatthew } 26654ccba60fSjmatthew 26664ccba60fSjmatthew static struct iavf_aq_buf * 26674ccba60fSjmatthew iavf_aqb_alloc(struct iavf_softc *sc) 26684ccba60fSjmatthew { 26694ccba60fSjmatthew struct iavf_aq_buf *aqb; 26704ccba60fSjmatthew 26714ccba60fSjmatthew aqb = malloc(sizeof(*aqb), M_DEVBUF, M_WAITOK); 26724ccba60fSjmatthew if (aqb == NULL) 26734ccba60fSjmatthew return (NULL); 26744ccba60fSjmatthew 26754ccba60fSjmatthew aqb->aqb_data = dma_alloc(IAVF_AQ_BUFLEN, PR_WAITOK); 26764ccba60fSjmatthew if (aqb->aqb_data == NULL) 26774ccba60fSjmatthew goto free; 26784ccba60fSjmatthew 26794ccba60fSjmatthew if (bus_dmamap_create(sc->sc_dmat, IAVF_AQ_BUFLEN, 1, 26804ccba60fSjmatthew IAVF_AQ_BUFLEN, 0, 26814ccba60fSjmatthew BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, 26824ccba60fSjmatthew &aqb->aqb_map) != 0) 26834ccba60fSjmatthew goto dma_free; 26844ccba60fSjmatthew 26854ccba60fSjmatthew if (bus_dmamap_load(sc->sc_dmat, aqb->aqb_map, aqb->aqb_data, 26864ccba60fSjmatthew IAVF_AQ_BUFLEN, NULL, BUS_DMA_WAITOK) != 0) 26874ccba60fSjmatthew goto destroy; 26884ccba60fSjmatthew 26894ccba60fSjmatthew return (aqb); 26904ccba60fSjmatthew 26914ccba60fSjmatthew destroy: 26924ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, aqb->aqb_map); 26934ccba60fSjmatthew dma_free: 26944ccba60fSjmatthew dma_free(aqb->aqb_data, IAVF_AQ_BUFLEN); 26954ccba60fSjmatthew free: 26964ccba60fSjmatthew free(aqb, M_DEVBUF, sizeof(*aqb)); 26974ccba60fSjmatthew 26984ccba60fSjmatthew return (NULL); 26994ccba60fSjmatthew } 27004ccba60fSjmatthew 27014ccba60fSjmatthew static void 27024ccba60fSjmatthew iavf_aqb_free(struct iavf_softc *sc, struct iavf_aq_buf *aqb) 27034ccba60fSjmatthew { 27044ccba60fSjmatthew bus_dmamap_unload(sc->sc_dmat, aqb->aqb_map); 27054ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, aqb->aqb_map); 27064ccba60fSjmatthew dma_free(aqb->aqb_data, IAVF_AQ_BUFLEN); 27074ccba60fSjmatthew free(aqb, M_DEVBUF, sizeof(*aqb)); 27084ccba60fSjmatthew } 27094ccba60fSjmatthew 27104ccba60fSjmatthew static int 2711e13657b7Sjmatthew iavf_arq_fill(struct iavf_softc *sc, int post) 27124ccba60fSjmatthew { 27134ccba60fSjmatthew struct iavf_aq_buf *aqb; 27144ccba60fSjmatthew struct iavf_aq_desc *arq, *iaq; 27154ccba60fSjmatthew unsigned int prod = sc->sc_arq_prod; 27164ccba60fSjmatthew unsigned int n; 2717e13657b7Sjmatthew int filled = 0; 27184ccba60fSjmatthew 27194ccba60fSjmatthew n = if_rxr_get(&sc->sc_arq_ring, IAVF_AQ_NUM); 27204ccba60fSjmatthew arq = IAVF_DMA_KVA(&sc->sc_arq); 27214ccba60fSjmatthew 27224ccba60fSjmatthew while (n > 0) { 27234ccba60fSjmatthew aqb = SIMPLEQ_FIRST(&sc->sc_arq_idle); 27244ccba60fSjmatthew if (aqb != NULL) 27254ccba60fSjmatthew SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_idle, aqb_entry); 27264ccba60fSjmatthew else if ((aqb = iavf_aqb_alloc(sc)) == NULL) 27274ccba60fSjmatthew break; 27284ccba60fSjmatthew 27294ccba60fSjmatthew memset(aqb->aqb_data, 0, IAVF_AQ_BUFLEN); 27304ccba60fSjmatthew 27314ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN, 27324ccba60fSjmatthew BUS_DMASYNC_PREREAD); 27334ccba60fSjmatthew 27344ccba60fSjmatthew iaq = &arq[prod]; 27354ccba60fSjmatthew iaq->iaq_flags = htole16(IAVF_AQ_BUF | 27364ccba60fSjmatthew (IAVF_AQ_BUFLEN > I40E_AQ_LARGE_BUF ? IAVF_AQ_LB : 0)); 27374ccba60fSjmatthew iaq->iaq_opcode = 0; 27384ccba60fSjmatthew iaq->iaq_datalen = htole16(IAVF_AQ_BUFLEN); 27394ccba60fSjmatthew iaq->iaq_retval = 0; 27404ccba60fSjmatthew iaq->iaq_vc_opcode = 0; 27414ccba60fSjmatthew iaq->iaq_vc_retval = 0; 27424ccba60fSjmatthew iaq->iaq_param[0] = 0; 27434ccba60fSjmatthew iaq->iaq_param[1] = 0; 27444ccba60fSjmatthew iavf_aq_dva(iaq, aqb->aqb_map->dm_segs[0].ds_addr); 27454ccba60fSjmatthew 27464ccba60fSjmatthew SIMPLEQ_INSERT_TAIL(&sc->sc_arq_live, aqb, aqb_entry); 27474ccba60fSjmatthew 27484ccba60fSjmatthew prod++; 27494ccba60fSjmatthew prod &= IAVF_AQ_MASK; 27504ccba60fSjmatthew 2751e13657b7Sjmatthew filled = 1; 27524ccba60fSjmatthew 27534ccba60fSjmatthew n--; 27544ccba60fSjmatthew } 27554ccba60fSjmatthew 27564ccba60fSjmatthew if_rxr_put(&sc->sc_arq_ring, n); 27574ccba60fSjmatthew sc->sc_arq_prod = prod; 27584ccba60fSjmatthew 2759e13657b7Sjmatthew if (filled && post) 2760e13657b7Sjmatthew iavf_wr(sc, sc->sc_aq_regs->arq_tail, sc->sc_arq_prod); 2761e13657b7Sjmatthew 2762e13657b7Sjmatthew return (filled); 27634ccba60fSjmatthew } 27644ccba60fSjmatthew 27654ccba60fSjmatthew static void 27664ccba60fSjmatthew iavf_arq_unfill(struct iavf_softc *sc) 27674ccba60fSjmatthew { 27684ccba60fSjmatthew struct iavf_aq_buf *aqb; 27694ccba60fSjmatthew 27704ccba60fSjmatthew while ((aqb = SIMPLEQ_FIRST(&sc->sc_arq_live)) != NULL) { 27714ccba60fSjmatthew SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_live, aqb_entry); 27724ccba60fSjmatthew 27734ccba60fSjmatthew bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN, 27744ccba60fSjmatthew BUS_DMASYNC_POSTREAD); 27754ccba60fSjmatthew iavf_aqb_free(sc, aqb); 2776e13657b7Sjmatthew if_rxr_put(&sc->sc_arq_ring, 1); 27774ccba60fSjmatthew } 27784ccba60fSjmatthew } 27794ccba60fSjmatthew 27804ccba60fSjmatthew static void 27814ccba60fSjmatthew iavf_arq_timeout(void *xsc) 27824ccba60fSjmatthew { 27834ccba60fSjmatthew struct iavf_softc *sc = xsc; 27844ccba60fSjmatthew 27854ccba60fSjmatthew sc->sc_admin_result = -1; 27864ccba60fSjmatthew cond_signal(&sc->sc_admin_cond); 27874ccba60fSjmatthew } 27884ccba60fSjmatthew 27894ccba60fSjmatthew static int 27904ccba60fSjmatthew iavf_arq_wait(struct iavf_softc *sc, int msec) 27914ccba60fSjmatthew { 27924ccba60fSjmatthew cond_init(&sc->sc_admin_cond); 27934ccba60fSjmatthew 27944ccba60fSjmatthew timeout_add_msec(&sc->sc_admin_timeout, msec); 27954ccba60fSjmatthew 27964ccba60fSjmatthew cond_wait(&sc->sc_admin_cond, "iavfarq"); 27971f28ec92Sjmatthew timeout_del(&sc->sc_admin_timeout); 27981f28ec92Sjmatthew 2799e13657b7Sjmatthew iavf_arq_fill(sc, 1); 28004ccba60fSjmatthew return sc->sc_admin_result; 28014ccba60fSjmatthew } 28024ccba60fSjmatthew 28034ccba60fSjmatthew static int 28044ccba60fSjmatthew iavf_dmamem_alloc(struct iavf_softc *sc, struct iavf_dmamem *ixm, 28054ccba60fSjmatthew bus_size_t size, u_int align) 28064ccba60fSjmatthew { 28074ccba60fSjmatthew ixm->ixm_size = size; 28084ccba60fSjmatthew 28094ccba60fSjmatthew if (bus_dmamap_create(sc->sc_dmat, ixm->ixm_size, 1, 28104ccba60fSjmatthew ixm->ixm_size, 0, 28114ccba60fSjmatthew BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, 28124ccba60fSjmatthew &ixm->ixm_map) != 0) 28134ccba60fSjmatthew return (1); 28144ccba60fSjmatthew if (bus_dmamem_alloc(sc->sc_dmat, ixm->ixm_size, 28154ccba60fSjmatthew align, 0, &ixm->ixm_seg, 1, &ixm->ixm_nsegs, 28164ccba60fSjmatthew BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0) 28174ccba60fSjmatthew goto destroy; 28184ccba60fSjmatthew if (bus_dmamem_map(sc->sc_dmat, &ixm->ixm_seg, ixm->ixm_nsegs, 28194ccba60fSjmatthew ixm->ixm_size, &ixm->ixm_kva, BUS_DMA_WAITOK) != 0) 28204ccba60fSjmatthew goto free; 28214ccba60fSjmatthew if (bus_dmamap_load(sc->sc_dmat, ixm->ixm_map, ixm->ixm_kva, 28224ccba60fSjmatthew ixm->ixm_size, NULL, BUS_DMA_WAITOK) != 0) 28234ccba60fSjmatthew goto unmap; 28244ccba60fSjmatthew 28254ccba60fSjmatthew return (0); 28264ccba60fSjmatthew unmap: 28274ccba60fSjmatthew bus_dmamem_unmap(sc->sc_dmat, ixm->ixm_kva, ixm->ixm_size); 28284ccba60fSjmatthew free: 28294ccba60fSjmatthew bus_dmamem_free(sc->sc_dmat, &ixm->ixm_seg, 1); 28304ccba60fSjmatthew destroy: 28314ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, ixm->ixm_map); 28324ccba60fSjmatthew return (1); 28334ccba60fSjmatthew } 28344ccba60fSjmatthew 28354ccba60fSjmatthew static void 28364ccba60fSjmatthew iavf_dmamem_free(struct iavf_softc *sc, struct iavf_dmamem *ixm) 28374ccba60fSjmatthew { 28384ccba60fSjmatthew bus_dmamap_unload(sc->sc_dmat, ixm->ixm_map); 28394ccba60fSjmatthew bus_dmamem_unmap(sc->sc_dmat, ixm->ixm_kva, ixm->ixm_size); 28404ccba60fSjmatthew bus_dmamem_free(sc->sc_dmat, &ixm->ixm_seg, 1); 28414ccba60fSjmatthew bus_dmamap_destroy(sc->sc_dmat, ixm->ixm_map); 28424ccba60fSjmatthew } 2843