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