[Arm-dev] [PATCH 08/30] net: thunderx: Add 81xx support to BGX driver

Fri Nov 11 00:03:47 UTC 2016
mohun106 at gmail.com <mohun106 at gmail.com>

From: Sunil Goutham <sgoutham at cavium.com>

This patch adds support for BGX module on 81xx where a BGX
can be split and have different LMACs configured in
different modes.

Signed-off-by: Sunil Goutham <sgoutham at cavium.com>
Signed-off-by: David S. Miller <davem at davemloft.net>
---
 drivers/net/ethernet/cavium/thunder/thunder_bgx.c |  112 +++++++++++++++++++--
 drivers/net/ethernet/cavium/thunder/thunder_bgx.h |   11 ++
 2 files changed, 113 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 93aedfe..64bd880 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -50,6 +50,7 @@ struct bgx {
 	int			lmac_count;
 	void __iomem		*reg_base;
 	struct pci_dev		*pdev;
+	bool                    is_81xx;
 };
 
 static struct bgx *bgx_vnic[MAX_BGX_THUNDER];
@@ -801,9 +802,17 @@ 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 > MAX_LMAC_PER_BGX)
+		return;
 
 	lmac = &bgx->lmac[lmacid];
-	sprintf(str, "BGX%d QLM mode", bgx->bgx_id);
+	dlm = (lmacid / 2) + (bgx->bgx_id * 2);
+	if (!bgx->is_81xx)
+		sprintf(str, "BGX%d QLM mode", bgx->bgx_id);
+	else
+		sprintf(str, "BGX%d DLM%d mode", bgx->bgx_id, dlm);
 
 	switch (lmac->lmac_type) {
 	case BGX_MODE_SGMII:
@@ -855,26 +864,81 @@ static void lmac_set_lane2sds(struct lmac *lmac)
 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;
 
 	lmac = &bgx->lmac[idx];
-	lmac->lmacid = idx;
 
-	/* Read LMAC0 type to figure out QLM mode
-	 * This is configured by low level firmware
+	if (!bgx->is_81xx) {
+		/* Read LMAC0 type to figure out QLM mode
+		 * This is configured by low level firmware
+		 */
+		cmr_cfg = bgx_reg_read(bgx, 0, BGX_CMRX_CFG);
+		lmac->lmac_type = (cmr_cfg >> 8) & 0x07;
+		lmac->use_training =
+			bgx_reg_read(bgx, 0, BGX_SPUX_BR_PMD_CRTL) &
+				SPU_PMD_CRTL_TRAIN_EN;
+		lmac_set_lane2sds(lmac);
+		return;
+	}
+
+	/* On 81xx BGX can be split across 2 DLMs
+	 * firmware programs lmac_type of LMAC0 and LMAC2
 	 */
-	cmr_cfg = bgx_reg_read(bgx, 0, BGX_CMRX_CFG);
-	lmac->lmac_type = (cmr_cfg >> 8) & 0x07;
-	lmac->use_training =
-		bgx_reg_read(bgx, 0, BGX_SPUX_BR_PMD_CRTL) &
+	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->use_training =
+			bgx_reg_read(bgx, idx, BGX_SPUX_BR_PMD_CRTL) &
+				SPU_PMD_CRTL_TRAIN_EN;
+		lmac_set_lane2sds(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;
+		olmac->use_training =
+		bgx_reg_read(bgx, idx + 1, BGX_SPUX_BR_PMD_CRTL) &
 			SPU_PMD_CRTL_TRAIN_EN;
-	lmac_set_lane2sds(lmac);
+		lmac_set_lane2sds(olmac);
+	}
+}
+
+static bool is_dlm0_in_bgx_mode(struct bgx *bgx)
+{
+	struct lmac *lmac;
+
+	if (!bgx->is_81xx)
+		return true;
+
+	lmac = &bgx->lmac[1];
+	if (lmac->lmac_type == BGX_MODE_INVALID)
+		return false;
+
+	return true;
 }
 
 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 */
+	for (idx = 0; idx < MAX_LMAC_PER_BGX; idx++) {
+		lmac = &bgx->lmac[idx];
+		lmac->lmac_type = BGX_MODE_INVALID;
+		lmac->lmacid = idx;
+	}
+
 	/* It is assumed that low level firmware sets this value */
 	bgx->lmac_count = bgx_reg_read(bgx, 0, BGX_CMR_RX_LMACS) & 0x7;
 	if (bgx->lmac_count > MAX_LMAC_PER_BGX)
@@ -882,7 +946,28 @@ static void bgx_get_qlm_mode(struct bgx *bgx)
 
 	for (idx = 0; idx < bgx->lmac_count; idx++)
 		bgx_set_lmac_config(bgx, idx);
-	bgx_print_qlm_mode(bgx, 0);
+
+	if (!bgx->is_81xx) {
+		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;
+	}
 }
 
 #ifdef CONFIG_ACPI
@@ -1057,6 +1142,7 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	struct device *dev = &pdev->dev;
 	struct bgx *bgx = NULL;
 	u8 lmac;
+	u16 sdevid;
 
 	bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL);
 	if (!bgx)
@@ -1078,6 +1164,10 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto err_disable_device;
 	}
 
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdevid);
+	if (sdevid == PCI_SUBSYS_DEVID_81XX_BGX)
+		bgx->is_81xx = true;
+
 	/* MAP configuration registers */
 	bgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
 	if (!bgx->reg_base) {
@@ -1103,6 +1193,8 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		if (err) {
 			dev_err(dev, "BGX%d failed to enable lmac%d\n",
 				bgx->bgx_id, lmac);
+			while (lmac)
+				bgx_lmac_disable(bgx, --lmac);
 			goto err_enable;
 		}
 	}
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
index b7b91c8..38e9fb4 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
@@ -9,6 +9,14 @@
 #ifndef THUNDER_BGX_H
 #define THUNDER_BGX_H
 
+/* PCI device ID */
+#define	PCI_DEVICE_ID_THUNDER_BGX		0xA026
+
+/* Subsystem device IDs */
+#define PCI_SUBSYS_DEVID_88XX_BGX		0xA126
+#define PCI_SUBSYS_DEVID_81XX_BGX		0xA226
+#define PCI_SUBSYS_DEVID_83XX_BGX		0xA326
+
 #define    MAX_BGX_THUNDER			8 /* Max 4 nodes, 2 per node */
 #define    MAX_BGX_PER_CN88XX			2
 #define    MAX_BGX_PER_CN81XX			2
@@ -215,6 +223,9 @@ enum LMAC_TYPE {
 	BGX_MODE_XLAUI = 4, /* 4 lanes, 10.3125 Gbaud */
 	BGX_MODE_10G_KR = 3,/* 1 lane, 10.3125 Gbaud */
 	BGX_MODE_40G_KR = 4,/* 4 lanes, 10.3125 Gbaud */
+	BGX_MODE_RGMII = 5,
+	BGX_MODE_QSGMII = 6,
+	BGX_MODE_INVALID = 7,
 };
 
 #endif /* THUNDER_BGX_H */
-- 
1.7.1