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

📄 at_main.c

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

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 + -