📄 at_main.c
字号:
#ifdef NETIF_F_HW_VLAN_TX
netdev->features = NETIF_F_SG |
NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX ;
#else
netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
#endif
#ifdef NETIF_F_TSO
netdev->features |= NETIF_F_TSO;
#ifdef NETIF_F_TSO6
netdev->features |= NETIF_F_TSO6;
#endif//NETIF_F_TSO6
#endif//NETIF_F_TSO
#endif//MAX_SKB_FRAGS
#ifdef NETIF_F_LLTX
netdev->features |= NETIF_F_LLTX;
#endif
if(pci_using_64) {
netdev->features |= NETIF_F_HIGHDMA;
AT_DBG("pci using 64bit address\n");
}
/* get user settings */
at_check_options(adapter);
/* Init GPHY as early as possible due to power saving issue */
at_phy_init(&adapter->hw);
/* reset the controller to
* put the device in a known good starting state */
if (at_reset_hw(&adapter->hw)) {
err = -EIO;
goto err_reset;
}
/* copy the MAC address out of the EEPROM */
at_read_mac_addr(&adapter->hw);
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
#ifdef ETHTOOL_GPERMADDR
memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr)) {
#else
if (!is_valid_ether_addr(netdev->dev_addr)) {
#endif
AT_DBG("Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
}
AT_DBG("mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
adapter->hw.mac_addr[0],
adapter->hw.mac_addr[1],
adapter->hw.mac_addr[2],
adapter->hw.mac_addr[3],
adapter->hw.mac_addr[4],
adapter->hw.mac_addr[5] );
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &at_watchdog;
adapter->watchdog_timer.data = (unsigned long) adapter;
init_timer(&adapter->phy_config_timer);
adapter->phy_config_timer.function = &at_phy_config;
adapter->phy_config_timer.data = (unsigned long) adapter;
INIT_WORK(&adapter->reset_task, at_reset_task);
INIT_WORK(&adapter->link_chg_task, at_link_chg_task);
strcpy(netdev->name, "eth%d"); // ??
if((err = register_netdev(netdev)))
goto err_register;
/* assume we have no link for now */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
cards_found++;
return 0;
//err_init_hw:
err_reset:
err_register:
err_sw_init:
err_eeprom:
#ifdef CONFIG_AT_NAPI
if (adapter->polling_netdev) {
for (i = 0; i < adapter->num_rx_queues; i++)
dev_put(&adapter->polling_netdev[i]);
kfree(adapter->polling_netdev);
}
#endif
#ifdef CONFIG_AT_MQ
if (adapter->cpu_netdev) {
free_percpu(adapter->cpu_netdev);
}
#endif
iounmap(adapter->hw.hw_addr);
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
pci_release_regions(pdev);
err_pci_reg:
err_dma:
pci_disable_device(pdev);
return err;
}
/**
* at_remove - Device Removal Routine
* @pdev: PCI device information struct
*
* at_remove is called by the PCI subsystem to alert the driver
* that it should release a PCI device. The could be caused by a
* Hot-Plug event, or because the driver is going to be removed from
* memory.
**/
static void __devexit
at_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct at_adapter *adapter = netdev_priv(netdev);
#ifdef CONFIG_AT_NAPI
int i;
#endif
DEBUGFUNC("at_remove");
/* flush_scheduled work may reschedule our watchdog task, so
* explicitly disable watchdog tasks from being rescheduled */
set_bit(__AT_DOWN, &adapter->flags);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_config_timer);
flush_scheduled_work();
unregister_netdev(netdev);
#ifdef CONFIG_AT_NAPI
for (i = 0; i < adapter->num_rx_queues; i++)
dev_put(&adapter->polling_netdev[i]);
kfree(adapter->polling_netdev);
#endif
at_force_ps(&adapter->hw);
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
#ifdef CONFIG_AT_MQ
free_percpu(adapter->cpu_netdev);//free previously allocated percpu memory ....arg-->>pointer returned by alloc_percpu.
#endif
free_netdev(netdev);
pci_disable_device(pdev);
}
#ifdef USE_REBOOT_NOTIFIER
/* only want to do this for 2.4 kernels? */
static int
at_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{
struct pci_dev *pdev = NULL;
DEBUGFUNC("at_notify_reboot !");
switch(event) {
case SYS_DOWN:
case SYS_HALT:
case SYS_POWER_OFF:
while((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
if(pci_dev_driver(pdev) == &at_driver)
at_suspend(pdev, PMSG_SUSPEND);
}
}
return NOTIFY_DONE;
}
#endif
#ifndef USE_REBOOT_NOTIFIER
static void at_shutdown(struct pci_dev *pdev)
{
at_suspend(pdev, PMSG_SUSPEND);
}
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
* the interrupt routine is executing.
*/
static void
at_netpoll(struct net_device *netdev)
{
struct at_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
at_intr(adapter->pdev->irq, netdev);
at_clean_tx_irq(adapter);
#ifndef CONFIG_AT_NAPI
at_clean_rx_irq(adapter, 0);
#endif
enable_irq(adapter->pdev->irq);
}
#endif
static int
at_suspend(struct pci_dev *pdev, pm_message_t state)
{
#define AT_SUSPEND_LINK_TIMEOUT 28
struct net_device *netdev = pci_get_drvdata(pdev);
struct at_adapter *adapter = netdev_priv(netdev);
struct at_hw * hw = &adapter->hw;
//u16 speed, duplex;
u32 ctrl = 0;
u32 mac_ctrl_data = 0;
u32 wol_ctrl_data = 0;
u16 mii_advertise_data = 0;
u16 mii_bmsr_data = 0;
u16 mii_intr_status_data = 0;
u32 wufc = adapter->wol;
u32 i;
#ifdef CONFIG_PM
int retval = 0;
#endif
DEBUGFUNC("at_suspend !");
if (netif_running(netdev)) {
WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
at_down(adapter);
}
netif_device_detach(netdev);
#ifdef CONFIG_PM
retval = pci_save_state(pdev);
if (retval)
return retval;
#endif
if (wufc) {
/* get link status */
at_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
at_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
mii_advertise_data = MII_AR_10T_HD_CAPS;
printk(KERN_DEBUG "THe mii advertise data is %x\n", mii_advertise_data);
if ((at_write_phy_reg(hw, MII_ADVERTISE, mii_advertise_data) != 0) ||
(at_write_phy_reg(hw, MII_AT001_CR, 0) != 0) ||
/* not advertise 1000M capacity */
(at_phy_commit(hw)) != 0) {
printk(KERN_DEBUG "set phy register failed\n");
}
hw->phy_configured = FALSE; /* re-init PHY when resume */
/* turn on magic packet wol */
if (wufc & AT_WUFC_MAG) {
wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
}
if (wufc & AT_WUFC_LNKC) {
/* if orignal link status is link, just wait for retrive link */
if (mii_bmsr_data & BMSR_LSTATUS) {
for (i=0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
msec_delay(100);
at_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
if (mii_bmsr_data & BMSR_LSTATUS) {
break;
}
}
if (0 == (mii_bmsr_data & BMSR_LSTATUS)) {
printk(KERN_DEBUG "%s: Link may change when suspend\n",
at_driver_name);
}
}
wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
/* only link up can wake up */
if (at_write_phy_reg(hw, 18, 0x400) != 0) {
printk(KERN_DEBUG "%s: read write phy register failed.\n",
at_driver_name);
goto wol_dis;
}
}
/* clear phy interrupt */
at_read_phy_reg(hw, 19, &mii_intr_status_data);
/* Config MAC Ctrl register */
mac_ctrl_data = MAC_CTRL_RX_EN;
/* set to 10/100M halt duplex */
mac_ctrl_data |= MAC_CTRL_SPEED_10_100 << MAC_CTRL_SPEED_SHIFT;
mac_ctrl_data |= (((u32)adapter->hw.preamble_len & MAC_CTRL_PRMLEN_MASK)
<< MAC_CTRL_PRMLEN_SHIFT);
if (adapter->vlgrp) {
mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
}
if (wufc & AT_WUFC_MAG) {
/* magic packet maybe Broadcast&multicast&Unicast frame */
mac_ctrl_data |= MAC_CTRL_BC_EN;
}
AT_DBG("%s: suspend MAC=0x%x\n", at_driver_name, mac_ctrl_data);
AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
/* pcie patch */
ctrl = AT_READ_REG(hw, REG_PCIE_PHYMISC);
ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
goto suspend_exit;
}
wol_dis:
/* WOL disabled */
AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
/* pcie patch */
ctrl = AT_READ_REG(hw, REG_PCIE_PHYMISC);
ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
at_force_ps(hw);
hw->phy_configured = FALSE; /* re-init PHY when resume */
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
suspend_exit:
if (netif_running(netdev))
at_free_irq(adapter);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
#undef AT_SUSPEND_LINK_TIMEOUT
}
#ifdef CONFIG_PM
static int
at_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct at_adapter *adapter = netdev_priv(netdev);
u32 err;
DEBUGFUNC("at_resume !");
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if ((err = pci_enable_device(pdev))) {
printk(KERN_ERR "ATL1e: Cannot enable PCI device from suspend\n");
return err;
}
pci_set_master(pdev);
AT_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
if (netif_running(netdev) && (err = at_request_irq(adapter)))
return err;
at_reset_hw(&adapter->hw);
if(netif_running(netdev))
at_up(adapter);
netif_device_attach(netdev);
return 0;
}
#endif
#ifdef CONFIG_AT_PCI_ERS
/**
* at_io_error_detected - called when PCI error is detected
* @pdev: Pointer to PCI device
* @state: The current pci connection state
*
* This function is called after a PCI bus error affecting
* this device has been detected.
*/
static pci_ers_result_t at_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct at_adapter *adapter = netdev->priv;
netif_device_detach(netdev);
if (netif_running(netdev))
at_down(adapter);
pci_disable_device(pdev);
/* Request a slot slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
}
/**
* at_io_slot_reset - called after the pci bus has been reset.
* @pdev: Pointer to PCI device
*
* Restart the card from scratch, as if from a cold-boot. Implementation
* resembles the first-half of the e1000_resume routine.
*/
static pci_ers_result_t at_io_slot_reset(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct at_adapter *adapter = netdev->priv;
if (pci_enable_device(pdev)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -