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

📄 at_main.c

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

    memset(tpd_ring->desc, 0, tpd_ring->size);

    atomic_set(&tpd_ring->next_to_use, 0);
    atomic_set(&tpd_ring->next_to_clean, 0);
}

/**
 * at_clean_rx_ring - Free RFD Buffers
 * @adapter: board private structure
 **/

static void
at_clean_rx_ring(struct at_adapter *adapter)
{
    struct at_rfd_ring *rfd_ring = &adapter->rfd_ring;
    struct at_rrd_ring *rrd_ring = &adapter->rrd_ring;
    struct at_buffer *buffer_info;
    struct pci_dev *pdev = adapter->pdev;
    unsigned long size;
    unsigned int i;

//    DEBUGFUNC("at_clean_rx_ring !");

    /* Free all the Rx ring sk_buffs */

    for(i = 0; i < rfd_ring->count; i++) {
        buffer_info = &rfd_ring->buffer_info[i];
        if(buffer_info->dma) {

            pci_unmap_page(pdev,
                           buffer_info->dma,
                           buffer_info->length,
                           PCI_DMA_FROMDEVICE);
            buffer_info->dma = 0;
        }
        if(buffer_info->skb) {
            dev_kfree_skb(buffer_info->skb);
            buffer_info->skb = NULL;
        }
    }

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

    /* Zero out the descriptor ring */

    memset(rfd_ring->desc, 0, rfd_ring->size);

    rfd_ring->next_to_clean = 0;
    atomic_set(&rfd_ring->next_to_use, 0);
    
    rrd_ring->next_to_use = 0;
    atomic_set(&rrd_ring->next_to_clean, 0);
}

/**
 * at_get_stats - Get System Network Statistics
 * @netdev: network interface device structure
 *
 * Returns the address of the device statistics structure.
 * The statistics are actually updated from the timer callback.
 **/

static struct net_device_stats *
at_get_stats(struct net_device *netdev)
{
    struct at_adapter *adapter = netdev_priv(netdev);
  
   // DEBUGFUNC("at_get_stats");
    return &adapter->net_stats;
}       

/**
 * at_ioctl -
 * @netdev:
 * @ifreq:
 * @cmd:
 **/

static int
at_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
//    DEBUGFUNC("at_ioctl !");
    switch (cmd) {
#ifdef SIOCGMIIPHY
    case SIOCGMIIPHY:
    case SIOCGMIIREG:
    case SIOCSMIIREG:
        return at_mii_ioctl(netdev, ifr, cmd);
#endif

/*
#ifdef ETHTOOL_OPS_COMPAT
	case SIOCETHTOOL:
		return at_ethtool_ioctl(ifr);
#endif
*/
	
	//michael add 2005-11-1
	case SIOCETHTOOL:
		return at_ethtool_ioctl(netdev,ifr);
#ifdef SIOCDEVPRIVATE
    case SIOCDEVPRIVATE:
        return at_priv_ioctl(netdev, ifr);
#endif

	default:
		return -EOPNOTSUPP;
	}
}

#ifdef SIOCGMIIPHY
/**
 * at_mii_ioctl -
 * @netdev:
 * @ifreq:
 * @cmd:
 **/

static int
at_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
    struct at_adapter *adapter = netdev_priv(netdev);
    struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
    unsigned long flags;

//    DEBUGFUNC("at_mii_ioctl !");

    switch (cmd) {
    case SIOCGMIIPHY:
        data->phy_id = 0;
        break;
    case SIOCGMIIREG:
        if (!capable(CAP_NET_ADMIN))
            return -EPERM;
        spin_lock_irqsave(&adapter->stats_lock, flags);
        if (at_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) {
            spin_unlock_irqrestore(&adapter->stats_lock, flags);
            return -EIO;
        }
        spin_unlock_irqrestore(&adapter->stats_lock, flags);
        break;
    case SIOCSMIIREG:
        if (!capable(CAP_NET_ADMIN))
            return -EPERM;
        if (data->reg_num & ~(0x1F))
            return -EFAULT;
         
        spin_lock_irqsave(&adapter->stats_lock, flags);
	DEBUGOUT1("<at_mii_ioctl> write %x %x", 
			data->reg_num, 
			data->val_in);
        if (at_write_phy_reg(&adapter->hw, data->reg_num, data->val_in)) {
            spin_unlock_irqrestore(&adapter->stats_lock, flags);
            return -EIO;
        }
        // ......
        spin_unlock_irqrestore(&adapter->stats_lock, flags);
        break;
        
    default:
        return -EOPNOTSUPP;
    }
    return AT_SUCCESS;
}

#endif

/**
 * at_tx_timeout - Respond to a Tx Hang
 * @netdev: network interface device structure
 **/

static void
at_tx_timeout(struct net_device *netdev)
{
    struct at_adapter *adapter = netdev_priv(netdev);

    DEBUGFUNC("at_tx_timeout !");

    /* Do the reset outside of interrupt context */
    schedule_work(&adapter->tx_timeout_task);
}

/*
 * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
 * will assert. We do soft reset <0x1400=1> according 
 * with the SPEC. BUT, it seemes that PCIE or DMA 
 * state-machine will not be reset. DMAR_TO_INT will
 * assert again and again.
 */
static void
at_tx_timeout_task(struct net_device *netdev)
{
    struct at_adapter *adapter = netdev_priv(netdev);
    //struct at_hw* hw = &adapter->hw;
    
    //uint32_t val1, val2;
    
    DEBUGFUNC("at_tx_timeout_task !");

    
    netif_device_detach(netdev);
    
    /*******   disp debug info **********
    val1 = AT_READ_REG(hw, 0x15f0);
    DEBUGOUT1("<15f0> = 0x%x", val1);
    val1 = AT_READ_REG(hw, 0x1540);
    val2 = AT_READ_REG(hw, 0x1544);
    DEBUGOUT1("<1540> = 0x%x <1544> = 0x%x", val1, val2);
    val1 = AT_READ_REG(hw, 0x1548);
    val2 = AT_READ_REG(hw, 0x154c);
    DEBUGOUT1("<1548> = 0x%x <154c> = 0x%x", val1, val2);
    val1 = AT_READ_REG(hw, 0x1550);
    val2 = AT_READ_REG(hw, 0x1554);
    DEBUGOUT1("<1550> = 0x%x <1554> = 0x%x", val1, val2);
    val1 = AT_READ_REG(hw, 0x1558);
    val2 = AT_READ_REG(hw, 0x155c);
    DEBUGOUT1("<1558> = 0x%x <155c> = 0x%x", val1, val2);
    
    DEBUGOUT1("tpd next to clean %d, tpd next to use %d",
		(uint16_t) atomic_read(&adapter->tpd_ring.next_to_clean),
                (uint16_t) atomic_read(&adapter->tpd_ring.next_to_use));

    DEBUGOUT1("rfd ring: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x",
               *((uint32_t*)(adapter->rfd_ring.desc) + 0),
               *((uint32_t*)(adapter->rfd_ring.desc) + 1),
               *((uint32_t*)(adapter->rfd_ring.desc) + 2),
               *((uint32_t*)(adapter->rfd_ring.desc) + 3),
               *((uint32_t*)(adapter->rfd_ring.desc) + 4),
               *((uint32_t*)(adapter->rfd_ring.desc) + 5));

    DEBUGOUT1("rfd ring: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x",
               *((uint32_t*)(adapter->rfd_ring.desc) + 6),
               *((uint32_t*)(adapter->rfd_ring.desc) + 7),
               *((uint32_t*)(adapter->rfd_ring.desc) + 8),
               *((uint32_t*)(adapter->rfd_ring.desc) + 9),
               *((uint32_t*)(adapter->rfd_ring.desc) + 10),
               *((uint32_t*)(adapter->rfd_ring.desc) + 11));
    
    DEBUGOUT1("rfd ring: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x",
               *((uint32_t*)(adapter->rfd_ring.desc) + 12),
               *((uint32_t*)(adapter->rfd_ring.desc) + 13),
               *((uint32_t*)(adapter->rfd_ring.desc) + 14),
               *((uint32_t*)(adapter->rfd_ring.desc) + 15),
               *((uint32_t*)(adapter->rfd_ring.desc) + 16),
               *((uint32_t*)(adapter->rfd_ring.desc) + 17));
    
    DEBUGOUT1("rfd ring: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x",
               *((uint32_t*)(adapter->rfd_ring.desc) + 18),
               *((uint32_t*)(adapter->rfd_ring.desc) + 19),
               *((uint32_t*)(adapter->rfd_ring.desc) + 20),
               *((uint32_t*)(adapter->rfd_ring.desc) + 21),
               *((uint32_t*)(adapter->rfd_ring.desc) + 22),
               *((uint32_t*)(adapter->rfd_ring.desc) + 23));
    */
    at_down(adapter);
    at_up(adapter);
    netif_device_attach(netdev);
}
/**
 * at_link_chg_task - deal with link change event Out of interrupt context
 * @netdev: network interface device structure
 **/
static void
at_link_chg_task(struct net_device* netdev)
{
    struct at_adapter * adapter = netdev_priv(netdev);
    unsigned long flags;
    DEBUGFUNC("at_link_chg_task !");
    
    spin_lock_irqsave(&adapter->stats_lock, flags);
    
    at_check_link(adapter);
    
    spin_unlock_irqrestore(&adapter->stats_lock, flags);
}

