Commit 57aaf63c authored by Sunil Goutham's avatar Sunil Goutham Committed by David S. Miller

net: thunderx: Add 81xx support to BGX driver

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: default avatarSunil Goutham <sgoutham@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0bcb7d51
...@@ -50,6 +50,7 @@ struct bgx { ...@@ -50,6 +50,7 @@ struct bgx {
int lmac_count; int lmac_count;
void __iomem *reg_base; void __iomem *reg_base;
struct pci_dev *pdev; struct pci_dev *pdev;
bool is_81xx;
}; };
static struct bgx *bgx_vnic[MAX_BGX_THUNDER]; static struct bgx *bgx_vnic[MAX_BGX_THUNDER];
...@@ -803,9 +804,17 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid) ...@@ -803,9 +804,17 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid)
struct device *dev = &bgx->pdev->dev; struct device *dev = &bgx->pdev->dev;
struct lmac *lmac; struct lmac *lmac;
char str[20]; char str[20];
u8 dlm;
if (lmacid > MAX_LMAC_PER_BGX)
return;
lmac = &bgx->lmac[lmacid]; lmac = &bgx->lmac[lmacid];
dlm = (lmacid / 2) + (bgx->bgx_id * 2);
if (!bgx->is_81xx)
sprintf(str, "BGX%d QLM mode", bgx->bgx_id); 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) { switch (lmac->lmac_type) {
case BGX_MODE_SGMII: case BGX_MODE_SGMII:
...@@ -857,11 +866,14 @@ static void lmac_set_lane2sds(struct lmac *lmac) ...@@ -857,11 +866,14 @@ static void lmac_set_lane2sds(struct lmac *lmac)
static void bgx_set_lmac_config(struct bgx *bgx, u8 idx) static void bgx_set_lmac_config(struct bgx *bgx, u8 idx)
{ {
struct lmac *lmac; struct lmac *lmac;
struct lmac *olmac;
u64 cmr_cfg; u64 cmr_cfg;
u8 lmac_type;
u8 lane_to_sds;
lmac = &bgx->lmac[idx]; lmac = &bgx->lmac[idx];
lmac->lmacid = idx;
if (!bgx->is_81xx) {
/* Read LMAC0 type to figure out QLM mode /* Read LMAC0 type to figure out QLM mode
* This is configured by low level firmware * This is configured by low level firmware
*/ */
...@@ -871,12 +883,64 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx) ...@@ -871,12 +883,64 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx)
bgx_reg_read(bgx, 0, BGX_SPUX_BR_PMD_CRTL) & bgx_reg_read(bgx, 0, BGX_SPUX_BR_PMD_CRTL) &
SPU_PMD_CRTL_TRAIN_EN; SPU_PMD_CRTL_TRAIN_EN;
lmac_set_lane2sds(lmac); lmac_set_lane2sds(lmac);
return;
}
/* On 81xx BGX can be split across 2 DLMs
* firmware programs lmac_type of LMAC0 and LMAC2
*/
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(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) static void bgx_get_qlm_mode(struct bgx *bgx)
{ {
struct lmac *lmac;
struct lmac *lmac01;
struct lmac *lmac23;
u8 idx; 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 */ /* It is assumed that low level firmware sets this value */
bgx->lmac_count = bgx_reg_read(bgx, 0, BGX_CMR_RX_LMACS) & 0x7; bgx->lmac_count = bgx_reg_read(bgx, 0, BGX_CMR_RX_LMACS) & 0x7;
if (bgx->lmac_count > MAX_LMAC_PER_BGX) if (bgx->lmac_count > MAX_LMAC_PER_BGX)
...@@ -884,7 +948,28 @@ static void bgx_get_qlm_mode(struct bgx *bgx) ...@@ -884,7 +948,28 @@ static void bgx_get_qlm_mode(struct bgx *bgx)
for (idx = 0; idx < bgx->lmac_count; idx++) for (idx = 0; idx < bgx->lmac_count; idx++)
bgx_set_lmac_config(bgx, idx); bgx_set_lmac_config(bgx, idx);
if (!bgx->is_81xx) {
bgx_print_qlm_mode(bgx, 0); 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 #ifdef CONFIG_ACPI
...@@ -1059,6 +1144,7 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1059,6 +1144,7 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct bgx *bgx = NULL; struct bgx *bgx = NULL;
u8 lmac; u8 lmac;
u16 sdevid;
bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL); bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL);
if (!bgx) if (!bgx)
...@@ -1080,6 +1166,10 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1080,6 +1166,10 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_disable_device; 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 */ /* MAP configuration registers */
bgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); bgx->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0);
if (!bgx->reg_base) { if (!bgx->reg_base) {
...@@ -1105,6 +1195,8 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1105,6 +1195,8 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err) { if (err) {
dev_err(dev, "BGX%d failed to enable lmac%d\n", dev_err(dev, "BGX%d failed to enable lmac%d\n",
bgx->bgx_id, lmac); bgx->bgx_id, lmac);
while (lmac)
bgx_lmac_disable(bgx, --lmac);
goto err_enable; goto err_enable;
} }
} }
......
...@@ -9,6 +9,14 @@ ...@@ -9,6 +9,14 @@
#ifndef THUNDER_BGX_H #ifndef THUNDER_BGX_H
#define 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_THUNDER 8 /* Max 4 nodes, 2 per node */
#define MAX_BGX_PER_CN88XX 2 #define MAX_BGX_PER_CN88XX 2
#define MAX_BGX_PER_CN81XX 2 #define MAX_BGX_PER_CN81XX 2
...@@ -215,6 +223,9 @@ enum LMAC_TYPE { ...@@ -215,6 +223,9 @@ enum LMAC_TYPE {
BGX_MODE_XLAUI = 4, /* 4 lanes, 10.3125 Gbaud */ BGX_MODE_XLAUI = 4, /* 4 lanes, 10.3125 Gbaud */
BGX_MODE_10G_KR = 3,/* 1 lane, 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_40G_KR = 4,/* 4 lanes, 10.3125 Gbaud */
BGX_MODE_RGMII = 5,
BGX_MODE_QSGMII = 6,
BGX_MODE_INVALID = 7,
}; };
#endif /* THUNDER_BGX_H */ #endif /* THUNDER_BGX_H */
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