brintos

brintos / linux-shallow public Read only

0
0
Text · 18.7 KiB · 9318022 Raw
776 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */3 4#include <linux/types.h>5#include <linux/module.h>6#include <linux/pci.h>7#include <linux/netdevice.h>8#include <linux/string.h>9#include <linux/etherdevice.h>10#include <linux/phylink.h>11#include <net/ip.h>12#include <linux/if_vlan.h>13 14#include "../libwx/wx_type.h"15#include "../libwx/wx_lib.h"16#include "../libwx/wx_hw.h"17#include "txgbe_type.h"18#include "txgbe_hw.h"19#include "txgbe_phy.h"20#include "txgbe_irq.h"21#include "txgbe_fdir.h"22#include "txgbe_ethtool.h"23 24char txgbe_driver_name[] = "txgbe";25 26/* txgbe_pci_tbl - PCI Device ID Table27 *28 * Wildcard entries (PCI_ANY_ID) should come last29 * Last entry must be all 0s30 *31 * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,32 *   Class, Class Mask, private data (not used) }33 */34static const struct pci_device_id txgbe_pci_tbl[] = {35	{ PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_SP1000), 0},36	{ PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_WX1820), 0},37	/* required last entry */38	{ .device = 0 }39};40 41#define DEFAULT_DEBUG_LEVEL_SHIFT 342 43static void txgbe_check_minimum_link(struct wx *wx)44{45	struct pci_dev *pdev;46 47	pdev = wx->pdev;48	pcie_print_link_status(pdev);49}50 51/**52 * txgbe_enumerate_functions - Get the number of ports this device has53 * @wx: wx structure54 *55 * This function enumerates the phsyical functions co-located on a single slot,56 * in order to determine how many ports a device has. This is most useful in57 * determining the required GT/s of PCIe bandwidth necessary for optimal58 * performance.59 **/60static int txgbe_enumerate_functions(struct wx *wx)61{62	struct pci_dev *entry, *pdev = wx->pdev;63	int physfns = 0;64 65	list_for_each_entry(entry, &pdev->bus->devices, bus_list) {66		/* When the devices on the bus don't all match our device ID,67		 * we can't reliably determine the correct number of68		 * functions. This can occur if a function has been direct69		 * attached to a virtual machine using VT-d.70		 */71		if (entry->vendor != pdev->vendor ||72		    entry->device != pdev->device)73			return -EINVAL;74 75		physfns++;76	}77 78	return physfns;79}80 81static void txgbe_up_complete(struct wx *wx)82{83	struct net_device *netdev = wx->netdev;84 85	txgbe_reinit_gpio_intr(wx);86	wx_control_hw(wx, true);87	wx_configure_vectors(wx);88 89	/* make sure to complete pre-operations */90	smp_mb__before_atomic();91	wx_napi_enable_all(wx);92 93	phylink_start(wx->phylink);94 95	/* clear any pending interrupts, may auto mask */96	rd32(wx, WX_PX_IC(0));97	rd32(wx, WX_PX_IC(1));98	rd32(wx, WX_PX_MISC_IC);99	txgbe_irq_enable(wx, true);100 101	/* enable transmits */102	netif_tx_start_all_queues(netdev);103}104 105static void txgbe_reset(struct wx *wx)106{107	struct net_device *netdev = wx->netdev;108	u8 old_addr[ETH_ALEN];109	int err;110 111	err = txgbe_reset_hw(wx);112	if (err != 0)113		wx_err(wx, "Hardware Error: %d\n", err);114 115	wx_start_hw(wx);116	/* do not flush user set addresses */117	memcpy(old_addr, &wx->mac_table[0].addr, netdev->addr_len);118	wx_flush_sw_mac_table(wx);119	wx_mac_set_default_filter(wx, old_addr);120}121 122static void txgbe_disable_device(struct wx *wx)123{124	struct net_device *netdev = wx->netdev;125	u32 i;126 127	wx_disable_pcie_master(wx);128	/* disable receives */129	wx_disable_rx(wx);130 131	/* disable all enabled rx queues */132	for (i = 0; i < wx->num_rx_queues; i++)133		/* this call also flushes the previous write */134		wx_disable_rx_queue(wx, wx->rx_ring[i]);135 136	netif_tx_stop_all_queues(netdev);137	netif_tx_disable(netdev);138 139	wx_irq_disable(wx);140	wx_napi_disable_all(wx);141 142	if (wx->bus.func < 2)143		wr32m(wx, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wx->bus.func), 0);144	else145		wx_err(wx, "%s: invalid bus lan id %d\n",146		       __func__, wx->bus.func);147 148	if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||149	      ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {150		/* disable mac transmiter */151		wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);152	}153 154	/* disable transmits in the hardware now that interrupts are off */155	for (i = 0; i < wx->num_tx_queues; i++) {156		u8 reg_idx = wx->tx_ring[i]->reg_idx;157 158		wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH);159	}160 161	/* Disable the Tx DMA engine */162	wr32m(wx, WX_TDM_CTL, WX_TDM_CTL_TE, 0);163 164	wx_update_stats(wx);165}166 167void txgbe_down(struct wx *wx)168{169	txgbe_disable_device(wx);170	txgbe_reset(wx);171	phylink_stop(wx->phylink);172 173	wx_clean_all_tx_rings(wx);174	wx_clean_all_rx_rings(wx);175}176 177void txgbe_up(struct wx *wx)178{179	wx_configure(wx);180	txgbe_up_complete(wx);181}182 183/**184 *  txgbe_init_type_code - Initialize the shared code185 *  @wx: pointer to hardware structure186 **/187static void txgbe_init_type_code(struct wx *wx)188{189	u8 device_type = wx->subsystem_device_id & 0xF0;190 191	switch (wx->device_id) {192	case TXGBE_DEV_ID_SP1000:193	case TXGBE_DEV_ID_WX1820:194		wx->mac.type = wx_mac_sp;195		break;196	default:197		wx->mac.type = wx_mac_unknown;198		break;199	}200 201	switch (device_type) {202	case TXGBE_ID_SFP:203		wx->media_type = sp_media_fiber;204		break;205	case TXGBE_ID_XAUI:206	case TXGBE_ID_SGMII:207		wx->media_type = sp_media_copper;208		break;209	case TXGBE_ID_KR_KX_KX4:210	case TXGBE_ID_MAC_XAUI:211	case TXGBE_ID_MAC_SGMII:212		wx->media_type = sp_media_backplane;213		break;214	case TXGBE_ID_SFI_XAUI:215		if (wx->bus.func == 0)216			wx->media_type = sp_media_fiber;217		else218			wx->media_type = sp_media_copper;219		break;220	default:221		wx->media_type = sp_media_unknown;222		break;223	}224}225 226/**227 * txgbe_sw_init - Initialize general software structures (struct wx)228 * @wx: board private structure to initialize229 **/230static int txgbe_sw_init(struct wx *wx)231{232	u16 msix_count = 0;233	int err;234 235	wx->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES;236	wx->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES;237	wx->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES;238	wx->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE;239	wx->mac.vft_size = TXGBE_SP_VFT_TBL_SIZE;240	wx->mac.rx_pb_size = TXGBE_SP_RX_PB_SIZE;241	wx->mac.tx_pb_size = TXGBE_SP_TDB_PB_SZ;242 243	/* PCI config space info */244	err = wx_sw_init(wx);245	if (err < 0)246		return err;247 248	txgbe_init_type_code(wx);249 250	/* Set common capability flags and settings */251	wx->max_q_vectors = TXGBE_MAX_MSIX_VECTORS;252	err = wx_get_pcie_msix_counts(wx, &msix_count, TXGBE_MAX_MSIX_VECTORS);253	if (err)254		wx_err(wx, "Do not support MSI-X\n");255	wx->mac.max_msix_vectors = msix_count;256 257	wx->ring_feature[RING_F_RSS].limit = min_t(int, TXGBE_MAX_RSS_INDICES,258						   num_online_cpus());259	wx->rss_enabled = true;260 261	wx->ring_feature[RING_F_FDIR].limit = min_t(int, TXGBE_MAX_FDIR_INDICES,262						    num_online_cpus());263	set_bit(WX_FLAG_FDIR_CAPABLE, wx->flags);264	set_bit(WX_FLAG_FDIR_HASH, wx->flags);265	wx->atr_sample_rate = TXGBE_DEFAULT_ATR_SAMPLE_RATE;266	wx->atr = txgbe_atr;267	wx->configure_fdir = txgbe_configure_fdir;268 269	/* enable itr by default in dynamic mode */270	wx->rx_itr_setting = 1;271	wx->tx_itr_setting = 1;272 273	/* set default ring sizes */274	wx->tx_ring_count = TXGBE_DEFAULT_TXD;275	wx->rx_ring_count = TXGBE_DEFAULT_RXD;276 277	/* set default work limits */278	wx->tx_work_limit = TXGBE_DEFAULT_TX_WORK;279	wx->rx_work_limit = TXGBE_DEFAULT_RX_WORK;280 281	wx->do_reset = txgbe_do_reset;282 283	return 0;284}285 286static void txgbe_init_fdir(struct txgbe *txgbe)287{288	txgbe->fdir_filter_count = 0;289	spin_lock_init(&txgbe->fdir_perfect_lock);290}291 292/**293 * txgbe_open - Called when a network interface is made active294 * @netdev: network interface device structure295 *296 * Returns 0 on success, negative value on failure297 *298 * The open entry point is called when a network interface is made299 * active by the system (IFF_UP).300 **/301static int txgbe_open(struct net_device *netdev)302{303	struct wx *wx = netdev_priv(netdev);304	int err;305 306	err = wx_setup_resources(wx);307	if (err)308		goto err_reset;309 310	wx_configure(wx);311 312	err = txgbe_request_queue_irqs(wx);313	if (err)314		goto err_free_resources;315 316	/* Notify the stack of the actual queue counts. */317	err = netif_set_real_num_tx_queues(netdev, wx->num_tx_queues);318	if (err)319		goto err_free_irq;320 321	err = netif_set_real_num_rx_queues(netdev, wx->num_rx_queues);322	if (err)323		goto err_free_irq;324 325	txgbe_up_complete(wx);326 327	return 0;328 329err_free_irq:330	wx_free_irq(wx);331err_free_resources:332	wx_free_resources(wx);333err_reset:334	txgbe_reset(wx);335 336	return err;337}338 339/**340 * txgbe_close_suspend - actions necessary to both suspend and close flows341 * @wx: the private wx struct342 *343 * This function should contain the necessary work common to both suspending344 * and closing of the device.345 */346static void txgbe_close_suspend(struct wx *wx)347{348	txgbe_disable_device(wx);349	wx_free_resources(wx);350}351 352/**353 * txgbe_close - Disables a network interface354 * @netdev: network interface device structure355 *356 * Returns 0, this is not allowed to fail357 *358 * The close entry point is called when an interface is de-activated359 * by the OS.  The hardware is still under the drivers control, but360 * needs to be disabled.  A global MAC reset is issued to stop the361 * hardware, and all transmit and receive resources are freed.362 **/363static int txgbe_close(struct net_device *netdev)364{365	struct wx *wx = netdev_priv(netdev);366 367	txgbe_down(wx);368	wx_free_irq(wx);369	wx_free_resources(wx);370	txgbe_fdir_filter_exit(wx);371	wx_control_hw(wx, false);372 373	return 0;374}375 376static void txgbe_dev_shutdown(struct pci_dev *pdev)377{378	struct wx *wx = pci_get_drvdata(pdev);379	struct net_device *netdev;380 381	netdev = wx->netdev;382	netif_device_detach(netdev);383 384	rtnl_lock();385	if (netif_running(netdev))386		txgbe_close_suspend(wx);387	rtnl_unlock();388 389	wx_control_hw(wx, false);390 391	pci_disable_device(pdev);392}393 394static void txgbe_shutdown(struct pci_dev *pdev)395{396	txgbe_dev_shutdown(pdev);397 398	if (system_state == SYSTEM_POWER_OFF) {399		pci_wake_from_d3(pdev, false);400		pci_set_power_state(pdev, PCI_D3hot);401	}402}403 404/**405 * txgbe_setup_tc - routine to configure net_device for multiple traffic406 * classes.407 *408 * @dev: net device to configure409 * @tc: number of traffic classes to enable410 */411int txgbe_setup_tc(struct net_device *dev, u8 tc)412{413	struct wx *wx = netdev_priv(dev);414	struct txgbe *txgbe = wx->priv;415 416	/* Hardware has to reinitialize queues and interrupts to417	 * match packet buffer alignment. Unfortunately, the418	 * hardware is not flexible enough to do this dynamically.419	 */420	if (netif_running(dev))421		txgbe_close(dev);422	else423		txgbe_reset(wx);424 425	txgbe_free_misc_irq(txgbe);426	wx_clear_interrupt_scheme(wx);427 428	if (tc)429		netdev_set_num_tc(dev, tc);430	else431		netdev_reset_tc(dev);432 433	wx_init_interrupt_scheme(wx);434	txgbe_setup_misc_irq(txgbe);435 436	if (netif_running(dev))437		txgbe_open(dev);438 439	return 0;440}441 442static void txgbe_reinit_locked(struct wx *wx)443{444	int err = 0;445 446	netif_trans_update(wx->netdev);447 448	err = wx_set_state_reset(wx);449	if (err) {450		wx_err(wx, "wait device reset timeout\n");451		return;452	}453 454	txgbe_down(wx);455	txgbe_up(wx);456 457	clear_bit(WX_STATE_RESETTING, wx->state);458}459 460void txgbe_do_reset(struct net_device *netdev)461{462	struct wx *wx = netdev_priv(netdev);463 464	if (netif_running(netdev))465		txgbe_reinit_locked(wx);466	else467		txgbe_reset(wx);468}469 470static const struct net_device_ops txgbe_netdev_ops = {471	.ndo_open               = txgbe_open,472	.ndo_stop               = txgbe_close,473	.ndo_change_mtu         = wx_change_mtu,474	.ndo_start_xmit         = wx_xmit_frame,475	.ndo_set_rx_mode        = wx_set_rx_mode,476	.ndo_set_features       = wx_set_features,477	.ndo_fix_features       = wx_fix_features,478	.ndo_validate_addr      = eth_validate_addr,479	.ndo_set_mac_address    = wx_set_mac,480	.ndo_get_stats64        = wx_get_stats64,481	.ndo_vlan_rx_add_vid    = wx_vlan_rx_add_vid,482	.ndo_vlan_rx_kill_vid   = wx_vlan_rx_kill_vid,483};484 485/**486 * txgbe_probe - Device Initialization Routine487 * @pdev: PCI device information struct488 * @ent: entry in txgbe_pci_tbl489 *490 * Returns 0 on success, negative on failure491 *492 * txgbe_probe initializes an adapter identified by a pci_dev structure.493 * The OS initialization, configuring of the wx private structure,494 * and a hardware reset occur.495 **/496static int txgbe_probe(struct pci_dev *pdev,497		       const struct pci_device_id __always_unused *ent)498{499	struct net_device *netdev;500	int err, expected_gts;501	struct wx *wx = NULL;502	struct txgbe *txgbe;503 504	u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0;505	u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0;506	u16 build = 0, major = 0, patch = 0;507	u32 etrack_id = 0;508 509	err = pci_enable_device_mem(pdev);510	if (err)511		return err;512 513	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));514	if (err) {515		dev_err(&pdev->dev,516			"No usable DMA configuration, aborting\n");517		goto err_pci_disable_dev;518	}519 520	err = pci_request_selected_regions(pdev,521					   pci_select_bars(pdev, IORESOURCE_MEM),522					   txgbe_driver_name);523	if (err) {524		dev_err(&pdev->dev,525			"pci_request_selected_regions failed 0x%x\n", err);526		goto err_pci_disable_dev;527	}528 529	pci_set_master(pdev);530 531	netdev = devm_alloc_etherdev_mqs(&pdev->dev,532					 sizeof(struct wx),533					 TXGBE_MAX_TX_QUEUES,534					 TXGBE_MAX_RX_QUEUES);535	if (!netdev) {536		err = -ENOMEM;537		goto err_pci_release_regions;538	}539 540	SET_NETDEV_DEV(netdev, &pdev->dev);541 542	wx = netdev_priv(netdev);543	wx->netdev = netdev;544	wx->pdev = pdev;545 546	wx->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;547 548	wx->hw_addr = devm_ioremap(&pdev->dev,549				   pci_resource_start(pdev, 0),550				   pci_resource_len(pdev, 0));551	if (!wx->hw_addr) {552		err = -EIO;553		goto err_pci_release_regions;554	}555 556	wx->driver_name = txgbe_driver_name;557	txgbe_set_ethtool_ops(netdev);558	netdev->netdev_ops = &txgbe_netdev_ops;559 560	/* setup the private structure */561	err = txgbe_sw_init(wx);562	if (err)563		goto err_free_mac_table;564 565	/* check if flash load is done after hw power up */566	err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PERST);567	if (err)568		goto err_free_mac_table;569	err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PWRRST);570	if (err)571		goto err_free_mac_table;572 573	err = wx_mng_present(wx);574	if (err) {575		dev_err(&pdev->dev, "Management capability is not present\n");576		goto err_free_mac_table;577	}578 579	err = txgbe_reset_hw(wx);580	if (err) {581		dev_err(&pdev->dev, "HW Init failed: %d\n", err);582		goto err_free_mac_table;583	}584 585	netdev->features = NETIF_F_SG |586			   NETIF_F_TSO |587			   NETIF_F_TSO6 |588			   NETIF_F_RXHASH |589			   NETIF_F_RXCSUM |590			   NETIF_F_HW_CSUM;591 592	netdev->gso_partial_features =  NETIF_F_GSO_ENCAP_ALL;593	netdev->features |= netdev->gso_partial_features;594	netdev->features |= NETIF_F_SCTP_CRC;595	netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID;596	netdev->hw_enc_features |= netdev->vlan_features;597	netdev->features |= NETIF_F_VLAN_FEATURES;598	/* copy netdev features into list of user selectable features */599	netdev->hw_features |= netdev->features | NETIF_F_RXALL;600	netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;601	netdev->features |= NETIF_F_HIGHDMA;602	netdev->hw_features |= NETIF_F_GRO;603	netdev->features |= NETIF_F_GRO;604 605	netdev->priv_flags |= IFF_UNICAST_FLT;606	netdev->priv_flags |= IFF_SUPP_NOFCS;607	netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;608 609	netdev->min_mtu = ETH_MIN_MTU;610	netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE -611			  (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);612 613	/* make sure the EEPROM is good */614	err = txgbe_validate_eeprom_checksum(wx, NULL);615	if (err != 0) {616		dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");617		wr32(wx, WX_MIS_RST, WX_MIS_RST_SW_RST);618		err = -EIO;619		goto err_free_mac_table;620	}621 622	eth_hw_addr_set(netdev, wx->mac.perm_addr);623	wx_mac_set_default_filter(wx, wx->mac.perm_addr);624 625	err = wx_init_interrupt_scheme(wx);626	if (err)627		goto err_free_mac_table;628 629	/* Save off EEPROM version number and Option Rom version which630	 * together make a unique identify for the eeprom631	 */632	wx_read_ee_hostif(wx,633			  wx->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_H,634			  &eeprom_verh);635	wx_read_ee_hostif(wx,636			  wx->eeprom.sw_region_offset + TXGBE_EEPROM_VERSION_L,637			  &eeprom_verl);638	etrack_id = (eeprom_verh << 16) | eeprom_verl;639 640	wx_read_ee_hostif(wx,641			  wx->eeprom.sw_region_offset + TXGBE_ISCSI_BOOT_CONFIG,642			  &offset);643 644	/* Make sure offset to SCSI block is valid */645	if (!(offset == 0x0) && !(offset == 0xffff)) {646		wx_read_ee_hostif(wx, offset + 0x84, &eeprom_cfg_blkh);647		wx_read_ee_hostif(wx, offset + 0x83, &eeprom_cfg_blkl);648 649		/* Only display Option Rom if exist */650		if (eeprom_cfg_blkl && eeprom_cfg_blkh) {651			major = eeprom_cfg_blkl >> 8;652			build = (eeprom_cfg_blkl << 8) | (eeprom_cfg_blkh >> 8);653			patch = eeprom_cfg_blkh & 0x00ff;654 655			snprintf(wx->eeprom_id, sizeof(wx->eeprom_id),656				 "0x%08x, %d.%d.%d", etrack_id, major, build,657				 patch);658		} else {659			snprintf(wx->eeprom_id, sizeof(wx->eeprom_id),660				 "0x%08x", etrack_id);661		}662	} else {663		snprintf(wx->eeprom_id, sizeof(wx->eeprom_id),664			 "0x%08x", etrack_id);665	}666 667	if (etrack_id < 0x20010)668		dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n");669 670	txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL);671	if (!txgbe) {672		err = -ENOMEM;673		goto err_release_hw;674	}675 676	txgbe->wx = wx;677	wx->priv = txgbe;678 679	txgbe_init_fdir(txgbe);680 681	err = txgbe_setup_misc_irq(txgbe);682	if (err)683		goto err_release_hw;684 685	err = txgbe_init_phy(txgbe);686	if (err)687		goto err_free_misc_irq;688 689	err = register_netdev(netdev);690	if (err)691		goto err_remove_phy;692 693	pci_set_drvdata(pdev, wx);694 695	netif_tx_stop_all_queues(netdev);696 697	/* calculate the expected PCIe bandwidth required for optimal698	 * performance. Note that some older parts will never have enough699	 * bandwidth due to being older generation PCIe parts. We clamp these700	 * parts to ensure that no warning is displayed, as this could confuse701	 * users otherwise.702	 */703	expected_gts = txgbe_enumerate_functions(wx) * 10;704 705	/* don't check link if we failed to enumerate functions */706	if (expected_gts > 0)707		txgbe_check_minimum_link(wx);708	else709		dev_warn(&pdev->dev, "Failed to enumerate PF devices.\n");710 711	return 0;712 713err_remove_phy:714	txgbe_remove_phy(txgbe);715err_free_misc_irq:716	txgbe_free_misc_irq(txgbe);717err_release_hw:718	wx_clear_interrupt_scheme(wx);719	wx_control_hw(wx, false);720err_free_mac_table:721	kfree(wx->mac_table);722err_pci_release_regions:723	pci_release_selected_regions(pdev,724				     pci_select_bars(pdev, IORESOURCE_MEM));725err_pci_disable_dev:726	pci_disable_device(pdev);727	return err;728}729 730/**731 * txgbe_remove - Device Removal Routine732 * @pdev: PCI device information struct733 *734 * txgbe_remove is called by the PCI subsystem to alert the driver735 * that it should release a PCI device.  The could be caused by a736 * Hot-Plug event, or because the driver is going to be removed from737 * memory.738 **/739static void txgbe_remove(struct pci_dev *pdev)740{741	struct wx *wx = pci_get_drvdata(pdev);742	struct txgbe *txgbe = wx->priv;743	struct net_device *netdev;744 745	netdev = wx->netdev;746	unregister_netdev(netdev);747 748	txgbe_remove_phy(txgbe);749	txgbe_free_misc_irq(txgbe);750	wx_free_isb_resources(wx);751 752	pci_release_selected_regions(pdev,753				     pci_select_bars(pdev, IORESOURCE_MEM));754 755	kfree(wx->rss_key);756	kfree(wx->mac_table);757	wx_clear_interrupt_scheme(wx);758 759	pci_disable_device(pdev);760}761 762static struct pci_driver txgbe_driver = {763	.name     = txgbe_driver_name,764	.id_table = txgbe_pci_tbl,765	.probe    = txgbe_probe,766	.remove   = txgbe_remove,767	.shutdown = txgbe_shutdown,768};769 770module_pci_driver(txgbe_driver);771 772MODULE_DEVICE_TABLE(pci, txgbe_pci_tbl);773MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");774MODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver");775MODULE_LICENSE("GPL");776