ath9k_hw: move the cck channel 14 INI to the AR9002 hw code
[safe/jmp/linux-2.6] / drivers / net / atl1c / atl1c_main.c
index deb7b53..50dc531 100644 (file)
 
 #include "atl1c.h"
 
-#define ATL1C_DRV_VERSION "1.0.0.1-NAPI"
+#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
 char atl1c_driver_name[] = "atl1c";
 char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 #define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
 #define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063
+#define PCI_DEVICE_ID_ATHEROS_L2C_B    0x2060 /* AR8152 v1.1 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L2C_B2   0x2062 /* AR8152 v2.0 Fast 10/100 */
+#define PCI_DEVICE_ID_ATHEROS_L1D      0x1073 /* AR8151 v1.0 Gigabit 1000 */
+
+#define L2CB_V10                       0xc0
+#define L2CB_V11                       0xc1
+
 /*
  * atl1c_pci_tbl - PCI Device ID Table
  *
@@ -35,9 +42,12 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
  *   Class, Class Mask, private data (not used) }
  */
-static struct pci_device_id atl1c_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
        /* required last entry */
        { 0 }
 };
@@ -164,6 +174,24 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter)
 }
 
 /*
+ * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads
+ * of the idle status register until the device is actually idle
+ */
+static u32 atl1c_wait_until_idle(struct atl1c_hw *hw)
+{
+       int timeout;
+       u32 data;
+
+       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
+               if ((data & IDLE_STATUS_MASK) == 0)
+                       return 0;
+               msleep(1);
+       }
+       return data;
+}
+
+/*
  * atl1c_phy_config - Timer Call-back
  * @data: pointer to netdev cast into an unsigned long
  */
@@ -180,27 +208,12 @@ static void atl1c_phy_config(unsigned long data)
 
 void atl1c_reinit_locked(struct atl1c_adapter *adapter)
 {
-
        WARN_ON(in_interrupt());
        atl1c_down(adapter);
        atl1c_up(adapter);
        clear_bit(__AT_RESETTING, &adapter->flags);
 }
 
-static void atl1c_reset_task(struct work_struct *work)
-{
-       struct atl1c_adapter *adapter;
-       struct net_device *netdev;
-
-       adapter = container_of(work, struct atl1c_adapter, reset_task);
-       netdev = adapter->netdev;
-
-       netif_device_detach(netdev);
-       atl1c_down(adapter);
-       atl1c_up(adapter);
-       netif_device_attach(netdev);
-}
-
 static void atl1c_check_link_status(struct atl1c_adapter *adapter)
 {
        struct atl1c_hw *hw = &adapter->hw;
@@ -220,11 +233,11 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
                /* link down */
                if (netif_carrier_ok(netdev)) {
                        hw->hibernate = true;
-                       atl1c_set_aspm(hw, false);
                        if (atl1c_stop_mac(hw) != 0)
                                if (netif_msg_hw(adapter))
                                        dev_warn(&pdev->dev,
                                                "stop mac failed\n");
+                       atl1c_set_aspm(hw, false);
                }
                netif_carrier_off(netdev);
        } else {
@@ -240,10 +253,10 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
                    adapter->link_duplex != duplex) {
                        adapter->link_speed  = speed;
                        adapter->link_duplex = duplex;
+                       atl1c_set_aspm(hw, true);
                        atl1c_enable_tx_ctrl(hw);
                        atl1c_enable_rx_ctrl(hw);
                        atl1c_setup_mac_ctrl(adapter);
-                       atl1c_set_aspm(hw, true);
                        if (netif_msg_link(adapter))
                                dev_info(&pdev->dev,
                                        "%s: %s NIC Link is Up<%d Mbps %s>\n",
@@ -257,18 +270,6 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
        }
 }
 
-/*
- * atl1c_link_chg_task - deal with link change event Out of interrupt context
- * @netdev: network interface device structure
- */
-static void atl1c_link_chg_task(struct work_struct *work)
-{
-       struct atl1c_adapter *adapter;
-
-       adapter = container_of(work, struct atl1c_adapter, link_chg_task);
-       atl1c_check_link_status(adapter);
-}
-
 static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -293,20 +294,40 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
                        adapter->link_speed = SPEED_0;
                }
        }
-       schedule_work(&adapter->link_chg_task);
+
+       adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE;
+       schedule_work(&adapter->common_task);
 }
 
-static void atl1c_del_timer(struct atl1c_adapter *adapter)
+static void atl1c_common_task(struct work_struct *work)
 {
-       del_timer_sync(&adapter->phy_config_timer);
+       struct atl1c_adapter *adapter;
+       struct net_device *netdev;
+
+       adapter = container_of(work, struct atl1c_adapter, common_task);
+       netdev = adapter->netdev;
+
+       if (adapter->work_event & ATL1C_WORK_EVENT_RESET) {
+               netif_device_detach(netdev);
+               atl1c_down(adapter);
+               atl1c_up(adapter);
+               netif_device_attach(netdev);
+               return;
+       }
+
+       if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE)
+               atl1c_check_link_status(adapter);
+
+       return;
 }
 
-static void atl1c_cancel_work(struct atl1c_adapter *adapter)
+
+static void atl1c_del_timer(struct atl1c_adapter *adapter)
 {
-       cancel_work_sync(&adapter->reset_task);
-       cancel_work_sync(&adapter->link_chg_task);
+       del_timer_sync(&adapter->phy_config_timer);
 }
 
+
 /*
  * atl1c_tx_timeout - Respond to a Tx Hang
  * @netdev: network interface device structure
@@ -316,7 +337,8 @@ static void atl1c_tx_timeout(struct net_device *netdev)
        struct atl1c_adapter *adapter = netdev_priv(netdev);
 
        /* Do the reset outside of interrupt context */
-       schedule_work(&adapter->reset_task);
+       adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+       schedule_work(&adapter->common_task);
 }
 
 /*
@@ -355,7 +377,7 @@ static void atl1c_set_multi(struct net_device *netdev)
        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) {
+       netdev_for_each_mc_addr(mc_ptr, netdev) {
                hash_value = atl1c_hash_mc_addr(hw, mc_ptr->dmi_addr);
                atl1c_hash_set(hw, hash_value);
        }
@@ -516,10 +538,6 @@ static int atl1c_mii_ioctl(struct net_device *netdev,
                break;
 
        case SIOCGMIIREG:
-               if (!capable(CAP_NET_ADMIN)) {
-                       retval = -EPERM;
-                       goto out;
-               }
                if (atl1c_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
                                    &data->val_out)) {
                        retval = -EIO;
@@ -528,10 +546,6 @@ static int atl1c_mii_ioctl(struct net_device *netdev,
                break;
 
        case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN)) {
-                       retval = -EPERM;
-                       goto out;
-               }
                if (data->reg_num & ~(0x1F)) {
                        retval = -EFAULT;
                        goto out;
@@ -589,11 +603,18 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
        case PCI_DEVICE_ID_ATTANSIC_L2C:
                hw->nic_type = athr_l2c;
                break;
-
        case PCI_DEVICE_ID_ATTANSIC_L1C:
                hw->nic_type = athr_l1c;
                break;
-
+       case PCI_DEVICE_ID_ATHEROS_L2C_B:
+               hw->nic_type = athr_l2c_b;
+               break;
+       case PCI_DEVICE_ID_ATHEROS_L2C_B2:
+               hw->nic_type = athr_l2c_b2;
+               break;
+       case PCI_DEVICE_ID_ATHEROS_L1D:
+               hw->nic_type = athr_l1d;
+               break;
        default:
                break;
        }
@@ -616,10 +637,13 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
                hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
        if (link_ctrl_data & LINK_CTRL_L1_EN)
                hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
+       if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
+               hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
 
-       if (hw->nic_type == athr_l1c) {
+       if (hw->nic_type == athr_l1c ||
+           hw->nic_type == athr_l1d) {
                hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
-               hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
+               hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
        }
        return 0;
 }
@@ -700,6 +724,35 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
        return 0;
 }
 
+static inline void atl1c_clean_buffer(struct pci_dev *pdev,
+                               struct atl1c_buffer *buffer_info, int in_irq)
+{
+       u16 pci_driection;
+       if (buffer_info->flags & ATL1C_BUFFER_FREE)
+               return;
+       if (buffer_info->dma) {
+               if (buffer_info->flags & ATL1C_PCIMAP_FROMDEVICE)
+                       pci_driection = PCI_DMA_FROMDEVICE;
+               else
+                       pci_driection = PCI_DMA_TODEVICE;
+
+               if (buffer_info->flags & ATL1C_PCIMAP_SINGLE)
+                       pci_unmap_single(pdev, buffer_info->dma,
+                                       buffer_info->length, pci_driection);
+               else if (buffer_info->flags & ATL1C_PCIMAP_PAGE)
+                       pci_unmap_page(pdev, buffer_info->dma,
+                                       buffer_info->length, pci_driection);
+       }
+       if (buffer_info->skb) {
+               if (in_irq)
+                       dev_kfree_skb_irq(buffer_info->skb);
+               else
+                       dev_kfree_skb(buffer_info->skb);
+       }
+       buffer_info->dma = 0;
+       buffer_info->skb = NULL;
+       ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
+}
 /*
  * atl1c_clean_tx_ring - Free Tx-skb
  * @adapter: board private structure
@@ -715,22 +768,12 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
        ring_count = tpd_ring->count;
        for (index = 0; index < ring_count; index++) {
                buffer_info = &tpd_ring->buffer_info[index];
-               if (buffer_info->state == ATL1_BUFFER_FREE)
-                       continue;
-               if (buffer_info->dma)
-                       pci_unmap_single(pdev, buffer_info->dma,
-                                       buffer_info->length,
-                                       PCI_DMA_TODEVICE);
-               if (buffer_info->skb)
-                       dev_kfree_skb(buffer_info->skb);
-               buffer_info->dma = 0;
-               buffer_info->skb = NULL;
-               buffer_info->state = ATL1_BUFFER_FREE;
+               atl1c_clean_buffer(pdev, buffer_info, 0);
        }
 
        /* Zero out Tx-buffers */
        memset(tpd_ring->desc, 0, sizeof(struct atl1c_tpd_desc) *
-                               ring_count);
+               ring_count);
        atomic_set(&tpd_ring->next_to_clean, 0);
        tpd_ring->next_to_use = 0;
 }
@@ -750,16 +793,7 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter)
        for (i = 0; i < adapter->num_rx_queues; i++) {
                for (j = 0; j < rfd_ring[i].count; j++) {
                        buffer_info = &rfd_ring[i].buffer_info[j];
-                       if (buffer_info->state == ATL1_BUFFER_FREE)
-                               continue;
-                       if (buffer_info->dma)
-                               pci_unmap_single(pdev, buffer_info->dma,
-                                               buffer_info->length,
-                                               PCI_DMA_FROMDEVICE);
-                       if (buffer_info->skb)
-                               dev_kfree_skb(buffer_info->skb);
-                       buffer_info->state = ATL1_BUFFER_FREE;
-                       buffer_info->skb = NULL;
+                       atl1c_clean_buffer(pdev, buffer_info, 0);
                }
                /* zero out the descriptor ring */
                memset(rfd_ring[i].desc, 0, rfd_ring[i].size);
@@ -786,7 +820,8 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter)
                atomic_set(&tpd_ring[i].next_to_clean, 0);
                buffer_info = tpd_ring[i].buffer_info;
                for (j = 0; j < tpd_ring->count; j++)
-                       buffer_info[i].state = ATL1_BUFFER_FREE;
+                       ATL1C_SET_BUFFER_STATE(&buffer_info[i],
+                                       ATL1C_BUFFER_FREE);
        }
        for (i = 0; i < adapter->num_rx_queues; i++) {
                rfd_ring[i].next_to_use = 0;
@@ -795,7 +830,7 @@ static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter)
                rrd_ring[i].next_to_clean = 0;
                for (j = 0; j < rfd_ring[i].count; j++) {
                        buffer_info = &rfd_ring[i].buffer_info[j];
-                       buffer_info->state = ATL1_BUFFER_FREE;
+                       ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
                }
        }
 }
@@ -1106,7 +1141,6 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter)
 static int atl1c_stop_mac(struct atl1c_hw *hw)
 {
        u32 data;
-       int timeout;
 
        AT_READ_REG(hw, REG_RXQ_CTRL, &data);
        data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN |
@@ -1117,25 +1151,13 @@ static int atl1c_stop_mac(struct atl1c_hw *hw)
        data &= ~TXQ_CTRL_EN;
        AT_WRITE_REG(hw, REG_TWSI_CTRL, data);
 
-       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
-               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
-               if ((data & (IDLE_STATUS_RXQ_NO_IDLE |
-                       IDLE_STATUS_TXQ_NO_IDLE)) == 0)
-                       break;
-               msleep(1);
-       }
+       atl1c_wait_until_idle(hw);
 
        AT_READ_REG(hw, REG_MAC_CTRL, &data);
        data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN);
        AT_WRITE_REG(hw, REG_MAC_CTRL, data);
 
-       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
-               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
-               if ((data & IDLE_STATUS_MASK) == 0)
-                       return 0;
-               msleep(1);
-       }
-       return data;
+       return (int)atl1c_wait_until_idle(hw);
 }
 
 static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw)
@@ -1178,8 +1200,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
 {
        struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
        struct pci_dev *pdev = adapter->pdev;
-       u32 idle_status_data = 0;
-       int timeout = 0;
        int ret;
 
        AT_WRITE_REG(hw, REG_IMR, 0);
@@ -1198,15 +1218,10 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
        AT_WRITE_FLUSH(hw);
        msleep(10);
        /* Wait at least 10ms for All module to be Idle */
-       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
-               AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data);
-               if ((idle_status_data & IDLE_STATUS_MASK) == 0)
-                       break;
-               msleep(1);
-       }
-       if (timeout >= AT_HW_MAX_IDLE_DELAY) {
+
+       if (atl1c_wait_until_idle(hw)) {
                dev_err(&pdev->dev,
-                       "MAC state machine cann't be idle since"
+                       "MAC state machine can't be idle since"
                        " disabled for 10ms second\n");
                return -1;
        }
@@ -1239,34 +1254,95 @@ static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
 static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
 {
        u32 pm_ctrl_data;
+       u32 link_ctrl_data;
 
        AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
+       AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
+       pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
 
-       pm_ctrl_data &= PM_CTRL_SERDES_PD_EX_L1;
-       pm_ctrl_data |= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
-       pm_ctrl_data |= ~PM_CTRL_SERDES_L1_EN;
        pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
                        PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+       pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
+                         PM_CTRL_LCKDET_TIMER_SHIFT);
 
        pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+       pm_ctrl_data |= PM_CTRL_RBER_EN;
+       pm_ctrl_data |= PM_CTRL_SDES_EN;
+
+       if (hw->nic_type == athr_l2c_b ||
+           hw->nic_type == athr_l1d ||
+           hw->nic_type == athr_l2c_b2) {
+               link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
+               if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
+                       if (hw->nic_type == athr_l2c_b &&
+                           hw->revision_id == L2CB_V10)
+                               link_ctrl_data |= LINK_CTRL_EXT_SYNC;
+               }
 
-       if (linkup) {
-               pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
-               pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+               AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
 
-               if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) {
-                       pm_ctrl_data |= AT_ASPM_L1_TIMER <<
-                               PM_CTRL_L1_ENTRY_TIMER_SHIFT;
-                       pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
-               } else
-                       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+               pm_ctrl_data |= PM_CTRL_PCIE_RECV;
+               pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
+               pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+               pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
+               pm_ctrl_data &= ~PM_CTRL_HOTRST;
+               pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+               pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
+       }
 
+       if (linkup) {
+               pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+               pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+               if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
+                       pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
                if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
                        pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
-               else
+
+               if (hw->nic_type == athr_l2c_b ||
+                   hw->nic_type == athr_l1d ||
+                   hw->nic_type == athr_l2c_b2) {
+                       if (hw->nic_type == athr_l2c_b)
+                               if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
+                                       pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+                       pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+                       pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+                       pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+                       pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+                       if (hw->adapter->link_speed == SPEED_100 ||
+                           hw->adapter->link_speed == SPEED_1000) {
+                               pm_ctrl_data &=
+                                       ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+                                         PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+                               if (hw->nic_type == athr_l1d)
+                                       pm_ctrl_data |= 0xF <<
+                                               PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+                               else
+                                       pm_ctrl_data |= 7 <<
+                                               PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+                       }
+               } else {
+                       pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+                       pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+                       pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
+                       pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
                        pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+                       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+               }
+               atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+               if (hw->adapter->link_speed == SPEED_10)
+                       if (hw->nic_type == athr_l1d)
+                               atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
+                       else
+                               atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+               else if (hw->adapter->link_speed == SPEED_100)
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
+               else
+                       atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
 
        } else {
+               pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+               pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
                pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
                pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
 
@@ -1317,6 +1393,10 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
                mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
 
        mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
+       if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+               mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
+               mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
+       }
        AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
 }
 
@@ -1467,6 +1547,7 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter,
        struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *)
                                &adapter->tpd_ring[type];
        struct atl1c_buffer *buffer_info;
+       struct pci_dev *pdev = adapter->pdev;
        u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
        u16 hw_next_to_clean;
        u16 shift;
@@ -1482,16 +1563,7 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter,
 
        while (next_to_clean != hw_next_to_clean) {
                buffer_info = &tpd_ring->buffer_info[next_to_clean];
-               if (buffer_info->state == ATL1_BUFFER_BUSY) {
-                       pci_unmap_page(adapter->pdev, buffer_info->dma,
-                                       buffer_info->length, PCI_DMA_TODEVICE);
-                       buffer_info->dma = 0;
-                       if (buffer_info->skb) {
-                               dev_kfree_skb_irq(buffer_info->skb);
-                               buffer_info->skb = NULL;
-                       }
-                       buffer_info->state = ATL1_BUFFER_FREE;
-               }
+               atl1c_clean_buffer(pdev, buffer_info, 1);
                if (++next_to_clean == tpd_ring->count)
                        next_to_clean = 0;
                atomic_set(&tpd_ring->next_to_clean, next_to_clean);
@@ -1556,14 +1628,15 @@ static irqreturn_t atl1c_intr(int irq, void *data)
                        /* reset MAC */
                        hw->intr_mask &= ~ISR_ERROR;
                        AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
-                       schedule_work(&adapter->reset_task);
+                       adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+                       schedule_work(&adapter->common_task);
                        break;
                }
 
                if (status & ISR_OVER)
                        if (netif_msg_intr(adapter))
                                dev_warn(&pdev->dev,
-                                       "TX/RX over flow (status = 0x%x)\n",
+                                       "TX/RX overflow (status = 0x%x)\n",
                                        status & ISR_OVER);
 
                /* link event */
@@ -1607,7 +1680,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid
        buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
        next_info = &rfd_ring->buffer_info[next_next];
 
-       while (next_info->state == ATL1_BUFFER_FREE) {
+       while (next_info->flags & ATL1C_BUFFER_FREE) {
                rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
 
                skb = dev_alloc_skb(adapter->rx_buffer_len);
@@ -1623,12 +1696,14 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid
                 * the 14 byte MAC header is removed
                 */
                vir_addr = skb->data;
-               buffer_info->state = ATL1_BUFFER_BUSY;
+               ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
                buffer_info->skb = skb;
                buffer_info->length = adapter->rx_buffer_len;
                buffer_info->dma = pci_map_single(pdev, vir_addr,
                                                buffer_info->length,
                                                PCI_DMA_FROMDEVICE);
+               ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
+                       ATL1C_PCIMAP_FROMDEVICE);
                rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
                rfd_next_to_use = next_next;
                if (++next_next == rfd_ring->count)
@@ -1673,7 +1748,8 @@ static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring,
                        RRS_RX_RFD_INDEX_MASK;
        for (i = 0; i < num; i++) {
                buffer_info[rfd_index].skb = NULL;
-               buffer_info[rfd_index].state = ATL1_BUFFER_FREE;
+               ATL1C_SET_BUFFER_STATE(&buffer_info[rfd_index],
+                                       ATL1C_BUFFER_FREE);
                if (++rfd_index == rfd_ring->count)
                        rfd_index = 0;
        }
@@ -1701,7 +1777,7 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
                if (likely(RRS_RXD_IS_VALID(rrs->word3))) {
                        rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) &
                                RRS_RX_RFD_CNT_MASK;
-                       if (unlikely(rfd_num) != 1)
+                       if (unlikely(rfd_num != 1))
                                /* TODO support mul rfd*/
                                if (netif_msg_rx_err(adapter))
                                        dev_warn(&pdev->dev,
@@ -1752,7 +1828,6 @@ rrs_checked:
                } else
                        netif_receive_skb(skb);
 
-               netdev->last_rx = jiffies;
                (*work_done)++;
                count++;
        }
@@ -1988,7 +2063,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
                buffer_info->length = map_len;
                buffer_info->dma = pci_map_single(adapter->pdev,
                                        skb->data, hdr_len, PCI_DMA_TODEVICE);
