Following patches has been picked up from mainline:
36fa35d net: thunderx: Allow IPv6 frames with zero UDP checksum
78aacb6 net: thunderx: Fix invalid mac addresses for node1 interfaces
18de7ba net: thunderx: Fix LMAC mode debug prints for QSGMII mode
075ad76 net: thunderx: Fix PHY autoneg for SGMII QLM mode
c73e442 net: thunderx: avoid dereferencing xcv when NULL
fff37fd net: thunderx: Leave serdes lane config on 81/83xx to firmware
fff4ffd net: thunderx: Support to configure queue sizes from ethtool
171d87a net: thunderx: Make hfunc variable const type in nicvf_set_rxfh()
60dce04 net: thunderx: Fix error return code in nicvf_open()
bd3ad7d net: thunderx: Fix transmit queue timeout issue
430da20 net: thunderx: Pause frame support
d5b2d7a net: thunderx: Configure RED and backpressure levels
1cc7025 net: thunderx: Add ethtool support for supported ports and link modes.
5271156 net: thunderx: 80xx BGX0 configuration changes
Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
---
SOURCES/0001-thunderx-nic-updates.patch | 1796 +++++++++++++++++++++++++++++++
SPECS/kernel-aarch64.spec | 2 +
2 files changed, 1798 insertions(+)
create mode 100644 SOURCES/0001-thunderx-nic-updates.patch
diff --git a/SOURCES/0001-thunderx-nic-updates.patch b/SOURCES/0001-thunderx-nic-updates.patch
new file mode 100644
index 0000000..8f0e3e4
--- /dev/null
+++ b/SOURCES/0001-thunderx-nic-updates.patch
@@ -0,0 +1,1796 @@
+From 61c0e7db4f29bb556cdeed8c6d540a29bff32797 Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Thu, 24 Nov 2016 14:48:00 +0530
+Subject: [PATCH 01/14] net: thunderx: 80xx BGX0 configuration changes
+
+On 80xx only one lane of DLM0 and DLM1 (of BGX0) can be used
+, so even though lmac count may be 2 but LMAC1 should use
+serdes lane of DLM1. Since it's not possible to distinguish
+80xx from 81xx as PCI devid are same, this patch adds this
+config support by replying on what firmware configures the
+lmacs with.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 5271156b1a93eeb9a1a48d8a4be5074b3c31a5cd)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index a3f4f83..8e94d9c 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -969,11 +969,25 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx)
+ lmac_set_training(bgx, lmac, lmac->lmacid);
+ lmac_set_lane2sds(bgx, lmac);
+
+- /* Set LMAC type of other lmac on same DLM i.e LMAC 1/3 */
+ olmac = &bgx->lmac[idx + 1];
+- olmac->lmac_type = lmac->lmac_type;
++ /* Check if other LMAC on the same DLM is already configured by
++ * firmware, if so use the same config or else set as same, as
++ * that of LMAC 0/2.
++ * This check is needed as on 80xx only one lane of each of the
++ * DLM of BGX0 is used, so have to rely on firmware for
++ * distingushing 80xx from 81xx.
++ */
++ cmr_cfg = bgx_reg_read(bgx, idx + 1, BGX_CMRX_CFG);
++ lmac_type = (u8)((cmr_cfg >> 8) & 0x07);
++ lane_to_sds = (u8)(cmr_cfg & 0xFF);
++ if ((lmac_type == 0) && (lane_to_sds == 0xE4)) {
++ olmac->lmac_type = lmac->lmac_type;
++ lmac_set_lane2sds(bgx, olmac);
++ } else {
++ olmac->lmac_type = lmac_type;
++ olmac->lane_to_sds = lane_to_sds;
++ }
+ lmac_set_training(bgx, olmac, olmac->lmacid);
+- lmac_set_lane2sds(bgx, olmac);
+ }
+ }
+
+--
+2.5.5
+
+
+From 06f5f7f7917c40710e394aaa846097162394d599 Mon Sep 17 00:00:00 2001
+From: Thanneeru Srinivasulu <tsrinivasulu(a)cavium.com>
+Date: Thu, 24 Nov 2016 14:48:01 +0530
+Subject: [PATCH 02/14] net: thunderx: Add ethtool support for supported ports
+ and link modes.
+
+Signed-off-by: Thanneeru Srinivasulu <tsrinivasulu(a)cavium.com>
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 1cc702591bae9f70b1aa2f9cb60241961bc1858a)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nic.h | 2 ++
+ drivers/net/ethernet/cavium/thunder/nic_main.c | 1 +
+ .../net/ethernet/cavium/thunder/nicvf_ethtool.c | 36 ++++++++++++++++++++--
+ drivers/net/ethernet/cavium/thunder/nicvf_main.c | 1 +
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 1 +
+ 5 files changed, 38 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
+index cec0a86..a32ce99 100644
+--- a/drivers/net/ethernet/cavium/thunder/nic.h
++++ b/drivers/net/ethernet/cavium/thunder/nic.h
+@@ -291,6 +291,7 @@ struct nicvf {
+ u8 node;
+ u8 cpi_alg;
+ bool link_up;
++ u8 mac_type;
+ u8 duplex;
+ u32 speed;
+ bool tns_mode;
+@@ -445,6 +446,7 @@ struct bgx_stats_msg {
+ /* Physical interface link status */
+ struct bgx_link_status {
+ u8 msg;
++ u8 mac_type;
+ u8 link_up;
+ u8 duplex;
+ u32 speed;
+diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
+index aa3563f..4338742 100644
+--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
+@@ -1392,6 +1392,7 @@ static void nic_poll_for_link(struct work_struct *work)
+ mbx.link_status.link_up = link.link_up;
+ mbx.link_status.duplex = link.duplex;
+ mbx.link_status.speed = link.speed;
++ mbx.link_status.mac_type = link.mac_type;
+ nic_send_msg_to_vf(nic, vf, &mbx);
+ }
+ }
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+index 432bf6b..d4d76a7 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+@@ -130,12 +130,42 @@ static int nicvf_get_settings(struct net_device *netdev,
+ return 0;
+ }
+
+- if (nic->speed <= 1000) {
+- cmd->port = PORT_MII;
++ switch (nic->speed) {
++ case SPEED_1000:
++ cmd->port = PORT_MII | PORT_TP;
+ cmd->autoneg = AUTONEG_ENABLE;
+- } else {
++ cmd->supported |= SUPPORTED_MII | SUPPORTED_TP;
++ cmd->supported |= SUPPORTED_1000baseT_Full |
++ SUPPORTED_1000baseT_Half |
++ SUPPORTED_100baseT_Full |
++ SUPPORTED_100baseT_Half |
++ SUPPORTED_10baseT_Full |
++ SUPPORTED_10baseT_Half;
++ cmd->supported |= SUPPORTED_Autoneg;
++ cmd->advertising |= ADVERTISED_1000baseT_Full |
++ ADVERTISED_1000baseT_Half |
++ ADVERTISED_100baseT_Full |
++ ADVERTISED_100baseT_Half |
++ ADVERTISED_10baseT_Full |
++ ADVERTISED_10baseT_Half;
++ break;
++ case SPEED_10000:
++ if (nic->mac_type == BGX_MODE_RXAUI) {
++ cmd->port = PORT_TP;
++ cmd->supported |= SUPPORTED_TP;
++ } else {
++ cmd->port = PORT_FIBRE;
++ cmd->supported |= SUPPORTED_FIBRE;
++ }
++ cmd->autoneg = AUTONEG_DISABLE;
++ cmd->supported |= SUPPORTED_10000baseT_Full;
++ break;
++ case SPEED_40000:
+ cmd->port = PORT_FIBRE;
+ cmd->autoneg = AUTONEG_DISABLE;
++ cmd->supported |= SUPPORTED_FIBRE;
++ cmd->supported |= SUPPORTED_40000baseCR4_Full;
++ break;
+ }
+ cmd->duplex = nic->duplex;
+ ethtool_cmd_speed_set(cmd, nic->speed);
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+index 4f5c917..8ad63b7 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+@@ -221,6 +221,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
+ nic->link_up = mbx.link_status.link_up;
+ nic->duplex = mbx.link_status.duplex;
+ nic->speed = mbx.link_status.speed;
++ nic->mac_type = mbx.link_status.mac_type;
+ if (nic->link_up) {
+ netdev_info(nic->netdev, "%s: Link is Up %d Mbps %s\n",
+ nic->netdev->name, nic->speed,
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index 8e94d9c..c8a1256 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -162,6 +162,7 @@ void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status)
+ return;
+
+ lmac = &bgx->lmac[lmacid];
++ link->mac_type = lmac->lmac_type;
+ link->link_up = lmac->link_up;
+ link->duplex = lmac->last_duplex;
+ link->speed = lmac->last_speed;
+--
+2.5.5
+
+
+From 1885df686d94092a69c23add969ba6553fc2aa7e Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Thu, 24 Nov 2016 14:48:02 +0530
+Subject: [PATCH 03/14] net: thunderx: Configure RED and backpressure levels
+
+This patch enables moving average calculation of Rx pkt's resources
+and configures RED and backpressure levels for both CQ and RBDR.
+Also initialize SQ's CQ_LIMIT properly.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit d5b2d7a7184062c436f9a2b237e77bdb8e06a936)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nic_main.c | 9 ++++++++
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 9 ++++++--
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.h | 24 +++++++++++++++++-----
+ drivers/net/ethernet/cavium/thunder/q_struct.h | 8 ++++++--
+ 4 files changed, 41 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
+index 4338742..089d4b7 100644
+--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
+@@ -937,6 +937,15 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
+
+ bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
+
++ /* Enable moving average calculation.
++ * Keep the LVL/AVG delay to HW enforced minimum so that, not too many
++ * packets sneek in between average calculations.
++ */
++ nic_reg_write(nic, NIC_PF_CQ_AVG_CFG,
++ (BIT_ULL(20) | 0x2ull << 14 | 0x1));
++ nic_reg_write(nic, NIC_PF_RRM_AVG_CFG,
++ (BIT_ULL(20) | 0x3ull << 14 | 0x1));
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+index c17acf7..d5eda9d 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+@@ -544,14 +544,18 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ mbx.rq.msg = NIC_MBOX_MSG_RQ_BP_CFG;
+- mbx.rq.cfg = (1ULL << 63) | (1ULL << 62) | (qs->vnic_id << 0);
++ mbx.rq.cfg = BIT_ULL(63) | BIT_ULL(62) |
++ (RQ_PASS_RBDR_LVL << 16) | (RQ_PASS_CQ_LVL << 8) |
++ (qs->vnic_id << 0);
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ /* RQ drop config
+ * Enable CQ drop to reserve sufficient CQEs for all tx packets
+ */
+ mbx.rq.msg = NIC_MBOX_MSG_RQ_DROP_CFG;
+- mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8);
++ mbx.rq.cfg = BIT_ULL(63) | BIT_ULL(62) |
++ (RQ_PASS_RBDR_LVL << 40) | (RQ_DROP_RBDR_LVL << 32) |
++ (RQ_PASS_CQ_LVL << 16) | (RQ_DROP_CQ_LVL << 8);
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ if (!nic->sqs_mode && (qidx == 0)) {
+@@ -647,6 +651,7 @@ static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs,
+ sq_cfg.ldwb = 0;
+ sq_cfg.qsize = SND_QSIZE;
+ sq_cfg.tstmp_bgx_intf = 0;
++ sq_cfg.cq_limit = 0;
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, *(u64 *)&sq_cfg);
+
+ /* Set threshold value for interrupt generation */
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+index 2e3c940..20511f2 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+@@ -85,12 +85,26 @@
+
+ #define MAX_CQES_FOR_TX ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
+ MAX_CQE_PER_PKT_XMIT)
+-/* Calculate number of CQEs to reserve for all SQEs.
+- * Its 1/256th level of CQ size.
+- * '+ 1' to account for pipelining
++
++/* RED and Backpressure levels of CQ for pkt reception
++ * For CQ, level is a measure of emptiness i.e 0x0 means full
++ * eg: For CQ of size 4K, and for pass/drop levels of 128/96
++ * HW accepts pkt if unused CQE >= 2048
++ * RED accepts pkt if unused CQE < 2048 & >= 1536
++ * DROPs pkts if unused CQE < 1536
++ */
++#define RQ_PASS_CQ_LVL 128ULL
++#define RQ_DROP_CQ_LVL 96ULL
++
++/* RED and Backpressure levels of RBDR for pkt reception
++ * For RBDR, level is a measure of fullness i.e 0x0 means empty
++ * eg: For RBDR of size 8K, and for pass/drop levels of 4/0
++ * HW accepts pkt if unused RBs >= 256
++ * RED accepts pkt if unused RBs < 256 & >= 0
++ * DROPs pkts if unused RBs < 0
+ */
+-#define RQ_CQ_DROP ((256 / (CMP_QUEUE_LEN / \
+- (CMP_QUEUE_LEN - MAX_CQES_FOR_TX))) + 1)
++#define RQ_PASS_RBDR_LVL 8ULL
++#define RQ_DROP_RBDR_LVL 0ULL
+
+ /* Descriptor size in bytes */
+ #define SND_QUEUE_DESC_SIZE 16
+diff --git a/drivers/net/ethernet/cavium/thunder/q_struct.h b/drivers/net/ethernet/cavium/thunder/q_struct.h
+index 9e6d987..f363472 100644
+--- a/drivers/net/ethernet/cavium/thunder/q_struct.h
++++ b/drivers/net/ethernet/cavium/thunder/q_struct.h
+@@ -624,7 +624,9 @@ struct cq_cfg {
+
+ struct sq_cfg {
+ #if defined(__BIG_ENDIAN_BITFIELD)
+- u64 reserved_20_63:44;
++ u64 reserved_32_63:32;
++ u64 cq_limit:8;
++ u64 reserved_20_23:4;
+ u64 ena:1;
+ u64 reserved_18_18:1;
+ u64 reset:1;
+@@ -642,7 +644,9 @@ struct sq_cfg {
+ u64 reset:1;
+ u64 reserved_18_18:1;
+ u64 ena:1;
+- u64 reserved_20_63:44;
++ u64 reserved_20_23:4;
++ u64 cq_limit:8;
++ u64 reserved_32_63:32;
+ #endif
+ };
+
+--
+2.5.5
+
+
+From 2336e358e5ced0f20cacb6a24e233c772ff88eae Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Thu, 24 Nov 2016 14:48:03 +0530
+Subject: [PATCH 04/14] net: thunderx: Pause frame support
+
+Enable pause frames on both Rx and Tx side, configure pause
+interval e.t.c. Also support for enable/disable pause frames
+on Rx/Tx via ethtool has been added.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 430da208089ba74ff3d2992d80387c8ea5cabd0e)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nic.h | 17 +++++++
+ drivers/net/ethernet/cavium/thunder/nic_main.c | 27 +++++++++++
+ .../net/ethernet/cavium/thunder/nicvf_ethtool.c | 51 +++++++++++++++++++++
+ drivers/net/ethernet/cavium/thunder/nicvf_main.c | 6 +++
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 53 ++++++++++++++++++++++
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.h | 12 +++++
+ 6 files changed, 166 insertions(+)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
+index a32ce99..9ec29f9 100644
+--- a/drivers/net/ethernet/cavium/thunder/nic.h
++++ b/drivers/net/ethernet/cavium/thunder/nic.h
+@@ -148,6 +148,12 @@ struct nicvf_rss_info {
+ u64 key[RSS_HASH_KEY_SIZE];
+ } ____cacheline_aligned_in_smp;
+
++struct nicvf_pfc {
++ u8 autoneg;
++ u8 fc_rx;
++ u8 fc_tx;
++};
++
+ enum rx_stats_reg_offset {
+ RX_OCTS = 0x0,
+ RX_UCAST = 0x1,
+@@ -297,6 +303,7 @@ struct nicvf {
+ bool tns_mode;
+ bool loopback_supported;
+ struct nicvf_rss_info rss_info;
++ struct nicvf_pfc pfc;
+ struct tasklet_struct qs_err_task;
+ struct work_struct reset_task;
+
+@@ -357,6 +364,7 @@ struct nicvf {
+ #define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */
+ #define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */
+ #define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */
++#define NIC_MBOX_MSG_PFC 0x18 /* Pause frame control */
+ #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */
+ #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */
+
+@@ -500,6 +508,14 @@ struct reset_stat_cfg {
+ u16 sq_stat_mask;
+ };
+
++struct pfc {
++ u8 msg;
++ u8 get; /* Get or set PFC settings */
++ u8 autoneg;
++ u8 fc_rx;
++ u8 fc_tx;
++};
++
+ /* 128 bit shared memory between PF and each VF */
+ union nic_mbx {
+ struct { u8 msg; } msg;
+@@ -518,6 +534,7 @@ union nic_mbx {
+ struct nicvf_ptr nicvf;
+ struct set_loopback lbk;
+ struct reset_stat_cfg reset_stat;
++ struct pfc pfc;
+ };
+
+ #define NIC_NODE_ID_MASK 0x03
+diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
+index 089d4b7..9800a5d 100644
+--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
+@@ -1026,6 +1026,30 @@ static void nic_enable_vf(struct nicpf *nic, int vf, bool enable)
+ bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable);
+ }
+
++static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg)
++{
++ int bgx, lmac;
++ struct pfc pfc;
++ union nic_mbx mbx = {};
++
++ if (vf >= nic->num_vf_en)
++ return;
++ bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
++ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
++
++ if (cfg->get) {
++ bgx_lmac_get_pfc(nic->node, bgx, lmac, &pfc);
++ mbx.pfc.msg = NIC_MBOX_MSG_PFC;
++ mbx.pfc.autoneg = pfc.autoneg;
++ mbx.pfc.fc_rx = pfc.fc_rx;
++ mbx.pfc.fc_tx = pfc.fc_tx;
++ nic_send_msg_to_vf(nic, vf, &mbx);
++ } else {
++ bgx_lmac_set_pfc(nic->node, bgx, lmac, cfg);
++ nic_mbx_send_ack(nic, vf);
++ }
++}
++
+ /* Interrupt handler to handle mailbox messages from VFs */
+ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
+ {
+@@ -1167,6 +1191,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
+ case NIC_MBOX_MSG_RESET_STAT_COUNTER:
+ ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat);
+ break;
++ case NIC_MBOX_MSG_PFC:
++ nic_pause_frame(nic, vf, &mbx.pfc);
++ goto unlock;
+ default:
+ dev_err(&nic->pdev->dev,
+ "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+index d4d76a7..b048241 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+@@ -720,6 +720,55 @@ static int nicvf_set_channels(struct net_device *dev,
+ return err;
+ }
+
++static void nicvf_get_pauseparam(struct net_device *dev,
++ struct ethtool_pauseparam *pause)
++{
++ struct nicvf *nic = netdev_priv(dev);
++ union nic_mbx mbx = {};
++
++ /* Supported only for 10G/40G interfaces */
++ if ((nic->mac_type == BGX_MODE_SGMII) ||
++ (nic->mac_type == BGX_MODE_QSGMII) ||
++ (nic->mac_type == BGX_MODE_RGMII))
++ return;
++
++ mbx.pfc.msg = NIC_MBOX_MSG_PFC;
++ mbx.pfc.get = 1;
++ if (!nicvf_send_msg_to_pf(nic, &mbx)) {
++ pause->autoneg = nic->pfc.autoneg;
++ pause->rx_pause = nic->pfc.fc_rx;
++ pause->tx_pause = nic->pfc.fc_tx;
++ }
++}
++
++static int nicvf_set_pauseparam(struct net_device *dev,
++ struct ethtool_pauseparam *pause)
++{
++ struct nicvf *nic = netdev_priv(dev);
++ union nic_mbx mbx = {};
++
++ /* Supported only for 10G/40G interfaces */
++ if ((nic->mac_type == BGX_MODE_SGMII) ||
++ (nic->mac_type == BGX_MODE_QSGMII) ||
++ (nic->mac_type == BGX_MODE_RGMII))
++ return -EOPNOTSUPP;
++
++ if (pause->autoneg)
++ return -EOPNOTSUPP;
++
++ mbx.pfc.msg = NIC_MBOX_MSG_PFC;
++ mbx.pfc.get = 0;
++ mbx.pfc.fc_rx = pause->rx_pause;
++ mbx.pfc.fc_tx = pause->tx_pause;
++ if (nicvf_send_msg_to_pf(nic, &mbx))
++ return -EAGAIN;
++
++ nic->pfc.fc_rx = pause->rx_pause;
++ nic->pfc.fc_tx = pause->tx_pause;
++
++ return 0;
++}
++
+ static const struct ethtool_ops nicvf_ethtool_ops = {
+ .get_settings = nicvf_get_settings,
+ .get_link = nicvf_get_link,
+@@ -741,6 +790,8 @@ static const struct ethtool_ops nicvf_ethtool_ops = {
+ .set_rxfh = nicvf_set_rxfh,
+ .get_channels = nicvf_get_channels,
+ .set_channels = nicvf_set_channels,
++ .get_pauseparam = nicvf_get_pauseparam,
++ .set_pauseparam = nicvf_set_pauseparam,
+ .get_ts_info = ethtool_op_get_ts_info,
+ };
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+index 8ad63b7..3761e44 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+@@ -256,6 +256,12 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic)
+ nic->pnicvf = (struct nicvf *)mbx.nicvf.nicvf;
+ nic->pf_acked = true;
+ break;
++ case NIC_MBOX_MSG_PFC:
++ nic->pfc.autoneg = mbx.pfc.autoneg;
++ nic->pfc.fc_rx = mbx.pfc.fc_rx;
++ nic->pfc.fc_tx = mbx.pfc.fc_tx;
++ nic->pf_acked = true;
++ break;
+ default:
+ netdev_err(nic->netdev,
+ "Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index c8a1256..1744b4fc 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -213,6 +213,47 @@ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
+ }
+ EXPORT_SYMBOL(bgx_lmac_rx_tx_enable);
+
++void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause)
++{
++ struct pfc *pfc = (struct pfc *)pause;
++ struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
++ struct lmac *lmac;
++ u64 cfg;
++
++ if (!bgx)
++ return;
++ lmac = &bgx->lmac[lmacid];
++ if (lmac->is_sgmii)
++ return;
++
++ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_CBFC_CTL);
++ pfc->fc_rx = cfg & RX_EN;
++ pfc->fc_tx = cfg & TX_EN;
++ pfc->autoneg = 0;
++}
++EXPORT_SYMBOL(bgx_lmac_get_pfc);
++
++void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause)
++{
++ struct pfc *pfc = (struct pfc *)pause;
++ struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
++ struct lmac *lmac;
++ u64 cfg;
++
++ if (!bgx)
++ return;
++ lmac = &bgx->lmac[lmacid];
++ if (lmac->is_sgmii)
++ return;
++
++ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_CBFC_CTL);
++ cfg &= ~(RX_EN | TX_EN);
++ cfg |= (pfc->fc_rx ? RX_EN : 0x00);
++ cfg |= (pfc->fc_tx ? TX_EN : 0x00);
++ bgx_reg_write(bgx, lmacid, BGX_SMUX_CBFC_CTL, cfg);
++}
++EXPORT_SYMBOL(bgx_lmac_set_pfc);
++
+ static void bgx_sgmii_change_link_state(struct lmac *lmac)
+ {
+ struct bgx *bgx = lmac->bgx;
+@@ -524,6 +565,18 @@ static int bgx_lmac_xaui_init(struct bgx *bgx, struct lmac *lmac)
+ cfg |= SMU_TX_CTL_DIC_EN;
+ bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg);
+
++ /* Enable receive and transmission of pause frames */
++ bgx_reg_write(bgx, lmacid, BGX_SMUX_CBFC_CTL, ((0xffffULL << 32) |
++ BCK_EN | DRP_EN | TX_EN | RX_EN));
++ /* Configure pause time and interval */
++ bgx_reg_write(bgx, lmacid,
++ BGX_SMUX_TX_PAUSE_PKT_TIME, DEFAULT_PAUSE_TIME);
++ cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_PAUSE_PKT_INTERVAL);
++ cfg &= ~0xFFFFull;
++ bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_PAUSE_PKT_INTERVAL,
++ cfg | (DEFAULT_PAUSE_TIME - 0x1000));
++ bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_PAUSE_ZERO, 0x01);
++
+ /* take lmac_count into account */
+ bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
+ /* max packet size */
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+index 01cc7c8..c18ebfe 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+@@ -27,6 +27,7 @@
+ #define MAX_BGX_CHANS_PER_LMAC 16
+ #define MAX_DMAC_PER_LMAC 8
+ #define MAX_FRAME_SIZE 9216
++#define DEFAULT_PAUSE_TIME 0xFFFF
+
+ #define BGX_ID_MASK 0x3
+
+@@ -126,7 +127,10 @@
+ #define SMU_RX_CTL_STATUS (3ull << 0)
+ #define BGX_SMUX_TX_APPEND 0x20100
+ #define SMU_TX_APPEND_FCS_D BIT_ULL(2)
++#define BGX_SMUX_TX_PAUSE_PKT_TIME 0x20110
+ #define BGX_SMUX_TX_MIN_PKT 0x20118
++#define BGX_SMUX_TX_PAUSE_PKT_INTERVAL 0x20120
++#define BGX_SMUX_TX_PAUSE_ZERO 0x20138
+ #define BGX_SMUX_TX_INT 0x20140
+ #define BGX_SMUX_TX_CTL 0x20178
+ #define SMU_TX_CTL_DIC_EN BIT_ULL(0)
+@@ -136,6 +140,11 @@
+ #define BGX_SMUX_CTL 0x20200
+ #define SMU_CTL_RX_IDLE BIT_ULL(0)
+ #define SMU_CTL_TX_IDLE BIT_ULL(1)
++#define BGX_SMUX_CBFC_CTL 0x20218
++#define RX_EN BIT_ULL(0)
++#define TX_EN BIT_ULL(1)
++#define BCK_EN BIT_ULL(2)
++#define DRP_EN BIT_ULL(3)
+
+ #define BGX_GMP_PCS_MRX_CTL 0x30000
+ #define PCS_MRX_CTL_RST_AN BIT_ULL(9)
+@@ -207,6 +216,9 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac);
+ void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status);
+ void bgx_lmac_internal_loopback(int node, int bgx_idx,
+ int lmac_idx, bool enable);
++void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause);
++void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause);
++
+ void xcv_init_hw(void);
+ void xcv_setup_link(bool link_up, int link_speed);
+
+--
+2.5.5
+
+
+From 4dcce09dc780208de07a8d955ee25affbb75b041 Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Thu, 1 Dec 2016 18:24:28 +0530
+Subject: [PATCH 05/14] net: thunderx: Fix transmit queue timeout issue
+
+Transmit queue timeout issue is seen in two cases
+- Due to a race condition btw setting stop_queue at xmit()
+ and checking for stopped_queue in NAPI poll routine, at times
+ transmission from a SQ comes to a halt. This is fixed
+ by using barriers and also added a check for SQ free descriptors,
+ incase SQ is stopped and there are only CQE_RX i.e no CQE_TX.
+- Contrary to an assumption, a HW errata where HW doesn't stop transmission
+ even though there are not enough CQEs available for a CQE_TX is
+ not fixed in T88 pass 2.x. This results in a Qset error with
+ 'CQ_WR_FULL' stalling transmission. This is fixed by adjusting
+ RXQ's RED levels for CQ level such that there is always enough
+ space left for CQE_TXs.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit bd3ad7d3a14b07aeeb4f92abc757672719e2a0eb)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nicvf_main.c | 52 ++++++++++++++++++----
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 24 ++--------
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.h | 15 ++++---
+ 3 files changed, 54 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+index 3761e44..06aba60 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+@@ -643,6 +643,7 @@ static int nicvf_cq_intr_handler(struct net_device *netdev, u8 cq_idx,
+ struct cmp_queue *cq = &qs->cq[cq_idx];
+ struct cqe_rx_t *cq_desc;
+ struct netdev_queue *txq;
++ struct snd_queue *sq;
+ unsigned int tx_pkts = 0, tx_bytes = 0;
+
+ spin_lock_bh(&cq->lock);
+@@ -708,16 +709,20 @@ loop:
+
+ done:
+ /* Wakeup TXQ if its stopped earlier due to SQ full */
+- if (tx_done) {
++ sq = &nic->qs->sq[cq_idx];
++ if (tx_done ||
++ (atomic_read(&sq->free_cnt) >= MIN_SQ_DESC_PER_PKT_XMIT)) {
+ netdev = nic->pnicvf->netdev;
+ txq = netdev_get_tx_queue(netdev,
+ nicvf_netdev_qidx(nic, cq_idx));
+ if (tx_pkts)
+ netdev_tx_completed_queue(txq, tx_pkts, tx_bytes);
+
+- nic = nic->pnicvf;
++ /* To read updated queue and carrier status */
++ smp_mb();
+ if (netif_tx_queue_stopped(txq) && netif_carrier_ok(netdev)) {
+- netif_tx_start_queue(txq);
++ netif_tx_wake_queue(txq);
++ nic = nic->pnicvf;
+ this_cpu_inc(nic->drv_stats->txq_wake);
+ if (netif_msg_tx_err(nic))
+ netdev_warn(netdev,
+@@ -1053,6 +1058,9 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
+ struct nicvf *nic = netdev_priv(netdev);
+ int qid = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq = netdev_get_tx_queue(netdev, qid);
++ struct nicvf *snic;
++ struct snd_queue *sq;
++ int tmp;
+
+ /* Check for minimum packet length */
+ if (skb->len <= ETH_HLEN) {
+@@ -1060,13 +1068,39 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev)
+ return NETDEV_TX_OK;
+ }
+
+- if (!netif_tx_queue_stopped(txq) && !nicvf_sq_append_skb(nic, skb)) {
++ snic = nic;
++ /* Get secondary Qset's SQ structure */
++ if (qid >= MAX_SND_QUEUES_PER_QS) {
++ tmp = qid / MAX_SND_QUEUES_PER_QS;
++ snic = (struct nicvf *)nic->snicvf[tmp - 1];
++ if (!snic) {
++ netdev_warn(nic->netdev,
++ "Secondary Qset#%d's ptr not initialized\n",
++ tmp - 1);
++ dev_kfree_skb(skb);
++ return NETDEV_TX_OK;
++ }
++ qid = qid % MAX_SND_QUEUES_PER_QS;
++ }
++
++ sq = &snic->qs->sq[qid];
++ if (!netif_tx_queue_stopped(txq) &&
++ !nicvf_sq_append_skb(snic, sq, skb, qid)) {
+ netif_tx_stop_queue(txq);
+- this_cpu_inc(nic->drv_stats->txq_stop);
+- if (netif_msg_tx_err(nic))
+- netdev_warn(netdev,
+- "%s: Transmit ring full, stopping SQ%d\n",
+- netdev->name, qid);
++
++ /* Barrier, so that stop_queue visible to other cpus */
++ smp_mb();
++
++ /* Check again, incase another cpu freed descriptors */
++ if (atomic_read(&sq->free_cnt) > MIN_SQ_DESC_PER_PKT_XMIT) {
++ netif_tx_wake_queue(txq);
++ } else {
++ this_cpu_inc(nic->drv_stats->txq_stop);
++ if (netif_msg_tx_err(nic))
++ netdev_warn(netdev,
++ "%s: Transmit ring full, stopping SQ%d\n",
++ netdev->name, qid);
++ }
+ return NETDEV_TX_BUSY;
+ }
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+index d5eda9d..8071864 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+@@ -1187,30 +1187,12 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq,
+ }
+
+ /* Append an skb to a SQ for packet transfer. */
+-int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb)
++int nicvf_sq_append_skb(struct nicvf *nic, struct snd_queue *sq,
++ struct sk_buff *skb, u8 sq_num)
+ {
+ int i, size;
+ int subdesc_cnt, tso_sqe = 0;
+- int sq_num, qentry;
+- struct queue_set *qs;
+- struct snd_queue *sq;
+-
+- sq_num = skb_get_queue_mapping(skb);
+- if (sq_num >= MAX_SND_QUEUES_PER_QS) {
+- /* Get secondary Qset's SQ structure */
+- i = sq_num / MAX_SND_QUEUES_PER_QS;
+- if (!nic->snicvf[i - 1]) {
+- netdev_warn(nic->netdev,
+- "Secondary Qset#%d's ptr not initialized\n",
+- i - 1);
+- return 1;
+- }
+- nic = (struct nicvf *)nic->snicvf[i - 1];
+- sq_num = sq_num % MAX_SND_QUEUES_PER_QS;
+- }
+-
+- qs = nic->qs;
+- sq = &qs->sq[sq_num];
++ int qentry;
+
+ subdesc_cnt = nicvf_sq_subdesc_required(nic, skb);
+ if (subdesc_cnt > atomic_read(&sq->free_cnt))
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+index 20511f2..9e21046 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+@@ -88,13 +88,13 @@
+
+ /* RED and Backpressure levels of CQ for pkt reception
+ * For CQ, level is a measure of emptiness i.e 0x0 means full
+- * eg: For CQ of size 4K, and for pass/drop levels of 128/96
+- * HW accepts pkt if unused CQE >= 2048
+- * RED accepts pkt if unused CQE < 2048 & >= 1536
+- * DROPs pkts if unused CQE < 1536
++ * eg: For CQ of size 4K, and for pass/drop levels of 160/144
++ * HW accepts pkt if unused CQE >= 2560
++ * RED accepts pkt if unused CQE < 2304 & >= 2560
++ * DROPs pkts if unused CQE < 2304
+ */
+-#define RQ_PASS_CQ_LVL 128ULL
+-#define RQ_DROP_CQ_LVL 96ULL
++#define RQ_PASS_CQ_LVL 160ULL
++#define RQ_DROP_CQ_LVL 144ULL
+
+ /* RED and Backpressure levels of RBDR for pkt reception
+ * For RBDR, level is a measure of fullness i.e 0x0 means empty
+@@ -306,7 +306,8 @@ void nicvf_sq_disable(struct nicvf *nic, int qidx);
+ void nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt);
+ void nicvf_sq_free_used_descs(struct net_device *netdev,
+ struct snd_queue *sq, int qidx);
+-int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb);
++int nicvf_sq_append_skb(struct nicvf *nic, struct snd_queue *sq,
++ struct sk_buff *skb, u8 sq_num);
+
+ struct sk_buff *nicvf_get_rcv_skb(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
+ void nicvf_rbdr_task(unsigned long data);
+--
+2.5.5
+
+
+From ff39248cdad9577f0a344a00c2c83b4fa5b7b69e Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <weiyongjun1(a)huawei.com>
+Date: Wed, 11 Jan 2017 16:32:51 +0000
+Subject: [PATCH 06/14] net: thunderx: Fix error return code in nicvf_open()
+
+Fix to return a negative error code from the error handling
+case instead of 0, as done elsewhere in this function.
+
+Fixes: 712c31853440 ("net: thunderx: Program LMAC credits based on MTU")
+Signed-off-by: Wei Yongjun <weiyongjun1(a)huawei.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 60dce04b81424940a3183c8e7e81e1234a27e906)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nicvf_main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+index 06aba60..7a0bc52 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+@@ -1273,7 +1273,8 @@ int nicvf_open(struct net_device *netdev)
+ /* Configure receive side scaling and MTU */
+ if (!nic->sqs_mode) {
+ nicvf_rss_init(nic);
+- if (nicvf_update_hw_max_frs(nic, netdev->mtu))
++ err = nicvf_update_hw_max_frs(nic, netdev->mtu);
++ if (err)
+ goto cleanup;
+
+ /* Clear percpu stats */
+--
+2.5.5
+
+
+From 3df3815a3942d7a6821ed7098f7c463da3001fd9 Mon Sep 17 00:00:00 2001
+From: Robert Richter <rrichter(a)cavium.com>
+Date: Wed, 11 Jan 2017 18:04:32 +0100
+Subject: [PATCH 07/14] net: thunderx: Make hfunc variable const type in
+ nicvf_set_rxfh()
+
+>From struct ethtool_ops:
+
+ int (*set_rxfh)(struct net_device *, const u32 *indir,
+ const u8 *key, const u8 hfunc);
+
+Change function arg of hfunc to const type.
+
+V2: Fixed indentation.
+
+Signed-off-by: Robert Richter <rrichter(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 171d87aca0da1fab6a15b96ad8e298216a5951b0)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+index b048241..72c7d1f 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+@@ -629,7 +629,7 @@ static int nicvf_get_rxfh(struct net_device *dev, u32 *indir, u8 *hkey,
+ }
+
+ static int nicvf_set_rxfh(struct net_device *dev, const u32 *indir,
+- const u8 *hkey, u8 hfunc)
++ const u8 *hkey, const u8 hfunc)
+ {
+ struct nicvf *nic = netdev_priv(dev);
+ struct nicvf_rss_info *rss = &nic->rss_info;
+--
+2.5.5
+
+
+From 6c10f2f37ca625a957ad893ee713d970306b9aef Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Wed, 25 Jan 2017 17:36:23 +0530
+Subject: [PATCH 08/14] net: thunderx: Support to configure queue sizes from
+ ethtool
+
+Adds support to set Rx/Tx queue sizes from ethtool. Fixes
+an issue with retrieving queue size. Also sets SQ's CQ_LIMIT
+based on configured Tx queue size such that HW doesn't process
+SQEs when there is no sufficient space in CQ.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit fff4ffdde175bfa4516394db95ae56153224664b)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ .../net/ethernet/cavium/thunder/nicvf_ethtool.c | 39 ++++++++++++++++++++--
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 19 +++++++++--
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.h | 16 ++++++---
+ 3 files changed, 65 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+index 72c7d1f..1c82700 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+@@ -465,12 +465,46 @@ static void nicvf_get_ringparam(struct net_device *netdev,
+ struct nicvf *nic = netdev_priv(netdev);
+ struct queue_set *qs = nic->qs;
+
+- ring->rx_max_pending = MAX_RCV_BUF_COUNT;
+- ring->rx_pending = qs->rbdr_len;
++ ring->rx_max_pending = MAX_CMP_QUEUE_LEN;
++ ring->rx_pending = qs->cq_len;
+ ring->tx_max_pending = MAX_SND_QUEUE_LEN;
+ ring->tx_pending = qs->sq_len;
+ }
+
++static int nicvf_set_ringparam(struct net_device *netdev,
++ struct ethtool_ringparam *ring)
++{
++ struct nicvf *nic = netdev_priv(netdev);
++ struct queue_set *qs = nic->qs;
++ u32 rx_count, tx_count;
++
++ /* Due to HW errata this is not supported on T88 pass 1.x silicon */
++ if (pass1_silicon(nic->pdev))
++ return -EINVAL;
++
++ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
++ return -EINVAL;
++
++ tx_count = clamp_t(u32, ring->tx_pending,
++ MIN_SND_QUEUE_LEN, MAX_SND_QUEUE_LEN);
++ rx_count = clamp_t(u32, ring->rx_pending,
++ MIN_CMP_QUEUE_LEN, MAX_CMP_QUEUE_LEN);
++
++ if ((tx_count == qs->sq_len) && (rx_count == qs->cq_len))
++ return 0;
++
++ /* Permitted lengths are 1K, 2K, 4K, 8K, 16K, 32K, 64K */
++ qs->sq_len = rounddown_pow_of_two(tx_count);
++ qs->cq_len = rounddown_pow_of_two(rx_count);
++
++ if (netif_running(netdev)) {
++ nicvf_stop(netdev);
++ nicvf_open(netdev);
++ }
++
++ return 0;
++}
++
+ static int nicvf_get_rss_hash_opts(struct nicvf *nic,
+ struct ethtool_rxnfc *info)
+ {
+@@ -782,6 +816,7 @@ static const struct ethtool_ops nicvf_ethtool_ops = {
+ .get_regs = nicvf_get_regs,
+ .get_coalesce = nicvf_get_coalesce,
+ .get_ringparam = nicvf_get_ringparam,
++ .set_ringparam = nicvf_set_ringparam,
+ .get_rxnfc = nicvf_get_rxnfc,
+ .set_rxnfc = nicvf_set_rxnfc,
+ .get_rxfh_key_size = nicvf_get_rxfh_key_size,
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+index 8071864..142c045 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+@@ -601,7 +601,7 @@ void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
+ cq_cfg.ena = 1;
+ cq_cfg.reset = 0;
+ cq_cfg.caching = 0;
+- cq_cfg.qsize = CMP_QSIZE;
++ cq_cfg.qsize = ilog2(qs->cq_len >> 10);
+ cq_cfg.avg_con = 0;
+ nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG, qidx, *(u64 *)&cq_cfg);
+
+@@ -649,9 +649,12 @@ static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs,
+ sq_cfg.ena = 1;
+ sq_cfg.reset = 0;
+ sq_cfg.ldwb = 0;
+- sq_cfg.qsize = SND_QSIZE;
++ sq_cfg.qsize = ilog2(qs->sq_len >> 10);
+ sq_cfg.tstmp_bgx_intf = 0;
+- sq_cfg.cq_limit = 0;
++ /* CQ's level at which HW will stop processing SQEs to avoid
++ * transmitting a pkt with no space in CQ to post CQE_TX.
++ */
++ sq_cfg.cq_limit = (CMP_QUEUE_PIPELINE_RSVD * 256) / qs->cq_len;
+ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_CFG, qidx, *(u64 *)&sq_cfg);
+
+ /* Set threshold value for interrupt generation */
+@@ -812,11 +815,21 @@ int nicvf_config_data_transfer(struct nicvf *nic, bool enable)
+ {
+ bool disable = false;
+ struct queue_set *qs = nic->qs;
++ struct queue_set *pqs = nic->pnicvf->qs;
+ int qidx;
+
+ if (!qs)
+ return 0;
+
++ /* Take primary VF's queue lengths.
++ * This is needed to take queue lengths set from ethtool
++ * into consideration.
++ */
++ if (nic->sqs_mode && pqs) {
++ qs->cq_len = pqs->cq_len;
++ qs->sq_len = pqs->sq_len;
++ }
++
+ if (enable) {
+ if (nicvf_alloc_resources(nic))
+ return -ENOMEM;
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+index 9e21046..5cb84da 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+@@ -59,8 +59,9 @@
+ /* Default queue count per QS, its lengths and threshold values */
+ #define DEFAULT_RBDR_CNT 1
+
+-#define SND_QSIZE SND_QUEUE_SIZE2
++#define SND_QSIZE SND_QUEUE_SIZE0
+ #define SND_QUEUE_LEN (1ULL << (SND_QSIZE + 10))
++#define MIN_SND_QUEUE_LEN (1ULL << (SND_QUEUE_SIZE0 + 10))
+ #define MAX_SND_QUEUE_LEN (1ULL << (SND_QUEUE_SIZE6 + 10))
+ #define SND_QUEUE_THRESH 2ULL
+ #define MIN_SQ_DESC_PER_PKT_XMIT 2
+@@ -70,11 +71,18 @@
+ /* Keep CQ and SQ sizes same, if timestamping
+ * is enabled this equation will change.
+ */
+-#define CMP_QSIZE CMP_QUEUE_SIZE2
++#define CMP_QSIZE CMP_QUEUE_SIZE0
+ #define CMP_QUEUE_LEN (1ULL << (CMP_QSIZE + 10))
++#define MIN_CMP_QUEUE_LEN (1ULL << (CMP_QUEUE_SIZE0 + 10))
++#define MAX_CMP_QUEUE_LEN (1ULL << (CMP_QUEUE_SIZE6 + 10))
+ #define CMP_QUEUE_CQE_THRESH (NAPI_POLL_WEIGHT / 2)
+ #define CMP_QUEUE_TIMER_THRESH 80 /* ~2usec */
+
++/* No of CQEs that might anyway gets used by HW due to pipelining
++ * effects irrespective of PASS/DROP/LEVELS being configured
++ */
++#define CMP_QUEUE_PIPELINE_RSVD 544
++
+ #define RBDR_SIZE RBDR_SIZE0
+ #define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13))
+ #define MAX_RCV_BUF_COUNT (1ULL << (RBDR_SIZE6 + 13))
+@@ -93,8 +101,8 @@
+ * RED accepts pkt if unused CQE < 2304 & >= 2560
+ * DROPs pkts if unused CQE < 2304
+ */
+-#define RQ_PASS_CQ_LVL 160ULL
+-#define RQ_DROP_CQ_LVL 144ULL
++#define RQ_PASS_CQ_LVL 192ULL
++#define RQ_DROP_CQ_LVL 184ULL
+
+ /* RED and Backpressure levels of RBDR for pkt reception
+ * For RBDR, level is a measure of fullness i.e 0x0 means empty
+--
+2.5.5
+
+
+From 1108842a9601ca29806c04b0b9652f8afc63db84 Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Wed, 25 Jan 2017 17:36:24 +0530
+Subject: [PATCH 09/14] net: thunderx: Leave serdes lane config on 81/83xx to
+ firmware
+
+For DLMs and SLMs on 80/81/83xx, many lane configurations
+across different boards are coming up. Also kernel doesn't have
+any way to identify board type/info and since firmware does,
+just get rid of figuring out lane to serdes config and take
+whatever has been programmed by low level firmware.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit fff37fdad9df3b214294ef83943d92aa9e1c7ecc)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 95 +++++------------------
+ 1 file changed, 18 insertions(+), 77 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index 1744b4fc..aa5836c 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -892,17 +892,15 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid)
+ struct device *dev = &bgx->pdev->dev;
+ struct lmac *lmac;
+ char str[20];
+- u8 dlm;
+
+- if (lmacid > bgx->max_lmac)
++ if (!bgx->is_dlm && lmacid)
+ return;
+
+ lmac = &bgx->lmac[lmacid];
+- dlm = (lmacid / 2) + (bgx->bgx_id * 2);
+ if (!bgx->is_dlm)
+ sprintf(str, "BGX%d QLM mode", bgx->bgx_id);
+ else
+- sprintf(str, "BGX%d DLM%d mode", bgx->bgx_id, dlm);
++ sprintf(str, "BGX%d LMAC%d mode", bgx->bgx_id, lmacid);
+
+ switch (lmac->lmac_type) {
+ case BGX_MODE_SGMII:
+@@ -988,7 +986,6 @@ static void lmac_set_training(struct bgx *bgx, struct lmac *lmac, int lmacid)
+ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx)
+ {
+ struct lmac *lmac;
+- struct lmac *olmac;
+ u64 cmr_cfg;
+ u8 lmac_type;
+ u8 lane_to_sds;
+@@ -1008,62 +1005,26 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx)
+ return;
+ }
+
+- /* On 81xx BGX can be split across 2 DLMs
+- * firmware programs lmac_type of LMAC0 and LMAC2
++ /* For DLMs or SLMs on 80/81/83xx so many lane configurations
++ * are possible and vary across boards. Also Kernel doesn't have
++ * any way to identify board type/info and since firmware does,
++ * just take lmac type and serdes lane config as is.
+ */
+- if ((idx == 0) || (idx == 2)) {
+- cmr_cfg = bgx_reg_read(bgx, idx, BGX_CMRX_CFG);
+- lmac_type = (u8)((cmr_cfg >> 8) & 0x07);
+- lane_to_sds = (u8)(cmr_cfg & 0xFF);
+- /* Check if config is not reset value */
+- if ((lmac_type == 0) && (lane_to_sds == 0xE4))
+- lmac->lmac_type = BGX_MODE_INVALID;
+- else
+- lmac->lmac_type = lmac_type;
+- lmac_set_training(bgx, lmac, lmac->lmacid);
+- lmac_set_lane2sds(bgx, lmac);
+-
+- olmac = &bgx->lmac[idx + 1];
+- /* Check if other LMAC on the same DLM is already configured by
+- * firmware, if so use the same config or else set as same, as
+- * that of LMAC 0/2.
+- * This check is needed as on 80xx only one lane of each of the
+- * DLM of BGX0 is used, so have to rely on firmware for
+- * distingushing 80xx from 81xx.
+- */
+- cmr_cfg = bgx_reg_read(bgx, idx + 1, BGX_CMRX_CFG);
+- lmac_type = (u8)((cmr_cfg >> 8) & 0x07);
+- lane_to_sds = (u8)(cmr_cfg & 0xFF);
+- if ((lmac_type == 0) && (lane_to_sds == 0xE4)) {
+- olmac->lmac_type = lmac->lmac_type;
+- lmac_set_lane2sds(bgx, olmac);
+- } else {
+- olmac->lmac_type = lmac_type;
+- olmac->lane_to_sds = lane_to_sds;
+- }
+- lmac_set_training(bgx, olmac, olmac->lmacid);
+- }
+-}
+-
+-static bool is_dlm0_in_bgx_mode(struct bgx *bgx)
+-{
+- struct lmac *lmac;
+-
+- if (!bgx->is_dlm)
+- return true;
+-
+- lmac = &bgx->lmac[0];
+- if (lmac->lmac_type == BGX_MODE_INVALID)
+- return false;
+-
+- return true;
++ cmr_cfg = bgx_reg_read(bgx, idx, BGX_CMRX_CFG);
++ lmac_type = (u8)((cmr_cfg >> 8) & 0x07);
++ lane_to_sds = (u8)(cmr_cfg & 0xFF);
++ /* Check if config is reset value */
++ if ((lmac_type == 0) && (lane_to_sds == 0xE4))
++ lmac->lmac_type = BGX_MODE_INVALID;
++ else
++ lmac->lmac_type = lmac_type;
++ lmac->lane_to_sds = lane_to_sds;
++ lmac_set_training(bgx, lmac, lmac->lmacid);
+ }
+
+ static void bgx_get_qlm_mode(struct bgx *bgx)
+ {
+ struct lmac *lmac;
+- struct lmac *lmac01;
+- struct lmac *lmac23;
+ u8 idx;
+
+ /* Init all LMAC's type to invalid */
+@@ -1079,29 +1040,9 @@ static void bgx_get_qlm_mode(struct bgx *bgx)
+ if (bgx->lmac_count > bgx->max_lmac)
+ bgx->lmac_count = bgx->max_lmac;
+
+- for (idx = 0; idx < bgx->max_lmac; idx++)
+- bgx_set_lmac_config(bgx, idx);
+-
+- if (!bgx->is_dlm || bgx->is_rgx) {
+- bgx_print_qlm_mode(bgx, 0);
+- return;
+- }
+-
+- if (bgx->lmac_count) {
+- bgx_print_qlm_mode(bgx, 0);
+- bgx_print_qlm_mode(bgx, 2);
+- }
+-
+- /* If DLM0 is not in BGX mode then LMAC0/1 have
+- * to be configured with serdes lanes of DLM1
+- */
+- if (is_dlm0_in_bgx_mode(bgx) || (bgx->lmac_count > 2))
+- return;
+ for (idx = 0; idx < bgx->lmac_count; idx++) {
+- lmac01 = &bgx->lmac[idx];
+- lmac23 = &bgx->lmac[idx + 2];
+- lmac01->lmac_type = lmac23->lmac_type;
+- lmac01->lane_to_sds = lmac23->lane_to_sds;
++ bgx_set_lmac_config(bgx, idx);
++ bgx_print_qlm_mode(bgx, idx);
+ }
+ }
+
+--
+2.5.5
+
+
+From 4d3d951bfbbcb4938fa29d1756e8ae8e011802e2 Mon Sep 17 00:00:00 2001
+From: Vincent <vincent.stehle(a)laposte.net>
+Date: Mon, 30 Jan 2017 15:06:43 +0100
+Subject: [PATCH 10/14] net: thunderx: avoid dereferencing xcv when NULL
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes the following smatch and coccinelle warnings:
+
+ drivers/net/ethernet/cavium/thunder/thunder_xcv.c:119 xcv_setup_link() error: we previously assumed 'xcv' could be null (see line 118) [smatch]
+ drivers/net/ethernet/cavium/thunder/thunder_xcv.c:119:16-20: ERROR: xcv is NULL but dereferenced. [coccinelle]
+
+Fixes: 6465859aba1e66a5 ("net: thunderx: Add RGMII interface type support")
+Signed-off-by: Vincent Stehlé <vincent.stehle(a)laposte.net>
+Cc: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit c73e44269369e936165f0f9b61f1f09a11dae01c)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/thunder_xcv.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_xcv.c b/drivers/net/ethernet/cavium/thunder/thunder_xcv.c
+index 67befed..578c7f8 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_xcv.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_xcv.c
+@@ -116,8 +116,7 @@ void xcv_setup_link(bool link_up, int link_speed)
+ int speed = 2;
+
+ if (!xcv) {
+- dev_err(&xcv->pdev->dev,
+- "XCV init not done, probe may have failed\n");
++ pr_err("XCV init not done, probe may have failed\n");
+ return;
+ }
+
+--
+2.5.5
+
+
+From b26339185447e850da6e19db1df0d9d0cdc09419 Mon Sep 17 00:00:00 2001
+From: Thanneeru Srinivasulu <tsrinivasulu(a)cavium.com>
+Date: Wed, 8 Feb 2017 18:09:00 +0530
+Subject: [PATCH 11/14] net: thunderx: Fix PHY autoneg for SGMII QLM mode
+
+This patch fixes the case where there is no phydev attached
+to a LMAC in DT due to non-existance of a PHY driver or due
+to usage of non-stanadard PHY which doesn't support autoneg.
+Changes dependeds on firmware to send correct info w.r.t
+PHY and autoneg capability.
+
+This patch also covers a case where a 10G/40G interface is used
+as a 1G with convertors with Cortina PHY in between.
+
+Signed-off-by: Thanneeru Srinivasulu <tsrinivasulu(a)cavium.com>
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 075ad765ef7541b2860de8408c165a92b78aefa3)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 108 +++++++++++++++++++---
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.h | 5 +
+ 2 files changed, 101 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index aa5836c..6eadbd7 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -31,6 +31,7 @@ struct lmac {
+ u8 lmac_type;
+ u8 lane_to_sds;
+ bool use_training;
++ bool autoneg;
+ bool link_up;
+ int lmacid; /* ID within BGX */
+ int lmacid_bd; /* ID on board */
+@@ -459,7 +460,17 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac)
+ /* power down, reset autoneg, autoneg enable */
+ cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
+ cfg &= ~PCS_MRX_CTL_PWR_DN;
+- cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN);
++ cfg |= PCS_MRX_CTL_RST_AN;
++ if (lmac->phydev) {
++ cfg |= PCS_MRX_CTL_AN_EN;
++ } else {
++ /* In scenarios where PHY driver is not present or it's a
++ * non-standard PHY, FW sets AN_EN to inform Linux driver
++ * to do auto-neg and link polling or not.
++ */
++ if (cfg & PCS_MRX_CTL_AN_EN)
++ lmac->autoneg = true;
++ }
+ bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
+
+ if (lmac->lmac_type == BGX_MODE_QSGMII) {
+@@ -470,7 +481,7 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac)
+ return 0;
+ }
+
+- if (lmac->lmac_type == BGX_MODE_SGMII) {
++ if ((lmac->lmac_type == BGX_MODE_SGMII) && lmac->phydev) {
+ if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS,
+ PCS_MRX_STATUS_AN_CPT, false)) {
+ dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n");
+@@ -676,12 +687,71 @@ static int bgx_xaui_check_link(struct lmac *lmac)
+ return -1;
+ }
+
++static void bgx_poll_for_sgmii_link(struct lmac *lmac)
++{
++ u64 pcs_link, an_result;
++ u8 speed;
++
++ pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid,
++ BGX_GMP_PCS_MRX_STATUS);
++
++ /*Link state bit is sticky, read it again*/
++ if (!(pcs_link & PCS_MRX_STATUS_LINK))
++ pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid,
++ BGX_GMP_PCS_MRX_STATUS);
++
++ if (bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_GMP_PCS_MRX_STATUS,
++ PCS_MRX_STATUS_AN_CPT, false)) {
++ lmac->link_up = false;
++ lmac->last_speed = SPEED_UNKNOWN;
++ lmac->last_duplex = DUPLEX_UNKNOWN;
++ goto next_poll;
++ }
++
++ lmac->link_up = ((pcs_link & PCS_MRX_STATUS_LINK) != 0) ? true : false;
++ an_result = bgx_reg_read(lmac->bgx, lmac->lmacid,
++ BGX_GMP_PCS_ANX_AN_RESULTS);
++
++ speed = (an_result >> 3) & 0x3;
++ lmac->last_duplex = (an_result >> 1) & 0x1;
++ switch (speed) {
++ case 0:
++ lmac->last_speed = 10;
++ break;
++ case 1:
++ lmac->last_speed = 100;
++ break;
++ case 2:
++ lmac->last_speed = 1000;
++ break;
++ default:
++ lmac->link_up = false;
++ lmac->last_speed = SPEED_UNKNOWN;
++ lmac->last_duplex = DUPLEX_UNKNOWN;
++ break;
++ }
++
++next_poll:
++
++ if (lmac->last_link != lmac->link_up) {
++ if (lmac->link_up)
++ bgx_sgmii_change_link_state(lmac);
++ lmac->last_link = lmac->link_up;
++ }
++
++ queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 3);
++}
++
+ static void bgx_poll_for_link(struct work_struct *work)
+ {
+ struct lmac *lmac;
+ u64 spu_link, smu_link;
+
+ lmac = container_of(work, struct lmac, dwork.work);
++ if (lmac->is_sgmii) {
++ bgx_poll_for_sgmii_link(lmac);
++ return;
++ }
+
+ /* Receive link is latching low. Force it high and verify it */
+ bgx_reg_modify(lmac->bgx, lmac->lmacid,
+@@ -773,9 +843,21 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
+ (lmac->lmac_type != BGX_MODE_XLAUI) &&
+ (lmac->lmac_type != BGX_MODE_40G_KR) &&
+ (lmac->lmac_type != BGX_MODE_10G_KR)) {
+- if (!lmac->phydev)
+- return -ENODEV;
+-
++ if (!lmac->phydev) {
++ if (lmac->autoneg) {
++ bgx_reg_write(bgx, lmacid,
++ BGX_GMP_PCS_LINKX_TIMER,
++ PCS_LINKX_TIMER_COUNT);
++ goto poll;
++ } else {
++ /* Default to below link speed and duplex */
++ lmac->link_up = true;
++ lmac->last_speed = 1000;
++ lmac->last_duplex = 1;
++ bgx_sgmii_change_link_state(lmac);
++ return 0;
++ }
++ }
+ lmac->phydev->dev_flags = 0;
+
+ if (phy_connect_direct(&lmac->netdev, lmac->phydev,
+@@ -784,15 +866,17 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
+ return -ENODEV;
+
+ phy_start_aneg(lmac->phydev);
+- } else {
+- lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND |
+- WQ_MEM_RECLAIM, 1);
+- if (!lmac->check_link)
+- return -ENOMEM;
+- INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link);
+- queue_delayed_work(lmac->check_link, &lmac->dwork, 0);
++ return 0;
+ }
+
++poll:
++ lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND |
++ WQ_MEM_RECLAIM, 1);
++ if (!lmac->check_link)
++ return -ENOMEM;
++ INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link);
++ queue_delayed_work(lmac->check_link, &lmac->dwork, 0);
++
+ return 0;
+ }
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+index c18ebfe..a60f189 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+@@ -153,10 +153,15 @@
+ #define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14)
+ #define PCS_MRX_CTL_RESET BIT_ULL(15)
+ #define BGX_GMP_PCS_MRX_STATUS 0x30008
++#define PCS_MRX_STATUS_LINK BIT_ULL(2)
+ #define PCS_MRX_STATUS_AN_CPT BIT_ULL(5)
++#define BGX_GMP_PCS_ANX_ADV 0x30010
+ #define BGX_GMP_PCS_ANX_AN_RESULTS 0x30020
++#define BGX_GMP_PCS_LINKX_TIMER 0x30040
++#define PCS_LINKX_TIMER_COUNT 0x1E84
+ #define BGX_GMP_PCS_SGM_AN_ADV 0x30068
+ #define BGX_GMP_PCS_MISCX_CTL 0x30078
++#define PCS_MISC_CTL_MODE BIT_ULL(8)
+ #define PCS_MISC_CTL_DISP_EN BIT_ULL(13)
+ #define PCS_MISC_CTL_GMX_ENO BIT_ULL(11)
+ #define PCS_MISC_CTL_SAMP_PT_MASK 0x7Full
+--
+2.5.5
+
+
+From 6f831cdf29fa390612b2bcc48ebd002452959696 Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Tue, 7 Mar 2017 18:09:09 +0530
+Subject: [PATCH 12/14] net: thunderx: Fix LMAC mode debug prints for QSGMII
+ mode
+
+When BGX/LMACs are in QSGMII mode, for some LMACs, mode info is
+not being printed. This patch will fix that. With changes already
+done to not do any sort of serdes 2 lane mapping config calculation
+in kernel driver, we can get rid of this logic.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 18de7ba95f6e5ab150e482618123d92ee2240dc0)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index 6eadbd7..e3223fa 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -1009,12 +1009,6 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid)
+ dev_info(dev, "%s: 40G_KR4\n", (char *)str);
+ break;
+ case BGX_MODE_QSGMII:
+- if ((lmacid == 0) &&
+- (bgx_get_lane2sds_cfg(bgx, lmac) != lmacid))
+- return;
+- if ((lmacid == 2) &&
+- (bgx_get_lane2sds_cfg(bgx, lmac) == lmacid))
+- return;
+ dev_info(dev, "%s: QSGMII\n", (char *)str);
+ break;
+ case BGX_MODE_RGMII:
+--
+2.5.5
+
+
+From bf375972be4b651de342b43cab0c908d0eb733be Mon Sep 17 00:00:00 2001
+From: Sunil Goutham <sgoutham(a)cavium.com>
+Date: Tue, 7 Mar 2017 18:09:10 +0530
+Subject: [PATCH 13/14] net: thunderx: Fix invalid mac addresses for node1
+ interfaces
+
+When booted with ACPI, random mac addresses are being
+assigned to node1 interfaces due to mismatch of bgx_id
+in BGX driver and ACPI tables.
+
+This patch fixes this issue by setting maximum BGX devices
+per node based on platform/soc instead of a macro. This
+change will set the bgx_id appropriately.
+
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 78aacb6f6eeea3c581a29b4a50438d0bdf85ad0b)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 58 ++++++++++++++++++-----
+ drivers/net/ethernet/cavium/thunder/thunder_bgx.h | 1 -
+ 2 files changed, 45 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index e3223fa..898a684 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -123,14 +123,44 @@ static int bgx_poll_reg(struct bgx *bgx, u8 lmac, u64 reg, u64 mask, bool zero)
+ return 1;
+ }
+
++static int max_bgx_per_node;
++static void set_max_bgx_per_node(struct pci_dev *pdev)
++{
++ u16 sdevid;
++
++ if (max_bgx_per_node)
++ return;
++
++ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdevid);
++ switch (sdevid) {
++ case PCI_SUBSYS_DEVID_81XX_BGX:
++ max_bgx_per_node = MAX_BGX_PER_CN81XX;
++ break;
++ case PCI_SUBSYS_DEVID_83XX_BGX:
++ max_bgx_per_node = MAX_BGX_PER_CN83XX;
++ break;
++ case PCI_SUBSYS_DEVID_88XX_BGX:
++ default:
++ max_bgx_per_node = MAX_BGX_PER_CN88XX;
++ break;
++ }
++}
++
++static struct bgx *get_bgx(int node, int bgx_idx)
++{
++ int idx = (node * max_bgx_per_node) + bgx_idx;
++
++ return bgx_vnic[idx];
++}
++
+ /* Return number of BGX present in HW */
+ unsigned bgx_get_map(int node)
+ {
+ int i;
+ unsigned map = 0;
+
+- for (i = 0; i < MAX_BGX_PER_NODE; i++) {
+- if (bgx_vnic[(node * MAX_BGX_PER_NODE) + i])
++ for (i = 0; i < max_bgx_per_node; i++) {
++ if (bgx_vnic[(node * max_bgx_per_node) + i])
+ map |= (1 << i);
+ }
+
+@@ -143,7 +173,7 @@ int bgx_get_lmac_count(int node, int bgx_idx)
+ {
+ struct bgx *bgx;
+
+- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ bgx = get_bgx(node, bgx_idx);
+ if (bgx)
+ return bgx->lmac_count;
+
+@@ -158,7 +188,7 @@ void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status)
+ struct bgx *bgx;
+ struct lmac *lmac;
+
+- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ bgx = get_bgx(node, bgx_idx);
+ if (!bgx)
+ return;
+
+@@ -172,7 +202,7 @@ EXPORT_SYMBOL(bgx_get_lmac_link_state);
+
+ const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid)
+ {
+- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ struct bgx *bgx = get_bgx(node, bgx_idx);
+
+ if (bgx)
+ return bgx->lmac[lmacid].mac;
+@@ -183,7 +213,7 @@ EXPORT_SYMBOL(bgx_get_lmac_mac);
+
+ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac)
+ {
+- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ struct bgx *bgx = get_bgx(node, bgx_idx);
+
+ if (!bgx)
+ return;
+@@ -194,7 +224,7 @@ EXPORT_SYMBOL(bgx_set_lmac_mac);
+
+ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
+ {
+- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ struct bgx *bgx = get_bgx(node, bgx_idx);
+ struct lmac *lmac;
+ u64 cfg;
+
+@@ -217,7 +247,7 @@ EXPORT_SYMBOL(bgx_lmac_rx_tx_enable);
+ void bgx_lmac_get_pfc(int node, int bgx_idx, int lmacid, void *pause)
+ {
+ struct pfc *pfc = (struct pfc *)pause;
+- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
++ struct bgx *bgx = get_bgx(node, bgx_idx);
+ struct lmac *lmac;
+ u64 cfg;
+
+@@ -237,7 +267,7 @@ EXPORT_SYMBOL(bgx_lmac_get_pfc);
+ void bgx_lmac_set_pfc(int node, int bgx_idx, int lmacid, void *pause)
+ {
+ struct pfc *pfc = (struct pfc *)pause;
+- struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
++ struct bgx *bgx = get_bgx(node, bgx_idx);
+ struct lmac *lmac;
+ u64 cfg;
+
+@@ -367,7 +397,7 @@ u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx)
+ {
+ struct bgx *bgx;
+
+- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ bgx = get_bgx(node, bgx_idx);
+ if (!bgx)
+ return 0;
+
+@@ -381,7 +411,7 @@ u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx)
+ {
+ struct bgx *bgx;
+
+- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ bgx = get_bgx(node, bgx_idx);
+ if (!bgx)
+ return 0;
+
+@@ -409,7 +439,7 @@ void bgx_lmac_internal_loopback(int node, int bgx_idx,
+ struct lmac *lmac;
+ u64 cfg;
+
+- bgx = bgx_vnic[(node * MAX_BGX_PER_NODE) + bgx_idx];
++ bgx = get_bgx(node, bgx_idx);
+ if (!bgx)
+ return;
+
+@@ -1326,11 +1356,13 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ goto err_release_regions;
+ }
+
++ set_max_bgx_per_node(pdev);
++
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &sdevid);
+ if (sdevid != PCI_DEVICE_ID_THUNDER_RGX) {
+ bgx->bgx_id = (pci_resource_start(pdev,
+ PCI_CFG_REG_BAR_NUM) >> 24) & BGX_ID_MASK;
+- bgx->bgx_id += nic_get_node_id(pdev) * MAX_BGX_PER_NODE;
++ bgx->bgx_id += nic_get_node_id(pdev) * max_bgx_per_node;
+ bgx->max_lmac = MAX_LMAC_PER_BGX;
+ bgx_vnic[bgx->bgx_id] = bgx;
+ } else {
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+index a60f189..c5080f2c 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+@@ -22,7 +22,6 @@
+ #define MAX_BGX_PER_CN88XX 2
+ #define MAX_BGX_PER_CN81XX 3 /* 2 BGXs + 1 RGX */
+ #define MAX_BGX_PER_CN83XX 4
+-#define MAX_BGX_PER_NODE 4
+ #define MAX_LMAC_PER_BGX 4
+ #define MAX_BGX_CHANS_PER_LMAC 16
+ #define MAX_DMAC_PER_LMAC 8
+--
+2.5.5
+
+
+From 52401dec7de73bf432a335148082db3aa7970bbd Mon Sep 17 00:00:00 2001
+From: Thanneeru Srinivasulu <tsrinivasulu(a)cavium.com>
+Date: Tue, 7 Mar 2017 18:09:11 +0530
+Subject: [PATCH 14/14] net: thunderx: Allow IPv6 frames with zero UDP checksum
+
+Do not consider IPv6 frames with zero UDP checksum as frames
+with bad checksum and drop them.
+
+Signed-off-by: Thanneeru Srinivasulu <tsrinivasulu(a)cavium.com>
+Signed-off-by: Sunil Goutham <sgoutham(a)cavium.com>
+Signed-off-by: David S. Miller <davem(a)davemloft.net>
+(cherry picked from commit 36fa35d22bffc78c85b5e68adbdd99e914bec764)
+Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev(a)caviumnetworks.com>
+---
+ drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+index 142c045..b44aadd 100644
+--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
++++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+@@ -559,9 +559,11 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs,
+ nicvf_send_msg_to_pf(nic, &mbx);
+
+ if (!nic->sqs_mode && (qidx == 0)) {
+- /* Enable checking L3/L4 length and TCP/UDP checksums */
++ /* Enable checking L3/L4 length and TCP/UDP checksums
++ * Also allow IPv6 pkts with zero UDP checksum.
++ */
+ nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0,
+- (BIT(24) | BIT(23) | BIT(21)));
++ (BIT(24) | BIT(23) | BIT(21) | BIT(20)));
+ nicvf_config_vlan_stripping(nic, nic->netdev->features);
+ }
+
+--
+2.5.5
+
diff --git a/SPECS/kernel-aarch64.spec b/SPECS/kernel-aarch64.spec
index b6d58e5..c197862 100644
--- a/SPECS/kernel-aarch64.spec
+++ b/SPECS/kernel-aarch64.spec
@@ -360,6 +360,7 @@ Patch1030: 1030-pca954x-pca955x-pca963x-ds1307-ACPI-support.patch
Patch2000: ThunderX-7.3.1611.patch
Patch2001: 0001-PCI-ASPM-Don-t-retrain-link-if-ASPM-not-possible.patch
Patch2002: 0001-net-thunderx-acpi-fix-LMAC-initialization.patch
+Patch2003: 0001-thunderx-nic-updates.patch
# QDF2400 Patches
#Patch4000: 4000-arm64-Define-Qualcomm-Technologies-ARMv8-CPU.patch
@@ -730,6 +731,7 @@ git am %{PATCH1030}
git am %{PATCH2000}
git am %{PATCH2001}
git am %{PATCH2002}
+git am %{PATCH2003}
# NO LONGER NEEDED as of 4.5.0-15.2.1
--
2.5.5