📄 at_main.c
字号:
#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 + -