154dfc97bSShailend Chand /*- 254dfc97bSShailend Chand * SPDX-License-Identifier: BSD-3-Clause 354dfc97bSShailend Chand * 4*d438b4efSShailend 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" 33*d438b4efSShailend Chand #include "gve_dqo.h" 3454dfc97bSShailend Chand 35*d438b4efSShailend Chand #define GVE_DRIVER_VERSION "GVE-FBSD-1.2.0\n" 365f62584aSShailend Chand #define GVE_VERSION_MAJOR 1 37*d438b4efSShailend Chand #define GVE_VERSION_MINOR 2 38*d438b4efSShailend Chand #define GVE_VERSION_SUB 0 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 128*d438b4efSShailend Chand if (gve_is_gqi(priv)) { 12954dfc97bSShailend Chand err = gve_register_qpls(priv); 13054dfc97bSShailend Chand if (err != 0) 13154dfc97bSShailend Chand goto reset; 132*d438b4efSShailend 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 180*d438b4efSShailend Chand if (gve_is_gqi(priv)) { 18154dfc97bSShailend Chand if (gve_unregister_qpls(priv) != 0) 18254dfc97bSShailend Chand goto reset; 183*d438b4efSShailend Chand } 18454dfc97bSShailend Chand 185*d438b4efSShailend 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 376*d438b4efSShailend Chand /* 377*d438b4efSShailend Chand * Set TSO limits, must match the arguments to bus_dma_tag_create 378*d438b4efSShailend Chand * when creating tx->dqo.buf_dmatag 379*d438b4efSShailend Chand */ 380*d438b4efSShailend Chand if (!gve_is_gqi(priv)) { 381*d438b4efSShailend Chand if_sethwtsomax(ifp, GVE_TSO_MAXSIZE_DQO); 382*d438b4efSShailend Chand if_sethwtsomaxsegcount(ifp, GVE_TX_MAX_DATA_DESCS_DQO); 383*d438b4efSShailend Chand if_sethwtsomaxsegsize(ifp, GVE_TX_MAX_BUF_SIZE_DQO); 384*d438b4efSShailend Chand } 385*d438b4efSShailend Chand 38654dfc97bSShailend Chand #if __FreeBSD_version >= 1400086 38754dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 38854dfc97bSShailend Chand #else 38954dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_KNOWSEPOCH); 39054dfc97bSShailend Chand #endif 39154dfc97bSShailend Chand 39254dfc97bSShailend Chand ifmedia_init(&priv->media, IFM_IMASK, gve_media_change, gve_media_status); 39354dfc97bSShailend Chand if_setgetcounterfn(ifp, gve_get_counter); 39454dfc97bSShailend Chand 39554dfc97bSShailend Chand caps = IFCAP_RXCSUM | 39654dfc97bSShailend Chand IFCAP_TXCSUM | 39754dfc97bSShailend Chand IFCAP_TXCSUM_IPV6 | 39854dfc97bSShailend Chand IFCAP_TSO | 39954dfc97bSShailend Chand IFCAP_LRO; 40054dfc97bSShailend Chand 40154dfc97bSShailend Chand if ((priv->supported_features & GVE_SUP_JUMBO_FRAMES_MASK) != 0) 40254dfc97bSShailend Chand caps |= IFCAP_JUMBO_MTU; 40354dfc97bSShailend Chand 40454dfc97bSShailend Chand if_setcapabilities(ifp, caps); 40554dfc97bSShailend Chand if_setcapenable(ifp, caps); 40654dfc97bSShailend Chand 40754dfc97bSShailend Chand if (bootverbose) 40854dfc97bSShailend Chand device_printf(priv->dev, "Setting initial MTU to %d\n", priv->max_mtu); 40954dfc97bSShailend Chand if_setmtu(ifp, priv->max_mtu); 41054dfc97bSShailend Chand 41154dfc97bSShailend Chand ether_ifattach(ifp, priv->mac); 41254dfc97bSShailend Chand 41354dfc97bSShailend Chand ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 41454dfc97bSShailend Chand ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 41554dfc97bSShailend Chand } 41654dfc97bSShailend Chand 41754dfc97bSShailend Chand static int 41854dfc97bSShailend Chand gve_alloc_counter_array(struct gve_priv *priv) 41954dfc97bSShailend Chand { 42054dfc97bSShailend Chand int err; 42154dfc97bSShailend Chand 42254dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, sizeof(uint32_t) * priv->num_event_counters, 42354dfc97bSShailend Chand PAGE_SIZE, &priv->counter_array_mem); 42454dfc97bSShailend Chand if (err != 0) 42554dfc97bSShailend Chand return (err); 42654dfc97bSShailend Chand 42754dfc97bSShailend Chand priv->counters = priv->counter_array_mem.cpu_addr; 42854dfc97bSShailend Chand return (0); 42954dfc97bSShailend Chand } 43054dfc97bSShailend Chand 43154dfc97bSShailend Chand static void 43254dfc97bSShailend Chand gve_free_counter_array(struct gve_priv *priv) 43354dfc97bSShailend Chand { 43454dfc97bSShailend Chand if (priv->counters != NULL) 43554dfc97bSShailend Chand gve_dma_free_coherent(&priv->counter_array_mem); 43654dfc97bSShailend Chand priv->counter_array_mem = (struct gve_dma_handle){}; 43754dfc97bSShailend Chand } 43854dfc97bSShailend Chand 43954dfc97bSShailend Chand static int 44054dfc97bSShailend Chand gve_alloc_irq_db_array(struct gve_priv *priv) 44154dfc97bSShailend Chand { 44254dfc97bSShailend Chand int err; 44354dfc97bSShailend Chand 44454dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, 44554dfc97bSShailend Chand sizeof(struct gve_irq_db) * (priv->num_queues), PAGE_SIZE, 44654dfc97bSShailend Chand &priv->irqs_db_mem); 44754dfc97bSShailend Chand if (err != 0) 44854dfc97bSShailend Chand return (err); 44954dfc97bSShailend Chand 45054dfc97bSShailend Chand priv->irq_db_indices = priv->irqs_db_mem.cpu_addr; 45154dfc97bSShailend Chand return (0); 45254dfc97bSShailend Chand } 45354dfc97bSShailend Chand 45454dfc97bSShailend Chand static void 45554dfc97bSShailend Chand gve_free_irq_db_array(struct gve_priv *priv) 45654dfc97bSShailend Chand { 45754dfc97bSShailend Chand if (priv->irq_db_indices != NULL) 45854dfc97bSShailend Chand gve_dma_free_coherent(&priv->irqs_db_mem); 45954dfc97bSShailend Chand priv->irqs_db_mem = (struct gve_dma_handle){}; 46054dfc97bSShailend Chand } 46154dfc97bSShailend Chand 46254dfc97bSShailend Chand static void 46354dfc97bSShailend Chand gve_free_rings(struct gve_priv *priv) 46454dfc97bSShailend Chand { 46554dfc97bSShailend Chand gve_free_irqs(priv); 46654dfc97bSShailend Chand gve_free_tx_rings(priv); 46754dfc97bSShailend Chand gve_free_rx_rings(priv); 468*d438b4efSShailend Chand if (gve_is_gqi(priv)) 46954dfc97bSShailend Chand gve_free_qpls(priv); 47054dfc97bSShailend Chand } 47154dfc97bSShailend Chand 47254dfc97bSShailend Chand static int 47354dfc97bSShailend Chand gve_alloc_rings(struct gve_priv *priv) 47454dfc97bSShailend Chand { 47554dfc97bSShailend Chand int err; 47654dfc97bSShailend Chand 477*d438b4efSShailend Chand if (gve_is_gqi(priv)) { 47854dfc97bSShailend Chand err = gve_alloc_qpls(priv); 47954dfc97bSShailend Chand if (err != 0) 48054dfc97bSShailend Chand goto abort; 481*d438b4efSShailend Chand } 48254dfc97bSShailend Chand 48354dfc97bSShailend Chand err = gve_alloc_rx_rings(priv); 48454dfc97bSShailend Chand if (err != 0) 48554dfc97bSShailend Chand goto abort; 48654dfc97bSShailend Chand 48754dfc97bSShailend Chand err = gve_alloc_tx_rings(priv); 48854dfc97bSShailend Chand if (err != 0) 48954dfc97bSShailend Chand goto abort; 49054dfc97bSShailend Chand 49154dfc97bSShailend Chand err = gve_alloc_irqs(priv); 49254dfc97bSShailend Chand if (err != 0) 49354dfc97bSShailend Chand goto abort; 49454dfc97bSShailend Chand 49554dfc97bSShailend Chand return (0); 49654dfc97bSShailend Chand 49754dfc97bSShailend Chand abort: 49854dfc97bSShailend Chand gve_free_rings(priv); 49954dfc97bSShailend Chand return (err); 50054dfc97bSShailend Chand } 50154dfc97bSShailend Chand 50254dfc97bSShailend Chand static void 50354dfc97bSShailend Chand gve_deconfigure_resources(struct gve_priv *priv) 50454dfc97bSShailend Chand { 50554dfc97bSShailend Chand int err; 50654dfc97bSShailend Chand 50754dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) { 50854dfc97bSShailend Chand err = gve_adminq_deconfigure_device_resources(priv); 50954dfc97bSShailend Chand if (err != 0) { 51054dfc97bSShailend Chand device_printf(priv->dev, "Failed to deconfigure device resources: err=%d\n", 51154dfc97bSShailend Chand err); 51254dfc97bSShailend Chand return; 51354dfc97bSShailend Chand } 51454dfc97bSShailend Chand if (bootverbose) 51554dfc97bSShailend Chand device_printf(priv->dev, "Deconfigured device resources\n"); 51654dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 51754dfc97bSShailend Chand } 51854dfc97bSShailend Chand 51954dfc97bSShailend Chand gve_free_irq_db_array(priv); 52054dfc97bSShailend Chand gve_free_counter_array(priv); 521*d438b4efSShailend Chand 522*d438b4efSShailend Chand if (priv->ptype_lut_dqo) { 523*d438b4efSShailend Chand free(priv->ptype_lut_dqo, M_GVE); 524*d438b4efSShailend Chand priv->ptype_lut_dqo = NULL; 525*d438b4efSShailend Chand } 52654dfc97bSShailend Chand } 52754dfc97bSShailend Chand 52854dfc97bSShailend Chand static int 52954dfc97bSShailend Chand gve_configure_resources(struct gve_priv *priv) 53054dfc97bSShailend Chand { 53154dfc97bSShailend Chand int err; 53254dfc97bSShailend Chand 53354dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) 53454dfc97bSShailend Chand return (0); 53554dfc97bSShailend Chand 53654dfc97bSShailend Chand err = gve_alloc_counter_array(priv); 53754dfc97bSShailend Chand if (err != 0) 53854dfc97bSShailend Chand return (err); 53954dfc97bSShailend Chand 54054dfc97bSShailend Chand err = gve_alloc_irq_db_array(priv); 54154dfc97bSShailend Chand if (err != 0) 54254dfc97bSShailend Chand goto abort; 54354dfc97bSShailend Chand 54454dfc97bSShailend Chand err = gve_adminq_configure_device_resources(priv); 54554dfc97bSShailend Chand if (err != 0) { 54654dfc97bSShailend Chand device_printf(priv->dev, "Failed to configure device resources: err=%d\n", 54754dfc97bSShailend Chand err); 54854dfc97bSShailend Chand err = (ENXIO); 54954dfc97bSShailend Chand goto abort; 55054dfc97bSShailend Chand } 55154dfc97bSShailend Chand 552*d438b4efSShailend Chand if (!gve_is_gqi(priv)) { 553*d438b4efSShailend Chand priv->ptype_lut_dqo = malloc(sizeof(*priv->ptype_lut_dqo), M_GVE, 554*d438b4efSShailend Chand M_WAITOK | M_ZERO); 555*d438b4efSShailend Chand 556*d438b4efSShailend Chand err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo); 557*d438b4efSShailend Chand if (err != 0) { 558*d438b4efSShailend Chand device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n", 559*d438b4efSShailend Chand err); 560*d438b4efSShailend Chand goto abort; 561*d438b4efSShailend Chand } 562*d438b4efSShailend Chand } 563*d438b4efSShailend Chand 56454dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 56554dfc97bSShailend Chand if (bootverbose) 56654dfc97bSShailend Chand device_printf(priv->dev, "Configured device resources\n"); 56754dfc97bSShailend Chand return (0); 56854dfc97bSShailend Chand 56954dfc97bSShailend Chand abort: 57054dfc97bSShailend Chand gve_deconfigure_resources(priv); 57154dfc97bSShailend Chand return (err); 57254dfc97bSShailend Chand } 57354dfc97bSShailend Chand 57454dfc97bSShailend Chand static void 57554dfc97bSShailend Chand gve_set_queue_cnts(struct gve_priv *priv) 57654dfc97bSShailend Chand { 57754dfc97bSShailend Chand priv->tx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_TX_QUEUES); 57854dfc97bSShailend Chand priv->rx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_RX_QUEUES); 57954dfc97bSShailend Chand priv->tx_cfg.num_queues = priv->tx_cfg.max_queues; 58054dfc97bSShailend Chand priv->rx_cfg.num_queues = priv->rx_cfg.max_queues; 58154dfc97bSShailend Chand 58254dfc97bSShailend Chand if (priv->default_num_queues > 0) { 58354dfc97bSShailend Chand priv->tx_cfg.num_queues = MIN(priv->default_num_queues, 58454dfc97bSShailend Chand priv->tx_cfg.num_queues); 58554dfc97bSShailend Chand priv->rx_cfg.num_queues = MIN(priv->default_num_queues, 58654dfc97bSShailend Chand priv->rx_cfg.num_queues); 58754dfc97bSShailend Chand } 58854dfc97bSShailend Chand 58954dfc97bSShailend Chand priv->num_queues = priv->tx_cfg.num_queues + priv->rx_cfg.num_queues; 59054dfc97bSShailend Chand priv->mgmt_msix_idx = priv->num_queues; 59154dfc97bSShailend Chand } 59254dfc97bSShailend Chand 59354dfc97bSShailend Chand static int 59454dfc97bSShailend Chand gve_alloc_adminq_and_describe_device(struct gve_priv *priv) 59554dfc97bSShailend Chand { 59654dfc97bSShailend Chand int err; 59754dfc97bSShailend Chand 59854dfc97bSShailend Chand if ((err = gve_adminq_alloc(priv)) != 0) 59954dfc97bSShailend Chand return (err); 60054dfc97bSShailend Chand 60154dfc97bSShailend Chand if ((err = gve_verify_driver_compatibility(priv)) != 0) { 60254dfc97bSShailend Chand device_printf(priv->dev, 60354dfc97bSShailend Chand "Failed to verify driver compatibility: err=%d\n", err); 60454dfc97bSShailend Chand goto abort; 60554dfc97bSShailend Chand } 60654dfc97bSShailend Chand 60754dfc97bSShailend Chand if ((err = gve_adminq_describe_device(priv)) != 0) 60854dfc97bSShailend Chand goto abort; 60954dfc97bSShailend Chand 61054dfc97bSShailend Chand gve_set_queue_cnts(priv); 61154dfc97bSShailend Chand 61254dfc97bSShailend Chand priv->num_registered_pages = 0; 61354dfc97bSShailend Chand return (0); 61454dfc97bSShailend Chand 61554dfc97bSShailend Chand abort: 61654dfc97bSShailend Chand gve_release_adminq(priv); 61754dfc97bSShailend Chand return (err); 61854dfc97bSShailend Chand } 61954dfc97bSShailend Chand 62054dfc97bSShailend Chand void 62154dfc97bSShailend Chand gve_schedule_reset(struct gve_priv *priv) 62254dfc97bSShailend Chand { 62354dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) 62454dfc97bSShailend Chand return; 62554dfc97bSShailend Chand 62654dfc97bSShailend Chand device_printf(priv->dev, "Scheduling reset task!\n"); 62754dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 62854dfc97bSShailend Chand taskqueue_enqueue(priv->service_tq, &priv->service_task); 62954dfc97bSShailend Chand } 63054dfc97bSShailend Chand 63154dfc97bSShailend Chand static void 63254dfc97bSShailend Chand gve_destroy(struct gve_priv *priv) 63354dfc97bSShailend Chand { 63454dfc97bSShailend Chand gve_down(priv); 63554dfc97bSShailend Chand gve_deconfigure_resources(priv); 63654dfc97bSShailend Chand gve_release_adminq(priv); 63754dfc97bSShailend Chand } 63854dfc97bSShailend Chand 63954dfc97bSShailend Chand static void 64054dfc97bSShailend Chand gve_restore(struct gve_priv *priv) 64154dfc97bSShailend Chand { 64254dfc97bSShailend Chand int err; 64354dfc97bSShailend Chand 64454dfc97bSShailend Chand err = gve_adminq_alloc(priv); 64554dfc97bSShailend Chand if (err != 0) 64654dfc97bSShailend Chand goto abort; 64754dfc97bSShailend Chand 64854dfc97bSShailend Chand err = gve_configure_resources(priv); 64954dfc97bSShailend Chand if (err != 0) 65054dfc97bSShailend Chand goto abort; 65154dfc97bSShailend Chand 65254dfc97bSShailend Chand err = gve_up(priv); 65354dfc97bSShailend Chand if (err != 0) 65454dfc97bSShailend Chand goto abort; 65554dfc97bSShailend Chand 65654dfc97bSShailend Chand return; 65754dfc97bSShailend Chand 65854dfc97bSShailend Chand abort: 65954dfc97bSShailend Chand device_printf(priv->dev, "Restore failed!\n"); 66054dfc97bSShailend Chand return; 66154dfc97bSShailend Chand } 66254dfc97bSShailend Chand 66354dfc97bSShailend Chand static void 66454dfc97bSShailend Chand gve_handle_reset(struct gve_priv *priv) 66554dfc97bSShailend Chand { 66654dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_DO_RESET)) 66754dfc97bSShailend Chand return; 66854dfc97bSShailend Chand 66954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 67054dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 67154dfc97bSShailend Chand 67254dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 67354dfc97bSShailend Chand 67454dfc97bSShailend Chand if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 67554dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 67654dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 67754dfc97bSShailend Chand 67854dfc97bSShailend Chand /* 67954dfc97bSShailend Chand * Releasing the adminq causes the NIC to destroy all resources 68054dfc97bSShailend Chand * registered with it, so by clearing the flags beneath we cause 68154dfc97bSShailend Chand * the subsequent gve_down call below to not attempt to tell the 68254dfc97bSShailend Chand * NIC to destroy these resources again. 68354dfc97bSShailend Chand * 68454dfc97bSShailend Chand * The call to gve_down is needed in the first place to refresh 68554dfc97bSShailend Chand * the state and the DMA-able memory within each driver ring. 68654dfc97bSShailend Chand */ 68754dfc97bSShailend Chand gve_release_adminq(priv); 68854dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 68954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK); 69054dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RX_RINGS_OK); 69154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_TX_RINGS_OK); 69254dfc97bSShailend Chand 69354dfc97bSShailend Chand gve_down(priv); 69454dfc97bSShailend Chand gve_restore(priv); 69554dfc97bSShailend Chand 69654dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 69754dfc97bSShailend Chand 69854dfc97bSShailend Chand priv->reset_cnt++; 69954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 70054dfc97bSShailend Chand } 70154dfc97bSShailend Chand 70254dfc97bSShailend Chand static void 70354dfc97bSShailend Chand gve_handle_link_status(struct gve_priv *priv) 70454dfc97bSShailend Chand { 70554dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 70654dfc97bSShailend Chand bool link_up = status & GVE_DEVICE_STATUS_LINK_STATUS; 70754dfc97bSShailend Chand 70854dfc97bSShailend Chand if (link_up == gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) 70954dfc97bSShailend Chand return; 71054dfc97bSShailend Chand 71154dfc97bSShailend Chand if (link_up) { 71254dfc97bSShailend Chand if (bootverbose) 71354dfc97bSShailend Chand device_printf(priv->dev, "Device link is up.\n"); 71454dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_UP); 71554dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 71654dfc97bSShailend Chand } else { 71754dfc97bSShailend Chand device_printf(priv->dev, "Device link is down.\n"); 71854dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 71954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 72054dfc97bSShailend Chand } 72154dfc97bSShailend Chand } 72254dfc97bSShailend Chand 72354dfc97bSShailend Chand static void 72454dfc97bSShailend Chand gve_service_task(void *arg, int pending) 72554dfc97bSShailend Chand { 72654dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 72754dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 72854dfc97bSShailend Chand 72954dfc97bSShailend Chand if (((GVE_DEVICE_STATUS_RESET_MASK & status) != 0) && 73054dfc97bSShailend Chand !gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) { 73154dfc97bSShailend Chand device_printf(priv->dev, "Device requested reset\n"); 73254dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 73354dfc97bSShailend Chand } 73454dfc97bSShailend Chand 73554dfc97bSShailend Chand gve_handle_reset(priv); 73654dfc97bSShailend Chand gve_handle_link_status(priv); 73754dfc97bSShailend Chand } 73854dfc97bSShailend Chand 73954dfc97bSShailend Chand static int 74054dfc97bSShailend Chand gve_probe(device_t dev) 74154dfc97bSShailend Chand { 7421bbdfb0bSXin LI uint16_t deviceid, vendorid; 7431bbdfb0bSXin LI int i; 7441bbdfb0bSXin LI 7451bbdfb0bSXin LI vendorid = pci_get_vendor(dev); 7461bbdfb0bSXin LI deviceid = pci_get_device(dev); 7471bbdfb0bSXin LI 7481177a6c8SXin LI for (i = 0; i < nitems(gve_devs); i++) { 7491bbdfb0bSXin LI if (vendorid == gve_devs[i].vendor_id && 7501bbdfb0bSXin LI deviceid == gve_devs[i].device_id) { 7511bbdfb0bSXin LI device_set_desc(dev, gve_devs[i].name); 75254dfc97bSShailend Chand return (BUS_PROBE_DEFAULT); 75354dfc97bSShailend Chand } 7541bbdfb0bSXin LI } 75554dfc97bSShailend Chand return (ENXIO); 75654dfc97bSShailend Chand } 75754dfc97bSShailend Chand 75854dfc97bSShailend Chand static void 75954dfc97bSShailend Chand gve_free_sys_res_mem(struct gve_priv *priv) 76054dfc97bSShailend Chand { 76154dfc97bSShailend Chand if (priv->msix_table != NULL) 76254dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 76354dfc97bSShailend Chand rman_get_rid(priv->msix_table), priv->msix_table); 76454dfc97bSShailend Chand 76554dfc97bSShailend Chand if (priv->db_bar != NULL) 76654dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 76754dfc97bSShailend Chand rman_get_rid(priv->db_bar), priv->db_bar); 76854dfc97bSShailend Chand 76954dfc97bSShailend Chand if (priv->reg_bar != NULL) 77054dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 77154dfc97bSShailend Chand rman_get_rid(priv->reg_bar), priv->reg_bar); 77254dfc97bSShailend Chand } 77354dfc97bSShailend Chand 77454dfc97bSShailend Chand static int 77554dfc97bSShailend Chand gve_attach(device_t dev) 77654dfc97bSShailend Chand { 77754dfc97bSShailend Chand struct gve_priv *priv; 77854dfc97bSShailend Chand int rid; 77954dfc97bSShailend Chand int err; 78054dfc97bSShailend Chand 781*d438b4efSShailend Chand snprintf(gve_version, sizeof(gve_version), "%d.%d.%d", 782*d438b4efSShailend Chand GVE_VERSION_MAJOR, GVE_VERSION_MINOR, GVE_VERSION_SUB); 783*d438b4efSShailend Chand 78454dfc97bSShailend Chand priv = device_get_softc(dev); 78554dfc97bSShailend Chand priv->dev = dev; 78654dfc97bSShailend Chand GVE_IFACE_LOCK_INIT(priv->gve_iface_lock); 78754dfc97bSShailend Chand 78854dfc97bSShailend Chand pci_enable_busmaster(dev); 78954dfc97bSShailend Chand 79054dfc97bSShailend Chand rid = PCIR_BAR(GVE_REGISTER_BAR); 79154dfc97bSShailend Chand priv->reg_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 79254dfc97bSShailend Chand &rid, RF_ACTIVE); 79354dfc97bSShailend Chand if (priv->reg_bar == NULL) { 79454dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR0\n"); 79554dfc97bSShailend Chand err = ENXIO; 79654dfc97bSShailend Chand goto abort; 79754dfc97bSShailend Chand } 79854dfc97bSShailend Chand 79954dfc97bSShailend Chand rid = PCIR_BAR(GVE_DOORBELL_BAR); 80054dfc97bSShailend Chand priv->db_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 80154dfc97bSShailend Chand &rid, RF_ACTIVE); 80254dfc97bSShailend Chand if (priv->db_bar == NULL) { 80354dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR2\n"); 80454dfc97bSShailend Chand err = ENXIO; 80554dfc97bSShailend Chand goto abort; 80654dfc97bSShailend Chand } 80754dfc97bSShailend Chand 80854dfc97bSShailend Chand rid = pci_msix_table_bar(priv->dev); 80954dfc97bSShailend Chand priv->msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 81054dfc97bSShailend Chand &rid, RF_ACTIVE); 81154dfc97bSShailend Chand if (priv->msix_table == NULL) { 81254dfc97bSShailend Chand device_printf(dev, "Failed to allocate msix table\n"); 81354dfc97bSShailend Chand err = ENXIO; 81454dfc97bSShailend Chand goto abort; 81554dfc97bSShailend Chand } 81654dfc97bSShailend Chand 81754dfc97bSShailend Chand err = gve_alloc_adminq_and_describe_device(priv); 81854dfc97bSShailend Chand if (err != 0) 81954dfc97bSShailend Chand goto abort; 82054dfc97bSShailend Chand 82154dfc97bSShailend Chand err = gve_configure_resources(priv); 82254dfc97bSShailend Chand if (err != 0) 82354dfc97bSShailend Chand goto abort; 82454dfc97bSShailend Chand 82554dfc97bSShailend Chand err = gve_alloc_rings(priv); 82654dfc97bSShailend Chand if (err != 0) 82754dfc97bSShailend Chand goto abort; 82854dfc97bSShailend Chand 829aa386085SZhenlei Huang gve_setup_ifnet(dev, priv); 83054dfc97bSShailend Chand 83154dfc97bSShailend Chand priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; 83254dfc97bSShailend Chand 83354dfc97bSShailend Chand bus_write_multi_1(priv->reg_bar, DRIVER_VERSION, GVE_DRIVER_VERSION, 83454dfc97bSShailend Chand sizeof(GVE_DRIVER_VERSION) - 1); 83554dfc97bSShailend Chand 83654dfc97bSShailend Chand TASK_INIT(&priv->service_task, 0, gve_service_task, priv); 83754dfc97bSShailend Chand priv->service_tq = taskqueue_create("gve service", M_WAITOK | M_ZERO, 83854dfc97bSShailend Chand taskqueue_thread_enqueue, &priv->service_tq); 83954dfc97bSShailend Chand taskqueue_start_threads(&priv->service_tq, 1, PI_NET, "%s service tq", 84054dfc97bSShailend Chand device_get_nameunit(priv->dev)); 84154dfc97bSShailend Chand 84254dfc97bSShailend Chand gve_setup_sysctl(priv); 84354dfc97bSShailend Chand 84454dfc97bSShailend Chand if (bootverbose) 84554dfc97bSShailend Chand device_printf(priv->dev, "Successfully attached %s", GVE_DRIVER_VERSION); 84654dfc97bSShailend Chand return (0); 84754dfc97bSShailend Chand 84854dfc97bSShailend Chand abort: 84954dfc97bSShailend Chand gve_free_rings(priv); 85054dfc97bSShailend Chand gve_deconfigure_resources(priv); 85154dfc97bSShailend Chand gve_release_adminq(priv); 85254dfc97bSShailend Chand gve_free_sys_res_mem(priv); 85354dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 85454dfc97bSShailend Chand return (err); 85554dfc97bSShailend Chand } 85654dfc97bSShailend Chand 85754dfc97bSShailend Chand static int 85854dfc97bSShailend Chand gve_detach(device_t dev) 85954dfc97bSShailend Chand { 86054dfc97bSShailend Chand struct gve_priv *priv = device_get_softc(dev); 86154dfc97bSShailend Chand if_t ifp = priv->ifp; 862d412c076SJohn Baldwin int error; 863d412c076SJohn Baldwin 864d412c076SJohn Baldwin error = bus_generic_detach(dev); 865d412c076SJohn Baldwin if (error != 0) 866d412c076SJohn Baldwin return (error); 86754dfc97bSShailend Chand 86854dfc97bSShailend Chand ether_ifdetach(ifp); 86954dfc97bSShailend Chand 87054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 87154dfc97bSShailend Chand gve_destroy(priv); 87254dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 87354dfc97bSShailend Chand 87454dfc97bSShailend Chand gve_free_rings(priv); 87554dfc97bSShailend Chand gve_free_sys_res_mem(priv); 87654dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 87754dfc97bSShailend Chand 87854dfc97bSShailend Chand while (taskqueue_cancel(priv->service_tq, &priv->service_task, NULL)) 87954dfc97bSShailend Chand taskqueue_drain(priv->service_tq, &priv->service_task); 88054dfc97bSShailend Chand taskqueue_free(priv->service_tq); 88154dfc97bSShailend Chand 88254dfc97bSShailend Chand if_free(ifp); 883d412c076SJohn Baldwin return (0); 88454dfc97bSShailend Chand } 88554dfc97bSShailend Chand 88654dfc97bSShailend Chand static device_method_t gve_methods[] = { 88754dfc97bSShailend Chand DEVMETHOD(device_probe, gve_probe), 88854dfc97bSShailend Chand DEVMETHOD(device_attach, gve_attach), 88954dfc97bSShailend Chand DEVMETHOD(device_detach, gve_detach), 89054dfc97bSShailend Chand DEVMETHOD_END 89154dfc97bSShailend Chand }; 89254dfc97bSShailend Chand 89354dfc97bSShailend Chand static driver_t gve_driver = { 89454dfc97bSShailend Chand "gve", 89554dfc97bSShailend Chand gve_methods, 89654dfc97bSShailend Chand sizeof(struct gve_priv) 89754dfc97bSShailend Chand }; 89854dfc97bSShailend Chand 89954dfc97bSShailend Chand #if __FreeBSD_version < 1301503 90054dfc97bSShailend Chand static devclass_t gve_devclass; 90154dfc97bSShailend Chand 90254dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, gve_devclass, 0, 0); 90354dfc97bSShailend Chand #else 90454dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, 0, 0); 90554dfc97bSShailend Chand #endif 9061177a6c8SXin LI MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, gve, gve_devs, 9071177a6c8SXin LI nitems(gve_devs)); 908