18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/module.h>
58c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
68c2ecf20Sopenharmony_ci#include <linux/aer.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "fm10k.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistatic const struct fm10k_info *fm10k_info_tbl[] = {
118c2ecf20Sopenharmony_ci	[fm10k_device_pf] = &fm10k_pf_info,
128c2ecf20Sopenharmony_ci	[fm10k_device_vf] = &fm10k_vf_info,
138c2ecf20Sopenharmony_ci};
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * fm10k_pci_tbl - PCI Device ID Table
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last
198c2ecf20Sopenharmony_ci * Last entry must be all 0s
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
228c2ecf20Sopenharmony_ci *   Class, Class Mask, private data (not used) }
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_cistatic const struct pci_device_id fm10k_pci_tbl[] = {
258c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), fm10k_device_pf },
268c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_QDA2), fm10k_device_pf },
278c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_SDI_FM10420_DA2), fm10k_device_pf },
288c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, FM10K_DEV_ID_VF), fm10k_device_vf },
298c2ecf20Sopenharmony_ci	/* required last entry */
308c2ecf20Sopenharmony_ci	{ 0, }
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, fm10k_pci_tbl);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciu16 fm10k_read_pci_cfg_word(struct fm10k_hw *hw, u32 reg)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = hw->back;
378c2ecf20Sopenharmony_ci	u16 value = 0;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (FM10K_REMOVED(hw->hw_addr))
408c2ecf20Sopenharmony_ci		return ~value;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	pci_read_config_word(interface->pdev, reg, &value);
438c2ecf20Sopenharmony_ci	if (value == 0xFFFF)
448c2ecf20Sopenharmony_ci		fm10k_write_flush(hw);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return value;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciu32 fm10k_read_reg(struct fm10k_hw *hw, int reg)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	u32 __iomem *hw_addr = READ_ONCE(hw->hw_addr);
528c2ecf20Sopenharmony_ci	u32 value = 0;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (FM10K_REMOVED(hw_addr))
558c2ecf20Sopenharmony_ci		return ~value;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	value = readl(&hw_addr[reg]);
588c2ecf20Sopenharmony_ci	if (!(~value) && (!reg || !(~readl(hw_addr)))) {
598c2ecf20Sopenharmony_ci		struct fm10k_intfc *interface = hw->back;
608c2ecf20Sopenharmony_ci		struct net_device *netdev = interface->netdev;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		hw->hw_addr = NULL;
638c2ecf20Sopenharmony_ci		netif_device_detach(netdev);
648c2ecf20Sopenharmony_ci		netdev_err(netdev, "PCIe link lost, device now detached\n");
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return value;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int fm10k_hw_ready(struct fm10k_intfc *interface)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	fm10k_write_flush(hw);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return FM10K_REMOVED(hw->hw_addr) ? -ENODEV : 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/**
808c2ecf20Sopenharmony_ci * fm10k_macvlan_schedule - Schedule MAC/VLAN queue task
818c2ecf20Sopenharmony_ci * @interface: fm10k private interface structure
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Schedule the MAC/VLAN queue monitor task. If the MAC/VLAN task cannot be
848c2ecf20Sopenharmony_ci * started immediately, request that it be restarted when possible.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_civoid fm10k_macvlan_schedule(struct fm10k_intfc *interface)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	/* Avoid processing the MAC/VLAN queue when the service task is
898c2ecf20Sopenharmony_ci	 * disabled, or when we're resetting the device.
908c2ecf20Sopenharmony_ci	 */
918c2ecf20Sopenharmony_ci	if (!test_bit(__FM10K_MACVLAN_DISABLE, interface->state) &&
928c2ecf20Sopenharmony_ci	    !test_and_set_bit(__FM10K_MACVLAN_SCHED, interface->state)) {
938c2ecf20Sopenharmony_ci		clear_bit(__FM10K_MACVLAN_REQUEST, interface->state);
948c2ecf20Sopenharmony_ci		/* We delay the actual start of execution in order to allow
958c2ecf20Sopenharmony_ci		 * multiple MAC/VLAN updates to accumulate before handling
968c2ecf20Sopenharmony_ci		 * them, and to allow some time to let the mailbox drain
978c2ecf20Sopenharmony_ci		 * between runs.
988c2ecf20Sopenharmony_ci		 */
998c2ecf20Sopenharmony_ci		queue_delayed_work(fm10k_workqueue,
1008c2ecf20Sopenharmony_ci				   &interface->macvlan_task, 10);
1018c2ecf20Sopenharmony_ci	} else {
1028c2ecf20Sopenharmony_ci		set_bit(__FM10K_MACVLAN_REQUEST, interface->state);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/**
1078c2ecf20Sopenharmony_ci * fm10k_stop_macvlan_task - Stop the MAC/VLAN queue monitor
1088c2ecf20Sopenharmony_ci * @interface: fm10k private interface structure
1098c2ecf20Sopenharmony_ci *
1108c2ecf20Sopenharmony_ci * Wait until the MAC/VLAN queue task has stopped, and cancel any future
1118c2ecf20Sopenharmony_ci * requests.
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_cistatic void fm10k_stop_macvlan_task(struct fm10k_intfc *interface)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	/* Disable the MAC/VLAN work item */
1168c2ecf20Sopenharmony_ci	set_bit(__FM10K_MACVLAN_DISABLE, interface->state);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* Make sure we waited until any current invocations have stopped */
1198c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&interface->macvlan_task);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* We set the __FM10K_MACVLAN_SCHED bit when we schedule the task.
1228c2ecf20Sopenharmony_ci	 * However, it may not be unset of the MAC/VLAN task never actually
1238c2ecf20Sopenharmony_ci	 * got a chance to run. Since we've canceled the task here, and it
1248c2ecf20Sopenharmony_ci	 * cannot be rescheuled right now, we need to ensure the scheduled bit
1258c2ecf20Sopenharmony_ci	 * gets unset.
1268c2ecf20Sopenharmony_ci	 */
1278c2ecf20Sopenharmony_ci	clear_bit(__FM10K_MACVLAN_SCHED, interface->state);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/**
1318c2ecf20Sopenharmony_ci * fm10k_resume_macvlan_task - Restart the MAC/VLAN queue monitor
1328c2ecf20Sopenharmony_ci * @interface: fm10k private interface structure
1338c2ecf20Sopenharmony_ci *
1348c2ecf20Sopenharmony_ci * Clear the __FM10K_MACVLAN_DISABLE bit and, if a request occurred, schedule
1358c2ecf20Sopenharmony_ci * the MAC/VLAN work monitor.
1368c2ecf20Sopenharmony_ci */
1378c2ecf20Sopenharmony_cistatic void fm10k_resume_macvlan_task(struct fm10k_intfc *interface)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	/* Re-enable the MAC/VLAN work item */
1408c2ecf20Sopenharmony_ci	clear_bit(__FM10K_MACVLAN_DISABLE, interface->state);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* We might have received a MAC/VLAN request while disabled. If so,
1438c2ecf20Sopenharmony_ci	 * kick off the queue now.
1448c2ecf20Sopenharmony_ci	 */
1458c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_MACVLAN_REQUEST, interface->state))
1468c2ecf20Sopenharmony_ci		fm10k_macvlan_schedule(interface);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_civoid fm10k_service_event_schedule(struct fm10k_intfc *interface)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	if (!test_bit(__FM10K_SERVICE_DISABLE, interface->state) &&
1528c2ecf20Sopenharmony_ci	    !test_and_set_bit(__FM10K_SERVICE_SCHED, interface->state)) {
1538c2ecf20Sopenharmony_ci		clear_bit(__FM10K_SERVICE_REQUEST, interface->state);
1548c2ecf20Sopenharmony_ci		queue_work(fm10k_workqueue, &interface->service_task);
1558c2ecf20Sopenharmony_ci	} else {
1568c2ecf20Sopenharmony_ci		set_bit(__FM10K_SERVICE_REQUEST, interface->state);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic void fm10k_service_event_complete(struct fm10k_intfc *interface)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	WARN_ON(!test_bit(__FM10K_SERVICE_SCHED, interface->state));
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/* flush memory to make sure state is correct before next watchog */
1658c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
1668c2ecf20Sopenharmony_ci	clear_bit(__FM10K_SERVICE_SCHED, interface->state);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* If a service event was requested since we started, immediately
1698c2ecf20Sopenharmony_ci	 * re-schedule now. This ensures we don't drop a request until the
1708c2ecf20Sopenharmony_ci	 * next timer event.
1718c2ecf20Sopenharmony_ci	 */
1728c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_SERVICE_REQUEST, interface->state))
1738c2ecf20Sopenharmony_ci		fm10k_service_event_schedule(interface);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void fm10k_stop_service_event(struct fm10k_intfc *interface)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	set_bit(__FM10K_SERVICE_DISABLE, interface->state);
1798c2ecf20Sopenharmony_ci	cancel_work_sync(&interface->service_task);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* It's possible that cancel_work_sync stopped the service task from
1828c2ecf20Sopenharmony_ci	 * running before it could actually start. In this case the
1838c2ecf20Sopenharmony_ci	 * __FM10K_SERVICE_SCHED bit will never be cleared. Since we know that
1848c2ecf20Sopenharmony_ci	 * the service task cannot be running at this point, we need to clear
1858c2ecf20Sopenharmony_ci	 * the scheduled bit, as otherwise the service task may never be
1868c2ecf20Sopenharmony_ci	 * restarted.
1878c2ecf20Sopenharmony_ci	 */
1888c2ecf20Sopenharmony_ci	clear_bit(__FM10K_SERVICE_SCHED, interface->state);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void fm10k_start_service_event(struct fm10k_intfc *interface)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	clear_bit(__FM10K_SERVICE_DISABLE, interface->state);
1948c2ecf20Sopenharmony_ci	fm10k_service_event_schedule(interface);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/**
1988c2ecf20Sopenharmony_ci * fm10k_service_timer - Timer Call-back
1998c2ecf20Sopenharmony_ci * @t: pointer to timer data
2008c2ecf20Sopenharmony_ci **/
2018c2ecf20Sopenharmony_cistatic void fm10k_service_timer(struct timer_list *t)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = from_timer(interface, t,
2048c2ecf20Sopenharmony_ci						   service_timer);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Reset the timer */
2078c2ecf20Sopenharmony_ci	mod_timer(&interface->service_timer, (HZ * 2) + jiffies);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	fm10k_service_event_schedule(interface);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/**
2138c2ecf20Sopenharmony_ci * fm10k_prepare_for_reset - Prepare the driver and device for a pending reset
2148c2ecf20Sopenharmony_ci * @interface: fm10k private data structure
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * This function prepares for a device reset by shutting as much down as we
2178c2ecf20Sopenharmony_ci * can. It does nothing and returns false if __FM10K_RESETTING was already set
2188c2ecf20Sopenharmony_ci * prior to calling this function. It returns true if it actually did work.
2198c2ecf20Sopenharmony_ci */
2208c2ecf20Sopenharmony_cistatic bool fm10k_prepare_for_reset(struct fm10k_intfc *interface)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* put off any impending NetWatchDogTimeout */
2258c2ecf20Sopenharmony_ci	netif_trans_update(netdev);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* Nothing to do if a reset is already in progress */
2288c2ecf20Sopenharmony_ci	if (test_and_set_bit(__FM10K_RESETTING, interface->state))
2298c2ecf20Sopenharmony_ci		return false;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* As the MAC/VLAN task will be accessing registers it must not be
2328c2ecf20Sopenharmony_ci	 * running while we reset. Although the task will not be scheduled
2338c2ecf20Sopenharmony_ci	 * once we start resetting it may already be running
2348c2ecf20Sopenharmony_ci	 */
2358c2ecf20Sopenharmony_ci	fm10k_stop_macvlan_task(interface);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	rtnl_lock();
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	fm10k_iov_suspend(interface->pdev);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (netif_running(netdev))
2428c2ecf20Sopenharmony_ci		fm10k_close(netdev);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	fm10k_mbx_free_irq(interface);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* free interrupts */
2478c2ecf20Sopenharmony_ci	fm10k_clear_queueing_scheme(interface);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	/* delay any future reset requests */
2508c2ecf20Sopenharmony_ci	interface->last_reset = jiffies + (10 * HZ);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	rtnl_unlock();
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return true;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic int fm10k_handle_reset(struct fm10k_intfc *interface)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
2608c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
2618c2ecf20Sopenharmony_ci	int err;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	WARN_ON(!test_bit(__FM10K_RESETTING, interface->state));
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	rtnl_lock();
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	pci_set_master(interface->pdev);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* reset and initialize the hardware so it is in a known state */
2708c2ecf20Sopenharmony_ci	err = hw->mac.ops.reset_hw(hw);
2718c2ecf20Sopenharmony_ci	if (err) {
2728c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev, "reset_hw failed: %d\n", err);
2738c2ecf20Sopenharmony_ci		goto reinit_err;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	err = hw->mac.ops.init_hw(hw);
2778c2ecf20Sopenharmony_ci	if (err) {
2788c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev, "init_hw failed: %d\n", err);
2798c2ecf20Sopenharmony_ci		goto reinit_err;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	err = fm10k_init_queueing_scheme(interface);
2838c2ecf20Sopenharmony_ci	if (err) {
2848c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev,
2858c2ecf20Sopenharmony_ci			"init_queueing_scheme failed: %d\n", err);
2868c2ecf20Sopenharmony_ci		goto reinit_err;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* re-associate interrupts */
2908c2ecf20Sopenharmony_ci	err = fm10k_mbx_request_irq(interface);
2918c2ecf20Sopenharmony_ci	if (err)
2928c2ecf20Sopenharmony_ci		goto err_mbx_irq;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	err = fm10k_hw_ready(interface);
2958c2ecf20Sopenharmony_ci	if (err)
2968c2ecf20Sopenharmony_ci		goto err_open;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	/* update hardware address for VFs if perm_addr has changed */
2998c2ecf20Sopenharmony_ci	if (hw->mac.type == fm10k_mac_vf) {
3008c2ecf20Sopenharmony_ci		if (is_valid_ether_addr(hw->mac.perm_addr)) {
3018c2ecf20Sopenharmony_ci			ether_addr_copy(hw->mac.addr, hw->mac.perm_addr);
3028c2ecf20Sopenharmony_ci			ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr);
3038c2ecf20Sopenharmony_ci			ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr);
3048c2ecf20Sopenharmony_ci			netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		if (hw->mac.vlan_override)
3088c2ecf20Sopenharmony_ci			netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
3098c2ecf20Sopenharmony_ci		else
3108c2ecf20Sopenharmony_ci			netdev->features |= NETIF_F_HW_VLAN_CTAG_RX;
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	err = netif_running(netdev) ? fm10k_open(netdev) : 0;
3148c2ecf20Sopenharmony_ci	if (err)
3158c2ecf20Sopenharmony_ci		goto err_open;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	fm10k_iov_resume(interface->pdev);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	rtnl_unlock();
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	fm10k_resume_macvlan_task(interface);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	clear_bit(__FM10K_RESETTING, interface->state);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return err;
3268c2ecf20Sopenharmony_cierr_open:
3278c2ecf20Sopenharmony_ci	fm10k_mbx_free_irq(interface);
3288c2ecf20Sopenharmony_cierr_mbx_irq:
3298c2ecf20Sopenharmony_ci	fm10k_clear_queueing_scheme(interface);
3308c2ecf20Sopenharmony_cireinit_err:
3318c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	rtnl_unlock();
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	clear_bit(__FM10K_RESETTING, interface->state);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return err;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic void fm10k_detach_subtask(struct fm10k_intfc *interface)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
3438c2ecf20Sopenharmony_ci	u32 __iomem *hw_addr;
3448c2ecf20Sopenharmony_ci	u32 value;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* do nothing if netdev is still present or hw_addr is set */
3478c2ecf20Sopenharmony_ci	if (netif_device_present(netdev) || interface->hw.hw_addr)
3488c2ecf20Sopenharmony_ci		return;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* We've lost the PCIe register space, and can no longer access the
3518c2ecf20Sopenharmony_ci	 * device. Shut everything except the detach subtask down and prepare
3528c2ecf20Sopenharmony_ci	 * to reset the device in case we recover. If we actually prepare for
3538c2ecf20Sopenharmony_ci	 * reset, indicate that we're detached.
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	if (fm10k_prepare_for_reset(interface))
3568c2ecf20Sopenharmony_ci		set_bit(__FM10K_RESET_DETACHED, interface->state);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* check the real address space to see if we've recovered */
3598c2ecf20Sopenharmony_ci	hw_addr = READ_ONCE(interface->uc_addr);
3608c2ecf20Sopenharmony_ci	value = readl(hw_addr);
3618c2ecf20Sopenharmony_ci	if (~value) {
3628c2ecf20Sopenharmony_ci		int err;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		/* Make sure the reset was initiated because we detached,
3658c2ecf20Sopenharmony_ci		 * otherwise we might race with a different reset flow.
3668c2ecf20Sopenharmony_ci		 */
3678c2ecf20Sopenharmony_ci		if (!test_and_clear_bit(__FM10K_RESET_DETACHED,
3688c2ecf20Sopenharmony_ci					interface->state))
3698c2ecf20Sopenharmony_ci			return;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		/* Restore the hardware address */
3728c2ecf20Sopenharmony_ci		interface->hw.hw_addr = interface->uc_addr;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		/* PCIe link has been restored, and the device is active
3758c2ecf20Sopenharmony_ci		 * again. Restore everything and reset the device.
3768c2ecf20Sopenharmony_ci		 */
3778c2ecf20Sopenharmony_ci		err = fm10k_handle_reset(interface);
3788c2ecf20Sopenharmony_ci		if (err) {
3798c2ecf20Sopenharmony_ci			netdev_err(netdev, "Unable to reset device: %d\n", err);
3808c2ecf20Sopenharmony_ci			interface->hw.hw_addr = NULL;
3818c2ecf20Sopenharmony_ci			return;
3828c2ecf20Sopenharmony_ci		}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		/* Re-attach the netdev */
3858c2ecf20Sopenharmony_ci		netif_device_attach(netdev);
3868c2ecf20Sopenharmony_ci		netdev_warn(netdev, "PCIe link restored, device now attached\n");
3878c2ecf20Sopenharmony_ci		return;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic void fm10k_reset_subtask(struct fm10k_intfc *interface)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	int err;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(FM10K_FLAG_RESET_REQUESTED,
3968c2ecf20Sopenharmony_ci				interface->flags))
3978c2ecf20Sopenharmony_ci		return;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/* If another thread has already prepared to reset the device, we
4008c2ecf20Sopenharmony_ci	 * should not attempt to handle a reset here, since we'd race with
4018c2ecf20Sopenharmony_ci	 * that thread. This may happen if we suspend the device or if the
4028c2ecf20Sopenharmony_ci	 * PCIe link is lost. In this case, we'll just ignore the RESET
4038c2ecf20Sopenharmony_ci	 * request, as it will (eventually) be taken care of when the thread
4048c2ecf20Sopenharmony_ci	 * which actually started the reset is finished.
4058c2ecf20Sopenharmony_ci	 */
4068c2ecf20Sopenharmony_ci	if (!fm10k_prepare_for_reset(interface))
4078c2ecf20Sopenharmony_ci		return;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	netdev_err(interface->netdev, "Reset interface\n");
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	err = fm10k_handle_reset(interface);
4128c2ecf20Sopenharmony_ci	if (err)
4138c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev,
4148c2ecf20Sopenharmony_ci			"fm10k_handle_reset failed: %d\n", err);
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci/**
4188c2ecf20Sopenharmony_ci * fm10k_configure_swpri_map - Configure Receive SWPRI to PC mapping
4198c2ecf20Sopenharmony_ci * @interface: board private structure
4208c2ecf20Sopenharmony_ci *
4218c2ecf20Sopenharmony_ci * Configure the SWPRI to PC mapping for the port.
4228c2ecf20Sopenharmony_ci **/
4238c2ecf20Sopenharmony_cistatic void fm10k_configure_swpri_map(struct fm10k_intfc *interface)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
4268c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
4278c2ecf20Sopenharmony_ci	int i;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* clear flag indicating update is needed */
4308c2ecf20Sopenharmony_ci	clear_bit(FM10K_FLAG_SWPRI_CONFIG, interface->flags);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* these registers are only available on the PF */
4338c2ecf20Sopenharmony_ci	if (hw->mac.type != fm10k_mac_pf)
4348c2ecf20Sopenharmony_ci		return;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* configure SWPRI to PC map */
4378c2ecf20Sopenharmony_ci	for (i = 0; i < FM10K_SWPRI_MAX; i++)
4388c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, FM10K_SWPRI_MAP(i),
4398c2ecf20Sopenharmony_ci				netdev_get_prio_tc_map(netdev, i));
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/**
4438c2ecf20Sopenharmony_ci * fm10k_watchdog_update_host_state - Update the link status based on host.
4448c2ecf20Sopenharmony_ci * @interface: board private structure
4458c2ecf20Sopenharmony_ci **/
4468c2ecf20Sopenharmony_cistatic void fm10k_watchdog_update_host_state(struct fm10k_intfc *interface)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
4498c2ecf20Sopenharmony_ci	s32 err;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_LINK_DOWN, interface->state)) {
4528c2ecf20Sopenharmony_ci		interface->host_ready = false;
4538c2ecf20Sopenharmony_ci		if (time_is_after_jiffies(interface->link_down_event))
4548c2ecf20Sopenharmony_ci			return;
4558c2ecf20Sopenharmony_ci		clear_bit(__FM10K_LINK_DOWN, interface->state);
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (test_bit(FM10K_FLAG_SWPRI_CONFIG, interface->flags)) {
4598c2ecf20Sopenharmony_ci		if (rtnl_trylock()) {
4608c2ecf20Sopenharmony_ci			fm10k_configure_swpri_map(interface);
4618c2ecf20Sopenharmony_ci			rtnl_unlock();
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/* lock the mailbox for transmit and receive */
4668c2ecf20Sopenharmony_ci	fm10k_mbx_lock(interface);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	err = hw->mac.ops.get_host_state(hw, &interface->host_ready);
4698c2ecf20Sopenharmony_ci	if (err && time_is_before_jiffies(interface->last_reset))
4708c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/* free the lock */
4738c2ecf20Sopenharmony_ci	fm10k_mbx_unlock(interface);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci/**
4778c2ecf20Sopenharmony_ci * fm10k_mbx_subtask - Process upstream and downstream mailboxes
4788c2ecf20Sopenharmony_ci * @interface: board private structure
4798c2ecf20Sopenharmony_ci *
4808c2ecf20Sopenharmony_ci * This function will process both the upstream and downstream mailboxes.
4818c2ecf20Sopenharmony_ci **/
4828c2ecf20Sopenharmony_cistatic void fm10k_mbx_subtask(struct fm10k_intfc *interface)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	/* If we're resetting, bail out */
4858c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_RESETTING, interface->state))
4868c2ecf20Sopenharmony_ci		return;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/* process upstream mailbox and update device state */
4898c2ecf20Sopenharmony_ci	fm10k_watchdog_update_host_state(interface);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* process downstream mailboxes */
4928c2ecf20Sopenharmony_ci	fm10k_iov_mbx(interface);
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci/**
4968c2ecf20Sopenharmony_ci * fm10k_watchdog_host_is_ready - Update netdev status based on host ready
4978c2ecf20Sopenharmony_ci * @interface: board private structure
4988c2ecf20Sopenharmony_ci **/
4998c2ecf20Sopenharmony_cistatic void fm10k_watchdog_host_is_ready(struct fm10k_intfc *interface)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/* only continue if link state is currently down */
5048c2ecf20Sopenharmony_ci	if (netif_carrier_ok(netdev))
5058c2ecf20Sopenharmony_ci		return;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	netif_info(interface, drv, netdev, "NIC Link is up\n");
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	netif_carrier_on(netdev);
5108c2ecf20Sopenharmony_ci	netif_tx_wake_all_queues(netdev);
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci/**
5148c2ecf20Sopenharmony_ci * fm10k_watchdog_host_not_ready - Update netdev status based on host not ready
5158c2ecf20Sopenharmony_ci * @interface: board private structure
5168c2ecf20Sopenharmony_ci **/
5178c2ecf20Sopenharmony_cistatic void fm10k_watchdog_host_not_ready(struct fm10k_intfc *interface)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* only continue if link state is currently up */
5228c2ecf20Sopenharmony_ci	if (!netif_carrier_ok(netdev))
5238c2ecf20Sopenharmony_ci		return;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	netif_info(interface, drv, netdev, "NIC Link is down\n");
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
5288c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(netdev);
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci/**
5328c2ecf20Sopenharmony_ci * fm10k_update_stats - Update the board statistics counters.
5338c2ecf20Sopenharmony_ci * @interface: board private structure
5348c2ecf20Sopenharmony_ci **/
5358c2ecf20Sopenharmony_civoid fm10k_update_stats(struct fm10k_intfc *interface)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct net_device_stats *net_stats = &interface->netdev->stats;
5388c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
5398c2ecf20Sopenharmony_ci	u64 hw_csum_tx_good = 0, hw_csum_rx_good = 0, rx_length_errors = 0;
5408c2ecf20Sopenharmony_ci	u64 rx_switch_errors = 0, rx_drops = 0, rx_pp_errors = 0;
5418c2ecf20Sopenharmony_ci	u64 rx_link_errors = 0;
5428c2ecf20Sopenharmony_ci	u64 rx_errors = 0, rx_csum_errors = 0, tx_csum_errors = 0;
5438c2ecf20Sopenharmony_ci	u64 restart_queue = 0, tx_busy = 0, alloc_failed = 0;
5448c2ecf20Sopenharmony_ci	u64 rx_bytes_nic = 0, rx_pkts_nic = 0, rx_drops_nic = 0;
5458c2ecf20Sopenharmony_ci	u64 tx_bytes_nic = 0, tx_pkts_nic = 0;
5468c2ecf20Sopenharmony_ci	u64 bytes, pkts;
5478c2ecf20Sopenharmony_ci	int i;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	/* ensure only one thread updates stats at a time */
5508c2ecf20Sopenharmony_ci	if (test_and_set_bit(__FM10K_UPDATING_STATS, interface->state))
5518c2ecf20Sopenharmony_ci		return;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* do not allow stats update via service task for next second */
5548c2ecf20Sopenharmony_ci	interface->next_stats_update = jiffies + HZ;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/* gather some stats to the interface struct that are per queue */
5578c2ecf20Sopenharmony_ci	for (bytes = 0, pkts = 0, i = 0; i < interface->num_tx_queues; i++) {
5588c2ecf20Sopenharmony_ci		struct fm10k_ring *tx_ring = READ_ONCE(interface->tx_ring[i]);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci		if (!tx_ring)
5618c2ecf20Sopenharmony_ci			continue;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		restart_queue += tx_ring->tx_stats.restart_queue;
5648c2ecf20Sopenharmony_ci		tx_busy += tx_ring->tx_stats.tx_busy;
5658c2ecf20Sopenharmony_ci		tx_csum_errors += tx_ring->tx_stats.csum_err;
5668c2ecf20Sopenharmony_ci		bytes += tx_ring->stats.bytes;
5678c2ecf20Sopenharmony_ci		pkts += tx_ring->stats.packets;
5688c2ecf20Sopenharmony_ci		hw_csum_tx_good += tx_ring->tx_stats.csum_good;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	interface->restart_queue = restart_queue;
5728c2ecf20Sopenharmony_ci	interface->tx_busy = tx_busy;
5738c2ecf20Sopenharmony_ci	net_stats->tx_bytes = bytes;
5748c2ecf20Sopenharmony_ci	net_stats->tx_packets = pkts;
5758c2ecf20Sopenharmony_ci	interface->tx_csum_errors = tx_csum_errors;
5768c2ecf20Sopenharmony_ci	interface->hw_csum_tx_good = hw_csum_tx_good;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* gather some stats to the interface struct that are per queue */
5798c2ecf20Sopenharmony_ci	for (bytes = 0, pkts = 0, i = 0; i < interface->num_rx_queues; i++) {
5808c2ecf20Sopenharmony_ci		struct fm10k_ring *rx_ring = READ_ONCE(interface->rx_ring[i]);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		if (!rx_ring)
5838c2ecf20Sopenharmony_ci			continue;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		bytes += rx_ring->stats.bytes;
5868c2ecf20Sopenharmony_ci		pkts += rx_ring->stats.packets;
5878c2ecf20Sopenharmony_ci		alloc_failed += rx_ring->rx_stats.alloc_failed;
5888c2ecf20Sopenharmony_ci		rx_csum_errors += rx_ring->rx_stats.csum_err;
5898c2ecf20Sopenharmony_ci		rx_errors += rx_ring->rx_stats.errors;
5908c2ecf20Sopenharmony_ci		hw_csum_rx_good += rx_ring->rx_stats.csum_good;
5918c2ecf20Sopenharmony_ci		rx_switch_errors += rx_ring->rx_stats.switch_errors;
5928c2ecf20Sopenharmony_ci		rx_drops += rx_ring->rx_stats.drops;
5938c2ecf20Sopenharmony_ci		rx_pp_errors += rx_ring->rx_stats.pp_errors;
5948c2ecf20Sopenharmony_ci		rx_link_errors += rx_ring->rx_stats.link_errors;
5958c2ecf20Sopenharmony_ci		rx_length_errors += rx_ring->rx_stats.length_errors;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	net_stats->rx_bytes = bytes;
5998c2ecf20Sopenharmony_ci	net_stats->rx_packets = pkts;
6008c2ecf20Sopenharmony_ci	interface->alloc_failed = alloc_failed;
6018c2ecf20Sopenharmony_ci	interface->rx_csum_errors = rx_csum_errors;
6028c2ecf20Sopenharmony_ci	interface->hw_csum_rx_good = hw_csum_rx_good;
6038c2ecf20Sopenharmony_ci	interface->rx_switch_errors = rx_switch_errors;
6048c2ecf20Sopenharmony_ci	interface->rx_drops = rx_drops;
6058c2ecf20Sopenharmony_ci	interface->rx_pp_errors = rx_pp_errors;
6068c2ecf20Sopenharmony_ci	interface->rx_link_errors = rx_link_errors;
6078c2ecf20Sopenharmony_ci	interface->rx_length_errors = rx_length_errors;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	hw->mac.ops.update_hw_stats(hw, &interface->stats);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	for (i = 0; i < hw->mac.max_queues; i++) {
6128c2ecf20Sopenharmony_ci		struct fm10k_hw_stats_q *q = &interface->stats.q[i];
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		tx_bytes_nic += q->tx_bytes.count;
6158c2ecf20Sopenharmony_ci		tx_pkts_nic += q->tx_packets.count;
6168c2ecf20Sopenharmony_ci		rx_bytes_nic += q->rx_bytes.count;
6178c2ecf20Sopenharmony_ci		rx_pkts_nic += q->rx_packets.count;
6188c2ecf20Sopenharmony_ci		rx_drops_nic += q->rx_drops.count;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	interface->tx_bytes_nic = tx_bytes_nic;
6228c2ecf20Sopenharmony_ci	interface->tx_packets_nic = tx_pkts_nic;
6238c2ecf20Sopenharmony_ci	interface->rx_bytes_nic = rx_bytes_nic;
6248c2ecf20Sopenharmony_ci	interface->rx_packets_nic = rx_pkts_nic;
6258c2ecf20Sopenharmony_ci	interface->rx_drops_nic = rx_drops_nic;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/* Fill out the OS statistics structure */
6288c2ecf20Sopenharmony_ci	net_stats->rx_errors = rx_errors;
6298c2ecf20Sopenharmony_ci	net_stats->rx_dropped = interface->stats.nodesc_drop.count;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	/* Update VF statistics */
6328c2ecf20Sopenharmony_ci	fm10k_iov_update_stats(interface);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	clear_bit(__FM10K_UPDATING_STATS, interface->state);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci/**
6388c2ecf20Sopenharmony_ci * fm10k_watchdog_flush_tx - flush queues on host not ready
6398c2ecf20Sopenharmony_ci * @interface: pointer to the device interface structure
6408c2ecf20Sopenharmony_ci **/
6418c2ecf20Sopenharmony_cistatic void fm10k_watchdog_flush_tx(struct fm10k_intfc *interface)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	int some_tx_pending = 0;
6448c2ecf20Sopenharmony_ci	int i;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/* nothing to do if carrier is up */
6478c2ecf20Sopenharmony_ci	if (netif_carrier_ok(interface->netdev))
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	for (i = 0; i < interface->num_tx_queues; i++) {
6518c2ecf20Sopenharmony_ci		struct fm10k_ring *tx_ring = interface->tx_ring[i];
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		if (tx_ring->next_to_use != tx_ring->next_to_clean) {
6548c2ecf20Sopenharmony_ci			some_tx_pending = 1;
6558c2ecf20Sopenharmony_ci			break;
6568c2ecf20Sopenharmony_ci		}
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* We've lost link, so the controller stops DMA, but we've got
6608c2ecf20Sopenharmony_ci	 * queued Tx work that's never going to get done, so reset
6618c2ecf20Sopenharmony_ci	 * controller to flush Tx.
6628c2ecf20Sopenharmony_ci	 */
6638c2ecf20Sopenharmony_ci	if (some_tx_pending)
6648c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci/**
6688c2ecf20Sopenharmony_ci * fm10k_watchdog_subtask - check and bring link up
6698c2ecf20Sopenharmony_ci * @interface: pointer to the device interface structure
6708c2ecf20Sopenharmony_ci **/
6718c2ecf20Sopenharmony_cistatic void fm10k_watchdog_subtask(struct fm10k_intfc *interface)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	/* if interface is down do nothing */
6748c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_DOWN, interface->state) ||
6758c2ecf20Sopenharmony_ci	    test_bit(__FM10K_RESETTING, interface->state))
6768c2ecf20Sopenharmony_ci		return;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (interface->host_ready)
6798c2ecf20Sopenharmony_ci		fm10k_watchdog_host_is_ready(interface);
6808c2ecf20Sopenharmony_ci	else
6818c2ecf20Sopenharmony_ci		fm10k_watchdog_host_not_ready(interface);
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	/* update stats only once every second */
6848c2ecf20Sopenharmony_ci	if (time_is_before_jiffies(interface->next_stats_update))
6858c2ecf20Sopenharmony_ci		fm10k_update_stats(interface);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	/* flush any uncompleted work */
6888c2ecf20Sopenharmony_ci	fm10k_watchdog_flush_tx(interface);
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci/**
6928c2ecf20Sopenharmony_ci * fm10k_check_hang_subtask - check for hung queues and dropped interrupts
6938c2ecf20Sopenharmony_ci * @interface: pointer to the device interface structure
6948c2ecf20Sopenharmony_ci *
6958c2ecf20Sopenharmony_ci * This function serves two purposes.  First it strobes the interrupt lines
6968c2ecf20Sopenharmony_ci * in order to make certain interrupts are occurring.  Secondly it sets the
6978c2ecf20Sopenharmony_ci * bits needed to check for TX hangs.  As a result we should immediately
6988c2ecf20Sopenharmony_ci * determine if a hang has occurred.
6998c2ecf20Sopenharmony_ci */
7008c2ecf20Sopenharmony_cistatic void fm10k_check_hang_subtask(struct fm10k_intfc *interface)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	/* If we're down or resetting, just bail */
7038c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_DOWN, interface->state) ||
7048c2ecf20Sopenharmony_ci	    test_bit(__FM10K_RESETTING, interface->state))
7058c2ecf20Sopenharmony_ci		return;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* rate limit tx hang checks to only once every 2 seconds */
7088c2ecf20Sopenharmony_ci	if (time_is_after_eq_jiffies(interface->next_tx_hang_check))
7098c2ecf20Sopenharmony_ci		return;
7108c2ecf20Sopenharmony_ci	interface->next_tx_hang_check = jiffies + (2 * HZ);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if (netif_carrier_ok(interface->netdev)) {
7138c2ecf20Sopenharmony_ci		int i;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci		/* Force detection of hung controller */
7168c2ecf20Sopenharmony_ci		for (i = 0; i < interface->num_tx_queues; i++)
7178c2ecf20Sopenharmony_ci			set_check_for_tx_hang(interface->tx_ring[i]);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		/* Rearm all in-use q_vectors for immediate firing */
7208c2ecf20Sopenharmony_ci		for (i = 0; i < interface->num_q_vectors; i++) {
7218c2ecf20Sopenharmony_ci			struct fm10k_q_vector *qv = interface->q_vector[i];
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci			if (!qv->tx.count && !qv->rx.count)
7248c2ecf20Sopenharmony_ci				continue;
7258c2ecf20Sopenharmony_ci			writel(FM10K_ITR_ENABLE | FM10K_ITR_PENDING2, qv->itr);
7268c2ecf20Sopenharmony_ci		}
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci/**
7318c2ecf20Sopenharmony_ci * fm10k_service_task - manages and runs subtasks
7328c2ecf20Sopenharmony_ci * @work: pointer to work_struct containing our data
7338c2ecf20Sopenharmony_ci **/
7348c2ecf20Sopenharmony_cistatic void fm10k_service_task(struct work_struct *work)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	interface = container_of(work, struct fm10k_intfc, service_task);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	/* Check whether we're detached first */
7418c2ecf20Sopenharmony_ci	fm10k_detach_subtask(interface);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	/* tasks run even when interface is down */
7448c2ecf20Sopenharmony_ci	fm10k_mbx_subtask(interface);
7458c2ecf20Sopenharmony_ci	fm10k_reset_subtask(interface);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* tasks only run when interface is up */
7488c2ecf20Sopenharmony_ci	fm10k_watchdog_subtask(interface);
7498c2ecf20Sopenharmony_ci	fm10k_check_hang_subtask(interface);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/* release lock on service events to allow scheduling next event */
7528c2ecf20Sopenharmony_ci	fm10k_service_event_complete(interface);
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci/**
7568c2ecf20Sopenharmony_ci * fm10k_macvlan_task - send queued MAC/VLAN requests to switch manager
7578c2ecf20Sopenharmony_ci * @work: pointer to work_struct containing our data
7588c2ecf20Sopenharmony_ci *
7598c2ecf20Sopenharmony_ci * This work item handles sending MAC/VLAN updates to the switch manager. When
7608c2ecf20Sopenharmony_ci * the interface is up, it will attempt to queue mailbox messages to the
7618c2ecf20Sopenharmony_ci * switch manager requesting updates for MAC/VLAN pairs. If the Tx fifo of the
7628c2ecf20Sopenharmony_ci * mailbox is full, it will reschedule itself to try again in a short while.
7638c2ecf20Sopenharmony_ci * This ensures that the driver does not overload the switch mailbox with too
7648c2ecf20Sopenharmony_ci * many simultaneous requests, causing an unnecessary reset.
7658c2ecf20Sopenharmony_ci **/
7668c2ecf20Sopenharmony_cistatic void fm10k_macvlan_task(struct work_struct *work)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct fm10k_macvlan_request *item;
7698c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
7708c2ecf20Sopenharmony_ci	struct delayed_work *dwork;
7718c2ecf20Sopenharmony_ci	struct list_head *requests;
7728c2ecf20Sopenharmony_ci	struct fm10k_hw *hw;
7738c2ecf20Sopenharmony_ci	unsigned long flags;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	dwork = to_delayed_work(work);
7768c2ecf20Sopenharmony_ci	interface = container_of(dwork, struct fm10k_intfc, macvlan_task);
7778c2ecf20Sopenharmony_ci	hw = &interface->hw;
7788c2ecf20Sopenharmony_ci	requests = &interface->macvlan_requests;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	do {
7818c2ecf20Sopenharmony_ci		/* Pop the first item off the list */
7828c2ecf20Sopenharmony_ci		spin_lock_irqsave(&interface->macvlan_lock, flags);
7838c2ecf20Sopenharmony_ci		item = list_first_entry_or_null(requests,
7848c2ecf20Sopenharmony_ci						struct fm10k_macvlan_request,
7858c2ecf20Sopenharmony_ci						list);
7868c2ecf20Sopenharmony_ci		if (item)
7878c2ecf20Sopenharmony_ci			list_del_init(&item->list);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&interface->macvlan_lock, flags);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		/* We have no more items to process */
7928c2ecf20Sopenharmony_ci		if (!item)
7938c2ecf20Sopenharmony_ci			goto done;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		fm10k_mbx_lock(interface);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		/* Check that we have plenty of space to send the message. We
7988c2ecf20Sopenharmony_ci		 * want to ensure that the mailbox stays low enough to avoid a
7998c2ecf20Sopenharmony_ci		 * change in the host state, otherwise we may see spurious
8008c2ecf20Sopenharmony_ci		 * link up / link down notifications.
8018c2ecf20Sopenharmony_ci		 */
8028c2ecf20Sopenharmony_ci		if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU + 5)) {
8038c2ecf20Sopenharmony_ci			hw->mbx.ops.process(hw, &hw->mbx);
8048c2ecf20Sopenharmony_ci			set_bit(__FM10K_MACVLAN_REQUEST, interface->state);
8058c2ecf20Sopenharmony_ci			fm10k_mbx_unlock(interface);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci			/* Put the request back on the list */
8088c2ecf20Sopenharmony_ci			spin_lock_irqsave(&interface->macvlan_lock, flags);
8098c2ecf20Sopenharmony_ci			list_add(&item->list, requests);
8108c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&interface->macvlan_lock, flags);
8118c2ecf20Sopenharmony_ci			break;
8128c2ecf20Sopenharmony_ci		}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		switch (item->type) {
8158c2ecf20Sopenharmony_ci		case FM10K_MC_MAC_REQUEST:
8168c2ecf20Sopenharmony_ci			hw->mac.ops.update_mc_addr(hw,
8178c2ecf20Sopenharmony_ci						   item->mac.glort,
8188c2ecf20Sopenharmony_ci						   item->mac.addr,
8198c2ecf20Sopenharmony_ci						   item->mac.vid,
8208c2ecf20Sopenharmony_ci						   item->set);
8218c2ecf20Sopenharmony_ci			break;
8228c2ecf20Sopenharmony_ci		case FM10K_UC_MAC_REQUEST:
8238c2ecf20Sopenharmony_ci			hw->mac.ops.update_uc_addr(hw,
8248c2ecf20Sopenharmony_ci						   item->mac.glort,
8258c2ecf20Sopenharmony_ci						   item->mac.addr,
8268c2ecf20Sopenharmony_ci						   item->mac.vid,
8278c2ecf20Sopenharmony_ci						   item->set,
8288c2ecf20Sopenharmony_ci						   0);
8298c2ecf20Sopenharmony_ci			break;
8308c2ecf20Sopenharmony_ci		case FM10K_VLAN_REQUEST:
8318c2ecf20Sopenharmony_ci			hw->mac.ops.update_vlan(hw,
8328c2ecf20Sopenharmony_ci						item->vlan.vid,
8338c2ecf20Sopenharmony_ci						item->vlan.vsi,
8348c2ecf20Sopenharmony_ci						item->set);
8358c2ecf20Sopenharmony_ci			break;
8368c2ecf20Sopenharmony_ci		default:
8378c2ecf20Sopenharmony_ci			break;
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		fm10k_mbx_unlock(interface);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci		/* Free the item now that we've sent the update */
8438c2ecf20Sopenharmony_ci		kfree(item);
8448c2ecf20Sopenharmony_ci	} while (true);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cidone:
8478c2ecf20Sopenharmony_ci	WARN_ON(!test_bit(__FM10K_MACVLAN_SCHED, interface->state));
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/* flush memory to make sure state is correct */
8508c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
8518c2ecf20Sopenharmony_ci	clear_bit(__FM10K_MACVLAN_SCHED, interface->state);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	/* If a MAC/VLAN request was scheduled since we started, we should
8548c2ecf20Sopenharmony_ci	 * re-schedule. However, there is no reason to re-schedule if there is
8558c2ecf20Sopenharmony_ci	 * no work to do.
8568c2ecf20Sopenharmony_ci	 */
8578c2ecf20Sopenharmony_ci	if (test_bit(__FM10K_MACVLAN_REQUEST, interface->state))
8588c2ecf20Sopenharmony_ci		fm10k_macvlan_schedule(interface);
8598c2ecf20Sopenharmony_ci}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci/**
8628c2ecf20Sopenharmony_ci * fm10k_configure_tx_ring - Configure Tx ring after Reset
8638c2ecf20Sopenharmony_ci * @interface: board private structure
8648c2ecf20Sopenharmony_ci * @ring: structure containing ring specific data
8658c2ecf20Sopenharmony_ci *
8668c2ecf20Sopenharmony_ci * Configure the Tx descriptor ring after a reset.
8678c2ecf20Sopenharmony_ci **/
8688c2ecf20Sopenharmony_cistatic void fm10k_configure_tx_ring(struct fm10k_intfc *interface,
8698c2ecf20Sopenharmony_ci				    struct fm10k_ring *ring)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
8728c2ecf20Sopenharmony_ci	u64 tdba = ring->dma;
8738c2ecf20Sopenharmony_ci	u32 size = ring->count * sizeof(struct fm10k_tx_desc);
8748c2ecf20Sopenharmony_ci	u32 txint = FM10K_INT_MAP_DISABLE;
8758c2ecf20Sopenharmony_ci	u32 txdctl = BIT(FM10K_TXDCTL_MAX_TIME_SHIFT) | FM10K_TXDCTL_ENABLE;
8768c2ecf20Sopenharmony_ci	u8 reg_idx = ring->reg_idx;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* disable queue to avoid issues while updating state */
8798c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TXDCTL(reg_idx), 0);
8808c2ecf20Sopenharmony_ci	fm10k_write_flush(hw);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* possible poll here to verify ring resources have been cleaned */
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	/* set location and size for descriptor ring */
8858c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TDBAL(reg_idx), tdba & DMA_BIT_MASK(32));
8868c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TDBAH(reg_idx), tdba >> 32);
8878c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TDLEN(reg_idx), size);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	/* reset head and tail pointers */
8908c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TDH(reg_idx), 0);
8918c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TDT(reg_idx), 0);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	/* store tail pointer */
8948c2ecf20Sopenharmony_ci	ring->tail = &interface->uc_addr[FM10K_TDT(reg_idx)];
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	/* reset ntu and ntc to place SW in sync with hardware */
8978c2ecf20Sopenharmony_ci	ring->next_to_clean = 0;
8988c2ecf20Sopenharmony_ci	ring->next_to_use = 0;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* Map interrupt */
9018c2ecf20Sopenharmony_ci	if (ring->q_vector) {
9028c2ecf20Sopenharmony_ci		txint = ring->q_vector->v_idx + NON_Q_VECTORS;
9038c2ecf20Sopenharmony_ci		txint |= FM10K_INT_MAP_TIMER0;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TXINT(reg_idx), txint);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	/* enable use of FTAG bit in Tx descriptor, register is RO for VF */
9098c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_PFVTCTL(reg_idx),
9108c2ecf20Sopenharmony_ci			FM10K_PFVTCTL_FTAG_DESC_ENABLE);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* Initialize XPS */
9138c2ecf20Sopenharmony_ci	if (!test_and_set_bit(__FM10K_TX_XPS_INIT_DONE, ring->state) &&
9148c2ecf20Sopenharmony_ci	    ring->q_vector)
9158c2ecf20Sopenharmony_ci		netif_set_xps_queue(ring->netdev,
9168c2ecf20Sopenharmony_ci				    &ring->q_vector->affinity_mask,
9178c2ecf20Sopenharmony_ci				    ring->queue_index);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	/* enable queue */
9208c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_TXDCTL(reg_idx), txdctl);
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci/**
9248c2ecf20Sopenharmony_ci * fm10k_enable_tx_ring - Verify Tx ring is enabled after configuration
9258c2ecf20Sopenharmony_ci * @interface: board private structure
9268c2ecf20Sopenharmony_ci * @ring: structure containing ring specific data
9278c2ecf20Sopenharmony_ci *
9288c2ecf20Sopenharmony_ci * Verify the Tx descriptor ring is ready for transmit.
9298c2ecf20Sopenharmony_ci **/
9308c2ecf20Sopenharmony_cistatic void fm10k_enable_tx_ring(struct fm10k_intfc *interface,
9318c2ecf20Sopenharmony_ci				 struct fm10k_ring *ring)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
9348c2ecf20Sopenharmony_ci	int wait_loop = 10;
9358c2ecf20Sopenharmony_ci	u32 txdctl;
9368c2ecf20Sopenharmony_ci	u8 reg_idx = ring->reg_idx;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	/* if we are already enabled just exit */
9398c2ecf20Sopenharmony_ci	if (fm10k_read_reg(hw, FM10K_TXDCTL(reg_idx)) & FM10K_TXDCTL_ENABLE)
9408c2ecf20Sopenharmony_ci		return;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/* poll to verify queue is enabled */
9438c2ecf20Sopenharmony_ci	do {
9448c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
9458c2ecf20Sopenharmony_ci		txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(reg_idx));
9468c2ecf20Sopenharmony_ci	} while (!(txdctl & FM10K_TXDCTL_ENABLE) && --wait_loop);
9478c2ecf20Sopenharmony_ci	if (!wait_loop)
9488c2ecf20Sopenharmony_ci		netif_err(interface, drv, interface->netdev,
9498c2ecf20Sopenharmony_ci			  "Could not enable Tx Queue %d\n", reg_idx);
9508c2ecf20Sopenharmony_ci}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci/**
9538c2ecf20Sopenharmony_ci * fm10k_configure_tx - Configure Transmit Unit after Reset
9548c2ecf20Sopenharmony_ci * @interface: board private structure
9558c2ecf20Sopenharmony_ci *
9568c2ecf20Sopenharmony_ci * Configure the Tx unit of the MAC after a reset.
9578c2ecf20Sopenharmony_ci **/
9588c2ecf20Sopenharmony_cistatic void fm10k_configure_tx(struct fm10k_intfc *interface)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	int i;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	/* Setup the HW Tx Head and Tail descriptor pointers */
9638c2ecf20Sopenharmony_ci	for (i = 0; i < interface->num_tx_queues; i++)
9648c2ecf20Sopenharmony_ci		fm10k_configure_tx_ring(interface, interface->tx_ring[i]);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/* poll here to verify that Tx rings are now enabled */
9678c2ecf20Sopenharmony_ci	for (i = 0; i < interface->num_tx_queues; i++)
9688c2ecf20Sopenharmony_ci		fm10k_enable_tx_ring(interface, interface->tx_ring[i]);
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci/**
9728c2ecf20Sopenharmony_ci * fm10k_configure_rx_ring - Configure Rx ring after Reset
9738c2ecf20Sopenharmony_ci * @interface: board private structure
9748c2ecf20Sopenharmony_ci * @ring: structure containing ring specific data
9758c2ecf20Sopenharmony_ci *
9768c2ecf20Sopenharmony_ci * Configure the Rx descriptor ring after a reset.
9778c2ecf20Sopenharmony_ci **/
9788c2ecf20Sopenharmony_cistatic void fm10k_configure_rx_ring(struct fm10k_intfc *interface,
9798c2ecf20Sopenharmony_ci				    struct fm10k_ring *ring)
9808c2ecf20Sopenharmony_ci{
9818c2ecf20Sopenharmony_ci	u64 rdba = ring->dma;
9828c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
9838c2ecf20Sopenharmony_ci	u32 size = ring->count * sizeof(union fm10k_rx_desc);
9848c2ecf20Sopenharmony_ci	u32 rxqctl, rxdctl = FM10K_RXDCTL_WRITE_BACK_MIN_DELAY;
9858c2ecf20Sopenharmony_ci	u32 srrctl = FM10K_SRRCTL_BUFFER_CHAINING_EN;
9868c2ecf20Sopenharmony_ci	u32 rxint = FM10K_INT_MAP_DISABLE;
9878c2ecf20Sopenharmony_ci	u8 rx_pause = interface->rx_pause;
9888c2ecf20Sopenharmony_ci	u8 reg_idx = ring->reg_idx;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	/* disable queue to avoid issues while updating state */
9918c2ecf20Sopenharmony_ci	rxqctl = fm10k_read_reg(hw, FM10K_RXQCTL(reg_idx));
9928c2ecf20Sopenharmony_ci	rxqctl &= ~FM10K_RXQCTL_ENABLE;
9938c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RXQCTL(reg_idx), rxqctl);
9948c2ecf20Sopenharmony_ci	fm10k_write_flush(hw);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	/* possible poll here to verify ring resources have been cleaned */
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	/* set location and size for descriptor ring */
9998c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RDBAL(reg_idx), rdba & DMA_BIT_MASK(32));
10008c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RDBAH(reg_idx), rdba >> 32);
10018c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RDLEN(reg_idx), size);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* reset head and tail pointers */
10048c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RDH(reg_idx), 0);
10058c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RDT(reg_idx), 0);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/* store tail pointer */
10088c2ecf20Sopenharmony_ci	ring->tail = &interface->uc_addr[FM10K_RDT(reg_idx)];
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	/* reset ntu and ntc to place SW in sync with hardware */
10118c2ecf20Sopenharmony_ci	ring->next_to_clean = 0;
10128c2ecf20Sopenharmony_ci	ring->next_to_use = 0;
10138c2ecf20Sopenharmony_ci	ring->next_to_alloc = 0;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	/* Configure the Rx buffer size for one buff without split */
10168c2ecf20Sopenharmony_ci	srrctl |= FM10K_RX_BUFSZ >> FM10K_SRRCTL_BSIZEPKT_SHIFT;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	/* Configure the Rx ring to suppress loopback packets */
10198c2ecf20Sopenharmony_ci	srrctl |= FM10K_SRRCTL_LOOPBACK_SUPPRESS;
10208c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_SRRCTL(reg_idx), srrctl);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	/* Enable drop on empty */
10238c2ecf20Sopenharmony_ci#ifdef CONFIG_DCB
10248c2ecf20Sopenharmony_ci	if (interface->pfc_en)
10258c2ecf20Sopenharmony_ci		rx_pause = interface->pfc_en;
10268c2ecf20Sopenharmony_ci#endif
10278c2ecf20Sopenharmony_ci	if (!(rx_pause & BIT(ring->qos_pc)))
10288c2ecf20Sopenharmony_ci		rxdctl |= FM10K_RXDCTL_DROP_ON_EMPTY;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RXDCTL(reg_idx), rxdctl);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	/* assign default VLAN to queue */
10338c2ecf20Sopenharmony_ci	ring->vid = hw->mac.default_vid;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	/* if we have an active VLAN, disable default VLAN ID */
10368c2ecf20Sopenharmony_ci	if (test_bit(hw->mac.default_vid, interface->active_vlans))
10378c2ecf20Sopenharmony_ci		ring->vid |= FM10K_VLAN_CLEAR;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	/* Map interrupt */
10408c2ecf20Sopenharmony_ci	if (ring->q_vector) {
10418c2ecf20Sopenharmony_ci		rxint = ring->q_vector->v_idx + NON_Q_VECTORS;
10428c2ecf20Sopenharmony_ci		rxint |= FM10K_INT_MAP_TIMER1;
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RXINT(reg_idx), rxint);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	/* enable queue */
10488c2ecf20Sopenharmony_ci	rxqctl = fm10k_read_reg(hw, FM10K_RXQCTL(reg_idx));
10498c2ecf20Sopenharmony_ci	rxqctl |= FM10K_RXQCTL_ENABLE;
10508c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_RXQCTL(reg_idx), rxqctl);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	/* place buffers on ring for receive data */
10538c2ecf20Sopenharmony_ci	fm10k_alloc_rx_buffers(ring, fm10k_desc_unused(ring));
10548c2ecf20Sopenharmony_ci}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci/**
10578c2ecf20Sopenharmony_ci * fm10k_update_rx_drop_en - Configures the drop enable bits for Rx rings
10588c2ecf20Sopenharmony_ci * @interface: board private structure
10598c2ecf20Sopenharmony_ci *
10608c2ecf20Sopenharmony_ci * Configure the drop enable bits for the Rx rings.
10618c2ecf20Sopenharmony_ci **/
10628c2ecf20Sopenharmony_civoid fm10k_update_rx_drop_en(struct fm10k_intfc *interface)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
10658c2ecf20Sopenharmony_ci	u8 rx_pause = interface->rx_pause;
10668c2ecf20Sopenharmony_ci	int i;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci#ifdef CONFIG_DCB
10698c2ecf20Sopenharmony_ci	if (interface->pfc_en)
10708c2ecf20Sopenharmony_ci		rx_pause = interface->pfc_en;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci#endif
10738c2ecf20Sopenharmony_ci	for (i = 0; i < interface->num_rx_queues; i++) {
10748c2ecf20Sopenharmony_ci		struct fm10k_ring *ring = interface->rx_ring[i];
10758c2ecf20Sopenharmony_ci		u32 rxdctl = FM10K_RXDCTL_WRITE_BACK_MIN_DELAY;
10768c2ecf20Sopenharmony_ci		u8 reg_idx = ring->reg_idx;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci		if (!(rx_pause & BIT(ring->qos_pc)))
10798c2ecf20Sopenharmony_ci			rxdctl |= FM10K_RXDCTL_DROP_ON_EMPTY;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, FM10K_RXDCTL(reg_idx), rxdctl);
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci/**
10868c2ecf20Sopenharmony_ci * fm10k_configure_dglort - Configure Receive DGLORT after reset
10878c2ecf20Sopenharmony_ci * @interface: board private structure
10888c2ecf20Sopenharmony_ci *
10898c2ecf20Sopenharmony_ci * Configure the DGLORT description and RSS tables.
10908c2ecf20Sopenharmony_ci **/
10918c2ecf20Sopenharmony_cistatic void fm10k_configure_dglort(struct fm10k_intfc *interface)
10928c2ecf20Sopenharmony_ci{
10938c2ecf20Sopenharmony_ci	struct fm10k_dglort_cfg dglort = { 0 };
10948c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
10958c2ecf20Sopenharmony_ci	int i;
10968c2ecf20Sopenharmony_ci	u32 mrqc;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	/* Fill out hash function seeds */
10998c2ecf20Sopenharmony_ci	for (i = 0; i < FM10K_RSSRK_SIZE; i++)
11008c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, FM10K_RSSRK(0, i), interface->rssrk[i]);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	/* Write RETA table to hardware */
11038c2ecf20Sopenharmony_ci	for (i = 0; i < FM10K_RETA_SIZE; i++)
11048c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, FM10K_RETA(0, i), interface->reta[i]);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	/* Generate RSS hash based on packet types, TCP/UDP
11078c2ecf20Sopenharmony_ci	 * port numbers and/or IPv4/v6 src and dst addresses
11088c2ecf20Sopenharmony_ci	 */
11098c2ecf20Sopenharmony_ci	mrqc = FM10K_MRQC_IPV4 |
11108c2ecf20Sopenharmony_ci	       FM10K_MRQC_TCP_IPV4 |
11118c2ecf20Sopenharmony_ci	       FM10K_MRQC_IPV6 |
11128c2ecf20Sopenharmony_ci	       FM10K_MRQC_TCP_IPV6;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	if (test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, interface->flags))
11158c2ecf20Sopenharmony_ci		mrqc |= FM10K_MRQC_UDP_IPV4;
11168c2ecf20Sopenharmony_ci	if (test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, interface->flags))
11178c2ecf20Sopenharmony_ci		mrqc |= FM10K_MRQC_UDP_IPV6;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_MRQC(0), mrqc);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* configure default DGLORT mapping for RSS/DCB */
11228c2ecf20Sopenharmony_ci	dglort.inner_rss = 1;
11238c2ecf20Sopenharmony_ci	dglort.rss_l = fls(interface->ring_feature[RING_F_RSS].mask);
11248c2ecf20Sopenharmony_ci	dglort.pc_l = fls(interface->ring_feature[RING_F_QOS].mask);
11258c2ecf20Sopenharmony_ci	hw->mac.ops.configure_dglort_map(hw, &dglort);
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	/* assign GLORT per queue for queue mapped testing */
11288c2ecf20Sopenharmony_ci	if (interface->glort_count > 64) {
11298c2ecf20Sopenharmony_ci		memset(&dglort, 0, sizeof(dglort));
11308c2ecf20Sopenharmony_ci		dglort.inner_rss = 1;
11318c2ecf20Sopenharmony_ci		dglort.glort = interface->glort + 64;
11328c2ecf20Sopenharmony_ci		dglort.idx = fm10k_dglort_pf_queue;
11338c2ecf20Sopenharmony_ci		dglort.queue_l = fls(interface->num_rx_queues - 1);
11348c2ecf20Sopenharmony_ci		hw->mac.ops.configure_dglort_map(hw, &dglort);
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	/* assign glort value for RSS/DCB specific to this interface */
11388c2ecf20Sopenharmony_ci	memset(&dglort, 0, sizeof(dglort));
11398c2ecf20Sopenharmony_ci	dglort.inner_rss = 1;
11408c2ecf20Sopenharmony_ci	dglort.glort = interface->glort;
11418c2ecf20Sopenharmony_ci	dglort.rss_l = fls(interface->ring_feature[RING_F_RSS].mask);
11428c2ecf20Sopenharmony_ci	dglort.pc_l = fls(interface->ring_feature[RING_F_QOS].mask);
11438c2ecf20Sopenharmony_ci	/* configure DGLORT mapping for RSS/DCB */
11448c2ecf20Sopenharmony_ci	dglort.idx = fm10k_dglort_pf_rss;
11458c2ecf20Sopenharmony_ci	if (interface->l2_accel)
11468c2ecf20Sopenharmony_ci		dglort.shared_l = fls(interface->l2_accel->size);
11478c2ecf20Sopenharmony_ci	hw->mac.ops.configure_dglort_map(hw, &dglort);
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci/**
11518c2ecf20Sopenharmony_ci * fm10k_configure_rx - Configure Receive Unit after Reset
11528c2ecf20Sopenharmony_ci * @interface: board private structure
11538c2ecf20Sopenharmony_ci *
11548c2ecf20Sopenharmony_ci * Configure the Rx unit of the MAC after a reset.
11558c2ecf20Sopenharmony_ci **/
11568c2ecf20Sopenharmony_cistatic void fm10k_configure_rx(struct fm10k_intfc *interface)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	int i;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	/* Configure SWPRI to PC map */
11618c2ecf20Sopenharmony_ci	fm10k_configure_swpri_map(interface);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	/* Configure RSS and DGLORT map */
11648c2ecf20Sopenharmony_ci	fm10k_configure_dglort(interface);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	/* Setup the HW Rx Head and Tail descriptor pointers */
11678c2ecf20Sopenharmony_ci	for (i = 0; i < interface->num_rx_queues; i++)
11688c2ecf20Sopenharmony_ci		fm10k_configure_rx_ring(interface, interface->rx_ring[i]);
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	/* possible poll here to verify that Rx rings are now enabled */
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_cistatic void fm10k_napi_enable_all(struct fm10k_intfc *interface)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	struct fm10k_q_vector *q_vector;
11768c2ecf20Sopenharmony_ci	int q_idx;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	for (q_idx = 0; q_idx < interface->num_q_vectors; q_idx++) {
11798c2ecf20Sopenharmony_ci		q_vector = interface->q_vector[q_idx];
11808c2ecf20Sopenharmony_ci		napi_enable(&q_vector->napi);
11818c2ecf20Sopenharmony_ci	}
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic irqreturn_t fm10k_msix_clean_rings(int __always_unused irq, void *data)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	struct fm10k_q_vector *q_vector = data;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (q_vector->rx.count || q_vector->tx.count)
11898c2ecf20Sopenharmony_ci		napi_schedule_irqoff(&q_vector->napi);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistatic irqreturn_t fm10k_msix_mbx_vf(int __always_unused irq, void *data)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = data;
11978c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
11988c2ecf20Sopenharmony_ci	struct fm10k_mbx_info *mbx = &hw->mbx;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	/* re-enable mailbox interrupt and indicate 20us delay */
12018c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_VFITR(FM10K_MBX_VECTOR),
12028c2ecf20Sopenharmony_ci			(FM10K_MBX_INT_DELAY >> hw->mac.itr_scale) |
12038c2ecf20Sopenharmony_ci			FM10K_ITR_ENABLE);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	/* service upstream mailbox */
12068c2ecf20Sopenharmony_ci	if (fm10k_mbx_trylock(interface)) {
12078c2ecf20Sopenharmony_ci		mbx->ops.process(hw, mbx);
12088c2ecf20Sopenharmony_ci		fm10k_mbx_unlock(interface);
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	hw->mac.get_host_state = true;
12128c2ecf20Sopenharmony_ci	fm10k_service_event_schedule(interface);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
12158c2ecf20Sopenharmony_ci}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci#define FM10K_ERR_MSG(type) case (type): error = #type; break
12188c2ecf20Sopenharmony_cistatic void fm10k_handle_fault(struct fm10k_intfc *interface, int type,
12198c2ecf20Sopenharmony_ci			       struct fm10k_fault *fault)
12208c2ecf20Sopenharmony_ci{
12218c2ecf20Sopenharmony_ci	struct pci_dev *pdev = interface->pdev;
12228c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
12238c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
12248c2ecf20Sopenharmony_ci	char *error;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	switch (type) {
12278c2ecf20Sopenharmony_ci	case FM10K_PCA_FAULT:
12288c2ecf20Sopenharmony_ci		switch (fault->type) {
12298c2ecf20Sopenharmony_ci		default:
12308c2ecf20Sopenharmony_ci			error = "Unknown PCA error";
12318c2ecf20Sopenharmony_ci			break;
12328c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_NO_FAULT);
12338c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_UNMAPPED_ADDR);
12348c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_BAD_QACCESS_PF);
12358c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_BAD_QACCESS_VF);
12368c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_MALICIOUS_REQ);
12378c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_POISONED_TLP);
12388c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(PCA_TLP_ABORT);
12398c2ecf20Sopenharmony_ci		}
12408c2ecf20Sopenharmony_ci		break;
12418c2ecf20Sopenharmony_ci	case FM10K_THI_FAULT:
12428c2ecf20Sopenharmony_ci		switch (fault->type) {
12438c2ecf20Sopenharmony_ci		default:
12448c2ecf20Sopenharmony_ci			error = "Unknown THI error";
12458c2ecf20Sopenharmony_ci			break;
12468c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(THI_NO_FAULT);
12478c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(THI_MAL_DIS_Q_FAULT);
12488c2ecf20Sopenharmony_ci		}
12498c2ecf20Sopenharmony_ci		break;
12508c2ecf20Sopenharmony_ci	case FM10K_FUM_FAULT:
12518c2ecf20Sopenharmony_ci		switch (fault->type) {
12528c2ecf20Sopenharmony_ci		default:
12538c2ecf20Sopenharmony_ci			error = "Unknown FUM error";
12548c2ecf20Sopenharmony_ci			break;
12558c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_NO_FAULT);
12568c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_UNMAPPED_ADDR);
12578c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_BAD_VF_QACCESS);
12588c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_ADD_DECODE_ERR);
12598c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_RO_ERROR);
12608c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_QPRC_CRC_ERROR);
12618c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_CSR_TIMEOUT);
12628c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_INVALID_TYPE);
12638c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_INVALID_LENGTH);
12648c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_INVALID_BE);
12658c2ecf20Sopenharmony_ci		FM10K_ERR_MSG(FUM_INVALID_ALIGN);
12668c2ecf20Sopenharmony_ci		}
12678c2ecf20Sopenharmony_ci		break;
12688c2ecf20Sopenharmony_ci	default:
12698c2ecf20Sopenharmony_ci		error = "Undocumented fault";
12708c2ecf20Sopenharmony_ci		break;
12718c2ecf20Sopenharmony_ci	}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	dev_warn(&pdev->dev,
12748c2ecf20Sopenharmony_ci		 "%s Address: 0x%llx SpecInfo: 0x%x Func: %02x.%0x\n",
12758c2ecf20Sopenharmony_ci		 error, fault->address, fault->specinfo,
12768c2ecf20Sopenharmony_ci		 PCI_SLOT(fault->func), PCI_FUNC(fault->func));
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	/* For VF faults, clear out the respective LPORT, reset the queue
12798c2ecf20Sopenharmony_ci	 * resources, and then reconnect to the mailbox. This allows the
12808c2ecf20Sopenharmony_ci	 * VF in question to resume behavior. For transient faults that are
12818c2ecf20Sopenharmony_ci	 * the result of non-malicious behavior this will log the fault and
12828c2ecf20Sopenharmony_ci	 * allow the VF to resume functionality. Obviously for malicious VFs
12838c2ecf20Sopenharmony_ci	 * they will be able to attempt malicious behavior again. In this
12848c2ecf20Sopenharmony_ci	 * case, the system administrator will need to step in and manually
12858c2ecf20Sopenharmony_ci	 * remove or disable the VF in question.
12868c2ecf20Sopenharmony_ci	 */
12878c2ecf20Sopenharmony_ci	if (fault->func && iov_data) {
12888c2ecf20Sopenharmony_ci		int vf = fault->func - 1;
12898c2ecf20Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[vf];
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		hw->iov.ops.reset_lport(hw, vf_info);
12928c2ecf20Sopenharmony_ci		hw->iov.ops.reset_resources(hw, vf_info);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		/* reset_lport disables the VF, so re-enable it */
12958c2ecf20Sopenharmony_ci		hw->iov.ops.set_lport(hw, vf_info, vf,
12968c2ecf20Sopenharmony_ci				      FM10K_VF_FLAG_MULTI_CAPABLE);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci		/* reset_resources will disconnect from the mbx  */
12998c2ecf20Sopenharmony_ci		vf_info->mbx.ops.connect(hw, &vf_info->mbx);
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cistatic void fm10k_report_fault(struct fm10k_intfc *interface, u32 eicr)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
13068c2ecf20Sopenharmony_ci	struct fm10k_fault fault = { 0 };
13078c2ecf20Sopenharmony_ci	int type, err;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	for (eicr &= FM10K_EICR_FAULT_MASK, type = FM10K_PCA_FAULT;
13108c2ecf20Sopenharmony_ci	     eicr;
13118c2ecf20Sopenharmony_ci	     eicr >>= 1, type += FM10K_FAULT_SIZE) {
13128c2ecf20Sopenharmony_ci		/* only check if there is an error reported */
13138c2ecf20Sopenharmony_ci		if (!(eicr & 0x1))
13148c2ecf20Sopenharmony_ci			continue;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		/* retrieve fault info */
13178c2ecf20Sopenharmony_ci		err = hw->mac.ops.get_fault(hw, type, &fault);
13188c2ecf20Sopenharmony_ci		if (err) {
13198c2ecf20Sopenharmony_ci			dev_err(&interface->pdev->dev,
13208c2ecf20Sopenharmony_ci				"error reading fault\n");
13218c2ecf20Sopenharmony_ci			continue;
13228c2ecf20Sopenharmony_ci		}
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci		fm10k_handle_fault(interface, type, &fault);
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_cistatic void fm10k_reset_drop_on_empty(struct fm10k_intfc *interface, u32 eicr)
13298c2ecf20Sopenharmony_ci{
13308c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
13318c2ecf20Sopenharmony_ci	const u32 rxdctl = FM10K_RXDCTL_WRITE_BACK_MIN_DELAY;
13328c2ecf20Sopenharmony_ci	u32 maxholdq;
13338c2ecf20Sopenharmony_ci	int q;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	if (!(eicr & FM10K_EICR_MAXHOLDTIME))
13368c2ecf20Sopenharmony_ci		return;
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	maxholdq = fm10k_read_reg(hw, FM10K_MAXHOLDQ(7));
13398c2ecf20Sopenharmony_ci	if (maxholdq)
13408c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, FM10K_MAXHOLDQ(7), maxholdq);
13418c2ecf20Sopenharmony_ci	for (q = 255;;) {
13428c2ecf20Sopenharmony_ci		if (maxholdq & BIT(31)) {
13438c2ecf20Sopenharmony_ci			if (q < FM10K_MAX_QUEUES_PF) {
13448c2ecf20Sopenharmony_ci				interface->rx_overrun_pf++;
13458c2ecf20Sopenharmony_ci				fm10k_write_reg(hw, FM10K_RXDCTL(q), rxdctl);
13468c2ecf20Sopenharmony_ci			} else {
13478c2ecf20Sopenharmony_ci				interface->rx_overrun_vf++;
13488c2ecf20Sopenharmony_ci			}
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci		maxholdq *= 2;
13528c2ecf20Sopenharmony_ci		if (!maxholdq)
13538c2ecf20Sopenharmony_ci			q &= ~(32 - 1);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci		if (!q)
13568c2ecf20Sopenharmony_ci			break;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci		if (q-- % 32)
13598c2ecf20Sopenharmony_ci			continue;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci		maxholdq = fm10k_read_reg(hw, FM10K_MAXHOLDQ(q / 32));
13628c2ecf20Sopenharmony_ci		if (maxholdq)
13638c2ecf20Sopenharmony_ci			fm10k_write_reg(hw, FM10K_MAXHOLDQ(q / 32), maxholdq);
13648c2ecf20Sopenharmony_ci	}
13658c2ecf20Sopenharmony_ci}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_cistatic irqreturn_t fm10k_msix_mbx_pf(int __always_unused irq, void *data)
13688c2ecf20Sopenharmony_ci{
13698c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = data;
13708c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
13718c2ecf20Sopenharmony_ci	struct fm10k_mbx_info *mbx = &hw->mbx;
13728c2ecf20Sopenharmony_ci	u32 eicr;
13738c2ecf20Sopenharmony_ci	s32 err = 0;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	/* unmask any set bits related to this interrupt */
13768c2ecf20Sopenharmony_ci	eicr = fm10k_read_reg(hw, FM10K_EICR);
13778c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_EICR, eicr & (FM10K_EICR_MAILBOX |
13788c2ecf20Sopenharmony_ci						FM10K_EICR_SWITCHREADY |
13798c2ecf20Sopenharmony_ci						FM10K_EICR_SWITCHNOTREADY));
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	/* report any faults found to the message log */
13828c2ecf20Sopenharmony_ci	fm10k_report_fault(interface, eicr);
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	/* reset any queues disabled due to receiver overrun */
13858c2ecf20Sopenharmony_ci	fm10k_reset_drop_on_empty(interface, eicr);
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	/* service mailboxes */
13888c2ecf20Sopenharmony_ci	if (fm10k_mbx_trylock(interface)) {
13898c2ecf20Sopenharmony_ci		err = mbx->ops.process(hw, mbx);
13908c2ecf20Sopenharmony_ci		/* handle VFLRE events */
13918c2ecf20Sopenharmony_ci		fm10k_iov_event(interface);
13928c2ecf20Sopenharmony_ci		fm10k_mbx_unlock(interface);
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (err == FM10K_ERR_RESET_REQUESTED)
13968c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	/* if switch toggled state we should reset GLORTs */
13998c2ecf20Sopenharmony_ci	if (eicr & FM10K_EICR_SWITCHNOTREADY) {
14008c2ecf20Sopenharmony_ci		/* force link down for at least 4 seconds */
14018c2ecf20Sopenharmony_ci		interface->link_down_event = jiffies + (4 * HZ);
14028c2ecf20Sopenharmony_ci		set_bit(__FM10K_LINK_DOWN, interface->state);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		/* reset dglort_map back to no config */
14058c2ecf20Sopenharmony_ci		hw->mac.dglort_map = FM10K_DGLORTMAP_NONE;
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	/* we should validate host state after interrupt event */
14098c2ecf20Sopenharmony_ci	hw->mac.get_host_state = true;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	/* validate host state, and handle VF mailboxes in the service task */
14128c2ecf20Sopenharmony_ci	fm10k_service_event_schedule(interface);
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	/* re-enable mailbox interrupt and indicate 20us delay */
14158c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_ITR(FM10K_MBX_VECTOR),
14168c2ecf20Sopenharmony_ci			(FM10K_MBX_INT_DELAY >> hw->mac.itr_scale) |
14178c2ecf20Sopenharmony_ci			FM10K_ITR_ENABLE);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_civoid fm10k_mbx_free_irq(struct fm10k_intfc *interface)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
14258c2ecf20Sopenharmony_ci	struct msix_entry *entry;
14268c2ecf20Sopenharmony_ci	int itr_reg;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	/* no mailbox IRQ to free if MSI-X is not enabled */
14298c2ecf20Sopenharmony_ci	if (!interface->msix_entries)
14308c2ecf20Sopenharmony_ci		return;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	entry = &interface->msix_entries[FM10K_MBX_VECTOR];
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	/* disconnect the mailbox */
14358c2ecf20Sopenharmony_ci	hw->mbx.ops.disconnect(hw, &hw->mbx);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	/* disable Mailbox cause */
14388c2ecf20Sopenharmony_ci	if (hw->mac.type == fm10k_mac_pf) {
14398c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, FM10K_EIMR,
14408c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(PCA_FAULT) |
14418c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(FUM_FAULT) |
14428c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(MAILBOX) |
14438c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(SWITCHREADY) |
14448c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(SWITCHNOTREADY) |
14458c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(SRAMERROR) |
14468c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(VFLR) |
14478c2ecf20Sopenharmony_ci				FM10K_EIMR_DISABLE(MAXHOLDTIME));
14488c2ecf20Sopenharmony_ci		itr_reg = FM10K_ITR(FM10K_MBX_VECTOR);
14498c2ecf20Sopenharmony_ci	} else {
14508c2ecf20Sopenharmony_ci		itr_reg = FM10K_VFITR(FM10K_MBX_VECTOR);
14518c2ecf20Sopenharmony_ci	}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, itr_reg, FM10K_ITR_MASK_SET);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	free_irq(entry->vector, interface);
14568c2ecf20Sopenharmony_ci}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_mac_addr(struct fm10k_hw *hw, u32 **results,
14598c2ecf20Sopenharmony_ci			      struct fm10k_mbx_info *mbx)
14608c2ecf20Sopenharmony_ci{
14618c2ecf20Sopenharmony_ci	bool vlan_override = hw->mac.vlan_override;
14628c2ecf20Sopenharmony_ci	u16 default_vid = hw->mac.default_vid;
14638c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
14648c2ecf20Sopenharmony_ci	s32 err;
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	err = fm10k_msg_mac_vlan_vf(hw, results, mbx);
14678c2ecf20Sopenharmony_ci	if (err)
14688c2ecf20Sopenharmony_ci		return err;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	interface = container_of(hw, struct fm10k_intfc, hw);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	/* MAC was changed so we need reset */
14738c2ecf20Sopenharmony_ci	if (is_valid_ether_addr(hw->mac.perm_addr) &&
14748c2ecf20Sopenharmony_ci	    !ether_addr_equal(hw->mac.perm_addr, hw->mac.addr))
14758c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	/* VLAN override was changed, or default VLAN changed */
14788c2ecf20Sopenharmony_ci	if ((vlan_override != hw->mac.vlan_override) ||
14798c2ecf20Sopenharmony_ci	    (default_vid != hw->mac.default_vid))
14808c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	return 0;
14838c2ecf20Sopenharmony_ci}
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci/* generic error handler for mailbox issues */
14868c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results,
14878c2ecf20Sopenharmony_ci			   struct fm10k_mbx_info __always_unused *mbx)
14888c2ecf20Sopenharmony_ci{
14898c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
14908c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	interface = container_of(hw, struct fm10k_intfc, hw);
14938c2ecf20Sopenharmony_ci	pdev = interface->pdev;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	dev_err(&pdev->dev, "Unknown message ID %u\n",
14968c2ecf20Sopenharmony_ci		**results & FM10K_TLV_ID_MASK);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	return 0;
14998c2ecf20Sopenharmony_ci}
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_cistatic const struct fm10k_msg_data vf_mbx_data[] = {
15028c2ecf20Sopenharmony_ci	FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
15038c2ecf20Sopenharmony_ci	FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_mbx_mac_addr),
15048c2ecf20Sopenharmony_ci	FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf),
15058c2ecf20Sopenharmony_ci	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_mbx_error),
15068c2ecf20Sopenharmony_ci};
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_cistatic int fm10k_mbx_request_irq_vf(struct fm10k_intfc *interface)
15098c2ecf20Sopenharmony_ci{
15108c2ecf20Sopenharmony_ci	struct msix_entry *entry = &interface->msix_entries[FM10K_MBX_VECTOR];
15118c2ecf20Sopenharmony_ci	struct net_device *dev = interface->netdev;
15128c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
15138c2ecf20Sopenharmony_ci	int err;
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	/* Use timer0 for interrupt moderation on the mailbox */
15168c2ecf20Sopenharmony_ci	u32 itr = entry->entry | FM10K_INT_MAP_TIMER0;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	/* register mailbox handlers */
15198c2ecf20Sopenharmony_ci	err = hw->mbx.ops.register_handlers(&hw->mbx, vf_mbx_data);
15208c2ecf20Sopenharmony_ci	if (err)
15218c2ecf20Sopenharmony_ci		return err;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	/* request the IRQ */
15248c2ecf20Sopenharmony_ci	err = request_irq(entry->vector, fm10k_msix_mbx_vf, 0,
15258c2ecf20Sopenharmony_ci			  dev->name, interface);
15268c2ecf20Sopenharmony_ci	if (err) {
15278c2ecf20Sopenharmony_ci		netif_err(interface, probe, dev,
15288c2ecf20Sopenharmony_ci			  "request_irq for msix_mbx failed: %d\n", err);
15298c2ecf20Sopenharmony_ci		return err;
15308c2ecf20Sopenharmony_ci	}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	/* map all of the interrupt sources */
15338c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_VFINT_MAP, itr);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	/* enable interrupt */
15368c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_VFITR(entry->entry), FM10K_ITR_ENABLE);
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	return 0;
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic s32 fm10k_lport_map(struct fm10k_hw *hw, u32 **results,
15428c2ecf20Sopenharmony_ci			   struct fm10k_mbx_info *mbx)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
15458c2ecf20Sopenharmony_ci	u32 dglort_map = hw->mac.dglort_map;
15468c2ecf20Sopenharmony_ci	s32 err;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	interface = container_of(hw, struct fm10k_intfc, hw);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	err = fm10k_msg_err_pf(hw, results, mbx);
15518c2ecf20Sopenharmony_ci	if (!err && hw->swapi.status) {
15528c2ecf20Sopenharmony_ci		/* force link down for a reasonable delay */
15538c2ecf20Sopenharmony_ci		interface->link_down_event = jiffies + (2 * HZ);
15548c2ecf20Sopenharmony_ci		set_bit(__FM10K_LINK_DOWN, interface->state);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci		/* reset dglort_map back to no config */
15578c2ecf20Sopenharmony_ci		hw->mac.dglort_map = FM10K_DGLORTMAP_NONE;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci		fm10k_service_event_schedule(interface);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci		/* prevent overloading kernel message buffer */
15628c2ecf20Sopenharmony_ci		if (interface->lport_map_failed)
15638c2ecf20Sopenharmony_ci			return 0;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci		interface->lport_map_failed = true;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci		if (hw->swapi.status == FM10K_MSG_ERR_PEP_NOT_SCHEDULED)
15688c2ecf20Sopenharmony_ci			dev_warn(&interface->pdev->dev,
15698c2ecf20Sopenharmony_ci				 "cannot obtain link because the host interface is configured for a PCIe host interface bandwidth of zero\n");
15708c2ecf20Sopenharmony_ci		dev_warn(&interface->pdev->dev,
15718c2ecf20Sopenharmony_ci			 "request logical port map failed: %d\n",
15728c2ecf20Sopenharmony_ci			 hw->swapi.status);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci		return 0;
15758c2ecf20Sopenharmony_ci	}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	err = fm10k_msg_lport_map_pf(hw, results, mbx);
15788c2ecf20Sopenharmony_ci	if (err)
15798c2ecf20Sopenharmony_ci		return err;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	interface->lport_map_failed = false;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	/* we need to reset if port count was just updated */
15848c2ecf20Sopenharmony_ci	if (dglort_map != hw->mac.dglort_map)
15858c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	return 0;
15888c2ecf20Sopenharmony_ci}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_cistatic s32 fm10k_update_pvid(struct fm10k_hw *hw, u32 **results,
15918c2ecf20Sopenharmony_ci			     struct fm10k_mbx_info __always_unused *mbx)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
15948c2ecf20Sopenharmony_ci	u16 glort, pvid;
15958c2ecf20Sopenharmony_ci	u32 pvid_update;
15968c2ecf20Sopenharmony_ci	s32 err;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_UPDATE_PVID],
15998c2ecf20Sopenharmony_ci				     &pvid_update);
16008c2ecf20Sopenharmony_ci	if (err)
16018c2ecf20Sopenharmony_ci		return err;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	/* extract values from the pvid update */
16048c2ecf20Sopenharmony_ci	glort = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_GLORT);
16058c2ecf20Sopenharmony_ci	pvid = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_PVID);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	/* if glort is not valid return error */
16088c2ecf20Sopenharmony_ci	if (!fm10k_glort_valid_pf(hw, glort))
16098c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	/* verify VLAN ID is valid */
16128c2ecf20Sopenharmony_ci	if (pvid >= FM10K_VLAN_TABLE_VID_MAX)
16138c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	interface = container_of(hw, struct fm10k_intfc, hw);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	/* check to see if this belongs to one of the VFs */
16188c2ecf20Sopenharmony_ci	err = fm10k_iov_update_pvid(interface, glort, pvid);
16198c2ecf20Sopenharmony_ci	if (!err)
16208c2ecf20Sopenharmony_ci		return 0;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	/* we need to reset if default VLAN was just updated */
16238c2ecf20Sopenharmony_ci	if (pvid != hw->mac.default_vid)
16248c2ecf20Sopenharmony_ci		set_bit(FM10K_FLAG_RESET_REQUESTED, interface->flags);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	hw->mac.default_vid = pvid;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	return 0;
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_cistatic const struct fm10k_msg_data pf_mbx_data[] = {
16328c2ecf20Sopenharmony_ci	FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf),
16338c2ecf20Sopenharmony_ci	FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf),
16348c2ecf20Sopenharmony_ci	FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_lport_map),
16358c2ecf20Sopenharmony_ci	FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf),
16368c2ecf20Sopenharmony_ci	FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf),
16378c2ecf20Sopenharmony_ci	FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_update_pvid),
16388c2ecf20Sopenharmony_ci	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_mbx_error),
16398c2ecf20Sopenharmony_ci};
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_cistatic int fm10k_mbx_request_irq_pf(struct fm10k_intfc *interface)
16428c2ecf20Sopenharmony_ci{
16438c2ecf20Sopenharmony_ci	struct msix_entry *entry = &interface->msix_entries[FM10K_MBX_VECTOR];
16448c2ecf20Sopenharmony_ci	struct net_device *dev = interface->netdev;
16458c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
16468c2ecf20Sopenharmony_ci	int err;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	/* Use timer0 for interrupt moderation on the mailbox */
16498c2ecf20Sopenharmony_ci	u32 mbx_itr = entry->entry | FM10K_INT_MAP_TIMER0;
16508c2ecf20Sopenharmony_ci	u32 other_itr = entry->entry | FM10K_INT_MAP_IMMEDIATE;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	/* register mailbox handlers */
16538c2ecf20Sopenharmony_ci	err = hw->mbx.ops.register_handlers(&hw->mbx, pf_mbx_data);
16548c2ecf20Sopenharmony_ci	if (err)
16558c2ecf20Sopenharmony_ci		return err;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	/* request the IRQ */
16588c2ecf20Sopenharmony_ci	err = request_irq(entry->vector, fm10k_msix_mbx_pf, 0,
16598c2ecf20Sopenharmony_ci			  dev->name, interface);
16608c2ecf20Sopenharmony_ci	if (err) {
16618c2ecf20Sopenharmony_ci		netif_err(interface, probe, dev,
16628c2ecf20Sopenharmony_ci			  "request_irq for msix_mbx failed: %d\n", err);
16638c2ecf20Sopenharmony_ci		return err;
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	/* Enable interrupts w/ no moderation for "other" interrupts */
16678c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_pcie_fault), other_itr);
16688c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_switch_up_down), other_itr);
16698c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_sram), other_itr);
16708c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_max_hold_time), other_itr);
16718c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_vflr), other_itr);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	/* Enable interrupts w/ moderation for mailbox */
16748c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_mailbox), mbx_itr);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	/* Enable individual interrupt causes */
16778c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_EIMR, FM10K_EIMR_ENABLE(PCA_FAULT) |
16788c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(FUM_FAULT) |
16798c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(MAILBOX) |
16808c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(SWITCHREADY) |
16818c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(SWITCHNOTREADY) |
16828c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(SRAMERROR) |
16838c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(VFLR) |
16848c2ecf20Sopenharmony_ci					FM10K_EIMR_ENABLE(MAXHOLDTIME));
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	/* enable interrupt */
16878c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_ITR(entry->entry), FM10K_ITR_ENABLE);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	return 0;
16908c2ecf20Sopenharmony_ci}
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ciint fm10k_mbx_request_irq(struct fm10k_intfc *interface)
16938c2ecf20Sopenharmony_ci{
16948c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
16958c2ecf20Sopenharmony_ci	int err;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	/* enable Mailbox cause */
16988c2ecf20Sopenharmony_ci	if (hw->mac.type == fm10k_mac_pf)
16998c2ecf20Sopenharmony_ci		err = fm10k_mbx_request_irq_pf(interface);
17008c2ecf20Sopenharmony_ci	else
17018c2ecf20Sopenharmony_ci		err = fm10k_mbx_request_irq_vf(interface);
17028c2ecf20Sopenharmony_ci	if (err)
17038c2ecf20Sopenharmony_ci		return err;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	/* connect mailbox */
17068c2ecf20Sopenharmony_ci	err = hw->mbx.ops.connect(hw, &hw->mbx);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	/* if the mailbox failed to connect, then free IRQ */
17098c2ecf20Sopenharmony_ci	if (err)
17108c2ecf20Sopenharmony_ci		fm10k_mbx_free_irq(interface);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	return err;
17138c2ecf20Sopenharmony_ci}
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci/**
17168c2ecf20Sopenharmony_ci * fm10k_qv_free_irq - release interrupts associated with queue vectors
17178c2ecf20Sopenharmony_ci * @interface: board private structure
17188c2ecf20Sopenharmony_ci *
17198c2ecf20Sopenharmony_ci * Release all interrupts associated with this interface
17208c2ecf20Sopenharmony_ci **/
17218c2ecf20Sopenharmony_civoid fm10k_qv_free_irq(struct fm10k_intfc *interface)
17228c2ecf20Sopenharmony_ci{
17238c2ecf20Sopenharmony_ci	int vector = interface->num_q_vectors;
17248c2ecf20Sopenharmony_ci	struct msix_entry *entry;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	entry = &interface->msix_entries[NON_Q_VECTORS + vector];
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	while (vector) {
17298c2ecf20Sopenharmony_ci		struct fm10k_q_vector *q_vector;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci		vector--;
17328c2ecf20Sopenharmony_ci		entry--;
17338c2ecf20Sopenharmony_ci		q_vector = interface->q_vector[vector];
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci		if (!q_vector->tx.count && !q_vector->rx.count)
17368c2ecf20Sopenharmony_ci			continue;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci		/* clear the affinity_mask in the IRQ descriptor */
17398c2ecf20Sopenharmony_ci		irq_set_affinity_hint(entry->vector, NULL);
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci		/* disable interrupts */
17428c2ecf20Sopenharmony_ci		writel(FM10K_ITR_MASK_SET, q_vector->itr);
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci		free_irq(entry->vector, q_vector);
17458c2ecf20Sopenharmony_ci	}
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci/**
17498c2ecf20Sopenharmony_ci * fm10k_qv_request_irq - initialize interrupts for queue vectors
17508c2ecf20Sopenharmony_ci * @interface: board private structure
17518c2ecf20Sopenharmony_ci *
17528c2ecf20Sopenharmony_ci * Attempts to configure interrupts using the best available
17538c2ecf20Sopenharmony_ci * capabilities of the hardware and kernel.
17548c2ecf20Sopenharmony_ci **/
17558c2ecf20Sopenharmony_ciint fm10k_qv_request_irq(struct fm10k_intfc *interface)
17568c2ecf20Sopenharmony_ci{
17578c2ecf20Sopenharmony_ci	struct net_device *dev = interface->netdev;
17588c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
17598c2ecf20Sopenharmony_ci	struct msix_entry *entry;
17608c2ecf20Sopenharmony_ci	unsigned int ri = 0, ti = 0;
17618c2ecf20Sopenharmony_ci	int vector, err;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	entry = &interface->msix_entries[NON_Q_VECTORS];
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	for (vector = 0; vector < interface->num_q_vectors; vector++) {
17668c2ecf20Sopenharmony_ci		struct fm10k_q_vector *q_vector = interface->q_vector[vector];
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci		/* name the vector */
17698c2ecf20Sopenharmony_ci		if (q_vector->tx.count && q_vector->rx.count) {
17708c2ecf20Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name),
17718c2ecf20Sopenharmony_ci				 "%s-TxRx-%u", dev->name, ri++);
17728c2ecf20Sopenharmony_ci			ti++;
17738c2ecf20Sopenharmony_ci		} else if (q_vector->rx.count) {
17748c2ecf20Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name),
17758c2ecf20Sopenharmony_ci				 "%s-rx-%u", dev->name, ri++);
17768c2ecf20Sopenharmony_ci		} else if (q_vector->tx.count) {
17778c2ecf20Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name),
17788c2ecf20Sopenharmony_ci				 "%s-tx-%u", dev->name, ti++);
17798c2ecf20Sopenharmony_ci		} else {
17808c2ecf20Sopenharmony_ci			/* skip this unused q_vector */
17818c2ecf20Sopenharmony_ci			continue;
17828c2ecf20Sopenharmony_ci		}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci		/* Assign ITR register to q_vector */
17858c2ecf20Sopenharmony_ci		q_vector->itr = (hw->mac.type == fm10k_mac_pf) ?
17868c2ecf20Sopenharmony_ci				&interface->uc_addr[FM10K_ITR(entry->entry)] :
17878c2ecf20Sopenharmony_ci				&interface->uc_addr[FM10K_VFITR(entry->entry)];
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci		/* request the IRQ */
17908c2ecf20Sopenharmony_ci		err = request_irq(entry->vector, &fm10k_msix_clean_rings, 0,
17918c2ecf20Sopenharmony_ci				  q_vector->name, q_vector);
17928c2ecf20Sopenharmony_ci		if (err) {
17938c2ecf20Sopenharmony_ci			netif_err(interface, probe, dev,
17948c2ecf20Sopenharmony_ci				  "request_irq failed for MSIX interrupt Error: %d\n",
17958c2ecf20Sopenharmony_ci				  err);
17968c2ecf20Sopenharmony_ci			goto err_out;
17978c2ecf20Sopenharmony_ci		}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci		/* assign the mask for this irq */
18008c2ecf20Sopenharmony_ci		irq_set_affinity_hint(entry->vector, &q_vector->affinity_mask);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		/* Enable q_vector */
18038c2ecf20Sopenharmony_ci		writel(FM10K_ITR_ENABLE, q_vector->itr);
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci		entry++;
18068c2ecf20Sopenharmony_ci	}
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	return 0;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_cierr_out:
18118c2ecf20Sopenharmony_ci	/* wind through the ring freeing all entries and vectors */
18128c2ecf20Sopenharmony_ci	while (vector) {
18138c2ecf20Sopenharmony_ci		struct fm10k_q_vector *q_vector;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci		entry--;
18168c2ecf20Sopenharmony_ci		vector--;
18178c2ecf20Sopenharmony_ci		q_vector = interface->q_vector[vector];
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci		if (!q_vector->tx.count && !q_vector->rx.count)
18208c2ecf20Sopenharmony_ci			continue;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci		/* clear the affinity_mask in the IRQ descriptor */
18238c2ecf20Sopenharmony_ci		irq_set_affinity_hint(entry->vector, NULL);
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci		/* disable interrupts */
18268c2ecf20Sopenharmony_ci		writel(FM10K_ITR_MASK_SET, q_vector->itr);
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci		free_irq(entry->vector, q_vector);
18298c2ecf20Sopenharmony_ci	}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	return err;
18328c2ecf20Sopenharmony_ci}
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_civoid fm10k_up(struct fm10k_intfc *interface)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	/* Enable Tx/Rx DMA */
18398c2ecf20Sopenharmony_ci	hw->mac.ops.start_hw(hw);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	/* configure Tx descriptor rings */
18428c2ecf20Sopenharmony_ci	fm10k_configure_tx(interface);
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	/* configure Rx descriptor rings */
18458c2ecf20Sopenharmony_ci	fm10k_configure_rx(interface);
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/* configure interrupts */
18488c2ecf20Sopenharmony_ci	hw->mac.ops.update_int_moderator(hw);
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	/* enable statistics capture again */
18518c2ecf20Sopenharmony_ci	clear_bit(__FM10K_UPDATING_STATS, interface->state);
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	/* clear down bit to indicate we are ready to go */
18548c2ecf20Sopenharmony_ci	clear_bit(__FM10K_DOWN, interface->state);
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	/* enable polling cleanups */
18578c2ecf20Sopenharmony_ci	fm10k_napi_enable_all(interface);
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	/* re-establish Rx filters */
18608c2ecf20Sopenharmony_ci	fm10k_restore_rx_state(interface);
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	/* enable transmits */
18638c2ecf20Sopenharmony_ci	netif_tx_start_all_queues(interface->netdev);
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/* kick off the service timer now */
18668c2ecf20Sopenharmony_ci	hw->mac.get_host_state = true;
18678c2ecf20Sopenharmony_ci	mod_timer(&interface->service_timer, jiffies);
18688c2ecf20Sopenharmony_ci}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_cistatic void fm10k_napi_disable_all(struct fm10k_intfc *interface)
18718c2ecf20Sopenharmony_ci{
18728c2ecf20Sopenharmony_ci	struct fm10k_q_vector *q_vector;
18738c2ecf20Sopenharmony_ci	int q_idx;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	for (q_idx = 0; q_idx < interface->num_q_vectors; q_idx++) {
18768c2ecf20Sopenharmony_ci		q_vector = interface->q_vector[q_idx];
18778c2ecf20Sopenharmony_ci		napi_disable(&q_vector->napi);
18788c2ecf20Sopenharmony_ci	}
18798c2ecf20Sopenharmony_ci}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_civoid fm10k_down(struct fm10k_intfc *interface)
18828c2ecf20Sopenharmony_ci{
18838c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
18848c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
18858c2ecf20Sopenharmony_ci	int err, i = 0, count = 0;
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	/* signal that we are down to the interrupt handler and service task */
18888c2ecf20Sopenharmony_ci	if (test_and_set_bit(__FM10K_DOWN, interface->state))
18898c2ecf20Sopenharmony_ci		return;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	/* call carrier off first to avoid false dev_watchdog timeouts */
18928c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	/* disable transmits */
18958c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(netdev);
18968c2ecf20Sopenharmony_ci	netif_tx_disable(netdev);
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	/* reset Rx filters */
18998c2ecf20Sopenharmony_ci	fm10k_reset_rx_state(interface);
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	/* disable polling routines */
19028c2ecf20Sopenharmony_ci	fm10k_napi_disable_all(interface);
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	/* capture stats one last time before stopping interface */
19058c2ecf20Sopenharmony_ci	fm10k_update_stats(interface);
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	/* prevent updating statistics while we're down */
19088c2ecf20Sopenharmony_ci	while (test_and_set_bit(__FM10K_UPDATING_STATS, interface->state))
19098c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	/* skip waiting for TX DMA if we lost PCIe link */
19128c2ecf20Sopenharmony_ci	if (FM10K_REMOVED(hw->hw_addr))
19138c2ecf20Sopenharmony_ci		goto skip_tx_dma_drain;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	/* In some rare circumstances it can take a while for Tx queues to
19168c2ecf20Sopenharmony_ci	 * quiesce and be fully disabled. Attempt to .stop_hw() first, and
19178c2ecf20Sopenharmony_ci	 * then if we get ERR_REQUESTS_PENDING, go ahead and wait in a loop
19188c2ecf20Sopenharmony_ci	 * until the Tx queues have emptied, or until a number of retries. If
19198c2ecf20Sopenharmony_ci	 * we fail to clear within the retry loop, we will issue a warning
19208c2ecf20Sopenharmony_ci	 * indicating that Tx DMA is probably hung. Note this means we call
19218c2ecf20Sopenharmony_ci	 * .stop_hw() twice but this shouldn't cause any problems.
19228c2ecf20Sopenharmony_ci	 */
19238c2ecf20Sopenharmony_ci	err = hw->mac.ops.stop_hw(hw);
19248c2ecf20Sopenharmony_ci	if (err != FM10K_ERR_REQUESTS_PENDING)
19258c2ecf20Sopenharmony_ci		goto skip_tx_dma_drain;
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci#define TX_DMA_DRAIN_RETRIES 25
19288c2ecf20Sopenharmony_ci	for (count = 0; count < TX_DMA_DRAIN_RETRIES; count++) {
19298c2ecf20Sopenharmony_ci		usleep_range(10000, 20000);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci		/* start checking at the last ring to have pending Tx */
19328c2ecf20Sopenharmony_ci		for (; i < interface->num_tx_queues; i++)
19338c2ecf20Sopenharmony_ci			if (fm10k_get_tx_pending(interface->tx_ring[i], false))
19348c2ecf20Sopenharmony_ci				break;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci		/* if all the queues are drained, we can break now */
19378c2ecf20Sopenharmony_ci		if (i == interface->num_tx_queues)
19388c2ecf20Sopenharmony_ci			break;
19398c2ecf20Sopenharmony_ci	}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	if (count >= TX_DMA_DRAIN_RETRIES)
19428c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev,
19438c2ecf20Sopenharmony_ci			"Tx queues failed to drain after %d tries. Tx DMA is probably hung.\n",
19448c2ecf20Sopenharmony_ci			count);
19458c2ecf20Sopenharmony_ciskip_tx_dma_drain:
19468c2ecf20Sopenharmony_ci	/* Disable DMA engine for Tx/Rx */
19478c2ecf20Sopenharmony_ci	err = hw->mac.ops.stop_hw(hw);
19488c2ecf20Sopenharmony_ci	if (err == FM10K_ERR_REQUESTS_PENDING)
19498c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev,
19508c2ecf20Sopenharmony_ci			"due to pending requests hw was not shut down gracefully\n");
19518c2ecf20Sopenharmony_ci	else if (err)
19528c2ecf20Sopenharmony_ci		dev_err(&interface->pdev->dev, "stop_hw failed: %d\n", err);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	/* free any buffers still on the rings */
19558c2ecf20Sopenharmony_ci	fm10k_clean_all_tx_rings(interface);
19568c2ecf20Sopenharmony_ci	fm10k_clean_all_rx_rings(interface);
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci/**
19608c2ecf20Sopenharmony_ci * fm10k_sw_init - Initialize general software structures
19618c2ecf20Sopenharmony_ci * @interface: host interface private structure to initialize
19628c2ecf20Sopenharmony_ci * @ent: PCI device ID entry
19638c2ecf20Sopenharmony_ci *
19648c2ecf20Sopenharmony_ci * fm10k_sw_init initializes the interface private data structure.
19658c2ecf20Sopenharmony_ci * Fields are initialized based on PCI device information and
19668c2ecf20Sopenharmony_ci * OS network device settings (MTU size).
19678c2ecf20Sopenharmony_ci **/
19688c2ecf20Sopenharmony_cistatic int fm10k_sw_init(struct fm10k_intfc *interface,
19698c2ecf20Sopenharmony_ci			 const struct pci_device_id *ent)
19708c2ecf20Sopenharmony_ci{
19718c2ecf20Sopenharmony_ci	const struct fm10k_info *fi = fm10k_info_tbl[ent->driver_data];
19728c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
19738c2ecf20Sopenharmony_ci	struct pci_dev *pdev = interface->pdev;
19748c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
19758c2ecf20Sopenharmony_ci	u32 rss_key[FM10K_RSSRK_SIZE];
19768c2ecf20Sopenharmony_ci	unsigned int rss;
19778c2ecf20Sopenharmony_ci	int err;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	/* initialize back pointer */
19808c2ecf20Sopenharmony_ci	hw->back = interface;
19818c2ecf20Sopenharmony_ci	hw->hw_addr = interface->uc_addr;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	/* PCI config space info */
19848c2ecf20Sopenharmony_ci	hw->vendor_id = pdev->vendor;
19858c2ecf20Sopenharmony_ci	hw->device_id = pdev->device;
19868c2ecf20Sopenharmony_ci	hw->revision_id = pdev->revision;
19878c2ecf20Sopenharmony_ci	hw->subsystem_vendor_id = pdev->subsystem_vendor;
19888c2ecf20Sopenharmony_ci	hw->subsystem_device_id = pdev->subsystem_device;
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	/* Setup hw api */
19918c2ecf20Sopenharmony_ci	memcpy(&hw->mac.ops, fi->mac_ops, sizeof(hw->mac.ops));
19928c2ecf20Sopenharmony_ci	hw->mac.type = fi->mac;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	/* Setup IOV handlers */
19958c2ecf20Sopenharmony_ci	if (fi->iov_ops)
19968c2ecf20Sopenharmony_ci		memcpy(&hw->iov.ops, fi->iov_ops, sizeof(hw->iov.ops));
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	/* Set common capability flags and settings */
19998c2ecf20Sopenharmony_ci	rss = min_t(int, FM10K_MAX_RSS_INDICES, num_online_cpus());
20008c2ecf20Sopenharmony_ci	interface->ring_feature[RING_F_RSS].limit = rss;
20018c2ecf20Sopenharmony_ci	fi->get_invariants(hw);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	/* pick up the PCIe bus settings for reporting later */
20048c2ecf20Sopenharmony_ci	if (hw->mac.ops.get_bus_info)
20058c2ecf20Sopenharmony_ci		hw->mac.ops.get_bus_info(hw);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	/* limit the usable DMA range */
20088c2ecf20Sopenharmony_ci	if (hw->mac.ops.set_dma_mask)
20098c2ecf20Sopenharmony_ci		hw->mac.ops.set_dma_mask(hw, dma_get_mask(&pdev->dev));
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	/* update netdev with DMA restrictions */
20128c2ecf20Sopenharmony_ci	if (dma_get_mask(&pdev->dev) > DMA_BIT_MASK(32)) {
20138c2ecf20Sopenharmony_ci		netdev->features |= NETIF_F_HIGHDMA;
20148c2ecf20Sopenharmony_ci		netdev->vlan_features |= NETIF_F_HIGHDMA;
20158c2ecf20Sopenharmony_ci	}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	/* reset and initialize the hardware so it is in a known state */
20188c2ecf20Sopenharmony_ci	err = hw->mac.ops.reset_hw(hw);
20198c2ecf20Sopenharmony_ci	if (err) {
20208c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "reset_hw failed: %d\n", err);
20218c2ecf20Sopenharmony_ci		return err;
20228c2ecf20Sopenharmony_ci	}
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	err = hw->mac.ops.init_hw(hw);
20258c2ecf20Sopenharmony_ci	if (err) {
20268c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "init_hw failed: %d\n", err);
20278c2ecf20Sopenharmony_ci		return err;
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	/* initialize hardware statistics */
20318c2ecf20Sopenharmony_ci	hw->mac.ops.update_hw_stats(hw, &interface->stats);
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	/* Set upper limit on IOV VFs that can be allocated */
20348c2ecf20Sopenharmony_ci	pci_sriov_set_totalvfs(pdev, hw->iov.total_vfs);
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	/* Start with random Ethernet address */
20378c2ecf20Sopenharmony_ci	eth_random_addr(hw->mac.addr);
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	/* Initialize MAC address from hardware */
20408c2ecf20Sopenharmony_ci	err = hw->mac.ops.read_mac_addr(hw);
20418c2ecf20Sopenharmony_ci	if (err) {
20428c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
20438c2ecf20Sopenharmony_ci			 "Failed to obtain MAC address defaulting to random\n");
20448c2ecf20Sopenharmony_ci		/* tag address assignment as random */
20458c2ecf20Sopenharmony_ci		netdev->addr_assign_type |= NET_ADDR_RANDOM;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	ether_addr_copy(netdev->dev_addr, hw->mac.addr);
20498c2ecf20Sopenharmony_ci	ether_addr_copy(netdev->perm_addr, hw->mac.addr);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(netdev->perm_addr)) {
20528c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Invalid MAC Address\n");
20538c2ecf20Sopenharmony_ci		return -EIO;
20548c2ecf20Sopenharmony_ci	}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	/* initialize DCBNL interface */
20578c2ecf20Sopenharmony_ci	fm10k_dcbnl_set_ops(netdev);
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	/* set default ring sizes */
20608c2ecf20Sopenharmony_ci	interface->tx_ring_count = FM10K_DEFAULT_TXD;
20618c2ecf20Sopenharmony_ci	interface->rx_ring_count = FM10K_DEFAULT_RXD;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	/* set default interrupt moderation */
20648c2ecf20Sopenharmony_ci	interface->tx_itr = FM10K_TX_ITR_DEFAULT;
20658c2ecf20Sopenharmony_ci	interface->rx_itr = FM10K_ITR_ADAPTIVE | FM10K_RX_ITR_DEFAULT;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	/* Initialize the MAC/VLAN queue */
20688c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&interface->macvlan_requests);
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	netdev_rss_key_fill(rss_key, sizeof(rss_key));
20718c2ecf20Sopenharmony_ci	memcpy(interface->rssrk, rss_key, sizeof(rss_key));
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	/* Initialize the mailbox lock */
20748c2ecf20Sopenharmony_ci	spin_lock_init(&interface->mbx_lock);
20758c2ecf20Sopenharmony_ci	spin_lock_init(&interface->macvlan_lock);
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	/* Start off interface as being down */
20788c2ecf20Sopenharmony_ci	set_bit(__FM10K_DOWN, interface->state);
20798c2ecf20Sopenharmony_ci	set_bit(__FM10K_UPDATING_STATS, interface->state);
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci	return 0;
20828c2ecf20Sopenharmony_ci}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci/**
20858c2ecf20Sopenharmony_ci * fm10k_probe - Device Initialization Routine
20868c2ecf20Sopenharmony_ci * @pdev: PCI device information struct
20878c2ecf20Sopenharmony_ci * @ent: entry in fm10k_pci_tbl
20888c2ecf20Sopenharmony_ci *
20898c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure
20908c2ecf20Sopenharmony_ci *
20918c2ecf20Sopenharmony_ci * fm10k_probe initializes an interface identified by a pci_dev structure.
20928c2ecf20Sopenharmony_ci * The OS initialization, configuring of the interface private structure,
20938c2ecf20Sopenharmony_ci * and a hardware reset occur.
20948c2ecf20Sopenharmony_ci **/
20958c2ecf20Sopenharmony_cistatic int fm10k_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
20968c2ecf20Sopenharmony_ci{
20978c2ecf20Sopenharmony_ci	struct net_device *netdev;
20988c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface;
20998c2ecf20Sopenharmony_ci	int err;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	if (pdev->error_state != pci_channel_io_normal) {
21028c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
21038c2ecf20Sopenharmony_ci			"PCI device still in an error state. Unable to load...\n");
21048c2ecf20Sopenharmony_ci		return -EIO;
21058c2ecf20Sopenharmony_ci	}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	err = pci_enable_device_mem(pdev);
21088c2ecf20Sopenharmony_ci	if (err) {
21098c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
21108c2ecf20Sopenharmony_ci			"PCI enable device failed: %d\n", err);
21118c2ecf20Sopenharmony_ci		return err;
21128c2ecf20Sopenharmony_ci	}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48));
21158c2ecf20Sopenharmony_ci	if (err)
21168c2ecf20Sopenharmony_ci		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
21178c2ecf20Sopenharmony_ci	if (err) {
21188c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
21198c2ecf20Sopenharmony_ci			"DMA configuration failed: %d\n", err);
21208c2ecf20Sopenharmony_ci		goto err_dma;
21218c2ecf20Sopenharmony_ci	}
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci	err = pci_request_mem_regions(pdev, fm10k_driver_name);
21248c2ecf20Sopenharmony_ci	if (err) {
21258c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
21268c2ecf20Sopenharmony_ci			"pci_request_selected_regions failed: %d\n", err);
21278c2ecf20Sopenharmony_ci		goto err_pci_reg;
21288c2ecf20Sopenharmony_ci	}
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	pci_enable_pcie_error_reporting(pdev);
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	pci_set_master(pdev);
21338c2ecf20Sopenharmony_ci	pci_save_state(pdev);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	netdev = fm10k_alloc_netdev(fm10k_info_tbl[ent->driver_data]);
21368c2ecf20Sopenharmony_ci	if (!netdev) {
21378c2ecf20Sopenharmony_ci		err = -ENOMEM;
21388c2ecf20Sopenharmony_ci		goto err_alloc_netdev;
21398c2ecf20Sopenharmony_ci	}
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	interface = netdev_priv(netdev);
21448c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, interface);
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	interface->netdev = netdev;
21478c2ecf20Sopenharmony_ci	interface->pdev = pdev;
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	interface->uc_addr = ioremap(pci_resource_start(pdev, 0),
21508c2ecf20Sopenharmony_ci				     FM10K_UC_ADDR_SIZE);
21518c2ecf20Sopenharmony_ci	if (!interface->uc_addr) {
21528c2ecf20Sopenharmony_ci		err = -EIO;
21538c2ecf20Sopenharmony_ci		goto err_ioremap;
21548c2ecf20Sopenharmony_ci	}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	err = fm10k_sw_init(interface, ent);
21578c2ecf20Sopenharmony_ci	if (err)
21588c2ecf20Sopenharmony_ci		goto err_sw_init;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	/* enable debugfs support */
21618c2ecf20Sopenharmony_ci	fm10k_dbg_intfc_init(interface);
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	err = fm10k_init_queueing_scheme(interface);
21648c2ecf20Sopenharmony_ci	if (err)
21658c2ecf20Sopenharmony_ci		goto err_sw_init;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	/* the mbx interrupt might attempt to schedule the service task, so we
21688c2ecf20Sopenharmony_ci	 * must ensure it is disabled since we haven't yet requested the timer
21698c2ecf20Sopenharmony_ci	 * or work item.
21708c2ecf20Sopenharmony_ci	 */
21718c2ecf20Sopenharmony_ci	set_bit(__FM10K_SERVICE_DISABLE, interface->state);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	err = fm10k_mbx_request_irq(interface);
21748c2ecf20Sopenharmony_ci	if (err)
21758c2ecf20Sopenharmony_ci		goto err_mbx_interrupt;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	/* final check of hardware state before registering the interface */
21788c2ecf20Sopenharmony_ci	err = fm10k_hw_ready(interface);
21798c2ecf20Sopenharmony_ci	if (err)
21808c2ecf20Sopenharmony_ci		goto err_register;
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	err = register_netdev(netdev);
21838c2ecf20Sopenharmony_ci	if (err)
21848c2ecf20Sopenharmony_ci		goto err_register;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	/* carrier off reporting is important to ethtool even BEFORE open */
21878c2ecf20Sopenharmony_ci	netif_carrier_off(netdev);
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	/* stop all the transmit queues from transmitting until link is up */
21908c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(netdev);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	/* Initialize service timer and service task late in order to avoid
21938c2ecf20Sopenharmony_ci	 * cleanup issues.
21948c2ecf20Sopenharmony_ci	 */
21958c2ecf20Sopenharmony_ci	timer_setup(&interface->service_timer, fm10k_service_timer, 0);
21968c2ecf20Sopenharmony_ci	INIT_WORK(&interface->service_task, fm10k_service_task);
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	/* Setup the MAC/VLAN queue */
21998c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&interface->macvlan_task, fm10k_macvlan_task);
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	/* kick off service timer now, even when interface is down */
22028c2ecf20Sopenharmony_ci	mod_timer(&interface->service_timer, (HZ * 2) + jiffies);
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	/* print warning for non-optimal configurations */
22058c2ecf20Sopenharmony_ci	pcie_print_link_status(interface->pdev);
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	/* report MAC address for logging */
22088c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "%pM\n", netdev->dev_addr);
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	/* enable SR-IOV after registering netdev to enforce PF/VF ordering */
22118c2ecf20Sopenharmony_ci	fm10k_iov_configure(pdev, 0);
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	/* clear the service task disable bit and kick off service task */
22148c2ecf20Sopenharmony_ci	clear_bit(__FM10K_SERVICE_DISABLE, interface->state);
22158c2ecf20Sopenharmony_ci	fm10k_service_event_schedule(interface);
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci	return 0;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_cierr_register:
22208c2ecf20Sopenharmony_ci	fm10k_mbx_free_irq(interface);
22218c2ecf20Sopenharmony_cierr_mbx_interrupt:
22228c2ecf20Sopenharmony_ci	fm10k_clear_queueing_scheme(interface);
22238c2ecf20Sopenharmony_cierr_sw_init:
22248c2ecf20Sopenharmony_ci	if (interface->sw_addr)
22258c2ecf20Sopenharmony_ci		iounmap(interface->sw_addr);
22268c2ecf20Sopenharmony_ci	iounmap(interface->uc_addr);
22278c2ecf20Sopenharmony_cierr_ioremap:
22288c2ecf20Sopenharmony_ci	free_netdev(netdev);
22298c2ecf20Sopenharmony_cierr_alloc_netdev:
22308c2ecf20Sopenharmony_ci	pci_disable_pcie_error_reporting(pdev);
22318c2ecf20Sopenharmony_ci	pci_release_mem_regions(pdev);
22328c2ecf20Sopenharmony_cierr_pci_reg:
22338c2ecf20Sopenharmony_cierr_dma:
22348c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
22358c2ecf20Sopenharmony_ci	return err;
22368c2ecf20Sopenharmony_ci}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci/**
22398c2ecf20Sopenharmony_ci * fm10k_remove - Device Removal Routine
22408c2ecf20Sopenharmony_ci * @pdev: PCI device information struct
22418c2ecf20Sopenharmony_ci *
22428c2ecf20Sopenharmony_ci * fm10k_remove is called by the PCI subsystem to alert the driver
22438c2ecf20Sopenharmony_ci * that it should release a PCI device.  The could be caused by a
22448c2ecf20Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from
22458c2ecf20Sopenharmony_ci * memory.
22468c2ecf20Sopenharmony_ci **/
22478c2ecf20Sopenharmony_cistatic void fm10k_remove(struct pci_dev *pdev)
22488c2ecf20Sopenharmony_ci{
22498c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
22508c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	del_timer_sync(&interface->service_timer);
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	fm10k_stop_service_event(interface);
22558c2ecf20Sopenharmony_ci	fm10k_stop_macvlan_task(interface);
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	/* Remove all pending MAC/VLAN requests */
22588c2ecf20Sopenharmony_ci	fm10k_clear_macvlan_queue(interface, interface->glort, true);
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci	/* free netdev, this may bounce the interrupts due to setup_tc */
22618c2ecf20Sopenharmony_ci	if (netdev->reg_state == NETREG_REGISTERED)
22628c2ecf20Sopenharmony_ci		unregister_netdev(netdev);
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	/* release VFs */
22658c2ecf20Sopenharmony_ci	fm10k_iov_disable(pdev);
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	/* disable mailbox interrupt */
22688c2ecf20Sopenharmony_ci	fm10k_mbx_free_irq(interface);
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	/* free interrupts */
22718c2ecf20Sopenharmony_ci	fm10k_clear_queueing_scheme(interface);
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	/* remove any debugfs interfaces */
22748c2ecf20Sopenharmony_ci	fm10k_dbg_intfc_exit(interface);
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	if (interface->sw_addr)
22778c2ecf20Sopenharmony_ci		iounmap(interface->sw_addr);
22788c2ecf20Sopenharmony_ci	iounmap(interface->uc_addr);
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	free_netdev(netdev);
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	pci_release_mem_regions(pdev);
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	pci_disable_pcie_error_reporting(pdev);
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
22878c2ecf20Sopenharmony_ci}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_cistatic void fm10k_prepare_suspend(struct fm10k_intfc *interface)
22908c2ecf20Sopenharmony_ci{
22918c2ecf20Sopenharmony_ci	/* the watchdog task reads from registers, which might appear like
22928c2ecf20Sopenharmony_ci	 * a surprise remove if the PCIe device is disabled while we're
22938c2ecf20Sopenharmony_ci	 * stopped. We stop the watchdog task until after we resume software
22948c2ecf20Sopenharmony_ci	 * activity.
22958c2ecf20Sopenharmony_ci	 *
22968c2ecf20Sopenharmony_ci	 * Note that the MAC/VLAN task will be stopped as part of preparing
22978c2ecf20Sopenharmony_ci	 * for reset so we don't need to handle it here.
22988c2ecf20Sopenharmony_ci	 */
22998c2ecf20Sopenharmony_ci	fm10k_stop_service_event(interface);
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	if (fm10k_prepare_for_reset(interface))
23028c2ecf20Sopenharmony_ci		set_bit(__FM10K_RESET_SUSPENDED, interface->state);
23038c2ecf20Sopenharmony_ci}
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_cistatic int fm10k_handle_resume(struct fm10k_intfc *interface)
23068c2ecf20Sopenharmony_ci{
23078c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
23088c2ecf20Sopenharmony_ci	int err;
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	/* Even if we didn't properly prepare for reset in
23118c2ecf20Sopenharmony_ci	 * fm10k_prepare_suspend, we'll attempt to resume anyways.
23128c2ecf20Sopenharmony_ci	 */
23138c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(__FM10K_RESET_SUSPENDED, interface->state))
23148c2ecf20Sopenharmony_ci		dev_warn(&interface->pdev->dev,
23158c2ecf20Sopenharmony_ci			 "Device was shut down as part of suspend... Attempting to recover\n");
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	/* reset statistics starting values */
23188c2ecf20Sopenharmony_ci	hw->mac.ops.rebind_hw_stats(hw, &interface->stats);
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	err = fm10k_handle_reset(interface);
23218c2ecf20Sopenharmony_ci	if (err)
23228c2ecf20Sopenharmony_ci		return err;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	/* assume host is not ready, to prevent race with watchdog in case we
23258c2ecf20Sopenharmony_ci	 * actually don't have connection to the switch
23268c2ecf20Sopenharmony_ci	 */
23278c2ecf20Sopenharmony_ci	interface->host_ready = false;
23288c2ecf20Sopenharmony_ci	fm10k_watchdog_host_not_ready(interface);
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	/* force link to stay down for a second to prevent link flutter */
23318c2ecf20Sopenharmony_ci	interface->link_down_event = jiffies + (HZ);
23328c2ecf20Sopenharmony_ci	set_bit(__FM10K_LINK_DOWN, interface->state);
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci	/* restart the service task */
23358c2ecf20Sopenharmony_ci	fm10k_start_service_event(interface);
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	/* Restart the MAC/VLAN request queue in-case of outstanding events */
23388c2ecf20Sopenharmony_ci	fm10k_macvlan_schedule(interface);
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	return 0;
23418c2ecf20Sopenharmony_ci}
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci/**
23448c2ecf20Sopenharmony_ci * fm10k_resume - Generic PM resume hook
23458c2ecf20Sopenharmony_ci * @dev: generic device structure
23468c2ecf20Sopenharmony_ci *
23478c2ecf20Sopenharmony_ci * Generic PM hook used when waking the device from a low power state after
23488c2ecf20Sopenharmony_ci * suspend or hibernation. This function does not need to handle lower PCIe
23498c2ecf20Sopenharmony_ci * device state as the stack takes care of that for us.
23508c2ecf20Sopenharmony_ci **/
23518c2ecf20Sopenharmony_cistatic int __maybe_unused fm10k_resume(struct device *dev)
23528c2ecf20Sopenharmony_ci{
23538c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = dev_get_drvdata(dev);
23548c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
23558c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
23568c2ecf20Sopenharmony_ci	int err;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	/* refresh hw_addr in case it was dropped */
23598c2ecf20Sopenharmony_ci	hw->hw_addr = interface->uc_addr;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	err = fm10k_handle_resume(interface);
23628c2ecf20Sopenharmony_ci	if (err)
23638c2ecf20Sopenharmony_ci		return err;
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	netif_device_attach(netdev);
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	return 0;
23688c2ecf20Sopenharmony_ci}
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci/**
23718c2ecf20Sopenharmony_ci * fm10k_suspend - Generic PM suspend hook
23728c2ecf20Sopenharmony_ci * @dev: generic device structure
23738c2ecf20Sopenharmony_ci *
23748c2ecf20Sopenharmony_ci * Generic PM hook used when setting the device into a low power state for
23758c2ecf20Sopenharmony_ci * system suspend or hibernation. This function does not need to handle lower
23768c2ecf20Sopenharmony_ci * PCIe device state as the stack takes care of that for us.
23778c2ecf20Sopenharmony_ci **/
23788c2ecf20Sopenharmony_cistatic int __maybe_unused fm10k_suspend(struct device *dev)
23798c2ecf20Sopenharmony_ci{
23808c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = dev_get_drvdata(dev);
23818c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	fm10k_prepare_suspend(interface);
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	return 0;
23888c2ecf20Sopenharmony_ci}
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci/**
23918c2ecf20Sopenharmony_ci * fm10k_io_error_detected - called when PCI error is detected
23928c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
23938c2ecf20Sopenharmony_ci * @state: The current pci connection state
23948c2ecf20Sopenharmony_ci *
23958c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting
23968c2ecf20Sopenharmony_ci * this device has been detected.
23978c2ecf20Sopenharmony_ci */
23988c2ecf20Sopenharmony_cistatic pci_ers_result_t fm10k_io_error_detected(struct pci_dev *pdev,
23998c2ecf20Sopenharmony_ci						pci_channel_state_t state)
24008c2ecf20Sopenharmony_ci{
24018c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
24028c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	if (state == pci_channel_io_perm_failure)
24078c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	fm10k_prepare_suspend(interface);
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	/* Request a slot reset. */
24128c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
24138c2ecf20Sopenharmony_ci}
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci/**
24168c2ecf20Sopenharmony_ci * fm10k_io_slot_reset - called after the pci bus has been reset.
24178c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
24188c2ecf20Sopenharmony_ci *
24198c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot.
24208c2ecf20Sopenharmony_ci */
24218c2ecf20Sopenharmony_cistatic pci_ers_result_t fm10k_io_slot_reset(struct pci_dev *pdev)
24228c2ecf20Sopenharmony_ci{
24238c2ecf20Sopenharmony_ci	pci_ers_result_t result;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	if (pci_reenable_device(pdev)) {
24268c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
24278c2ecf20Sopenharmony_ci			"Cannot re-enable PCI device after reset.\n");
24288c2ecf20Sopenharmony_ci		result = PCI_ERS_RESULT_DISCONNECT;
24298c2ecf20Sopenharmony_ci	} else {
24308c2ecf20Sopenharmony_ci		pci_set_master(pdev);
24318c2ecf20Sopenharmony_ci		pci_restore_state(pdev);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci		/* After second error pci->state_saved is false, this
24348c2ecf20Sopenharmony_ci		 * resets it so EEH doesn't break.
24358c2ecf20Sopenharmony_ci		 */
24368c2ecf20Sopenharmony_ci		pci_save_state(pdev);
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci		pci_wake_from_d3(pdev, false);
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci		result = PCI_ERS_RESULT_RECOVERED;
24418c2ecf20Sopenharmony_ci	}
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	return result;
24448c2ecf20Sopenharmony_ci}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci/**
24478c2ecf20Sopenharmony_ci * fm10k_io_resume - called when traffic can start flowing again.
24488c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
24498c2ecf20Sopenharmony_ci *
24508c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells us that
24518c2ecf20Sopenharmony_ci * its OK to resume normal operation.
24528c2ecf20Sopenharmony_ci */
24538c2ecf20Sopenharmony_cistatic void fm10k_io_resume(struct pci_dev *pdev)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
24568c2ecf20Sopenharmony_ci	struct net_device *netdev = interface->netdev;
24578c2ecf20Sopenharmony_ci	int err;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	err = fm10k_handle_resume(interface);
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	if (err)
24628c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
24638c2ecf20Sopenharmony_ci			 "%s failed: %d\n", __func__, err);
24648c2ecf20Sopenharmony_ci	else
24658c2ecf20Sopenharmony_ci		netif_device_attach(netdev);
24668c2ecf20Sopenharmony_ci}
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci/**
24698c2ecf20Sopenharmony_ci * fm10k_io_reset_prepare - called when PCI function is about to be reset
24708c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
24718c2ecf20Sopenharmony_ci *
24728c2ecf20Sopenharmony_ci * This callback is called when the PCI function is about to be reset,
24738c2ecf20Sopenharmony_ci * allowing the device driver to prepare for it.
24748c2ecf20Sopenharmony_ci */
24758c2ecf20Sopenharmony_cistatic void fm10k_io_reset_prepare(struct pci_dev *pdev)
24768c2ecf20Sopenharmony_ci{
24778c2ecf20Sopenharmony_ci	/* warn incase we have any active VF devices */
24788c2ecf20Sopenharmony_ci	if (pci_num_vf(pdev))
24798c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
24808c2ecf20Sopenharmony_ci			 "PCIe FLR may cause issues for any active VF devices\n");
24818c2ecf20Sopenharmony_ci	fm10k_prepare_suspend(pci_get_drvdata(pdev));
24828c2ecf20Sopenharmony_ci}
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci/**
24858c2ecf20Sopenharmony_ci * fm10k_io_reset_done - called when PCI function has finished resetting
24868c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device
24878c2ecf20Sopenharmony_ci *
24888c2ecf20Sopenharmony_ci * This callback is called just after the PCI function is reset, such as via
24898c2ecf20Sopenharmony_ci * /sys/class/net/<enpX>/device/reset or similar.
24908c2ecf20Sopenharmony_ci */
24918c2ecf20Sopenharmony_cistatic void fm10k_io_reset_done(struct pci_dev *pdev)
24928c2ecf20Sopenharmony_ci{
24938c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
24948c2ecf20Sopenharmony_ci	int err = fm10k_handle_resume(interface);
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	if (err) {
24978c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
24988c2ecf20Sopenharmony_ci			 "%s failed: %d\n", __func__, err);
24998c2ecf20Sopenharmony_ci		netif_device_detach(interface->netdev);
25008c2ecf20Sopenharmony_ci	}
25018c2ecf20Sopenharmony_ci}
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_cistatic const struct pci_error_handlers fm10k_err_handler = {
25048c2ecf20Sopenharmony_ci	.error_detected = fm10k_io_error_detected,
25058c2ecf20Sopenharmony_ci	.slot_reset = fm10k_io_slot_reset,
25068c2ecf20Sopenharmony_ci	.resume = fm10k_io_resume,
25078c2ecf20Sopenharmony_ci	.reset_prepare = fm10k_io_reset_prepare,
25088c2ecf20Sopenharmony_ci	.reset_done = fm10k_io_reset_done,
25098c2ecf20Sopenharmony_ci};
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(fm10k_pm_ops, fm10k_suspend, fm10k_resume);
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_cistatic struct pci_driver fm10k_driver = {
25148c2ecf20Sopenharmony_ci	.name			= fm10k_driver_name,
25158c2ecf20Sopenharmony_ci	.id_table		= fm10k_pci_tbl,
25168c2ecf20Sopenharmony_ci	.probe			= fm10k_probe,
25178c2ecf20Sopenharmony_ci	.remove			= fm10k_remove,
25188c2ecf20Sopenharmony_ci	.driver = {
25198c2ecf20Sopenharmony_ci		.pm		= &fm10k_pm_ops,
25208c2ecf20Sopenharmony_ci	},
25218c2ecf20Sopenharmony_ci	.sriov_configure	= fm10k_iov_configure,
25228c2ecf20Sopenharmony_ci	.err_handler		= &fm10k_err_handler
25238c2ecf20Sopenharmony_ci};
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci/**
25268c2ecf20Sopenharmony_ci * fm10k_register_pci_driver - register driver interface
25278c2ecf20Sopenharmony_ci *
25288c2ecf20Sopenharmony_ci * This function is called on module load in order to register the driver.
25298c2ecf20Sopenharmony_ci **/
25308c2ecf20Sopenharmony_ciint fm10k_register_pci_driver(void)
25318c2ecf20Sopenharmony_ci{
25328c2ecf20Sopenharmony_ci	return pci_register_driver(&fm10k_driver);
25338c2ecf20Sopenharmony_ci}
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci/**
25368c2ecf20Sopenharmony_ci * fm10k_unregister_pci_driver - unregister driver interface
25378c2ecf20Sopenharmony_ci *
25388c2ecf20Sopenharmony_ci * This function is called on module unload in order to remove the driver.
25398c2ecf20Sopenharmony_ci **/
25408c2ecf20Sopenharmony_civoid fm10k_unregister_pci_driver(void)
25418c2ecf20Sopenharmony_ci{
25428c2ecf20Sopenharmony_ci	pci_unregister_driver(&fm10k_driver);
25438c2ecf20Sopenharmony_ci}
2544