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

📄 at_main.c

📁 Linux* Base Driver for the Attansic(R) L1 Gigabit Ethernet Adapter
💻 C
📖 第 1 页 / 共 5 页
字号:
#include "at.h"

#define RUN_REALTIME 0

char at_driver_name[] = "ATL1";
char at_driver_string[] = "Attansic(R) L1 Ethernet Network Driver";
#define DRV_VERSION "0.1.40.6"
char at_driver_version[] = DRV_VERSION;
char at_copyright[] = "Copyright (c) 1999-2005 Attansic Corporation.";


/* 
 * 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[] = {
    ATTANSIC_ETHERNET_DEVICE(0x1048),
    /* required last entry */
    {0,}
};

MODULE_DEVICE_TABLE(pci, at_pci_tbl);

int32_t at_up(struct at_adapter *adapter);
void at_down(struct at_adapter *adapter);
int at_reset(struct at_adapter *adapter);
int32_t at_setup_ring_resources(struct at_adapter *adapter);
void at_free_ring_resources(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 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_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, struct pt_regs *regs);
static void at_inc_smb(struct at_adapter * adapter);
static void at_intr_rx(struct at_adapter* adapter);
static void at_intr_tx(struct at_adapter* adapter);

static void at_watchdog(unsigned long data);
static void at_phy_config(unsigned long data);
static void at_tx_timeout_task(struct net_device *netdev);
static void at_check_for_link(struct at_adapter* adapter);
static void at_link_chg_task(struct net_device* netdev);
static uint32_t at_check_link(struct at_adapter* adapter);

static void at_clean_tx_ring(struct at_adapter *adapter);
static void at_clean_rx_ring(struct at_adapter *adapter);
static uint16_t at_alloc_rx_buffers(struct at_adapter *adapter);
static uint32_t at_configure(struct at_adapter *adapter);
static void at_pcie_patch(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_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
static void at_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
static void at_restore_vlan(struct at_adapter *adapter);
#endif

static int at_notify_reboot(struct notifier_block *nb, unsigned long event, void *p);
static int at_suspend(struct pci_dev *pdev, uint32_t state);
#ifdef CONFIG_PM
static int at_resume(struct pci_dev *pdev);
#endif

static void at_via_workaround(struct at_adapter * adapter);


struct notifier_block at_notifier_reboot = {
    .notifier_call  = at_notify_reboot,
    .next       = NULL,
    .priority   = 0
};

/* Exported from other modules */

extern void at_check_options(struct at_adapter *adapter);
extern int at_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
#ifdef SIOCDEVPRIVATE
extern int at_priv_ioctl(struct net_device* netdev, struct ifreq* ifr);
#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
};

MODULE_AUTHOR("Attansic Corporation, <xiong_huang@attansic.com>");
MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver");
MODULE_LICENSE("ATTANSIC");
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_module_init(&at_driver);
    if(ret >= 0) {
        register_reboot_notifier(&at_notifier_reboot);
    }
    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)
{
    unregister_reboot_notifier(&at_notifier_reboot);
    pci_unregister_driver(&at_driver);
}

module_exit(at_exit_module);


/**
 * 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;
//    uint16_t eeprom_data;

    DEBUGFUNC("at_probe !");

    if((err = pci_enable_device(pdev)))
        return err;

    if((err = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
        if((err = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
            AT_ERR("No usable DMA configuration, aborting\n");
            return err;
        }
        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)))
        return err;

    // Enables bus-mastering on the device and calls 
    // pcibios_set_master to do the needed arch specific settings
    pci_set_master(pdev);

    netdev = alloc_etherdev(sizeof(struct at_adapter));
    if(!netdev) {
        err = -ENOMEM;
        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 = (uint32_t)mmio_len;
    adapter->hw.hw_addr = ioremap_nocache(mmio_start, mmio_len);
    if(!adapter->hw.hw_addr) {
        err = -EIO;
        goto err_ioremap;
    }
    /* get device reversion number */
    adapter->hw.dev_rev = 
	    AT_READ_REGW(&adapter->hw, (REG_MASTER_CTRL+2));

    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;
