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*40097cd6SShailend Chand #define GVE_DRIVER_VERSION "GVE-FBSD-1.3.1\n" 365f62584aSShailend Chand #define GVE_VERSION_MAJOR 1 372348ac89SShailend Chand #define GVE_VERSION_MINOR 3 38*40097cd6SShailend Chand #define GVE_VERSION_SUB 1 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); 19954dfc97bSShailend Chand int err; 20054dfc97bSShailend Chand 20154dfc97bSShailend Chand if ((new_mtu > priv->max_mtu) || (new_mtu < ETHERMIN)) { 20254dfc97bSShailend Chand device_printf(priv->dev, "Invalid new MTU setting. new mtu: %d max mtu: %d min mtu: %d\n", 20354dfc97bSShailend Chand new_mtu, priv->max_mtu, ETHERMIN); 20454dfc97bSShailend Chand return (EINVAL); 20554dfc97bSShailend Chand } 20654dfc97bSShailend Chand 20754dfc97bSShailend Chand err = gve_adminq_set_mtu(priv, new_mtu); 20854dfc97bSShailend Chand if (err == 0) { 20954dfc97bSShailend Chand if (bootverbose) 21054dfc97bSShailend Chand device_printf(priv->dev, "MTU set to %d\n", new_mtu); 21154dfc97bSShailend Chand if_setmtu(ifp, new_mtu); 21254dfc97bSShailend Chand } else { 21354dfc97bSShailend Chand device_printf(priv->dev, "Failed to set MTU to %d\n", new_mtu); 21454dfc97bSShailend Chand } 21554dfc97bSShailend Chand 21654dfc97bSShailend Chand return (err); 21754dfc97bSShailend Chand } 21854dfc97bSShailend Chand 21954dfc97bSShailend Chand static void 22054dfc97bSShailend Chand gve_init(void *arg) 22154dfc97bSShailend Chand { 22254dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 22354dfc97bSShailend Chand 22454dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) { 22554dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 22654dfc97bSShailend Chand gve_up(priv); 22754dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 22854dfc97bSShailend Chand } 22954dfc97bSShailend Chand } 23054dfc97bSShailend Chand 23154dfc97bSShailend Chand static int 23254dfc97bSShailend Chand gve_ioctl(if_t ifp, u_long command, caddr_t data) 23354dfc97bSShailend Chand { 23454dfc97bSShailend Chand struct gve_priv *priv; 23554dfc97bSShailend Chand struct ifreq *ifr; 23654dfc97bSShailend Chand int rc = 0; 23754dfc97bSShailend Chand 23854dfc97bSShailend Chand priv = if_getsoftc(ifp); 23954dfc97bSShailend Chand ifr = (struct ifreq *)data; 24054dfc97bSShailend Chand 24154dfc97bSShailend Chand switch (command) { 24254dfc97bSShailend Chand case SIOCSIFMTU: 24354dfc97bSShailend Chand if (if_getmtu(ifp) == ifr->ifr_mtu) 24454dfc97bSShailend Chand break; 24554dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 24654dfc97bSShailend Chand gve_down(priv); 24754dfc97bSShailend Chand gve_set_mtu(ifp, ifr->ifr_mtu); 24854dfc97bSShailend Chand rc = gve_up(priv); 24954dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 25054dfc97bSShailend Chand break; 25154dfc97bSShailend Chand 25254dfc97bSShailend Chand case SIOCSIFFLAGS: 25354dfc97bSShailend Chand if ((if_getflags(ifp) & IFF_UP) != 0) { 25454dfc97bSShailend Chand if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 25554dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 25654dfc97bSShailend Chand rc = gve_up(priv); 25754dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 25854dfc97bSShailend Chand } 25954dfc97bSShailend Chand } else { 26054dfc97bSShailend Chand if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 26154dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 26254dfc97bSShailend Chand gve_down(priv); 26354dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 26454dfc97bSShailend Chand } 26554dfc97bSShailend Chand } 26654dfc97bSShailend Chand break; 26754dfc97bSShailend Chand 26854dfc97bSShailend Chand case SIOCSIFCAP: 26954dfc97bSShailend Chand if (ifr->ifr_reqcap == if_getcapenable(ifp)) 27054dfc97bSShailend Chand break; 27154dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 27254dfc97bSShailend Chand gve_down(priv); 27354dfc97bSShailend Chand if_setcapenable(ifp, ifr->ifr_reqcap); 27454dfc97bSShailend Chand rc = gve_up(priv); 27554dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 27654dfc97bSShailend Chand break; 27754dfc97bSShailend Chand 27854dfc97bSShailend Chand case SIOCSIFMEDIA: 27954dfc97bSShailend Chand /* FALLTHROUGH */ 28054dfc97bSShailend Chand case SIOCGIFMEDIA: 28154dfc97bSShailend Chand rc = ifmedia_ioctl(ifp, ifr, &priv->media, command); 28254dfc97bSShailend Chand break; 28354dfc97bSShailend Chand 28454dfc97bSShailend Chand default: 28554dfc97bSShailend Chand rc = ether_ioctl(ifp, command, data); 28654dfc97bSShailend Chand break; 28754dfc97bSShailend Chand } 28854dfc97bSShailend Chand 28954dfc97bSShailend Chand return (rc); 29054dfc97bSShailend Chand } 29154dfc97bSShailend Chand 29254dfc97bSShailend Chand static int 29354dfc97bSShailend Chand gve_media_change(if_t ifp) 29454dfc97bSShailend Chand { 29554dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 29654dfc97bSShailend Chand 29754dfc97bSShailend Chand device_printf(priv->dev, "Media change not supported\n"); 29854dfc97bSShailend Chand return (0); 29954dfc97bSShailend Chand } 30054dfc97bSShailend Chand 30154dfc97bSShailend Chand static void 30254dfc97bSShailend Chand gve_media_status(if_t ifp, struct ifmediareq *ifmr) 30354dfc97bSShailend Chand { 30454dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 30554dfc97bSShailend Chand 30654dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 30754dfc97bSShailend Chand 30854dfc97bSShailend Chand ifmr->ifm_status = IFM_AVALID; 30954dfc97bSShailend Chand ifmr->ifm_active = IFM_ETHER; 31054dfc97bSShailend Chand 31154dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 31254dfc97bSShailend Chand ifmr->ifm_status |= IFM_ACTIVE; 31354dfc97bSShailend Chand ifmr->ifm_active |= IFM_AUTO; 31454dfc97bSShailend Chand } else { 31554dfc97bSShailend Chand ifmr->ifm_active |= IFM_NONE; 31654dfc97bSShailend Chand } 31754dfc97bSShailend Chand 31854dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 31954dfc97bSShailend Chand } 32054dfc97bSShailend Chand 32154dfc97bSShailend Chand static uint64_t 32254dfc97bSShailend Chand gve_get_counter(if_t ifp, ift_counter cnt) 32354dfc97bSShailend Chand { 32454dfc97bSShailend Chand struct gve_priv *priv; 32554dfc97bSShailend Chand uint64_t rpackets = 0; 32654dfc97bSShailend Chand uint64_t tpackets = 0; 32754dfc97bSShailend Chand uint64_t rbytes = 0; 32854dfc97bSShailend Chand uint64_t tbytes = 0; 32954dfc97bSShailend Chand uint64_t rx_dropped_pkt = 0; 33054dfc97bSShailend Chand uint64_t tx_dropped_pkt = 0; 33154dfc97bSShailend Chand 33254dfc97bSShailend Chand priv = if_getsoftc(ifp); 33354dfc97bSShailend Chand 33454dfc97bSShailend Chand gve_accum_stats(priv, &rpackets, &rbytes, &rx_dropped_pkt, &tpackets, 33554dfc97bSShailend Chand &tbytes, &tx_dropped_pkt); 33654dfc97bSShailend Chand 33754dfc97bSShailend Chand switch (cnt) { 33854dfc97bSShailend Chand case IFCOUNTER_IPACKETS: 33954dfc97bSShailend Chand return (rpackets); 34054dfc97bSShailend Chand 34154dfc97bSShailend Chand case IFCOUNTER_OPACKETS: 34254dfc97bSShailend Chand return (tpackets); 34354dfc97bSShailend Chand 34454dfc97bSShailend Chand case IFCOUNTER_IBYTES: 34554dfc97bSShailend Chand return (rbytes); 34654dfc97bSShailend Chand 34754dfc97bSShailend Chand case IFCOUNTER_OBYTES: 34854dfc97bSShailend Chand return (tbytes); 34954dfc97bSShailend Chand 35054dfc97bSShailend Chand case IFCOUNTER_IQDROPS: 35154dfc97bSShailend Chand return (rx_dropped_pkt); 35254dfc97bSShailend Chand 35354dfc97bSShailend Chand case IFCOUNTER_OQDROPS: 35454dfc97bSShailend Chand return (tx_dropped_pkt); 35554dfc97bSShailend Chand 35654dfc97bSShailend Chand default: 35754dfc97bSShailend Chand return (if_get_counter_default(ifp, cnt)); 35854dfc97bSShailend Chand } 35954dfc97bSShailend Chand } 36054dfc97bSShailend Chand 361aa386085SZhenlei Huang static void 36254dfc97bSShailend Chand gve_setup_ifnet(device_t dev, struct gve_priv *priv) 36354dfc97bSShailend Chand { 36454dfc97bSShailend Chand int caps = 0; 36554dfc97bSShailend Chand if_t ifp; 36654dfc97bSShailend Chand 36754dfc97bSShailend Chand ifp = priv->ifp = if_alloc(IFT_ETHER); 36854dfc97bSShailend Chand if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 36954dfc97bSShailend Chand if_setsoftc(ifp, priv); 37054dfc97bSShailend Chand if_setdev(ifp, dev); 37154dfc97bSShailend Chand if_setinitfn(ifp, gve_init); 37254dfc97bSShailend Chand if_setioctlfn(ifp, gve_ioctl); 37354dfc97bSShailend Chand if_settransmitfn(ifp, gve_xmit_ifp); 37454dfc97bSShailend Chand if_setqflushfn(ifp, gve_qflush); 37554dfc97bSShailend Chand 376d438b4efSShailend Chand /* 377d438b4efSShailend Chand * Set TSO limits, must match the arguments to bus_dma_tag_create 3782348ac89SShailend Chand * when creating tx->dqo.buf_dmatag. Only applies to the RDA mode 3792348ac89SShailend Chand * because in QPL we copy the entire pakcet into the bounce buffer 3802348ac89SShailend Chand * and thus it does not matter how fragmented the mbuf is. 381d438b4efSShailend Chand */ 3822348ac89SShailend Chand if (!gve_is_gqi(priv) && !gve_is_qpl(priv)) { 383d438b4efSShailend Chand if_sethwtsomaxsegcount(ifp, GVE_TX_MAX_DATA_DESCS_DQO); 384d438b4efSShailend Chand if_sethwtsomaxsegsize(ifp, GVE_TX_MAX_BUF_SIZE_DQO); 385d438b4efSShailend Chand } 3862348ac89SShailend Chand if_sethwtsomax(ifp, GVE_TSO_MAXSIZE_DQO); 387d438b4efSShailend Chand 38854dfc97bSShailend Chand #if __FreeBSD_version >= 1400086 38954dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 39054dfc97bSShailend Chand #else 39154dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_KNOWSEPOCH); 39254dfc97bSShailend Chand #endif 39354dfc97bSShailend Chand 39454dfc97bSShailend Chand ifmedia_init(&priv->media, IFM_IMASK, gve_media_change, gve_media_status); 39554dfc97bSShailend Chand if_setgetcounterfn(ifp, gve_get_counter); 39654dfc97bSShailend Chand 39754dfc97bSShailend Chand caps = IFCAP_RXCSUM | 39854dfc97bSShailend Chand IFCAP_TXCSUM | 39954dfc97bSShailend Chand IFCAP_TXCSUM_IPV6 | 40054dfc97bSShailend Chand IFCAP_TSO | 40154dfc97bSShailend Chand IFCAP_LRO; 40254dfc97bSShailend Chand 40354dfc97bSShailend Chand if ((priv->supported_features & GVE_SUP_JUMBO_FRAMES_MASK) != 0) 40454dfc97bSShailend Chand caps |= IFCAP_JUMBO_MTU; 40554dfc97bSShailend Chand 40654dfc97bSShailend Chand if_setcapabilities(ifp, caps); 40754dfc97bSShailend Chand if_setcapenable(ifp, caps); 40854dfc97bSShailend Chand 40954dfc97bSShailend Chand if (bootverbose) 41054dfc97bSShailend Chand device_printf(priv->dev, "Setting initial MTU to %d\n", priv->max_mtu); 41154dfc97bSShailend Chand if_setmtu(ifp, priv->max_mtu); 41254dfc97bSShailend Chand 41354dfc97bSShailend Chand ether_ifattach(ifp, priv->mac); 41454dfc97bSShailend Chand 41554dfc97bSShailend Chand ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 41654dfc97bSShailend Chand ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 41754dfc97bSShailend Chand } 41854dfc97bSShailend Chand 41954dfc97bSShailend Chand static int 42054dfc97bSShailend Chand gve_alloc_counter_array(struct gve_priv *priv) 42154dfc97bSShailend Chand { 42254dfc97bSShailend Chand int err; 42354dfc97bSShailend Chand 42454dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, sizeof(uint32_t) * priv->num_event_counters, 42554dfc97bSShailend Chand PAGE_SIZE, &priv->counter_array_mem); 42654dfc97bSShailend Chand if (err != 0) 42754dfc97bSShailend Chand return (err); 42854dfc97bSShailend Chand 42954dfc97bSShailend Chand priv->counters = priv->counter_array_mem.cpu_addr; 43054dfc97bSShailend Chand return (0); 43154dfc97bSShailend Chand } 43254dfc97bSShailend Chand 43354dfc97bSShailend Chand static void 43454dfc97bSShailend Chand gve_free_counter_array(struct gve_priv *priv) 43554dfc97bSShailend Chand { 43654dfc97bSShailend Chand if (priv->counters != NULL) 43754dfc97bSShailend Chand gve_dma_free_coherent(&priv->counter_array_mem); 43854dfc97bSShailend Chand priv->counter_array_mem = (struct gve_dma_handle){}; 43954dfc97bSShailend Chand } 44054dfc97bSShailend Chand 44154dfc97bSShailend Chand static int 44254dfc97bSShailend Chand gve_alloc_irq_db_array(struct gve_priv *priv) 44354dfc97bSShailend Chand { 44454dfc97bSShailend Chand int err; 44554dfc97bSShailend Chand 44654dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, 44754dfc97bSShailend Chand sizeof(struct gve_irq_db) * (priv->num_queues), PAGE_SIZE, 44854dfc97bSShailend Chand &priv->irqs_db_mem); 44954dfc97bSShailend Chand if (err != 0) 45054dfc97bSShailend Chand return (err); 45154dfc97bSShailend Chand 45254dfc97bSShailend Chand priv->irq_db_indices = priv->irqs_db_mem.cpu_addr; 45354dfc97bSShailend Chand return (0); 45454dfc97bSShailend Chand } 45554dfc97bSShailend Chand 45654dfc97bSShailend Chand static void 45754dfc97bSShailend Chand gve_free_irq_db_array(struct gve_priv *priv) 45854dfc97bSShailend Chand { 45954dfc97bSShailend Chand if (priv->irq_db_indices != NULL) 46054dfc97bSShailend Chand gve_dma_free_coherent(&priv->irqs_db_mem); 46154dfc97bSShailend Chand priv->irqs_db_mem = (struct gve_dma_handle){}; 46254dfc97bSShailend Chand } 46354dfc97bSShailend Chand 46454dfc97bSShailend Chand static void 46554dfc97bSShailend Chand gve_free_rings(struct gve_priv *priv) 46654dfc97bSShailend Chand { 46754dfc97bSShailend Chand gve_free_irqs(priv); 46854dfc97bSShailend Chand gve_free_tx_rings(priv); 46954dfc97bSShailend Chand gve_free_rx_rings(priv); 4702348ac89SShailend Chand if (gve_is_qpl(priv)) 47154dfc97bSShailend Chand gve_free_qpls(priv); 47254dfc97bSShailend Chand } 47354dfc97bSShailend Chand 47454dfc97bSShailend Chand static int 47554dfc97bSShailend Chand gve_alloc_rings(struct gve_priv *priv) 47654dfc97bSShailend Chand { 47754dfc97bSShailend Chand int err; 47854dfc97bSShailend Chand 4792348ac89SShailend Chand if (gve_is_qpl(priv)) { 48054dfc97bSShailend Chand err = gve_alloc_qpls(priv); 48154dfc97bSShailend Chand if (err != 0) 48254dfc97bSShailend Chand goto abort; 483d438b4efSShailend Chand } 48454dfc97bSShailend Chand 48554dfc97bSShailend Chand err = gve_alloc_rx_rings(priv); 48654dfc97bSShailend Chand if (err != 0) 48754dfc97bSShailend Chand goto abort; 48854dfc97bSShailend Chand 48954dfc97bSShailend Chand err = gve_alloc_tx_rings(priv); 49054dfc97bSShailend Chand if (err != 0) 49154dfc97bSShailend Chand goto abort; 49254dfc97bSShailend Chand 49354dfc97bSShailend Chand err = gve_alloc_irqs(priv); 49454dfc97bSShailend Chand if (err != 0) 49554dfc97bSShailend Chand goto abort; 49654dfc97bSShailend Chand 49754dfc97bSShailend Chand return (0); 49854dfc97bSShailend Chand 49954dfc97bSShailend Chand abort: 50054dfc97bSShailend Chand gve_free_rings(priv); 50154dfc97bSShailend Chand return (err); 50254dfc97bSShailend Chand } 50354dfc97bSShailend Chand 50454dfc97bSShailend Chand static void 50554dfc97bSShailend Chand gve_deconfigure_resources(struct gve_priv *priv) 50654dfc97bSShailend Chand { 50754dfc97bSShailend Chand int err; 50854dfc97bSShailend Chand 50954dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) { 51054dfc97bSShailend Chand err = gve_adminq_deconfigure_device_resources(priv); 51154dfc97bSShailend Chand if (err != 0) { 51254dfc97bSShailend Chand device_printf(priv->dev, "Failed to deconfigure device resources: err=%d\n", 51354dfc97bSShailend Chand err); 51454dfc97bSShailend Chand return; 51554dfc97bSShailend Chand } 51654dfc97bSShailend Chand if (bootverbose) 51754dfc97bSShailend Chand device_printf(priv->dev, "Deconfigured device resources\n"); 51854dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 51954dfc97bSShailend Chand } 52054dfc97bSShailend Chand 52154dfc97bSShailend Chand gve_free_irq_db_array(priv); 52254dfc97bSShailend Chand gve_free_counter_array(priv); 523d438b4efSShailend Chand 524d438b4efSShailend Chand if (priv->ptype_lut_dqo) { 525d438b4efSShailend Chand free(priv->ptype_lut_dqo, M_GVE); 526d438b4efSShailend Chand priv->ptype_lut_dqo = NULL; 527d438b4efSShailend Chand } 52854dfc97bSShailend Chand } 52954dfc97bSShailend Chand 53054dfc97bSShailend Chand static int 53154dfc97bSShailend Chand gve_configure_resources(struct gve_priv *priv) 53254dfc97bSShailend Chand { 53354dfc97bSShailend Chand int err; 53454dfc97bSShailend Chand 53554dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) 53654dfc97bSShailend Chand return (0); 53754dfc97bSShailend Chand 53854dfc97bSShailend Chand err = gve_alloc_counter_array(priv); 53954dfc97bSShailend Chand if (err != 0) 54054dfc97bSShailend Chand return (err); 54154dfc97bSShailend Chand 54254dfc97bSShailend Chand err = gve_alloc_irq_db_array(priv); 54354dfc97bSShailend Chand if (err != 0) 54454dfc97bSShailend Chand goto abort; 54554dfc97bSShailend Chand 54654dfc97bSShailend Chand err = gve_adminq_configure_device_resources(priv); 54754dfc97bSShailend Chand if (err != 0) { 54854dfc97bSShailend Chand device_printf(priv->dev, "Failed to configure device resources: err=%d\n", 54954dfc97bSShailend Chand err); 55054dfc97bSShailend Chand err = (ENXIO); 55154dfc97bSShailend Chand goto abort; 55254dfc97bSShailend Chand } 55354dfc97bSShailend Chand 554d438b4efSShailend Chand if (!gve_is_gqi(priv)) { 555d438b4efSShailend Chand priv->ptype_lut_dqo = malloc(sizeof(*priv->ptype_lut_dqo), M_GVE, 556d438b4efSShailend Chand M_WAITOK | M_ZERO); 557d438b4efSShailend Chand 558d438b4efSShailend Chand err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo); 559d438b4efSShailend Chand if (err != 0) { 560d438b4efSShailend Chand device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n", 561d438b4efSShailend Chand err); 562d438b4efSShailend Chand goto abort; 563d438b4efSShailend Chand } 564d438b4efSShailend Chand } 565d438b4efSShailend Chand 56654dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 56754dfc97bSShailend Chand if (bootverbose) 56854dfc97bSShailend Chand device_printf(priv->dev, "Configured device resources\n"); 56954dfc97bSShailend Chand return (0); 57054dfc97bSShailend Chand 57154dfc97bSShailend Chand abort: 57254dfc97bSShailend Chand gve_deconfigure_resources(priv); 57354dfc97bSShailend Chand return (err); 57454dfc97bSShailend Chand } 57554dfc97bSShailend Chand 57654dfc97bSShailend Chand static void 57754dfc97bSShailend Chand gve_set_queue_cnts(struct gve_priv *priv) 57854dfc97bSShailend Chand { 57954dfc97bSShailend Chand priv->tx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_TX_QUEUES); 58054dfc97bSShailend Chand priv->rx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_RX_QUEUES); 58154dfc97bSShailend Chand priv->tx_cfg.num_queues = priv->tx_cfg.max_queues; 58254dfc97bSShailend Chand priv->rx_cfg.num_queues = priv->rx_cfg.max_queues; 58354dfc97bSShailend Chand 58454dfc97bSShailend Chand if (priv->default_num_queues > 0) { 58554dfc97bSShailend Chand priv->tx_cfg.num_queues = MIN(priv->default_num_queues, 58654dfc97bSShailend Chand priv->tx_cfg.num_queues); 58754dfc97bSShailend Chand priv->rx_cfg.num_queues = MIN(priv->default_num_queues, 58854dfc97bSShailend Chand priv->rx_cfg.num_queues); 58954dfc97bSShailend Chand } 59054dfc97bSShailend Chand 59154dfc97bSShailend Chand priv->num_queues = priv->tx_cfg.num_queues + priv->rx_cfg.num_queues; 59254dfc97bSShailend Chand priv->mgmt_msix_idx = priv->num_queues; 59354dfc97bSShailend Chand } 59454dfc97bSShailend Chand 59554dfc97bSShailend Chand static int 59654dfc97bSShailend Chand gve_alloc_adminq_and_describe_device(struct gve_priv *priv) 59754dfc97bSShailend Chand { 59854dfc97bSShailend Chand int err; 59954dfc97bSShailend Chand 60054dfc97bSShailend Chand if ((err = gve_adminq_alloc(priv)) != 0) 60154dfc97bSShailend Chand return (err); 60254dfc97bSShailend Chand 60354dfc97bSShailend Chand if ((err = gve_verify_driver_compatibility(priv)) != 0) { 60454dfc97bSShailend Chand device_printf(priv->dev, 60554dfc97bSShailend Chand "Failed to verify driver compatibility: err=%d\n", err); 60654dfc97bSShailend Chand goto abort; 60754dfc97bSShailend Chand } 60854dfc97bSShailend Chand 60954dfc97bSShailend Chand if ((err = gve_adminq_describe_device(priv)) != 0) 61054dfc97bSShailend Chand goto abort; 61154dfc97bSShailend Chand 61254dfc97bSShailend Chand gve_set_queue_cnts(priv); 61354dfc97bSShailend Chand 61454dfc97bSShailend Chand priv->num_registered_pages = 0; 61554dfc97bSShailend Chand return (0); 61654dfc97bSShailend Chand 61754dfc97bSShailend Chand abort: 61854dfc97bSShailend Chand gve_release_adminq(priv); 61954dfc97bSShailend Chand return (err); 62054dfc97bSShailend Chand } 62154dfc97bSShailend Chand 62254dfc97bSShailend Chand void 62354dfc97bSShailend Chand gve_schedule_reset(struct gve_priv *priv) 62454dfc97bSShailend Chand { 62554dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) 62654dfc97bSShailend Chand return; 62754dfc97bSShailend Chand 62854dfc97bSShailend Chand device_printf(priv->dev, "Scheduling reset task!\n"); 62954dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 63054dfc97bSShailend Chand taskqueue_enqueue(priv->service_tq, &priv->service_task); 63154dfc97bSShailend Chand } 63254dfc97bSShailend Chand 63354dfc97bSShailend Chand static void 63454dfc97bSShailend Chand gve_destroy(struct gve_priv *priv) 63554dfc97bSShailend Chand { 63654dfc97bSShailend Chand gve_down(priv); 63754dfc97bSShailend Chand gve_deconfigure_resources(priv); 63854dfc97bSShailend Chand gve_release_adminq(priv); 63954dfc97bSShailend Chand } 64054dfc97bSShailend Chand 64154dfc97bSShailend Chand static void 64254dfc97bSShailend Chand gve_restore(struct gve_priv *priv) 64354dfc97bSShailend Chand { 64454dfc97bSShailend Chand int err; 64554dfc97bSShailend Chand 64654dfc97bSShailend Chand err = gve_adminq_alloc(priv); 64754dfc97bSShailend Chand if (err != 0) 64854dfc97bSShailend Chand goto abort; 64954dfc97bSShailend Chand 65054dfc97bSShailend Chand err = gve_configure_resources(priv); 65154dfc97bSShailend Chand if (err != 0) 65254dfc97bSShailend Chand goto abort; 65354dfc97bSShailend Chand 65454dfc97bSShailend Chand err = gve_up(priv); 65554dfc97bSShailend Chand if (err != 0) 65654dfc97bSShailend Chand goto abort; 65754dfc97bSShailend Chand 65854dfc97bSShailend Chand return; 65954dfc97bSShailend Chand 66054dfc97bSShailend Chand abort: 66154dfc97bSShailend Chand device_printf(priv->dev, "Restore failed!\n"); 66254dfc97bSShailend Chand return; 66354dfc97bSShailend Chand } 66454dfc97bSShailend Chand 66554dfc97bSShailend Chand static void 66654dfc97bSShailend Chand gve_handle_reset(struct gve_priv *priv) 66754dfc97bSShailend Chand { 66854dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_DO_RESET)) 66954dfc97bSShailend Chand return; 67054dfc97bSShailend Chand 67154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 67254dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 67354dfc97bSShailend Chand 67454dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 67554dfc97bSShailend Chand 67654dfc97bSShailend Chand if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 67754dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 67854dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 67954dfc97bSShailend Chand 68054dfc97bSShailend Chand /* 68154dfc97bSShailend Chand * Releasing the adminq causes the NIC to destroy all resources 68254dfc97bSShailend Chand * registered with it, so by clearing the flags beneath we cause 68354dfc97bSShailend Chand * the subsequent gve_down call below to not attempt to tell the 68454dfc97bSShailend Chand * NIC to destroy these resources again. 68554dfc97bSShailend Chand * 68654dfc97bSShailend Chand * The call to gve_down is needed in the first place to refresh 68754dfc97bSShailend Chand * the state and the DMA-able memory within each driver ring. 68854dfc97bSShailend Chand */ 68954dfc97bSShailend Chand gve_release_adminq(priv); 69054dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 69154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK); 69254dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RX_RINGS_OK); 69354dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_TX_RINGS_OK); 69454dfc97bSShailend Chand 69554dfc97bSShailend Chand gve_down(priv); 69654dfc97bSShailend Chand gve_restore(priv); 69754dfc97bSShailend Chand 69854dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 69954dfc97bSShailend Chand 70054dfc97bSShailend Chand priv->reset_cnt++; 70154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 70254dfc97bSShailend Chand } 70354dfc97bSShailend Chand 70454dfc97bSShailend Chand static void 70554dfc97bSShailend Chand gve_handle_link_status(struct gve_priv *priv) 70654dfc97bSShailend Chand { 70754dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 70854dfc97bSShailend Chand bool link_up = status & GVE_DEVICE_STATUS_LINK_STATUS; 70954dfc97bSShailend Chand 71054dfc97bSShailend Chand if (link_up == gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) 71154dfc97bSShailend Chand return; 71254dfc97bSShailend Chand 71354dfc97bSShailend Chand if (link_up) { 71454dfc97bSShailend Chand if (bootverbose) 71554dfc97bSShailend Chand device_printf(priv->dev, "Device link is up.\n"); 71654dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_UP); 71754dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 71854dfc97bSShailend Chand } else { 71954dfc97bSShailend Chand device_printf(priv->dev, "Device link is down.\n"); 72054dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 72154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 72254dfc97bSShailend Chand } 72354dfc97bSShailend Chand } 72454dfc97bSShailend Chand 72554dfc97bSShailend Chand static void 72654dfc97bSShailend Chand gve_service_task(void *arg, int pending) 72754dfc97bSShailend Chand { 72854dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 72954dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 73054dfc97bSShailend Chand 73154dfc97bSShailend Chand if (((GVE_DEVICE_STATUS_RESET_MASK & status) != 0) && 73254dfc97bSShailend Chand !gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) { 73354dfc97bSShailend Chand device_printf(priv->dev, "Device requested reset\n"); 73454dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 73554dfc97bSShailend Chand } 73654dfc97bSShailend Chand 73754dfc97bSShailend Chand gve_handle_reset(priv); 73854dfc97bSShailend Chand gve_handle_link_status(priv); 73954dfc97bSShailend Chand } 74054dfc97bSShailend Chand 74154dfc97bSShailend Chand static int 74254dfc97bSShailend Chand gve_probe(device_t dev) 74354dfc97bSShailend Chand { 7441bbdfb0bSXin LI uint16_t deviceid, vendorid; 7451bbdfb0bSXin LI int i; 7461bbdfb0bSXin LI 7471bbdfb0bSXin LI vendorid = pci_get_vendor(dev); 7481bbdfb0bSXin LI deviceid = pci_get_device(dev); 7491bbdfb0bSXin LI 7501177a6c8SXin LI for (i = 0; i < nitems(gve_devs); i++) { 7511bbdfb0bSXin LI if (vendorid == gve_devs[i].vendor_id && 7521bbdfb0bSXin LI deviceid == gve_devs[i].device_id) { 7531bbdfb0bSXin LI device_set_desc(dev, gve_devs[i].name); 75454dfc97bSShailend Chand return (BUS_PROBE_DEFAULT); 75554dfc97bSShailend Chand } 7561bbdfb0bSXin LI } 75754dfc97bSShailend Chand return (ENXIO); 75854dfc97bSShailend Chand } 75954dfc97bSShailend Chand 76054dfc97bSShailend Chand static void 76154dfc97bSShailend Chand gve_free_sys_res_mem(struct gve_priv *priv) 76254dfc97bSShailend Chand { 76354dfc97bSShailend Chand if (priv->msix_table != NULL) 76454dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 76554dfc97bSShailend Chand rman_get_rid(priv->msix_table), priv->msix_table); 76654dfc97bSShailend Chand 76754dfc97bSShailend Chand if (priv->db_bar != NULL) 76854dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 76954dfc97bSShailend Chand rman_get_rid(priv->db_bar), priv->db_bar); 77054dfc97bSShailend Chand 77154dfc97bSShailend Chand if (priv->reg_bar != NULL) 77254dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 77354dfc97bSShailend Chand rman_get_rid(priv->reg_bar), priv->reg_bar); 77454dfc97bSShailend Chand } 77554dfc97bSShailend Chand 77654dfc97bSShailend Chand static int 77754dfc97bSShailend Chand gve_attach(device_t dev) 77854dfc97bSShailend Chand { 77954dfc97bSShailend Chand struct gve_priv *priv; 78054dfc97bSShailend Chand int rid; 78154dfc97bSShailend Chand int err; 78254dfc97bSShailend Chand 783d438b4efSShailend Chand snprintf(gve_version, sizeof(gve_version), "%d.%d.%d", 784d438b4efSShailend Chand GVE_VERSION_MAJOR, GVE_VERSION_MINOR, GVE_VERSION_SUB); 785d438b4efSShailend Chand 78654dfc97bSShailend Chand priv = device_get_softc(dev); 78754dfc97bSShailend Chand priv->dev = dev; 78854dfc97bSShailend Chand GVE_IFACE_LOCK_INIT(priv->gve_iface_lock); 78954dfc97bSShailend Chand 79054dfc97bSShailend Chand pci_enable_busmaster(dev); 79154dfc97bSShailend Chand 79254dfc97bSShailend Chand rid = PCIR_BAR(GVE_REGISTER_BAR); 79354dfc97bSShailend Chand priv->reg_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 79454dfc97bSShailend Chand &rid, RF_ACTIVE); 79554dfc97bSShailend Chand if (priv->reg_bar == NULL) { 79654dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR0\n"); 79754dfc97bSShailend Chand err = ENXIO; 79854dfc97bSShailend Chand goto abort; 79954dfc97bSShailend Chand } 80054dfc97bSShailend Chand 80154dfc97bSShailend Chand rid = PCIR_BAR(GVE_DOORBELL_BAR); 80254dfc97bSShailend Chand priv->db_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 80354dfc97bSShailend Chand &rid, RF_ACTIVE); 80454dfc97bSShailend Chand if (priv->db_bar == NULL) { 80554dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR2\n"); 80654dfc97bSShailend Chand err = ENXIO; 80754dfc97bSShailend Chand goto abort; 80854dfc97bSShailend Chand } 80954dfc97bSShailend Chand 81054dfc97bSShailend Chand rid = pci_msix_table_bar(priv->dev); 81154dfc97bSShailend Chand priv->msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 81254dfc97bSShailend Chand &rid, RF_ACTIVE); 81354dfc97bSShailend Chand if (priv->msix_table == NULL) { 81454dfc97bSShailend Chand device_printf(dev, "Failed to allocate msix table\n"); 81554dfc97bSShailend Chand err = ENXIO; 81654dfc97bSShailend Chand goto abort; 81754dfc97bSShailend Chand } 81854dfc97bSShailend Chand 81954dfc97bSShailend Chand err = gve_alloc_adminq_and_describe_device(priv); 82054dfc97bSShailend Chand if (err != 0) 82154dfc97bSShailend Chand goto abort; 82254dfc97bSShailend Chand 82354dfc97bSShailend Chand err = gve_configure_resources(priv); 82454dfc97bSShailend Chand if (err != 0) 82554dfc97bSShailend Chand goto abort; 82654dfc97bSShailend Chand 82754dfc97bSShailend Chand err = gve_alloc_rings(priv); 82854dfc97bSShailend Chand if (err != 0) 82954dfc97bSShailend Chand goto abort; 83054dfc97bSShailend Chand 831aa386085SZhenlei Huang gve_setup_ifnet(dev, priv); 83254dfc97bSShailend Chand 83354dfc97bSShailend Chand priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; 83454dfc97bSShailend Chand 83554dfc97bSShailend Chand bus_write_multi_1(priv->reg_bar, DRIVER_VERSION, GVE_DRIVER_VERSION, 83654dfc97bSShailend Chand sizeof(GVE_DRIVER_VERSION) - 1); 83754dfc97bSShailend Chand 83854dfc97bSShailend Chand TASK_INIT(&priv->service_task, 0, gve_service_task, priv); 83954dfc97bSShailend Chand priv->service_tq = taskqueue_create("gve service", M_WAITOK | M_ZERO, 84054dfc97bSShailend Chand taskqueue_thread_enqueue, &priv->service_tq); 84154dfc97bSShailend Chand taskqueue_start_threads(&priv->service_tq, 1, PI_NET, "%s service tq", 84254dfc97bSShailend Chand device_get_nameunit(priv->dev)); 84354dfc97bSShailend Chand 84454dfc97bSShailend Chand gve_setup_sysctl(priv); 84554dfc97bSShailend Chand 84654dfc97bSShailend Chand if (bootverbose) 84754dfc97bSShailend Chand device_printf(priv->dev, "Successfully attached %s", GVE_DRIVER_VERSION); 84854dfc97bSShailend Chand return (0); 84954dfc97bSShailend Chand 85054dfc97bSShailend Chand abort: 85154dfc97bSShailend Chand gve_free_rings(priv); 85254dfc97bSShailend Chand gve_deconfigure_resources(priv); 85354dfc97bSShailend Chand gve_release_adminq(priv); 85454dfc97bSShailend Chand gve_free_sys_res_mem(priv); 85554dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 85654dfc97bSShailend Chand return (err); 85754dfc97bSShailend Chand } 85854dfc97bSShailend Chand 85954dfc97bSShailend Chand static int 86054dfc97bSShailend Chand gve_detach(device_t dev) 86154dfc97bSShailend Chand { 86254dfc97bSShailend Chand struct gve_priv *priv = device_get_softc(dev); 86354dfc97bSShailend Chand if_t ifp = priv->ifp; 864d412c076SJohn Baldwin int error; 865d412c076SJohn Baldwin 866d412c076SJohn Baldwin error = bus_generic_detach(dev); 867d412c076SJohn Baldwin if (error != 0) 868d412c076SJohn Baldwin return (error); 86954dfc97bSShailend Chand 87054dfc97bSShailend Chand ether_ifdetach(ifp); 87154dfc97bSShailend Chand 87254dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 87354dfc97bSShailend Chand gve_destroy(priv); 87454dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 87554dfc97bSShailend Chand 87654dfc97bSShailend Chand gve_free_rings(priv); 87754dfc97bSShailend Chand gve_free_sys_res_mem(priv); 87854dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 87954dfc97bSShailend Chand 88054dfc97bSShailend Chand while (taskqueue_cancel(priv->service_tq, &priv->service_task, NULL)) 88154dfc97bSShailend Chand taskqueue_drain(priv->service_tq, &priv->service_task); 88254dfc97bSShailend Chand taskqueue_free(priv->service_tq); 88354dfc97bSShailend Chand 88454dfc97bSShailend Chand if_free(ifp); 885d412c076SJohn Baldwin return (0); 88654dfc97bSShailend Chand } 88754dfc97bSShailend Chand 88854dfc97bSShailend Chand static device_method_t gve_methods[] = { 88954dfc97bSShailend Chand DEVMETHOD(device_probe, gve_probe), 89054dfc97bSShailend Chand DEVMETHOD(device_attach, gve_attach), 89154dfc97bSShailend Chand DEVMETHOD(device_detach, gve_detach), 89254dfc97bSShailend Chand DEVMETHOD_END 89354dfc97bSShailend Chand }; 89454dfc97bSShailend Chand 89554dfc97bSShailend Chand static driver_t gve_driver = { 89654dfc97bSShailend Chand "gve", 89754dfc97bSShailend Chand gve_methods, 89854dfc97bSShailend Chand sizeof(struct gve_priv) 89954dfc97bSShailend Chand }; 90054dfc97bSShailend Chand 90154dfc97bSShailend Chand #if __FreeBSD_version < 1301503 90254dfc97bSShailend Chand static devclass_t gve_devclass; 90354dfc97bSShailend Chand 90454dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, gve_devclass, 0, 0); 90554dfc97bSShailend Chand #else 90654dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, 0, 0); 90754dfc97bSShailend Chand #endif 9081177a6c8SXin LI MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, gve, gve_devs, 9091177a6c8SXin LI nitems(gve_devs)); 910