📄 atl1_main.c
字号:
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; /* 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; */ iowrite32(value, hw->hw_addr + REG_MAC_CTRL);}/* * atl1_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 atl1_set_mac(struct net_device *netdev, void *p){ struct atl1_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; 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); atl1_set_mac_addr(&adapter->hw); return 0;}static u32 atl1_check_link(struct atl1_adapter *adapter){ struct atl1_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; u32 ret_val; u16 speed, duplex, phy_data; int reconfig = 0; /* MII_BMSR must read twice */ atl1_read_phy_reg(hw, MII_BMSR, &phy_data); atl1_read_phy_reg(hw, MII_BMSR, &phy_data); if (!(phy_data & BMSR_LSTATUS)) { /* link down */ if (netif_carrier_ok(netdev)) { /* old link state: Up */ dev_info(&adapter->pdev->dev, "link is down\n"); adapter->link_speed = SPEED_0; netif_carrier_off(netdev); netif_stop_queue(netdev); } return ATL1_SUCCESS; } /* Link Up */ ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex); if (ret_val) return ret_val; switch (hw->media_type) { 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 (!reconfig) { if (adapter->link_speed != speed || adapter->link_duplex != duplex) { adapter->link_speed = speed; adapter->link_duplex = duplex; atl1_setup_mac_ctrl(adapter); dev_info(&adapter->pdev->dev, "%s link is up %d Mbps %s\n", 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 ATL1_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->media_type != MEDIA_TYPE_AUTO_SENSOR && hw->media_type != MEDIA_TYPE_1000M_FULL) { switch (hw->media_type) { 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; } atl1_write_phy_reg(hw, MII_BMCR, phy_data); return ATL1_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 ATL1_SUCCESS;}static void atl1_check_for_link(struct atl1_adapter *adapter){ struct net_device *netdev = adapter->netdev; u16 phy_data = 0; spin_lock(&adapter->lock); adapter->phy_timer_pending = false; atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); spin_unlock(&adapter->lock); /* notify upper layer link down ASAP */ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ if (netif_carrier_ok(netdev)) { /* old link state: Up */ dev_info(&adapter->pdev->dev, "%s link is down\n", netdev->name); adapter->link_speed = SPEED_0; netif_carrier_off(netdev); netif_stop_queue(netdev); } } schedule_work(&adapter->link_chg_task);}/* * atl1_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 atl1_set_multi(struct net_device *netdev){ struct atl1_adapter *adapter = netdev_priv(netdev); struct atl1_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; u32 rctl; u32 hash_value; /* Check for Promiscuous and All Multicast modes */ rctl = ioread32(hw->hw_addr + 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); iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL); /* clear the old settings from the multicast hash table */ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); /* compute 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 = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr); atl1_hash_set(hw, hash_value); }}/* * atl1_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 atl1_change_mtu(struct net_device *netdev, int new_mtu){ struct atl1_adapter *adapter = netdev_priv(netdev); int old_mtu = netdev->mtu; int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { dev_warn(&adapter->pdev->dev, "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)) { atl1_down(adapter); atl1_up(adapter); } return 0;}static void set_flow_ctrl_old(struct atl1_adapter *adapter){ u32 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); iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH); /* 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); iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH);}static void set_flow_ctrl_new(struct atl1_hw *hw){ u32 hi, lo, value; /* RXF Flow Control */ value = ioread32(hw->hw_addr + 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); iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH); /* RRD Flow Control */ value = ioread32(hw->hw_addr + 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); iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH);}/* * atl1_configure - Configure Transmit&Receive Unit after Reset * @adapter: board private structure * * Configure the Tx /Rx unit of the MAC after a reset. */static u32 atl1_configure(struct atl1_adapter *adapter){ struct atl1_hw *hw = &adapter->hw; u32 value; /* clear interrupt status */ iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR); /* 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])); iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4)); /* tx / rx ring */ /* HI base address */ iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32), hw->hw_addr + REG_DESC_BASE_ADDR_HI); /* LO base address */ iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL), hw->hw_addr + REG_DESC_RFD_ADDR_LO); iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL), hw->hw_addr + REG_DESC_RRD_ADDR_LO); iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL), hw->hw_addr + REG_DESC_TPD_ADDR_LO); iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL), hw->hw_addr + REG_DESC_CMB_ADDR_LO); iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL), hw->hw_addr + REG_DESC_SMB_ADDR_LO); /* element count */ value = adapter->rrd_ring.count; value <<= 16; value += adapter->rfd_ring.count; iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE); iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE); /* Load Ptr */ iowrite32(1, hw->hw_addr + REG_LOAD_PTR); /* config Mailbox */ value = ((atomic_read(&adapter->tpd_ring.next_to_use) & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) | ((atomic_read(&adapter->rrd_ring.next_to_clean) & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) | ((atomic_read(&adapter->rfd_ring.next_to_use) & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT); iowrite32(value, hw->hw_addr + REG_MAILBOX); /* config IPG/IFG */ value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK) << MAC_IPG_IFG_IPGT_SHIFT) | (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) << MAC_IPG_IFG_MIFG_SHIFT) | (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) << MAC_IPG_IFG_IPGR1_SHIFT) | (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) << MAC_IPG_IFG_IPGR2_SHIFT); iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG); /* config Half-Duplex Control */ value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | (((u32) 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) | (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL); /* set Interrupt Moderator Timer */ iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT); iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL); /* set Interrupt Clear Timer */ iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER); /* set max frame size hw will accept */ iowrite32(hw->max_frame_size, hw->hw_addr + REG_MTU); /* jumbo size & rrd retirement timer */ value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) << RXQ_JMBOSZ_TH_SHIFT) | (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK) << RXQ_JMBO_LKAH_SHIFT) | (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK) << RXQ_RRD_TIMER_SHIFT); iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM); /* 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 = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK) << TXQ_CTRL_TPD_BURST_NUM_SHIFT) | (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK) << TXQ_CTRL_TXF_BURST_NUM_SHIFT) | (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK) << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN; iowrite32(value, hw->hw_addr + REG_TXQ_CTRL); /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */ value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK) << TX_JUMBO_TASK_TH_SHIFT) | (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK) << TX_TPD_MIN_IPG_SHIFT); iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG); /* config RXQ */ value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK) << RXQ_CTRL_RFD_BURST_NUM_SHIFT) | (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK) << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) | (((u32) 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; iowrite32(value, hw->hw_addr + REG_RXQ_CTRL); /* 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_EN | DMA_CTRL_DMAW_EN; value |= (u32) hw->dma_ord;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -