xref: /freebsd/sys/dev/gve/gve_main.c (revision 031800c786823a9ad4c4d2f79f217d42dad3f5d1)
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*031800c7SJasper Tran O'Leary #define GVE_DRIVER_VERSION "GVE-FBSD-1.3.2\n"
365f62584aSShailend Chand #define GVE_VERSION_MAJOR 1
372348ac89SShailend Chand #define GVE_VERSION_MINOR 3
38*031800c7SJasper Tran O'Leary #define GVE_VERSION_SUB 2
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);
199909e2d7bSJasper Tran O'Leary 	const uint32_t max_problem_range = 8227;
200909e2d7bSJasper Tran O'Leary 	const uint32_t min_problem_range = 7822;
20154dfc97bSShailend Chand 	int err;
20254dfc97bSShailend Chand 
20354dfc97bSShailend Chand 	if ((new_mtu > priv->max_mtu) || (new_mtu < ETHERMIN)) {
20454dfc97bSShailend Chand 		device_printf(priv->dev, "Invalid new MTU setting. new mtu: %d max mtu: %d min mtu: %d\n",
20554dfc97bSShailend Chand 		    new_mtu, priv->max_mtu, ETHERMIN);
20654dfc97bSShailend Chand 		return (EINVAL);
20754dfc97bSShailend Chand 	}
20854dfc97bSShailend Chand 
209909e2d7bSJasper Tran O'Leary 	/*
210909e2d7bSJasper Tran O'Leary 	 * When hardware LRO is enabled in DQ mode, MTUs within the range
211909e2d7bSJasper Tran O'Leary 	 * [7822, 8227] trigger hardware issues which cause a drastic drop
212909e2d7bSJasper Tran O'Leary 	 * in throughput.
213909e2d7bSJasper Tran O'Leary 	 */
214909e2d7bSJasper Tran O'Leary 	if (!gve_is_gqi(priv) && !gve_disable_hw_lro &&
215909e2d7bSJasper Tran O'Leary 	    new_mtu >= min_problem_range && new_mtu <= max_problem_range) {
216909e2d7bSJasper Tran O'Leary 		device_printf(priv->dev,
217909e2d7bSJasper Tran O'Leary 		    "Cannot set to MTU to %d within the range [%d, %d] while hardware LRO is enabled\n",
218909e2d7bSJasper Tran O'Leary 		    new_mtu, min_problem_range, max_problem_range);
219909e2d7bSJasper Tran O'Leary 		return (EINVAL);
220909e2d7bSJasper Tran O'Leary 	}
221909e2d7bSJasper Tran O'Leary 
22254dfc97bSShailend Chand 	err = gve_adminq_set_mtu(priv, new_mtu);
22354dfc97bSShailend Chand 	if (err == 0) {
22454dfc97bSShailend Chand 		if (bootverbose)
22554dfc97bSShailend Chand 			device_printf(priv->dev, "MTU set to %d\n", new_mtu);
22654dfc97bSShailend Chand 		if_setmtu(ifp, new_mtu);
22754dfc97bSShailend Chand 	} else {
22854dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to set MTU to %d\n", new_mtu);
22954dfc97bSShailend Chand 	}
23054dfc97bSShailend Chand 
23154dfc97bSShailend Chand 	return (err);
23254dfc97bSShailend Chand }
23354dfc97bSShailend Chand 
23454dfc97bSShailend Chand static void
23554dfc97bSShailend Chand gve_init(void *arg)
23654dfc97bSShailend Chand {
23754dfc97bSShailend Chand 	struct gve_priv *priv = (struct gve_priv *)arg;
23854dfc97bSShailend Chand 
23954dfc97bSShailend Chand 	if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QUEUES_UP)) {
24054dfc97bSShailend Chand 		GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
24154dfc97bSShailend Chand 		gve_up(priv);
24254dfc97bSShailend Chand 		GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
24354dfc97bSShailend Chand 	}
24454dfc97bSShailend Chand }
24554dfc97bSShailend Chand 
24654dfc97bSShailend Chand static int
24754dfc97bSShailend Chand gve_ioctl(if_t ifp, u_long command, caddr_t data)
24854dfc97bSShailend Chand {
24954dfc97bSShailend Chand 	struct gve_priv *priv;
25054dfc97bSShailend Chand 	struct ifreq *ifr;
25154dfc97bSShailend Chand 	int rc = 0;
25254dfc97bSShailend Chand 
25354dfc97bSShailend Chand 	priv = if_getsoftc(ifp);
25454dfc97bSShailend Chand 	ifr = (struct ifreq *)data;
25554dfc97bSShailend Chand 
25654dfc97bSShailend Chand 	switch (command) {
25754dfc97bSShailend Chand 	case SIOCSIFMTU:
25854dfc97bSShailend Chand 		if (if_getmtu(ifp) == ifr->ifr_mtu)
25954dfc97bSShailend Chand 			break;
26054dfc97bSShailend Chand 		GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
26154dfc97bSShailend Chand 		gve_down(priv);
26254dfc97bSShailend Chand 		gve_set_mtu(ifp, ifr->ifr_mtu);
26354dfc97bSShailend Chand 		rc = gve_up(priv);
26454dfc97bSShailend Chand 		GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
26554dfc97bSShailend Chand 		break;
26654dfc97bSShailend Chand 
26754dfc97bSShailend Chand 	case SIOCSIFFLAGS:
26854dfc97bSShailend Chand 		if ((if_getflags(ifp) & IFF_UP) != 0) {
26954dfc97bSShailend Chand 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) {
27054dfc97bSShailend Chand 				GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
27154dfc97bSShailend Chand 				rc = gve_up(priv);
27254dfc97bSShailend Chand 				GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
27354dfc97bSShailend Chand 			}
27454dfc97bSShailend Chand 		} else {
27554dfc97bSShailend Chand 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) {
27654dfc97bSShailend Chand 				GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
27754dfc97bSShailend Chand 				gve_down(priv);
27854dfc97bSShailend Chand 				GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
27954dfc97bSShailend Chand 			}
28054dfc97bSShailend Chand 		}
28154dfc97bSShailend Chand 		break;
28254dfc97bSShailend Chand 
28354dfc97bSShailend Chand 	case SIOCSIFCAP:
28454dfc97bSShailend Chand 		if (ifr->ifr_reqcap == if_getcapenable(ifp))
28554dfc97bSShailend Chand 			break;
28654dfc97bSShailend Chand 		GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
28754dfc97bSShailend Chand 		gve_down(priv);
28854dfc97bSShailend Chand 		if_setcapenable(ifp, ifr->ifr_reqcap);
28954dfc97bSShailend Chand 		rc = gve_up(priv);
29054dfc97bSShailend Chand 		GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
29154dfc97bSShailend Chand 		break;
29254dfc97bSShailend Chand 
29354dfc97bSShailend Chand 	case SIOCSIFMEDIA:
29454dfc97bSShailend Chand 		/* FALLTHROUGH */
29554dfc97bSShailend Chand 	case SIOCGIFMEDIA:
29654dfc97bSShailend Chand 		rc = ifmedia_ioctl(ifp, ifr, &priv->media, command);
29754dfc97bSShailend Chand 		break;
29854dfc97bSShailend Chand 
29954dfc97bSShailend Chand 	default:
30054dfc97bSShailend Chand 		rc = ether_ioctl(ifp, command, data);
30154dfc97bSShailend Chand 		break;
30254dfc97bSShailend Chand 	}
30354dfc97bSShailend Chand 
30454dfc97bSShailend Chand 	return (rc);
30554dfc97bSShailend Chand }
30654dfc97bSShailend Chand 
30754dfc97bSShailend Chand static int
30854dfc97bSShailend Chand gve_media_change(if_t ifp)
30954dfc97bSShailend Chand {
31054dfc97bSShailend Chand 	struct gve_priv *priv = if_getsoftc(ifp);
31154dfc97bSShailend Chand 
31254dfc97bSShailend Chand 	device_printf(priv->dev, "Media change not supported\n");
31354dfc97bSShailend Chand 	return (0);
31454dfc97bSShailend Chand }
31554dfc97bSShailend Chand 
31654dfc97bSShailend Chand static void
31754dfc97bSShailend Chand gve_media_status(if_t ifp, struct ifmediareq *ifmr)
31854dfc97bSShailend Chand {
31954dfc97bSShailend Chand 	struct gve_priv *priv = if_getsoftc(ifp);
32054dfc97bSShailend Chand 
32154dfc97bSShailend Chand 	GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
32254dfc97bSShailend Chand 
32354dfc97bSShailend Chand 	ifmr->ifm_status = IFM_AVALID;
32454dfc97bSShailend Chand 	ifmr->ifm_active = IFM_ETHER;
32554dfc97bSShailend Chand 
32654dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP)) {
32754dfc97bSShailend Chand 		ifmr->ifm_status |= IFM_ACTIVE;
32854dfc97bSShailend Chand 		ifmr->ifm_active |= IFM_AUTO;
32954dfc97bSShailend Chand 	} else {
33054dfc97bSShailend Chand 		ifmr->ifm_active |= IFM_NONE;
33154dfc97bSShailend Chand 	}
33254dfc97bSShailend Chand 
33354dfc97bSShailend Chand 	GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
33454dfc97bSShailend Chand }
33554dfc97bSShailend Chand 
33654dfc97bSShailend Chand static uint64_t
33754dfc97bSShailend Chand gve_get_counter(if_t ifp, ift_counter cnt)
33854dfc97bSShailend Chand {
33954dfc97bSShailend Chand 	struct gve_priv *priv;
34054dfc97bSShailend Chand 	uint64_t rpackets = 0;
34154dfc97bSShailend Chand 	uint64_t tpackets = 0;
34254dfc97bSShailend Chand 	uint64_t rbytes = 0;
34354dfc97bSShailend Chand 	uint64_t tbytes = 0;
34454dfc97bSShailend Chand 	uint64_t rx_dropped_pkt = 0;
34554dfc97bSShailend Chand 	uint64_t tx_dropped_pkt = 0;
34654dfc97bSShailend Chand 
34754dfc97bSShailend Chand 	priv = if_getsoftc(ifp);
34854dfc97bSShailend Chand 
34954dfc97bSShailend Chand 	gve_accum_stats(priv, &rpackets, &rbytes, &rx_dropped_pkt, &tpackets,
35054dfc97bSShailend Chand 	    &tbytes, &tx_dropped_pkt);
35154dfc97bSShailend Chand 
35254dfc97bSShailend Chand 	switch (cnt) {
35354dfc97bSShailend Chand 	case IFCOUNTER_IPACKETS:
35454dfc97bSShailend Chand 		return (rpackets);
35554dfc97bSShailend Chand 
35654dfc97bSShailend Chand 	case IFCOUNTER_OPACKETS:
35754dfc97bSShailend Chand 		return (tpackets);
35854dfc97bSShailend Chand 
35954dfc97bSShailend Chand 	case IFCOUNTER_IBYTES:
36054dfc97bSShailend Chand 		return (rbytes);
36154dfc97bSShailend Chand 
36254dfc97bSShailend Chand 	case IFCOUNTER_OBYTES:
36354dfc97bSShailend Chand 		return (tbytes);
36454dfc97bSShailend Chand 
36554dfc97bSShailend Chand 	case IFCOUNTER_IQDROPS:
36654dfc97bSShailend Chand 		return (rx_dropped_pkt);
36754dfc97bSShailend Chand 
36854dfc97bSShailend Chand 	case IFCOUNTER_OQDROPS:
36954dfc97bSShailend Chand 		return (tx_dropped_pkt);
37054dfc97bSShailend Chand 
37154dfc97bSShailend Chand 	default:
37254dfc97bSShailend Chand 		return (if_get_counter_default(ifp, cnt));
37354dfc97bSShailend Chand 	}
37454dfc97bSShailend Chand }
37554dfc97bSShailend Chand 
376aa386085SZhenlei Huang static void
37754dfc97bSShailend Chand gve_setup_ifnet(device_t dev, struct gve_priv *priv)
37854dfc97bSShailend Chand {
37954dfc97bSShailend Chand 	int caps = 0;
38054dfc97bSShailend Chand 	if_t ifp;
38154dfc97bSShailend Chand 
38254dfc97bSShailend Chand 	ifp = priv->ifp = if_alloc(IFT_ETHER);
38354dfc97bSShailend Chand 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
38454dfc97bSShailend Chand 	if_setsoftc(ifp, priv);
38554dfc97bSShailend Chand 	if_setdev(ifp, dev);
38654dfc97bSShailend Chand 	if_setinitfn(ifp, gve_init);
38754dfc97bSShailend Chand 	if_setioctlfn(ifp, gve_ioctl);
38854dfc97bSShailend Chand 	if_settransmitfn(ifp, gve_xmit_ifp);
38954dfc97bSShailend Chand 	if_setqflushfn(ifp, gve_qflush);
39054dfc97bSShailend Chand 
391d438b4efSShailend Chand 	/*
392d438b4efSShailend Chand 	 * Set TSO limits, must match the arguments to bus_dma_tag_create
3932348ac89SShailend Chand 	 * when creating tx->dqo.buf_dmatag. Only applies to the RDA mode
394*031800c7SJasper Tran O'Leary 	 * because in QPL we copy the entire packet into the bounce buffer
3952348ac89SShailend Chand 	 * and thus it does not matter how fragmented the mbuf is.
396d438b4efSShailend Chand 	 */
3972348ac89SShailend Chand 	if (!gve_is_gqi(priv) && !gve_is_qpl(priv)) {
398d438b4efSShailend Chand 		if_sethwtsomaxsegcount(ifp, GVE_TX_MAX_DATA_DESCS_DQO);
399d438b4efSShailend Chand 		if_sethwtsomaxsegsize(ifp, GVE_TX_MAX_BUF_SIZE_DQO);
400d438b4efSShailend Chand 	}
4012348ac89SShailend Chand 	if_sethwtsomax(ifp, GVE_TSO_MAXSIZE_DQO);
402d438b4efSShailend Chand 
40354dfc97bSShailend Chand #if __FreeBSD_version >= 1400086
40454dfc97bSShailend Chand 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
40554dfc97bSShailend Chand #else
40654dfc97bSShailend Chand 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_KNOWSEPOCH);
40754dfc97bSShailend Chand #endif
40854dfc97bSShailend Chand 
40954dfc97bSShailend Chand 	ifmedia_init(&priv->media, IFM_IMASK, gve_media_change, gve_media_status);
41054dfc97bSShailend Chand 	if_setgetcounterfn(ifp, gve_get_counter);
41154dfc97bSShailend Chand 
41254dfc97bSShailend Chand 	caps = IFCAP_RXCSUM |
41354dfc97bSShailend Chand 	       IFCAP_TXCSUM |
41454dfc97bSShailend Chand 	       IFCAP_TXCSUM_IPV6 |
41554dfc97bSShailend Chand 	       IFCAP_TSO |
41654dfc97bSShailend Chand 	       IFCAP_LRO;
41754dfc97bSShailend Chand 
41854dfc97bSShailend Chand 	if ((priv->supported_features & GVE_SUP_JUMBO_FRAMES_MASK) != 0)
41954dfc97bSShailend Chand 		caps |= IFCAP_JUMBO_MTU;
42054dfc97bSShailend Chand 
42154dfc97bSShailend Chand 	if_setcapabilities(ifp, caps);
42254dfc97bSShailend Chand 	if_setcapenable(ifp, caps);
42354dfc97bSShailend Chand 
42454dfc97bSShailend Chand 	if (bootverbose)
42554dfc97bSShailend Chand 		device_printf(priv->dev, "Setting initial MTU to %d\n", priv->max_mtu);
42654dfc97bSShailend Chand 	if_setmtu(ifp, priv->max_mtu);
42754dfc97bSShailend Chand 
42854dfc97bSShailend Chand 	ether_ifattach(ifp, priv->mac);
42954dfc97bSShailend Chand 
43054dfc97bSShailend Chand 	ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
43154dfc97bSShailend Chand 	ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
43254dfc97bSShailend Chand }
43354dfc97bSShailend Chand 
43454dfc97bSShailend Chand static int
43554dfc97bSShailend Chand gve_alloc_counter_array(struct gve_priv *priv)
43654dfc97bSShailend Chand {
43754dfc97bSShailend Chand 	int err;
43854dfc97bSShailend Chand 
43954dfc97bSShailend Chand 	err = gve_dma_alloc_coherent(priv, sizeof(uint32_t) * priv->num_event_counters,
44054dfc97bSShailend Chand 	    PAGE_SIZE, &priv->counter_array_mem);
44154dfc97bSShailend Chand 	if (err != 0)
44254dfc97bSShailend Chand 		return (err);
44354dfc97bSShailend Chand 
44454dfc97bSShailend Chand 	priv->counters = priv->counter_array_mem.cpu_addr;
44554dfc97bSShailend Chand 	return (0);
44654dfc97bSShailend Chand }
44754dfc97bSShailend Chand 
44854dfc97bSShailend Chand static void
44954dfc97bSShailend Chand gve_free_counter_array(struct gve_priv *priv)
45054dfc97bSShailend Chand {
45154dfc97bSShailend Chand 	if (priv->counters != NULL)
45254dfc97bSShailend Chand 		gve_dma_free_coherent(&priv->counter_array_mem);
45354dfc97bSShailend Chand 	priv->counter_array_mem = (struct gve_dma_handle){};
45454dfc97bSShailend Chand }
45554dfc97bSShailend Chand 
45654dfc97bSShailend Chand static int
45754dfc97bSShailend Chand gve_alloc_irq_db_array(struct gve_priv *priv)
45854dfc97bSShailend Chand {
45954dfc97bSShailend Chand 	int err;
46054dfc97bSShailend Chand 
46154dfc97bSShailend Chand 	err = gve_dma_alloc_coherent(priv,
46254dfc97bSShailend Chand 	    sizeof(struct gve_irq_db) * (priv->num_queues), PAGE_SIZE,
46354dfc97bSShailend Chand 	    &priv->irqs_db_mem);
46454dfc97bSShailend Chand 	if (err != 0)
46554dfc97bSShailend Chand 		return (err);
46654dfc97bSShailend Chand 
46754dfc97bSShailend Chand 	priv->irq_db_indices = priv->irqs_db_mem.cpu_addr;
46854dfc97bSShailend Chand 	return (0);
46954dfc97bSShailend Chand }
47054dfc97bSShailend Chand 
47154dfc97bSShailend Chand static void
47254dfc97bSShailend Chand gve_free_irq_db_array(struct gve_priv *priv)
47354dfc97bSShailend Chand {
47454dfc97bSShailend Chand 	if (priv->irq_db_indices != NULL)
47554dfc97bSShailend Chand 		gve_dma_free_coherent(&priv->irqs_db_mem);
47654dfc97bSShailend Chand 	priv->irqs_db_mem = (struct gve_dma_handle){};
47754dfc97bSShailend Chand }
47854dfc97bSShailend Chand 
47954dfc97bSShailend Chand static void
48054dfc97bSShailend Chand gve_free_rings(struct gve_priv *priv)
48154dfc97bSShailend Chand {
48254dfc97bSShailend Chand 	gve_free_irqs(priv);
48354dfc97bSShailend Chand 	gve_free_tx_rings(priv);
48454dfc97bSShailend Chand 	gve_free_rx_rings(priv);
4852348ac89SShailend Chand 	if (gve_is_qpl(priv))
48654dfc97bSShailend Chand 		gve_free_qpls(priv);
48754dfc97bSShailend Chand }
48854dfc97bSShailend Chand 
48954dfc97bSShailend Chand static int
49054dfc97bSShailend Chand gve_alloc_rings(struct gve_priv *priv)
49154dfc97bSShailend Chand {
49254dfc97bSShailend Chand 	int err;
49354dfc97bSShailend Chand 
4942348ac89SShailend Chand 	if (gve_is_qpl(priv)) {
49554dfc97bSShailend Chand 		err = gve_alloc_qpls(priv);
49654dfc97bSShailend Chand 		if (err != 0)
49754dfc97bSShailend Chand 			goto abort;
498d438b4efSShailend Chand 	}
49954dfc97bSShailend Chand 
50054dfc97bSShailend Chand 	err = gve_alloc_rx_rings(priv);
50154dfc97bSShailend Chand 	if (err != 0)
50254dfc97bSShailend Chand 		goto abort;
50354dfc97bSShailend Chand 
50454dfc97bSShailend Chand 	err = gve_alloc_tx_rings(priv);
50554dfc97bSShailend Chand 	if (err != 0)
50654dfc97bSShailend Chand 		goto abort;
50754dfc97bSShailend Chand 
50854dfc97bSShailend Chand 	err = gve_alloc_irqs(priv);
50954dfc97bSShailend Chand 	if (err != 0)
51054dfc97bSShailend Chand 		goto abort;
51154dfc97bSShailend Chand 
51254dfc97bSShailend Chand 	return (0);
51354dfc97bSShailend Chand 
51454dfc97bSShailend Chand abort:
51554dfc97bSShailend Chand 	gve_free_rings(priv);
51654dfc97bSShailend Chand 	return (err);
51754dfc97bSShailend Chand }
51854dfc97bSShailend Chand 
51954dfc97bSShailend Chand static void
52062b2d0c3SJasper Tran O'Leary gve_deconfigure_and_free_device_resources(struct gve_priv *priv)
52154dfc97bSShailend Chand {
52254dfc97bSShailend Chand 	int err;
52354dfc97bSShailend Chand 
52454dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK)) {
52554dfc97bSShailend Chand 		err = gve_adminq_deconfigure_device_resources(priv);
52654dfc97bSShailend Chand 		if (err != 0) {
52754dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to deconfigure device resources: err=%d\n",
52854dfc97bSShailend Chand 			    err);
52954dfc97bSShailend Chand 			return;
53054dfc97bSShailend Chand 		}
53154dfc97bSShailend Chand 		if (bootverbose)
53254dfc97bSShailend Chand 			device_printf(priv->dev, "Deconfigured device resources\n");
53354dfc97bSShailend Chand 		gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK);
53454dfc97bSShailend Chand 	}
53554dfc97bSShailend Chand 
53654dfc97bSShailend Chand 	gve_free_irq_db_array(priv);
53754dfc97bSShailend Chand 	gve_free_counter_array(priv);
538d438b4efSShailend Chand 
539d438b4efSShailend Chand 	if (priv->ptype_lut_dqo) {
540d438b4efSShailend Chand 		free(priv->ptype_lut_dqo, M_GVE);
541d438b4efSShailend Chand 		priv->ptype_lut_dqo = NULL;
542d438b4efSShailend Chand 	}
54354dfc97bSShailend Chand }
54454dfc97bSShailend Chand 
54554dfc97bSShailend Chand static int
54662b2d0c3SJasper Tran O'Leary gve_alloc_and_configure_device_resources(struct gve_priv *priv)
54754dfc97bSShailend Chand {
54854dfc97bSShailend Chand 	int err;
54954dfc97bSShailend Chand 
55054dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK))
55154dfc97bSShailend Chand 		return (0);
55254dfc97bSShailend Chand 
55354dfc97bSShailend Chand 	err = gve_alloc_counter_array(priv);
55454dfc97bSShailend Chand 	if (err != 0)
55554dfc97bSShailend Chand 		return (err);
55654dfc97bSShailend Chand 
55754dfc97bSShailend Chand 	err = gve_alloc_irq_db_array(priv);
55854dfc97bSShailend Chand 	if (err != 0)
55954dfc97bSShailend Chand 		goto abort;
56054dfc97bSShailend Chand 
56154dfc97bSShailend Chand 	err = gve_adminq_configure_device_resources(priv);
56254dfc97bSShailend Chand 	if (err != 0) {
56354dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to configure device resources: err=%d\n",
56454dfc97bSShailend Chand 			      err);
56554dfc97bSShailend Chand 		err = (ENXIO);
56654dfc97bSShailend Chand 		goto abort;
56754dfc97bSShailend Chand 	}
56854dfc97bSShailend Chand 
569d438b4efSShailend Chand 	if (!gve_is_gqi(priv)) {
570d438b4efSShailend Chand 		priv->ptype_lut_dqo = malloc(sizeof(*priv->ptype_lut_dqo), M_GVE,
571d438b4efSShailend Chand 		    M_WAITOK | M_ZERO);
572d438b4efSShailend Chand 
573d438b4efSShailend Chand 		err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo);
574d438b4efSShailend Chand 		if (err != 0) {
575d438b4efSShailend Chand 			device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n",
576d438b4efSShailend Chand 			    err);
577d438b4efSShailend Chand 			goto abort;
578d438b4efSShailend Chand 		}
579d438b4efSShailend Chand 	}
580d438b4efSShailend Chand 
58154dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK);
58254dfc97bSShailend Chand 	if (bootverbose)
58354dfc97bSShailend Chand 		device_printf(priv->dev, "Configured device resources\n");
58454dfc97bSShailend Chand 	return (0);
58554dfc97bSShailend Chand 
58654dfc97bSShailend Chand abort:
58762b2d0c3SJasper Tran O'Leary 	gve_deconfigure_and_free_device_resources(priv);
58854dfc97bSShailend Chand 	return (err);
58954dfc97bSShailend Chand }
59054dfc97bSShailend Chand 
59154dfc97bSShailend Chand static void
59254dfc97bSShailend Chand gve_set_queue_cnts(struct gve_priv *priv)
59354dfc97bSShailend Chand {
59454dfc97bSShailend Chand 	priv->tx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_TX_QUEUES);
59554dfc97bSShailend Chand 	priv->rx_cfg.max_queues = gve_reg_bar_read_4(priv, MAX_RX_QUEUES);
59654dfc97bSShailend Chand 	priv->tx_cfg.num_queues = priv->tx_cfg.max_queues;
59754dfc97bSShailend Chand 	priv->rx_cfg.num_queues = priv->rx_cfg.max_queues;
59854dfc97bSShailend Chand 
59954dfc97bSShailend Chand 	if (priv->default_num_queues > 0) {
60054dfc97bSShailend Chand 		priv->tx_cfg.num_queues = MIN(priv->default_num_queues,
60154dfc97bSShailend Chand 		    priv->tx_cfg.num_queues);
60254dfc97bSShailend Chand 		priv->rx_cfg.num_queues = MIN(priv->default_num_queues,
60354dfc97bSShailend Chand 		    priv->rx_cfg.num_queues);
60454dfc97bSShailend Chand 	}
60554dfc97bSShailend Chand 
60654dfc97bSShailend Chand 	priv->num_queues = priv->tx_cfg.num_queues + priv->rx_cfg.num_queues;
60754dfc97bSShailend Chand 	priv->mgmt_msix_idx = priv->num_queues;
60854dfc97bSShailend Chand }
60954dfc97bSShailend Chand 
61054dfc97bSShailend Chand static int
61154dfc97bSShailend Chand gve_alloc_adminq_and_describe_device(struct gve_priv *priv)
61254dfc97bSShailend Chand {
61354dfc97bSShailend Chand 	int err;
61454dfc97bSShailend Chand 
61554dfc97bSShailend Chand 	if ((err = gve_adminq_alloc(priv)) != 0)
61654dfc97bSShailend Chand 		return (err);
61754dfc97bSShailend Chand 
61854dfc97bSShailend Chand 	if ((err = gve_verify_driver_compatibility(priv)) != 0) {
61954dfc97bSShailend Chand 		device_printf(priv->dev,
62054dfc97bSShailend Chand 		    "Failed to verify driver compatibility: err=%d\n", err);
62154dfc97bSShailend Chand 		goto abort;
62254dfc97bSShailend Chand 	}
62354dfc97bSShailend Chand 
62454dfc97bSShailend Chand 	if ((err = gve_adminq_describe_device(priv)) != 0)
62554dfc97bSShailend Chand 		goto abort;
62654dfc97bSShailend Chand 
62754dfc97bSShailend Chand 	gve_set_queue_cnts(priv);
62854dfc97bSShailend Chand 
62954dfc97bSShailend Chand 	priv->num_registered_pages = 0;
63054dfc97bSShailend Chand 	return (0);
63154dfc97bSShailend Chand 
63254dfc97bSShailend Chand abort:
63354dfc97bSShailend Chand 	gve_release_adminq(priv);
63454dfc97bSShailend Chand 	return (err);
63554dfc97bSShailend Chand }
63654dfc97bSShailend Chand 
63754dfc97bSShailend Chand void
63854dfc97bSShailend Chand gve_schedule_reset(struct gve_priv *priv)
63954dfc97bSShailend Chand {
64054dfc97bSShailend Chand 	if (gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET))
64154dfc97bSShailend Chand 		return;
64254dfc97bSShailend Chand 
64354dfc97bSShailend Chand 	device_printf(priv->dev, "Scheduling reset task!\n");
64454dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET);
64554dfc97bSShailend Chand 	taskqueue_enqueue(priv->service_tq, &priv->service_task);
64654dfc97bSShailend Chand }
64754dfc97bSShailend Chand 
64854dfc97bSShailend Chand static void
64954dfc97bSShailend Chand gve_destroy(struct gve_priv *priv)
65054dfc97bSShailend Chand {
65154dfc97bSShailend Chand 	gve_down(priv);
65262b2d0c3SJasper Tran O'Leary 	gve_deconfigure_and_free_device_resources(priv);
65354dfc97bSShailend Chand 	gve_release_adminq(priv);
65454dfc97bSShailend Chand }
65554dfc97bSShailend Chand 
65654dfc97bSShailend Chand static void
65754dfc97bSShailend Chand gve_restore(struct gve_priv *priv)
65854dfc97bSShailend Chand {
65954dfc97bSShailend Chand 	int err;
66054dfc97bSShailend Chand 
66154dfc97bSShailend Chand 	err = gve_adminq_alloc(priv);
66254dfc97bSShailend Chand 	if (err != 0)
66354dfc97bSShailend Chand 		goto abort;
66454dfc97bSShailend Chand 
66562b2d0c3SJasper Tran O'Leary 	err = gve_adminq_configure_device_resources(priv);
66662b2d0c3SJasper Tran O'Leary 	if (err != 0) {
66762b2d0c3SJasper Tran O'Leary 		device_printf(priv->dev, "Failed to configure device resources: err=%d\n",
66862b2d0c3SJasper Tran O'Leary 		    err);
66962b2d0c3SJasper Tran O'Leary 		err = (ENXIO);
67054dfc97bSShailend Chand 		goto abort;
67162b2d0c3SJasper Tran O'Leary 	}
67262b2d0c3SJasper Tran O'Leary 	if (!gve_is_gqi(priv)) {
67362b2d0c3SJasper Tran O'Leary 		err = gve_adminq_get_ptype_map_dqo(priv, priv->ptype_lut_dqo);
67462b2d0c3SJasper Tran O'Leary 		if (err != 0) {
67562b2d0c3SJasper Tran O'Leary 			device_printf(priv->dev, "Failed to configure ptype lut: err=%d\n",
67662b2d0c3SJasper Tran O'Leary 			    err);
67762b2d0c3SJasper Tran O'Leary 			goto abort;
67862b2d0c3SJasper Tran O'Leary 		}
67962b2d0c3SJasper Tran O'Leary 	}
68054dfc97bSShailend Chand 
68154dfc97bSShailend Chand 	err = gve_up(priv);
68254dfc97bSShailend Chand 	if (err != 0)
68354dfc97bSShailend Chand 		goto abort;
68454dfc97bSShailend Chand 
68554dfc97bSShailend Chand 	return;
68654dfc97bSShailend Chand 
68754dfc97bSShailend Chand abort:
68854dfc97bSShailend Chand 	device_printf(priv->dev, "Restore failed!\n");
68954dfc97bSShailend Chand 	return;
69054dfc97bSShailend Chand }
69154dfc97bSShailend Chand 
69254dfc97bSShailend Chand static void
69362b2d0c3SJasper Tran O'Leary gve_clear_device_resources(struct gve_priv *priv)
69462b2d0c3SJasper Tran O'Leary {
69562b2d0c3SJasper Tran O'Leary 	int i;
69662b2d0c3SJasper Tran O'Leary 
69762b2d0c3SJasper Tran O'Leary 	for (i = 0; i < priv->num_event_counters; i++)
69862b2d0c3SJasper Tran O'Leary 		priv->counters[i] = 0;
69962b2d0c3SJasper Tran O'Leary 	bus_dmamap_sync(priv->counter_array_mem.tag, priv->counter_array_mem.map,
70062b2d0c3SJasper Tran O'Leary 	    BUS_DMASYNC_PREWRITE);
70162b2d0c3SJasper Tran O'Leary 
70262b2d0c3SJasper Tran O'Leary 	for (i = 0; i < priv->num_queues; i++)
70362b2d0c3SJasper Tran O'Leary 		priv->irq_db_indices[i] = (struct gve_irq_db){};
70462b2d0c3SJasper Tran O'Leary 	bus_dmamap_sync(priv->irqs_db_mem.tag, priv->irqs_db_mem.map,
70562b2d0c3SJasper Tran O'Leary 	    BUS_DMASYNC_PREWRITE);
70662b2d0c3SJasper Tran O'Leary 
70762b2d0c3SJasper Tran O'Leary 	if (priv->ptype_lut_dqo)
70862b2d0c3SJasper Tran O'Leary 		*priv->ptype_lut_dqo = (struct gve_ptype_lut){0};
70962b2d0c3SJasper Tran O'Leary }
71062b2d0c3SJasper Tran O'Leary 
71162b2d0c3SJasper Tran O'Leary static void
71254dfc97bSShailend Chand gve_handle_reset(struct gve_priv *priv)
71354dfc97bSShailend Chand {
71454dfc97bSShailend Chand 	if (!gve_get_state_flag(priv, GVE_STATE_FLAG_DO_RESET))
71554dfc97bSShailend Chand 		return;
71654dfc97bSShailend Chand 
71754dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_DO_RESET);
71854dfc97bSShailend Chand 	gve_set_state_flag(priv, GVE_STATE_FLAG_IN_RESET);
71954dfc97bSShailend Chand 
72054dfc97bSShailend Chand 	GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
72154dfc97bSShailend Chand 
72254dfc97bSShailend Chand 	if_setdrvflagbits(priv->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
72354dfc97bSShailend Chand 	if_link_state_change(priv->ifp, LINK_STATE_DOWN);
72454dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
72554dfc97bSShailend Chand 
72654dfc97bSShailend Chand 	/*
72754dfc97bSShailend Chand 	 * Releasing the adminq causes the NIC to destroy all resources
72854dfc97bSShailend Chand 	 * registered with it, so by clearing the flags beneath we cause
72954dfc97bSShailend Chand 	 * the subsequent gve_down call below to not attempt to tell the
73054dfc97bSShailend Chand 	 * NIC to destroy these resources again.
73154dfc97bSShailend Chand 	 *
73254dfc97bSShailend Chand 	 * The call to gve_down is needed in the first place to refresh
73354dfc97bSShailend Chand 	 * the state and the DMA-able memory within each driver ring.
73454dfc97bSShailend Chand 	 */
73554dfc97bSShailend Chand 	gve_release_adminq(priv);
73654dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_RESOURCES_OK);
73754dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK);
73854dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_RX_RINGS_OK);
73954dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_TX_RINGS_OK);
74054dfc97bSShailend Chand 
74154dfc97bSShailend Chand 	gve_down(priv);
74262b2d0c3SJasper Tran O'Leary 	gve_clear_device_resources(priv);
74362b2d0c3SJasper Tran O'Leary 
74454dfc97bSShailend Chand 	gve_restore(priv);
74554dfc97bSShailend Chand 
74654dfc97bSShailend Chand 	GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
74754dfc97bSShailend Chand 
74854dfc97bSShailend Chand 	priv->reset_cnt++;
74954dfc97bSShailend Chand 	gve_clear_state_flag(priv, GVE_STATE_FLAG_IN_RESET);
75054dfc97bSShailend Chand }
75154dfc97bSShailend Chand 
75254dfc97bSShailend Chand static void
75354dfc97bSShailend Chand gve_handle_link_status(struct gve_priv *priv)
75454dfc97bSShailend Chand {
75554dfc97bSShailend Chand 	uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS);
75654dfc97bSShailend Chand 	bool link_up = status & GVE_DEVICE_STATUS_LINK_STATUS;
75754dfc97bSShailend Chand 
75854dfc97bSShailend Chand 	if (link_up == gve_get_state_flag(priv, GVE_STATE_FLAG_LINK_UP))
75954dfc97bSShailend Chand 		return;
76054dfc97bSShailend Chand 
76154dfc97bSShailend Chand 	if (link_up) {
76254dfc97bSShailend Chand 		if (bootverbose)
76354dfc97bSShailend Chand 			device_printf(priv->dev, "Device link is up.\n");
76454dfc97bSShailend Chand 		if_link_state_change(priv->ifp, LINK_STATE_UP);
76554dfc97bSShailend Chand 		gve_set_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
76654dfc97bSShailend Chand 	} else {
76754dfc97bSShailend Chand 		device_printf(priv->dev, "Device link is down.\n");
76854dfc97bSShailend Chand 		if_link_state_change(priv->ifp, LINK_STATE_DOWN);
76954dfc97bSShailend Chand 		gve_clear_state_flag(priv, GVE_STATE_FLAG_LINK_UP);
77054dfc97bSShailend Chand 	}
77154dfc97bSShailend Chand }
77254dfc97bSShailend Chand 
77354dfc97bSShailend Chand static void
77454dfc97bSShailend Chand gve_service_task(void *arg, int pending)
77554dfc97bSShailend Chand {
77654dfc97bSShailend Chand 	struct gve_priv *priv = (struct gve_priv *)arg;
77754dfc97bSShailend Chand 	uint32_t status = gve_reg_bar_read_4(priv, DEVICE_STATUS);
77854dfc97bSShailend Chand 
77954dfc97bSShailend Chand 	if (((GVE_DEVICE_STATUS_RESET_MASK & status) != 0) &&
78054dfc97bSShailend Chand 	    !gve_get_state_flag(priv, GVE_STATE_FLAG_IN_RESET)) {
78154dfc97bSShailend Chand 		device_printf(priv->dev, "Device requested reset\n");
78254dfc97bSShailend Chand 		gve_set_state_flag(priv, GVE_STATE_FLAG_DO_RESET);
78354dfc97bSShailend Chand 	}
78454dfc97bSShailend Chand 
78554dfc97bSShailend Chand 	gve_handle_reset(priv);
78654dfc97bSShailend Chand 	gve_handle_link_status(priv);
78754dfc97bSShailend Chand }
78854dfc97bSShailend Chand 
78954dfc97bSShailend Chand static int
79054dfc97bSShailend Chand gve_probe(device_t dev)
79154dfc97bSShailend Chand {
7921bbdfb0bSXin LI 	uint16_t deviceid, vendorid;
7931bbdfb0bSXin LI 	int i;
7941bbdfb0bSXin LI 
7951bbdfb0bSXin LI 	vendorid = pci_get_vendor(dev);
7961bbdfb0bSXin LI 	deviceid = pci_get_device(dev);
7971bbdfb0bSXin LI 
7981177a6c8SXin LI 	for (i = 0; i < nitems(gve_devs); i++) {
7991bbdfb0bSXin LI 		if (vendorid == gve_devs[i].vendor_id &&
8001bbdfb0bSXin LI 		    deviceid == gve_devs[i].device_id) {
8011bbdfb0bSXin LI 			device_set_desc(dev, gve_devs[i].name);
80254dfc97bSShailend Chand 			return (BUS_PROBE_DEFAULT);
80354dfc97bSShailend Chand 		}
8041bbdfb0bSXin LI 	}
80554dfc97bSShailend Chand 	return (ENXIO);
80654dfc97bSShailend Chand }
80754dfc97bSShailend Chand 
80854dfc97bSShailend Chand static void
80954dfc97bSShailend Chand gve_free_sys_res_mem(struct gve_priv *priv)
81054dfc97bSShailend Chand {
81154dfc97bSShailend Chand 	if (priv->msix_table != NULL)
81254dfc97bSShailend Chand 		bus_release_resource(priv->dev, SYS_RES_MEMORY,
81354dfc97bSShailend Chand 		    rman_get_rid(priv->msix_table), priv->msix_table);
81454dfc97bSShailend Chand 
81554dfc97bSShailend Chand 	if (priv->db_bar != NULL)
81654dfc97bSShailend Chand 		bus_release_resource(priv->dev, SYS_RES_MEMORY,
81754dfc97bSShailend Chand 		    rman_get_rid(priv->db_bar), priv->db_bar);
81854dfc97bSShailend Chand 
81954dfc97bSShailend Chand 	if (priv->reg_bar != NULL)
82054dfc97bSShailend Chand 		bus_release_resource(priv->dev, SYS_RES_MEMORY,
82154dfc97bSShailend Chand 		    rman_get_rid(priv->reg_bar), priv->reg_bar);
82254dfc97bSShailend Chand }
82354dfc97bSShailend Chand 
82454dfc97bSShailend Chand static int
82554dfc97bSShailend Chand gve_attach(device_t dev)
82654dfc97bSShailend Chand {
82754dfc97bSShailend Chand 	struct gve_priv *priv;
82854dfc97bSShailend Chand 	int rid;
82954dfc97bSShailend Chand 	int err;
83054dfc97bSShailend Chand 
831d438b4efSShailend Chand 	snprintf(gve_version, sizeof(gve_version), "%d.%d.%d",
832d438b4efSShailend Chand 	    GVE_VERSION_MAJOR, GVE_VERSION_MINOR, GVE_VERSION_SUB);
833d438b4efSShailend Chand 
83454dfc97bSShailend Chand 	priv = device_get_softc(dev);
83554dfc97bSShailend Chand 	priv->dev = dev;
83654dfc97bSShailend Chand 	GVE_IFACE_LOCK_INIT(priv->gve_iface_lock);
83754dfc97bSShailend Chand 
83854dfc97bSShailend Chand 	pci_enable_busmaster(dev);
83954dfc97bSShailend Chand 
84054dfc97bSShailend Chand 	rid = PCIR_BAR(GVE_REGISTER_BAR);
84154dfc97bSShailend Chand 	priv->reg_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
84254dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
84354dfc97bSShailend Chand 	if (priv->reg_bar == NULL) {
84454dfc97bSShailend Chand 		device_printf(dev, "Failed to allocate BAR0\n");
84554dfc97bSShailend Chand 		err = ENXIO;
84654dfc97bSShailend Chand 		goto abort;
84754dfc97bSShailend Chand 	}
84854dfc97bSShailend Chand 
84954dfc97bSShailend Chand 	rid = PCIR_BAR(GVE_DOORBELL_BAR);
85054dfc97bSShailend Chand 	priv->db_bar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
85154dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
85254dfc97bSShailend Chand 	if (priv->db_bar == NULL) {
85354dfc97bSShailend Chand 		device_printf(dev, "Failed to allocate BAR2\n");
85454dfc97bSShailend Chand 		err = ENXIO;
85554dfc97bSShailend Chand 		goto abort;
85654dfc97bSShailend Chand 	}
85754dfc97bSShailend Chand 
85854dfc97bSShailend Chand 	rid = pci_msix_table_bar(priv->dev);
85954dfc97bSShailend Chand 	priv->msix_table = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
86054dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
86154dfc97bSShailend Chand 	if (priv->msix_table == NULL) {
86254dfc97bSShailend Chand 		device_printf(dev, "Failed to allocate msix table\n");
86354dfc97bSShailend Chand 		err = ENXIO;
86454dfc97bSShailend Chand 		goto abort;
86554dfc97bSShailend Chand 	}
86654dfc97bSShailend Chand 
86754dfc97bSShailend Chand 	err = gve_alloc_adminq_and_describe_device(priv);
86854dfc97bSShailend Chand 	if (err != 0)
86954dfc97bSShailend Chand 		goto abort;
87054dfc97bSShailend Chand 
87162b2d0c3SJasper Tran O'Leary 	err = gve_alloc_and_configure_device_resources(priv);
87254dfc97bSShailend Chand 	if (err != 0)
87354dfc97bSShailend Chand 		goto abort;
87454dfc97bSShailend Chand 
87554dfc97bSShailend Chand 	err = gve_alloc_rings(priv);
87654dfc97bSShailend Chand 	if (err != 0)
87754dfc97bSShailend Chand 		goto abort;
87854dfc97bSShailend Chand 
879aa386085SZhenlei Huang 	gve_setup_ifnet(dev, priv);
88054dfc97bSShailend Chand 
88154dfc97bSShailend Chand 	priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK;
88254dfc97bSShailend Chand 
88354dfc97bSShailend Chand 	bus_write_multi_1(priv->reg_bar, DRIVER_VERSION, GVE_DRIVER_VERSION,
88454dfc97bSShailend Chand 	    sizeof(GVE_DRIVER_VERSION) - 1);
88554dfc97bSShailend Chand 
88654dfc97bSShailend Chand 	TASK_INIT(&priv->service_task, 0, gve_service_task, priv);
88754dfc97bSShailend Chand 	priv->service_tq = taskqueue_create("gve service", M_WAITOK | M_ZERO,
88854dfc97bSShailend Chand 	    taskqueue_thread_enqueue, &priv->service_tq);
88954dfc97bSShailend Chand 	taskqueue_start_threads(&priv->service_tq, 1, PI_NET, "%s service tq",
89054dfc97bSShailend Chand 	    device_get_nameunit(priv->dev));
89154dfc97bSShailend Chand 
89254dfc97bSShailend Chand         gve_setup_sysctl(priv);
89354dfc97bSShailend Chand 
89454dfc97bSShailend Chand 	if (bootverbose)
89554dfc97bSShailend Chand 		device_printf(priv->dev, "Successfully attached %s", GVE_DRIVER_VERSION);
89654dfc97bSShailend Chand 	return (0);
89754dfc97bSShailend Chand 
89854dfc97bSShailend Chand abort:
89954dfc97bSShailend Chand 	gve_free_rings(priv);
90062b2d0c3SJasper Tran O'Leary 	gve_deconfigure_and_free_device_resources(priv);
90154dfc97bSShailend Chand 	gve_release_adminq(priv);
90254dfc97bSShailend Chand 	gve_free_sys_res_mem(priv);
90354dfc97bSShailend Chand 	GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock);
90454dfc97bSShailend Chand 	return (err);
90554dfc97bSShailend Chand }
90654dfc97bSShailend Chand 
90754dfc97bSShailend Chand static int
90854dfc97bSShailend Chand gve_detach(device_t dev)
90954dfc97bSShailend Chand {
91054dfc97bSShailend Chand 	struct gve_priv *priv = device_get_softc(dev);
91154dfc97bSShailend Chand 	if_t ifp = priv->ifp;
912d412c076SJohn Baldwin 	int error;
913d412c076SJohn Baldwin 
914d412c076SJohn Baldwin 	error = bus_generic_detach(dev);
915d412c076SJohn Baldwin 	if (error != 0)
916d412c076SJohn Baldwin 		return (error);
91754dfc97bSShailend Chand 
91854dfc97bSShailend Chand 	ether_ifdetach(ifp);
91954dfc97bSShailend Chand 
92054dfc97bSShailend Chand 	GVE_IFACE_LOCK_LOCK(priv->gve_iface_lock);
92154dfc97bSShailend Chand 	gve_destroy(priv);
92254dfc97bSShailend Chand 	GVE_IFACE_LOCK_UNLOCK(priv->gve_iface_lock);
92354dfc97bSShailend Chand 
92454dfc97bSShailend Chand 	gve_free_rings(priv);
92554dfc97bSShailend Chand 	gve_free_sys_res_mem(priv);
92654dfc97bSShailend Chand 	GVE_IFACE_LOCK_DESTROY(priv->gve_iface_lock);
92754dfc97bSShailend Chand 
92854dfc97bSShailend Chand 	while (taskqueue_cancel(priv->service_tq, &priv->service_task, NULL))
92954dfc97bSShailend Chand 		taskqueue_drain(priv->service_tq, &priv->service_task);
93054dfc97bSShailend Chand 	taskqueue_free(priv->service_tq);
93154dfc97bSShailend Chand 
93254dfc97bSShailend Chand 	if_free(ifp);
933d412c076SJohn Baldwin 	return (0);
93454dfc97bSShailend Chand }
93554dfc97bSShailend Chand 
93654dfc97bSShailend Chand static device_method_t gve_methods[] = {
93754dfc97bSShailend Chand 	DEVMETHOD(device_probe, gve_probe),
93854dfc97bSShailend Chand 	DEVMETHOD(device_attach, gve_attach),
93954dfc97bSShailend Chand 	DEVMETHOD(device_detach, gve_detach),
94054dfc97bSShailend Chand 	DEVMETHOD_END
94154dfc97bSShailend Chand };
94254dfc97bSShailend Chand 
94354dfc97bSShailend Chand static driver_t gve_driver = {
94454dfc97bSShailend Chand 	"gve",
94554dfc97bSShailend Chand 	gve_methods,
94654dfc97bSShailend Chand 	sizeof(struct gve_priv)
94754dfc97bSShailend Chand };
94854dfc97bSShailend Chand 
94954dfc97bSShailend Chand #if __FreeBSD_version < 1301503
95054dfc97bSShailend Chand static devclass_t gve_devclass;
95154dfc97bSShailend Chand 
95254dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, gve_devclass, 0, 0);
95354dfc97bSShailend Chand #else
95454dfc97bSShailend Chand DRIVER_MODULE(gve, pci, gve_driver, 0, 0);
95554dfc97bSShailend Chand #endif
9561177a6c8SXin LI MODULE_PNP_INFO("U16:vendor;U16:device;D:#", pci, gve, gve_devs,
9571177a6c8SXin LI     nitems(gve_devs));
958