162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/****************************************************************************
362306a36Sopenharmony_ci * Driver for Solarflare network controllers and boards
462306a36Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd.
562306a36Sopenharmony_ci * Copyright 2005-2013 Solarflare Communications Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/filter.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/netdevice.h>
1262306a36Sopenharmony_ci#include <linux/etherdevice.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/notifier.h>
1562306a36Sopenharmony_ci#include <linux/ip.h>
1662306a36Sopenharmony_ci#include <linux/tcp.h>
1762306a36Sopenharmony_ci#include <linux/in.h>
1862306a36Sopenharmony_ci#include <linux/ethtool.h>
1962306a36Sopenharmony_ci#include <linux/topology.h>
2062306a36Sopenharmony_ci#include <linux/gfp.h>
2162306a36Sopenharmony_ci#include <linux/interrupt.h>
2262306a36Sopenharmony_ci#include "net_driver.h"
2362306a36Sopenharmony_ci#include <net/gre.h>
2462306a36Sopenharmony_ci#include <net/udp_tunnel.h>
2562306a36Sopenharmony_ci#include "efx.h"
2662306a36Sopenharmony_ci#include "efx_common.h"
2762306a36Sopenharmony_ci#include "efx_channels.h"
2862306a36Sopenharmony_ci#include "rx_common.h"
2962306a36Sopenharmony_ci#include "tx_common.h"
3062306a36Sopenharmony_ci#include "nic.h"
3162306a36Sopenharmony_ci#include "io.h"
3262306a36Sopenharmony_ci#include "selftest.h"
3362306a36Sopenharmony_ci#include "sriov.h"
3462306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
3562306a36Sopenharmony_ci#include "siena_sriov.h"
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "mcdi_port_common.h"
3962306a36Sopenharmony_ci#include "mcdi_pcol.h"
4062306a36Sopenharmony_ci#include "workarounds.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**************************************************************************
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Configurable values
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci *************************************************************************/
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cimodule_param_named(interrupt_mode, efx_siena_interrupt_mode, uint, 0444);
4962306a36Sopenharmony_ciMODULE_PARM_DESC(interrupt_mode,
5062306a36Sopenharmony_ci		 "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cimodule_param_named(rss_cpus, efx_siena_rss_cpus, uint, 0444);
5362306a36Sopenharmony_ciMODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * Use separate channels for TX and RX events
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * Set this to 1 to use separate channels for TX and RX. It allows us
5962306a36Sopenharmony_ci * to control interrupt affinity separately for TX and RX.
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci * This is only used in MSI-X interrupt mode
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cibool efx_siena_separate_tx_channels;
6462306a36Sopenharmony_cimodule_param_named(efx_separate_tx_channels, efx_siena_separate_tx_channels,
6562306a36Sopenharmony_ci		   bool, 0444);
6662306a36Sopenharmony_ciMODULE_PARM_DESC(efx_separate_tx_channels,
6762306a36Sopenharmony_ci		 "Use separate channels for TX and RX");
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* Initial interrupt moderation settings.  They can be modified after
7062306a36Sopenharmony_ci * module load with ethtool.
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * The default for RX should strike a balance between increasing the
7362306a36Sopenharmony_ci * round-trip latency and reducing overhead.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_cistatic unsigned int rx_irq_mod_usec = 60;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Initial interrupt moderation settings.  They can be modified after
7862306a36Sopenharmony_ci * module load with ethtool.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * This default is chosen to ensure that a 10G link does not go idle
8162306a36Sopenharmony_ci * while a TX queue is stopped after it has become full.  A queue is
8262306a36Sopenharmony_ci * restarted when it drops below half full.  The time this takes (assuming
8362306a36Sopenharmony_ci * worst case 3 descriptors per packet and 1024 descriptors) is
8462306a36Sopenharmony_ci *   512 / 3 * 1.2 = 205 usec.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic unsigned int tx_irq_mod_usec = 150;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic bool phy_flash_cfg;
8962306a36Sopenharmony_cimodule_param(phy_flash_cfg, bool, 0644);
9062306a36Sopenharmony_ciMODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially");
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic unsigned debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
9362306a36Sopenharmony_ci			 NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
9462306a36Sopenharmony_ci			 NETIF_MSG_IFUP | NETIF_MSG_RX_ERR |
9562306a36Sopenharmony_ci			 NETIF_MSG_TX_ERR | NETIF_MSG_HW);
9662306a36Sopenharmony_cimodule_param(debug, uint, 0);
9762306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/**************************************************************************
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * Utility functions and prototypes
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci *************************************************************************/
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic void efx_remove_port(struct efx_nic *efx);
10662306a36Sopenharmony_cistatic int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog);
10762306a36Sopenharmony_cistatic int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp);
10862306a36Sopenharmony_cistatic int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs,
10962306a36Sopenharmony_ci			u32 flags);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define EFX_ASSERT_RESET_SERIALISED(efx)		\
11262306a36Sopenharmony_ci	do {						\
11362306a36Sopenharmony_ci		if ((efx->state == STATE_READY) ||	\
11462306a36Sopenharmony_ci		    (efx->state == STATE_RECOVERY) ||	\
11562306a36Sopenharmony_ci		    (efx->state == STATE_DISABLED))	\
11662306a36Sopenharmony_ci			ASSERT_RTNL();			\
11762306a36Sopenharmony_ci	} while (0)
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/**************************************************************************
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * Port handling
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci **************************************************************************/
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic void efx_fini_port(struct efx_nic *efx);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int efx_probe_port(struct efx_nic *efx)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	int rc;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev, "create port\n");
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (phy_flash_cfg)
13462306a36Sopenharmony_ci		efx->phy_mode = PHY_MODE_SPECIAL;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* Connect up MAC/PHY operations table */
13762306a36Sopenharmony_ci	rc = efx->type->probe_port(efx);
13862306a36Sopenharmony_ci	if (rc)
13962306a36Sopenharmony_ci		return rc;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Initialise MAC address to permanent address */
14262306a36Sopenharmony_ci	eth_hw_addr_set(efx->net_dev, efx->net_dev->perm_addr);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int efx_init_port(struct efx_nic *efx)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	int rc;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev, "init port\n");
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	mutex_lock(&efx->mac_lock);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	efx->port_initialized = true;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* Ensure the PHY advertises the correct flow control settings */
15862306a36Sopenharmony_ci	rc = efx_siena_mcdi_port_reconfigure(efx);
15962306a36Sopenharmony_ci	if (rc && rc != -EPERM)
16062306a36Sopenharmony_ci		goto fail;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	mutex_unlock(&efx->mac_lock);
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cifail:
16662306a36Sopenharmony_ci	mutex_unlock(&efx->mac_lock);
16762306a36Sopenharmony_ci	return rc;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic void efx_fini_port(struct efx_nic *efx)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev, "shut down port\n");
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (!efx->port_initialized)
17562306a36Sopenharmony_ci		return;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	efx->port_initialized = false;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	efx->link_state.up = false;
18062306a36Sopenharmony_ci	efx_siena_link_status_changed(efx);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void efx_remove_port(struct efx_nic *efx)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev, "destroying port\n");
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	efx->type->remove_port(efx);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/**************************************************************************
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * NIC handling
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci **************************************************************************/
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic LIST_HEAD(efx_primary_list);
19762306a36Sopenharmony_cistatic LIST_HEAD(efx_unassociated_list);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic bool efx_same_controller(struct efx_nic *left, struct efx_nic *right)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	return left->type == right->type &&
20262306a36Sopenharmony_ci		left->vpd_sn && right->vpd_sn &&
20362306a36Sopenharmony_ci		!strcmp(left->vpd_sn, right->vpd_sn);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic void efx_associate(struct efx_nic *efx)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct efx_nic *other, *next;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (efx->primary == efx) {
21162306a36Sopenharmony_ci		/* Adding primary function; look for secondaries */
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		netif_dbg(efx, probe, efx->net_dev, "adding to primary list\n");
21462306a36Sopenharmony_ci		list_add_tail(&efx->node, &efx_primary_list);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		list_for_each_entry_safe(other, next, &efx_unassociated_list,
21762306a36Sopenharmony_ci					 node) {
21862306a36Sopenharmony_ci			if (efx_same_controller(efx, other)) {
21962306a36Sopenharmony_ci				list_del(&other->node);
22062306a36Sopenharmony_ci				netif_dbg(other, probe, other->net_dev,
22162306a36Sopenharmony_ci					  "moving to secondary list of %s %s\n",
22262306a36Sopenharmony_ci					  pci_name(efx->pci_dev),
22362306a36Sopenharmony_ci					  efx->net_dev->name);
22462306a36Sopenharmony_ci				list_add_tail(&other->node,
22562306a36Sopenharmony_ci					      &efx->secondary_list);
22662306a36Sopenharmony_ci				other->primary = efx;
22762306a36Sopenharmony_ci			}
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci	} else {
23062306a36Sopenharmony_ci		/* Adding secondary function; look for primary */
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		list_for_each_entry(other, &efx_primary_list, node) {
23362306a36Sopenharmony_ci			if (efx_same_controller(efx, other)) {
23462306a36Sopenharmony_ci				netif_dbg(efx, probe, efx->net_dev,
23562306a36Sopenharmony_ci					  "adding to secondary list of %s %s\n",
23662306a36Sopenharmony_ci					  pci_name(other->pci_dev),
23762306a36Sopenharmony_ci					  other->net_dev->name);
23862306a36Sopenharmony_ci				list_add_tail(&efx->node,
23962306a36Sopenharmony_ci					      &other->secondary_list);
24062306a36Sopenharmony_ci				efx->primary = other;
24162306a36Sopenharmony_ci				return;
24262306a36Sopenharmony_ci			}
24362306a36Sopenharmony_ci		}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		netif_dbg(efx, probe, efx->net_dev,
24662306a36Sopenharmony_ci			  "adding to unassociated list\n");
24762306a36Sopenharmony_ci		list_add_tail(&efx->node, &efx_unassociated_list);
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic void efx_dissociate(struct efx_nic *efx)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct efx_nic *other, *next;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	list_del(&efx->node);
25662306a36Sopenharmony_ci	efx->primary = NULL;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	list_for_each_entry_safe(other, next, &efx->secondary_list, node) {
25962306a36Sopenharmony_ci		list_del(&other->node);
26062306a36Sopenharmony_ci		netif_dbg(other, probe, other->net_dev,
26162306a36Sopenharmony_ci			  "moving to unassociated list\n");
26262306a36Sopenharmony_ci		list_add_tail(&other->node, &efx_unassociated_list);
26362306a36Sopenharmony_ci		other->primary = NULL;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int efx_probe_nic(struct efx_nic *efx)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	int rc;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev, "creating NIC\n");
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Carry out hardware-type specific initialisation */
27462306a36Sopenharmony_ci	rc = efx->type->probe(efx);
27562306a36Sopenharmony_ci	if (rc)
27662306a36Sopenharmony_ci		return rc;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	do {
27962306a36Sopenharmony_ci		if (!efx->max_channels || !efx->max_tx_channels) {
28062306a36Sopenharmony_ci			netif_err(efx, drv, efx->net_dev,
28162306a36Sopenharmony_ci				  "Insufficient resources to allocate"
28262306a36Sopenharmony_ci				  " any channels\n");
28362306a36Sopenharmony_ci			rc = -ENOSPC;
28462306a36Sopenharmony_ci			goto fail1;
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		/* Determine the number of channels and queues by trying
28862306a36Sopenharmony_ci		 * to hook in MSI-X interrupts.
28962306a36Sopenharmony_ci		 */
29062306a36Sopenharmony_ci		rc = efx_siena_probe_interrupts(efx);
29162306a36Sopenharmony_ci		if (rc)
29262306a36Sopenharmony_ci			goto fail1;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		rc = efx_siena_set_channels(efx);
29562306a36Sopenharmony_ci		if (rc)
29662306a36Sopenharmony_ci			goto fail1;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		/* dimension_resources can fail with EAGAIN */
29962306a36Sopenharmony_ci		rc = efx->type->dimension_resources(efx);
30062306a36Sopenharmony_ci		if (rc != 0 && rc != -EAGAIN)
30162306a36Sopenharmony_ci			goto fail2;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci		if (rc == -EAGAIN)
30462306a36Sopenharmony_ci			/* try again with new max_channels */
30562306a36Sopenharmony_ci			efx_siena_remove_interrupts(efx);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	} while (rc == -EAGAIN);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (efx->n_channels > 1)
31062306a36Sopenharmony_ci		netdev_rss_key_fill(efx->rss_context.rx_hash_key,
31162306a36Sopenharmony_ci				    sizeof(efx->rss_context.rx_hash_key));
31262306a36Sopenharmony_ci	efx_siena_set_default_rx_indir_table(efx, &efx->rss_context);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* Initialise the interrupt moderation settings */
31562306a36Sopenharmony_ci	efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000);
31662306a36Sopenharmony_ci	efx_siena_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec,
31762306a36Sopenharmony_ci				      true, true);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	return 0;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cifail2:
32262306a36Sopenharmony_ci	efx_siena_remove_interrupts(efx);
32362306a36Sopenharmony_cifail1:
32462306a36Sopenharmony_ci	efx->type->remove(efx);
32562306a36Sopenharmony_ci	return rc;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void efx_remove_nic(struct efx_nic *efx)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev, "destroying NIC\n");
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	efx_siena_remove_interrupts(efx);
33362306a36Sopenharmony_ci	efx->type->remove(efx);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci/**************************************************************************
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * NIC startup/shutdown
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci *************************************************************************/
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic int efx_probe_all(struct efx_nic *efx)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	int rc;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	rc = efx_probe_nic(efx);
34762306a36Sopenharmony_ci	if (rc) {
34862306a36Sopenharmony_ci		netif_err(efx, probe, efx->net_dev, "failed to create NIC\n");
34962306a36Sopenharmony_ci		goto fail1;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	rc = efx_probe_port(efx);
35362306a36Sopenharmony_ci	if (rc) {
35462306a36Sopenharmony_ci		netif_err(efx, probe, efx->net_dev, "failed to create port\n");
35562306a36Sopenharmony_ci		goto fail2;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	BUILD_BUG_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_RXQ_MIN_ENT);
35962306a36Sopenharmony_ci	if (WARN_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_TXQ_MIN_ENT(efx))) {
36062306a36Sopenharmony_ci		rc = -EINVAL;
36162306a36Sopenharmony_ci		goto fail3;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
36562306a36Sopenharmony_ci	rc = efx->type->vswitching_probe(efx);
36662306a36Sopenharmony_ci	if (rc) /* not fatal; the PF will still work fine */
36762306a36Sopenharmony_ci		netif_warn(efx, probe, efx->net_dev,
36862306a36Sopenharmony_ci			   "failed to setup vswitching rc=%d;"
36962306a36Sopenharmony_ci			   " VFs may not function\n", rc);
37062306a36Sopenharmony_ci#endif
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	rc = efx_siena_probe_filters(efx);
37362306a36Sopenharmony_ci	if (rc) {
37462306a36Sopenharmony_ci		netif_err(efx, probe, efx->net_dev,
37562306a36Sopenharmony_ci			  "failed to create filter tables\n");
37662306a36Sopenharmony_ci		goto fail4;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	rc = efx_siena_probe_channels(efx);
38062306a36Sopenharmony_ci	if (rc)
38162306a36Sopenharmony_ci		goto fail5;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return 0;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci fail5:
38662306a36Sopenharmony_ci	efx_siena_remove_filters(efx);
38762306a36Sopenharmony_ci fail4:
38862306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
38962306a36Sopenharmony_ci	efx->type->vswitching_remove(efx);
39062306a36Sopenharmony_ci#endif
39162306a36Sopenharmony_ci fail3:
39262306a36Sopenharmony_ci	efx_remove_port(efx);
39362306a36Sopenharmony_ci fail2:
39462306a36Sopenharmony_ci	efx_remove_nic(efx);
39562306a36Sopenharmony_ci fail1:
39662306a36Sopenharmony_ci	return rc;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void efx_remove_all(struct efx_nic *efx)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	rtnl_lock();
40262306a36Sopenharmony_ci	efx_xdp_setup_prog(efx, NULL);
40362306a36Sopenharmony_ci	rtnl_unlock();
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	efx_siena_remove_channels(efx);
40662306a36Sopenharmony_ci	efx_siena_remove_filters(efx);
40762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
40862306a36Sopenharmony_ci	efx->type->vswitching_remove(efx);
40962306a36Sopenharmony_ci#endif
41062306a36Sopenharmony_ci	efx_remove_port(efx);
41162306a36Sopenharmony_ci	efx_remove_nic(efx);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/**************************************************************************
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci * Interrupt moderation
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci **************************************************************************/
41962306a36Sopenharmony_ciunsigned int efx_siena_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	if (usecs == 0)
42262306a36Sopenharmony_ci		return 0;
42362306a36Sopenharmony_ci	if (usecs * 1000 < efx->timer_quantum_ns)
42462306a36Sopenharmony_ci		return 1; /* never round down to 0 */
42562306a36Sopenharmony_ci	return usecs * 1000 / efx->timer_quantum_ns;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/* Set interrupt moderation parameters */
42962306a36Sopenharmony_ciint efx_siena_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
43062306a36Sopenharmony_ci				  unsigned int rx_usecs, bool rx_adaptive,
43162306a36Sopenharmony_ci				  bool rx_may_override_tx)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct efx_channel *channel;
43462306a36Sopenharmony_ci	unsigned int timer_max_us;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	EFX_ASSERT_RESET_SERIALISED(efx);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	timer_max_us = efx->timer_max_ns / 1000;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (tx_usecs > timer_max_us || rx_usecs > timer_max_us)
44162306a36Sopenharmony_ci		return -EINVAL;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (tx_usecs != rx_usecs && efx->tx_channel_offset == 0 &&
44462306a36Sopenharmony_ci	    !rx_may_override_tx) {
44562306a36Sopenharmony_ci		netif_err(efx, drv, efx->net_dev, "Channels are shared. "
44662306a36Sopenharmony_ci			  "RX and TX IRQ moderation must be equal\n");
44762306a36Sopenharmony_ci		return -EINVAL;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	efx->irq_rx_adaptive = rx_adaptive;
45162306a36Sopenharmony_ci	efx->irq_rx_moderation_us = rx_usecs;
45262306a36Sopenharmony_ci	efx_for_each_channel(channel, efx) {
45362306a36Sopenharmony_ci		if (efx_channel_has_rx_queue(channel))
45462306a36Sopenharmony_ci			channel->irq_moderation_us = rx_usecs;
45562306a36Sopenharmony_ci		else if (efx_channel_has_tx_queues(channel))
45662306a36Sopenharmony_ci			channel->irq_moderation_us = tx_usecs;
45762306a36Sopenharmony_ci		else if (efx_channel_is_xdp_tx(channel))
45862306a36Sopenharmony_ci			channel->irq_moderation_us = tx_usecs;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return 0;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_civoid efx_siena_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
46562306a36Sopenharmony_ci				  unsigned int *rx_usecs, bool *rx_adaptive)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	*rx_adaptive = efx->irq_rx_adaptive;
46862306a36Sopenharmony_ci	*rx_usecs = efx->irq_rx_moderation_us;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* If channels are shared between RX and TX, so is IRQ
47162306a36Sopenharmony_ci	 * moderation.  Otherwise, IRQ moderation is the same for all
47262306a36Sopenharmony_ci	 * TX channels and is not adaptive.
47362306a36Sopenharmony_ci	 */
47462306a36Sopenharmony_ci	if (efx->tx_channel_offset == 0) {
47562306a36Sopenharmony_ci		*tx_usecs = *rx_usecs;
47662306a36Sopenharmony_ci	} else {
47762306a36Sopenharmony_ci		struct efx_channel *tx_channel;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		tx_channel = efx->channel[efx->tx_channel_offset];
48062306a36Sopenharmony_ci		*tx_usecs = tx_channel->irq_moderation_us;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/**************************************************************************
48562306a36Sopenharmony_ci *
48662306a36Sopenharmony_ci * ioctls
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci *************************************************************************/
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/* Net device ioctl
49162306a36Sopenharmony_ci * Context: process, rtnl_lock() held.
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_cistatic int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(net_dev);
49662306a36Sopenharmony_ci	struct mii_ioctl_data *data = if_mii(ifr);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (cmd == SIOCSHWTSTAMP)
49962306a36Sopenharmony_ci		return efx_siena_ptp_set_ts_config(efx, ifr);
50062306a36Sopenharmony_ci	if (cmd == SIOCGHWTSTAMP)
50162306a36Sopenharmony_ci		return efx_siena_ptp_get_ts_config(efx, ifr);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* Convert phy_id from older PRTAD/DEVAD format */
50462306a36Sopenharmony_ci	if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
50562306a36Sopenharmony_ci	    (data->phy_id & 0xfc00) == 0x0400)
50662306a36Sopenharmony_ci		data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	return mdio_mii_ioctl(&efx->mdio, data, cmd);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci/**************************************************************************
51262306a36Sopenharmony_ci *
51362306a36Sopenharmony_ci * Kernel net device interface
51462306a36Sopenharmony_ci *
51562306a36Sopenharmony_ci *************************************************************************/
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. */
51862306a36Sopenharmony_cistatic int efx_net_open(struct net_device *net_dev)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(net_dev);
52162306a36Sopenharmony_ci	int rc;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n",
52462306a36Sopenharmony_ci		  raw_smp_processor_id());
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	rc = efx_check_disabled(efx);
52762306a36Sopenharmony_ci	if (rc)
52862306a36Sopenharmony_ci		return rc;
52962306a36Sopenharmony_ci	if (efx->phy_mode & PHY_MODE_SPECIAL)
53062306a36Sopenharmony_ci		return -EBUSY;
53162306a36Sopenharmony_ci	if (efx_siena_mcdi_poll_reboot(efx) && efx_siena_reset(efx, RESET_TYPE_ALL))
53262306a36Sopenharmony_ci		return -EIO;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	/* Notify the kernel of the link state polled during driver load,
53562306a36Sopenharmony_ci	 * before the monitor starts running */
53662306a36Sopenharmony_ci	efx_siena_link_status_changed(efx);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	efx_siena_start_all(efx);
53962306a36Sopenharmony_ci	if (efx->state == STATE_DISABLED || efx->reset_pending)
54062306a36Sopenharmony_ci		netif_device_detach(efx->net_dev);
54162306a36Sopenharmony_ci	efx_siena_selftest_async_start(efx);
54262306a36Sopenharmony_ci	return 0;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/* Context: process, rtnl_lock() held.
54662306a36Sopenharmony_ci * Note that the kernel will ignore our return code; this method
54762306a36Sopenharmony_ci * should really be a void.
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_cistatic int efx_net_stop(struct net_device *net_dev)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(net_dev);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
55462306a36Sopenharmony_ci		  raw_smp_processor_id());
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* Stop the device and flush all the channels */
55762306a36Sopenharmony_ci	efx_siena_stop_all(efx);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(net_dev);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (efx->type->vlan_rx_add_vid)
56762306a36Sopenharmony_ci		return efx->type->vlan_rx_add_vid(efx, proto, vid);
56862306a36Sopenharmony_ci	else
56962306a36Sopenharmony_ci		return -EOPNOTSUPP;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vid)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(net_dev);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (efx->type->vlan_rx_kill_vid)
57762306a36Sopenharmony_ci		return efx->type->vlan_rx_kill_vid(efx, proto, vid);
57862306a36Sopenharmony_ci	else
57962306a36Sopenharmony_ci		return -EOPNOTSUPP;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic const struct net_device_ops efx_netdev_ops = {
58362306a36Sopenharmony_ci	.ndo_open		= efx_net_open,
58462306a36Sopenharmony_ci	.ndo_stop		= efx_net_stop,
58562306a36Sopenharmony_ci	.ndo_get_stats64	= efx_siena_net_stats,
58662306a36Sopenharmony_ci	.ndo_tx_timeout		= efx_siena_watchdog,
58762306a36Sopenharmony_ci	.ndo_start_xmit		= efx_siena_hard_start_xmit,
58862306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
58962306a36Sopenharmony_ci	.ndo_eth_ioctl		= efx_ioctl,
59062306a36Sopenharmony_ci	.ndo_change_mtu		= efx_siena_change_mtu,
59162306a36Sopenharmony_ci	.ndo_set_mac_address	= efx_siena_set_mac_address,
59262306a36Sopenharmony_ci	.ndo_set_rx_mode	= efx_siena_set_rx_mode,
59362306a36Sopenharmony_ci	.ndo_set_features	= efx_siena_set_features,
59462306a36Sopenharmony_ci	.ndo_features_check	= efx_siena_features_check,
59562306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= efx_vlan_rx_add_vid,
59662306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= efx_vlan_rx_kill_vid,
59762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
59862306a36Sopenharmony_ci	.ndo_set_vf_mac		= efx_sriov_set_vf_mac,
59962306a36Sopenharmony_ci	.ndo_set_vf_vlan	= efx_sriov_set_vf_vlan,
60062306a36Sopenharmony_ci	.ndo_set_vf_spoofchk	= efx_sriov_set_vf_spoofchk,
60162306a36Sopenharmony_ci	.ndo_get_vf_config	= efx_sriov_get_vf_config,
60262306a36Sopenharmony_ci	.ndo_set_vf_link_state  = efx_sriov_set_vf_link_state,
60362306a36Sopenharmony_ci#endif
60462306a36Sopenharmony_ci	.ndo_get_phys_port_id   = efx_siena_get_phys_port_id,
60562306a36Sopenharmony_ci	.ndo_get_phys_port_name	= efx_siena_get_phys_port_name,
60662306a36Sopenharmony_ci	.ndo_setup_tc		= efx_siena_setup_tc,
60762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
60862306a36Sopenharmony_ci	.ndo_rx_flow_steer	= efx_siena_filter_rfs,
60962306a36Sopenharmony_ci#endif
61062306a36Sopenharmony_ci	.ndo_xdp_xmit		= efx_xdp_xmit,
61162306a36Sopenharmony_ci	.ndo_bpf		= efx_xdp
61262306a36Sopenharmony_ci};
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct bpf_prog *old_prog;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (efx->xdp_rxq_info_failed) {
61962306a36Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
62062306a36Sopenharmony_ci			  "Unable to bind XDP program due to previous failure of rxq_info\n");
62162306a36Sopenharmony_ci		return -EINVAL;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (prog && efx->net_dev->mtu > efx_siena_xdp_max_mtu(efx)) {
62562306a36Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
62662306a36Sopenharmony_ci			  "Unable to configure XDP with MTU of %d (max: %d)\n",
62762306a36Sopenharmony_ci			  efx->net_dev->mtu, efx_siena_xdp_max_mtu(efx));
62862306a36Sopenharmony_ci		return -EINVAL;
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	old_prog = rtnl_dereference(efx->xdp_prog);
63262306a36Sopenharmony_ci	rcu_assign_pointer(efx->xdp_prog, prog);
63362306a36Sopenharmony_ci	/* Release the reference that was originally passed by the caller. */
63462306a36Sopenharmony_ci	if (old_prog)
63562306a36Sopenharmony_ci		bpf_prog_put(old_prog);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return 0;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/* Context: process, rtnl_lock() held. */
64162306a36Sopenharmony_cistatic int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(dev);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	switch (xdp->command) {
64662306a36Sopenharmony_ci	case XDP_SETUP_PROG:
64762306a36Sopenharmony_ci		return efx_xdp_setup_prog(efx, xdp->prog);
64862306a36Sopenharmony_ci	default:
64962306a36Sopenharmony_ci		return -EINVAL;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs,
65462306a36Sopenharmony_ci			u32 flags)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct efx_nic *efx = netdev_priv(dev);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (!netif_running(dev))
65962306a36Sopenharmony_ci		return -EINVAL;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return efx_siena_xdp_tx_buffers(efx, n, xdpfs, flags & XDP_XMIT_FLUSH);
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic void efx_update_name(struct efx_nic *efx)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	strcpy(efx->name, efx->net_dev->name);
66762306a36Sopenharmony_ci	efx_siena_mtd_rename(efx);
66862306a36Sopenharmony_ci	efx_siena_set_channel_names(efx);
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic int efx_netdev_event(struct notifier_block *this,
67262306a36Sopenharmony_ci			    unsigned long event, void *ptr)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if ((net_dev->netdev_ops == &efx_netdev_ops) &&
67762306a36Sopenharmony_ci	    event == NETDEV_CHANGENAME)
67862306a36Sopenharmony_ci		efx_update_name(netdev_priv(net_dev));
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	return NOTIFY_DONE;
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic struct notifier_block efx_netdev_notifier = {
68462306a36Sopenharmony_ci	.notifier_call = efx_netdev_event,
68562306a36Sopenharmony_ci};
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic ssize_t phy_type_show(struct device *dev,
68862306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct efx_nic *efx = dev_get_drvdata(dev);
69162306a36Sopenharmony_ci	return sprintf(buf, "%d\n", efx->phy_type);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(phy_type);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic int efx_register_netdev(struct efx_nic *efx)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct net_device *net_dev = efx->net_dev;
69862306a36Sopenharmony_ci	struct efx_channel *channel;
69962306a36Sopenharmony_ci	int rc;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	net_dev->watchdog_timeo = 5 * HZ;
70262306a36Sopenharmony_ci	net_dev->irq = efx->pci_dev->irq;
70362306a36Sopenharmony_ci	net_dev->netdev_ops = &efx_netdev_ops;
70462306a36Sopenharmony_ci	if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0)
70562306a36Sopenharmony_ci		net_dev->priv_flags |= IFF_UNICAST_FLT;
70662306a36Sopenharmony_ci	net_dev->ethtool_ops = &efx_siena_ethtool_ops;
70762306a36Sopenharmony_ci	netif_set_tso_max_segs(net_dev, EFX_TSO_MAX_SEGS);
70862306a36Sopenharmony_ci	net_dev->min_mtu = EFX_MIN_MTU;
70962306a36Sopenharmony_ci	net_dev->max_mtu = EFX_MAX_MTU;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	rtnl_lock();
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* Enable resets to be scheduled and check whether any were
71462306a36Sopenharmony_ci	 * already requested.  If so, the NIC is probably hosed so we
71562306a36Sopenharmony_ci	 * abort.
71662306a36Sopenharmony_ci	 */
71762306a36Sopenharmony_ci	efx->state = STATE_READY;
71862306a36Sopenharmony_ci	smp_mb(); /* ensure we change state before checking reset_pending */
71962306a36Sopenharmony_ci	if (efx->reset_pending) {
72062306a36Sopenharmony_ci		pci_err(efx->pci_dev, "aborting probe due to scheduled reset\n");
72162306a36Sopenharmony_ci		rc = -EIO;
72262306a36Sopenharmony_ci		goto fail_locked;
72362306a36Sopenharmony_ci	}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	rc = dev_alloc_name(net_dev, net_dev->name);
72662306a36Sopenharmony_ci	if (rc < 0)
72762306a36Sopenharmony_ci		goto fail_locked;
72862306a36Sopenharmony_ci	efx_update_name(efx);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* Always start with carrier off; PHY events will detect the link */
73162306a36Sopenharmony_ci	netif_carrier_off(net_dev);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	rc = register_netdevice(net_dev);
73462306a36Sopenharmony_ci	if (rc)
73562306a36Sopenharmony_ci		goto fail_locked;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	efx_for_each_channel(channel, efx) {
73862306a36Sopenharmony_ci		struct efx_tx_queue *tx_queue;
73962306a36Sopenharmony_ci		efx_for_each_channel_tx_queue(tx_queue, channel)
74062306a36Sopenharmony_ci			efx_siena_init_tx_queue_core_txq(tx_queue);
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	efx_associate(efx);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	rtnl_unlock();
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
74862306a36Sopenharmony_ci	if (rc) {
74962306a36Sopenharmony_ci		netif_err(efx, drv, efx->net_dev,
75062306a36Sopenharmony_ci			  "failed to init net dev attributes\n");
75162306a36Sopenharmony_ci		goto fail_registered;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	efx_siena_init_mcdi_logging(efx);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return 0;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cifail_registered:
75962306a36Sopenharmony_ci	rtnl_lock();
76062306a36Sopenharmony_ci	efx_dissociate(efx);
76162306a36Sopenharmony_ci	unregister_netdevice(net_dev);
76262306a36Sopenharmony_cifail_locked:
76362306a36Sopenharmony_ci	efx->state = STATE_UNINIT;
76462306a36Sopenharmony_ci	rtnl_unlock();
76562306a36Sopenharmony_ci	netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
76662306a36Sopenharmony_ci	return rc;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic void efx_unregister_netdev(struct efx_nic *efx)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	if (!efx->net_dev)
77262306a36Sopenharmony_ci		return;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	BUG_ON(netdev_priv(efx->net_dev) != efx);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (efx_dev_registered(efx)) {
77762306a36Sopenharmony_ci		strscpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
77862306a36Sopenharmony_ci		efx_siena_fini_mcdi_logging(efx);
77962306a36Sopenharmony_ci		device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
78062306a36Sopenharmony_ci		unregister_netdev(efx->net_dev);
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci/**************************************************************************
78562306a36Sopenharmony_ci *
78662306a36Sopenharmony_ci * List of NICs we support
78762306a36Sopenharmony_ci *
78862306a36Sopenharmony_ci **************************************************************************/
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci/* PCI device ID table */
79162306a36Sopenharmony_cistatic const struct pci_device_id efx_pci_table[] = {
79262306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0803),	/* SFC9020 */
79362306a36Sopenharmony_ci	 .driver_data = (unsigned long)&siena_a0_nic_type},
79462306a36Sopenharmony_ci	{PCI_DEVICE(PCI_VENDOR_ID_SOLARFLARE, 0x0813),	/* SFL9021 */
79562306a36Sopenharmony_ci	 .driver_data = (unsigned long)&siena_a0_nic_type},
79662306a36Sopenharmony_ci	{0}			/* end of list */
79762306a36Sopenharmony_ci};
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/**************************************************************************
80062306a36Sopenharmony_ci *
80162306a36Sopenharmony_ci * Data housekeeping
80262306a36Sopenharmony_ci *
80362306a36Sopenharmony_ci **************************************************************************/
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_civoid efx_siena_update_sw_stats(struct efx_nic *efx, u64 *stats)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	u64 n_rx_nodesc_trunc = 0;
80862306a36Sopenharmony_ci	struct efx_channel *channel;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	efx_for_each_channel(channel, efx)
81162306a36Sopenharmony_ci		n_rx_nodesc_trunc += channel->n_rx_nodesc_trunc;
81262306a36Sopenharmony_ci	stats[GENERIC_STAT_rx_nodesc_trunc] = n_rx_nodesc_trunc;
81362306a36Sopenharmony_ci	stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops);
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/**************************************************************************
81762306a36Sopenharmony_ci *
81862306a36Sopenharmony_ci * PCI interface
81962306a36Sopenharmony_ci *
82062306a36Sopenharmony_ci **************************************************************************/
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci/* Main body of final NIC shutdown code
82362306a36Sopenharmony_ci * This is called only at module unload (or hotplug removal).
82462306a36Sopenharmony_ci */
82562306a36Sopenharmony_cistatic void efx_pci_remove_main(struct efx_nic *efx)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	/* Flush reset_work. It can no longer be scheduled since we
82862306a36Sopenharmony_ci	 * are not READY.
82962306a36Sopenharmony_ci	 */
83062306a36Sopenharmony_ci	BUG_ON(efx->state == STATE_READY);
83162306a36Sopenharmony_ci	efx_siena_flush_reset_workqueue(efx);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	efx_siena_disable_interrupts(efx);
83462306a36Sopenharmony_ci	efx_siena_clear_interrupt_affinity(efx);
83562306a36Sopenharmony_ci	efx_siena_fini_interrupt(efx);
83662306a36Sopenharmony_ci	efx_fini_port(efx);
83762306a36Sopenharmony_ci	efx->type->fini(efx);
83862306a36Sopenharmony_ci	efx_siena_fini_napi(efx);
83962306a36Sopenharmony_ci	efx_remove_all(efx);
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci/* Final NIC shutdown
84362306a36Sopenharmony_ci * This is called only at module unload (or hotplug removal).  A PF can call
84462306a36Sopenharmony_ci * this on its VFs to ensure they are unbound first.
84562306a36Sopenharmony_ci */
84662306a36Sopenharmony_cistatic void efx_pci_remove(struct pci_dev *pci_dev)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	struct efx_nic *efx;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	efx = pci_get_drvdata(pci_dev);
85162306a36Sopenharmony_ci	if (!efx)
85262306a36Sopenharmony_ci		return;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/* Mark the NIC as fini, then stop the interface */
85562306a36Sopenharmony_ci	rtnl_lock();
85662306a36Sopenharmony_ci	efx_dissociate(efx);
85762306a36Sopenharmony_ci	dev_close(efx->net_dev);
85862306a36Sopenharmony_ci	efx_siena_disable_interrupts(efx);
85962306a36Sopenharmony_ci	efx->state = STATE_UNINIT;
86062306a36Sopenharmony_ci	rtnl_unlock();
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (efx->type->sriov_fini)
86362306a36Sopenharmony_ci		efx->type->sriov_fini(efx);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	efx_unregister_netdev(efx);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	efx_siena_mtd_remove(efx);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	efx_pci_remove_main(efx);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	efx_siena_fini_io(efx);
87262306a36Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n");
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	efx_siena_fini_struct(efx);
87562306a36Sopenharmony_ci	free_netdev(efx->net_dev);
87662306a36Sopenharmony_ci};
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci/* NIC VPD information
87962306a36Sopenharmony_ci * Called during probe to display the part number of the
88062306a36Sopenharmony_ci * installed NIC.
88162306a36Sopenharmony_ci */
88262306a36Sopenharmony_cistatic void efx_probe_vpd_strings(struct efx_nic *efx)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct pci_dev *dev = efx->pci_dev;
88562306a36Sopenharmony_ci	unsigned int vpd_size, kw_len;
88662306a36Sopenharmony_ci	u8 *vpd_data;
88762306a36Sopenharmony_ci	int start;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	vpd_data = pci_vpd_alloc(dev, &vpd_size);
89062306a36Sopenharmony_ci	if (IS_ERR(vpd_data)) {
89162306a36Sopenharmony_ci		pci_warn(dev, "Unable to read VPD\n");
89262306a36Sopenharmony_ci		return;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size,
89662306a36Sopenharmony_ci					     PCI_VPD_RO_KEYWORD_PARTNO, &kw_len);
89762306a36Sopenharmony_ci	if (start < 0)
89862306a36Sopenharmony_ci		pci_err(dev, "Part number not found or incomplete\n");
89962306a36Sopenharmony_ci	else
90062306a36Sopenharmony_ci		pci_info(dev, "Part Number : %.*s\n", kw_len, vpd_data + start);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size,
90362306a36Sopenharmony_ci					     PCI_VPD_RO_KEYWORD_SERIALNO, &kw_len);
90462306a36Sopenharmony_ci	if (start < 0)
90562306a36Sopenharmony_ci		pci_err(dev, "Serial number not found or incomplete\n");
90662306a36Sopenharmony_ci	else
90762306a36Sopenharmony_ci		efx->vpd_sn = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	kfree(vpd_data);
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci/* Main body of NIC initialisation
91462306a36Sopenharmony_ci * This is called at module load (or hotplug insertion, theoretically).
91562306a36Sopenharmony_ci */
91662306a36Sopenharmony_cistatic int efx_pci_probe_main(struct efx_nic *efx)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	int rc;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* Do start-of-day initialisation */
92162306a36Sopenharmony_ci	rc = efx_probe_all(efx);
92262306a36Sopenharmony_ci	if (rc)
92362306a36Sopenharmony_ci		goto fail1;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	efx_siena_init_napi(efx);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	down_write(&efx->filter_sem);
92862306a36Sopenharmony_ci	rc = efx->type->init(efx);
92962306a36Sopenharmony_ci	up_write(&efx->filter_sem);
93062306a36Sopenharmony_ci	if (rc) {
93162306a36Sopenharmony_ci		pci_err(efx->pci_dev, "failed to initialise NIC\n");
93262306a36Sopenharmony_ci		goto fail3;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	rc = efx_init_port(efx);
93662306a36Sopenharmony_ci	if (rc) {
93762306a36Sopenharmony_ci		netif_err(efx, probe, efx->net_dev,
93862306a36Sopenharmony_ci			  "failed to initialise port\n");
93962306a36Sopenharmony_ci		goto fail4;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	rc = efx_siena_init_interrupt(efx);
94362306a36Sopenharmony_ci	if (rc)
94462306a36Sopenharmony_ci		goto fail5;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	efx_siena_set_interrupt_affinity(efx);
94762306a36Sopenharmony_ci	rc = efx_siena_enable_interrupts(efx);
94862306a36Sopenharmony_ci	if (rc)
94962306a36Sopenharmony_ci		goto fail6;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	return 0;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci fail6:
95462306a36Sopenharmony_ci	efx_siena_clear_interrupt_affinity(efx);
95562306a36Sopenharmony_ci	efx_siena_fini_interrupt(efx);
95662306a36Sopenharmony_ci fail5:
95762306a36Sopenharmony_ci	efx_fini_port(efx);
95862306a36Sopenharmony_ci fail4:
95962306a36Sopenharmony_ci	efx->type->fini(efx);
96062306a36Sopenharmony_ci fail3:
96162306a36Sopenharmony_ci	efx_siena_fini_napi(efx);
96262306a36Sopenharmony_ci	efx_remove_all(efx);
96362306a36Sopenharmony_ci fail1:
96462306a36Sopenharmony_ci	return rc;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_cistatic int efx_pci_probe_post_io(struct efx_nic *efx)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	struct net_device *net_dev = efx->net_dev;
97062306a36Sopenharmony_ci	int rc = efx_pci_probe_main(efx);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (rc)
97362306a36Sopenharmony_ci		return rc;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (efx->type->sriov_init) {
97662306a36Sopenharmony_ci		rc = efx->type->sriov_init(efx);
97762306a36Sopenharmony_ci		if (rc)
97862306a36Sopenharmony_ci			pci_err(efx->pci_dev, "SR-IOV can't be enabled rc %d\n",
97962306a36Sopenharmony_ci				rc);
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	/* Determine netdevice features */
98362306a36Sopenharmony_ci	net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
98462306a36Sopenharmony_ci			      NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL);
98562306a36Sopenharmony_ci	if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
98662306a36Sopenharmony_ci		net_dev->features |= NETIF_F_TSO6;
98762306a36Sopenharmony_ci	/* Check whether device supports TSO */
98862306a36Sopenharmony_ci	if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
98962306a36Sopenharmony_ci		net_dev->features &= ~NETIF_F_ALL_TSO;
99062306a36Sopenharmony_ci	/* Mask for features that also apply to VLAN devices */
99162306a36Sopenharmony_ci	net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
99262306a36Sopenharmony_ci				   NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
99362306a36Sopenharmony_ci				   NETIF_F_RXCSUM);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	net_dev->hw_features |= net_dev->features & ~efx->fixed_features;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* Disable receiving frames with bad FCS, by default. */
99862306a36Sopenharmony_ci	net_dev->features &= ~NETIF_F_RXALL;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	/* Disable VLAN filtering by default.  It may be enforced if
100162306a36Sopenharmony_ci	 * the feature is fixed (i.e. VLAN filters are required to
100262306a36Sopenharmony_ci	 * receive VLAN tagged packets due to vPort restrictions).
100362306a36Sopenharmony_ci	 */
100462306a36Sopenharmony_ci	net_dev->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
100562306a36Sopenharmony_ci	net_dev->features |= efx->fixed_features;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	net_dev->xdp_features = NETDEV_XDP_ACT_BASIC |
100862306a36Sopenharmony_ci				NETDEV_XDP_ACT_REDIRECT |
100962306a36Sopenharmony_ci				NETDEV_XDP_ACT_NDO_XMIT;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	rc = efx_register_netdev(efx);
101262306a36Sopenharmony_ci	if (!rc)
101362306a36Sopenharmony_ci		return 0;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	efx_pci_remove_main(efx);
101662306a36Sopenharmony_ci	return rc;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci/* NIC initialisation
102062306a36Sopenharmony_ci *
102162306a36Sopenharmony_ci * This is called at module load (or hotplug insertion,
102262306a36Sopenharmony_ci * theoretically).  It sets up PCI mappings, resets the NIC,
102362306a36Sopenharmony_ci * sets up and registers the network devices with the kernel and hooks
102462306a36Sopenharmony_ci * the interrupt service routine.  It does not prepare the device for
102562306a36Sopenharmony_ci * transmission; this is left to the first time one of the network
102662306a36Sopenharmony_ci * interfaces is brought up (i.e. efx_net_open).
102762306a36Sopenharmony_ci */
102862306a36Sopenharmony_cistatic int efx_pci_probe(struct pci_dev *pci_dev,
102962306a36Sopenharmony_ci			 const struct pci_device_id *entry)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	struct net_device *net_dev;
103262306a36Sopenharmony_ci	struct efx_nic *efx;
103362306a36Sopenharmony_ci	int rc;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Allocate and initialise a struct net_device and struct efx_nic */
103662306a36Sopenharmony_ci	net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES,
103762306a36Sopenharmony_ci				     EFX_MAX_RX_QUEUES);
103862306a36Sopenharmony_ci	if (!net_dev)
103962306a36Sopenharmony_ci		return -ENOMEM;
104062306a36Sopenharmony_ci	efx = netdev_priv(net_dev);
104162306a36Sopenharmony_ci	efx->type = (const struct efx_nic_type *) entry->driver_data;
104262306a36Sopenharmony_ci	efx->fixed_features |= NETIF_F_HIGHDMA;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	pci_set_drvdata(pci_dev, efx);
104562306a36Sopenharmony_ci	SET_NETDEV_DEV(net_dev, &pci_dev->dev);
104662306a36Sopenharmony_ci	rc = efx_siena_init_struct(efx, pci_dev, net_dev);
104762306a36Sopenharmony_ci	if (rc)
104862306a36Sopenharmony_ci		goto fail1;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	pci_info(pci_dev, "Solarflare NIC detected\n");
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (!efx->type->is_vf)
105362306a36Sopenharmony_ci		efx_probe_vpd_strings(efx);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* Set up basic I/O (BAR mappings etc) */
105662306a36Sopenharmony_ci	rc = efx_siena_init_io(efx, efx->type->mem_bar(efx),
105762306a36Sopenharmony_ci			       efx->type->max_dma_mask,
105862306a36Sopenharmony_ci			       efx->type->mem_map_size(efx));
105962306a36Sopenharmony_ci	if (rc)
106062306a36Sopenharmony_ci		goto fail2;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	rc = efx_pci_probe_post_io(efx);
106362306a36Sopenharmony_ci	if (rc) {
106462306a36Sopenharmony_ci		/* On failure, retry once immediately.
106562306a36Sopenharmony_ci		 * If we aborted probe due to a scheduled reset, dismiss it.
106662306a36Sopenharmony_ci		 */
106762306a36Sopenharmony_ci		efx->reset_pending = 0;
106862306a36Sopenharmony_ci		rc = efx_pci_probe_post_io(efx);
106962306a36Sopenharmony_ci		if (rc) {
107062306a36Sopenharmony_ci			/* On another failure, retry once more
107162306a36Sopenharmony_ci			 * after a 50-305ms delay.
107262306a36Sopenharmony_ci			 */
107362306a36Sopenharmony_ci			unsigned char r;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci			get_random_bytes(&r, 1);
107662306a36Sopenharmony_ci			msleep((unsigned int)r + 50);
107762306a36Sopenharmony_ci			efx->reset_pending = 0;
107862306a36Sopenharmony_ci			rc = efx_pci_probe_post_io(efx);
107962306a36Sopenharmony_ci		}
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci	if (rc)
108262306a36Sopenharmony_ci		goto fail3;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	/* Try to create MTDs, but allow this to fail */
108762306a36Sopenharmony_ci	rtnl_lock();
108862306a36Sopenharmony_ci	rc = efx_mtd_probe(efx);
108962306a36Sopenharmony_ci	rtnl_unlock();
109062306a36Sopenharmony_ci	if (rc && rc != -EPERM)
109162306a36Sopenharmony_ci		netif_warn(efx, probe, efx->net_dev,
109262306a36Sopenharmony_ci			   "failed to create MTDs (%d)\n", rc);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (efx->type->udp_tnl_push_ports)
109562306a36Sopenharmony_ci		efx->type->udp_tnl_push_ports(efx);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	return 0;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci fail3:
110062306a36Sopenharmony_ci	efx_siena_fini_io(efx);
110162306a36Sopenharmony_ci fail2:
110262306a36Sopenharmony_ci	efx_siena_fini_struct(efx);
110362306a36Sopenharmony_ci fail1:
110462306a36Sopenharmony_ci	WARN_ON(rc > 0);
110562306a36Sopenharmony_ci	netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc);
110662306a36Sopenharmony_ci	free_netdev(net_dev);
110762306a36Sopenharmony_ci	return rc;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci/* efx_pci_sriov_configure returns the actual number of Virtual Functions
111162306a36Sopenharmony_ci * enabled on success
111262306a36Sopenharmony_ci */
111362306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
111462306a36Sopenharmony_cistatic int efx_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	int rc;
111762306a36Sopenharmony_ci	struct efx_nic *efx = pci_get_drvdata(dev);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (efx->type->sriov_configure) {
112062306a36Sopenharmony_ci		rc = efx->type->sriov_configure(efx, num_vfs);
112162306a36Sopenharmony_ci		if (rc)
112262306a36Sopenharmony_ci			return rc;
112362306a36Sopenharmony_ci		else
112462306a36Sopenharmony_ci			return num_vfs;
112562306a36Sopenharmony_ci	} else
112662306a36Sopenharmony_ci		return -EOPNOTSUPP;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci#endif
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic int efx_pm_freeze(struct device *dev)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	struct efx_nic *efx = dev_get_drvdata(dev);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	rtnl_lock();
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	if (efx->state != STATE_DISABLED) {
113762306a36Sopenharmony_ci		efx->state = STATE_UNINIT;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		efx_device_detach_sync(efx);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci		efx_siena_stop_all(efx);
114262306a36Sopenharmony_ci		efx_siena_disable_interrupts(efx);
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	rtnl_unlock();
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	return 0;
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic void efx_pci_shutdown(struct pci_dev *pci_dev)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	struct efx_nic *efx = pci_get_drvdata(pci_dev);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (!efx)
115562306a36Sopenharmony_ci		return;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	efx_pm_freeze(&pci_dev->dev);
115862306a36Sopenharmony_ci	pci_disable_device(pci_dev);
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic int efx_pm_thaw(struct device *dev)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	int rc;
116462306a36Sopenharmony_ci	struct efx_nic *efx = dev_get_drvdata(dev);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	rtnl_lock();
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (efx->state != STATE_DISABLED) {
116962306a36Sopenharmony_ci		rc = efx_siena_enable_interrupts(efx);
117062306a36Sopenharmony_ci		if (rc)
117162306a36Sopenharmony_ci			goto fail;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci		mutex_lock(&efx->mac_lock);
117462306a36Sopenharmony_ci		efx_siena_mcdi_port_reconfigure(efx);
117562306a36Sopenharmony_ci		mutex_unlock(&efx->mac_lock);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		efx_siena_start_all(efx);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		efx_device_attach_if_not_resetting(efx);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		efx->state = STATE_READY;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		efx->type->resume_wol(efx);
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	rtnl_unlock();
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/* Reschedule any quenched resets scheduled during efx_pm_freeze() */
118962306a36Sopenharmony_ci	efx_siena_queue_reset_work(efx);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	return 0;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_cifail:
119462306a36Sopenharmony_ci	rtnl_unlock();
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return rc;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic int efx_pm_poweroff(struct device *dev)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
120262306a36Sopenharmony_ci	struct efx_nic *efx = pci_get_drvdata(pci_dev);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	efx->type->fini(efx);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	efx->reset_pending = 0;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	pci_save_state(pci_dev);
120962306a36Sopenharmony_ci	return pci_set_power_state(pci_dev, PCI_D3hot);
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci/* Used for both resume and restore */
121362306a36Sopenharmony_cistatic int efx_pm_resume(struct device *dev)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
121662306a36Sopenharmony_ci	struct efx_nic *efx = pci_get_drvdata(pci_dev);
121762306a36Sopenharmony_ci	int rc;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	rc = pci_set_power_state(pci_dev, PCI_D0);
122062306a36Sopenharmony_ci	if (rc)
122162306a36Sopenharmony_ci		return rc;
122262306a36Sopenharmony_ci	pci_restore_state(pci_dev);
122362306a36Sopenharmony_ci	rc = pci_enable_device(pci_dev);
122462306a36Sopenharmony_ci	if (rc)
122562306a36Sopenharmony_ci		return rc;
122662306a36Sopenharmony_ci	pci_set_master(efx->pci_dev);
122762306a36Sopenharmony_ci	rc = efx->type->reset(efx, RESET_TYPE_ALL);
122862306a36Sopenharmony_ci	if (rc)
122962306a36Sopenharmony_ci		return rc;
123062306a36Sopenharmony_ci	down_write(&efx->filter_sem);
123162306a36Sopenharmony_ci	rc = efx->type->init(efx);
123262306a36Sopenharmony_ci	up_write(&efx->filter_sem);
123362306a36Sopenharmony_ci	if (rc)
123462306a36Sopenharmony_ci		return rc;
123562306a36Sopenharmony_ci	rc = efx_pm_thaw(dev);
123662306a36Sopenharmony_ci	return rc;
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_cistatic int efx_pm_suspend(struct device *dev)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	int rc;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	efx_pm_freeze(dev);
124462306a36Sopenharmony_ci	rc = efx_pm_poweroff(dev);
124562306a36Sopenharmony_ci	if (rc)
124662306a36Sopenharmony_ci		efx_pm_resume(dev);
124762306a36Sopenharmony_ci	return rc;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic const struct dev_pm_ops efx_pm_ops = {
125162306a36Sopenharmony_ci	.suspend	= efx_pm_suspend,
125262306a36Sopenharmony_ci	.resume		= efx_pm_resume,
125362306a36Sopenharmony_ci	.freeze		= efx_pm_freeze,
125462306a36Sopenharmony_ci	.thaw		= efx_pm_thaw,
125562306a36Sopenharmony_ci	.poweroff	= efx_pm_poweroff,
125662306a36Sopenharmony_ci	.restore	= efx_pm_resume,
125762306a36Sopenharmony_ci};
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic struct pci_driver efx_pci_driver = {
126062306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
126162306a36Sopenharmony_ci	.id_table	= efx_pci_table,
126262306a36Sopenharmony_ci	.probe		= efx_pci_probe,
126362306a36Sopenharmony_ci	.remove		= efx_pci_remove,
126462306a36Sopenharmony_ci	.driver.pm	= &efx_pm_ops,
126562306a36Sopenharmony_ci	.shutdown	= efx_pci_shutdown,
126662306a36Sopenharmony_ci	.err_handler	= &efx_siena_err_handlers,
126762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
126862306a36Sopenharmony_ci	.sriov_configure = efx_pci_sriov_configure,
126962306a36Sopenharmony_ci#endif
127062306a36Sopenharmony_ci};
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/**************************************************************************
127362306a36Sopenharmony_ci *
127462306a36Sopenharmony_ci * Kernel module interface
127562306a36Sopenharmony_ci *
127662306a36Sopenharmony_ci *************************************************************************/
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic int __init efx_init_module(void)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	int rc;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	pr_info("Solarflare Siena driver\n");
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	rc = register_netdevice_notifier(&efx_netdev_notifier);
128562306a36Sopenharmony_ci	if (rc)
128662306a36Sopenharmony_ci		goto err_notifier;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
128962306a36Sopenharmony_ci	rc = efx_init_sriov();
129062306a36Sopenharmony_ci	if (rc)
129162306a36Sopenharmony_ci		goto err_sriov;
129262306a36Sopenharmony_ci#endif
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	rc = efx_siena_create_reset_workqueue();
129562306a36Sopenharmony_ci	if (rc)
129662306a36Sopenharmony_ci		goto err_reset;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	rc = pci_register_driver(&efx_pci_driver);
129962306a36Sopenharmony_ci	if (rc < 0)
130062306a36Sopenharmony_ci		goto err_pci;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return 0;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci err_pci:
130562306a36Sopenharmony_ci	efx_siena_destroy_reset_workqueue();
130662306a36Sopenharmony_ci err_reset:
130762306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
130862306a36Sopenharmony_ci	efx_fini_sriov();
130962306a36Sopenharmony_ci err_sriov:
131062306a36Sopenharmony_ci#endif
131162306a36Sopenharmony_ci	unregister_netdevice_notifier(&efx_netdev_notifier);
131262306a36Sopenharmony_ci err_notifier:
131362306a36Sopenharmony_ci	return rc;
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic void __exit efx_exit_module(void)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	pr_info("Solarflare Siena driver unloading\n");
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	pci_unregister_driver(&efx_pci_driver);
132162306a36Sopenharmony_ci	efx_siena_destroy_reset_workqueue();
132262306a36Sopenharmony_ci#ifdef CONFIG_SFC_SIENA_SRIOV
132362306a36Sopenharmony_ci	efx_fini_sriov();
132462306a36Sopenharmony_ci#endif
132562306a36Sopenharmony_ci	unregister_netdevice_notifier(&efx_netdev_notifier);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cimodule_init(efx_init_module);
133062306a36Sopenharmony_cimodule_exit(efx_exit_module);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ciMODULE_AUTHOR("Solarflare Communications and "
133362306a36Sopenharmony_ci	      "Michael Brown <mbrown@fensystems.co.uk>");
133462306a36Sopenharmony_ciMODULE_DESCRIPTION("Solarflare Siena network driver");
133562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
133662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, efx_pci_table);
1337