xref: /freebsd/sys/dev/gve/gve_main.c (revision 1177a6c8dcfd6625c541d6ffc3c6915b8b6354f7)
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