xref: /freebsd-src/sys/dev/gve/gve_main.c (revision 40097cd67c0d52e2b288e8555b12faf02768d89c)
154dfc97bSShailend Chand /*-
254dfc97bSShailend Chand  * SPDX-License-Identifier: BSD-3-Clause
354dfc97bSShailend Chand  *
4d438b4efSShailend Chand  * Copyright (c) 2023-2024 Google LLC
554dfc97bSShailend Chand  *
654dfc97bSShailend Chand  * Redistribution and use in source and binary forms, with or without modification,
754dfc97bSShailend Chand  * are permitted provided that the following conditions are met:
854dfc97bSShailend Chand  *
954dfc97bSShailend Chand  * 1. Redistributions of source code must retain the above copyright notice, this
1054dfc97bSShailend Chand  *    list of conditions and the following disclaimer.
1154dfc97bSShailend Chand  *
1254dfc97bSShailend Chand  * 2. Redistributions in binary form must reproduce the above copyright notice,
1354dfc97bSShailend Chand  *    this list of conditions and the following disclaimer in the documentation
1454dfc97bSShailend Chand  *    and/or other materials provided with the distribution.
1554dfc97bSShailend Chand  *
1654dfc97bSShailend Chand  * 3. Neither the name of the copyright holder nor the names of its contributors
1754dfc97bSShailend Chand  *    may be used to endorse or promote products derived from this software without
1854dfc97bSShailend Chand  *    specific prior written permission.
1954dfc97bSShailend Chand  *
2054dfc97bSShailend Chand  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2154dfc97bSShailend Chand  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2254dfc97bSShailend Chand  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2354dfc97bSShailend Chand  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
2454dfc97bSShailend Chand  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2554dfc97bSShailend Chand  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2654dfc97bSShailend Chand  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2754dfc97bSShailend Chand  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2854dfc97bSShailend Chand  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2954dfc97bSShailend Chand  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3054dfc97bSShailend Chand  */
3154dfc97bSShailend Chand #include "gve.h"
3254dfc97bSShailend Chand #include "gve_adminq.h"
33d438b4efSShailend Chand #include "gve_dqo.h"
3454dfc97bSShailend Chand 
35*40097cd6SShailend Chand #define GVE_DRIVER_VERSION "GVE-FBSD-1.3.1\n"
365f62584aSShailend Chand #define GVE_VERSION_MAJOR 1
372348ac89SShailend Chand #define GVE_VERSION_MINOR 3
38*40097cd6SShailend Chand #define GVE_VERSION_SUB 1
3954dfc97bSShailend Chand 
4054dfc97bSShailend Chand #define GVE_DEFAULT_RX_COPYBREAK 256
4154dfc97bSShailend Chand 
421bbdfb0bSXin LI /* Devices supported by this driver. */
431bbdfb0bSXin LI static struct gve_dev {
441bbdfb0bSXin LI         uint16_t vendor_id;
451bbdfb0bSXin LI         uint16_t device_id;
461bbdfb0bSXin LI         const char *name;
471bbdfb0bSXin LI } gve_devs[] = {
481bbdfb0bSXin LI 	{ PCI_VENDOR_ID_GOOGLE, PCI_DEV_ID_GVNIC, "gVNIC" }
491bbdfb0bSXin LI };
501bbdfb0bSXin LI 
5154dfc97bSShailend Chand struct sx gve_global_lock;
5254dfc97bSShailend Chand 
5354dfc97bSShailend Chand static int
5454dfc97bSShailend Chand gve_verify_driver_compatibility(struct gve_priv *priv)
5554dfc97bSShailend Chand {
5654dfc97bSShailend Chand 	int err;
5754dfc97bSShailend Chand 	struct gve_driver_info *driver_info;
5854dfc97bSShailend Chand 	struct gve_dma_handle driver_info_mem;
5954dfc97bSShailend Chand 
6054dfc97bSShailend Chand 	err = gve_dma_alloc_coherent(priv, sizeof(struct gve_driver_info),
6154dfc97bSShailend Chand 	    PAGE_SIZE, &driver_info_mem);
6254dfc97bSShailend Chand 
6354dfc97bSShailend Chand 	if (err != 0)
6454dfc97bSShailend Chand 		return (ENOMEM);
6554dfc97bSShailend Chand 
6654dfc97bSShailend Chand 	driver_info = driver_info_mem.cpu_addr;
6754dfc97bSShailend Chand 
6854dfc97bSShailend Chand 	*driver_info = (struct gve_driver_info) {
6954dfc97bSShailend Chand 		.os_type = 3, /* Freebsd */
7054dfc97bSShailend Chand 		.driver_major = GVE_VERSION_MAJOR,
7154dfc97bSShailend Chand 		.driver_minor = GVE_VERSION_MINOR,
7254dfc97bSShailend Chand 		.driver_sub = GVE_VERSION_SUB,
7354dfc97bSShailend Chand 		.os_version_major = htobe32(FBSD_VERSION_MAJOR),
7454dfc97bSShailend Chand 		.os_version_minor = htobe32(FBSD_VERSION_MINOR),
7554dfc97bSShailend Chand 		.os_version_sub = htobe32(FBSD_VERSION_PATCH),
7654dfc97bSShailend Chand 		.driver_capability_flags = {
7754dfc97bSShailend Chand 			htobe64(GVE_DRIVER_CAPABILITY_FLAGS1),
7854dfc97bSShailend Chand 			htobe64(GVE_DRIVER_CAPABILITY_FLAGS2),
7954dfc97bSShailend Chand 			htobe64(GVE_DRIVER_CAPABILITY_FLAGS3),
8054dfc97bSShailend Chand 			htobe64(GVE_DRIVER_CAPABILITY_FLAGS4),
8154dfc97bSShailend Chand 		},
8254dfc97bSShailend Chand 	};
8354dfc97bSShailend Chand 
8454dfc97bSShailend Chand 	snprintf(driver_info->os_version_str1, sizeof(driver_info->os_version_str1),
8554dfc97bSShailend Chand 	    "FreeBSD %u", __FreeBSD_version);
8654dfc97bSShailend Chand 
8754dfc97bSShailend Chand 	bus_dmamap_sync(driver_info_mem.tag, driver_info_mem.map,
8854dfc97bSShailend Chand 	    BUS_DMASYNC_PREREAD);
8954dfc97bSShailend Chand 
9054dfc97bSShailend Chand 	err = gve_adminq_verify_driver_compatibility(priv,
9154dfc97bSShailend Chand 	    sizeof(struct gve_driver_info), driver_info_mem.bus_addr);
9254dfc97bSShailend Chand 
9354dfc97bSShailend Chand 	/* It's ok if the device doesn't support this */
9454dfc97bSShailend Chand 	if (err == EOPNOTSUPP)
9554dfc97bSShailend Chand 		err = 0;
9654dfc97bSShailend Chand 
9754dfc97bSShailend Chand 	gve_dma_free_coherent(&driver_info_mem);
9854dfc97bSShailend Chand 
9954dfc97bSShailend Chand 	return (err);
10054dfc97bSShailend Chand }
10154dfc97bSShailend Chand 
10254dfc97bSShailend Chand static int
10354dfc97bSShailend Chand gve_up(struct gve_priv *priv)
10454dfc97bSShailend Chand {
10554dfc97bSShailend Chand 	if_t ifp = priv->ifp;
10654dfc97bSShailend Chand 	int err;
10754dfc97bSShailend Chand 
10854dfc97bSShailend Chand 	GVE_IFACE_LOCK_ASSERT(priv->gve_iface_lock);
10954dfc97bSShailend Chand 
11054dfc97bSShailend Chand 	if (device_is_attached(priv->dev) == 0) {
11154dfc97bSShailend Chand 		device_printf(priv->dev, "Cannot bring the iface up when detached\n");
11254dfc97bSShailend Chand 		return (ENXIO);
11354dfc97bSShailend Chand 	}
11454dfc97bSShailend Chand 
11554dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP))
11654dfc97bSShailend Chand 		return (0);
11754dfc97bSShailend Chand 
11854dfc97bSShailend Chand 	if_clearhwassist(ifp);
11954dfc97bSShailend Chand 	if (if_getcapenable(ifp) & IFCAP_TXCSUM)
12054dfc97bSShailend Chand 		if_sethwassistbits(ifp, CSUM_TCP | CSUM_UDP, 0);
12154dfc97bSShailend Chand 	if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
12254dfc97bSShailend Chand 		if_sethwassistbits(ifp, CSUM_IP6_TCP | CSUM_IP6_UDP, 0);
12354dfc97bSShailend Chand 	if (if_getcapenable(ifp) & IFCAP_TSO4)
12454dfc97bSShailend Chand 		if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
12554dfc97bSShailend Chand 	if (if_getcapenable(ifp) & IFCAP_TSO6)
12654dfc97bSShailend Chand 		if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
12754dfc97bSShailend Chand 
1282348ac89SShailend Chand 	if (gve_is_qpl(priv)) {
12954dfc97bSShailend Chand 		err = gve_register_qpls(priv);
13054dfc97bSShailend Chand 		if (err != 0)
13154dfc97bSShailend Chand 			goto reset;
132d438b4efSShailend Chand 	}
13354dfc97bSShailend Chand 
13454dfc97bSShailend Chand 	err = gve_create_rx_rings(priv);
13554dfc97bSShailend Chand 	if (err != 0)
13654dfc97bSShailend Chand 		goto reset;
13754dfc97bSShailend Chand 
13854dfc97bSShailend Chand 	err = gve_create_tx_rings(priv);
13954dfc97bSShailend Chand 	if (err != 0)
14054dfc97bSShailend Chand 		goto reset;
14154dfc97bSShailend Chand 
14254dfc97bSShailend Chand 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
14354dfc97bSShailend Chand 
14454dfc97bSShailend Chand 	if (!gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) {
14554dfc97bSShailend Chand 		if_link_state_change(ifp, LINK_STATE_UP);
14654dfc97bSShailend Chand 		gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
14754dfc97bSShailend Chand 	}
14854dfc97bSShailend Chand 
14954dfc97bSShailend Chand 	gve_unmask_all_queue_irqs(priv);
15054dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP);
15154dfc97bSShailend Chand 	priv->interface_up_cnt++;
15254dfc97bSShailend Chand 	return (0);
15354dfc97bSShailend Chand 
15454dfc97bSShailend Chand reset:
15554dfc97bSShailend Chand 	gve_schedule_reset(priv);
15654dfc97bSShailend Chand 	return (err);
15754dfc97bSShailend Chand }
15854dfc97bSShailend Chand 
15954dfc97bSShailend Chand static void
16054dfc97bSShailend Chand gve_down(struct gve_priv *priv)
16154dfc97bSShailend Chand {
16254dfc97bSShailend Chand 	GVE_IFACE_LOCK_ASSERT(priv->gve_iface_lock);
16354dfc97bSShailend Chand 
16454dfc97bSShailend Chand 	if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP))
16554dfc97bSShailend Chand 		return;
16654dfc97bSShailend Chand 
16754dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) {
16854dfc97bSShailend Chand 		if_link_state_change(priv->ifp, LINK_STATE_DOWN);
16954dfc97bSShailend Chand 		gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
17054dfc97bSShailend Chand 	}
17154dfc97bSShailend Chand 
17254dfc97bSShailend Chand 	if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
17354dfc97bSShailend Chand 
17454dfc97bSShailend Chand 	if (gve_destroy_rx_rings(priv) != 0)
17554dfc97bSShailend Chand 		goto reset;
17654dfc97bSShailend Chand 
17754dfc97bSShailend Chand 	if (gve_destroy_tx_rings(priv) != 0)
17854dfc97bSShailend Chand 		goto reset;
17954dfc97bSShailend Chand 
1802348ac89SShailend Chand 	if (gve_is_qpl(priv)) {
18154dfc97bSShailend Chand 		if (gve_unregister_qpls(priv) != 0)
18254dfc97bSShailend Chand 			goto reset;
183d438b4efSShailend Chand 	}
18454dfc97bSShailend Chand 
185d438b4efSShailend Chand 	if (gve_is_gqi(priv))
18654dfc97bSShailend Chand 		gve_mask_all_queue_irqs(priv);
18754dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP);
18854dfc97bSShailend Chand 	priv->interface_down_cnt++;
18954dfc97bSShailend Chand 	return;
19054dfc97bSShailend Chand 
19154dfc97bSShailend Chand reset:
19254dfc97bSShailend Chand 	gve_schedule_reset(priv);
19354dfc97bSShailend Chand }
19454dfc97bSShailend Chand 
19554dfc97bSShailend Chand static int
19654dfc97bSShailend Chand gve_set_mtu(if_t ifp, uint32_t new_mtu)
19754dfc97bSShailend Chand {
19854dfc97bSShailend Chand 	struct gve_priv *priv = if_getsoftc(ifp);
19954dfc97bSShailend Chand 	int err;
20054dfc97bSShailend Chand 
20154dfc97bSShailend Chand 	if ((new_mtu > priv->max_mtu) || (new_mtu < ETHERMIN)) {
20254dfc97bSShailend Chand 		device_printf(priv->dev, "Invalid new MTU setting. new mtu: %d max mtu: %d min mtu: %d\n",
20354dfc97bSShailend Chand 		    new_mtu, priv->max_mtu, ETHERMIN);
20454dfc97bSShailend Chand 		return (EINVAL);
20554dfc97bSShailend Chand 	}
20654dfc97bSShailend Chand 
20754dfc97bSShailend Chand 	err = gve_adminq_set_mtu(priv, new_mtu);
20854dfc97bSShailend Chand 	if (err == 0) {
20954dfc97bSShailend Chand 		if (bootverbose)
21054dfc97bSShailend Chand 			device_printf(priv->dev, "MTU set to %d\n", new_mtu);
21154dfc97bSShailend Chand 		if_setmtu(ifp, new_mtu);
21254dfc97bSShailend Chand 	} else {
21354dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to set MTU to %d\n", new_mtu);
21454dfc97bSShailend Chand 	}
21554dfc97bSShailend Chand 
21654dfc97bSShailend Chand 	return (err);
21754dfc97bSShailend Chand }
21854dfc97bSShailend Chand 
21954dfc97bSShailend Chand static void
22054dfc97bSShailend Chand gve_init(void *arg)
22154dfc97bSShailend Chand {
22254dfc97bSShailend Chand 	struct gve_priv *priv = (struct gve_priv *)arg;
22354dfc97bSShailend Chand 
22454dfc97bSShailend Chand 	if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) {
22554dfc97bSShailend Chand 		GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
22654dfc97bSShailend Chand 		gve_up(priv);
22754dfc97bSShailend Chand 		GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
22854dfc97bSShailend Chand 	}
22954dfc97bSShailend Chand }
23054dfc97bSShailend Chand 
23154dfc97bSShailend Chand static int
23254dfc97bSShailend Chand gve_ioctl(if_t ifp, u_long command, caddr_t data)
23354dfc97bSShailend Chand {
23454dfc97bSShailend Chand 	struct gve_priv *priv;
23554dfc97bSShailend Chand 	struct ifreq *ifr;
23654dfc97bSShailend Chand 	int rc = 0;
23754dfc97bSShailend Chand 
23854dfc97bSShailend Chand 	priv = if_getsoftc(ifp);
23954dfc97bSShailend Chand 	ifr = (struct ifreq *)data;
24054dfc97bSShailend Chand 
24154dfc97bSShailend Chand 	switch (command) {
24254dfc97bSShailend Chand 	case SIOCSIFMTU:
24354dfc97bSShailend Chand 		if (if_getmtu(ifp) == ifr->ifr_mtu)
24454dfc97bSShailend Chand 			break;
24554dfc97bSShailend Chand 		GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
24654dfc97bSShailend Chand 		gve_down(priv);
24754dfc97bSShailend Chand 		gve_set_mtu(ifp, ifr->ifr_mtu);
24854dfc97bSShailend Chand 		rc = gve_up(priv);
24954dfc97bSShailend Chand 		GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
25054dfc97bSShailend Chand 		break;
25154dfc97bSShailend Chand 
25254dfc97bSShailend Chand 	case SIOCSIFFLAGS:
25354dfc97bSShailend Chand 		if ((if_getflags(ifp) & IFF_UP) != 0) {
25454dfc97bSShailend Chand 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) {
25554dfc97bSShailend Chand 				GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
25654dfc97bSShailend Chand 				rc = gve_up(priv);
25754dfc97bSShailend Chand 				GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
25854dfc97bSShailend Chand 			}
25954dfc97bSShailend Chand 		} else {
26054dfc97bSShailend Chand 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
26154dfc97bSShailend Chand 				GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
26254dfc97bSShailend Chand 				gve_down(priv);
26354dfc97bSShailend Chand 				GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
26454dfc97bSShailend Chand 			}
26554dfc97bSShailend Chand 		}
26654dfc97bSShailend Chand 		break;
26754dfc97bSShailend Chand 
26854dfc97bSShailend Chand 	case SIOCSIFCAP:
26954dfc97bSShailend Chand 		if (ifr->ifr_reqcap == if_getcapenable(ifp))
27054dfc97bSShailend Chand 			break;
27154dfc97bSShailend Chand 		GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
27254dfc97bSShailend Chand 		gve_down(priv);
27354dfc97bSShailend Chand 		if_setcapenable(ifp, ifr->ifr_reqcap);
27454dfc97bSShailend Chand 		rc = gve_up(priv);
27554dfc97bSShailend Chand 		GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
27654dfc97bSShailend Chand 		break;
27754dfc97bSShailend Chand 
27854dfc97bSShailend Chand 	case SIOCSIFMEDIA:
27954dfc97bSShailend Chand 		/* FALLTHROUGH */
28054dfc97bSShailend Chand 	case SIOCGIFMEDIA:
28154dfc97bSShailend Chand 		rc = ifmedia_ioctl(ifp, ifr, &priv->media, command);
28254dfc97bSShailend Chand 		break;
28354dfc97bSShailend Chand 
28454dfc97bSShailend Chand 	default:
28554dfc97bSShailend Chand 		rc = ether_ioctl(ifp, command, data);
28654dfc97bSShailend Chand 		break;
28754dfc97bSShailend Chand 	}
28854dfc97bSShailend Chand 
28954dfc97bSShailend Chand 	return (rc);
29054dfc97bSShailend Chand }
29154dfc97bSShailend Chand 
29254dfc97bSShailend Chand static int
29354dfc97bSShailend Chand gve_media_change(if_t ifp)
29454dfc97bSShailend Chand {
29554dfc97bSShailend Chand 	struct gve_priv *priv = if_getsoftc(ifp);
29654dfc97bSShailend Chand 
29754dfc97bSShailend Chand 	device_printf(priv->dev, "Media change not supported\n");
29854dfc97bSShailend Chand 	return (0);
29954dfc97bSShailend Chand }
30054dfc97bSShailend Chand 
30154dfc97bSShailend Chand static void
30254dfc97bSShailend Chand gve_media_status(if_t ifp, struct ifmediareq *ifmr)
30354dfc97bSShailend Chand {
30454dfc97bSShailend Chand 	struct gve_priv *priv = if_getsoftc(ifp);
30554dfc97bSShailend Chand 
30654dfc97bSShailend Chand 	GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
30754dfc97bSShailend Chand 
30854dfc97bSShailend Chand 	ifmr->ifm_status = IFM_AVALID;
30954dfc97bSShailend Chand 	ifmr->ifm_active = IFM_ETHER;
31054dfc97bSShailend Chand 
31154dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) {
31254dfc97bSShailend Chand 		ifmr->ifm_status |= IFM_ACTIVE;
31354dfc97bSShailend Chand 		ifmr->ifm_active |= IFM_AUTO;
31454dfc97bSShailend Chand 	} else {
31554dfc97bSShailend Chand 		ifmr->ifm_active |= IFM_NONE;
31654dfc97bSShailend Chand 	}
31754dfc97bSShailend Chand 
31854dfc97bSShailend Chand 	GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
31954dfc97bSShailend Chand }
32054dfc97bSShailend Chand 
32154dfc97bSShailend Chand static uint64_t
32254dfc97bSShailend Chand gve_get_counter(if_t ifp, ift_counter cnt)
32354dfc97bSShailend Chand {
32454dfc97bSShailend Chand 	struct gve_priv *priv;
32554dfc97bSShailend Chand 	uint64_t rpackets = 0;
32654dfc97bSShailend Chand 	uint64_t tpackets = 0;
32754dfc97bSShailend Chand 	uint64_t rbytes = 0;
32854dfc97bSShailend Chand 	uint64_t tbytes = 0;
32954dfc97bSShailend Chand 	uint64_t rx_dropped_pkt = 0;
33054dfc97bSShailend Chand 	uint64_t tx_dropped_pkt = 0;
33154dfc97bSShailend Chand 
33254dfc97bSShailend Chand 	priv = if_getsoftc(ifp);
33354dfc97bSShailend Chand 
33454dfc97bSShailend Chand 	gve_accum_stats(priv, &rpackets, &rbytes, &rx_dropped_pkt, &tpackets,
33554dfc97bSShailend Chand 	    &tbytes, &tx_dropped_pkt);
33654dfc97bSShailend Chand 
33754dfc97bSShailend Chand 	switch (cnt) {
33854dfc97bSShailend Chand 	case IFCOUNTER_IPACKETS:
33954dfc97bSShailend Chand 		return (rpackets);
34054dfc97bSShailend Chand 
34154dfc97bSShailend Chand 	case IFCOUNTER_OPACKETS:
34254dfc97bSShailend Chand 		return (tpackets);
34354dfc97bSShailend Chand 
34454dfc97bSShailend Chand 	case IFCOUNTER_IBYTES:
34554dfc97bSShailend Chand 		return (rbytes);
34654dfc97bSShailend Chand 
34754dfc97bSShailend Chand 	case IFCOUNTER_OBYTES:
34854dfc97bSShailend Chand 		return (tbytes);
34954dfc97bSShailend Chand 
35054dfc97bSShailend Chand 	case IFCOUNTER_IQDROPS:
35154dfc97bSShailend Chand 		return (rx_dropped_pkt);
35254dfc97bSShailend Chand 
35354dfc97bSShailend Chand 	case IFCOUNTER_OQDROPS:
35454dfc97bSShailend Chand 		return (tx_dropped_pkt);
35554dfc97bSShailend Chand 
35654dfc97bSShailend Chand 	default:
35754dfc97bSShailend Chand 		return (if_get_counter_default(ifp, cnt));
35854dfc97bSShailend Chand 	}
35954dfc97bSShailend Chand }
36054dfc97bSShailend Chand 
361aa386085SZhenlei Huang static void
36254dfc97bSShailend Chand gve_setup_ifnet(device_t dev, struct gve_priv *priv)
36354dfc97bSShailend Chand {
36454dfc97bSShailend Chand 	int caps = 0;
36554dfc97bSShailend Chand 	if_t ifp;
36654dfc97bSShailend Chand 
36754dfc97bSShailend Chand 	ifp = priv->ifp = if_alloc(IFT_ETHER);
36854dfc97bSShailend Chand 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
36954dfc97bSShailend Chand 	if_setsoftc(ifp, priv);
37054dfc97bSShailend Chand 	if_setdev(ifp, dev);
37154dfc97bSShailend Chand 	if_setinitfn(ifp, gve_init);
37254dfc97bSShailend Chand 	if_setioctlfn(ifp, gve_ioctl);
37354dfc97bSShailend Chand 	if_settransmitfn(ifp, gve_xmit_ifp);
37454dfc97bSShailend Chand 	if_setqflushfn(ifp, gve_qflush);
37554dfc97bSShailend Chand 
376d438b4efSShailend Chand 	/*
377d438b4efSShailend Chand 	 * Set TSO limits, must match the arguments to bus_dma_tag_create
3782348ac89SShailend Chand 	 * when creating tx->dqo.buf_dmatag. Only applies to the RDA mode
3792348ac89SShailend Chand 	 * because in QPL we copy the entire pakcet into the bounce buffer
3802348ac89SShailend Chand 	 * and thus it does not matter how fragmented the mbuf is.
381d438b4efSShailend Chand 	 */
3822348ac89SShailend Chand 	if (!gve_is_gqi(priv) && !gve_is_qpl(priv)) {
383d438b4efSShailend Chand 		if_sethwtsomaxsegcount(ifp, GVE_TX_MAX_DATA_DESCS_DQO);
384d438b4efSShailend Chand 		if_sethwtsomaxsegsize(ifp, GVE_TX_MAX_BUF_SIZE_DQO);
385d438b4efSShailend Chand 	}
3862348ac89SShailend Chand 	if_sethwtsomax(ifp, GVE_TSO_MAXSIZE_DQO);
387d438b4efSShailend Chand 
38854dfc97bSShailend Chand #if __FreeBSD_version >= 1400086
38954dfc97bSShailend Chand 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
39054dfc97bSShailend Chand #else
39154dfc97bSShailend Chand 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_KNOWSEPOCH);
39254dfc97bSShailend Chand #endif
39354dfc97bSShailend Chand 
39454dfc97bSShailend Chand 	ifmedia_init(&priv->media, IFM_IMASK, gve_media_change, gve_media_status);
39554dfc97bSShailend Chand 	if_setgetcounterfn(ifp, gve_get_counter);
39654dfc97bSShailend Chand 
39754dfc97bSShailend Chand 	caps = IFCAP_RXCSUM |
39854dfc97bSShailend Chand 	       IFCAP_TXCSUM |
39954dfc97bSShailend Chand 	       IFCAP_TXCSUM_IPV6 |
40054dfc97bSShailend Chand 	       IFCAP_TSO |
40154dfc97bSShailend Chand 	       IFCAP_LRO;
40254dfc97bSShailend Chand 
40354dfc97bSShailend Chand 	if ((priv->supported_features & GVE_SUP_JUMBO_FRAMES_MASK) != 0)
40454dfc97bSShailend Chand 		caps |= IFCAP_JUMBO_MTU;
40554dfc97bSShailend Chand 
40654dfc97bSShailend Chand 	if_setcapabilities(ifp, caps);
40754dfc97bSShailend Chand 	if_setcapenable(ifp, caps);
40854dfc97bSShailend Chand 
40954dfc97bSShailend Chand 	if (bootverbose)
41054dfc97bSShailend Chand 		device_printf(priv->dev, "Setting initial MTU to %d\n", priv->max_mtu);
41154dfc97bSShailend Chand 	if_setmtu(ifp, priv->max_mtu);
41254dfc97bSShailend Chand 
41354dfc97bSShailend Chand 	ether_ifattach(ifp, priv->mac);
41454dfc97bSShailend Chand 
41554dfc97bSShailend Chand 	ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
41654dfc97bSShailend Chand 	ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
41754dfc97bSShailend Chand }
41854dfc97bSShailend Chand 
41954dfc97bSShailend Chand static int
42054dfc97bSShailend Chand gve_alloc_counter_array(struct gve_priv *priv)
42154dfc97bSShailend Chand {
42254dfc97bSShailend Chand 	int err;
42354dfc97bSShailend Chand 
42454dfc97bSShailend Chand 	err = gve_dma_alloc_coherent(priv, sizeof(uint32_t) * priv->num_event_counters,
42554dfc97bSShailend Chand 	    PAGE_SIZE, &priv->counter_array_mem);
42654dfc97bSShailend Chand 	if (err != 0)
42754dfc97bSShailend Chand 		return (err);
42854dfc97bSShailend Chand 
42954dfc97bSShailend Chand 	priv->counters = priv->counter_array_mem.cpu_addr;
43054dfc97bSShailend Chand 	return (0);
43154dfc97bSShailend Chand }
43254dfc97bSShailend Chand 
43354dfc97bSShailend Chand static void
43454dfc97bSShailend Chand gve_free_counter_array(struct gve_priv *priv)
43554dfc97bSShailend Chand {
43654dfc97bSShailend Chand 	if (priv->counters != NULL)
43754dfc97bSShailend Chand 		gve_dma_free_coherent(&priv->counter_array_mem);
43854dfc97bSShailend Chand 	priv->counter_array_mem = (struct gve_dma_handle){};
43954dfc97bSShailend Chand }
44054dfc97bSShailend Chand 
44154dfc97bSShailend Chand static int
44254dfc97bSShailend Chand gve_alloc_irq_db_array(struct gve_priv *priv)
44354dfc97bSShailend Chand {
44454dfc97bSShailend Chand 	int err;
44554dfc97bSShailend Chand 
44654dfc97bSShailend Chand 	err = gve_dma_alloc_coherent(priv,
44754dfc97bSShailend Chand 	    sizeof(struct gve_irq_db) * (priv->num_queues), PAGE_SIZE,
44854dfc97bSShailend Chand 	    &priv->irqs_db_mem);
44954dfc97bSShailend Chand 	if (err != 0)
45054dfc97bSShailend Chand 		return (err);
45154dfc97bSShailend Chand 
45254dfc97bSShailend Chand 	priv->irq_db_indices = priv->irqs_db_mem.cpu_addr;
45354dfc97bSShailend Chand 	return (0);
45454dfc97bSShailend Chand }
45554dfc97bSShailend Chand 
45654dfc97bSShailend Chand static void
45754dfc97bSShailend Chand gve_free_irq_db_array(struct gve_priv *priv)
45854dfc97bSShailend Chand {
45954dfc97bSShailend Chand 	if (priv->irq_db_indices != NULL)
46054dfc97bSShailend Chand 		gve_dma_free_coherent(&priv->irqs_db_mem);
46154dfc97bSShailend Chand 	priv->irqs_db_mem = (struct gve_dma_handle){};
46254dfc97bSShailend Chand }
46354dfc97bSShailend Chand 
46454dfc97bSShailend Chand static void
46554dfc97bSShailend Chand gve_free_rings(struct gve_priv *priv)
46654dfc97bSShailend Chand {
46754dfc97bSShailend Chand 	gve_free_irqs(priv);
46854dfc97bSShailend Chand 	gve_free_tx_rings(priv);
46954dfc97bSShailend Chand 	gve_free_rx_rings(priv);
4702348ac89SShailend Chand 	if (gve_is_qpl(priv))
47154dfc97bSShailend Chand 		gve_free_qpls(priv);
47254dfc97bSShailend Chand }
47354dfc97bSShailend Chand 
47454dfc97bSShailend Chand static int
47554dfc97bSShailend Chand gve_alloc_rings(struct gve_priv *priv)
47654dfc97bSShailend Chand {
47754dfc97bSShailend Chand 	int err;
47854dfc97bSShailend Chand 
4792348ac89SShailend Chand 	if (gve_is_qpl(priv)) {
48054dfc97bSShailend Chand 		err = gve_alloc_qpls(priv);
48154dfc97bSShailend Chand 		if (err != 0)
48254dfc97bSShailend Chand 			goto abort;
483d438b4efSShailend Chand 	}
48454dfc97bSShailend Chand 
48554dfc97bSShailend Chand 	err = gve_alloc_rx_rings(priv);
48654dfc97bSShailend Chand 	if (err != 0)
48754dfc97bSShailend Chand 		goto abort;
48854dfc97bSShailend Chand 
48954dfc97bSShailend Chand 	err = gve_alloc_tx_rings(priv);
49054dfc97bSShailend Chand 	if (err != 0)
49154dfc97bSShailend Chand 		goto abort;
49254dfc97bSShailend Chand 
49354dfc97bSShailend Chand 	err = gve_alloc_irqs(priv);
49454dfc97bSShailend Chand 	if (err != 0)
49554dfc97bSShailend Chand 		goto abort;
49654dfc97bSShailend Chand 
49754dfc97bSShailend Chand 	return (0);
49854dfc97bSShailend Chand 
49954dfc97bSShailend Chand abort:
50054dfc97bSShailend Chand 	gve_free_rings(priv);
50154dfc97bSShailend Chand 	return (err);
50254dfc97bSShailend Chand }
50354dfc97bSShailend Chand 
50454dfc97bSShailend Chand static void
50554dfc97bSShailend Chand gve_deconfigure_resources(struct gve_priv *priv)
50654dfc97bSShailend Chand {
50754dfc97bSShailend Chand 	int err;
50854dfc97bSShailend Chand 
50954dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) {
51054dfc97bSShailend Chand 		err = gve_adminq_deconfigure_device_resources(priv);
51154dfc97bSShailend Chand 		if (err != 0) {
51254dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to deconfigure device resources: err=%d\n",
51354dfc97bSShailend Chand 			    err);
51454dfc97bSShailend Chand 			return;
51554dfc97bSShailend Chand 		}
51654dfc97bSShailend Chand 		if (bootverbose)
51754dfc97bSShailend Chand 			device_printf(priv->dev, "Deconfigured device resources\n");
51854dfc97bSShailend Chand 		gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK);
51954dfc97bSShailend Chand 	}
52054dfc97bSShailend Chand 
52154dfc97bSShailend Chand 	gve_free_irq_db_array(priv);
52254dfc97bSShailend Chand 	gve_free_counter_array(priv);
523d438b4efSShailend Chand 
524d438b4efSShailend Chand 	if (priv->ptype_lut_dqo) {
525d438b4efSShailend Chand 		free(priv->ptype_lut_dqo, M_GVE);
526d438b4efSShailend Chand 		priv->ptype_lut_dqo = NULL;
527d438b4efSShailend Chand 	}
52854dfc97bSShailend Chand }
52954dfc97bSShailend Chand 
53054dfc97bSShailend Chand static int
53154dfc97bSShailend Chand gve_configure_resources(struct gve_priv *priv)
53254dfc97bSShailend Chand {
53354dfc97bSShailend Chand 	int err;
53454dfc97bSShailend Chand 
53554dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK))
53654dfc97bSShailend Chand 		return (0);
53754dfc97bSShailend Chand 
53854dfc97bSShailend Chand 	err = gve_alloc_counter_array(priv);
53954dfc97bSShailend Chand 	if (err != 0)
54054dfc97bSShailend Chand 		return (err);
54154dfc97bSShailend Chand 
54254dfc97bSShailend Chand 	err = gve_alloc_irq_db_array(priv);
54354dfc97bSShailend Chand 	if (err != 0)
54454dfc97bSShailend Chand 		goto abort;
54554dfc97bSShailend Chand 
54654dfc97bSShailend Chand 	err = gve_adminq_configure_device_resources(priv);
54754dfc97bSShailend Chand 	if (err != 0) {
54854dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to configure device resources: err=%d\n",
54954dfc97bSShailend Chand 			      err);
55054dfc97bSShailend Chand 		err = (ENXIO);
55154dfc97bSShailend Chand 		goto abort;
55254dfc97bSShailend Chand 	}
55354dfc97bSShailend Chand 
554d438b4efSShailend Chand 	if (!gve_is_gqi(priv)) {
555d438b4efSShailend Chand 		priv->ptype_lut_dqo = malloc(sizeof(*priv->ptype_lut_dqo), M_GVE,
556d438b4efSShailend Chand 		    M_WAITOK | M_ZERO);
557d438b4efSShailend Chand 
558d438b4efSShailend Chand 		err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo);
559d438b4efSShailend Chand 		if (err != 0) {
560d438b4efSShailend Chand 			device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n",
561d438b4efSShailend Chand 			    err);
562d438b4efSShailend Chand 			goto abort;
563d438b4efSShailend Chand 		}
564d438b4efSShailend Chand 	}
565d438b4efSShailend Chand 
56654dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK);
56754dfc97bSShailend Chand 	if (bootverbose)
56854dfc97bSShailend Chand 		device_printf(priv->dev, "Configured device resources\n");
56954dfc97bSShailend Chand 	return (0);
57054dfc97bSShailend Chand 
57154dfc97bSShailend Chand abort:
57254dfc97bSShailend Chand 	gve_deconfigure_resources(priv);
57354dfc97bSShailend Chand 	return (err);
57454dfc97bSShailend Chand }
57554dfc97bSShailend Chand 
57654dfc97bSShailend Chand static void
57754dfc97bSShailend Chand gve_set_queue_cnts(struct gve_priv *priv)
57854dfc97bSShailend Chand {
57954dfc97bSShailend Chand 	priv->tx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_TX_QUEUES);
58054dfc97bSShailend Chand 	priv->rx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_RX_QUEUES);
58154dfc97bSShailend Chand 	priv->tx_cfg.num_queues = priv->tx_cfg.max_queues;
58254dfc97bSShailend Chand 	priv->rx_cfg.num_queues = priv->rx_cfg.max_queues;
58354dfc97bSShailend Chand 
58454dfc97bSShailend Chand 	if (priv->default_num_queues > 0) {
58554dfc97bSShailend Chand 		priv->tx_cfg.num_queues = MIN(priv->default_num_queues,
58654dfc97bSShailend Chand 		    priv->tx_cfg.num_queues);
58754dfc97bSShailend Chand 		priv->rx_cfg.num_queues = MIN(priv->default_num_queues,
58854dfc97bSShailend Chand 		    priv->rx_cfg.num_queues);
58954dfc97bSShailend Chand 	}
59054dfc97bSShailend Chand 
59154dfc97bSShailend Chand 	priv->num_queues = priv->tx_cfg.num_queues + priv->rx_cfg.num_queues;
59254dfc97bSShailend Chand 	priv->mgmt_msix_idx = priv->num_queues;
59354dfc97bSShailend Chand }
59454dfc97bSShailend Chand 
59554dfc97bSShailend Chand static int
59654dfc97bSShailend Chand gve_alloc_adminq_and_describe_device(struct gve_priv *priv)
59754dfc97bSShailend Chand {
59854dfc97bSShailend Chand 	int err;
59954dfc97bSShailend Chand 
60054dfc97bSShailend Chand 	if ((err = gve_adminq_alloc(priv)) != 0)
60154dfc97bSShailend Chand 		return (err);
60254dfc97bSShailend Chand 
60354dfc97bSShailend Chand 	if ((err = gve_verify_driver_compatibility(priv)) != 0) {
60454dfc97bSShailend Chand 		device_printf(priv->dev,
60554dfc97bSShailend Chand 		    "Failed to verify driver compatibility: err=%d\n", err);
60654dfc97bSShailend Chand 		goto abort;
60754dfc97bSShailend Chand 	}
60854dfc97bSShailend Chand 
60954dfc97bSShailend Chand 	if ((err = gve_adminq_describe_device(priv)) != 0)
61054dfc97bSShailend Chand 		goto abort;
61154dfc97bSShailend Chand 
61254dfc97bSShailend Chand 	gve_set_queue_cnts(priv);
61354dfc97bSShailend Chand 
61454dfc97bSShailend Chand 	priv->num_registered_pages = 0;
61554dfc97bSShailend Chand 	return (0);
61654dfc97bSShailend Chand 
61754dfc97bSShailend Chand abort:
61854dfc97bSShailend Chand 	gve_release_adminq(priv);
61954dfc97bSShailend Chand 	return (err);
62054dfc97bSShailend Chand }
62154dfc97bSShailend Chand 
62254dfc97bSShailend Chand void
62354dfc97bSShailend Chand gve_schedule_reset(struct gve_priv *priv)
62454dfc97bSShailend Chand {
62554dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET))
62654dfc97bSShailend Chand 		return;
62754dfc97bSShailend Chand 
62854dfc97bSShailend Chand 	device_printf(priv->dev, "Scheduling reset task!\n");
62954dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET);
63054dfc97bSShailend Chand 	taskqueue_enqueue(priv->service_tq, &priv->service_task);
63154dfc97bSShailend Chand }
63254dfc97bSShailend Chand 
63354dfc97bSShailend Chand static void
63454dfc97bSShailend Chand gve_destroy(struct gve_priv *priv)
63554dfc97bSShailend Chand {
63654dfc97bSShailend Chand 	gve_down(priv);
63754dfc97bSShailend Chand 	gve_deconfigure_resources(priv);
63854dfc97bSShailend Chand 	gve_release_adminq(priv);
63954dfc97bSShailend Chand }
64054dfc97bSShailend Chand 
64154dfc97bSShailend Chand static void
64254dfc97bSShailend Chand gve_restore(struct gve_priv *priv)
64354dfc97bSShailend Chand {
64454dfc97bSShailend Chand 	int err;
64554dfc97bSShailend Chand 
64654dfc97bSShailend Chand 	err = gve_adminq_alloc(priv);
64754dfc97bSShailend Chand 	if (err != 0)
64854dfc97bSShailend Chand 		goto abort;
64954dfc97bSShailend Chand 
65054dfc97bSShailend Chand 	err = gve_configure_resources(priv);
65154dfc97bSShailend Chand 	if (err != 0)
65254dfc97bSShailend Chand 		goto abort;
65354dfc97bSShailend Chand 
65454dfc97bSShailend Chand 	err = gve_up(priv);
65554dfc97bSShailend Chand 	if (err != 0)
65654dfc97bSShailend Chand 		goto abort;
65754dfc97bSShailend Chand 
65854dfc97bSShailend Chand 	return;
65954dfc97bSShailend Chand 
66054dfc97bSShailend Chand abort:
66154dfc97bSShailend Chand 	device_printf(priv->dev, "Restore failed!\n");
66254dfc97bSShailend Chand 	return;
66354dfc97bSShailend Chand }
66454dfc97bSShailend Chand 
66554dfc97bSShailend Chand static void
66654dfc97bSShailend Chand gve_handle_reset(struct gve_priv *priv)
66754dfc97bSShailend Chand {
66854dfc97bSShailend Chand 	if (!gve_get_state_flag(priv, GVE_STATE_FLAG_DO_RESET))
66954dfc97bSShailend Chand 		return;
67054dfc97bSShailend Chand 
67154dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_DO_RESET);
67254dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_IN_RESET);
67354dfc97bSShailend Chand 
67454dfc97bSShailend Chand 	GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
67554dfc97bSShailend Chand 
67654dfc97bSShailend Chand 	if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
67754dfc97bSShailend Chand 	if_link_state_change(priv->ifp, LINK_STATE_DOWN);
67854dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
67954dfc97bSShailend Chand 
68054dfc97bSShailend Chand 	/*
68154dfc97bSShailend Chand 	 * Releasing the adminq causes the NIC to destroy all resources
68254dfc97bSShailend Chand 	 * registered with it, so by clearing the flags beneath we cause
68354dfc97bSShailend Chand 	 * the subsequent gve_down call below to not attempt to tell the
68454dfc97bSShailend Chand 	 * NIC to destroy these resources again.
68554dfc97bSShailend Chand 	 *
68654dfc97bSShailend Chand 	 * The call to gve_down is needed in the first place to refresh
68754dfc97bSShailend Chand 	 * the state and the DMA-able memory within each driver ring.
68854dfc97bSShailend Chand 	 */
68954dfc97bSShailend Chand 	gve_release_adminq(priv);
69054dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK);
69154dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK);
69254dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_RX_RINGS_OK);
69354dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_TX_RINGS_OK);
69454dfc97bSShailend Chand 
69554dfc97bSShailend Chand 	gve_down(priv);
69654dfc97bSShailend Chand 	gve_restore(priv);
69754dfc97bSShailend Chand 
69854dfc97bSShailend Chand 	GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
69954dfc97bSShailend Chand 
70054dfc97bSShailend Chand 	priv->reset_cnt++;
70154dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_IN_RESET);
70254dfc97bSShailend Chand }
70354dfc97bSShailend Chand 
70454dfc97bSShailend Chand static void
70554dfc97bSShailend Chand gve_handle_link_status(struct gve_priv *priv)
70654dfc97bSShailend Chand {
70754dfc97bSShailend Chand 	uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS);
70854dfc97bSShailend Chand 	bool link_up = status & GVE_DEVICE_STATUS_LINK_STATUS;
70954dfc97bSShailend Chand 
71054dfc97bSShailend Chand 	if (link_up == gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP))
71154dfc97bSShailend Chand 		return;
71254dfc97bSShailend Chand 
71354dfc97bSShailend Chand 	if (link_up) {
71454dfc97bSShailend Chand 		if (bootverbose)
71554dfc97bSShailend Chand 			device_printf(priv->dev, "Device link is up.\n");
71654dfc97bSShailend Chand 		if_link_state_change(priv->ifp, LINK_STATE_UP);
71754dfc97bSShailend Chand 		gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
71854dfc97bSShailend Chand 	} else {
71954dfc97bSShailend Chand 		device_printf(priv->dev, "Device link is down.\n");
72054dfc97bSShailend Chand 		if_link_state_change(priv->ifp, LINK_STATE_DOWN);
72154dfc97bSShailend Chand 		gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
72254dfc97bSShailend Chand 	}
72354dfc97bSShailend Chand }
72454dfc97bSShailend Chand 
72554dfc97bSShailend Chand static void
72654dfc97bSShailend Chand gve_service_task(void *arg, int pending)
72754dfc97bSShailend Chand {
72854dfc97bSShailend Chand 	struct gve_priv *priv = (struct gve_priv *)arg;
72954dfc97bSShailend Chand 	uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS);
73054dfc97bSShailend Chand 
73154dfc97bSShailend Chand 	if (((GVE_DEVICE_STATUS_RESET_MASK & status) != 0) &&
73254dfc97bSShailend Chand 	    !gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) {
73354dfc97bSShailend Chand 		device_printf(priv->dev, "Device requested reset\n");
73454dfc97bSShailend Chand 		gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET);
73554dfc97bSShailend Chand 	}
73654dfc97bSShailend Chand 
73754dfc97bSShailend Chand 	gve_handle_reset(priv);
73854dfc97bSShailend Chand 	gve_handle_link_status(priv);
73954dfc97bSShailend Chand }
74054dfc97bSShailend Chand 
74154dfc97bSShailend Chand static int
74254dfc97bSShailend Chand gve_probe(device_t dev)
74354dfc97bSShailend Chand {
7441bbdfb0bSXin LI 	uint16_t deviceid, vendorid;
7451bbdfb0bSXin LI 	int i;
7461bbdfb0bSXin LI 
7471bbdfb0bSXin LI 	vendorid = pci_get_vendor(dev);
7481bbdfb0bSXin LI 	deviceid = pci_get_device(dev);
7491bbdfb0bSXin LI 
7501177a6c8SXin LI 	for (i = 0; i < nitems(gve_devs); i++) {
7511bbdfb0bSXin LI 		if (vendorid == gve_devs[i].vendor_id &&
7521bbdfb0bSXin LI 		    deviceid == gve_devs[i].device_id) {
7531bbdfb0bSXin LI 			device_set_desc(dev, gve_devs[i].name);
75454dfc97bSShailend Chand 			return (BUS_PROBE_DEFAULT);
75554dfc97bSShailend Chand 		}
7561bbdfb0bSXin LI 	}
75754dfc97bSShailend Chand 	return (ENXIO);
75854dfc97bSShailend Chand }
75954dfc97bSShailend Chand 
76054dfc97bSShailend Chand static void
76154dfc97bSShailend Chand gve_free_sys_res_mem(struct gve_priv *priv)
76254dfc97bSShailend Chand {
76354dfc97bSShailend Chand 	if (priv->msix_table != NULL)
76454dfc97bSShailend Chand 		bus_release_resource(priv->dev, SYS_RES_MEMORY,
76554dfc97bSShailend Chand 		    rman_get_rid(priv->msix_table), priv->msix_table);
76654dfc97bSShailend Chand 
76754dfc97bSShailend Chand 	if (priv->db_bar != NULL)
76854dfc97bSShailend Chand 		bus_release_resource(priv->dev, SYS_RES_MEMORY,
76954dfc97bSShailend Chand 		    rman_get_rid(priv->db_bar), priv->db_bar);
77054dfc97bSShailend Chand 
77154dfc97bSShailend Chand 	if (priv->reg_bar != NULL)
77254dfc97bSShailend Chand 		bus_release_resource(priv->dev, SYS_RES_MEMORY,
77354dfc97bSShailend Chand 		    rman_get_rid(priv->reg_bar), priv->reg_bar);
77454dfc97bSShailend Chand }
77554dfc97bSShailend Chand 
77654dfc97bSShailend Chand static int
77754dfc97bSShailend Chand gve_attach(device_t dev)
77854dfc97bSShailend Chand {
77954dfc97bSShailend Chand 	struct gve_priv *priv;
78054dfc97bSShailend Chand 	int rid;
78154dfc97bSShailend Chand 	int err;
78254dfc97bSShailend Chand 
783d438b4efSShailend Chand 	snprintf(gve_version, sizeof(gve_version), "%d.%d.%d",
784d438b4efSShailend Chand 	    GVE_VERSION_MAJOR, GVE_VERSION_MINOR, GVE_VERSION_SUB);
785d438b4efSShailend Chand 
78654dfc97bSShailend Chand 	priv = device_get_softc(dev);
78754dfc97bSShailend Chand 	priv->dev = dev;
78854dfc97bSShailend Chand 	GVE_IFACE_LOCK_INIT(priv->gve_iface_lock);
78954dfc97bSShailend Chand 
79054dfc97bSShailend Chand 	pci_enable_busmaster(dev);
79154dfc97bSShailend Chand 
79254dfc97bSShailend Chand 	rid = PCIR_BAR(GVE_REGISTER_BAR);
79354dfc97bSShailend Chand 	priv->reg_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
79454dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
79554dfc97bSShailend Chand 	if (priv->reg_bar == NULL) {
79654dfc97bSShailend Chand 		device_printf(dev, "Failed to allocate BAR0\n");
79754dfc97bSShailend Chand 		err = ENXIO;
79854dfc97bSShailend Chand 		goto abort;
79954dfc97bSShailend Chand 	}
80054dfc97bSShailend Chand 
80154dfc97bSShailend Chand 	rid = PCIR_BAR(GVE_DOORBELL_BAR);
80254dfc97bSShailend Chand 	priv->db_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
80354dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
80454dfc97bSShailend Chand 	if (priv->db_bar == NULL) {
80554dfc97bSShailend Chand 		device_printf(dev, "Failed to allocate BAR2\n");
80654dfc97bSShailend Chand 		err = ENXIO;
80754dfc97bSShailend Chand 		goto abort;
80854dfc97bSShailend Chand 	}
80954dfc97bSShailend Chand 
81054dfc97bSShailend Chand 	rid = pci_msix_table_bar(priv->dev);
81154dfc97bSShailend Chand 	priv->msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
81254dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
81354dfc97bSShailend Chand 	if (priv->msix_table == NULL) {
81454dfc97bSShailend Chand 		device_printf(dev, "Failed to allocate msix table\n");
81554dfc97bSShailend Chand 		err = ENXIO;
81654dfc97bSShailend Chand 		goto abort;
81754dfc97bSShailend Chand 	}
81854dfc97bSShailend Chand 
81954dfc97bSShailend Chand 	err = gve_alloc_adminq_and_describe_device(priv);
82054dfc97bSShailend Chand 	if (err != 0)
82154dfc97bSShailend Chand 		goto abort;
82254dfc97bSShailend Chand 
82354dfc97bSShailend Chand 	err = gve_configure_resources(priv);
82454dfc97bSShailend Chand 	if (err != 0)
82554dfc97bSShailend Chand 		goto abort;
82654dfc97bSShailend Chand 
82754dfc97bSShailend Chand 	err = gve_alloc_rings(priv);
82854dfc97bSShailend Chand 	if (err != 0)
82954dfc97bSShailend Chand 		goto abort;
83054dfc97bSShailend Chand 
831aa386085SZhenlei Huang 	gve_setup_ifnet(dev, priv);
83254dfc97bSShailend Chand 
83354dfc97bSShailend Chand 	priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK;
83454dfc97bSShailend Chand 
83554dfc97bSShailend Chand 	bus_write_multi_1(priv->reg_bar, DRIVER_VERSION, GVE_DRIVER_VERSION,
83654dfc97bSShailend Chand 	    sizeof(GVE_DRIVER_VERSION) - 1);
83754dfc97bSShailend Chand 
83854dfc97bSShailend Chand 	TASK_INIT(&priv->service_task, 0, gve_service_task, priv);
83954dfc97bSShailend Chand 	priv->service_tq = taskqueue_create("gve service", M_WAITOK | M_ZERO,
84054dfc97bSShailend Chand 	    taskqueue_thread_enqueue, &priv->service_tq);
84154dfc97bSShailend Chand 	taskqueue_start_threads(&priv->service_tq, 1, PI_NET, "%s service tq",
84254dfc97bSShailend Chand 	    device_get_nameunit(priv->dev));
84354dfc97bSShailend Chand 
84454dfc97bSShailend Chand         gve_setup_sysctl(priv);
84554dfc97bSShailend Chand 
84654dfc97bSShailend Chand 	if (bootverbose)
84754dfc97bSShailend Chand 		device_printf(priv->dev, "Successfully attached %s", GVE_DRIVER_VERSION);
84854dfc97bSShailend Chand 	return (0);
84954dfc97bSShailend Chand 
85054dfc97bSShailend Chand abort:
85154dfc97bSShailend Chand 	gve_free_rings(priv);
85254dfc97bSShailend Chand 	gve_deconfigure_resources(priv);
85354dfc97bSShailend Chand 	gve_release_adminq(priv);
85454dfc97bSShailend Chand 	gve_free_sys_res_mem(priv);
85554dfc97bSShailend Chand 	GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock);
85654dfc97bSShailend Chand 	return (err);
85754dfc97bSShailend Chand }
85854dfc97bSShailend Chand 
85954dfc97bSShailend Chand static int
86054dfc97bSShailend Chand gve_detach(device_t dev)
86154dfc97bSShailend Chand {
86254dfc97bSShailend Chand 	struct gve_priv *priv = device_get_softc(dev);
86354dfc97bSShailend Chand 	if_t ifp = priv->ifp;
864d412c076SJohn Baldwin 	int error;
865d412c076SJohn Baldwin 
866d412c076SJohn Baldwin 	error = bus_generic_detach(dev);
867d412c076SJohn Baldwin 	if (error != 0)
868d412c076SJohn Baldwin 		return (error);
86954dfc97bSShailend Chand 
87054dfc97bSShailend Chand 	ether_ifdetach(ifp);
87154dfc97bSShailend Chand 
87254dfc97bSShailend Chand 	GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
87354dfc97bSShailend Chand 	gve_destroy(priv);
87454dfc97bSShailend Chand 	GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
87554dfc97bSShailend Chand 
87654dfc97bSShailend Chand 	gve_free_rings(priv);
87754dfc97bSShailend Chand 	gve_free_sys_res_mem(priv);
87854dfc97bSShailend Chand 	GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock);
87954dfc97bSShailend Chand 
88054dfc97bSShailend Chand 	while (taskqueue_cancel(priv->service_tq, &priv->service_task, NULL))
88154dfc97bSShailend Chand 		taskqueue_drain(priv->service_tq, &priv->service_task);
88254dfc97bSShailend Chand 	taskqueue_free(priv->service_tq);
88354dfc97bSShailend Chand 
88454dfc97bSShailend Chand 	if_free(ifp);
885d412c076SJohn Baldwin 	return (0);
88654dfc97bSShailend Chand }
88754dfc97bSShailend Chand 
88854dfc97bSShailend Chand static device_method_t gve_methods[] = {
88954dfc97bSShailend Chand 	DEVMETHOD(device_probe, gve_probe),
89054dfc97bSShailend Chand 	DEVMETHOD(device_attach, gve_attach),
89154dfc97bSShailend Chand 	DEVMETHOD(device_detach, gve_detach),
89254dfc97bSShailend Chand 	DEVMETHOD_END
89354dfc97bSShailend Chand };
89454dfc97bSShailend Chand 
89554dfc97bSShailend Chand static driver_t gve_driver = {
89654dfc97bSShailend Chand 	"gve",
89754dfc97bSShailend Chand 	gve_methods,
89854dfc97bSShailend Chand 	sizeof(struct gve_priv)
89954dfc97bSShailend Chand };
90054dfc97bSShailend Chand 
90154dfc97bSShailend Chand #if __FreeBSD_version < 1301503
90254dfc97bSShailend Chand static devclass_t gve_devclass;
90354dfc97bSShailend Chand 
90454dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, gve_devclass, 0, 0);
90554dfc97bSShailend Chand #else
90654dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, 0, 0);
90754dfc97bSShailend Chand #endif
9081177a6c8SXin LI MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, gve, gve_devs,
9091177a6c8SXin LI     nitems(gve_devs));
910