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

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
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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 {
+28 −7
Original line number Diff line number Diff line
@@ -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,
+8 −0
Original line number Diff line number Diff line
@@ -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 */
+36 −19
Original line number Diff line number Diff line
@@ -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 (hw->nic_type != athr_mt) {
		if (netdev->mtu > MAX_TSO_FRAME_SIZE)
			features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
	}

	return features;
}
@@ -517,6 +518,9 @@ static void atl1c_set_max_mtu(struct net_device *netdev)
		netdev->max_mtu = MAX_JUMBO_FRAME_SIZE -
			(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
		break;
	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;
@@ -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;