xref: /src/sys/dev/gve/gve_main.c (revision 54dfc97b0bd99f1c3bcbb37357cf28cd81a7cf00)
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