154dfc97bSShailend Chand /*- 254dfc97bSShailend Chand * SPDX-License-Identifier: BSD-3-Clause 354dfc97bSShailend Chand * 454dfc97bSShailend Chand * Copyright (c) 2023 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" 3354dfc97bSShailend Chand 3454dfc97bSShailend Chand #define GVE_DRIVER_VERSION "GVE-FBSD-1.0.0\n" 3554dfc97bSShailend Chand #define GVE_VERSION_MAJOR 0 3654dfc97bSShailend Chand #define GVE_VERSION_MINOR 9 3754dfc97bSShailend Chand #define GVE_VERSION_SUB 0 3854dfc97bSShailend Chand 3954dfc97bSShailend Chand #define GVE_DEFAULT_RX_COPYBREAK 256 4054dfc97bSShailend Chand 411bbdfb0bSXin LI /* Devices supported by this driver. */ 421bbdfb0bSXin LI static struct gve_dev { 431bbdfb0bSXin LI uint16_t vendor_id; 441bbdfb0bSXin LI uint16_t device_id; 451bbdfb0bSXin LI const char *name; 461bbdfb0bSXin LI } gve_devs[] = { 471bbdfb0bSXin LI { PCI_VENDOR_ID_GOOGLE, PCI_DEV_ID_GVNIC, "gVNIC" } 481bbdfb0bSXin LI }; 491bbdfb0bSXin LI 5054dfc97bSShailend Chand struct sx gve_global_lock; 5154dfc97bSShailend Chand 5254dfc97bSShailend Chand static int 5354dfc97bSShailend Chand gve_verify_driver_compatibility(struct gve_priv *priv) 5454dfc97bSShailend Chand { 5554dfc97bSShailend Chand int err; 5654dfc97bSShailend Chand struct gve_driver_info *driver_info; 5754dfc97bSShailend Chand struct gve_dma_handle driver_info_mem; 5854dfc97bSShailend Chand 5954dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, sizeof(struct gve_driver_info), 6054dfc97bSShailend Chand PAGE_SIZE, &driver_info_mem); 6154dfc97bSShailend Chand 6254dfc97bSShailend Chand if (err != 0) 6354dfc97bSShailend Chand return (ENOMEM); 6454dfc97bSShailend Chand 6554dfc97bSShailend Chand driver_info = driver_info_mem.cpu_addr; 6654dfc97bSShailend Chand 6754dfc97bSShailend Chand *driver_info = (struct gve_driver_info) { 6854dfc97bSShailend Chand .os_type = 3, /* Freebsd */ 6954dfc97bSShailend Chand .driver_major = GVE_VERSION_MAJOR, 7054dfc97bSShailend Chand .driver_minor = GVE_VERSION_MINOR, 7154dfc97bSShailend Chand .driver_sub = GVE_VERSION_SUB, 7254dfc97bSShailend Chand .os_version_major = htobe32(FBSD_VERSION_MAJOR), 7354dfc97bSShailend Chand .os_version_minor = htobe32(FBSD_VERSION_MINOR), 7454dfc97bSShailend Chand .os_version_sub = htobe32(FBSD_VERSION_PATCH), 7554dfc97bSShailend Chand .driver_capability_flags = { 7654dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS1), 7754dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS2), 7854dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS3), 7954dfc97bSShailend Chand htobe64(GVE_DRIVER_CAPABILITY_FLAGS4), 8054dfc97bSShailend Chand }, 8154dfc97bSShailend Chand }; 8254dfc97bSShailend Chand 8354dfc97bSShailend Chand snprintf(driver_info->os_version_str1, sizeof(driver_info->os_version_str1), 8454dfc97bSShailend Chand "FreeBSD %u", __FreeBSD_version); 8554dfc97bSShailend Chand 8654dfc97bSShailend Chand bus_dmamap_sync(driver_info_mem.tag, driver_info_mem.map, 8754dfc97bSShailend Chand BUS_DMASYNC_PREREAD); 8854dfc97bSShailend Chand 8954dfc97bSShailend Chand err = gve_adminq_verify_driver_compatibility(priv, 9054dfc97bSShailend Chand sizeof(struct gve_driver_info), driver_info_mem.bus_addr); 9154dfc97bSShailend Chand 9254dfc97bSShailend Chand /* It's ok if the device doesn't support this */ 9354dfc97bSShailend Chand if (err == EOPNOTSUPP) 9454dfc97bSShailend Chand err = 0; 9554dfc97bSShailend Chand 9654dfc97bSShailend Chand gve_dma_free_coherent(&driver_info_mem); 9754dfc97bSShailend Chand 9854dfc97bSShailend Chand return (err); 9954dfc97bSShailend Chand } 10054dfc97bSShailend Chand 10154dfc97bSShailend Chand static int 10254dfc97bSShailend Chand gve_up(struct gve_priv *priv) 10354dfc97bSShailend Chand { 10454dfc97bSShailend Chand if_t ifp = priv->ifp; 10554dfc97bSShailend Chand int err; 10654dfc97bSShailend Chand 10754dfc97bSShailend Chand GVE_IFACE_LOCK_ASSERT(priv->gve_iface_lock); 10854dfc97bSShailend Chand 10954dfc97bSShailend Chand if (device_is_attached(priv->dev) == 0) { 11054dfc97bSShailend Chand device_printf(priv->dev, "Cannot bring the iface up when detached\n"); 11154dfc97bSShailend Chand return (ENXIO); 11254dfc97bSShailend Chand } 11354dfc97bSShailend Chand 11454dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) 11554dfc97bSShailend Chand return (0); 11654dfc97bSShailend Chand 11754dfc97bSShailend Chand if_clearhwassist(ifp); 11854dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TXCSUM) 11954dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_TCP | CSUM_UDP, 0); 12054dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6) 12154dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_IP6_TCP | CSUM_IP6_UDP, 0); 12254dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TSO4) 12354dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_IP_TSO, 0); 12454dfc97bSShailend Chand if (if_getcapenable(ifp) & IFCAP_TSO6) 12554dfc97bSShailend Chand if_sethwassistbits(ifp, CSUM_IP6_TSO, 0); 12654dfc97bSShailend Chand 12754dfc97bSShailend Chand err = gve_register_qpls(priv); 12854dfc97bSShailend Chand if (err != 0) 12954dfc97bSShailend Chand goto reset; 13054dfc97bSShailend Chand 13154dfc97bSShailend Chand err = gve_create_rx_rings(priv); 13254dfc97bSShailend Chand if (err != 0) 13354dfc97bSShailend Chand goto reset; 13454dfc97bSShailend Chand 13554dfc97bSShailend Chand err = gve_create_tx_rings(priv); 13654dfc97bSShailend Chand if (err != 0) 13754dfc97bSShailend Chand goto reset; 13854dfc97bSShailend Chand 13954dfc97bSShailend Chand if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 14054dfc97bSShailend Chand 14154dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 14254dfc97bSShailend Chand if_link_state_change(ifp, LINK_STATE_UP); 14354dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 14454dfc97bSShailend Chand } 14554dfc97bSShailend Chand 14654dfc97bSShailend Chand gve_unmask_all_queue_irqs(priv); 14754dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP); 14854dfc97bSShailend Chand priv->interface_up_cnt++; 14954dfc97bSShailend Chand return (0); 15054dfc97bSShailend Chand 15154dfc97bSShailend Chand reset: 15254dfc97bSShailend Chand gve_schedule_reset(priv); 15354dfc97bSShailend Chand return (err); 15454dfc97bSShailend Chand } 15554dfc97bSShailend Chand 15654dfc97bSShailend Chand static void 15754dfc97bSShailend Chand gve_down(struct gve_priv *priv) 15854dfc97bSShailend Chand { 15954dfc97bSShailend Chand GVE_IFACE_LOCK_ASSERT(priv->gve_iface_lock); 16054dfc97bSShailend Chand 16154dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) 16254dfc97bSShailend Chand return; 16354dfc97bSShailend Chand 16454dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 16554dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 16654dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 16754dfc97bSShailend Chand } 16854dfc97bSShailend Chand 16954dfc97bSShailend Chand if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 17054dfc97bSShailend Chand 17154dfc97bSShailend Chand if (gve_destroy_rx_rings(priv) != 0) 17254dfc97bSShailend Chand goto reset; 17354dfc97bSShailend Chand 17454dfc97bSShailend Chand if (gve_destroy_tx_rings(priv) != 0) 17554dfc97bSShailend Chand goto reset; 17654dfc97bSShailend Chand 17754dfc97bSShailend Chand if (gve_unregister_qpls(priv) != 0) 17854dfc97bSShailend Chand goto reset; 17954dfc97bSShailend Chand 18054dfc97bSShailend Chand gve_mask_all_queue_irqs(priv); 18154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP); 18254dfc97bSShailend Chand priv->interface_down_cnt++; 18354dfc97bSShailend Chand return; 18454dfc97bSShailend Chand 18554dfc97bSShailend Chand reset: 18654dfc97bSShailend Chand gve_schedule_reset(priv); 18754dfc97bSShailend Chand } 18854dfc97bSShailend Chand 18954dfc97bSShailend Chand static int 19054dfc97bSShailend Chand gve_set_mtu(if_t ifp, uint32_t new_mtu) 19154dfc97bSShailend Chand { 19254dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 19354dfc97bSShailend Chand int err; 19454dfc97bSShailend Chand 19554dfc97bSShailend Chand if ((new_mtu > priv->max_mtu) || (new_mtu < ETHERMIN)) { 19654dfc97bSShailend Chand device_printf(priv->dev, "Invalid new MTU setting. new mtu: %d max mtu: %d min mtu: %d\n", 19754dfc97bSShailend Chand new_mtu, priv->max_mtu, ETHERMIN); 19854dfc97bSShailend Chand return (EINVAL); 19954dfc97bSShailend Chand } 20054dfc97bSShailend Chand 20154dfc97bSShailend Chand err = gve_adminq_set_mtu(priv, new_mtu); 20254dfc97bSShailend Chand if (err == 0) { 20354dfc97bSShailend Chand if (bootverbose) 20454dfc97bSShailend Chand device_printf(priv->dev, "MTU set to %d\n", new_mtu); 20554dfc97bSShailend Chand if_setmtu(ifp, new_mtu); 20654dfc97bSShailend Chand } else { 20754dfc97bSShailend Chand device_printf(priv->dev, "Failed to set MTU to %d\n", new_mtu); 20854dfc97bSShailend Chand } 20954dfc97bSShailend Chand 21054dfc97bSShailend Chand return (err); 21154dfc97bSShailend Chand } 21254dfc97bSShailend Chand 21354dfc97bSShailend Chand static void 21454dfc97bSShailend Chand gve_init(void *arg) 21554dfc97bSShailend Chand { 21654dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 21754dfc97bSShailend Chand 21854dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) { 21954dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 22054dfc97bSShailend Chand gve_up(priv); 22154dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 22254dfc97bSShailend Chand } 22354dfc97bSShailend Chand } 22454dfc97bSShailend Chand 22554dfc97bSShailend Chand static int 22654dfc97bSShailend Chand gve_ioctl(if_t ifp, u_long command, caddr_t data) 22754dfc97bSShailend Chand { 22854dfc97bSShailend Chand struct gve_priv *priv; 22954dfc97bSShailend Chand struct ifreq *ifr; 23054dfc97bSShailend Chand int rc = 0; 23154dfc97bSShailend Chand 23254dfc97bSShailend Chand priv = if_getsoftc(ifp); 23354dfc97bSShailend Chand ifr = (struct ifreq *)data; 23454dfc97bSShailend Chand 23554dfc97bSShailend Chand switch (command) { 23654dfc97bSShailend Chand case SIOCSIFMTU: 23754dfc97bSShailend Chand if (if_getmtu(ifp) == ifr->ifr_mtu) 23854dfc97bSShailend Chand break; 23954dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 24054dfc97bSShailend Chand gve_down(priv); 24154dfc97bSShailend Chand gve_set_mtu(ifp, ifr->ifr_mtu); 24254dfc97bSShailend Chand rc = gve_up(priv); 24354dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 24454dfc97bSShailend Chand break; 24554dfc97bSShailend Chand 24654dfc97bSShailend Chand case SIOCSIFFLAGS: 24754dfc97bSShailend Chand if ((if_getflags(ifp) & IFF_UP) != 0) { 24854dfc97bSShailend Chand if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 24954dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 25054dfc97bSShailend Chand rc = gve_up(priv); 25154dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 25254dfc97bSShailend Chand } 25354dfc97bSShailend Chand } else { 25454dfc97bSShailend Chand if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 25554dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 25654dfc97bSShailend Chand gve_down(priv); 25754dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 25854dfc97bSShailend Chand } 25954dfc97bSShailend Chand } 26054dfc97bSShailend Chand break; 26154dfc97bSShailend Chand 26254dfc97bSShailend Chand case SIOCSIFCAP: 26354dfc97bSShailend Chand if (ifr->ifr_reqcap == if_getcapenable(ifp)) 26454dfc97bSShailend Chand break; 26554dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 26654dfc97bSShailend Chand gve_down(priv); 26754dfc97bSShailend Chand if_setcapenable(ifp, ifr->ifr_reqcap); 26854dfc97bSShailend Chand rc = gve_up(priv); 26954dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 27054dfc97bSShailend Chand break; 27154dfc97bSShailend Chand 27254dfc97bSShailend Chand case SIOCSIFMEDIA: 27354dfc97bSShailend Chand /* FALLTHROUGH */ 27454dfc97bSShailend Chand case SIOCGIFMEDIA: 27554dfc97bSShailend Chand rc = ifmedia_ioctl(ifp, ifr, &priv->media, command); 27654dfc97bSShailend Chand break; 27754dfc97bSShailend Chand 27854dfc97bSShailend Chand default: 27954dfc97bSShailend Chand rc = ether_ioctl(ifp, command, data); 28054dfc97bSShailend Chand break; 28154dfc97bSShailend Chand } 28254dfc97bSShailend Chand 28354dfc97bSShailend Chand return (rc); 28454dfc97bSShailend Chand } 28554dfc97bSShailend Chand 28654dfc97bSShailend Chand static int 28754dfc97bSShailend Chand gve_media_change(if_t ifp) 28854dfc97bSShailend Chand { 28954dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 29054dfc97bSShailend Chand 29154dfc97bSShailend Chand device_printf(priv->dev, "Media change not supported\n"); 29254dfc97bSShailend Chand return (0); 29354dfc97bSShailend Chand } 29454dfc97bSShailend Chand 29554dfc97bSShailend Chand static void 29654dfc97bSShailend Chand gve_media_status(if_t ifp, struct ifmediareq *ifmr) 29754dfc97bSShailend Chand { 29854dfc97bSShailend Chand struct gve_priv *priv = if_getsoftc(ifp); 29954dfc97bSShailend Chand 30054dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 30154dfc97bSShailend Chand 30254dfc97bSShailend Chand ifmr->ifm_status = IFM_AVALID; 30354dfc97bSShailend Chand ifmr->ifm_active = IFM_ETHER; 30454dfc97bSShailend Chand 30554dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) { 30654dfc97bSShailend Chand ifmr->ifm_status |= IFM_ACTIVE; 30754dfc97bSShailend Chand ifmr->ifm_active |= IFM_AUTO; 30854dfc97bSShailend Chand } else { 30954dfc97bSShailend Chand ifmr->ifm_active |= IFM_NONE; 31054dfc97bSShailend Chand } 31154dfc97bSShailend Chand 31254dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 31354dfc97bSShailend Chand } 31454dfc97bSShailend Chand 31554dfc97bSShailend Chand static uint64_t 31654dfc97bSShailend Chand gve_get_counter(if_t ifp, ift_counter cnt) 31754dfc97bSShailend Chand { 31854dfc97bSShailend Chand struct gve_priv *priv; 31954dfc97bSShailend Chand uint64_t rpackets = 0; 32054dfc97bSShailend Chand uint64_t tpackets = 0; 32154dfc97bSShailend Chand uint64_t rbytes = 0; 32254dfc97bSShailend Chand uint64_t tbytes = 0; 32354dfc97bSShailend Chand uint64_t rx_dropped_pkt = 0; 32454dfc97bSShailend Chand uint64_t tx_dropped_pkt = 0; 32554dfc97bSShailend Chand 32654dfc97bSShailend Chand priv = if_getsoftc(ifp); 32754dfc97bSShailend Chand 32854dfc97bSShailend Chand gve_accum_stats(priv, &rpackets, &rbytes, &rx_dropped_pkt, &tpackets, 32954dfc97bSShailend Chand &tbytes, &tx_dropped_pkt); 33054dfc97bSShailend Chand 33154dfc97bSShailend Chand switch (cnt) { 33254dfc97bSShailend Chand case IFCOUNTER_IPACKETS: 33354dfc97bSShailend Chand return (rpackets); 33454dfc97bSShailend Chand 33554dfc97bSShailend Chand case IFCOUNTER_OPACKETS: 33654dfc97bSShailend Chand return (tpackets); 33754dfc97bSShailend Chand 33854dfc97bSShailend Chand case IFCOUNTER_IBYTES: 33954dfc97bSShailend Chand return (rbytes); 34054dfc97bSShailend Chand 34154dfc97bSShailend Chand case IFCOUNTER_OBYTES: 34254dfc97bSShailend Chand return (tbytes); 34354dfc97bSShailend Chand 34454dfc97bSShailend Chand case IFCOUNTER_IQDROPS: 34554dfc97bSShailend Chand return (rx_dropped_pkt); 34654dfc97bSShailend Chand 34754dfc97bSShailend Chand case IFCOUNTER_OQDROPS: 34854dfc97bSShailend Chand return (tx_dropped_pkt); 34954dfc97bSShailend Chand 35054dfc97bSShailend Chand default: 35154dfc97bSShailend Chand return (if_get_counter_default(ifp, cnt)); 35254dfc97bSShailend Chand } 35354dfc97bSShailend Chand } 35454dfc97bSShailend Chand 35554dfc97bSShailend Chand static int 35654dfc97bSShailend Chand gve_setup_ifnet(device_t dev, struct gve_priv *priv) 35754dfc97bSShailend Chand { 35854dfc97bSShailend Chand int caps = 0; 35954dfc97bSShailend Chand if_t ifp; 36054dfc97bSShailend Chand 36154dfc97bSShailend Chand ifp = priv->ifp = if_alloc(IFT_ETHER); 36254dfc97bSShailend Chand if (ifp == NULL) { 36354dfc97bSShailend Chand device_printf(priv->dev, "Failed to allocate ifnet struct\n"); 36454dfc97bSShailend Chand return (ENXIO); 36554dfc97bSShailend Chand } 36654dfc97bSShailend Chand 36754dfc97bSShailend Chand if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 36854dfc97bSShailend Chand if_setsoftc(ifp, priv); 36954dfc97bSShailend Chand if_setdev(ifp, dev); 37054dfc97bSShailend Chand if_setinitfn(ifp, gve_init); 37154dfc97bSShailend Chand if_setioctlfn(ifp, gve_ioctl); 37254dfc97bSShailend Chand if_settransmitfn(ifp, gve_xmit_ifp); 37354dfc97bSShailend Chand if_setqflushfn(ifp, gve_qflush); 37454dfc97bSShailend Chand 37554dfc97bSShailend Chand #if __FreeBSD_version >= 1400086 37654dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 37754dfc97bSShailend Chand #else 37854dfc97bSShailend Chand if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_KNOWSEPOCH); 37954dfc97bSShailend Chand #endif 38054dfc97bSShailend Chand 38154dfc97bSShailend Chand ifmedia_init(&priv->media, IFM_IMASK, gve_media_change, gve_media_status); 38254dfc97bSShailend Chand if_setgetcounterfn(ifp, gve_get_counter); 38354dfc97bSShailend Chand 38454dfc97bSShailend Chand caps = IFCAP_RXCSUM | 38554dfc97bSShailend Chand IFCAP_TXCSUM | 38654dfc97bSShailend Chand IFCAP_TXCSUM_IPV6 | 38754dfc97bSShailend Chand IFCAP_TSO | 38854dfc97bSShailend Chand IFCAP_LRO; 38954dfc97bSShailend Chand 39054dfc97bSShailend Chand if ((priv->supported_features & GVE_SUP_JUMBO_FRAMES_MASK) != 0) 39154dfc97bSShailend Chand caps |= IFCAP_JUMBO_MTU; 39254dfc97bSShailend Chand 39354dfc97bSShailend Chand if_setcapabilities(ifp, caps); 39454dfc97bSShailend Chand if_setcapenable(ifp, caps); 39554dfc97bSShailend Chand 39654dfc97bSShailend Chand if (bootverbose) 39754dfc97bSShailend Chand device_printf(priv->dev, "Setting initial MTU to %d\n", priv->max_mtu); 39854dfc97bSShailend Chand if_setmtu(ifp, priv->max_mtu); 39954dfc97bSShailend Chand 40054dfc97bSShailend Chand ether_ifattach(ifp, priv->mac); 40154dfc97bSShailend Chand 40254dfc97bSShailend Chand ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 40354dfc97bSShailend Chand ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 40454dfc97bSShailend Chand 40554dfc97bSShailend Chand return (0); 40654dfc97bSShailend Chand } 40754dfc97bSShailend Chand 40854dfc97bSShailend Chand static int 40954dfc97bSShailend Chand gve_alloc_counter_array(struct gve_priv *priv) 41054dfc97bSShailend Chand { 41154dfc97bSShailend Chand int err; 41254dfc97bSShailend Chand 41354dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, sizeof(uint32_t) * priv->num_event_counters, 41454dfc97bSShailend Chand PAGE_SIZE, &priv->counter_array_mem); 41554dfc97bSShailend Chand if (err != 0) 41654dfc97bSShailend Chand return (err); 41754dfc97bSShailend Chand 41854dfc97bSShailend Chand priv->counters = priv->counter_array_mem.cpu_addr; 41954dfc97bSShailend Chand return (0); 42054dfc97bSShailend Chand } 42154dfc97bSShailend Chand 42254dfc97bSShailend Chand static void 42354dfc97bSShailend Chand gve_free_counter_array(struct gve_priv *priv) 42454dfc97bSShailend Chand { 42554dfc97bSShailend Chand if (priv->counters != NULL) 42654dfc97bSShailend Chand gve_dma_free_coherent(&priv->counter_array_mem); 42754dfc97bSShailend Chand priv->counter_array_mem = (struct gve_dma_handle){}; 42854dfc97bSShailend Chand } 42954dfc97bSShailend Chand 43054dfc97bSShailend Chand static int 43154dfc97bSShailend Chand gve_alloc_irq_db_array(struct gve_priv *priv) 43254dfc97bSShailend Chand { 43354dfc97bSShailend Chand int err; 43454dfc97bSShailend Chand 43554dfc97bSShailend Chand err = gve_dma_alloc_coherent(priv, 43654dfc97bSShailend Chand sizeof(struct gve_irq_db) * (priv->num_queues), PAGE_SIZE, 43754dfc97bSShailend Chand &priv->irqs_db_mem); 43854dfc97bSShailend Chand if (err != 0) 43954dfc97bSShailend Chand return (err); 44054dfc97bSShailend Chand 44154dfc97bSShailend Chand priv->irq_db_indices = priv->irqs_db_mem.cpu_addr; 44254dfc97bSShailend Chand return (0); 44354dfc97bSShailend Chand } 44454dfc97bSShailend Chand 44554dfc97bSShailend Chand static void 44654dfc97bSShailend Chand gve_free_irq_db_array(struct gve_priv *priv) 44754dfc97bSShailend Chand { 44854dfc97bSShailend Chand if (priv->irq_db_indices != NULL) 44954dfc97bSShailend Chand gve_dma_free_coherent(&priv->irqs_db_mem); 45054dfc97bSShailend Chand priv->irqs_db_mem = (struct gve_dma_handle){}; 45154dfc97bSShailend Chand } 45254dfc97bSShailend Chand 45354dfc97bSShailend Chand static void 45454dfc97bSShailend Chand gve_free_rings(struct gve_priv *priv) 45554dfc97bSShailend Chand { 45654dfc97bSShailend Chand gve_free_irqs(priv); 45754dfc97bSShailend Chand gve_free_tx_rings(priv); 45854dfc97bSShailend Chand gve_free_rx_rings(priv); 45954dfc97bSShailend Chand gve_free_qpls(priv); 46054dfc97bSShailend Chand } 46154dfc97bSShailend Chand 46254dfc97bSShailend Chand static int 46354dfc97bSShailend Chand gve_alloc_rings(struct gve_priv *priv) 46454dfc97bSShailend Chand { 46554dfc97bSShailend Chand int err; 46654dfc97bSShailend Chand 46754dfc97bSShailend Chand err = gve_alloc_qpls(priv); 46854dfc97bSShailend Chand if (err != 0) 46954dfc97bSShailend Chand goto abort; 47054dfc97bSShailend Chand 47154dfc97bSShailend Chand err = gve_alloc_rx_rings(priv); 47254dfc97bSShailend Chand if (err != 0) 47354dfc97bSShailend Chand goto abort; 47454dfc97bSShailend Chand 47554dfc97bSShailend Chand err = gve_alloc_tx_rings(priv); 47654dfc97bSShailend Chand if (err != 0) 47754dfc97bSShailend Chand goto abort; 47854dfc97bSShailend Chand 47954dfc97bSShailend Chand err = gve_alloc_irqs(priv); 48054dfc97bSShailend Chand if (err != 0) 48154dfc97bSShailend Chand goto abort; 48254dfc97bSShailend Chand 48354dfc97bSShailend Chand return (0); 48454dfc97bSShailend Chand 48554dfc97bSShailend Chand abort: 48654dfc97bSShailend Chand gve_free_rings(priv); 48754dfc97bSShailend Chand return (err); 48854dfc97bSShailend Chand } 48954dfc97bSShailend Chand 49054dfc97bSShailend Chand static void 49154dfc97bSShailend Chand gve_deconfigure_resources(struct gve_priv *priv) 49254dfc97bSShailend Chand { 49354dfc97bSShailend Chand int err; 49454dfc97bSShailend Chand 49554dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) { 49654dfc97bSShailend Chand err = gve_adminq_deconfigure_device_resources(priv); 49754dfc97bSShailend Chand if (err != 0) { 49854dfc97bSShailend Chand device_printf(priv->dev, "Failed to deconfigure device resources: err=%d\n", 49954dfc97bSShailend Chand err); 50054dfc97bSShailend Chand return; 50154dfc97bSShailend Chand } 50254dfc97bSShailend Chand if (bootverbose) 50354dfc97bSShailend Chand device_printf(priv->dev, "Deconfigured device resources\n"); 50454dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 50554dfc97bSShailend Chand } 50654dfc97bSShailend Chand 50754dfc97bSShailend Chand gve_free_irq_db_array(priv); 50854dfc97bSShailend Chand gve_free_counter_array(priv); 50954dfc97bSShailend Chand } 51054dfc97bSShailend Chand 51154dfc97bSShailend Chand static int 51254dfc97bSShailend Chand gve_configure_resources(struct gve_priv *priv) 51354dfc97bSShailend Chand { 51454dfc97bSShailend Chand int err; 51554dfc97bSShailend Chand 51654dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) 51754dfc97bSShailend Chand return (0); 51854dfc97bSShailend Chand 51954dfc97bSShailend Chand err = gve_alloc_counter_array(priv); 52054dfc97bSShailend Chand if (err != 0) 52154dfc97bSShailend Chand return (err); 52254dfc97bSShailend Chand 52354dfc97bSShailend Chand err = gve_alloc_irq_db_array(priv); 52454dfc97bSShailend Chand if (err != 0) 52554dfc97bSShailend Chand goto abort; 52654dfc97bSShailend Chand 52754dfc97bSShailend Chand err = gve_adminq_configure_device_resources(priv); 52854dfc97bSShailend Chand if (err != 0) { 52954dfc97bSShailend Chand device_printf(priv->dev, "Failed to configure device resources: err=%d\n", 53054dfc97bSShailend Chand err); 53154dfc97bSShailend Chand err = (ENXIO); 53254dfc97bSShailend Chand goto abort; 53354dfc97bSShailend Chand } 53454dfc97bSShailend Chand 53554dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 53654dfc97bSShailend Chand if (bootverbose) 53754dfc97bSShailend Chand device_printf(priv->dev, "Configured device resources\n"); 53854dfc97bSShailend Chand return (0); 53954dfc97bSShailend Chand 54054dfc97bSShailend Chand abort: 54154dfc97bSShailend Chand gve_deconfigure_resources(priv); 54254dfc97bSShailend Chand return (err); 54354dfc97bSShailend Chand } 54454dfc97bSShailend Chand 54554dfc97bSShailend Chand static void 54654dfc97bSShailend Chand gve_set_queue_cnts(struct gve_priv *priv) 54754dfc97bSShailend Chand { 54854dfc97bSShailend Chand priv->tx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_TX_QUEUES); 54954dfc97bSShailend Chand priv->rx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_RX_QUEUES); 55054dfc97bSShailend Chand priv->tx_cfg.num_queues = priv->tx_cfg.max_queues; 55154dfc97bSShailend Chand priv->rx_cfg.num_queues = priv->rx_cfg.max_queues; 55254dfc97bSShailend Chand 55354dfc97bSShailend Chand if (priv->default_num_queues > 0) { 55454dfc97bSShailend Chand priv->tx_cfg.num_queues = MIN(priv->default_num_queues, 55554dfc97bSShailend Chand priv->tx_cfg.num_queues); 55654dfc97bSShailend Chand priv->rx_cfg.num_queues = MIN(priv->default_num_queues, 55754dfc97bSShailend Chand priv->rx_cfg.num_queues); 55854dfc97bSShailend Chand } 55954dfc97bSShailend Chand 56054dfc97bSShailend Chand priv->num_queues = priv->tx_cfg.num_queues + priv->rx_cfg.num_queues; 56154dfc97bSShailend Chand priv->mgmt_msix_idx = priv->num_queues; 56254dfc97bSShailend Chand } 56354dfc97bSShailend Chand 56454dfc97bSShailend Chand static int 56554dfc97bSShailend Chand gve_alloc_adminq_and_describe_device(struct gve_priv *priv) 56654dfc97bSShailend Chand { 56754dfc97bSShailend Chand int err; 56854dfc97bSShailend Chand 56954dfc97bSShailend Chand if ((err = gve_adminq_alloc(priv)) != 0) 57054dfc97bSShailend Chand return (err); 57154dfc97bSShailend Chand 57254dfc97bSShailend Chand if ((err = gve_verify_driver_compatibility(priv)) != 0) { 57354dfc97bSShailend Chand device_printf(priv->dev, 57454dfc97bSShailend Chand "Failed to verify driver compatibility: err=%d\n", err); 57554dfc97bSShailend Chand goto abort; 57654dfc97bSShailend Chand } 57754dfc97bSShailend Chand 57854dfc97bSShailend Chand if ((err = gve_adminq_describe_device(priv)) != 0) 57954dfc97bSShailend Chand goto abort; 58054dfc97bSShailend Chand 58154dfc97bSShailend Chand gve_set_queue_cnts(priv); 58254dfc97bSShailend Chand 58354dfc97bSShailend Chand priv->num_registered_pages = 0; 58454dfc97bSShailend Chand return (0); 58554dfc97bSShailend Chand 58654dfc97bSShailend Chand abort: 58754dfc97bSShailend Chand gve_release_adminq(priv); 58854dfc97bSShailend Chand return (err); 58954dfc97bSShailend Chand } 59054dfc97bSShailend Chand 59154dfc97bSShailend Chand void 59254dfc97bSShailend Chand gve_schedule_reset(struct gve_priv *priv) 59354dfc97bSShailend Chand { 59454dfc97bSShailend Chand if (gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) 59554dfc97bSShailend Chand return; 59654dfc97bSShailend Chand 59754dfc97bSShailend Chand device_printf(priv->dev, "Scheduling reset task!\n"); 59854dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 59954dfc97bSShailend Chand taskqueue_enqueue(priv->service_tq, &priv->service_task); 60054dfc97bSShailend Chand } 60154dfc97bSShailend Chand 60254dfc97bSShailend Chand static void 60354dfc97bSShailend Chand gve_destroy(struct gve_priv *priv) 60454dfc97bSShailend Chand { 60554dfc97bSShailend Chand gve_down(priv); 60654dfc97bSShailend Chand gve_deconfigure_resources(priv); 60754dfc97bSShailend Chand gve_release_adminq(priv); 60854dfc97bSShailend Chand } 60954dfc97bSShailend Chand 61054dfc97bSShailend Chand static void 61154dfc97bSShailend Chand gve_restore(struct gve_priv *priv) 61254dfc97bSShailend Chand { 61354dfc97bSShailend Chand int err; 61454dfc97bSShailend Chand 61554dfc97bSShailend Chand err = gve_adminq_alloc(priv); 61654dfc97bSShailend Chand if (err != 0) 61754dfc97bSShailend Chand goto abort; 61854dfc97bSShailend Chand 61954dfc97bSShailend Chand err = gve_configure_resources(priv); 62054dfc97bSShailend Chand if (err != 0) 62154dfc97bSShailend Chand goto abort; 62254dfc97bSShailend Chand 62354dfc97bSShailend Chand err = gve_up(priv); 62454dfc97bSShailend Chand if (err != 0) 62554dfc97bSShailend Chand goto abort; 62654dfc97bSShailend Chand 62754dfc97bSShailend Chand return; 62854dfc97bSShailend Chand 62954dfc97bSShailend Chand abort: 63054dfc97bSShailend Chand device_printf(priv->dev, "Restore failed!\n"); 63154dfc97bSShailend Chand return; 63254dfc97bSShailend Chand } 63354dfc97bSShailend Chand 63454dfc97bSShailend Chand static void 63554dfc97bSShailend Chand gve_handle_reset(struct gve_priv *priv) 63654dfc97bSShailend Chand { 63754dfc97bSShailend Chand if (!gve_get_state_flag(priv, GVE_STATE_FLAG_DO_RESET)) 63854dfc97bSShailend Chand return; 63954dfc97bSShailend Chand 64054dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 64154dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 64254dfc97bSShailend Chand 64354dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 64454dfc97bSShailend Chand 64554dfc97bSShailend Chand if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); 64654dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 64754dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 64854dfc97bSShailend Chand 64954dfc97bSShailend Chand /* 65054dfc97bSShailend Chand * Releasing the adminq causes the NIC to destroy all resources 65154dfc97bSShailend Chand * registered with it, so by clearing the flags beneath we cause 65254dfc97bSShailend Chand * the subsequent gve_down call below to not attempt to tell the 65354dfc97bSShailend Chand * NIC to destroy these resources again. 65454dfc97bSShailend Chand * 65554dfc97bSShailend Chand * The call to gve_down is needed in the first place to refresh 65654dfc97bSShailend Chand * the state and the DMA-able memory within each driver ring. 65754dfc97bSShailend Chand */ 65854dfc97bSShailend Chand gve_release_adminq(priv); 65954dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK); 66054dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK); 66154dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_RX_RINGS_OK); 66254dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_TX_RINGS_OK); 66354dfc97bSShailend Chand 66454dfc97bSShailend Chand gve_down(priv); 66554dfc97bSShailend Chand gve_restore(priv); 66654dfc97bSShailend Chand 66754dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 66854dfc97bSShailend Chand 66954dfc97bSShailend Chand priv->reset_cnt++; 67054dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_IN_RESET); 67154dfc97bSShailend Chand } 67254dfc97bSShailend Chand 67354dfc97bSShailend Chand static void 67454dfc97bSShailend Chand gve_handle_link_status(struct gve_priv *priv) 67554dfc97bSShailend Chand { 67654dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 67754dfc97bSShailend Chand bool link_up = status & GVE_DEVICE_STATUS_LINK_STATUS; 67854dfc97bSShailend Chand 67954dfc97bSShailend Chand if (link_up == gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) 68054dfc97bSShailend Chand return; 68154dfc97bSShailend Chand 68254dfc97bSShailend Chand if (link_up) { 68354dfc97bSShailend Chand if (bootverbose) 68454dfc97bSShailend Chand device_printf(priv->dev, "Device link is up.\n"); 68554dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_UP); 68654dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 68754dfc97bSShailend Chand } else { 68854dfc97bSShailend Chand device_printf(priv->dev, "Device link is down.\n"); 68954dfc97bSShailend Chand if_link_state_change(priv->ifp, LINK_STATE_DOWN); 69054dfc97bSShailend Chand gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP); 69154dfc97bSShailend Chand } 69254dfc97bSShailend Chand } 69354dfc97bSShailend Chand 69454dfc97bSShailend Chand static void 69554dfc97bSShailend Chand gve_service_task(void *arg, int pending) 69654dfc97bSShailend Chand { 69754dfc97bSShailend Chand struct gve_priv *priv = (struct gve_priv *)arg; 69854dfc97bSShailend Chand uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS); 69954dfc97bSShailend Chand 70054dfc97bSShailend Chand if (((GVE_DEVICE_STATUS_RESET_MASK & status) != 0) && 70154dfc97bSShailend Chand !gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) { 70254dfc97bSShailend Chand device_printf(priv->dev, "Device requested reset\n"); 70354dfc97bSShailend Chand gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET); 70454dfc97bSShailend Chand } 70554dfc97bSShailend Chand 70654dfc97bSShailend Chand gve_handle_reset(priv); 70754dfc97bSShailend Chand gve_handle_link_status(priv); 70854dfc97bSShailend Chand } 70954dfc97bSShailend Chand 71054dfc97bSShailend Chand static int 71154dfc97bSShailend Chand gve_probe(device_t dev) 71254dfc97bSShailend Chand { 7131bbdfb0bSXin LI uint16_t deviceid, vendorid; 7141bbdfb0bSXin LI int i; 7151bbdfb0bSXin LI 7161bbdfb0bSXin LI vendorid = pci_get_vendor(dev); 7171bbdfb0bSXin LI deviceid = pci_get_device(dev); 7181bbdfb0bSXin LI 719*1177a6c8SXin LI for (i = 0; i < nitems(gve_devs); i++) { 7201bbdfb0bSXin LI if (vendorid == gve_devs[i].vendor_id && 7211bbdfb0bSXin LI deviceid == gve_devs[i].device_id) { 7221bbdfb0bSXin LI device_set_desc(dev, gve_devs[i].name); 72354dfc97bSShailend Chand return (BUS_PROBE_DEFAULT); 72454dfc97bSShailend Chand } 7251bbdfb0bSXin LI } 72654dfc97bSShailend Chand return (ENXIO); 72754dfc97bSShailend Chand } 72854dfc97bSShailend Chand 72954dfc97bSShailend Chand static void 73054dfc97bSShailend Chand gve_free_sys_res_mem(struct gve_priv *priv) 73154dfc97bSShailend Chand { 73254dfc97bSShailend Chand if (priv->msix_table != NULL) 73354dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 73454dfc97bSShailend Chand rman_get_rid(priv->msix_table), priv->msix_table); 73554dfc97bSShailend Chand 73654dfc97bSShailend Chand if (priv->db_bar != NULL) 73754dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 73854dfc97bSShailend Chand rman_get_rid(priv->db_bar), priv->db_bar); 73954dfc97bSShailend Chand 74054dfc97bSShailend Chand if (priv->reg_bar != NULL) 74154dfc97bSShailend Chand bus_release_resource(priv->dev, SYS_RES_MEMORY, 74254dfc97bSShailend Chand rman_get_rid(priv->reg_bar), priv->reg_bar); 74354dfc97bSShailend Chand } 74454dfc97bSShailend Chand 74554dfc97bSShailend Chand static int 74654dfc97bSShailend Chand gve_attach(device_t dev) 74754dfc97bSShailend Chand { 74854dfc97bSShailend Chand struct gve_priv *priv; 74954dfc97bSShailend Chand int rid; 75054dfc97bSShailend Chand int err; 75154dfc97bSShailend Chand 75254dfc97bSShailend Chand priv = device_get_softc(dev); 75354dfc97bSShailend Chand priv->dev = dev; 75454dfc97bSShailend Chand GVE_IFACE_LOCK_INIT(priv->gve_iface_lock); 75554dfc97bSShailend Chand 75654dfc97bSShailend Chand pci_enable_busmaster(dev); 75754dfc97bSShailend Chand 75854dfc97bSShailend Chand rid = PCIR_BAR(GVE_REGISTER_BAR); 75954dfc97bSShailend Chand priv->reg_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 76054dfc97bSShailend Chand &rid, RF_ACTIVE); 76154dfc97bSShailend Chand if (priv->reg_bar == NULL) { 76254dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR0\n"); 76354dfc97bSShailend Chand err = ENXIO; 76454dfc97bSShailend Chand goto abort; 76554dfc97bSShailend Chand } 76654dfc97bSShailend Chand 76754dfc97bSShailend Chand rid = PCIR_BAR(GVE_DOORBELL_BAR); 76854dfc97bSShailend Chand priv->db_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 76954dfc97bSShailend Chand &rid, RF_ACTIVE); 77054dfc97bSShailend Chand if (priv->db_bar == NULL) { 77154dfc97bSShailend Chand device_printf(dev, "Failed to allocate BAR2\n"); 77254dfc97bSShailend Chand err = ENXIO; 77354dfc97bSShailend Chand goto abort; 77454dfc97bSShailend Chand } 77554dfc97bSShailend Chand 77654dfc97bSShailend Chand rid = pci_msix_table_bar(priv->dev); 77754dfc97bSShailend Chand priv->msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 77854dfc97bSShailend Chand &rid, RF_ACTIVE); 77954dfc97bSShailend Chand if (priv->msix_table == NULL) { 78054dfc97bSShailend Chand device_printf(dev, "Failed to allocate msix table\n"); 78154dfc97bSShailend Chand err = ENXIO; 78254dfc97bSShailend Chand goto abort; 78354dfc97bSShailend Chand } 78454dfc97bSShailend Chand 78554dfc97bSShailend Chand err = gve_alloc_adminq_and_describe_device(priv); 78654dfc97bSShailend Chand if (err != 0) 78754dfc97bSShailend Chand goto abort; 78854dfc97bSShailend Chand 78954dfc97bSShailend Chand err = gve_configure_resources(priv); 79054dfc97bSShailend Chand if (err != 0) 79154dfc97bSShailend Chand goto abort; 79254dfc97bSShailend Chand 79354dfc97bSShailend Chand err = gve_alloc_rings(priv); 79454dfc97bSShailend Chand if (err != 0) 79554dfc97bSShailend Chand goto abort; 79654dfc97bSShailend Chand 79754dfc97bSShailend Chand err = gve_setup_ifnet(dev, priv); 79854dfc97bSShailend Chand if (err != 0) 79954dfc97bSShailend Chand goto abort; 80054dfc97bSShailend Chand 80154dfc97bSShailend Chand priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; 80254dfc97bSShailend Chand 80354dfc97bSShailend Chand bus_write_multi_1(priv->reg_bar, DRIVER_VERSION, GVE_DRIVER_VERSION, 80454dfc97bSShailend Chand sizeof(GVE_DRIVER_VERSION) - 1); 80554dfc97bSShailend Chand 80654dfc97bSShailend Chand TASK_INIT(&priv->service_task, 0, gve_service_task, priv); 80754dfc97bSShailend Chand priv->service_tq = taskqueue_create("gve service", M_WAITOK | M_ZERO, 80854dfc97bSShailend Chand taskqueue_thread_enqueue, &priv->service_tq); 80954dfc97bSShailend Chand taskqueue_start_threads(&priv->service_tq, 1, PI_NET, "%s service tq", 81054dfc97bSShailend Chand device_get_nameunit(priv->dev)); 81154dfc97bSShailend Chand 81254dfc97bSShailend Chand gve_setup_sysctl(priv); 81354dfc97bSShailend Chand 81454dfc97bSShailend Chand if (bootverbose) 81554dfc97bSShailend Chand device_printf(priv->dev, "Successfully attached %s", GVE_DRIVER_VERSION); 81654dfc97bSShailend Chand return (0); 81754dfc97bSShailend Chand 81854dfc97bSShailend Chand abort: 81954dfc97bSShailend Chand gve_free_rings(priv); 82054dfc97bSShailend Chand gve_deconfigure_resources(priv); 82154dfc97bSShailend Chand gve_release_adminq(priv); 82254dfc97bSShailend Chand gve_free_sys_res_mem(priv); 82354dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 82454dfc97bSShailend Chand return (err); 82554dfc97bSShailend Chand } 82654dfc97bSShailend Chand 82754dfc97bSShailend Chand static int 82854dfc97bSShailend Chand gve_detach(device_t dev) 82954dfc97bSShailend Chand { 83054dfc97bSShailend Chand struct gve_priv *priv = device_get_softc(dev); 83154dfc97bSShailend Chand if_t ifp = priv->ifp; 83254dfc97bSShailend Chand 83354dfc97bSShailend Chand ether_ifdetach(ifp); 83454dfc97bSShailend Chand 83554dfc97bSShailend Chand GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock); 83654dfc97bSShailend Chand gve_destroy(priv); 83754dfc97bSShailend Chand GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock); 83854dfc97bSShailend Chand 83954dfc97bSShailend Chand gve_free_rings(priv); 84054dfc97bSShailend Chand gve_free_sys_res_mem(priv); 84154dfc97bSShailend Chand GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock); 84254dfc97bSShailend Chand 84354dfc97bSShailend Chand while (taskqueue_cancel(priv->service_tq, &priv->service_task, NULL)) 84454dfc97bSShailend Chand taskqueue_drain(priv->service_tq, &priv->service_task); 84554dfc97bSShailend Chand taskqueue_free(priv->service_tq); 84654dfc97bSShailend Chand 84754dfc97bSShailend Chand if_free(ifp); 84854dfc97bSShailend Chand return (bus_generic_detach(dev)); 84954dfc97bSShailend Chand } 85054dfc97bSShailend Chand 85154dfc97bSShailend Chand static device_method_t gve_methods[] = { 85254dfc97bSShailend Chand DEVMETHOD(device_probe, gve_probe), 85354dfc97bSShailend Chand DEVMETHOD(device_attach, gve_attach), 85454dfc97bSShailend Chand DEVMETHOD(device_detach, gve_detach), 85554dfc97bSShailend Chand DEVMETHOD_END 85654dfc97bSShailend Chand }; 85754dfc97bSShailend Chand 85854dfc97bSShailend Chand static driver_t gve_driver = { 85954dfc97bSShailend Chand "gve", 86054dfc97bSShailend Chand gve_methods, 86154dfc97bSShailend Chand sizeof(struct gve_priv) 86254dfc97bSShailend Chand }; 86354dfc97bSShailend Chand 86454dfc97bSShailend Chand #if __FreeBSD_version < 1301503 86554dfc97bSShailend Chand static devclass_t gve_devclass; 86654dfc97bSShailend Chand 86754dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, gve_devclass, 0, 0); 86854dfc97bSShailend Chand #else 86954dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, 0, 0); 87054dfc97bSShailend Chand #endif 871*1177a6c8SXin LI MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, gve, gve_devs, 872*1177a6c8SXin LI nitems(gve_devs)); 873