-               buffer_info->state = ATL1_BUFFER_BUSY;
+               ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
+               ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
+                       ATL1C_PCIMAP_TODEVICE);
                mapped_len += map_len;
                use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
                use_tpd->buffer_len = cpu_to_le16(buffer_info->length);
@@ -2002,16 +2079,15 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
                else {
                        use_tpd = atl1c_get_tpd(adapter, type);
                        memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
-                       use_tpd = atl1c_get_tpd(adapter, type);
-                       memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
                }
                buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
                buffer_info->length = buf_len - mapped_len;
                buffer_info->dma =
                        pci_map_single(adapter->pdev, skb->data + mapped_len,
                                        buffer_info->length, PCI_DMA_TODEVICE);
-               buffer_info->state = ATL1_BUFFER_BUSY;
-
+               ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
+               ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
+                       ATL1C_PCIMAP_TODEVICE);
                use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
                use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
        }
@@ -2031,8 +2107,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
                                        frag->page_offset,
                                        buffer_info->length,
                                        PCI_DMA_TODEVICE);
-               buffer_info->state = ATL1_BUFFER_BUSY;
-
+               ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
+               ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE,
+                       ATL1C_PCIMAP_TODEVICE);
                use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
                use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
        }
@@ -2067,7 +2144,8 @@ static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
        AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data);
 }
 
-static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
+                                         struct net_device *netdev)
 {
        struct atl1c_adapter *adapter = netdev_priv(netdev);
        unsigned long flags;
@@ -2123,7 +2201,6 @@ static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        atl1c_tx_map(adapter, skb, tpd, type);
        atl1c_tx_queue(adapter, skb, tpd, type);
 
-       netdev->trans_start = jiffies;
        spin_unlock_irqrestore(&adapter->tx_lock, flags);
        return NETDEV_TX_OK;
 }
@@ -2158,7 +2235,7 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter)
 
        if (!adapter->have_msi)
                flags |= IRQF_SHARED;
-       err = request_irq(adapter->pdev->irq, &atl1c_intr, flags,
+       err = request_irq(adapter->pdev->irq, atl1c_intr, flags,
                        netdev->name, netdev);
        if (err) {
                if (netif_msg_ifup(adapter))
@@ -2221,8 +2298,7 @@ void atl1c_down(struct atl1c_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
 
        atl1c_del_timer(adapter);
-       atl1c_cancel_work(adapter);
-
+       adapter->work_event = 0; /* clear all event */
        /* signal that we're down so the interrupt handler does not
         * reschedule our watchdog timer */
        set_bit(__AT_DOWN, &adapter->flags);
@@ -2317,7 +2393,7 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
        u32 ctrl;
        u32 mac_ctrl_data;
        u32 master_ctrl_data;
-       u32 wol_ctrl_data;
+       u32 wol_ctrl_data = 0;
        u16 mii_bmsr_data;
        u16 save_autoneg_advertised;
        u16 mii_intr_status_data;
@@ -2532,8 +2608,8 @@ static int __devinit atl1c_probe(struct pci_dev *pdev,
         * various kernel subsystems to support the mechanics required by a
         * fixed-high-32-bit system.
         */
-       if ((pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) ||
-           (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) != 0)) {
+       if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) ||
+           (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)) {
                dev_err(&pdev->dev, "No usable DMA configuration,aborting\n");
                goto err_dma;
        }
@@ -2615,15 +2691,12 @@ static int __devinit atl1c_probe(struct pci_dev *pdev,
        memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
        memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
        if (netif_msg_probe(adapter))
-               dev_dbg(&pdev->dev,
-                       "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
-                       adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
-                       adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
-                       adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+               dev_dbg(&pdev->dev, "mac address : %pM\n",
+                       adapter->hw.mac_addr);
 
        atl1c_hw_set_mac_addr(&adapter->hw);
-       INIT_WORK(&adapter->reset_task, atl1c_reset_task);
-       INIT_WORK(&adapter->link_chg_task, atl1c_link_chg_task);
+       INIT_WORK(&adapter->common_task, atl1c_common_task);
+       adapter->work_event = 0;
        err = register_netdev(netdev);
        if (err) {
                dev_err(&pdev->dev, "register netdevice failed\n");
@@ -2691,6 +2764,9 @@ static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev,
 
        netif_device_detach(netdev);
 
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
        if (netif_running(netdev))
                atl1c_down(adapter);