162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/types.h>
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci#include <linux/pci.h>
762306a36Sopenharmony_ci#include <linux/netdevice.h>
862306a36Sopenharmony_ci#include <linux/string.h>
962306a36Sopenharmony_ci#include <linux/etherdevice.h>
1062306a36Sopenharmony_ci#include <linux/phylink.h>
1162306a36Sopenharmony_ci#include <net/ip.h>
1262306a36Sopenharmony_ci#include <linux/if_vlan.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "../libwx/wx_type.h"
1562306a36Sopenharmony_ci#include "../libwx/wx_lib.h"
1662306a36Sopenharmony_ci#include "../libwx/wx_hw.h"
1762306a36Sopenharmony_ci#include "txgbe_type.h"
1862306a36Sopenharmony_ci#include "txgbe_hw.h"
1962306a36Sopenharmony_ci#include "txgbe_phy.h"
2062306a36Sopenharmony_ci#include "txgbe_ethtool.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cichar txgbe_driver_name[] = "txgbe";
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* txgbe_pci_tbl - PCI Device ID Table
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last
2762306a36Sopenharmony_ci * Last entry must be all 0s
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
3062306a36Sopenharmony_ci *   Class, Class Mask, private data (not used) }
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_cistatic const struct pci_device_id txgbe_pci_tbl[] = {
3362306a36Sopenharmony_ci	{ PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_SP1000), 0},
3462306a36Sopenharmony_ci	{ PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_WX1820), 0},
3562306a36Sopenharmony_ci	/* required last entry */
3662306a36Sopenharmony_ci	{ .device = 0 }
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define DEFAULT_DEBUG_LEVEL_SHIFT 3
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void txgbe_check_minimum_link(struct wx *wx)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct pci_dev *pdev;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	pdev = wx->pdev;
4662306a36Sopenharmony_ci	pcie_print_link_status(pdev);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/**
5062306a36Sopenharmony_ci * txgbe_enumerate_functions - Get the number of ports this device has
5162306a36Sopenharmony_ci * @wx: wx structure
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci * This function enumerates the phsyical functions co-located on a single slot,
5462306a36Sopenharmony_ci * in order to determine how many ports a device has. This is most useful in
5562306a36Sopenharmony_ci * determining the required GT/s of PCIe bandwidth necessary for optimal
5662306a36Sopenharmony_ci * performance.
5762306a36Sopenharmony_ci **/
5862306a36Sopenharmony_cistatic int txgbe_enumerate_functions(struct wx *wx)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct pci_dev *entry, *pdev = wx->pdev;
6162306a36Sopenharmony_ci	int physfns = 0;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	list_for_each_entry(entry, &pdev->bus->devices, bus_list) {
6462306a36Sopenharmony_ci		/* When the devices on the bus don't all match our device ID,
6562306a36Sopenharmony_ci		 * we can't reliably determine the correct number of
6662306a36Sopenharmony_ci		 * functions. This can occur if a function has been direct
6762306a36Sopenharmony_ci		 * attached to a virtual machine using VT-d.
6862306a36Sopenharmony_ci		 */
6962306a36Sopenharmony_ci		if (entry->vendor != pdev->vendor ||
7062306a36Sopenharmony_ci		    entry->device != pdev->device)
7162306a36Sopenharmony_ci			return -EINVAL;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		physfns++;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return physfns;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/**
8062306a36Sopenharmony_ci * txgbe_irq_enable - Enable default interrupt generation settings
8162306a36Sopenharmony_ci * @wx: pointer to private structure
8262306a36Sopenharmony_ci * @queues: enable irqs for queues
8362306a36Sopenharmony_ci **/
8462306a36Sopenharmony_cistatic void txgbe_irq_enable(struct wx *wx, bool queues)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* unmask interrupt */
8962306a36Sopenharmony_ci	wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
9062306a36Sopenharmony_ci	if (queues)
9162306a36Sopenharmony_ci		wx_intr_enable(wx, TXGBE_INTR_QALL(wx));
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/**
9562306a36Sopenharmony_ci * txgbe_intr - msi/legacy mode Interrupt Handler
9662306a36Sopenharmony_ci * @irq: interrupt number
9762306a36Sopenharmony_ci * @data: pointer to a network interface device structure
9862306a36Sopenharmony_ci **/
9962306a36Sopenharmony_cistatic irqreturn_t txgbe_intr(int __always_unused irq, void *data)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct wx_q_vector *q_vector;
10262306a36Sopenharmony_ci	struct wx *wx  = data;
10362306a36Sopenharmony_ci	struct pci_dev *pdev;
10462306a36Sopenharmony_ci	u32 eicr;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	q_vector = wx->q_vector[0];
10762306a36Sopenharmony_ci	pdev = wx->pdev;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	eicr = wx_misc_isb(wx, WX_ISB_VEC0);
11062306a36Sopenharmony_ci	if (!eicr) {
11162306a36Sopenharmony_ci		/* shared interrupt alert!
11262306a36Sopenharmony_ci		 * the interrupt that we masked before the ICR read.
11362306a36Sopenharmony_ci		 */
11462306a36Sopenharmony_ci		if (netif_running(wx->netdev))
11562306a36Sopenharmony_ci			txgbe_irq_enable(wx, true);
11662306a36Sopenharmony_ci		return IRQ_NONE;        /* Not our interrupt */
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci	wx->isb_mem[WX_ISB_VEC0] = 0;
11962306a36Sopenharmony_ci	if (!(pdev->msi_enabled))
12062306a36Sopenharmony_ci		wr32(wx, WX_PX_INTA, 1);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	wx->isb_mem[WX_ISB_MISC] = 0;
12362306a36Sopenharmony_ci	/* would disable interrupts here but it is auto disabled */
12462306a36Sopenharmony_ci	napi_schedule_irqoff(&q_vector->napi);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* re-enable link(maybe) and non-queue interrupts, no flush.
12762306a36Sopenharmony_ci	 * txgbe_poll will re-enable the queue interrupts
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	if (netif_running(wx->netdev))
13062306a36Sopenharmony_ci		txgbe_irq_enable(wx, false);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return IRQ_HANDLED;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/**
13662306a36Sopenharmony_ci * txgbe_request_msix_irqs - Initialize MSI-X interrupts
13762306a36Sopenharmony_ci * @wx: board private structure
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci * Allocate MSI-X vectors and request interrupts from the kernel.
14062306a36Sopenharmony_ci **/
14162306a36Sopenharmony_cistatic int txgbe_request_msix_irqs(struct wx *wx)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct net_device *netdev = wx->netdev;
14462306a36Sopenharmony_ci	int vector, err;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	for (vector = 0; vector < wx->num_q_vectors; vector++) {
14762306a36Sopenharmony_ci		struct wx_q_vector *q_vector = wx->q_vector[vector];
14862306a36Sopenharmony_ci		struct msix_entry *entry = &wx->msix_entries[vector];
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci		if (q_vector->tx.ring && q_vector->rx.ring)
15162306a36Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
15262306a36Sopenharmony_ci				 "%s-TxRx-%d", netdev->name, entry->entry);
15362306a36Sopenharmony_ci		else
15462306a36Sopenharmony_ci			/* skip this unused q_vector */
15562306a36Sopenharmony_ci			continue;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		err = request_irq(entry->vector, wx_msix_clean_rings, 0,
15862306a36Sopenharmony_ci				  q_vector->name, q_vector);
15962306a36Sopenharmony_ci		if (err) {
16062306a36Sopenharmony_ci			wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n",
16162306a36Sopenharmony_ci			       q_vector->name, err);
16262306a36Sopenharmony_ci			goto free_queue_irqs;
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cifree_queue_irqs:
16962306a36Sopenharmony_ci	while (vector) {
17062306a36Sopenharmony_ci		vector--;
17162306a36Sopenharmony_ci		free_irq(wx->msix_entries[vector].vector,
17262306a36Sopenharmony_ci			 wx->q_vector[vector]);
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci	wx_reset_interrupt_capability(wx);
17562306a36Sopenharmony_ci	return err;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * txgbe_request_irq - initialize interrupts
18062306a36Sopenharmony_ci * @wx: board private structure
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci * Attempt to configure interrupts using the best available
18362306a36Sopenharmony_ci * capabilities of the hardware and kernel.
18462306a36Sopenharmony_ci **/
18562306a36Sopenharmony_cistatic int txgbe_request_irq(struct wx *wx)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct net_device *netdev = wx->netdev;
18862306a36Sopenharmony_ci	struct pci_dev *pdev = wx->pdev;
18962306a36Sopenharmony_ci	int err;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (pdev->msix_enabled)
19262306a36Sopenharmony_ci		err = txgbe_request_msix_irqs(wx);
19362306a36Sopenharmony_ci	else if (pdev->msi_enabled)
19462306a36Sopenharmony_ci		err = request_irq(wx->pdev->irq, &txgbe_intr, 0,
19562306a36Sopenharmony_ci				  netdev->name, wx);
19662306a36Sopenharmony_ci	else
19762306a36Sopenharmony_ci		err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED,
19862306a36Sopenharmony_ci				  netdev->name, wx);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (err)
20162306a36Sopenharmony_ci		wx_err(wx, "request_irq failed, Error %d\n", err);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return err;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic void txgbe_up_complete(struct wx *wx)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct net_device *netdev = wx->netdev;
20962306a36Sopenharmony_ci	struct txgbe *txgbe;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	wx_control_hw(wx, true);
21262306a36Sopenharmony_ci	wx_configure_vectors(wx);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* make sure to complete pre-operations */
21562306a36Sopenharmony_ci	smp_mb__before_atomic();
21662306a36Sopenharmony_ci	wx_napi_enable_all(wx);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	txgbe = netdev_to_txgbe(netdev);
21962306a36Sopenharmony_ci	phylink_start(txgbe->phylink);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* clear any pending interrupts, may auto mask */
22262306a36Sopenharmony_ci	rd32(wx, WX_PX_IC(0));
22362306a36Sopenharmony_ci	rd32(wx, WX_PX_IC(1));
22462306a36Sopenharmony_ci	rd32(wx, WX_PX_MISC_IC);
22562306a36Sopenharmony_ci	txgbe_irq_enable(wx, true);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* enable transmits */
22862306a36Sopenharmony_ci	netif_tx_start_all_queues(netdev);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic void txgbe_reset(struct wx *wx)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct net_device *netdev = wx->netdev;
23462306a36Sopenharmony_ci	u8 old_addr[ETH_ALEN];
23562306a36Sopenharmony_ci	int err;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	err = txgbe_reset_hw(wx);
23862306a36Sopenharmony_ci	if (err != 0)
23962306a36Sopenharmony_ci		wx_err(wx, "Hardware Error: %d\n", err);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	wx_start_hw(wx);
24262306a36Sopenharmony_ci	/* do not flush user set addresses */
24362306a36Sopenharmony_ci	memcpy(old_addr, &wx->mac_table[0].addr, netdev->addr_len);
24462306a36Sopenharmony_ci	wx_flush_sw_mac_table(wx);
24562306a36Sopenharmony_ci	wx_mac_set_default_filter(wx, old_addr);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void txgbe_disable_device(struct wx *wx)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct net_device *netdev = wx->netdev;
25162306a36Sopenharmony_ci	u32 i;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	wx_disable_pcie_master(wx);
25462306a36Sopenharmony_ci	/* disable receives */
25562306a36Sopenharmony_ci	wx_disable_rx(wx);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* disable all enabled rx queues */
25862306a36Sopenharmony_ci	for (i = 0; i < wx->num_rx_queues; i++)
25962306a36Sopenharmony_ci		/* this call also flushes the previous write */
26062306a36Sopenharmony_ci		wx_disable_rx_queue(wx, wx->rx_ring[i]);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	netif_tx_stop_all_queues(netdev);
26362306a36Sopenharmony_ci	netif_tx_disable(netdev);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	wx_irq_disable(wx);
26662306a36Sopenharmony_ci	wx_napi_disable_all(wx);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (wx->bus.func < 2)
26962306a36Sopenharmony_ci		wr32m(wx, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wx->bus.func), 0);
27062306a36Sopenharmony_ci	else
27162306a36Sopenharmony_ci		wx_err(wx, "%s: invalid bus lan id %d\n",
27262306a36Sopenharmony_ci		       __func__, wx->bus.func);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
27562306a36Sopenharmony_ci	      ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {
27662306a36Sopenharmony_ci		/* disable mac transmiter */
27762306a36Sopenharmony_ci		wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* disable transmits in the hardware now that interrupts are off */
28162306a36Sopenharmony_ci	for (i = 0; i < wx->num_tx_queues; i++) {
28262306a36Sopenharmony_ci		u8 reg_idx = wx->tx_ring[i]->reg_idx;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH);
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* Disable the Tx DMA engine */
28862306a36Sopenharmony_ci	wr32m(wx, WX_TDM_CTL, WX_TDM_CTL_TE, 0);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic void txgbe_down(struct wx *wx)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct txgbe *txgbe = netdev_to_txgbe(wx->netdev);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	txgbe_disable_device(wx);
29662306a36Sopenharmony_ci	txgbe_reset(wx);
29762306a36Sopenharmony_ci	phylink_stop(txgbe->phylink);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	wx_clean_all_tx_rings(wx);
30062306a36Sopenharmony_ci	wx_clean_all_rx_rings(wx);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/**
30462306a36Sopenharmony_ci *  txgbe_init_type_code - Initialize the shared code
30562306a36Sopenharmony_ci *  @wx: pointer to hardware structure
30662306a36Sopenharmony_ci **/
30762306a36Sopenharmony_cistatic void txgbe_init_type_code(struct wx *wx)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	u8 device_type = wx->subsystem_device_id & 0xF0;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	switch (wx->device_id) {
31262306a36Sopenharmony_ci	case TXGBE_DEV_ID_SP1000:
31362306a36Sopenharmony_ci	case TXGBE_DEV_ID_WX1820:
31462306a36Sopenharmony_ci		wx->mac.type = wx_mac_sp;
31562306a36Sopenharmony_ci		break;
31662306a36Sopenharmony_ci	default:
31762306a36Sopenharmony_ci		wx->mac.type = wx_mac_unknown;
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	switch (device_type) {
32262306a36Sopenharmony_ci	case TXGBE_ID_SFP:
32362306a36Sopenharmony_ci		wx->media_type = sp_media_fiber;
32462306a36Sopenharmony_ci		break;
32562306a36Sopenharmony_ci	case TXGBE_ID_XAUI:
32662306a36Sopenharmony_ci	case TXGBE_ID_SGMII:
32762306a36Sopenharmony_ci		wx->media_type = sp_media_copper;
32862306a36Sopenharmony_ci		break;
32962306a36Sopenharmony_ci	case TXGBE_ID_KR_KX_KX4:
33062306a36Sopenharmony_ci	case TXGBE_ID_MAC_XAUI:
33162306a36Sopenharmony_ci	case TXGBE_ID_MAC_SGMII:
33262306a36Sopenharmony_ci		wx->media_type = sp_media_backplane;
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	case TXGBE_ID_SFI_XAUI:
33562306a36Sopenharmony_ci		if (wx->bus.func == 0)
33662306a36Sopenharmony_ci			wx->media_type = sp_media_fiber;
33762306a36Sopenharmony_ci		else
33862306a36Sopenharmony_ci			wx->media_type = sp_media_copper;
33962306a36Sopenharmony_ci		break;
34062306a36Sopenharmony_ci	default:
34162306a36Sopenharmony_ci		wx->media_type = sp_media_unknown;
34262306a36Sopenharmony_ci		break;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/**
34762306a36Sopenharmony_ci * txgbe_sw_init - Initialize general software structures (struct wx)
34862306a36Sopenharmony_ci * @wx: board private structure to initialize
34962306a36Sopenharmony_ci **/
35062306a36Sopenharmony_cistatic int txgbe_sw_init(struct wx *wx)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	u16 msix_count = 0;
35362306a36Sopenharmony_ci	int err;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	wx->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES;
35662306a36Sopenharmony_ci	wx->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES;
35762306a36Sopenharmony_ci	wx->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES;
35862306a36Sopenharmony_ci	wx->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE;
35962306a36Sopenharmony_ci	wx->mac.vft_size = TXGBE_SP_VFT_TBL_SIZE;
36062306a36Sopenharmony_ci	wx->mac.rx_pb_size = TXGBE_SP_RX_PB_SIZE;
36162306a36Sopenharmony_ci	wx->mac.tx_pb_size = TXGBE_SP_TDB_PB_SZ;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* PCI config space info */
36462306a36Sopenharmony_ci	err = wx_sw_init(wx);
36562306a36Sopenharmony_ci	if (err < 0)
36662306a36Sopenharmony_ci		return err;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	txgbe_init_type_code(wx);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Set common capability flags and settings */
37162306a36Sopenharmony_ci	wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;
37262306a36Sopenharmony_ci	err = wx_get_pcie_msix_counts(wx, &msix_count, TXGBE_MAX_MSIX_VECTORS);
37362306a36Sopenharmony_ci	if (err)
37462306a36Sopenharmony_ci		wx_err(wx, "Do not support MSI-X\n");
37562306a36Sopenharmony_ci	wx->mac.max_msix_vectors = msix_count;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* enable itr by default in dynamic mode */
37862306a36Sopenharmony_ci	wx->rx_itr_setting = 1;
37962306a36Sopenharmony_ci	wx->tx_itr_setting = 1;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* set default ring sizes */
38262306a36Sopenharmony_ci	wx->tx_ring_count = TXGBE_DEFAULT_TXD;
38362306a36Sopenharmony_ci	wx->rx_ring_count = TXGBE_DEFAULT_RXD;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* set default work limits */
38662306a36Sopenharmony_ci	wx->tx_work_limit = TXGBE_DEFAULT_TX_WORK;
38762306a36Sopenharmony_ci	wx->rx_work_limit = TXGBE_DEFAULT_RX_WORK;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/**
39362306a36Sopenharmony_ci * txgbe_open - Called when a network interface is made active
39462306a36Sopenharmony_ci * @netdev: network interface device structure
39562306a36Sopenharmony_ci *
39662306a36Sopenharmony_ci * Returns 0 on success, negative value on failure
39762306a36Sopenharmony_ci *
39862306a36Sopenharmony_ci * The open entry point is called when a network interface is made
39962306a36Sopenharmony_ci * active by the system (IFF_UP).
40062306a36Sopenharmony_ci **/
40162306a36Sopenharmony_cistatic int txgbe_open(struct net_device *netdev)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
40462306a36Sopenharmony_ci	int err;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	err = wx_setup_resources(wx);
40762306a36Sopenharmony_ci	if (err)
40862306a36Sopenharmony_ci		goto err_reset;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	wx_configure(wx);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	err = txgbe_request_irq(wx);
41362306a36Sopenharmony_ci	if (err)
41462306a36Sopenharmony_ci		goto err_free_isb;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* Notify the stack of the actual queue counts. */
41762306a36Sopenharmony_ci	err = netif_set_real_num_tx_queues(netdev, wx->num_tx_queues);
41862306a36Sopenharmony_ci	if (err)
41962306a36Sopenharmony_ci		goto err_free_irq;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	err = netif_set_real_num_rx_queues(netdev, wx->num_rx_queues);
42262306a36Sopenharmony_ci	if (err)
42362306a36Sopenharmony_ci		goto err_free_irq;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	txgbe_up_complete(wx);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return 0;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cierr_free_irq:
43062306a36Sopenharmony_ci	wx_free_irq(wx);
43162306a36Sopenharmony_cierr_free_isb:
43262306a36Sopenharmony_ci	wx_free_isb_resources(wx);
43362306a36Sopenharmony_cierr_reset:
43462306a36Sopenharmony_ci	txgbe_reset(wx);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return err;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/**
44062306a36Sopenharmony_ci * txgbe_close_suspend - actions necessary to both suspend and close flows
44162306a36Sopenharmony_ci * @wx: the private wx struct
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * This function should contain the necessary work common to both suspending
44462306a36Sopenharmony_ci * and closing of the device.
44562306a36Sopenharmony_ci */
44662306a36Sopenharmony_cistatic void txgbe_close_suspend(struct wx *wx)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	txgbe_disable_device(wx);
44962306a36Sopenharmony_ci	wx_free_resources(wx);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/**
45362306a36Sopenharmony_ci * txgbe_close - Disables a network interface
45462306a36Sopenharmony_ci * @netdev: network interface device structure
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci * Returns 0, this is not allowed to fail
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * The close entry point is called when an interface is de-activated
45962306a36Sopenharmony_ci * by the OS.  The hardware is still under the drivers control, but
46062306a36Sopenharmony_ci * needs to be disabled.  A global MAC reset is issued to stop the
46162306a36Sopenharmony_ci * hardware, and all transmit and receive resources are freed.
46262306a36Sopenharmony_ci **/
46362306a36Sopenharmony_cistatic int txgbe_close(struct net_device *netdev)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	txgbe_down(wx);
46862306a36Sopenharmony_ci	wx_free_irq(wx);
46962306a36Sopenharmony_ci	wx_free_resources(wx);
47062306a36Sopenharmony_ci	wx_control_hw(wx, false);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return 0;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void txgbe_dev_shutdown(struct pci_dev *pdev)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct wx *wx = pci_get_drvdata(pdev);
47862306a36Sopenharmony_ci	struct net_device *netdev;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	netdev = wx->netdev;
48162306a36Sopenharmony_ci	netif_device_detach(netdev);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	rtnl_lock();
48462306a36Sopenharmony_ci	if (netif_running(netdev))
48562306a36Sopenharmony_ci		txgbe_close_suspend(wx);
48662306a36Sopenharmony_ci	rtnl_unlock();
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	wx_control_hw(wx, false);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	pci_disable_device(pdev);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic void txgbe_shutdown(struct pci_dev *pdev)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	txgbe_dev_shutdown(pdev);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (system_state == SYSTEM_POWER_OFF) {
49862306a36Sopenharmony_ci		pci_wake_from_d3(pdev, false);
49962306a36Sopenharmony_ci		pci_set_power_state(pdev, PCI_D3hot);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic const struct net_device_ops txgbe_netdev_ops = {
50462306a36Sopenharmony_ci	.ndo_open               = txgbe_open,
50562306a36Sopenharmony_ci	.ndo_stop               = txgbe_close,
50662306a36Sopenharmony_ci	.ndo_change_mtu         = wx_change_mtu,
50762306a36Sopenharmony_ci	.ndo_start_xmit         = wx_xmit_frame,
50862306a36Sopenharmony_ci	.ndo_set_rx_mode        = wx_set_rx_mode,
50962306a36Sopenharmony_ci	.ndo_set_features       = wx_set_features,
51062306a36Sopenharmony_ci	.ndo_validate_addr      = eth_validate_addr,
51162306a36Sopenharmony_ci	.ndo_set_mac_address    = wx_set_mac,
51262306a36Sopenharmony_ci	.ndo_get_stats64        = wx_get_stats64,
51362306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid    = wx_vlan_rx_add_vid,
51462306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid   = wx_vlan_rx_kill_vid,
51562306a36Sopenharmony_ci};
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/**
51862306a36Sopenharmony_ci * txgbe_probe - Device Initialization Routine
51962306a36Sopenharmony_ci * @pdev: PCI device information struct
52062306a36Sopenharmony_ci * @ent: entry in txgbe_pci_tbl
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci * Returns 0 on success, negative on failure
52362306a36Sopenharmony_ci *
52462306a36Sopenharmony_ci * txgbe_probe initializes an adapter identified by a pci_dev structure.
52562306a36Sopenharmony_ci * The OS initialization, configuring of the wx private structure,
52662306a36Sopenharmony_ci * and a hardware reset occur.
52762306a36Sopenharmony_ci **/
52862306a36Sopenharmony_cistatic int txgbe_probe(struct pci_dev *pdev,
52962306a36Sopenharmony_ci		       const struct pci_device_id __always_unused *ent)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct net_device *netdev;
53262306a36Sopenharmony_ci	int err, expected_gts;
53362306a36Sopenharmony_ci	struct wx *wx = NULL;
53462306a36Sopenharmony_ci	struct txgbe *txgbe;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0;
53762306a36Sopenharmony_ci	u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0;
53862306a36Sopenharmony_ci	u16 build = 0, major = 0, patch = 0;
53962306a36Sopenharmony_ci	u8 part_str[TXGBE_PBANUM_LENGTH];
54062306a36Sopenharmony_ci	u32 etrack_id = 0;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	err = pci_enable_device_mem(pdev);
54362306a36Sopenharmony_ci	if (err)
54462306a36Sopenharmony_ci		return err;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
54762306a36Sopenharmony_ci	if (err) {
54862306a36Sopenharmony_ci		dev_err(&pdev->dev,
54962306a36Sopenharmony_ci			"No usable DMA configuration, aborting\n");
55062306a36Sopenharmony_ci		goto err_pci_disable_dev;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	err = pci_request_selected_regions(pdev,
55462306a36Sopenharmony_ci					   pci_select_bars(pdev, IORESOURCE_MEM),
55562306a36Sopenharmony_ci					   txgbe_driver_name);
55662306a36Sopenharmony_ci	if (err) {
55762306a36Sopenharmony_ci		dev_err(&pdev->dev,
55862306a36Sopenharmony_ci			"pci_request_selected_regions failed 0x%x\n", err);
55962306a36Sopenharmony_ci		goto err_pci_disable_dev;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	pci_set_master(pdev);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	netdev = devm_alloc_etherdev_mqs(&pdev->dev,
56562306a36Sopenharmony_ci					 sizeof(struct wx),
56662306a36Sopenharmony_ci					 TXGBE_MAX_TX_QUEUES,
56762306a36Sopenharmony_ci					 TXGBE_MAX_RX_QUEUES);
56862306a36Sopenharmony_ci	if (!netdev) {
56962306a36Sopenharmony_ci		err = -ENOMEM;
57062306a36Sopenharmony_ci		goto err_pci_release_regions;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	wx = netdev_priv(netdev);
57662306a36Sopenharmony_ci	wx->netdev = netdev;
57762306a36Sopenharmony_ci	wx->pdev = pdev;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	wx->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	wx->hw_addr = devm_ioremap(&pdev->dev,
58262306a36Sopenharmony_ci				   pci_resource_start(pdev, 0),
58362306a36Sopenharmony_ci				   pci_resource_len(pdev, 0));
58462306a36Sopenharmony_ci	if (!wx->hw_addr) {
58562306a36Sopenharmony_ci		err = -EIO;
58662306a36Sopenharmony_ci		goto err_pci_release_regions;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	wx->driver_name = txgbe_driver_name;
59062306a36Sopenharmony_ci	txgbe_set_ethtool_ops(netdev);
59162306a36Sopenharmony_ci	netdev->netdev_ops = &txgbe_netdev_ops;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* setup the private structure */
59462306a36Sopenharmony_ci	err = txgbe_sw_init(wx);
59562306a36Sopenharmony_ci	if (err)
59662306a36Sopenharmony_ci		goto err_free_mac_table;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/* check if flash load is done after hw power up */
59962306a36Sopenharmony_ci	err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PERST);
60062306a36Sopenharmony_ci	if (err)
60162306a36Sopenharmony_ci		goto err_free_mac_table;
60262306a36Sopenharmony_ci	err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PWRRST);
60362306a36Sopenharmony_ci	if (err)
60462306a36Sopenharmony_ci		goto err_free_mac_table;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	err = wx_mng_present(wx);
60762306a36Sopenharmony_ci	if (err) {
60862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Management capability is not present\n");
60962306a36Sopenharmony_ci		goto err_free_mac_table;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	err = txgbe_reset_hw(wx);
61362306a36Sopenharmony_ci	if (err) {
61462306a36Sopenharmony_ci		dev_err(&pdev->dev, "HW Init failed: %d\n", err);
61562306a36Sopenharmony_ci		goto err_free_mac_table;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	netdev->features = NETIF_F_SG |
61962306a36Sopenharmony_ci			   NETIF_F_TSO |
62062306a36Sopenharmony_ci			   NETIF_F_TSO6 |
62162306a36Sopenharmony_ci			   NETIF_F_RXHASH |
62262306a36Sopenharmony_ci			   NETIF_F_RXCSUM |
62362306a36Sopenharmony_ci			   NETIF_F_HW_CSUM;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	netdev->gso_partial_features =  NETIF_F_GSO_ENCAP_ALL;
62662306a36Sopenharmony_ci	netdev->features |= netdev->gso_partial_features;
62762306a36Sopenharmony_ci	netdev->features |= NETIF_F_SCTP_CRC;
62862306a36Sopenharmony_ci	netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID;
62962306a36Sopenharmony_ci	netdev->hw_enc_features |= netdev->vlan_features;
63062306a36Sopenharmony_ci	netdev->features |= NETIF_F_VLAN_FEATURES;
63162306a36Sopenharmony_ci	/* copy netdev features into list of user selectable features */
63262306a36Sopenharmony_ci	netdev->hw_features |= netdev->features | NETIF_F_RXALL;
63362306a36Sopenharmony_ci	netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;
63462306a36Sopenharmony_ci	netdev->features |= NETIF_F_HIGHDMA;
63562306a36Sopenharmony_ci	netdev->hw_features |= NETIF_F_GRO;
63662306a36Sopenharmony_ci	netdev->features |= NETIF_F_GRO;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT;
63962306a36Sopenharmony_ci	netdev->priv_flags |= IFF_SUPP_NOFCS;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	netdev->min_mtu = ETH_MIN_MTU;
64262306a36Sopenharmony_ci	netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE -
64362306a36Sopenharmony_ci			  (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* make sure the EEPROM is good */
64662306a36Sopenharmony_ci	err = txgbe_validate_eeprom_checksum(wx, NULL);
64762306a36Sopenharmony_ci	if (err != 0) {
64862306a36Sopenharmony_ci		dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
64962306a36Sopenharmony_ci		wr32(wx, WX_MIS_RST, WX_MIS_RST_SW_RST);
65062306a36Sopenharmony_ci		err = -EIO;
65162306a36Sopenharmony_ci		goto err_free_mac_table;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	eth_hw_addr_set(netdev, wx->mac.perm_addr);
65562306a36Sopenharmony_ci	wx_mac_set_default_filter(wx, wx->mac.perm_addr);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	err = wx_init_interrupt_scheme(wx);
65862306a36Sopenharmony_ci	if (err)
65962306a36Sopenharmony_ci		goto err_free_mac_table;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/* Save off EEPROM version number and Option Rom version which
66262306a36Sopenharmony_ci	 * together make a unique identify for the eeprom
66362306a36Sopenharmony_ci	 */
66462306a36Sopenharmony_ci	wx_read_ee_hostif(wx,
66562306a36Sopenharmony_ci			  wx->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_H,
66662306a36Sopenharmony_ci			  &eeprom_verh);
66762306a36Sopenharmony_ci	wx_read_ee_hostif(wx,
66862306a36Sopenharmony_ci			  wx->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_L,
66962306a36Sopenharmony_ci			  &eeprom_verl);
67062306a36Sopenharmony_ci	etrack_id = (eeprom_verh << 16) | eeprom_verl;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	wx_read_ee_hostif(wx,
67362306a36Sopenharmony_ci			  wx->eeprom.sw_region_offset + TXGBE_ISCSI_BOOT_CONFIG,
67462306a36Sopenharmony_ci			  &offset);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/* Make sure offset to SCSI block is valid */
67762306a36Sopenharmony_ci	if (!(offset == 0x0) && !(offset == 0xffff)) {
67862306a36Sopenharmony_ci		wx_read_ee_hostif(wx, offset + 0x84, &eeprom_cfg_blkh);
67962306a36Sopenharmony_ci		wx_read_ee_hostif(wx, offset + 0x83, &eeprom_cfg_blkl);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci		/* Only display Option Rom if exist */
68262306a36Sopenharmony_ci		if (eeprom_cfg_blkl && eeprom_cfg_blkh) {
68362306a36Sopenharmony_ci			major = eeprom_cfg_blkl >> 8;
68462306a36Sopenharmony_ci			build = (eeprom_cfg_blkl << 8) | (eeprom_cfg_blkh >> 8);
68562306a36Sopenharmony_ci			patch = eeprom_cfg_blkh & 0x00ff;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci			snprintf(wx->eeprom_id, sizeof(wx->eeprom_id),
68862306a36Sopenharmony_ci				 "0x%08x, %d.%d.%d", etrack_id, major, build,
68962306a36Sopenharmony_ci				 patch);
69062306a36Sopenharmony_ci		} else {
69162306a36Sopenharmony_ci			snprintf(wx->eeprom_id, sizeof(wx->eeprom_id),
69262306a36Sopenharmony_ci				 "0x%08x", etrack_id);
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci	} else {
69562306a36Sopenharmony_ci		snprintf(wx->eeprom_id, sizeof(wx->eeprom_id),
69662306a36Sopenharmony_ci			 "0x%08x", etrack_id);
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (etrack_id < 0x20010)
70062306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);
70362306a36Sopenharmony_ci	if (!txgbe) {
70462306a36Sopenharmony_ci		err = -ENOMEM;
70562306a36Sopenharmony_ci		goto err_release_hw;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	txgbe->wx = wx;
70962306a36Sopenharmony_ci	wx->priv = txgbe;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	err = txgbe_init_phy(txgbe);
71262306a36Sopenharmony_ci	if (err)
71362306a36Sopenharmony_ci		goto err_release_hw;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	err = register_netdev(netdev);
71662306a36Sopenharmony_ci	if (err)
71762306a36Sopenharmony_ci		goto err_remove_phy;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	pci_set_drvdata(pdev, wx);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	netif_tx_stop_all_queues(netdev);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* calculate the expected PCIe bandwidth required for optimal
72462306a36Sopenharmony_ci	 * performance. Note that some older parts will never have enough
72562306a36Sopenharmony_ci	 * bandwidth due to being older generation PCIe parts. We clamp these
72662306a36Sopenharmony_ci	 * parts to ensure that no warning is displayed, as this could confuse
72762306a36Sopenharmony_ci	 * users otherwise.
72862306a36Sopenharmony_ci	 */
72962306a36Sopenharmony_ci	expected_gts = txgbe_enumerate_functions(wx) * 10;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* don't check link if we failed to enumerate functions */
73262306a36Sopenharmony_ci	if (expected_gts > 0)
73362306a36Sopenharmony_ci		txgbe_check_minimum_link(wx);
73462306a36Sopenharmony_ci	else
73562306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n");
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/* First try to read PBA as a string */
73862306a36Sopenharmony_ci	err = txgbe_read_pba_string(wx, part_str, TXGBE_PBANUM_LENGTH);
73962306a36Sopenharmony_ci	if (err)
74062306a36Sopenharmony_ci		strncpy(part_str, "Unknown", TXGBE_PBANUM_LENGTH);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	netif_info(wx, probe, netdev, "%pM\n", netdev->dev_addr);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	return 0;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cierr_remove_phy:
74762306a36Sopenharmony_ci	txgbe_remove_phy(txgbe);
74862306a36Sopenharmony_cierr_release_hw:
74962306a36Sopenharmony_ci	wx_clear_interrupt_scheme(wx);
75062306a36Sopenharmony_ci	wx_control_hw(wx, false);
75162306a36Sopenharmony_cierr_free_mac_table:
75262306a36Sopenharmony_ci	kfree(wx->mac_table);
75362306a36Sopenharmony_cierr_pci_release_regions:
75462306a36Sopenharmony_ci	pci_release_selected_regions(pdev,
75562306a36Sopenharmony_ci				     pci_select_bars(pdev, IORESOURCE_MEM));
75662306a36Sopenharmony_cierr_pci_disable_dev:
75762306a36Sopenharmony_ci	pci_disable_device(pdev);
75862306a36Sopenharmony_ci	return err;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci/**
76262306a36Sopenharmony_ci * txgbe_remove - Device Removal Routine
76362306a36Sopenharmony_ci * @pdev: PCI device information struct
76462306a36Sopenharmony_ci *
76562306a36Sopenharmony_ci * txgbe_remove is called by the PCI subsystem to alert the driver
76662306a36Sopenharmony_ci * that it should release a PCI device.  The could be caused by a
76762306a36Sopenharmony_ci * Hot-Plug event, or because the driver is going to be removed from
76862306a36Sopenharmony_ci * memory.
76962306a36Sopenharmony_ci **/
77062306a36Sopenharmony_cistatic void txgbe_remove(struct pci_dev *pdev)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	struct wx *wx = pci_get_drvdata(pdev);
77362306a36Sopenharmony_ci	struct txgbe *txgbe = wx->priv;
77462306a36Sopenharmony_ci	struct net_device *netdev;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	netdev = wx->netdev;
77762306a36Sopenharmony_ci	unregister_netdev(netdev);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	txgbe_remove_phy(txgbe);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	pci_release_selected_regions(pdev,
78262306a36Sopenharmony_ci				     pci_select_bars(pdev, IORESOURCE_MEM));
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	kfree(wx->mac_table);
78562306a36Sopenharmony_ci	wx_clear_interrupt_scheme(wx);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	pci_disable_device(pdev);
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic struct pci_driver txgbe_driver = {
79162306a36Sopenharmony_ci	.name     = txgbe_driver_name,
79262306a36Sopenharmony_ci	.id_table = txgbe_pci_tbl,
79362306a36Sopenharmony_ci	.probe    = txgbe_probe,
79462306a36Sopenharmony_ci	.remove   = txgbe_remove,
79562306a36Sopenharmony_ci	.shutdown = txgbe_shutdown,
79662306a36Sopenharmony_ci};
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cimodule_pci_driver(txgbe_driver);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, txgbe_pci_tbl);
80162306a36Sopenharmony_ciMODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
80262306a36Sopenharmony_ciMODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver");
80362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
804