static void
at_check_for_link(struct at_adapter* adapter)
{
    struct net_device *netdev = adapter->netdev;
    uint16_t phy_data = 0;

    DEBUGFUNC("at_check_for_link!");
    
    spin_lock(&adapter->stats_lock);
    adapter->phy_timer_pending = FALSE;
    at_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
    at_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
    spin_unlock(&adapter->stats_lock);
    
    DEBUGOUT1("MII_BMSR=%x <at_check_for_link>", phy_data);
    
    // notify upper layer link down ASAP
    if (!(phy_data&BMSR_LSTATUS)) { // Link Down
        if (netif_carrier_ok(netdev)) { // old link state: Up
            printk(KERN_INFO
                   "%s: %s NIC Link is Down\n",
		   			at_driver_name,
                    netdev->name );
            adapter->link_speed = SPEED_0;
            netif_carrier_off(netdev);
            netif_stop_queue(netdev);
        }
    }
    schedule_work(&adapter->link_chg_task);
}
static inline void
at_clear_phy_int(struct at_adapter* adapter)
{
	uint16_t phy_data;
	
        spin_lock(&adapter->stats_lock);
	at_read_phy_reg(&adapter->hw, 19, &phy_data);
	spin_unlock(&adapter->stats_lock);
}

/**
 * at_intr - Interrupt Handler
 * @irq: interrupt number
 * @data: pointer to a network interface device structure
 * @pt_regs: CPU registers structure
 **/

static irqreturn_t
at_intr(int irq, void *data, struct pt_regs *regs)
{
    struct at_adapter *adapter = ((struct net_device*)data)->priv;
    uint32_t status;
    uint8_t update_rx;
    int max_ints = 10;
    
    if (0 == (status = adapter->cmb.cmb->int_stats))
        return IRQ_NONE;
        
    update_rx = 0;
    
    do {
        // clear CMB interrupt status at once
        adapter->cmb.cmb->int_stats = 0;
	
	if (status & ISR_GPHY) { // clear phy status
               at_clear_phy_int(adapter);
	}	       
        // clear ISR status, and Enable CMB DMA/Disable Interrupt
        AT_WRITE_REG(&adapter->hw, REG_ISR, status|ISR_DIS_INT);

        // check if SMB intr
        if (status & ISR_SMB)
        {
            at_inc_smb(adapter);
        }

        // check if PCIE PHY Link down
        if (status&ISR_PHY_LINKDOWN)
        {
            DEBUGOUT1("pcie phy linkdown %x", status);
            if(netif_running(adapter->netdev)) { // reset MAC
                AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
                schedule_work(&adapter->pcie_dma_to_rst_task);
                return IRQ_HANDLED; 
            }
        }

        // check if DMA read/write error ?
        if (status&(ISR_DMAR_TO_RST|ISR_DMAW_TO_RST)) 
        {
            DEBUGOUT1("PCIE DMA RW error (status = 0x%x) !", status);
            //AT_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
            AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
            schedule_work(&adapter->pcie_dma_to_rst_task);
            return IRQ_HANDLED; 
        }
 
        
        // link event
        if (status&ISR_GPHY)
        {
            adapter->soft_stats.tx_carrier_errors++;
            at_check_for_link(adapter);
        }

        // transmit event
        if (status&ISR_CMB_TX) {
            at_intr_tx(adapter);
        }
        
        // rx exception
        if (    status&(ISR_RXF_OV|
                        ISR_RFD_UNRUN|
                        ISR_RRD_OV|
                        ISR_HOST_RFD_UNRUN|
                        ISR_HOST_RRD_OV|
                        ISR_CMB_RX))    {
            if (status&(ISR_RXF_OV|
                        ISR_RFD_UNRUN|
                        ISR_RRD_OV|
                        ISR_HOST_RFD_UNRUN|
                        ISR_HOST_RRD_OV)) {
                DEBUGOUT1(KERN_INFO 
                          "Receive Exception ! status = 0x%x", status);
            }
            at_intr_rx(adapter);
        }


        if (--max_ints < 0)
            break;
        
    } while ((status = adapter->cmb.cmb->int_stats));
    
    // re-enable Interrupt
    AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_SMB|ISR_DIS_DMA);
    return IRQ_HANDLED;
}

static void
at_intr_tx(struct at_adapter* adapter)
{
    struct at_tpd_ring *tpd_ring = &adapter->tpd_ring; 
    struct at_buffer* buffer_info;
    uint16_t sw_tpd_next_to_clean;
    uint16_t cmb_tpd_next_to_clean;
    uint8_t update = 0;


    sw_tpd_next_to_clean = (uint16_t)atomic_read(&tpd_ring->next_to_clean);
    cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);

    while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
        tx_packet_desc_t* tpd;
        
        update = 1;
        
        tpd = AT_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
        buffer_info = &tpd_ring->buffer_info[sw_tpd_next_

⌨️ 快捷键说明

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