📄 at_main.c
字号:
**/
void
at_free_ring_resources(struct at_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct at_tpd_ring *tpd_ring = &adapter->tpd_ring;
struct at_rfd_ring *rfd_ring = &adapter->rfd_ring;
struct at_rrd_ring * rrd_ring = &adapter->rrd_ring;
struct at_ring_header * ring_header = &adapter->ring_header;
// DEBUGFUNC("at_free_ring_resources !");
at_clean_tx_ring(adapter);
at_clean_rx_ring(adapter);
kfree(tpd_ring->buffer_info);
pci_free_consistent(
pdev,
ring_header->size,
ring_header->desc,
ring_header->dma);
tpd_ring->buffer_info = NULL;
tpd_ring->desc = NULL;
tpd_ring->dma = 0;
rfd_ring->buffer_info = NULL;
rfd_ring->desc = NULL;
rfd_ring->dma = 0;
rrd_ring->desc = NULL;
rrd_ring->dma = 0;
}
int32_t
at_up(struct at_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
DEBUGFUNC("at_up !");
/* hardware has been reset, we need to reload some things */
at_set_multi(netdev);
#ifdef NETIF_F_HW_VLAN_TX
at_restore_vlan(adapter);
#endif
err = at_alloc_rx_buffers(adapter);
if (0 == err)
{ // no RX BUFFER allocated
return -ENOMEM;
}
if (at_configure(adapter)) {
err = -EIO;
goto err_up;
}
if ((err = request_irq(adapter->pdev->irq,
&at_intr,
SA_SHIRQ | SA_SAMPLE_RANDOM,
netdev->name, netdev)))
goto err_up;
mod_timer(&adapter->watchdog_timer, jiffies);
at_irq_enable(adapter);
at_check_link(adapter);
return 0;
// free irq
// disable any interrupt
AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
free_irq(adapter->pdev->irq, netdev);
err_up:
// free rx_buffers
at_clean_rx_ring(adapter);
return err;
}
inline void
at_setup_mac_ctrl(struct at_adapter* adapter)
{
uint32_t value;
struct at_hw* hw = &adapter->hw;
struct net_device* netdev = adapter->netdev;
/* Config MAC CTRL Register */
value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN;
// duplex
if (FULL_DUPLEX == adapter->link_duplex)
value |= MAC_CTRL_DUPLX;
// speed
value |= ((uint32_t)((SPEED_1000 == adapter->link_speed) ?
MAC_CTRL_SPEED_1000 :
MAC_CTRL_SPEED_10_100)<< MAC_CTRL_SPEED_SHIFT);
// flow control
value |= (MAC_CTRL_TX_FLOW|MAC_CTRL_RX_FLOW);
// PAD & CRC
value |= (MAC_CTRL_ADD_CRC|MAC_CTRL_PAD);
// preamble length
value |= (((uint32_t)adapter->hw.preamble_len
&MAC_CTRL_PRMLEN_MASK)<< MAC_CTRL_PRMLEN_SHIFT);
// vlan
if (adapter->vlgrp)
value |= MAC_CTRL_RMV_VLAN;
/*
// rx checksum
if (adapter->rx_csum)
value |= MAC_CTRL_RX_CHKSUM_EN;
*/
// filter mode
value |= MAC_CTRL_BC_EN;
if (netdev->flags & IFF_PROMISC)
value |= MAC_CTRL_PROMIS_EN;
else if (netdev->flags & IFF_ALLMULTI)
value |= MAC_CTRL_MC_ALL_EN;
// value |= MAC_CTRL_LOOPBACK;
AT_WRITE_REG(hw, REG_MAC_CTRL, value);
}
static uint32_t
at_check_link(struct at_adapter* adapter)
{
struct at_hw *hw = &adapter->hw;
struct net_device * netdev = adapter->netdev;
uint32_t ret_val;
uint16_t speed, duplex, phy_data;
int reconfig = 0;
// DEBUGFUNC("at_check_link !");
// MII_BMSR must read twise
at_read_phy_reg(hw, MII_BMSR, &phy_data);
at_read_phy_reg(hw, MII_BMSR, &phy_data);
if (!(phy_data&BMSR_LSTATUS)) { // link down
if (netif_carrier_ok(netdev)) { // old link state: Up
DEBUGOUT("NIC Link is Down");
adapter->link_speed = SPEED_0;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
}
return AT_SUCCESS;
}
// Link Up
ret_val = at_get_speed_and_duplex(hw, &speed, &duplex);
if (ret_val) return ret_val;
switch( hw->MediaType )
{
case MEDIA_TYPE_1000M_FULL:
if (speed != SPEED_1000 || duplex != FULL_DUPLEX)
reconfig = 1;
break;
case MEDIA_TYPE_100M_FULL:
if (speed != SPEED_100 || duplex != FULL_DUPLEX)
reconfig = 1;
break;
case MEDIA_TYPE_100M_HALF:
if (speed != SPEED_100 || duplex != HALF_DUPLEX)
reconfig = 1;
break;
case MEDIA_TYPE_10M_FULL:
if (speed != SPEED_10 || duplex != FULL_DUPLEX)
reconfig = 1;
break;
case MEDIA_TYPE_10M_HALF:
if (speed != SPEED_10 || duplex != HALF_DUPLEX)
reconfig = 1;
break;
}
// link result is our setting
if (0 == reconfig)
{
if (adapter->link_speed != speed ||
adapter->link_duplex != duplex ) {
adapter->link_speed = speed;
adapter->link_duplex = duplex;
at_setup_mac_ctrl(adapter);
printk(KERN_INFO
"%s: %s NIC Link is Up<%d Mbps %s>\n",
at_driver_name,
netdev->name, adapter->link_speed,
adapter->link_duplex == FULL_DUPLEX ?
"Full Duplex" : "Half Duplex");
}
if (!netif_carrier_ok(netdev)) { // Link down -> Up
netif_carrier_on(netdev);
netif_wake_queue(netdev);
}
return AT_SUCCESS;
}
// change orignal link status
if (netif_carrier_ok(netdev)) {
adapter->link_speed = SPEED_0;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
}
if (hw->MediaType != MEDIA_TYPE_AUTO_SENSOR &&
hw->MediaType != MEDIA_TYPE_1000M_FULL ) {
switch (hw->MediaType)
{
case MEDIA_TYPE_100M_FULL:
phy_data = MII_CR_FULL_DUPLEX|MII_CR_SPEED_100|MII_CR_RESET;
break;
case MEDIA_TYPE_100M_HALF:
phy_data = MII_CR_SPEED_100|MII_CR_RESET;
break;
case MEDIA_TYPE_10M_FULL:
phy_data = MII_CR_FULL_DUPLEX|MII_CR_SPEED_10|MII_CR_RESET;
break;
default: // MEDIA_TYPE_10M_HALF:
phy_data = MII_CR_SPEED_10|MII_CR_RESET;
break;
}
at_write_phy_reg(hw, MII_BMCR, phy_data);
DEBUGOUT("RE-CONFIG-PHY !");
return AT_SUCCESS;
}
// auto-neg, insert timer to re-config phy
if (!adapter->phy_timer_pending) {
adapter->phy_timer_pending = TRUE;
mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ);
}
return AT_SUCCESS;
}
void
at_down(struct at_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
DEBUGFUNC("at_down !");
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_config_timer);
adapter->phy_timer_pending = FALSE;
at_irq_disable(adapter);
free_irq(adapter->pdev->irq, netdev);
at_reset_hw(&adapter->hw);
adapter->cmb.cmb->int_stats = 0;
adapter->link_speed = SPEED_0;
adapter->link_duplex = -1;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
at_clean_tx_ring(adapter);
at_clean_rx_ring(adapter);
}
/**
* at_set_multi - Multicast and Promiscuous mode set
* @netdev: network interface device structure
*
* The set_multi entry point is called whenever the multicast address
* list or the network interface flags are updated. This routine is
* responsible for configuring the hardware for proper multicast,
* promiscuous mode, and all-multi behavior.
**/
static void
at_set_multi(struct net_device *netdev)
{
struct at_adapter *adapter = netdev_priv(netdev);
struct at_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
uint32_t rctl;
uint32_t hash_value;
// DEBUGFUNC("at_set_multi !");
/* Check for Promiscuous and All Multicast modes */
rctl = AT_READ_REG(hw, REG_MAC_CTRL);
if(netdev->flags & IFF_PROMISC) {
rctl |= MAC_CTRL_PROMIS_EN;
} else if(netdev->flags & IFF_ALLMULTI) {
rctl |= MAC_CTRL_MC_ALL_EN;
rctl &= ~MAC_CTRL_PROMIS_EN;
} else {
rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
}
AT_WRITE_REG(hw, REG_MAC_CTRL, rctl);
/* clear the old settings from the multicast hash table */
AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
/* comoute mc addresses' hash value ,and put it into hash table */
for(mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
hash_value = at_hash_mc_addr(hw, mc_ptr->dmi_addr);
at_hash_set(hw, hash_value);
}
}
#ifdef NETIF_F_HW_VLAN_TX
static void
at_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
struct at_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl;
// DEBUGFUNC("at_vlan_rx_register !");
at_irq_disable(adapter);
adapter->vlgrp = grp;
if(grp) {
/* enable VLAN tag insert/strip */
ctrl = AT_READ_REG(&adapter->hw, REG_MAC_CTRL);
ctrl |= MAC_CTRL_RMV_VLAN;
AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl);
} else {
/* disable VLAN tag insert/strip */
ctrl = AT_READ_REG(&adapter->hw, REG_MAC_CTRL);
ctrl &= ~MAC_CTRL_RMV_VLAN;
AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl);
}
at_irq_enable(adapter);
}
static void
at_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
{
/* We don't do Vlan filtering */
// DEBUGFUNC("at_vlan_rx_add_vid !");
return ;
}
static void
at_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
{
struct at_adapter *adapter = netdev_priv(netdev);
// DEBUGFUNC("at_vlan_rx_kill_vid !");
at_irq_disable(adapter);
if(adapter->vlgrp)
adapter->vlgrp->vlan_devices[vid] = NULL;
at_irq_enable(adapter);
/* We don't do Vlan filtering */
return;
}
static void
at_restore_vlan(struct at_adapter *adapter)
{
// DEBUGFUNC("at_restore_vlan !");
at_vlan_rx_register(adapter->netdev, adapter->vlgrp);
if(adapter->vlgrp) {
uint16_t vid;
for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
if(!adapter->vlgrp->vlan_devices[vid])
continue;
at_vlan_rx_add_vid(adapter->netdev, vid);
}
}
}
#endif
static inline
void set_flow_ctrl_old(struct at_adapter* adapter)
{
uint32_t Hi, Lo, value;
// RFD Flow Control
value = adapter->rfd_ring.count;
Hi = value / 16;
if (Hi < 2) Hi = 2;
Lo = value * 7 / 8;
value = ((Hi&RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT)|
((Lo&RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
AT_WRITE_REG(&adapter->hw, REG_RXQ_RXF_PAUSE_THRESH, value);
// RRD Flow Control
value = adapter->rrd_ring.count;
Lo = value / 16;
Hi = value * 7 / 8;
if (Lo < 2) Lo = 2;
value = ((Hi&RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT)|
((Lo&RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
AT_WRITE_REG(&adapter->hw, REG_RXQ_RRD_PAUSE_THRESH, value);
}
static inline
void set_flow_ctrl_new(struct at_hw* hw)
{
uint32_t Hi, Lo, value;
// RXF Flow Control
value = AT_READ_REG(hw, REG_SRAM_RXF_LEN);
Lo = value / 16;
if (Lo < 192) Lo = 192;
Hi = value * 7 / 8;
if (Hi < Lo) Hi = Lo + 16;
value = ((Hi&RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT)|
((Lo&RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
AT_WRITE_REG(hw, REG_RXQ_RXF_PAUSE_THRESH, value);
// RRD Flow Control
value = AT_READ_REG(hw, REG_SRAM_RRD_LEN);
Lo = value / 8;
Hi = value * 7 / 8;
if (Lo < 2) Lo = 2;
if (Hi < Lo) Hi = Lo + 3;
value = ((Hi&RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT)|
((Lo&RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
AT_WRITE_REG(hw, REG_RXQ_RRD_PAUSE_THRESH, value);
}
/**
* at_configure - Configure Transmit&Receive Unit after Reset
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -