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