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

📄 at_main.c

📁 Atheros公司AR8121/AR8113无线网卡的Linux驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
 *
 * 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;
    u32 rctl;
    u32 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);
    u32 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_restore_vlan(struct at_adapter *adapter)
{
    DEBUGFUNC("at_restore_vlan !");
    at_vlan_rx_register(adapter->netdev, adapter->vlgrp);
}
#endif

static u16 gPayLoadSize[] = {
    128, 256, 512, 1024, 2048, 4096,
};
/**
 * at_configure - Configure Transmit&Receive Unit after Reset
 * @adapter: board private structure
 *
 * Configure the Tx /Rx unit of the MAC after a reset.
 **/

static s32
at_configure(struct at_adapter *adapter)
{
    struct at_hw * hw = &adapter->hw;
    u32 value, hi;
    
    DEBUGFUNC("at_configure !");

    // clear interrupt status
    AT_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff);

    // 1. set MAC Address
    value = (((u32)hw->mac_addr[2]) << 24) |
            (((u32)hw->mac_addr[3]) << 16) |
            (((u32)hw->mac_addr[4]) << 8 ) |
            (((u32)hw->mac_addr[5])      ) ;
    AT_WRITE_REG(hw, REG_MAC_STA_ADDR, value);
    value = (((u32)hw->mac_addr[0]) << 8 ) |
            (((u32)hw->mac_addr[1])      ) ;
    AT_WRITE_REG(hw, (REG_MAC_STA_ADDR+4), value);

    // 2. Init the Multicast HASH table
    // done by set_muti

    // 3. Clear any WOL status
    value = AT_READ_REG(hw, REG_WOL_CTRL);
    AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
    
    // 4. Descripter Ring BaseMem/Length/Read ptr/Write ptr */
    // Descripter Ring BaseMem/Length/Read ptr/Write ptr 
    // TPD Ring/SMB/RXF0 Page CMBs, they use the same High 32bits memory
    AT_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, (u32)((adapter->ring_dma&0xffffffff00000000ULL) >>32));
    AT_WRITE_REG(hw, REG_TPD_BASE_ADDR_LO, (u32)(adapter->tpd_ring_dma));
    AT_WRITE_REG(hw, REG_TPD_RING_SIZE, (u16)(adapter->tpd_ring_size));
    AT_WRITE_REG(hw, REG_HOST_TX_CMB_LO, (u32)adapter->tpd_cmb_dma);
    // RXF Page Physical address / Page Length
    // RXF0
    AT_WRITE_REG(hw, REG_HOST_RXF0_PAGE0_LO, (u32)(adapter->rxf_page[0][0].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF0_PAGE1_LO, (u32)(adapter->rxf_page[0][1].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF0_MB0_LO, (u32)(adapter->rxf_page[0][0].WptrPhyAddr));
    AT_WRITE_REG(hw, REG_HOST_RXF0_MB1_LO, (u32)(adapter->rxf_page[0][1].WptrPhyAddr));
    AT_WRITE_REGB(hw, REG_HOST_RXF0_PAGE0_VLD, 1);
    AT_WRITE_REGB(hw, REG_HOST_RXF0_PAGE1_VLD, 1);
    // RXF1
    AT_WRITE_REG(hw, REG_RXF1_BASE_ADDR_HI, (u32)((adapter->ring_dma&0xffffffff00000000ULL) >>32));
    AT_WRITE_REG(hw, REG_HOST_RXF1_PAGE0_LO, (u32)(adapter->rxf_page[1][0].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF1_PAGE1_LO, (u32)(adapter->rxf_page[1][1].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF1_MB0_LO, (u32)(adapter->rxf_page[1][0].WptrPhyAddr));
    AT_WRITE_REG(hw, REG_HOST_RXF1_MB1_LO, (u32)(adapter->rxf_page[1][1].WptrPhyAddr));  
    AT_WRITE_REGB(hw, REG_HOST_RXF1_PAGE0_VLD, 1);
    AT_WRITE_REGB(hw, REG_HOST_RXF1_PAGE1_VLD, 1);        
    // RXF2
    AT_WRITE_REG(hw, REG_RXF1_BASE_ADDR_HI, (u32)((adapter->ring_dma&0xffffffff00000000ULL) >>32));
    AT_WRITE_REG(hw, REG_HOST_RXF2_PAGE0_LO, (u32)(adapter->rxf_page[2][0].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF2_PAGE1_LO, (u32)(adapter->rxf_page[2][1].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF2_MB0_LO, (u32)(adapter->rxf_page[2][0].WptrPhyAddr));
    AT_WRITE_REG(hw, REG_HOST_RXF2_MB1_LO, (u32)(adapter->rxf_page[2][1].WptrPhyAddr)); 
    AT_WRITE_REGB(hw, REG_HOST_RXF2_PAGE0_VLD, 1);
    AT_WRITE_REGB(hw, REG_HOST_RXF2_PAGE1_VLD, 1);    
    // RXF3
    AT_WRITE_REG(hw, REG_RXF1_BASE_ADDR_HI, (u32)((adapter->ring_dma&0xffffffff00000000ULL) >>32));
    AT_WRITE_REG(hw, REG_HOST_RXF3_PAGE0_LO, (u32)(adapter->rxf_page[3][0].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF3_PAGE1_LO, (u32)(adapter->rxf_page[3][1].dma));
    AT_WRITE_REG(hw, REG_HOST_RXF3_MB0_LO, (u32)(adapter->rxf_page[3][0].WptrPhyAddr));
    AT_WRITE_REG(hw, REG_HOST_RXF3_MB1_LO, (u32)(adapter->rxf_page[3][1].WptrPhyAddr)); 
    AT_WRITE_REGB(hw, REG_HOST_RXF3_PAGE0_VLD, 1);
    AT_WRITE_REGB(hw, REG_HOST_RXF3_PAGE1_VLD, 1);  
    // Page Length
    AT_WRITE_REG(hw, REG_HOST_RXFPAGE_SIZE, adapter->rxf_length);
    // Load all of base address above
    AT_WRITE_REG(hw, REG_LOAD_PTR, 1);


    // 5. set Interrupt Moderator Timer
    AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt);
    AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER2_INIT, adapter->imt);
    AT_WRITE_REG(hw, REG_MASTER_CTRL, 
                       MASTER_CTRL_LED_MODE|MASTER_CTRL_ITIMER_EN|MASTER_CTRL_ITIMER2_EN);
    
    // 13. rx/tx threshold to trig interrupt
    AT_WRITE_REGW(hw, REG_TRIG_RRD_THRESH, 1); // 1 packets
    AT_WRITE_REGW(hw, REG_TRIG_TPD_THRESH, (u16)(adapter->tpd_ring_size/2));
    AT_WRITE_REGW(hw, REG_TRIG_RXTIMER, 4);   // 10us
    AT_WRITE_REGW(hw, REG_TRIG_TXTIMER, (u16)(adapter->imt*4/3)); // 


    // 6. set Interrupt Clear Timer
    AT_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, 10000);
    

    // 7. Enable Read-Clear Interrupt Mechanism
/*
    O_32(pL1e->MemBase+REG_MASTER_CTRL, 
            MASTER_CTRL_INT_RDCLR|MASTER_CTRL_ITIMER_EN|MASTER_CTRL_ITIMER2_EN);
*/        
    // 8. set MTU
    AT_WRITE_REG(hw, REG_MTU, 
            hw->max_frame_size +
            ENET_HEADER_SIZE + 
            VLAN_SIZE +
            ETHERNET_FCS_SIZE);

    // 9. config TXQ
    // early tx threshold
    if (hw->nic_type != athr_l2e_revB) {
	    if (hw->max_frame_size <= 1500)
	        value = hw->max_frame_size + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE ;
	    else if (hw->max_frame_size < 6*1024)
	        value = (hw->max_frame_size + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE) * 2 / 3;
	    else
	        value = (hw->max_frame_size + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE) / 2;
	    AT_WRITE_REG(hw, REG_TX_EARLY_TH, (value + 7) >> 3);
	}
	
    // tx control
    value = AT_READ_REG(hw, REG_DEVICE_CTRL);
    hi = (value>>DEVICE_CTRL_MAX_PAYLOAD_SHIFT)&DEVICE_CTRL_MAX_PAYLOAD_MASK;
    if (hi < (u32)hw->dmaw_block)   
        hw->dmaw_block = (at_dma_req_block) hi;
    hi = (value>>DEVICE_CTRL_MAX_RREQ_SZ_SHIFT)&DEVICE_CTRL_MAX_RREQ_SZ_MASK;
    if (hi < (u32)hw->dmar_block)
        hw->dmar_block = (at_dma_req_block) hi;

	if (hw->nic_type != athr_l2e_revB) {
		AT_WRITE_REGW(hw, REG_TXQ_CTRL+2, gPayLoadSize[hw->dmar_block]);
	}

    AT_WRITE_REGW(hw, REG_TXQ_CTRL,  
        (((u16)5&TXQ_CTRL_NUM_TPD_BURST_MASK) << TXQ_CTRL_NUM_TPD_BURST_SHIFT) |
        TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN);
        
    // 10. config RXQ
 
    if (hw->nic_type != athr_l2e_revB) {    
    	// jumbo size cut-through  
    	AT_WRITE_REGW(hw, REG_RXQ_JMBOSZ_RRDTIM, 
        	(u16) ((hw->rx_jumbo_th&RXQ_JMBOSZ_TH_MASK) << RXQ_JMBOSZ_TH_SHIFT |
            	   (1&RXQ_JMBO_LKAH_MASK) << RXQ_JMBO_LKAH_SHIFT)); 
            	
	    // flow control
	    value = AT_READ_REG(hw, REG_SRAM_RXF_LEN);
	    hi = value * 4 / 5;
	    value /= 5;
	    value = 
	          ((hi&RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT)|
	          ((value&RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
	    AT_WRITE_REG(hw, REG_RXQ_RXF_PAUSE_THRESH, value);
    }
    
    // RRS  
    AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab);
    AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu);
    value = 0;
    if (hw->rrs_type&at_rrs_ipv4)       value |= RXQ_CTRL_HASH_TYPE_IPV4;
    if (hw->rrs_type&at_rrs_ipv4_tcp)   value |= RXQ_CTRL_HASH_TYPE_IPV4_TCP;
    if (hw->rrs_type&at_rrs_ipv6)       value |= RXQ_CTRL_HASH_TYPE_IPV6;
    if (hw->rrs_type&at_rss_ipv6_tcp)   value |= RXQ_CTRL_HASH_TYPE_IPV6_TCP;
    if (hw->rrs_type&(at_rrs_ipv4|at_rrs_ipv4_tcp|at_rrs_ipv6|at_rss_ipv6_tcp)) {
        value |= RXQ_CTRL_HASH_ENABLE|RXQ_CTRL_RSS_MODE_MQUESINT;
    }
    value |= RXQ_CTRL_IPV6_XSUM_VERIFY_EN|RXQ_CTRL_PBA_ALIGN_32|
            RXQ_CTRL_CUT_THRU_EN|RXQ_CTRL_EN;
    AT_WRITE_REG(hw, REG_RXQ_CTRL, value);

    // 11. config  DMA Engine
    value =  
        ((((u32)hw->dmar_block)&DMA_CTRL_DMAR_BURST_LEN_MASK)
           << DMA_CTRL_DMAR_BURST_LEN_SHIFT)|
        ((((u32)hw->dmaw_block)&DMA_CTRL_DMAW_BURST_LEN_MASK) 
           << DMA_CTRL_DMAW_BURST_LEN_SHIFT) |
        DMA_CTRL_DMAR_REQ_PRI | 
        DMA_CTRL_DMAR_OUT_ORDER |
        ((15&DMA_CTRL_DMAR_DLY_CNT_MASK)<<DMA_CTRL_DMAR_DLY_CNT_SHIFT) |
        ((4&DMA_CTRL_DMAW_DLY_CNT_MASK)<<DMA_CTRL_DMAW_DLY_CNT_SHIFT) |
        DMA_CTRL_RXCMB_EN;
	/* disable TXCMB */
	/* DMA_CTRL_TXCMB_EN */
    AT_WRITE_REG(hw, REG_DMA_CTRL, value);

    // 12. smb timer to trig interrupt
    AT_WRITE_REG(hw, REG_SMB_STAT_TIMER, 50000);
    
    value = AT_READ_REG(hw, REG_ISR);
    if (unlikely((value & ISR_PHY_LINKDOWN) != 0))
        value = 1;  /* config failed */
    else
        value = 0;

    // clear all interrupt status
    AT_WRITE_REG(hw, REG_ISR, 0x7fffffff);
    AT_WRITE_REG(hw, REG_ISR, 0);
    
    return value;
}

/**
 * at_set_mac - Change the Ethernet Address of the NIC
 * @netdev: network interface device structure
 * @p: pointer to an address structure
 *
 * Returns 0 on success, negative on failure
 **/

static int
at_set_mac(struct net_device *netdev, void *p)
{
    struct at_adapter *adapter = netdev_priv(netdev);
    struct sockaddr *addr = p;

    DEBUGFUNC("at_set_mac !");
    
    if (!is_valid_ether_addr(addr->sa_data))
        return -EADDRNOTAVAIL;
        
    if (netif_running(netdev))
        return -EBUSY; 

    memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
    memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);

    set_mac_addr(&adapter->hw);

    return 0;
}



/**
 * at_change_mtu - Change the Maximum Transfer Unit
 * @netdev: network interface device structure
 * @new_mtu: new value for maximum frame size
 *
 * Returns 0 on success, negative on failure
 **/

static int
at_change_mtu(struct net_device *netdev, int new_mtu)
{
    struct at_adapter *adapter = netdev_priv(netdev);
    struct at_hw* hw = &adapter->hw;
    
    DEBUGFUNC("at_change_mtu !");
    
    if ((new_mtu < 40) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE)))
        return -EINVAL;


    /* set MTU */
    if (hw->max_frame_size != new_mtu) {
        
        while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
            msleep(1);
        
        if (netif_running(netdev)) {
            at_down(adapter);
        }
        
        netdev->mtu = new_mtu;   
        hw->max_frame_size = new_mtu;
        hw->rx_jumbo_th = (new_mtu+
                                ENET_HEADER_SIZE + 
                                VLAN_SIZE +
                                ETHERNET_FCS_SIZE + 7)>>3;
        
        if (netif_running(netdev))
            at_up(adapter);
        else
            at_reset(adapter);

        clear_bit(__AT_RESETTING, &adapter->flags);
    }

    return 0;
}



void
at_read_pci_cfg(struct at_hw *hw, u32 reg, u16 *value)
{
    struct at_adapter *adapter = hw->back;

    pci_read_config_word(adapter->pdev, reg, value);
}

void
at_write_pci_cfg(struct at_hw *hw, u32 reg, u16 *value)
{
    struct at_adapter *adapter = hw->back;

    pci_write_config_word(adapter->pdev, reg, *value);
}

/**
 * at_clean_tx_ring - Free Tx-skb
 * @adapter: board private structure
 **/

static void
at_clean_tx_ring(struct at_adapter *adapter)
{
    struct at_buffer *buffer_info;
    struct pci_dev *pdev = adapter->pdev;
    u16 index;

//    DEBUGFUNC("at_clean_tx_ring !");

    if (NULL == adapter->tx_buffer_info ||
        NULL == adapter->tpd_ring)
        return;
    
    for (index=0; index < adapter->tpd_ring_size; index++) {
        buffer_info = adapter->tx_buffer_info + index;
        if (buffer_info->dma) {
            pci_unmap_page(pdev,
                           buffer_info->dma,
                           buffer_info->length,
                           PCI_DMA_TODEVICE);
            buffer_info->dma = 0;
        }
    }
    for(index = 0; index < adapter->tpd_ring_size; index++) {
        buffer_info = adapter->tx_buffer_info + index;
        if(buffer_info->skb) {
            dev_kfree_skb_any(buffer_info->skb);
            buffer_info->skb = NULL;
        }
    }
 
    /* Zero out Tx-buffers */
    memset(adapter->tx_buffer_info, 0, 
            sizeof(struct at_buffer)*adapter->tpd_ring_size);
    
    memset(adapter->tpd_ring, 0, 
            sizeof(TpdDescr)*adapter->tpd_ring_size);
}

/**
 * at_clean_rx_ring - Free rx-reservation skbs
 * @adapter: board private structure
 **/

static void
at_clean_rx_ring(struct at_adapter *adapter)
{
    u16 i;
// 

⌨️ 快捷键说明

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