#ifdef HAVE_TX_TIMEOUT
    netdev->tx_timeout = &at_tx_timeout;
    netdev->watchdog_timeo = 5 * HZ;
#endif
#ifdef NETIF_F_HW_VLAN_TX
    netdev->vlan_rx_register = at_vlan_rx_register;
    netdev->vlan_rx_add_vid = at_vlan_rx_add_vid;
    netdev->vlan_rx_kill_vid = at_vlan_rx_kill_vid;
#endif

    netdev->mem_start = mmio_start;
    netdev->mem_end = mmio_start + mmio_len;
    //netdev->base_addr = adapter->io_base;
    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;

    netdev->features = NETIF_F_HW_CSUM;
    
#ifdef MAX_SKB_FRAGS
    netdev->features |= NETIF_F_SG;
#endif
#ifdef NETIF_F_HW_VLAN_TX
    netdev->features |= 
               (NETIF_F_HW_VLAN_TX | 
                NETIF_F_HW_VLAN_RX );
#endif
#ifdef NETIF_F_TSO
    netdev->features |= NETIF_F_TSO;
#endif/*NETIF_F_TSO*/

    if(pci_using_64) {
        netdev->features |= NETIF_F_HIGHDMA;
        AT_DBG("pci using 64bit address\n");
    }
#ifdef NETIF_F_LLTX
	netdev->features |= NETIF_F_LLTX;
#endif

    /* patch for some L1 of old version,
     * the final version of L1 may not need these 
     * patches 
     */
    at_pcie_patch(adapter);    

    /* really reset GPHY core */
    AT_WRITE_REGW(&adapter->hw, REG_GPHY_ENABLE, 0);

    /* 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);

    if(!is_valid_ether_addr(netdev->dev_addr)) {
        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] );

    at_check_options(adapter);
    
    /* pre-init the MAC, and setup link */

    if ((err = at_init_hw(&adapter->hw))) {
        err = -EIO;
        goto err_init_hw;
    }
    
    /* assume we have no link for now */

    netif_carrier_off(netdev);
    netif_stop_queue(netdev);
    
    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;
    adapter->phy_timer_pending = FALSE;
    
    INIT_WORK(&adapter->tx_timeout_task,
        (void (*)(void *))at_tx_timeout_task, netdev);
        
    INIT_WORK(&adapter->link_chg_task, 
        (void (*)(void *))at_link_chg_task, netdev);
   
    INIT_WORK(&adapter->pcie_dma_to_rst_task,
        (void (*)(void *))at_tx_timeout_task, netdev);

    if((err = register_netdev(netdev)))
        goto err_register;

    
    cards_found++;

	at_via_workaround(adapter);

    return 0;

err_init_hw:
err_reset:
err_register:
err_sw_init:
err_eeprom:
    iounmap(adapter->hw.hw_addr);
err_ioremap:
    free_netdev(netdev);
err_alloc_etherdev:
    pci_release_regions(pdev);
    return err;
}

/**
 * at_pcie_patch - Patch for PCIE module
 **/
void at_pcie_patch(struct at_adapter* adapter)
{
    uint32_t value;
    value = 0x6600;
    AT_WRITE_REG(&adapter->hw, 0x12FC, value);    

    /* pcie flow control mode change */
    value = AT_READ_REG(&adapter->hw, 0x1008);
    value |= 0x8000;
    AT_WRITE_REG(&adapter->hw, 0x1008, value);
}

/**
 * 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;

    DEBUGFUNC("at_remove");

    /* Device not available. Return. */
    if (!netdev)  
        return;

    adapter = netdev_priv(netdev);
    
    AT_WRITE_REGW(&adapter->hw, REG_GPHY_ENABLE, 0);

    unregister_netdev(netdev);

    iounmap(adapter->hw.hw_addr);
    pci_release_regions(pdev);

    free_netdev(netdev);
}


/**
 * at_irq_disable - Mask off interrupt generation on the NIC
 * @adapter: board private structure
 **/
inline void
at_irq_disable(struct at_adapter *adapter)
{
    atomic_inc(&adapter->irq_sem);
    AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
    
    synchronize_irq(adapter->pdev->irq);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -