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

📄 at_main.c

📁 Linux* Base Driver for the Attansic(R) L1 Gigabit Ethernet Adapter
💻 C
📖 第 1 页 / 共 5 页
字号:
 * @adapter: board private structure
 *
 * Configure the Tx /Rx unit of the MAC after a reset.
 **/

static uint32_t
at_configure(struct at_adapter *adapter)
{
    struct at_hw * hw = &adapter->hw;
    uint32_t value;
    
//  DEBUGFUNC("at_configure !");
    // clear interrupt status
    AT_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff);

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

    // tx / rx ring :
    
    // HI base address
    AT_WRITE_REG(
          hw, 
          REG_DESC_BASE_ADDR_HI, 
          (uint32_t)((adapter->tpd_ring.dma&0xffffffff00000000ULL) >>32));
    // LO base address
    AT_WRITE_REG(
          hw, 
          REG_DESC_RFD_ADDR_LO, 
          (uint32_t)(adapter->rfd_ring.dma& 0x00000000ffffffffULL));
    AT_WRITE_REG(
          hw, 
          REG_DESC_RRD_ADDR_LO, 
          (uint32_t)(adapter->rrd_ring.dma& 0x00000000ffffffffULL));
    AT_WRITE_REG(hw, 
                 REG_DESC_TPD_ADDR_LO, 
                 (uint32_t)(adapter->tpd_ring.dma& 0x00000000ffffffffULL));
    AT_WRITE_REG(hw, 
                 REG_DESC_CMB_ADDR_LO, 
                 (uint32_t)(adapter->cmb.dma& 0x00000000ffffffffULL));
    AT_WRITE_REG(hw, 
                 REG_DESC_SMB_ADDR_LO, 
                 (uint32_t)(adapter->smb.dma& 0x00000000ffffffffULL));
    
    // element count
    value = adapter->rrd_ring.count;
    value <<= 16;
    value += adapter->rfd_ring.count;
    AT_WRITE_REG(hw, REG_DESC_RFD_RRD_RING_SIZE, value);
    AT_WRITE_REG(hw, REG_DESC_TPD_RING_SIZE, adapter->tpd_ring.count);

/* 
    // config SRAM
    // add RXF 256*8 bytes   
    value = ((2795 + 256) << 16) | 432;
    AT_WRITE_REG(hw, REG_SRAM_RXF_ADDR, value);
    value = 2364 + 256;
    AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, value);
    // sub TXF 256*8 bytes
    value = (4075 << 16) | (2796 + 256);
    AT_WRITE_REG(hw, REG_SRAM_TXF_ADDR, value);
    value = 1280 - 256;
    AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, value);
*/
    // Load Ptr
    AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
    
    
    /* config Mailbox */
    
    value = 
         (((uint32_t)atomic_read(&adapter->tpd_ring.next_to_use)
            &MB_TPD_PROD_INDX_MASK)<<MB_TPD_PROD_INDX_SHIFT) |
         (((uint32_t)atomic_read(&adapter->rrd_ring.next_to_clean)
            &MB_RRD_CONS_INDX_MASK)<<MB_RRD_CONS_INDX_SHIFT) |
         (((uint32_t)atomic_read(&adapter->rfd_ring.next_to_use)
            &MB_RFD_PROD_INDX_MASK)<<MB_RFD_PROD_INDX_SHIFT);
    AT_WRITE_REG(hw, REG_MAILBOX, value);
    
//    DEBUGOUT1("init Mailbox with 0x%x", value);
    
    /* config IPG/IFG */
    value = 
        (((uint32_t)hw->ipgt&MAC_IPG_IFG_IPGT_MASK) 
              <<MAC_IPG_IFG_IPGT_SHIFT) |
        (((uint32_t)hw->min_ifg &MAC_IPG_IFG_MIFG_MASK) 
              <<MAC_IPG_IFG_MIFG_SHIFT) |
        (((uint32_t)hw->ipgr1&MAC_IPG_IFG_IPGR1_MASK)
              <<MAC_IPG_IFG_IPGR1_SHIFT)|
        (((uint32_t)hw->ipgr2&MAC_IPG_IFG_IPGR2_MASK)
              <<MAC_IPG_IFG_IPGR2_SHIFT);
    AT_WRITE_REG(hw, REG_MAC_IPG_IFG, value);
//    DEBUGOUT1("init ipg/ifg with 0x%x", value);
    
    /* config  Half-Duplex Control */
    value = 
      ((uint32_t)hw->lcol&MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
      (((uint32_t)hw->max_retry&MAC_HALF_DUPLX_CTRL_RETRY_MASK)
          <<MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
      MAC_HALF_DUPLX_CTRL_EXC_DEF_EN   |
      (0xa<<MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
      (((uint32_t)hw->jam_ipg&MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
          <<MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
    AT_WRITE_REG(hw, REG_MAC_HALF_DUPLX_CTRL, value);
//    DEBUGOUT1("init Half Duplex with 0x%x", value);
    
    
    /* set Interrupt Moderator Timer */
    AT_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt);
    AT_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_ITIMER_EN);
//    DEBUGOUT1("init Irq Modurator Timer with 0x%x", adapter->imt);
    
    /* set Interrupt Clear Timer */
    AT_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, adapter->ict);
//    DEBUGOUT1("init Irq Clear Timer with 0x%x", adapter->ict);
    
    /* set MTU */
    AT_WRITE_REG(hw, REG_MTU, hw->max_frame_size+4); // 4 : VLAN
//    DEBUGOUT1("init MTU with 0x%x", hw->max_frame_size); 

    // jumbo size & rrd retirement timer
    value = 
      (((uint32_t)hw->rx_jumbo_th&RXQ_JMBOSZ_TH_MASK) 
          << RXQ_JMBOSZ_TH_SHIFT)|
      (((uint32_t)hw->rx_jumbo_lkah&RXQ_JMBO_LKAH_MASK) 
          << RXQ_JMBO_LKAH_SHIFT)|
      (((uint32_t)hw->rrd_ret_timer&RXQ_RRD_TIMER_MASK)
          << RXQ_RRD_TIMER_SHIFT) ;
    AT_WRITE_REG(hw, REG_RXQ_JMBOSZ_RRDTIM, value);
//    DEBUGOUT1("init RXQ Jumbo size RRD retirement Timer with 0x=%x", value);
    // Flow Control
    switch (hw->dev_rev)	    
    {
    case 0x8001: 
    case 0x9001:
    case 0x9002:
    case 0x9003:
	    set_flow_ctrl_old(adapter);
	    break;
    default:
	    set_flow_ctrl_new(hw);
	    break;
    }
				
    /* config TXQ */
    value =  
       (((uint32_t)hw->tpd_burst&TXQ_CTRL_TPD_BURST_NUM_MASK)
           << TXQ_CTRL_TPD_BURST_NUM_SHIFT) |
       (((uint32_t)hw->txf_burst&TXQ_CTRL_TXF_BURST_NUM_MASK) 
           << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
       (((uint32_t)hw->tpd_fetch_th&TXQ_CTRL_TPD_FETCH_TH_MASK)
           << TXQ_CTRL_TPD_FETCH_TH_SHIFT) |
       TXQ_CTRL_ENH_MODE |
       TXQ_CTRL_EN;
    AT_WRITE_REG(hw, REG_TXQ_CTRL, value);
//    DEBUGOUT1("init TXQ Control with 0x%x", value); 
     
    // min tpd fetch gap & tx jumbo packet size threshold for taskoffload
    value = 
      (((uint32_t)hw->tx_jumbo_task_th&TX_JUMBO_TASK_TH_MASK)
         << TX_JUMBO_TASK_TH_SHIFT) |
      (((uint32_t)hw->tpd_fetch_gap&TX_TPD_MIN_IPG_MASK)
         << TX_TPD_MIN_IPG_SHIFT);
    AT_WRITE_REG(hw, REG_TX_JUMBO_TASK_TH_TPD_IPG, value);
//    DEBUGOUT1("init TPD fetch gap & TX jumbo taskoffload threshold with 0x%x", value);
    
    /* config RXQ */
    value =  
      (((uint32_t)hw->rfd_burst&RXQ_CTRL_RFD_BURST_NUM_MASK) 
          << RXQ_CTRL_RFD_BURST_NUM_SHIFT)|
      (((uint32_t)hw->rrd_burst&RXQ_CTRL_RRD_BURST_THRESH_MASK)
          << RXQ_CTRL_RRD_BURST_THRESH_SHIFT)|
      (((uint32_t)hw->rfd_fetch_gap&RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
          << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) |
      RXQ_CTRL_CUT_THRU_EN | 
      RXQ_CTRL_EN ;
      AT_WRITE_REG(hw, REG_RXQ_CTRL, value);
//     DEBUGOUT1("init RXQ control with 0x%x", value);
   
    /* config  DMA Engine */
    value = 
      ((((uint32_t)hw->dmar_block)&DMA_CTRL_DMAR_BURST_LEN_MASK) 
           << DMA_CTRL_DMAR_BURST_LEN_SHIFT)|
      ((((uint32_t)hw->dmaw_block)&DMA_CTRL_DMAR_BURST_LEN_MASK) 
           << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
      DMA_CTRL_DMAR_EN | 
      DMA_CTRL_DMAW_EN;
    value  |= (uint32_t)hw->dma_ord;
    if (at_rcb_128 == hw->rcb_value) 
    {
        value |= DMA_CTRL_RCB_VALUE;
    }
    AT_WRITE_REG(hw, REG_DMA_CTRL, value);
//    DEBUGOUT1("init DMA Engine with 0x%x", value);
    
    /* config CMB / SMB */
    value = hw->cmb_rrd | ((uint32_t)hw->cmb_tpd << 16);
    AT_WRITE_REG(hw, REG_CMB_WRITE_TH, value);
    value = hw->cmb_rx_timer | ((uint32_t)hw->cmb_tx_timer << 16);
    AT_WRITE_REG(hw, REG_CMB_WRITE_TIMER, value);
    AT_WRITE_REG(hw, REG_SMB_TIMER, hw->smb_timer);
//    DEBUGOUT1("init CMB Write Timer with 0x%x", value);

    // --- enable CMB / SMB 
    value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN;
    AT_WRITE_REG(hw, REG_CSMB_CTRL, value);
    
    value = AT_READ_REG(&adapter->hw, REG_ISR);
    if ((value&ISR_PHY_LINKDOWN) != 0) {
        value = 1; // config failed 
    } else {
        value = 0;
    }
    // clear all interrupt status
    AT_WRITE_REG(&adapter->hw, REG_ISR, 0x3fffffff);
    AT_WRITE_REG(&adapter->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 (netif_running(netdev))
        return -EBUSY; 

    if(!is_valid_ether_addr(addr->sa_data))
        return -EADDRNOTAVAIL;

    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);
    int old_mtu = netdev->mtu;
    int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;

    DEBUGFUNC("at_change_mtu !");

    if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
       (max_frame > MAX_JUMBO_FRAME_SIZE)) {
        AT_ERR("Invalid MTU setting\n");
        return -EINVAL;
    }


    adapter->hw.max_frame_size = max_frame;
    adapter->hw.tx_jumbo_task_th = (max_frame+7)>>3;
    adapter->rx_buffer_len = (max_frame+7) & ~7;
    
    adapter->hw.rx_jumbo_th = adapter->rx_buffer_len  / 8;
    
    netdev->mtu = new_mtu;
        
    if((old_mtu != new_mtu) && netif_running(netdev)) {
        
        at_down(adapter);
        at_up(adapter);
    }

    return 0;
}


/**
 * at_alloc_rx_buffers - Replace used receive buffers
 * @adapter: address of board private structure
 **/

static uint16_t
at_alloc_rx_buffers(struct at_adapter *adapter)
{
    struct at_rfd_ring *rfd_ring = &adapter->rfd_ring;
    struct net_device *netdev = adapter->netdev;
    struct pci_dev *pdev = adapter->pdev;
    struct page *page;                                                       
    unsigned long offset;                                                    
    struct at_buffer *buffer_info, * next_info;
    struct sk_buff *skb;
    uint16_t num_alloc = 0;
    uint16_t rfd_next_to_use, next_next;
    rx_free_desc_t *rfd_desc;

    next_next = rfd_next_to_use = (uint16_t)atomic_read(&rfd_ring->next_to_use);
    if (++next_next == rfd_ring->count)      next_next = 0;
    buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
    next_info = &rfd_ring->buffer_info[next_next];

    while (!buffer_info->alloced && !next_info->alloced) {
        if (NULL != buffer_info->skb) {
            buffer_info->alloced = 1;
	    DEBUGOUT1("skip rfd allocate (%d)", rfd_next_to_use);
            goto next;
        }
	
        rfd_desc = AT_RFD_DESC(rfd_ring, rfd_next_to_use);

        skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);

        if(!skb) {
            /* Better luck next round */
            adapter->net_stats.rx_dropped++;
            break;
        }

        /* Make buffer alignment 2 beyond a 16 byte boundary
         * this will result in a 16 byte aligned IP header after
         * the 14 byte MAC header is removed
         */
        skb_reserve(skb, NET_IP_ALIGN);

        skb->dev = netdev;

        buffer_info->alloced = 1;
        buffer_info->skb = skb;
        buffer_info->length = (uint16_t)adapter->rx_buffer_len;
        page = virt_to_page(skb->data);                                            
        offset = (unsigned long) skb->data & ~PAGE_MASK;  
        buffer_info->dma =
                pci_map_page(pdev,
                             page,
                             offset,
                             adapter->rx_buffer_len,
                             PCI_DMA_FROMDEVICE);
        rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
        rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
        rfd_desc->coalese = 0;
        
next:
        rfd_next_to_use = next_next;
        if (++next_next == rfd_ring->count)     next_next = 0;
	
        buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
        next_info = &rfd_ring->buffer_info[next_next];
        num_alloc++;
    }
    
    if (0 != num_alloc) {
        /* Force memory writes to complete before letting h/w
         * know there are new descriptors to fetch.  (Only
         * applicable for weak-ordered memory model archs,
         * such as IA-64). */
        wmb();
        atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
    }
    return num_alloc;
}


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

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

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

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

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

static void
at_clean_tx_ring(struct at_adapter *adapter)
{
    struct at_tpd_ring *tpd_ring = &adapter->tpd_ring;
    struct at_buffer *buffer_info;
    struct pci_dev *pdev = adapter->pdev;
    unsigned long size;
    unsigned int i;

//    DEBUGFUNC("at_clean_tx_ring !");

    /* Free all the Tx ring sk_buffs */

    for(i = 0; i < tpd_ring->count; i++) {
        buffer_info = &tpd_ring->buffer_info[i];
        if (buffer_info->dma) {
            pci_unmap_page(pdev,
                           buffer_info->dma,
                           buffer_info->length,
                           PCI_DMA_TODEVICE);
            buffer_info->dma = 0;
        }
    }
    
    for(i = 0; i < tpd_ring->count; i++) {
        buffer_info = &tpd_ring->buffer_info[i];
        if(buffer_info->skb) {
            dev_kfree_skb_any(buffer_info->skb);
            buffer_info->skb = NULL;
        }
    }

    size = sizeof(struct at_buffer) * tpd_ring->count;
    memset(tpd_ring->buffer_info, 0, size);

⌨️ 快捷键说明

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