diff options
Diffstat (limited to 'drivers/net/ethernet/wangxun/txgbe/txgbe_main.c')
-rw-r--r-- | drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 405 |
1 files changed, 276 insertions, 129 deletions
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 3b151c410a5c..f3d2778b8e35 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -8,15 +8,22 @@ #include <linux/string.h> #include <linux/etherdevice.h> #include <linux/phylink.h> +#include <net/udp_tunnel.h> #include <net/ip.h> #include <linux/if_vlan.h> #include "../libwx/wx_type.h" #include "../libwx/wx_lib.h" +#include "../libwx/wx_ptp.h" #include "../libwx/wx_hw.h" +#include "../libwx/wx_mbx.h" +#include "../libwx/wx_sriov.h" #include "txgbe_type.h" #include "txgbe_hw.h" #include "txgbe_phy.h" +#include "txgbe_aml.h" +#include "txgbe_irq.h" +#include "txgbe_fdir.h" #include "txgbe_ethtool.h" char txgbe_driver_name[] = "txgbe"; @@ -32,6 +39,12 @@ char txgbe_driver_name[] = "txgbe"; static const struct pci_device_id txgbe_pci_tbl[] = { { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_SP1000), 0}, { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_WX1820), 0}, + { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_AML5010), 0}, + { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_AML5110), 0}, + { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_AML5025), 0}, + { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_AML5125), 0}, + { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_AML5040), 0}, + { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_AML5140), 0}, /* required last entry */ { .device = 0 } }; @@ -76,136 +89,62 @@ static int txgbe_enumerate_functions(struct wx *wx) return physfns; } -/** - * txgbe_irq_enable - Enable default interrupt generation settings - * @wx: pointer to private structure - * @queues: enable irqs for queues - **/ -static void txgbe_irq_enable(struct wx *wx, bool queues) -{ - wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); - - /* unmask interrupt */ - wx_intr_enable(wx, TXGBE_INTR_MISC); - if (queues) - wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); -} - -/** - * txgbe_intr - msi/legacy mode Interrupt Handler - * @irq: interrupt number - * @data: pointer to a network interface device structure - **/ -static irqreturn_t txgbe_intr(int __always_unused irq, void *data) +static void txgbe_sfp_detection_subtask(struct wx *wx) { - struct wx_q_vector *q_vector; - struct wx *wx = data; - struct pci_dev *pdev; - u32 eicr; - - q_vector = wx->q_vector[0]; - pdev = wx->pdev; + int err; - eicr = wx_misc_isb(wx, WX_ISB_VEC0); - if (!eicr) { - /* shared interrupt alert! - * the interrupt that we masked before the ICR read. - */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, true); - return IRQ_NONE; /* Not our interrupt */ - } - wx->isb_mem[WX_ISB_VEC0] = 0; - if (!(pdev->msi_enabled)) - wr32(wx, WX_PX_INTA, 1); + if (!test_bit(WX_FLAG_NEED_SFP_RESET, wx->flags)) + return; - wx->isb_mem[WX_ISB_MISC] = 0; - /* would disable interrupts here but it is auto disabled */ - napi_schedule_irqoff(&q_vector->napi); + /* wait for SFP module ready */ + msleep(200); - /* re-enable link(maybe) and non-queue interrupts, no flush. - * txgbe_poll will re-enable the queue interrupts - */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, false); + err = txgbe_identify_sfp(wx); + if (err) + return; - return IRQ_HANDLED; + clear_bit(WX_FLAG_NEED_SFP_RESET, wx->flags); } -/** - * txgbe_request_msix_irqs - Initialize MSI-X interrupts - * @wx: board private structure - * - * Allocate MSI-X vectors and request interrupts from the kernel. - **/ -static int txgbe_request_msix_irqs(struct wx *wx) +static void txgbe_link_config_subtask(struct wx *wx) { - struct net_device *netdev = wx->netdev; - int vector, err; + int err; - for (vector = 0; vector < wx->num_q_vectors; vector++) { - struct wx_q_vector *q_vector = wx->q_vector[vector]; - struct msix_entry *entry = &wx->msix_q_entries[vector]; + if (!test_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags)) + return; - if (q_vector->tx.ring && q_vector->rx.ring) - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-TxRx-%d", netdev->name, entry->entry); - else - /* skip this unused q_vector */ - continue; - - err = request_irq(entry->vector, wx_msix_clean_rings, 0, - q_vector->name, q_vector); - if (err) { - wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", - q_vector->name, err); - goto free_queue_irqs; - } - } - - return 0; + err = txgbe_set_phy_link(wx); + if (err) + return; -free_queue_irqs: - while (vector) { - vector--; - free_irq(wx->msix_q_entries[vector].vector, - wx->q_vector[vector]); - } - wx_reset_interrupt_capability(wx); - return err; + clear_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags); } /** - * txgbe_request_irq - initialize interrupts - * @wx: board private structure - * - * Attempt to configure interrupts using the best available - * capabilities of the hardware and kernel. + * txgbe_service_task - manages and runs subtasks + * @work: pointer to work_struct containing our data **/ -static int txgbe_request_irq(struct wx *wx) +static void txgbe_service_task(struct work_struct *work) { - struct net_device *netdev = wx->netdev; - struct pci_dev *pdev = wx->pdev; - int err; + struct wx *wx = container_of(work, struct wx, service_task); - if (pdev->msix_enabled) - err = txgbe_request_msix_irqs(wx); - else if (pdev->msi_enabled) - err = request_irq(wx->pdev->irq, &txgbe_intr, 0, - netdev->name, wx); - else - err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED, - netdev->name, wx); + txgbe_sfp_detection_subtask(wx); + txgbe_link_config_subtask(wx); - if (err) - wx_err(wx, "request_irq failed, Error %d\n", err); + wx_service_event_complete(wx); +} - return err; +static void txgbe_init_service(struct wx *wx) +{ + timer_setup(&wx->service_timer, wx_service_timer, 0); + INIT_WORK(&wx->service_task, txgbe_service_task); + clear_bit(WX_STATE_SERVICE_SCHED, wx->state); } static void txgbe_up_complete(struct wx *wx) { struct net_device *netdev = wx->netdev; + u32 reg; wx_control_hw(wx, true); wx_configure_vectors(wx); @@ -214,7 +153,27 @@ static void txgbe_up_complete(struct wx *wx) smp_mb__before_atomic(); wx_napi_enable_all(wx); - phylink_start(wx->phylink); + switch (wx->mac.type) { + case wx_mac_aml40: + reg = rd32(wx, TXGBE_AML_MAC_TX_CFG); + reg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK; + reg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G; + wr32(wx, WX_MAC_TX_CFG, reg); + txgbe_enable_sec_tx_path(wx); + netif_carrier_on(wx->netdev); + break; + case wx_mac_aml: + /* Enable TX laser */ + wr32m(wx, WX_GPIO_DR, TXGBE_GPIOBIT_1, 0); + txgbe_setup_link(wx); + phylink_start(wx->phylink); + break; + case wx_mac_sp: + phylink_start(wx->phylink); + break; + default: + break; + } /* clear any pending interrupts, may auto mask */ rd32(wx, WX_PX_IC(0)); @@ -224,6 +183,13 @@ static void txgbe_up_complete(struct wx *wx) /* enable transmits */ netif_tx_start_all_queues(netdev); + mod_timer(&wx->service_timer, jiffies); + + /* Set PF Reset Done bit so PF/VF Mail Ops can work */ + wr32m(wx, WX_CFG_PORT_CTL, WX_CFG_PORT_CTL_PFRSTD, + WX_CFG_PORT_CTL_PFRSTD); + /* update setting rx tx for all active vfs */ + wx_set_all_vfs(wx); } static void txgbe_reset(struct wx *wx) @@ -241,6 +207,9 @@ static void txgbe_reset(struct wx *wx) memcpy(old_addr, &wx->mac_table[0].addr, netdev->addr_len); wx_flush_sw_mac_table(wx); wx_mac_set_default_filter(wx, old_addr); + + if (test_bit(WX_STATE_PTP_RUNNING, wx->state)) + wx_ptp_reset(wx); } static void txgbe_disable_device(struct wx *wx) @@ -263,12 +232,24 @@ static void txgbe_disable_device(struct wx *wx) wx_irq_disable(wx); wx_napi_disable_all(wx); + timer_delete_sync(&wx->service_timer); + if (wx->bus.func < 2) wr32m(wx, TXGBE_MIS_PRB_CTL, TXGBE_MIS_PRB_CTL_LAN_UP(wx->bus.func), 0); else wx_err(wx, "%s: invalid bus lan id %d\n", __func__, wx->bus.func); + if (wx->num_vfs) { + /* Clear EITR Select mapping */ + wr32(wx, WX_PX_ITRSEL, 0); + /* Mark all the VFs as inactive */ + for (i = 0; i < wx->num_vfs; i++) + wx->vfinfo[i].clear_to_send = 0; + /* update setting rx tx for all active vfs */ + wx_set_all_vfs(wx); + } + if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) || ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) { /* disable mac transmiter */ @@ -292,7 +273,22 @@ void txgbe_down(struct wx *wx) { txgbe_disable_device(wx); txgbe_reset(wx); - phylink_stop(wx->phylink); + + switch (wx->mac.type) { + case wx_mac_aml40: + netif_carrier_off(wx->netdev); + break; + case wx_mac_aml: + phylink_stop(wx->phylink); + /* Disable TX laser */ + wr32m(wx, WX_GPIO_DR, TXGBE_GPIOBIT_1, TXGBE_GPIOBIT_1); + break; + case wx_mac_sp: + phylink_stop(wx->phylink); + break; + default: + break; + } wx_clean_all_tx_rings(wx); wx_clean_all_rx_rings(wx); @@ -301,6 +297,7 @@ void txgbe_down(struct wx *wx) void txgbe_up(struct wx *wx) { wx_configure(wx); + wx_ptp_init(wx); txgbe_up_complete(wx); } @@ -317,6 +314,16 @@ static void txgbe_init_type_code(struct wx *wx) case TXGBE_DEV_ID_WX1820: wx->mac.type = wx_mac_sp; break; + case TXGBE_DEV_ID_AML5010: + case TXGBE_DEV_ID_AML5110: + case TXGBE_DEV_ID_AML5025: + case TXGBE_DEV_ID_AML5125: + wx->mac.type = wx_mac_aml; + break; + case TXGBE_DEV_ID_AML5040: + case TXGBE_DEV_ID_AML5140: + wx->mac.type = wx_mac_aml40; + break; default: wx->mac.type = wx_mac_unknown; break; @@ -324,25 +331,25 @@ static void txgbe_init_type_code(struct wx *wx) switch (device_type) { case TXGBE_ID_SFP: - wx->media_type = sp_media_fiber; + wx->media_type = wx_media_fiber; break; case TXGBE_ID_XAUI: case TXGBE_ID_SGMII: - wx->media_type = sp_media_copper; + wx->media_type = wx_media_copper; break; case TXGBE_ID_KR_KX_KX4: case TXGBE_ID_MAC_XAUI: case TXGBE_ID_MAC_SGMII: - wx->media_type = sp_media_backplane; + wx->media_type = wx_media_backplane; break; case TXGBE_ID_SFI_XAUI: if (wx->bus.func == 0) - wx->media_type = sp_media_fiber; + wx->media_type = wx_media_fiber; else - wx->media_type = sp_media_copper; + wx->media_type = wx_media_copper; break; default: - wx->media_type = sp_media_unknown; + wx->media_type = wx_media_unknown; break; } } @@ -356,13 +363,13 @@ static int txgbe_sw_init(struct wx *wx) u16 msix_count = 0; int err; - wx->mac.num_rar_entries = TXGBE_SP_RAR_ENTRIES; - wx->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES; - wx->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES; - wx->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE; - wx->mac.vft_size = TXGBE_SP_VFT_TBL_SIZE; - wx->mac.rx_pb_size = TXGBE_SP_RX_PB_SIZE; - wx->mac.tx_pb_size = TXGBE_SP_TDB_PB_SZ; + wx->mac.num_rar_entries = TXGBE_RAR_ENTRIES; + wx->mac.max_tx_queues = TXGBE_MAX_TXQ; + wx->mac.max_rx_queues = TXGBE_MAX_RXQ; + wx->mac.mcft_size = TXGBE_MC_TBL_SIZE; + wx->mac.vft_size = TXGBE_VFT_TBL_SIZE; + wx->mac.rx_pb_size = TXGBE_RX_PB_SIZE; + wx->mac.tx_pb_size = TXGBE_TDB_PB_SZ; /* PCI config space info */ err = wx_sw_init(wx); @@ -382,6 +389,17 @@ static int txgbe_sw_init(struct wx *wx) num_online_cpus()); wx->rss_enabled = true; + wx->ring_feature[RING_F_FDIR].limit = min_t(int, TXGBE_MAX_FDIR_INDICES, + num_online_cpus()); + set_bit(WX_FLAG_FDIR_CAPABLE, wx->flags); + set_bit(WX_FLAG_FDIR_HASH, wx->flags); + wx->atr_sample_rate = TXGBE_DEFAULT_ATR_SAMPLE_RATE; + wx->atr = txgbe_atr; + wx->configure_fdir = txgbe_configure_fdir; + + set_bit(WX_FLAG_RSC_CAPABLE, wx->flags); + set_bit(WX_FLAG_MULTI_64_FUNC, wx->flags); + /* enable itr by default in dynamic mode */ wx->rx_itr_setting = 1; wx->tx_itr_setting = 1; @@ -389,14 +407,37 @@ static int txgbe_sw_init(struct wx *wx) /* set default ring sizes */ wx->tx_ring_count = TXGBE_DEFAULT_TXD; wx->rx_ring_count = TXGBE_DEFAULT_RXD; + wx->mbx.size = WX_VXMAILBOX_SIZE; /* set default work limits */ wx->tx_work_limit = TXGBE_DEFAULT_TX_WORK; wx->rx_work_limit = TXGBE_DEFAULT_RX_WORK; + wx->setup_tc = txgbe_setup_tc; + wx->do_reset = txgbe_do_reset; + set_bit(0, &wx->fwd_bitmask); + + switch (wx->mac.type) { + case wx_mac_sp: + break; + case wx_mac_aml: + case wx_mac_aml40: + set_bit(WX_FLAG_SWFW_RING, wx->flags); + wx->swfw_index = 0; + break; + default: + break; + } + return 0; } +static void txgbe_init_fdir(struct txgbe *txgbe) +{ + txgbe->fdir_filter_count = 0; + spin_lock_init(&txgbe->fdir_perfect_lock); +} + /** * txgbe_open - Called when a network interface is made active * @netdev: network interface device structure @@ -417,9 +458,9 @@ static int txgbe_open(struct net_device *netdev) wx_configure(wx); - err = txgbe_request_irq(wx); + err = txgbe_request_queue_irqs(wx); if (err) - goto err_free_isb; + goto err_free_resources; /* Notify the stack of the actual queue counts. */ err = netif_set_real_num_tx_queues(netdev, wx->num_tx_queues); @@ -430,14 +471,16 @@ static int txgbe_open(struct net_device *netdev) if (err) goto err_free_irq; + wx_ptp_init(wx); + txgbe_up_complete(wx); return 0; err_free_irq: wx_free_irq(wx); -err_free_isb: - wx_free_isb_resources(wx); +err_free_resources: + wx_free_resources(wx); err_reset: txgbe_reset(wx); @@ -453,6 +496,7 @@ err_reset: */ static void txgbe_close_suspend(struct wx *wx) { + wx_ptp_suspend(wx); txgbe_disable_device(wx); wx_free_resources(wx); } @@ -472,9 +516,11 @@ static int txgbe_close(struct net_device *netdev) { struct wx *wx = netdev_priv(netdev); + wx_ptp_stop(wx); txgbe_down(wx); wx_free_irq(wx); wx_free_resources(wx); + txgbe_fdir_filter_exit(wx); wx_control_hw(wx, false); return 0; @@ -518,6 +564,7 @@ static void txgbe_shutdown(struct pci_dev *pdev) int txgbe_setup_tc(struct net_device *dev, u8 tc) { struct wx *wx = netdev_priv(dev); + struct txgbe *txgbe = wx->priv; /* Hardware has to reinitialize queues and interrupts to * match packet buffer alignment. Unfortunately, the @@ -528,6 +575,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) else txgbe_reset(wx); + txgbe_free_misc_irq(txgbe); wx_clear_interrupt_scheme(wx); if (tc) @@ -536,6 +584,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) netdev_reset_tc(dev); wx_init_interrupt_scheme(wx); + txgbe_setup_misc_irq(txgbe); if (netif_running(dev)) txgbe_open(dev); @@ -543,6 +592,67 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) return 0; } +static void txgbe_reinit_locked(struct wx *wx) +{ + int err = 0; + + netif_trans_update(wx->netdev); + + err = wx_set_state_reset(wx); + if (err) { + wx_err(wx, "wait device reset timeout\n"); + return; + } + + txgbe_down(wx); + txgbe_up(wx); + + clear_bit(WX_STATE_RESETTING, wx->state); +} + +void txgbe_do_reset(struct net_device *netdev) +{ + struct wx *wx = netdev_priv(netdev); + + if (netif_running(netdev)) + txgbe_reinit_locked(wx); + else + txgbe_reset(wx); +} + +static int txgbe_udp_tunnel_sync(struct net_device *dev, unsigned int table) +{ + struct wx *wx = netdev_priv(dev); + struct udp_tunnel_info ti; + + udp_tunnel_nic_get_port(dev, table, 0, &ti); + switch (ti.type) { + case UDP_TUNNEL_TYPE_VXLAN: + wr32(wx, TXGBE_CFG_VXLAN, ntohs(ti.port)); + break; + case UDP_TUNNEL_TYPE_VXLAN_GPE: + wr32(wx, TXGBE_CFG_VXLAN_GPE, ntohs(ti.port)); + break; + case UDP_TUNNEL_TYPE_GENEVE: + wr32(wx, TXGBE_CFG_GENEVE, ntohs(ti.port)); + break; + default: + break; + } + + return 0; +} + +static const struct udp_tunnel_nic_info txgbe_udp_tunnels = { + .sync_table = txgbe_udp_tunnel_sync, + .flags = UDP_TUNNEL_NIC_INFO_OPEN_ONLY, + .tables = { + { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, + { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN_GPE, }, + { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, }, + }, +}; + static const struct net_device_ops txgbe_netdev_ops = { .ndo_open = txgbe_open, .ndo_stop = txgbe_close, @@ -550,11 +660,15 @@ static const struct net_device_ops txgbe_netdev_ops = { .ndo_start_xmit = wx_xmit_frame, .ndo_set_rx_mode = wx_set_rx_mode, .ndo_set_features = wx_set_features, + .ndo_fix_features = wx_fix_features, + .ndo_features_check = wx_features_check, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, .ndo_vlan_rx_add_vid = wx_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = wx_vlan_rx_kill_vid, + .ndo_hwtstamp_set = wx_hwtstamp_set, + .ndo_hwtstamp_get = wx_hwtstamp_get, }; /** @@ -628,14 +742,19 @@ static int txgbe_probe(struct pci_dev *pdev, goto err_pci_release_regions; } + /* The sapphire supports up to 63 VFs per pf, but physical + * function also need one pool for basic networking. + */ + pci_sriov_set_totalvfs(pdev, TXGBE_MAX_VFS_DRV_LIMIT); wx->driver_name = txgbe_driver_name; txgbe_set_ethtool_ops(netdev); netdev->netdev_ops = &txgbe_netdev_ops; + netdev->udp_tunnel_nic_info = &txgbe_udp_tunnels; /* setup the private structure */ err = txgbe_sw_init(wx); if (err) - goto err_free_mac_table; + goto err_pci_release_regions; /* check if flash load is done after hw power up */ err = wx_check_flash_load(wx, TXGBE_SPI_ILDR_STATUS_PERST); @@ -676,6 +795,7 @@ static int txgbe_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_HIGHDMA; netdev->hw_features |= NETIF_F_GRO; netdev->features |= NETIF_F_GRO; + netdev->features |= NETIF_F_RX_UDP_TUNNEL_PORT; netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; @@ -697,9 +817,11 @@ static int txgbe_probe(struct pci_dev *pdev, eth_hw_addr_set(netdev, wx->mac.perm_addr); wx_mac_set_default_filter(wx, wx->mac.perm_addr); + txgbe_init_service(wx); + err = wx_init_interrupt_scheme(wx); if (err) - goto err_free_mac_table; + goto err_cancel_service; /* Save off EEPROM version number and Option Rom version which * together make a unique identify for the eeprom @@ -742,6 +864,13 @@ static int txgbe_probe(struct pci_dev *pdev, if (etrack_id < 0x20010) dev_warn(&pdev->dev, "Please upgrade the firmware to 0x20010 or above.\n"); + err = txgbe_test_hostif(wx); + if (err != 0) { + dev_err(&pdev->dev, "Mismatched Firmware version\n"); + err = -EIO; + goto err_release_hw; + } + txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL); if (!txgbe) { err = -ENOMEM; @@ -751,10 +880,16 @@ static int txgbe_probe(struct pci_dev *pdev, txgbe->wx = wx; wx->priv = txgbe; - err = txgbe_init_phy(txgbe); + txgbe_init_fdir(txgbe); + + err = txgbe_setup_misc_irq(txgbe); if (err) goto err_release_hw; + err = txgbe_init_phy(txgbe); + if (err) + goto err_free_misc_irq; + err = register_netdev(netdev); if (err) goto err_remove_phy; @@ -781,10 +916,16 @@ static int txgbe_probe(struct pci_dev *pdev, err_remove_phy: txgbe_remove_phy(txgbe); +err_free_misc_irq: + txgbe_free_misc_irq(txgbe); err_release_hw: wx_clear_interrupt_scheme(wx); wx_control_hw(wx, false); +err_cancel_service: + timer_delete_sync(&wx->service_timer); + cancel_work_sync(&wx->service_task); err_free_mac_table: + kfree(wx->rss_key); kfree(wx->mac_table); err_pci_release_regions: pci_release_selected_regions(pdev, @@ -809,10 +950,15 @@ static void txgbe_remove(struct pci_dev *pdev) struct txgbe *txgbe = wx->priv; struct net_device *netdev; + cancel_work_sync(&wx->service_task); + netdev = wx->netdev; + wx_disable_sriov(wx); unregister_netdev(netdev); txgbe_remove_phy(txgbe); + txgbe_free_misc_irq(txgbe); + wx_free_isb_resources(wx); pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); @@ -830,11 +976,12 @@ static struct pci_driver txgbe_driver = { .probe = txgbe_probe, .remove = txgbe_remove, .shutdown = txgbe_shutdown, + .sriov_configure = wx_pci_sriov_configure, }; module_pci_driver(txgbe_driver); MODULE_DEVICE_TABLE(pci, txgbe_pci_tbl); MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>"); -MODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver"); +MODULE_DESCRIPTION("WangXun(R) 10/25/40 Gigabit PCI Express Network Driver"); MODULE_LICENSE("GPL"); |