⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at_main.c

📁 Atheros公司AR8121/AR8113无线网卡的Linux驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -