📄 at_main.c
字号:
/*
* Copyright(c) 2007 Atheros Corporation. All rights reserved.
*
* Derived from Intel e1000 driver
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* There are a lot of defines in here that are unused and/or have cryptic
* names. Please leave them alone, as they're the closest thing we have
* to a spec from Atheros at present. *ahem* -- CHS
*/
#include "at.h"
#ifdef CONFIG_AT_MQ
#include <linux/cpu.h>
#include <linux/smp.h>
#endif
char at_driver_name[] = "ATL1e";
char at_driver_string[] = "Atheros(R) AR8121/AR8113/AR8114 PCI-E Ethernet Network Driver";
#define DRV_VERSION "1.0.1.0"
char at_driver_version[] = DRV_VERSION;
char at_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
//#ifdef CONFIG_PCI_MSI
//#undef CONFIG_PCI_MSI
//#endif
/*
* at_pci_tbl - PCI Device ID Table
*
* Wildcard entries (PCI_ANY_ID) should come last
* Last entry must be all 0s
*
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
static struct pci_device_id at_pci_tbl[] = {
ATHEROS_ETHERNET_DEVICE(0x1026),
/* required last entry */
{0,}
};
MODULE_DEVICE_TABLE(pci, at_pci_tbl);
int at_up(struct at_adapter *adapter);
void at_down(struct at_adapter *adapter);
int at_reset(struct at_adapter *adapter);
s32 at_setup_ring_resources(struct at_adapter *adapter);
void at_free_ring_resources(struct at_adapter *adapter);
void at_reinit_locked(struct at_adapter *adapter);
/* Local Function Prototypes */
static int at_init_module(void);
static void at_exit_module(void);
static int at_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static int at_alloc_queues(struct at_adapter *adapter);
#ifdef CONFIG_AT_MQ
static void at_setup_queue_mapping(struct at_adapter *adapter);
void at_rx_schedule(void *data);
#endif
#ifdef CONFIG_AT_NAPI
static int at_clean(struct net_device *poll_dev, int *budget);
#endif
static void __devexit at_remove(struct pci_dev *pdev);
static int at_sw_init(struct at_adapter *adapter);
static int at_open(struct net_device *netdev);
static int at_close(struct net_device *netdev);
static int at_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats * at_get_stats(struct net_device *netdev);
static int at_tso(struct at_adapter* adapter, struct sk_buff *skb, TpdDescr* pTpd);
static void at_tx_map(struct at_adapter *adapter, struct sk_buff *skb, TpdDescr* pTpd);
static void at_tx_queue(struct at_adapter *adapter, u16 count, TpdDescr* pTpd);
static int at_tx_csum(struct at_adapter *adapter, struct sk_buff *skb, TpdDescr* pTpd);
static int at_change_mtu(struct net_device *netdev, int new_mtu);
static void at_set_multi(struct net_device *netdev);
static int at_set_mac(struct net_device *netdev, void *p);
static int at_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static void at_tx_timeout(struct net_device *dev);
static irqreturn_t at_intr(int irq, void *data);
static boolean_t at_clean_tx_irq(struct at_adapter* adapter);
static void at_watchdog(unsigned long data);
static void at_phy_config(unsigned long data);
static void at_reset_task(struct work_struct *work);
static void at_link_chg_task(struct work_struct *work);
static void at_check_for_link(struct at_adapter* adapter);
void at_set_ethtool_ops(struct net_device *netdev);
#ifdef ETHTOOL_OPS_COMPAT
extern int ethtool_ioctl(struct ifreq *ifr);
#endif
static int at_check_link(struct at_adapter* adapter);
void init_ring_ptrs(struct at_adapter *adapter);
static s32 at_configure(struct at_adapter *adapter);
#ifdef CONFIG_AT_NAPI
static void at_clean_rx_irq(struct at_adapter *adapter, u8 que, int *work_done, int work_to_do);
#else
static void at_clean_rx_irq(struct at_adapter *adapter, u8 que);
#endif
static void at_clean_tx_ring(struct at_adapter *adapter);
static void at_clean_rx_ring(struct at_adapter *adapter);
#ifdef SIOCGMIIPHY
static int at_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
#endif
#ifdef NETIF_F_HW_VLAN_TX
static void at_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
static void at_restore_vlan(struct at_adapter *adapter);
#endif
static int at_suspend(struct pci_dev *pdev, pm_message_t state);
#ifdef CONFIG_PM
static int at_resume(struct pci_dev *pdev);
#endif
#ifndef USE_REBOOT_NOTIFIER
static void at_shutdown(struct pci_dev *pdev);
#else
static int at_notify_reboot(struct notifier_block *nb, unsigned long event, void *p);
struct notifier_block at_notifier_reboot = {
.notifier_call = at_notify_reboot,
.next = NULL,
.priority = 0
};
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
/* for netdump / net console */
static void at_netpoll (struct net_device *netdev);
#endif
/* Exported from other modules */
extern void at_check_options(struct at_adapter *adapter);
#ifdef CONFIG_AT_PCI_ERS
static pci_ers_result_t at_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
static pci_ers_result_t at_io_slot_reset(struct pci_dev *pdev);
static void at_io_resume(struct pci_dev *pdev);
static struct pci_error_handlers at_err_handler = {
.error_detected = at_io_error_detected,
.slot_reset = at_io_slot_reset,
.resume = at_io_resume,
};
#endif
static struct pci_driver at_driver = {
.name = at_driver_name,
.id_table = at_pci_tbl,
.probe = at_probe,
.remove = __devexit_p(at_remove),
/* Power Managment Hooks */
#ifdef CONFIG_PM
.suspend = at_suspend,
.resume = at_resume,
#endif
#ifndef USE_REBOOT_NOTIFIER
.shutdown = at_shutdown,
#endif
#ifdef CONFIG_AT_PCI_ERS
.err_handler = &at_err_handler
#endif
};
MODULE_AUTHOR("Atheros Corporation, <xiong.huang@atheros.com>");
MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
/**
* at_init_module - Driver Registration Routine
*
* at_init_module is the first routine called when the driver is
* loaded. All it does is register with the PCI subsystem.
**/
static int __init
at_init_module(void)
{
int ret;
printk(KERN_INFO "%s - version %s\n",
at_driver_string, at_driver_version);
printk(KERN_INFO "%s\n", at_copyright);
ret = pci_register_driver(&at_driver);
#ifdef USE_REBOOT_NOTIFIER
if (ret >= 0) {
register_reboot_notifier(&at_notifier_reboot);
}
#endif
return ret;
}
module_init(at_init_module);
/**
* at_exit_module - Driver Exit Cleanup Routine
*
* at_exit_module is called just before the driver is removed
* from memory.
**/
static void __exit
at_exit_module(void)
{
#ifdef USE_REBOOT_NOTIFIER
unregister_reboot_notifier(&at_notifier_reboot);
#endif
pci_unregister_driver(&at_driver);
}
module_exit(at_exit_module);
static int at_request_irq(struct at_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int flags, err = 0;
flags = IRQF_SHARED;
#ifdef CONFIG_PCI_MSI
adapter->have_msi = TRUE;
if ((err = pci_enable_msi(adapter->pdev))) {
AT_DBG("Unable to allocate MSI interrupt Error: %d\n", err);
adapter->have_msi = FALSE;
}
if (adapter->have_msi) {
flags &= ~IRQF_SHARED;
}
#endif
if ((err = request_irq(adapter->pdev->irq, &at_intr, flags,
netdev->name, netdev))) {
AT_DBG("Unable to allocate interrupt Error: %d\n", err);
}
AT_DBG("at_request_irq OK\n");
return err;
}
static void at_free_irq(struct at_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
free_irq(adapter->pdev->irq, netdev);
#ifdef CONFIG_PCI_MSI
if (adapter->have_msi)
pci_disable_msi(adapter->pdev);
#endif
}
static void at_setup_pcicmd(struct pci_dev* pdev)
{
u16 cmd;
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INTX_DISABLE)
cmd &= ~PCI_COMMAND_INTX_DISABLE;
if (cmd & PCI_COMMAND_IO)
cmd &= ~PCI_COMMAND_IO;
if (0 == (cmd & PCI_COMMAND_MEMORY))
cmd |= PCI_COMMAND_MEMORY;
if (0 == (cmd & PCI_COMMAND_MASTER))
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, cmd);
/*
* some motherboards BIOS(PXE/EFI) driver may set PME
* while they transfer control to OS (Windows/Linux)
* so we should clear this bit before NIC work normally
*/
pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0);
msec_delay(1);
}
/**
* at_probe - Device Initialization Routine
* @pdev: PCI device information struct
* @ent: entry in at_pci_tbl
*
* Returns 0 on success, negative on failure
*
* at_probe initializes an adapter identified by a pci_dev structure.
* The OS initialization, configuring of the adapter private structure,
* and a hardware reset occur.
**/
static int __devinit
at_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *netdev;
struct at_adapter *adapter;
static int cards_found = 0;
unsigned long mmio_start;
int mmio_len;
boolean_t pci_using_64 = TRUE;
int err;
#ifdef CONFIG_AT_NAPI
int i;
#endif
DEBUGFUNC("at_probe !");
if((err = pci_enable_device(pdev)))
return err;
if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
!(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
pci_using_64 = TRUE;
} else {
if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) &&
(err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
AT_ERR("No usable DMA configuration, aborting\n");
goto err_dma;
}
pci_using_64 = FALSE;
}
// Mark all PCI regions associated with PCI device
// pdev as being reserved by owner at_driver_name
if((err = pci_request_regions(pdev, at_driver_name)))
goto err_pci_reg;
// Enables bus-mastering on the device and calls
// pcibios_set_master to do the needed arch specific settings
pci_set_master(pdev);
err = -ENOMEM;
netdev = alloc_etherdev(sizeof(struct at_adapter));
if(!netdev)
goto err_alloc_etherdev;
SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->hw.back = adapter;
mmio_start = pci_resource_start(pdev, BAR_0);
mmio_len = pci_resource_len(pdev, BAR_0);
AT_DBG("base memory = %lx memory length = %x \n",
mmio_start, mmio_len);
adapter->hw.mem_rang = (u32)mmio_len;
adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
if(!adapter->hw.hw_addr) {
err = -EIO;
goto err_ioremap;
}
at_setup_pcicmd(pdev);
netdev->base_addr = (unsigned long)adapter->hw.hw_addr;
netdev->open = &at_open;
netdev->stop = &at_close;
netdev->hard_start_xmit = &at_xmit_frame;
netdev->get_stats = &at_get_stats;
netdev->set_multicast_list = &at_set_multi;
netdev->set_mac_address = &at_set_mac;
netdev->change_mtu = &at_change_mtu;
netdev->do_ioctl = &at_ioctl;
at_set_ethtool_ops(netdev);
/*
printk("tdp:(%lu)(%lu), rrs(%lu),rx-flag(%lu), Xsum(%lu)\n",
sizeof(TpdDescr), sizeof(TpdIPv6Descr),
sizeof(RecvRetStatus), sizeof(RxFlags),
sizeof(TpdCXsumDescr));
*/
#ifdef HAVE_TX_TIMEOUT
netdev->tx_timeout = &at_tx_timeout;
netdev->watchdog_timeo = 5 * HZ;
#endif
#ifdef CONFIG_AT_NAPI
netdev->poll = &at_clean;
netdev->weight = 64;
#endif
#ifdef NETIF_F_HW_VLAN_TX
netdev->vlan_rx_register = at_vlan_rx_register;
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = at_netpoll;
#endif
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len;
adapter->bd_number = cards_found;
adapter->pci_using_64 = pci_using_64;
/* setup the private structure */
if((err = at_sw_init(adapter)))
goto err_sw_init;
err = -EIO;
#ifdef MAX_SKB_FRAGS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -