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

📄 at_main.c

📁 Atheros公司AR8121/AR8113无线网卡的Linux驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
 * needs to be disabled.  A global MAC reset is issued to stop the
 * hardware, and all transmit and receive resources are freed.
 **/

static int
at_close(struct net_device *netdev)
{
    struct at_adapter *adapter = netdev_priv(netdev);
    DEBUGFUNC("at_close!");

    WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
    
    at_down(adapter);
    at_free_irq(adapter);
    at_free_ring_resources(adapter);

    return 0;
}


/**
 * at_setup_mem_resources - allocate Tx / RX descriptor resources 
 * @adapter: board private structure
 *
 * Return 0 on success, negative on failure
 **/

s32
at_setup_ring_resources(struct at_adapter *adapter)
{
    struct pci_dev *pdev = adapter->pdev;
    int size, i;
    u32 offset = 0;
    u32 page_size;

    DEBUGFUNC("at_setup_ring_resources");

    /* real ring DMA buffer */
    page_size = adapter->rxf_length 
            + adapter->hw.max_frame_size 
            + ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE;
    page_size = (page_size + 31) & 0xFFFFFFE0;
            
    adapter->ring_size = size =   
          adapter->tpd_ring_size * sizeof(TpdDescr) + 7 // qword align
        + page_size * 2 * adapter->num_rx_queues + 31 // 32bytes algin
        + (1 + 2 * adapter->num_rx_queues) * 4 + 3; // cmb dma address
        
    adapter->ring_vir_addr = 
                    pci_alloc_consistent(pdev, size, &adapter->ring_dma);
    if (!adapter->ring_vir_addr) {
        DEBUGOUT1("pci_alloc_consistent failed, size = D%d", size);
        return -ENOMEM;
    }
 
    if (adapter->pci_using_64) { 
        // test whether HIDWORD dma buffer is not cross boundary
        if (    ((adapter->ring_dma       &0xffffffff00000000ULL)>>32)
             != (((adapter->ring_dma+size)&0xffffffff00000000ULL)>>32) ) {
            dma_addr_t dma;
            u8* addr;
            addr = pci_alloc_consistent(pdev, size, &dma);
            if (addr) {
                if ( ((dma&0xffffffff00000000ULL)>>32) !=
                     (((dma+size)&0xffffffff00000000ULL)>>32) ) {
                    pci_free_consistent(pdev, size, addr, dma);
                } else {
                     pci_free_consistent(
                        pdev, 
                        adapter->ring_size, 
                        adapter->ring_vir_addr, 
                        adapter->ring_dma);
                     adapter->ring_vir_addr = addr;
                     adapter->ring_dma = dma;
                     goto init_desc;
                }
            }

            pci_free_consistent(
                     pdev, 
                     adapter->ring_size, 
                     adapter->ring_vir_addr, 
                     adapter->ring_dma);
            DEBUGOUT("memory allocated cross 32bit boundary !");
            return -ENOMEM;
        }
    }
    
init_desc:
//    DEBUGOUT("memory allocated successfully !");    
    
    memset(adapter->ring_vir_addr, 0, adapter->ring_size);
    
    // tx buffer_infos
    size = sizeof(struct at_buffer) * (adapter->tpd_ring_size);
    adapter->tx_buffer_info = kmalloc(size, GFP_KERNEL);
    if(!adapter->tx_buffer_info) {
        pci_free_consistent(
                     pdev, 
                     adapter->ring_size, 
                     adapter->ring_vir_addr, 
                     adapter->ring_dma);
        adapter->ring_vir_addr = NULL;
        DEBUGOUT1("kmalloc failed , size = D%d", size);
        return -ENOMEM;
    }
    memset(adapter->tx_buffer_info, 0, size);
    
    

    // Init TPD Ring
    adapter->tpd_ring_dma = adapter->ring_dma;
    offset = (adapter->tpd_ring_dma & 0x7) ? 
                (8 - (adapter->tpd_ring_dma & 0x7)) : 0;
    adapter->tpd_ring_dma += offset;
    adapter->tpd_ring = (TpdDescr*) (adapter->ring_vir_addr + offset);
    

    // Init RXF-Pages
    offset += (sizeof(TpdDescr) * adapter->tpd_ring_size);
    offset = (offset + 31) & 0xFFFFFFE0;
    
    for (i=0; i < adapter->num_rx_queues; i++) {
        adapter->rxf_page[i][0].dma = 
            adapter->ring_dma + (offset + i * 2 * page_size);
        adapter->rxf_page[i][0].addr = 
            adapter->ring_vir_addr + (offset + i * 2 * page_size);
        
        adapter->rxf_page[i][1].dma = 
            adapter->rxf_page[i][0].dma + page_size;
        adapter->rxf_page[i][1].addr = 
            adapter->rxf_page[i][0].addr + page_size;
    }
    
    // Init CMB dma address
    offset += page_size * 2 * adapter->num_rx_queues;
    adapter->tpd_cmb_dma = adapter->ring_dma + offset;
    adapter->tpd_cmb = (u32*)(adapter->ring_vir_addr + offset);
    offset += 4;
    for (i=0; i < adapter->num_rx_queues; i++) {
        adapter->rxf_page[i][0].WptrPhyAddr = adapter->ring_dma + offset;
        adapter->rxf_page[i][0].pWptr = adapter->ring_vir_addr + offset;
        offset += 4;
        adapter->rxf_page[i][1].WptrPhyAddr = adapter->ring_dma + offset;
        adapter->rxf_page[i][1].pWptr = adapter->ring_vir_addr + offset;
        offset += 4;
    }
            
    if (offset > adapter->ring_size) {
        DEBUGOUT2("offset(%d) > ring size(%d) !!\n", 
            offset, adapter->ring_size);
    }
    
      
    // Read / Write Ptr Initialize:
    //   init_ring_ptrs(adapter);

    return AT_SUCCESS;
}


void
init_ring_ptrs(struct at_adapter *adapter)
{
    int i;
    // Read / Write Ptr Initialize:
    
    adapter->tpd_next_use = 0;
    atomic_set(&adapter->tpd_next_clean, 0);
    for (i=0; i < adapter->num_rx_queues; i++) {
        adapter->rxf_using[i] = 0;
        *adapter->rxf_page[i][0].pWptr = 0;
        *adapter->rxf_page[i][1].pWptr = 0;
        adapter->rxf_page[i][0].Rptr = 0;
        adapter->rxf_page[i][1].Rptr = 0;
        adapter->rxf_nxseq[i] = 0;
    }
}

/**
 * at_free_ring_resources - Free Tx / RX descriptor Resources
 * @adapter: board private structure
 *
 * Free all transmit software resources
 **/

void
at_free_ring_resources(struct at_adapter *adapter)
{
    struct pci_dev *pdev = adapter->pdev;
    
    DEBUGFUNC("at_free_ring_resources");

    at_clean_tx_ring(adapter);
    at_clean_rx_ring(adapter);
    
    if (adapter->ring_vir_addr) {
        pci_free_consistent(
             pdev, 
             adapter->ring_size,
             adapter->ring_vir_addr,
             adapter->ring_dma);
        adapter->ring_vir_addr = NULL;           
    }
    
    if (adapter->tx_buffer_info) {
        kfree(adapter->tx_buffer_info);
        adapter->tx_buffer_info = NULL;
    }
         
}


int
at_up(struct at_adapter *adapter)
{
    struct net_device *netdev = adapter->netdev;
    int err = 0;
    u32 val;

    DEBUGFUNC("at_up !"); 

    /* hardware has been reset, we need to reload some things */

    err = at_init_hw(&adapter->hw);
    if (err) {
        err = -EIO;
        return err;
    }

    at_set_multi(netdev);
    init_ring_ptrs(adapter);

#ifdef NETIF_F_HW_VLAN_TX
    at_restore_vlan(adapter);
#endif

    if (at_configure(adapter)) {
        err = -EIO;
        goto err_up;
    }    

    clear_bit(__AT_DOWN, &adapter->flags);
    
    val = AT_READ_REG(&adapter->hw, REG_MASTER_CTRL);
    AT_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val|MASTER_CTRL_MANUAL_INT);

#ifdef CONFIG_AT_MQ
    at_setup_queue_mapping(adapter);
#endif
  
#ifdef CONFIG_AT_NAPI
    netif_poll_enable(netdev);
#endif

    at_irq_enable(adapter);
err_up:
    return err;
}

inline void
at_setup_mac_ctrl(struct at_adapter* adapter)
{
    u32 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 |= ((u32)((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 |= (((u32)adapter->hw.preamble_len
                  &MAC_CTRL_PRMLEN_MASK)<< MAC_CTRL_PRMLEN_SHIFT);
    // vlan 
    if (adapter->vlgrp)     
        value |= MAC_CTRL_RMV_VLAN;
        
    // 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;

    AT_WRITE_REG(hw, REG_MAC_CTRL, value);
}


static int
at_check_link(struct at_adapter* adapter)
{
    struct at_hw *hw = &adapter->hw;
    struct net_device * netdev = adapter->netdev;
    int ret_val;
    u16 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
            u32 value;
            DEBUGOUT("NIC Link is Down");
            //disable rx
            value = AT_READ_REG(hw, REG_MAC_CTRL);
            value &= ~MAC_CTRL_RX_EN;
            AT_WRITE_REG(hw, REG_MAC_CTRL, value);            
            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;

/*  do not check AutoNeg's result
    switch( hw->MediaType )
    {
    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;
    }
    
printk("re-config-phy!\n");

    // change orignal link status
    if (netif_carrier_ok(netdev)) {
        u32 value;
        // disable rx
        value = AT_READ_REG(hw, REG_MAC_CTRL);
        value &= ~MAC_CTRL_RX_EN;
        AT_WRITE_REG(hw, REG_MAC_CTRL, value); 
            
        adapter->link_speed = SPEED_0;
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
    }
    
    // auto-neg, insert timer to re-config phy (if interval smaller than 5 seconds, something strange)
    if (!test_and_set_bit(0, &adapter->cfg_phy)) {
        mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ);
    }

    return AT_SUCCESS;
}

void
at_down(struct at_adapter *adapter)
{
    struct net_device *netdev = adapter->netdev;
    
    DEBUGFUNC("at_down !");

     /* signal that we're down so the interrupt handler does not
      * reschedule our watchdog timer */
    set_bit(__AT_DOWN, &adapter->flags);

#ifdef NETIF_F_LLTX
    netif_stop_queue(netdev);
#else
    netif_tx_disable(netdev);
#endif

    /* reset MAC to disable all RX/TX */
    at_reset_hw(&adapter->hw);
    msleep(1);
    
#ifdef CONFIG_AT_NAPI
    netif_poll_disable(netdev);
#endif    
    at_irq_disable(adapter);
    
    del_timer_sync(&adapter->watchdog_timer);
    del_timer_sync(&adapter->phy_config_timer);
    clear_bit(0, &adapter->cfg_phy);

    
    netif_carrier_off(netdev);
    adapter->link_speed = SPEED_0;
    adapter->link_duplex = -1;
    
    at_clean_tx_ring(adapter);
    at_clean_rx_ring(adapter);
}



/**
 * at_set_multi - Multicast and Promiscuous mode set
 * @netdev: network interface device structure

⌨️ 快捷键说明

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