📄 at_main.c
字号:
*
* 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 + -