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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
33b3142656
@ -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 @@ err_dma:
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user