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