Commit 33b31426 authored by David S. Miller's avatar David S. Miller

Merge branch 'atl1c-support-for-Mikrotik-10-25G-NIC-features'

Gatis Peisenieks says:

====================
atl1c: support for Mikrotik 10/25G NIC features

The new Mikrotik 10/25G NIC maintains compatibility with existing atl1c
driver. However it does have new features.

This patch set adds support for reporting cards higher link speed, max-mtu,
enables rx csum offload and improves tx performance.

v2:
    - fixed xmit_more handling as pointed out by Eric Dumazet
    - added a more reliable link detection on Mikrotik 10/25G NIC
      since MDIO op emulation can occasionally fail
Guangbin Huang says:
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0d59c95e ea0fbd05
......@@ -241,6 +241,8 @@ struct atl1c_tpd_ext_desc {
#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
#define RRS_MT_PROT_ID_TCPUDP BIT(19)
struct atl1c_recv_ret_status {
__le32 word0;
__le32 rss_hash;
......@@ -289,6 +291,7 @@ enum atl1c_nic_type {
athr_l2c_b2,
athr_l1d,
athr_l1d_2,
athr_mt,
};
enum atl1c_trans_queue {
......
......@@ -636,6 +636,23 @@ int atl1c_phy_init(struct atl1c_hw *hw)
return 0;
}
bool atl1c_get_link_status(struct atl1c_hw *hw)
{
u16 phy_data;
if (hw->nic_type == athr_mt) {
u32 spd;
AT_READ_REG(hw, REG_MT_SPEED, &spd);
return !!spd;
}
/* MII_BMSR must be read twice */
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
return !!(phy_data & BMSR_LSTATUS);
}
/*
* Detects the current speed and duplex settings of the hardware.
*
......@@ -648,6 +665,15 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
int err;
u16 phy_data;
if (hw->nic_type == athr_mt) {
u32 spd;
AT_READ_REG(hw, REG_MT_SPEED, &spd);
*speed = spd;
*duplex = FULL_DUPLEX;
return 0;
}
/* Read PHY Specific Status Register (17) */
err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
if (err)
......@@ -686,15 +712,12 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
int ret = 0;
u16 autoneg_advertised = ADVERTISED_10baseT_Half;
u16 save_autoneg_advertised;
u16 phy_data;
u16 mii_lpa_data;
u16 speed = SPEED_0;
u16 duplex = FULL_DUPLEX;
int i;
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
if (phy_data & BMSR_LSTATUS) {
if (atl1c_get_link_status(hw)) {
atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
if (mii_lpa_data & LPA_10FULL)
autoneg_advertised = ADVERTISED_10baseT_Full;
......@@ -717,9 +740,7 @@ int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
if (mii_lpa_data) {
for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
mdelay(100);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
if (phy_data & BMSR_LSTATUS) {
if (atl1c_get_link_status(hw)) {
if (atl1c_get_speed_and_duplex(hw, &speed,
&duplex) != 0)
dev_dbg(&pdev->dev,
......
......@@ -26,6 +26,7 @@ void atl1c_phy_disable(struct atl1c_hw *hw);
void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr);
int atl1c_phy_reset(struct atl1c_hw *hw);
int atl1c_read_mac_addr(struct atl1c_hw *hw);
bool atl1c_get_link_status(struct atl1c_hw *hw);
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
......@@ -764,6 +765,13 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define REG_DEBUG_DATA0 0x1900
#define REG_DEBUG_DATA1 0x1904
#define REG_MT_MAGIC 0x1F00
#define REG_MT_MODE 0x1F04
#define REG_MT_SPEED 0x1F08
#define REG_MT_VERSION 0x1F0C
#define MT_MAGIC 0xaabb1234
#define L1D_MPW_PHYID1 0xD01C /* V7 */
#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */
#define L1D_MPW_PHYID3 0xD01E /* V8 */
......
......@@ -232,15 +232,14 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
int err;
unsigned long flags;
u16 speed, duplex, phy_data;
u16 speed, duplex;
bool link;
spin_lock_irqsave(&adapter->mdio_lock, flags);
/* MII_BMSR must read twise */
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
link = atl1c_get_link_status(hw);
spin_unlock_irqrestore(&adapter->mdio_lock, flags);
if ((phy_data & BMSR_LSTATUS) == 0) {
if (!link) {
/* link down */
netif_carrier_off(netdev);
hw->hibernate = true;
......@@ -284,16 +283,13 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
u16 phy_data;
u16 link_up;
bool link;
spin_lock(&adapter->mdio_lock);
atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
link = atl1c_get_link_status(&adapter->hw);
spin_unlock(&adapter->mdio_lock);
link_up = phy_data & BMSR_LSTATUS;
/* notify upper layer link down ASAP */
if (!link_up) {
if (!link) {
if (netif_carrier_ok(netdev)) {
/* old link state: Up */
netif_carrier_off(netdev);
......@@ -478,6 +474,9 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
static netdev_features_t atl1c_fix_features(struct net_device *netdev,
netdev_features_t features)
{
struct atl1c_adapter *adapter = netdev_priv(netdev);
struct atl1c_hw *hw = &adapter->hw;
/*
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
......@@ -487,8 +486,10 @@ static netdev_features_t atl1c_fix_features(struct net_device *netdev,
else
features &= ~NETIF_F_HW_VLAN_CTAG_TX;
if (netdev->mtu > MAX_TSO_FRAME_SIZE)
features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
if (hw->nic_type != athr_mt) {
if (netdev->mtu > MAX_TSO_FRAME_SIZE)
features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
}
return features;
}
......@@ -515,9 +516,12 @@ static void atl1c_set_max_mtu(struct net_device *netdev)
case athr_l1d:
case athr_l1d_2:
netdev->max_mtu = MAX_JUMBO_FRAME_SIZE -
(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
break;
/* The 10/100 devices don't support jumbo packets, max_mtu 1500 */
case athr_mt:
netdev->max_mtu = 9500;
break;
/* The 10/100 devices don't support jumbo packets, max_mtu 1500 */
default:
netdev->max_mtu = ETH_DATA_LEN;
break;
......@@ -644,6 +648,7 @@ static int atl1c_alloc_queues(struct atl1c_adapter *adapter)
static void atl1c_set_mac_type(struct atl1c_hw *hw)
{
u32 magic;
switch (hw->device_id) {
case PCI_DEVICE_ID_ATTANSIC_L2C:
hw->nic_type = athr_l2c;
......@@ -662,6 +667,9 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
break;
case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
hw->nic_type = athr_l1d_2;
AT_READ_REG(hw, REG_MT_MAGIC, &magic);
if (magic == MT_MAGIC)
hw->nic_type = athr_mt;
break;
default:
break;
......@@ -1659,6 +1667,11 @@ static irqreturn_t atl1c_intr(int irq, void *data)
static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
struct sk_buff *skb, struct atl1c_recv_ret_status *prrs)
{
if (adapter->hw.nic_type == athr_mt) {
if (prrs->word3 & RRS_MT_PROT_ID_TCPUDP)
skb->ip_summed = CHECKSUM_UNNECESSARY;
return;
}
/*
* The pid field in RRS in not correct sometimes, so we
* cannot figure out if the packet is fragmented or not,
......@@ -2207,8 +2220,8 @@ static int atl1c_tx_map(struct atl1c_adapter *adapter,
return -1;
}
static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type)
static void atl1c_tx_queue(struct atl1c_adapter *adapter,
enum atl1c_trans_queue type)
{
struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
u16 reg;
......@@ -2234,6 +2247,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
if (atl1c_tpd_avail(adapter, type) < tpd_req) {
/* no enough descriptor, just stop queue */
atl1c_tx_queue(adapter, type);
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
}
......@@ -2242,6 +2256,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
/* do TSO and check sum */
if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) {
atl1c_tx_queue(adapter, type);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
......@@ -2266,8 +2281,10 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
atl1c_tx_rollback(adapter, tpd, type);
dev_kfree_skb_any(skb);
} else {
netdev_sent_queue(adapter->netdev, skb->len);
atl1c_tx_queue(adapter, skb, tpd, type);
bool more = netdev_xmit_more();
if (__netdev_sent_queue(adapter->netdev, skb->len, more))
atl1c_tx_queue(adapter, type);
}
return NETDEV_TX_OK;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment