154dfc97bSShailend Chand /*- 254dfc97bSShailend Chand * SPDX-License-Identifier: BSD-3-Clause 354dfc97bSShailend Chand * 4d438b4efSShailend Chand * Copyright (c) 2023-2024 Google LLC 554dfc97bSShailend Chand * 654dfc97bSShailend Chand * Redistribution and use in source and binary forms, with or without modification, 754dfc97bSShailend Chand * are permitted provided that the following conditions are met: 854dfc97bSShailend Chand * 954dfc97bSShailend Chand * 1. Redistributions of source code must retain the above copyright notice, this 1054dfc97bSShailend Chand * list of conditions and the following disclaimer. 1154dfc97bSShailend Chand * 1254dfc97bSShailend Chand * 2. Redistributions in binary form must reproduce the above copyright notice, 1354dfc97bSShailend Chand * this list of conditions and the following disclaimer in the documentation 1454dfc97bSShailend Chand * and/or other materials provided with the distribution. 1554dfc97bSShailend Chand * 1654dfc97bSShailend Chand * 3. Neither the name of the copyright holder nor the names of its contributors 1754dfc97bSShailend Chand * may be used to endorse or promote products derived from this software without 1854dfc97bSShailend Chand * specific prior written permission. 1954dfc97bSShailend Chand * 2054dfc97bSShailend Chand * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 2154dfc97bSShailend Chand * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2254dfc97bSShailend Chand * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2354dfc97bSShailend Chand * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 2454dfc97bSShailend Chand * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2554dfc97bSShailend Chand * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2654dfc97bSShailend Chand * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 2754dfc97bSShailend Chand * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2854dfc97bSShailend Chand * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2954dfc97bSShailend Chand * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3054dfc97bSShailend Chand */ 3154dfc97bSShailend Chand #include "gve.h" 3254dfc97bSShailend Chand #include "gve_adminq.h" 33d438b4efSShailend Chand #include "gve_dqo.h" 3454dfc97bSShailend Chand 35*031800c7SJasper Tran O'Leary #define GVE_DRIVER_VERSION "GVE-FBSD-1.3.2\n" 365f62584aSShailend Chand #define GVE_VERSION_MAJOR 1 372348ac89SShailend Chand #define GVE_VERSION_MINOR 3 38*031800c7SJasper Tran O'Leary #define GVE_VERSION_SUB 2 3954dfc97bSShailend Chand 4054dfc97bSShailend Chand #define GVE_DEFAULT_RX_COPYBREAK 256 4154dfc97bSShailend Chand 421bbdfb0bSXin LI /* Devices supported by this driver. */ 431bbdfb0bSXin LI static struct gve_dev { 441bbdfb0bSXin LI uint16_t vendor_id; 451bbdfb0bSXin LI uint16_t device_id; 461bbdfb0bSXin LI const char *name; 471bbdfb0bSXin LI } gve_devs[] = { 481bbdfb0bSXin LI { PCI_VENDOR_ID_GOOGLE, PCI_DEV_ID_GVNIC, "gVNIC" } 491bbdfb0bSXin LI }; 501bbdfb0bSXin LI 5154dfc97bSShailend Chand struct sx gve_global_lock; 5254dfc97bSShailend Chand 5354dfc97bSShailend Chand static int 5454dfc97bSShailend Chand gve_verify_driver_compatibility(struct gve_priv *priv) 5554dfc97bSShailend Chand { 5654dfc97bSShailend Chand int err; 5754dfc97bSShailend Chand struct gve_driver_info *driver_info; 5854dfc97bSShailend Chand struct gve_dma_handle driver_info_mem; 5954dfc97bSShailend Chand 6054dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, sizeof(struct gve_driver_info), 6154dfc97bSShailend Chand PAGE_SIZE, &driver_info_mem); 6254dfc97bSShailend Chand 6354dfc97bSShailend Chand if (err != 0) 6454dfc97bSShailend Chand return (ENOMEM); 6554dfc97bSShailend Chand 6654dfc97bSShailend Chand driver_info = driver_info_mem.cpu_addr; 6754dfc97bSShailend Chand 6854dfc97bSShailend Chand *driver_info = (struct gve_driver_info) { 6954dfc97bSShailend Chand .os_type = 3, /* Freebsd */ 7054dfc97bSShailend Chand .driver_major = GVE_VERSION_MAJOR, 7154dfc97bSShailend Chand .driver_minor = GVE_VERSION_MINOR, 7254dfc97bSShailend Chand .driver_sub = GVE_VERSION_SUB, 7354dfc97bSShailend Chand .os_version_major = htobe32(FBSD_VERSION_MAJOR), 7454dfc97bSShailend Chand .os_version_minor = htobe32(FBSD_VERSION_MINOR), 7554dfc97bSShailend Chand .os_version_sub = htobe32(FBSD_VERSION_PATCH), 7654dfc97bSShailend Chand .driver_capability_flags = { 7754dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS1), 7854dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS2), 7954dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS3), 8054dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS4), 8154dfc97bSShailend Chand }, 8254dfc97bSShailend Chand }; 8354dfc97bSShailend Chand 8454dfc97bSShailend Chand snprintf(driver_info->os_version_str1, sizeof(driver_info->os_version_str1), 8554dfc97bSShailend Chand "FreeBSD %u", __FreeBSD_version); 8654dfc97bSShailend Chand 8754dfc97bSShailend Chand bus_dmamap_sync(driver_info_mem.tag, driver_info_mem.map, 8854dfc97bSShailend Chand BUS_DMASYNC_PREREAD); 8954dfc97bSShailend Chand 9054dfc97bSShailend Chand err = gve_adminq_verify_driver_compatibility(priv, 9154dfc97bSShailend Chand sizeof(struct gve_driver_info), driver_info_mem.bus_addr); 9254dfc97bSShailend Chand 9354dfc97bSShailend Chand /* It's ok if the device doesn't support this */ 9454dfc97bSShailend Chand if (err == EOPNOTSUPP) 9554dfc97bSShailend Chand err = 0; 9654dfc97bSShailend Chand 9754dfc97bSShailend Chand gve_dma_free_coherent(&driver_info_mem); 9854dfc97bSShailend Chand 9954dfc97bSShailend Chand return (err); 10054dfc97bSShailend Chand } 10154dfc97bSShailend Chand 10254dfc97bSShailend Chand static int 10354dfc97bSShailend Chand gve_up(struct gve_priv *priv) 10454dfc97bSShailend Chand { 10554dfc97bSShailend Chand if_t ifp = priv->ifp; 10654dfc97bSShailend Chand int err; 10754dfc97bSShailend Chand 10854dfc97bSShailend Chand GVE_IFACE_LOCK_ASSERT(priv->gve_iface_lock); 10954dfc97bSShailend Chand 11054dfc97bSShailend Chand if (device_is_attached(priv->dev) == 0) { 11154dfc97bSShailend Chand device_printf(priv->dev, "Cannot bring the iface up when detached\n"); 11254dfc97bSShailend Chand return (ENXIO); 11354dfc97bSShailend Chand } 11454dfc97bSShailend Chand 11554dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) 11654dfc97bSShailend Chand return (0); 11754dfc97bSShailend Chand 11854dfc97bSShailend Chand if_clearhwassist(ifp); 11954dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TXCSUM) 12054dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_TCP | CSUM_UDP, 0); 12154dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6) 12254dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_IP6_TCP | CSUM_IP6_UDP, 0); 12354dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TSO4) 12454dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_IP_TSO, 0); 12554dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TSO6) 12654dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_IP6_TSO, 0); 12754dfc97bSShailend Chand 1282348ac89SShailend Chand if (gve_is_qpl(priv)) { 12954dfc97bSShailend Chand err = gve_register_qpls(priv); 13054dfc97bSShailend Chand if (err != 0) 13154dfc97bSShailend Chand goto reset; 132d438b4efSShailend Chand } 13354dfc97bSShailend Chand 13454dfc97bSShailend Chand err = gve_create_rx_rings(priv); 13554dfc97bSShailend Chand if (err != 0) 13654dfc97bSShailend Chand goto reset; 13754dfc97bSShailend Chand 13854dfc97bSShailend Chand err = gve_create_tx_rings(priv); 13954dfc97bSShailend Chand if (err != 0) 14054dfc97bSShailend Chand goto reset; 14154dfc97bSShailend Chand 14254dfc97bSShailend Chand if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 14354dfc97bSShailend Chand 14454dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 14554dfc97bSShailend Chand if_link_state_change(ifp, LINK_STATE_UP); 14654dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 14754dfc97bSShailend Chand } 14854dfc97bSShailend Chand 14954dfc97bSShailend Chand gve_unmask_all_queue_irqs(priv); 15054dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP); 15154dfc97bSShailend Chand priv->interface_up_cnt++; 15254dfc97bSShailend Chand return (0); 15354dfc97bSShailend Chand 15454dfc97bSShailend Chand reset: 15554dfc97bSShailend Chand gve_schedule_reset(priv); 15654dfc97bSShailend Chand return (err); 15754dfc97bSShailend Chand } 15854dfc97bSShailend Chand 15954dfc97bSShailend Chand static void 16054dfc97bSShailend Chand gve_down(struct gve_priv *priv) 16154dfc97bSShailend Chand { 16254dfc97bSShailend Chand GVE_IFACE_LOCK_ASSERT(priv->gve_iface_lock); 16354dfc97bSShailend Chand 16454dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) 16554dfc97bSShailend Chand return; 16654dfc97bSShailend Chand 16754dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 16854dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 16954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 17054dfc97bSShailend Chand } 17154dfc97bSShailend Chand 17254dfc97bSShailend Chand if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 17354dfc97bSShailend Chand 17454dfc97bSShailend Chand if (gve_destroy_rx_rings(priv) != 0) 17554dfc97bSShailend Chand goto reset; 17654dfc97bSShailend Chand 17754dfc97bSShailend Chand if (gve_destroy_tx_rings(priv) != 0) 17854dfc97bSShailend Chand goto reset; 17954dfc97bSShailend Chand 1802348ac89SShailend Chand if (gve_is_qpl(priv)) { 18154dfc97bSShailend Chand if (gve_unregister_qpls(priv) != 0) 18254dfc97bSShailend Chand goto reset; 183d438b4efSShailend Chand } 18454dfc97bSShailend Chand 185d438b4efSShailend Chand if (gve_is_gqi(priv)) 18654dfc97bSShailend Chand gve_mask_all_queue_irqs(priv); 18754dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP); 18854dfc97bSShailend Chand priv->interface_down_cnt++; 18954dfc97bSShailend Chand return; 19054dfc97bSShailend Chand 19154dfc97bSShailend Chand reset: 19254dfc97bSShailend Chand gve_schedule_reset(priv); 19354dfc97bSShailend Chand } 19454dfc97bSShailend Chand 19554dfc97bSShailend Chand static int 19654dfc97bSShailend Chand gve_set_mtu(if_t ifp, uint32_t new_mtu) 19754dfc97bSShailend Chand { 19854dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 199909e2d7bSJasper Tran O'Leary const uint32_t max_problem_range = 8227; 200909e2d7bSJasper Tran O'Leary const uint32_t min_problem_range = 7822; 20154dfc97bSShailend Chand int err; 20254dfc97bSShailend Chand 20354dfc97bSShailend Chand if ((new_mtu > priv->max_mtu) || (new_mtu < ETHERMIN)) { 20454dfc97bSShailend Chand device_printf(priv->dev, "Invalid new MTU setting. new mtu: %d max mtu: %d min mtu: %d\n", 20554dfc97bSShailend Chand new_mtu, priv->max_mtu, ETHERMIN); 20654dfc97bSShailend Chand return (EINVAL); 20754dfc97bSShailend Chand } 20854dfc97bSShailend Chand 209909e2d7bSJasper Tran O'Leary /* 210909e2d7bSJasper Tran O'Leary * When hardware LRO is enabled in DQ mode, MTUs within the range 211909e2d7bSJasper Tran O'Leary * [7822, 8227] trigger hardware issues which cause a drastic drop 212909e2d7bSJasper Tran O'Leary * in throughput. 213909e2d7bSJasper Tran O'Leary */ 214909e2d7bSJasper Tran O'Leary if (!gve_is_gqi(priv) && !gve_disable_hw_lro && 215909e2d7bSJasper Tran O'Leary new_mtu >= min_problem_range && new_mtu <= max_problem_range) { 216909e2d7bSJasper Tran O'Leary device_printf(priv->dev, 217909e2d7bSJasper Tran O'Leary "Cannot set to MTU to %d within the range [%d, %d] while hardware LRO is enabled\n", 218909e2d7bSJasper Tran O'Leary new_mtu, min_problem_range, max_problem_range); 219909e2d7bSJasper Tran O'Leary return (EINVAL); 220909e2d7bSJasper Tran O'Leary } 221909e2d7bSJasper Tran O'Leary 22254dfc97bSShailend Chand err = gve_adminq_set_mtu(priv, new_mtu); 22354dfc97bSShailend Chand if (err == 0) { 22454dfc97bSShailend Chand if (bootverbose) 22554dfc97bSShailend Chand device_printf(priv->dev, "MTU set to %d\n", new_mtu); 22654dfc97bSShailend Chand if_setmtu(ifp, new_mtu); 22754dfc97bSShailend Chand } else { 22854dfc97bSShailend Chand device_printf(priv->dev, "Failed to set MTU to %d\n", new_mtu); 22954dfc97bSShailend Chand } 23054dfc97bSShailend Chand 23154dfc97bSShailend Chand return (err); 23254dfc97bSShailend Chand } 23354dfc97bSShailend Chand 23454dfc97bSShailend Chand static void 23554dfc97bSShailend Chand gve_init(void *arg) 23654dfc97bSShailend Chand { 23754dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 23854dfc97bSShailend Chand 23954dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) { 24054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 24154dfc97bSShailend Chand gve_up(priv); 24254dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 24354dfc97bSShailend Chand } 24454dfc97bSShailend Chand } 24554dfc97bSShailend Chand 24654dfc97bSShailend Chand static int 24754dfc97bSShailend Chand gve_ioctl(if_t ifp, u_long command, caddr_t data) 24854dfc97bSShailend Chand { 24954dfc97bSShailend Chand struct gve_priv *priv; 25054dfc97bSShailend Chand struct ifreq *ifr; 25154dfc97bSShailend Chand int rc = 0; 25254dfc97bSShailend Chand 25354dfc97bSShailend Chand priv = if_getsoftc(ifp); 25454dfc97bSShailend Chand ifr = (struct ifreq *)data; 25554dfc97bSShailend Chand 25654dfc97bSShailend Chand switch (command) { 25754dfc97bSShailend Chand case SIOCSIFMTU: 25854dfc97bSShailend Chand if (if_getmtu(ifp) == ifr->ifr_mtu) 25954dfc97bSShailend Chand break; 26054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 26154dfc97bSShailend Chand gve_down(priv); 26254dfc97bSShailend Chand gve_set_mtu(ifp, ifr->ifr_mtu); 26354dfc97bSShailend Chand rc = gve_up(priv); 26454dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 26554dfc97bSShailend Chand break; 26654dfc97bSShailend Chand 26754dfc97bSShailend Chand case SIOCSIFFLAGS: 26854dfc97bSShailend Chand if ((if_getflags(ifp) & IFF_UP) != 0) { 26954dfc97bSShailend Chand if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 27054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 27154dfc97bSShailend Chand rc = gve_up(priv); 27254dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 27354dfc97bSShailend Chand } 27454dfc97bSShailend Chand } else { 27554dfc97bSShailend Chand if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 27654dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 27754dfc97bSShailend Chand gve_down(priv); 27854dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 27954dfc97bSShailend Chand } 28054dfc97bSShailend Chand } 28154dfc97bSShailend Chand break; 28254dfc97bSShailend Chand 28354dfc97bSShailend Chand case SIOCSIFCAP: 28454dfc97bSShailend Chand if (ifr->ifr_reqcap == if_getcapenable(ifp)) 28554dfc97bSShailend Chand break; 28654dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 28754dfc97bSShailend Chand gve_down(priv); 28854dfc97bSShailend Chand if_setcapenable(ifp, ifr->ifr_reqcap); 28954dfc97bSShailend Chand rc = gve_up(priv); 29054dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 29154dfc97bSShailend Chand break; 29254dfc97bSShailend Chand 29354dfc97bSShailend Chand case SIOCSIFMEDIA: 29454dfc97bSShailend Chand /* FALLTHROUGH */ 29554dfc97bSShailend Chand case SIOCGIFMEDIA: 29654dfc97bSShailend Chand rc = ifmedia_ioctl(ifp, ifr, &priv->media, command); 29754dfc97bSShailend Chand break; 29854dfc97bSShailend Chand 29954dfc97bSShailend Chand default: 30054dfc97bSShailend Chand rc = ether_ioctl(ifp, command, data); 30154dfc97bSShailend Chand break; 30254dfc97bSShailend Chand } 30354dfc97bSShailend Chand 30454dfc97bSShailend Chand return (rc); 30554dfc97bSShailend Chand } 30654dfc97bSShailend Chand 30754dfc97bSShailend Chand static int 30854dfc97bSShailend Chand gve_media_change(if_t ifp) 30954dfc97bSShailend Chand { 31054dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 31154dfc97bSShailend Chand 31254dfc97bSShailend Chand device_printf(priv->dev, "Media change not supported\n"); 31354dfc97bSShailend Chand return (0); 31454dfc97bSShailend Chand } 31554dfc97bSShailend Chand 31654dfc97bSShailend Chand static void 31754dfc97bSShailend Chand gve_media_status(if_t ifp, struct ifmediareq *ifmr) 31854dfc97bSShailend Chand { 31954dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 32054dfc97bSShailend Chand 32154dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 32254dfc97bSShailend Chand 32354dfc97bSShailend Chand ifmr->ifm_status = IFM_AVALID; 32454dfc97bSShailend Chand ifmr->ifm_active = IFM_ETHER; 32554dfc97bSShailend Chand 32654dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 32754dfc97bSShailend Chand ifmr->ifm_status |= IFM_ACTIVE; 32854dfc97bSShailend Chand ifmr->ifm_active |= IFM_AUTO; 32954dfc97bSShailend Chand } else { 33054dfc97bSShailend Chand ifmr->ifm_active |= IFM_NONE; 33154dfc97bSShailend Chand } 33254dfc97bSShailend Chand 33354dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 33454dfc97bSShailend Chand } 33554dfc97bSShailend Chand 33654dfc97bSShailend Chand static uint64_t 33754dfc97bSShailend Chand gve_get_counter(if_t ifp, ift_counter cnt) 33854dfc97bSShailend Chand { 33954dfc97bSShailend Chand struct gve_priv *priv; 34054dfc97bSShailend Chand uint64_t rpackets = 0; 34154dfc97bSShailend Chand uint64_t tpackets = 0; 34254dfc97bSShailend Chand uint64_t rbytes = 0; 34354dfc97bSShailend Chand uint64_t tbytes = 0; 34454dfc97bSShailend Chand uint64_t rx_dropped_pkt = 0; 34554dfc97bSShailend Chand uint64_t tx_dropped_pkt = 0; 34654dfc97bSShailend Chand 34754dfc97bSShailend Chand priv = if_getsoftc(ifp); 34854dfc97bSShailend Chand 34954dfc97bSShailend Chand gve_accum_stats(priv, &rpackets, &rbytes, &rx_dropped_pkt, &tpackets, 35054dfc97bSShailend Chand &tbytes, &tx_dropped_pkt); 35154dfc97bSShailend Chand 35254dfc97bSShailend Chand switch (cnt) { 35354dfc97bSShailend Chand case IFCOUNTER_IPACKETS: 35454dfc97bSShailend Chand return (rpackets); 35554dfc97bSShailend Chand 35654dfc97bSShailend Chand case IFCOUNTER_OPACKETS: 35754dfc97bSShailend Chand return (tpackets); 35854dfc97bSShailend Chand 35954dfc97bSShailend Chand case IFCOUNTER_IBYTES: 36054dfc97bSShailend Chand return (rbytes); 36154dfc97bSShailend Chand 36254dfc97bSShailend Chand case IFCOUNTER_OBYTES: 36354dfc97bSShailend Chand return (tbytes); 36454dfc97bSShailend Chand 36554dfc97bSShailend Chand case IFCOUNTER_IQDROPS: 36654dfc97bSShailend Chand return (rx_dropped_pkt); 36754dfc97bSShailend Chand 36854dfc97bSShailend Chand case IFCOUNTER_OQDROPS: 36954dfc97bSShailend Chand return (tx_dropped_pkt); 37054dfc97bSShailend Chand 37154dfc97bSShailend Chand default: 37254dfc97bSShailend Chand return (if_get_counter_default(ifp, cnt)); 37354dfc97bSShailend Chand } 37454dfc97bSShailend Chand } 37554dfc97bSShailend Chand 376aa386085SZhenlei Huang static void 37754dfc97bSShailend Chand gve_setup_ifnet(device_t dev, struct gve_priv *priv) 37854dfc97bSShailend Chand { 37954dfc97bSShailend Chand int caps = 0; 38054dfc97bSShailend Chand if_t ifp; 38154dfc97bSShailend Chand 38254dfc97bSShailend Chand ifp = priv->ifp = if_alloc(IFT_ETHER); 38354dfc97bSShailend Chand if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 38454dfc97bSShailend Chand if_setsoftc(ifp, priv); 38554dfc97bSShailend Chand if_setdev(ifp, dev); 38654dfc97bSShailend Chand if_setinitfn(ifp, gve_init); 38754dfc97bSShailend Chand if_setioctlfn(ifp, gve_ioctl); 38854dfc97bSShailend Chand if_settransmitfn(ifp, gve_xmit_ifp); 38954dfc97bSShailend Chand if_setqflushfn(ifp, gve_qflush); 39054dfc97bSShailend Chand 391d438b4efSShailend Chand /* 392d438b4efSShailend Chand * Set TSO limits, must match the arguments to bus_dma_tag_create 3932348ac89SShailend Chand * when creating tx->dqo.buf_dmatag. Only applies to the RDA mode 394*031800c7SJasper Tran O'Leary * because in QPL we copy the entire packet into the bounce buffer 3952348ac89SShailend Chand * and thus it does not matter how fragmented the mbuf is. 396d438b4efSShailend Chand */ 3972348ac89SShailend Chand if (!gve_is_gqi(priv) && !gve_is_qpl(priv)) { 398d438b4efSShailend Chand if_sethwtsomaxsegcount(ifp, GVE_TX_MAX_DATA_DESCS_DQO); 399d438b4efSShailend Chand if_sethwtsomaxsegsize(ifp, GVE_TX_MAX_BUF_SIZE_DQO); 400d438b4efSShailend Chand } 4012348ac89SShailend Chand if_sethwtsomax(ifp, GVE_TSO_MAXSIZE_DQO); 402d438b4efSShailend Chand 40354dfc97bSShailend Chand #if __FreeBSD_version >= 1400086 40454dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 40554dfc97bSShailend Chand #else 40654dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_KNOWSEPOCH); 40754dfc97bSShailend Chand #endif 40854dfc97bSShailend Chand 40954dfc97bSShailend Chand ifmedia_init(&priv->media, IFM_IMASK, gve_media_change, gve_media_status); 41054dfc97bSShailend Chand if_setgetcounterfn(ifp, gve_get_counter); 41154dfc97bSShailend Chand 41254dfc97bSShailend Chand caps = IFCAP_RXCSUM | 41354dfc97bSShailend Chand IFCAP_TXCSUM | 41454dfc97bSShailend Chand IFCAP_TXCSUM_IPV6 | 41554dfc97bSShailend Chand IFCAP_TSO | 41654dfc97bSShailend Chand IFCAP_LRO; 41754dfc97bSShailend Chand 41854dfc97bSShailend Chand if ((priv->supported_features & GVE_SUP_JUMBO_FRAMES_MASK) != 0) 41954dfc97bSShailend Chand caps |= IFCAP_JUMBO_MTU; 42054dfc97bSShailend Chand 42154dfc97bSShailend Chand if_setcapabilities(ifp, caps); 42254dfc97bSShailend Chand if_setcapenable(ifp, caps); 42354dfc97bSShailend Chand 42454dfc97bSShailend Chand if (bootverbose) 42554dfc97bSShailend Chand device_printf(priv->dev, "Setting initial MTU to %d\n", priv->max_mtu); 42654dfc97bSShailend Chand if_setmtu(ifp, priv->max_mtu); 42754dfc97bSShailend Chand 42854dfc97bSShailend Chand ether_ifattach(ifp, priv->mac); 42954dfc97bSShailend Chand 43054dfc97bSShailend Chand ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 43154dfc97bSShailend Chand ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 43254dfc97bSShailend Chand } 43354dfc97bSShailend Chand 43454dfc97bSShailend Chand static int 43554dfc97bSShailend Chand gve_alloc_counter_array(struct gve_priv *priv) 43654dfc97bSShailend Chand { 43754dfc97bSShailend Chand int err; 43854dfc97bSShailend Chand 43954dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, sizeof(uint32_t) * priv->num_event_counters, 44054dfc97bSShailend Chand PAGE_SIZE, &priv->counter_array_mem); 44154dfc97bSShailend Chand if (err != 0) 44254dfc97bSShailend Chand return (err); 44354dfc97bSShailend Chand 44454dfc97bSShailend Chand priv->counters = priv->counter_array_mem.cpu_addr; 44554dfc97bSShailend Chand return (0); 44654dfc97bSShailend Chand } 44754dfc97bSShailend Chand 44854dfc97bSShailend Chand static void 44954dfc97bSShailend Chand gve_free_counter_array(struct gve_priv *priv) 45054dfc97bSShailend Chand { 45154dfc97bSShailend Chand if (priv->counters != NULL) 45254dfc97bSShailend Chand gve_dma_free_coherent(&priv->counter_array_mem); 45354dfc97bSShailend Chand priv->counter_array_mem = (struct gve_dma_handle){}; 45454dfc97bSShailend Chand } 45554dfc97bSShailend Chand 45654dfc97bSShailend Chand static int 45754dfc97bSShailend Chand gve_alloc_irq_db_array(struct gve_priv *priv) 45854dfc97bSShailend Chand { 45954dfc97bSShailend Chand int err; 46054dfc97bSShailend Chand 46154dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, 46254dfc97bSShailend Chand sizeof(struct gve_irq_db) * (priv->num_queues), PAGE_SIZE, 46354dfc97bSShailend Chand &priv->irqs_db_mem); 46454dfc97bSShailend Chand if (err != 0) 46554dfc97bSShailend Chand return (err); 46654dfc97bSShailend Chand 46754dfc97bSShailend Chand priv->irq_db_indices = priv->irqs_db_mem.cpu_addr; 46854dfc97bSShailend Chand return (0); 46954dfc97bSShailend Chand } 47054dfc97bSShailend Chand 47154dfc97bSShailend Chand static void 47254dfc97bSShailend Chand gve_free_irq_db_array(struct gve_priv *priv) 47354dfc97bSShailend Chand { 47454dfc97bSShailend Chand if (priv->irq_db_indices != NULL) 47554dfc97bSShailend Chand gve_dma_free_coherent(&priv->irqs_db_mem); 47654dfc97bSShailend Chand priv->irqs_db_mem = (struct gve_dma_handle){}; 47754dfc97bSShailend Chand } 47854dfc97bSShailend Chand 47954dfc97bSShailend Chand static void 48054dfc97bSShailend Chand gve_free_rings(struct gve_priv *priv) 48154dfc97bSShailend Chand { 48254dfc97bSShailend Chand gve_free_irqs(priv); 48354dfc97bSShailend Chand gve_free_tx_rings(priv); 48454dfc97bSShailend Chand gve_free_rx_rings(priv); 4852348ac89SShailend Chand if (gve_is_qpl(priv)) 48654dfc97bSShailend Chand gve_free_qpls(priv); 48754dfc97bSShailend Chand } 48854dfc97bSShailend Chand 48954dfc97bSShailend Chand static int 49054dfc97bSShailend Chand gve_alloc_rings(struct gve_priv *priv) 49154dfc97bSShailend Chand { 49254dfc97bSShailend Chand int err; 49354dfc97bSShailend Chand 4942348ac89SShailend Chand if (gve_is_qpl(priv)) { 49554dfc97bSShailend Chand err = gve_alloc_qpls(priv); 49654dfc97bSShailend Chand if (err != 0) 49754dfc97bSShailend Chand goto abort; 498d438b4efSShailend Chand } 49954dfc97bSShailend Chand 50054dfc97bSShailend Chand err = gve_alloc_rx_rings(priv); 50154dfc97bSShailend Chand if (err != 0) 50254dfc97bSShailend Chand goto abort; 50354dfc97bSShailend Chand 50454dfc97bSShailend Chand err = gve_alloc_tx_rings(priv); 50554dfc97bSShailend Chand if (err != 0) 50654dfc97bSShailend Chand goto abort; 50754dfc97bSShailend Chand 50854dfc97bSShailend Chand err = gve_alloc_irqs(priv); 50954dfc97bSShailend Chand if (err != 0) 51054dfc97bSShailend Chand goto abort; 51154dfc97bSShailend Chand 51254dfc97bSShailend Chand return (0); 51354dfc97bSShailend Chand 51454dfc97bSShailend Chand abort: 51554dfc97bSShailend Chand gve_free_rings(priv); 51654dfc97bSShailend Chand return (err); 51754dfc97bSShailend Chand } 51854dfc97bSShailend Chand 51954dfc97bSShailend Chand static void 52062b2d0c3SJasper Tran O'Leary gve_deconfigure_and_free_device_resources(struct gve_priv *priv) 52154dfc97bSShailend Chand { 52254dfc97bSShailend Chand int err; 52354dfc97bSShailend Chand 52454dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) { 52554dfc97bSShailend Chand err = gve_adminq_deconfigure_device_resources(priv); 52654dfc97bSShailend Chand if (err != 0) { 52754dfc97bSShailend Chand device_printf(priv->dev, "Failed to deconfigure device resources: err=%d\n", 52854dfc97bSShailend Chand err); 52954dfc97bSShailend Chand return; 53054dfc97bSShailend Chand } 53154dfc97bSShailend Chand if (bootverbose) 53254dfc97bSShailend Chand device_printf(priv->dev, "Deconfigured device resources\n"); 53354dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 53454dfc97bSShailend Chand } 53554dfc97bSShailend Chand 53654dfc97bSShailend Chand gve_free_irq_db_array(priv); 53754dfc97bSShailend Chand gve_free_counter_array(priv); 538d438b4efSShailend Chand 539d438b4efSShailend Chand if (priv->ptype_lut_dqo) { 540d438b4efSShailend Chand free(priv->ptype_lut_dqo, M_GVE); 541d438b4efSShailend Chand priv->ptype_lut_dqo = NULL; 542d438b4efSShailend Chand } 54354dfc97bSShailend Chand } 54454dfc97bSShailend Chand 54554dfc97bSShailend Chand static int 54662b2d0c3SJasper Tran O'Leary gve_alloc_and_configure_device_resources(struct gve_priv *priv) 54754dfc97bSShailend Chand { 54854dfc97bSShailend Chand int err; 54954dfc97bSShailend Chand 55054dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) 55154dfc97bSShailend Chand return (0); 55254dfc97bSShailend Chand 55354dfc97bSShailend Chand err = gve_alloc_counter_array(priv); 55454dfc97bSShailend Chand if (err != 0) 55554dfc97bSShailend Chand return (err); 55654dfc97bSShailend Chand 55754dfc97bSShailend Chand err = gve_alloc_irq_db_array(priv); 55854dfc97bSShailend Chand if (err != 0) 55954dfc97bSShailend Chand goto abort; 56054dfc97bSShailend Chand 56154dfc97bSShailend Chand err = gve_adminq_configure_device_resources(priv); 56254dfc97bSShailend Chand if (err != 0) { 56354dfc97bSShailend Chand device_printf(priv->dev, "Failed to configure device resources: err=%d\n", 56454dfc97bSShailend Chand err); 56554dfc97bSShailend Chand err = (ENXIO); 56654dfc97bSShailend Chand goto abort; 56754dfc97bSShailend Chand } 56854dfc97bSShailend Chand 569d438b4efSShailend Chand if (!gve_is_gqi(priv)) { 570d438b4efSShailend Chand priv->ptype_lut_dqo = malloc(sizeof(*priv->ptype_lut_dqo), M_GVE, 571d438b4efSShailend Chand M_WAITOK | M_ZERO); 572d438b4efSShailend Chand 573d438b4efSShailend Chand err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo); 574d438b4efSShailend Chand if (err != 0) { 575d438b4efSShailend Chand device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n", 576d438b4efSShailend Chand err); 577d438b4efSShailend Chand goto abort; 578d438b4efSShailend Chand } 579d438b4efSShailend Chand } 580d438b4efSShailend Chand 58154dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 58254dfc97bSShailend Chand if (bootverbose) 58354dfc97bSShailend Chand device_printf(priv->dev, "Configured device resources\n"); 58454dfc97bSShailend Chand return (0); 58554dfc97bSShailend Chand 58654dfc97bSShailend Chand abort: 58762b2d0c3SJasper Tran O'Leary gve_deconfigure_and_free_device_resources(priv); 58854dfc97bSShailend Chand return (err); 58954dfc97bSShailend Chand } 59054dfc97bSShailend Chand 59154dfc97bSShailend Chand static void 59254dfc97bSShailend Chand gve_set_queue_cnts(struct gve_priv *priv) 59354dfc97bSShailend Chand { 59454dfc97bSShailend Chand priv->tx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_TX_QUEUES); 59554dfc97bSShailend Chand priv->rx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_RX_QUEUES); 59654dfc97bSShailend Chand priv->tx_cfg.num_queues = priv->tx_cfg.max_queues; 59754dfc97bSShailend Chand priv->rx_cfg.num_queues = priv->rx_cfg.max_queues; 59854dfc97bSShailend Chand 59954dfc97bSShailend Chand if (priv->default_num_queues > 0) { 60054dfc97bSShailend Chand priv->tx_cfg.num_queues = MIN(priv->default_num_queues, 60154dfc97bSShailend Chand priv->tx_cfg.num_queues); 60254dfc97bSShailend Chand priv->rx_cfg.num_queues = MIN(priv->default_num_queues, 60354dfc97bSShailend Chand priv->rx_cfg.num_queues); 60454dfc97bSShailend Chand } 60554dfc97bSShailend Chand 60654dfc97bSShailend Chand priv->num_queues = priv->tx_cfg.num_queues + priv->rx_cfg.num_queues; 60754dfc97bSShailend Chand priv->mgmt_msix_idx = priv->num_queues; 60854dfc97bSShailend Chand } 60954dfc97bSShailend Chand 61054dfc97bSShailend Chand static int 61154dfc97bSShailend Chand gve_alloc_adminq_and_describe_device(struct gve_priv *priv) 61254dfc97bSShailend Chand { 61354dfc97bSShailend Chand int err; 61454dfc97bSShailend Chand 61554dfc97bSShailend Chand if ((err = gve_adminq_alloc(priv)) != 0) 61654dfc97bSShailend Chand return (err); 61754dfc97bSShailend Chand 61854dfc97bSShailend Chand if ((err = gve_verify_driver_compatibility(priv)) != 0) { 61954dfc97bSShailend Chand device_printf(priv->dev, 62054dfc97bSShailend Chand "Failed to verify driver compatibility: err=%d\n", err); 62154dfc97bSShailend Chand goto abort; 62254dfc97bSShailend Chand } 62354dfc97bSShailend Chand 62454dfc97bSShailend Chand if ((err = gve_adminq_describe_device(priv)) != 0) 62554dfc97bSShailend Chand goto abort; 62654dfc97bSShailend Chand 62754dfc97bSShailend Chand gve_set_queue_cnts(priv); 62854dfc97bSShailend Chand 62954dfc97bSShailend Chand priv->num_registered_pages = 0; 63054dfc97bSShailend Chand return (0); 63154dfc97bSShailend Chand 63254dfc97bSShailend Chand abort: 63354dfc97bSShailend Chand gve_release_adminq(priv); 63454dfc97bSShailend Chand return (err); 63554dfc97bSShailend Chand } 63654dfc97bSShailend Chand 63754dfc97bSShailend Chand void 63854dfc97bSShailend Chand gve_schedule_reset(struct gve_priv *priv) 63954dfc97bSShailend Chand { 64054dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) 64154dfc97bSShailend Chand return; 64254dfc97bSShailend Chand 64354dfc97bSShailend Chand device_printf(priv->dev, "Scheduling reset task!\n"); 64454dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 64554dfc97bSShailend Chand taskqueue_enqueue(priv->service_tq, &priv->service_task); 64654dfc97bSShailend Chand } 64754dfc97bSShailend Chand 64854dfc97bSShailend Chand static void 64954dfc97bSShailend Chand gve_destroy(struct gve_priv *priv) 65054dfc97bSShailend Chand { 65154dfc97bSShailend Chand gve_down(priv); 65262b2d0c3SJasper Tran O'Leary gve_deconfigure_and_free_device_resources(priv); 65354dfc97bSShailend Chand gve_release_adminq(priv); 65454dfc97bSShailend Chand } 65554dfc97bSShailend Chand 65654dfc97bSShailend Chand static void 65754dfc97bSShailend Chand gve_restore(struct gve_priv *priv) 65854dfc97bSShailend Chand { 65954dfc97bSShailend Chand int err; 66054dfc97bSShailend Chand 66154dfc97bSShailend Chand err = gve_adminq_alloc(priv); 66254dfc97bSShailend Chand if (err != 0) 66354dfc97bSShailend Chand goto abort; 66454dfc97bSShailend Chand 66562b2d0c3SJasper Tran O'Leary err = gve_adminq_configure_device_resources(priv); 66662b2d0c3SJasper Tran O'Leary if (err != 0) { 66762b2d0c3SJasper Tran O'Leary device_printf(priv->dev, "Failed to configure device resources: err=%d\n", 66862b2d0c3SJasper Tran O'Leary err); 66962b2d0c3SJasper Tran O'Leary err = (ENXIO); 67054dfc97bSShailend Chand goto abort; 67162b2d0c3SJasper Tran O'Leary } 67262b2d0c3SJasper Tran O'Leary if (!gve_is_gqi(priv)) { 67362b2d0c3SJasper Tran O'Leary err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo); 67462b2d0c3SJasper Tran O'Leary if (err != 0) { 67562b2d0c3SJasper Tran O'Leary device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n", 67662b2d0c3SJasper Tran O'Leary err); 67762b2d0c3SJasper Tran O'Leary goto abort; 67862b2d0c3SJasper Tran O'Leary } 67962b2d0c3SJasper Tran O'Leary } 68054dfc97bSShailend Chand 68154dfc97bSShailend Chand err = gve_up(priv); 68254dfc97bSShailend Chand if (err != 0) 68354dfc97bSShailend Chand goto abort; 68454dfc97bSShailend Chand 68554dfc97bSShailend Chand return; 68654dfc97bSShailend Chand 68754dfc97bSShailend Chand abort: 68854dfc97bSShailend Chand device_printf(priv->dev, "Restore failed!\n"); 68954dfc97bSShailend Chand return; 69054dfc97bSShailend Chand } 69154dfc97bSShailend Chand 69254dfc97bSShailend Chand static void 69362b2d0c3SJasper Tran O'Leary gve_clear_device_resources(struct gve_priv *priv) 69462b2d0c3SJasper Tran O'Leary { 69562b2d0c3SJasper Tran O'Leary int i; 69662b2d0c3SJasper Tran O'Leary 69762b2d0c3SJasper Tran O'Leary for (i = 0; i < priv->num_event_counters; i++) 69862b2d0c3SJasper Tran O'Leary priv->counters[i] = 0; 69962b2d0c3SJasper Tran O'Leary bus_dmamap_sync(priv->counter_array_mem.tag, priv->counter_array_mem.map, 70062b2d0c3SJasper Tran O'Leary BUS_DMASYNC_PREWRITE); 70162b2d0c3SJasper Tran O'Leary 70262b2d0c3SJasper Tran O'Leary for (i = 0; i < priv->num_queues; i++) 70362b2d0c3SJasper Tran O'Leary priv->irq_db_indices[i] = (struct gve_irq_db){}; 70462b2d0c3SJasper Tran O'Leary bus_dmamap_sync(priv->irqs_db_mem.tag, priv->irqs_db_mem.map, 70562b2d0c3SJasper Tran O'Leary BUS_DMASYNC_PREWRITE); 70662b2d0c3SJasper Tran O'Leary 70762b2d0c3SJasper Tran O'Leary if (priv->ptype_lut_dqo) 70862b2d0c3SJasper Tran O'Leary *priv->ptype_lut_dqo = (struct gve_ptype_lut){0}; 70962b2d0c3SJasper Tran O'Leary } 71062b2d0c3SJasper Tran O'Leary 71162b2d0c3SJasper Tran O'Leary static void 71254dfc97bSShailend Chand gve_handle_reset(struct gve_priv *priv) 71354dfc97bSShailend Chand { 71454dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_DO_RESET)) 71554dfc97bSShailend Chand return; 71654dfc97bSShailend Chand 71754dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 71854dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 71954dfc97bSShailend Chand 72054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 72154dfc97bSShailend Chand 72254dfc97bSShailend Chand if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 72354dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 72454dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 72554dfc97bSShailend Chand 72654dfc97bSShailend Chand /* 72754dfc97bSShailend Chand * Releasing the adminq causes the NIC to destroy all resources 72854dfc97bSShailend Chand * registered with it, so by clearing the flags beneath we cause 72954dfc97bSShailend Chand * the subsequent gve_down call below to not attempt to tell the 73054dfc97bSShailend Chand * NIC to destroy these resources again. 73154dfc97bSShailend Chand * 73254dfc97bSShailend Chand * The call to gve_down is needed in the first place to refresh 73354dfc97bSShailend Chand * the state and the DMA-able memory within each driver ring. 73454dfc97bSShailend Chand */ 73554dfc97bSShailend Chand gve_release_adminq(priv); 73654dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 73754dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK); 73854dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RX_RINGS_OK); 73954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_TX_RINGS_OK); 74054dfc97bSShailend Chand 74154dfc97bSShailend Chand gve_down(priv); 74262b2d0c3SJasper Tran O'Leary gve_clear_device_resources(priv); 74362b2d0c3SJasper Tran O'Leary 74454dfc97bSShailend Chand gve_restore(priv); 74554dfc97bSShailend Chand 74654dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 74754dfc97bSShailend Chand 74854dfc97bSShailend Chand priv->reset_cnt++; 74954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 75054dfc97bSShailend Chand } 75154dfc97bSShailend Chand 75254dfc97bSShailend Chand static void 75354dfc97bSShailend Chand gve_handle_link_status(struct gve_priv *priv) 75454dfc97bSShailend Chand { 75554dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 75654dfc97bSShailend Chand bool link_up = status & GVE_DEVICE_STATUS_LINK_STATUS; 75754dfc97bSShailend Chand 75854dfc97bSShailend Chand if (link_up == gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) 75954dfc97bSShailend Chand return; 76054dfc97bSShailend Chand 76154dfc97bSShailend Chand if (link_up) { 76254dfc97bSShailend Chand if (bootverbose) 76354dfc97bSShailend Chand device_printf(priv->dev, "Device link is up.\n"); 76454dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_UP); 76554dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 76654dfc97bSShailend Chand } else { 76754dfc97bSShailend Chand device_printf(priv->dev, "Device link is down.\n"); 76854dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 76954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 77054dfc97bSShailend Chand } 77154dfc97bSShailend Chand } 77254dfc97bSShailend Chand 77354dfc97bSShailend Chand static void 77454dfc97bSShailend Chand gve_service_task(void *arg, int pending) 77554dfc97bSShailend Chand { 77654dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 77754dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 77854dfc97bSShailend Chand 77954dfc97bSShailend Chand if (((GVE_DEVICE_STATUS_RESET_MASK & status) != 0) && 78054dfc97bSShailend Chand !gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) { 78154dfc97bSShailend Chand device_printf(priv->dev, "Device requested reset\n"); 78254dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 78354dfc97bSShailend Chand } 78454dfc97bSShailend Chand 78554dfc97bSShailend Chand gve_handle_reset(priv); 78654dfc97bSShailend Chand gve_handle_link_status(priv); 78754dfc97bSShailend Chand } 78854dfc97bSShailend Chand 78954dfc97bSShailend Chand static int 79054dfc97bSShailend Chand gve_probe(device_t dev) 79154dfc97bSShailend Chand { 7921bbdfb0bSXin LI uint16_t deviceid, vendorid; 7931bbdfb0bSXin LI int i; 7941bbdfb0bSXin LI 7951bbdfb0bSXin LI vendorid = pci_get_vendor(dev); 7961bbdfb0bSXin LI deviceid = pci_get_device(dev); 7971bbdfb0bSXin LI 7981177a6c8SXin LI for (i = 0; i < nitems(gve_devs); i++) { 7991bbdfb0bSXin LI if (vendorid == gve_devs[i].vendor_id && 8001bbdfb0bSXin LI deviceid == gve_devs[i].device_id) { 8011bbdfb0bSXin LI device_set_desc(dev, gve_devs[i].name); 80254dfc97bSShailend Chand return (BUS_PROBE_DEFAULT); 80354dfc97bSShailend Chand } 8041bbdfb0bSXin LI } 80554dfc97bSShailend Chand return (ENXIO); 80654dfc97bSShailend Chand } 80754dfc97bSShailend Chand 80854dfc97bSShailend Chand static void 80954dfc97bSShailend Chand gve_free_sys_res_mem(struct gve_priv *priv) 81054dfc97bSShailend Chand { 81154dfc97bSShailend Chand if (priv->msix_table != NULL) 81254dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 81354dfc97bSShailend Chand rman_get_rid(priv->msix_table), priv->msix_table); 81454dfc97bSShailend Chand 81554dfc97bSShailend Chand if (priv->db_bar != NULL) 81654dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 81754dfc97bSShailend Chand rman_get_rid(priv->db_bar), priv->db_bar); 81854dfc97bSShailend Chand 81954dfc97bSShailend Chand if (priv->reg_bar != NULL) 82054dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 82154dfc97bSShailend Chand rman_get_rid(priv->reg_bar), priv->reg_bar); 82254dfc97bSShailend Chand } 82354dfc97bSShailend Chand 82454dfc97bSShailend Chand static int 82554dfc97bSShailend Chand gve_attach(device_t dev) 82654dfc97bSShailend Chand { 82754dfc97bSShailend Chand struct gve_priv *priv; 82854dfc97bSShailend Chand int rid; 82954dfc97bSShailend Chand int err; 83054dfc97bSShailend Chand 831d438b4efSShailend Chand snprintf(gve_version, sizeof(gve_version), "%d.%d.%d", 832d438b4efSShailend Chand GVE_VERSION_MAJOR, GVE_VERSION_MINOR, GVE_VERSION_SUB); 833d438b4efSShailend Chand 83454dfc97bSShailend Chand priv = device_get_softc(dev); 83554dfc97bSShailend Chand priv->dev = dev; 83654dfc97bSShailend Chand GVE_IFACE_LOCK_INIT(priv->gve_iface_lock); 83754dfc97bSShailend Chand 83854dfc97bSShailend Chand pci_enable_busmaster(dev); 83954dfc97bSShailend Chand 84054dfc97bSShailend Chand rid = PCIR_BAR(GVE_REGISTER_BAR); 84154dfc97bSShailend Chand priv->reg_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 84254dfc97bSShailend Chand &rid, RF_ACTIVE); 84354dfc97bSShailend Chand if (priv->reg_bar == NULL) { 84454dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR0\n"); 84554dfc97bSShailend Chand err = ENXIO; 84654dfc97bSShailend Chand goto abort; 84754dfc97bSShailend Chand } 84854dfc97bSShailend Chand 84954dfc97bSShailend Chand rid = PCIR_BAR(GVE_DOORBELL_BAR); 85054dfc97bSShailend Chand priv->db_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 85154dfc97bSShailend Chand &rid, RF_ACTIVE); 85254dfc97bSShailend Chand if (priv->db_bar == NULL) { 85354dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR2\n"); 85454dfc97bSShailend Chand err = ENXIO; 85554dfc97bSShailend Chand goto abort; 85654dfc97bSShailend Chand } 85754dfc97bSShailend Chand 85854dfc97bSShailend Chand rid = pci_msix_table_bar(priv->dev); 85954dfc97bSShailend Chand priv->msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 86054dfc97bSShailend Chand &rid, RF_ACTIVE); 86154dfc97bSShailend Chand if (priv->msix_table == NULL) { 86254dfc97bSShailend Chand device_printf(dev, "Failed to allocate msix table\n"); 86354dfc97bSShailend Chand err = ENXIO; 86454dfc97bSShailend Chand goto abort; 86554dfc97bSShailend Chand } 86654dfc97bSShailend Chand 86754dfc97bSShailend Chand err = gve_alloc_adminq_and_describe_device(priv); 86854dfc97bSShailend Chand if (err != 0) 86954dfc97bSShailend Chand goto abort; 87054dfc97bSShailend Chand 87162b2d0c3SJasper Tran O'Leary err = gve_alloc_and_configure_device_resources(priv); 87254dfc97bSShailend Chand if (err != 0) 87354dfc97bSShailend Chand goto abort; 87454dfc97bSShailend Chand 87554dfc97bSShailend Chand err = gve_alloc_rings(priv); 87654dfc97bSShailend Chand if (err != 0) 87754dfc97bSShailend Chand goto abort; 87854dfc97bSShailend Chand 879aa386085SZhenlei Huang gve_setup_ifnet(dev, priv); 88054dfc97bSShailend Chand 88154dfc97bSShailend Chand priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; 88254dfc97bSShailend Chand 88354dfc97bSShailend Chand bus_write_multi_1(priv->reg_bar, DRIVER_VERSION, GVE_DRIVER_VERSION, 88454dfc97bSShailend Chand sizeof(GVE_DRIVER_VERSION) - 1); 88554dfc97bSShailend Chand 88654dfc97bSShailend Chand TASK_INIT(&priv->service_task, 0, gve_service_task, priv); 88754dfc97bSShailend Chand priv->service_tq = taskqueue_create("gve service", M_WAITOK | M_ZERO, 88854dfc97bSShailend Chand taskqueue_thread_enqueue, &priv->service_tq); 88954dfc97bSShailend Chand taskqueue_start_threads(&priv->service_tq, 1, PI_NET, "%s service tq", 89054dfc97bSShailend Chand device_get_nameunit(priv->dev)); 89154dfc97bSShailend Chand 89254dfc97bSShailend Chand gve_setup_sysctl(priv); 89354dfc97bSShailend Chand 89454dfc97bSShailend Chand if (bootverbose) 89554dfc97bSShailend Chand device_printf(priv->dev, "Successfully attached %s", GVE_DRIVER_VERSION); 89654dfc97bSShailend Chand return (0); 89754dfc97bSShailend Chand 89854dfc97bSShailend Chand abort: 89954dfc97bSShailend Chand gve_free_rings(priv); 90062b2d0c3SJasper Tran O'Leary gve_deconfigure_and_free_device_resources(priv); 90154dfc97bSShailend Chand gve_release_adminq(priv); 90254dfc97bSShailend Chand gve_free_sys_res_mem(priv); 90354dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 90454dfc97bSShailend Chand return (err); 90554dfc97bSShailend Chand } 90654dfc97bSShailend Chand 90754dfc97bSShailend Chand static int 90854dfc97bSShailend Chand gve_detach(device_t dev) 90954dfc97bSShailend Chand { 91054dfc97bSShailend Chand struct gve_priv *priv = device_get_softc(dev); 91154dfc97bSShailend Chand if_t ifp = priv->ifp; 912d412c076SJohn Baldwin int error; 913d412c076SJohn Baldwin 914d412c076SJohn Baldwin error = bus_generic_detach(dev); 915d412c076SJohn Baldwin if (error != 0) 916d412c076SJohn Baldwin return (error); 91754dfc97bSShailend Chand 91854dfc97bSShailend Chand ether_ifdetach(ifp); 91954dfc97bSShailend Chand 92054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 92154dfc97bSShailend Chand gve_destroy(priv); 92254dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 92354dfc97bSShailend Chand 92454dfc97bSShailend Chand gve_free_rings(priv); 92554dfc97bSShailend Chand gve_free_sys_res_mem(priv); 92654dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 92754dfc97bSShailend Chand 92854dfc97bSShailend Chand while (taskqueue_cancel(priv->service_tq, &priv->service_task, NULL)) 92954dfc97bSShailend Chand taskqueue_drain(priv->service_tq, &priv->service_task); 93054dfc97bSShailend Chand taskqueue_free(priv->service_tq); 93154dfc97bSShailend Chand 93254dfc97bSShailend Chand if_free(ifp); 933d412c076SJohn Baldwin return (0); 93454dfc97bSShailend Chand } 93554dfc97bSShailend Chand 93654dfc97bSShailend Chand static device_method_t gve_methods[] = { 93754dfc97bSShailend Chand DEVMETHOD(device_probe, gve_probe), 93854dfc97bSShailend Chand DEVMETHOD(device_attach, gve_attach), 93954dfc97bSShailend Chand DEVMETHOD(device_detach, gve_detach), 94054dfc97bSShailend Chand DEVMETHOD_END 94154dfc97bSShailend Chand }; 94254dfc97bSShailend Chand 94354dfc97bSShailend Chand static driver_t gve_driver = { 94454dfc97bSShailend Chand "gve", 94554dfc97bSShailend Chand gve_methods, 94654dfc97bSShailend Chand sizeof(struct gve_priv) 94754dfc97bSShailend Chand }; 94854dfc97bSShailend Chand 94954dfc97bSShailend Chand #if __FreeBSD_version < 1301503 95054dfc97bSShailend Chand static devclass_t gve_devclass; 95154dfc97bSShailend Chand 95254dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, gve_devclass, 0, 0); 95354dfc97bSShailend Chand #else 95454dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, 0, 0); 95554dfc97bSShailend Chand #endif 9561177a6c8SXin LI MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, gve, gve_devs, 9571177a6c8SXin LI nitems(gve_devs)); 958