diff options
author | Sunil Goutham <sgoutham@cavium.com> | 2016-08-12 14:21:33 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-08-13 21:59:31 +0300 |
commit | 6465859aba1e66a5351b047fbf40e9e9bcb6c669 (patch) | |
tree | 4c7d1dc87d7b1f115440969e8f6067df9e7951a2 /drivers/net/ethernet/cavium/thunder/thunder_bgx.c | |
parent | 3f8057cfe8adc12bd272fe2c67e3c9ab9cff0a12 (diff) | |
download | linux-6465859aba1e66a5351b047fbf40e9e9bcb6c669.tar.xz |
net: thunderx: Add RGMII interface type support
This patch adds RGX/RGMII interface type support to BGX
driver. This type of interface is supported by 81xx SOC.
CN81XX VNIC has 8 VFs and max possible LMAC interfaces are 9,
hence RGMII interface will not work if all DLMs are in BGX mode
and all 8 LMACs are enabled
Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/cavium/thunder/thunder_bgx.c')
-rw-r--r-- | drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 97 |
1 files changed, 69 insertions, 28 deletions
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 0bf8d244185b..4ddc760afe03 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -48,9 +48,11 @@ struct bgx { u8 bgx_id; struct lmac lmac[MAX_LMAC_PER_BGX]; int lmac_count; + u8 max_lmac; void __iomem *reg_base; struct pci_dev *pdev; bool is_81xx; + bool is_rgx; }; static struct bgx *bgx_vnic[MAX_BGX_THUNDER]; @@ -61,6 +63,7 @@ static int bgx_xaui_check_link(struct lmac *lmac); /* Supported devices */ static const struct pci_device_id bgx_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_BGX) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_RGX) }, { 0, } /* end of table */ }; @@ -124,7 +127,7 @@ unsigned bgx_get_map(int node) int i; unsigned map = 0; - for (i = 0; i < MAX_BGX_PER_CN88XX; i++) { + for (i = 0; i < MAX_BGX_PER_CN81XX; i++) { if (bgx_vnic[(node * MAX_BGX_PER_CN88XX) + i]) map |= (1 << i); } @@ -189,10 +192,12 @@ 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_CN88XX) + bgx_idx]; + struct lmac *lmac; u64 cfg; if (!bgx) return; + lmac = &bgx->lmac[lmacid]; cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG); if (enable) @@ -200,6 +205,9 @@ void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable) else cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN); bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg); + + if (bgx->is_rgx) + xcv_setup_link(enable ? lmac->link_up : 0, lmac->last_speed); } EXPORT_SYMBOL(bgx_lmac_rx_tx_enable); @@ -266,9 +274,12 @@ static void bgx_sgmii_change_link_state(struct lmac *lmac) port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG); - /* renable lmac */ + /* Re-enable lmac */ cmr_cfg |= CMR_EN; bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg); + + if (bgx->is_rgx && (cmr_cfg & (CMR_PKT_RX_EN | CMR_PKT_TX_EN))) + xcv_setup_link(lmac->link_up, lmac->last_speed); } static void bgx_lmac_handler(struct net_device *netdev) @@ -418,10 +429,12 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) return 0; } - 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"); - return -1; + if (lmac->lmac_type == BGX_MODE_SGMII) { + 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"); + return -1; + } } return 0; @@ -663,6 +676,8 @@ static int phy_interface_mode(u8 lmac_type) { if (lmac_type == BGX_MODE_QSGMII) return PHY_INTERFACE_MODE_QSGMII; + if (lmac_type == BGX_MODE_RGMII) + return PHY_INTERFACE_MODE_RGMII; return PHY_INTERFACE_MODE_SGMII; } @@ -676,7 +691,8 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) lmac->bgx = bgx; if ((lmac->lmac_type == BGX_MODE_SGMII) || - (lmac->lmac_type == BGX_MODE_QSGMII)) { + (lmac->lmac_type == BGX_MODE_QSGMII) || + (lmac->lmac_type == BGX_MODE_RGMII)) { lmac->is_sgmii = 1; if (bgx_lmac_sgmii_init(bgx, lmac)) return -1; @@ -829,7 +845,7 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid) char str[20]; u8 dlm; - if (lmacid > MAX_LMAC_PER_BGX) + if (lmacid > bgx->max_lmac) return; lmac = &bgx->lmac[lmacid]; @@ -870,6 +886,9 @@ static void bgx_print_qlm_mode(struct bgx *bgx, u8 lmacid) return; dev_info(dev, "%s: QSGMII\n", (char *)str); break; + case BGX_MODE_RGMII: + dev_info(dev, "%s: RGMII\n", (char *)str); + break; case BGX_MODE_INVALID: /* Nothing to do */ break; @@ -885,6 +904,7 @@ static void lmac_set_lane2sds(struct bgx *bgx, struct lmac *lmac) break; case BGX_MODE_XAUI: case BGX_MODE_XLAUI: + case BGX_MODE_RGMII: lmac->lane_to_sds = 0xE4; break; case BGX_MODE_RXAUI: @@ -904,6 +924,18 @@ static void lmac_set_lane2sds(struct bgx *bgx, struct lmac *lmac) } } +static void lmac_set_training(struct bgx *bgx, struct lmac *lmac, int lmacid) +{ + if ((lmac->lmac_type != BGX_MODE_10G_KR) && + (lmac->lmac_type != BGX_MODE_40G_KR)) { + lmac->use_training = 0; + return; + } + + lmac->use_training = bgx_reg_read(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL) & + SPU_PMD_CRTL_TRAIN_EN; +} + static void bgx_set_lmac_config(struct bgx *bgx, u8 idx) { struct lmac *lmac; @@ -914,15 +946,15 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx) lmac = &bgx->lmac[idx]; - if (!bgx->is_81xx) { + if (!bgx->is_81xx || bgx->is_rgx) { /* 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; + if (bgx->is_rgx) + lmac->lmac_type = BGX_MODE_RGMII; + lmac_set_training(bgx, lmac, 0); lmac_set_lane2sds(bgx, lmac); return; } @@ -939,17 +971,13 @@ static void bgx_set_lmac_config(struct bgx *bgx, u8 idx) 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_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; - olmac->use_training = - bgx_reg_read(bgx, idx + 1, BGX_SPUX_BR_PMD_CRTL) & - SPU_PMD_CRTL_TRAIN_EN; + lmac_set_training(bgx, olmac, olmac->lmacid); lmac_set_lane2sds(bgx, olmac); } } @@ -976,21 +1004,22 @@ static void bgx_get_qlm_mode(struct bgx *bgx) u8 idx; /* Init all LMAC's type to invalid */ - for (idx = 0; idx < MAX_LMAC_PER_BGX; idx++) { + for (idx = 0; idx < bgx->max_lmac; idx++) { lmac = &bgx->lmac[idx]; - lmac->lmac_type = BGX_MODE_INVALID; lmac->lmacid = idx; + lmac->lmac_type = BGX_MODE_INVALID; + lmac->use_training = false; } /* 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) - bgx->lmac_count = MAX_LMAC_PER_BGX; + if (bgx->lmac_count > bgx->max_lmac) + bgx->lmac_count = bgx->max_lmac; - for (idx = 0; idx < MAX_LMAC_PER_BGX; idx++) + for (idx = 0; idx < bgx->max_lmac; idx++) bgx_set_lmac_config(bgx, idx); - if (!bgx->is_81xx) { + if (!bgx->is_81xx || bgx->is_rgx) { bgx_print_qlm_mode(bgx, 0); return; } @@ -1140,7 +1169,7 @@ static int bgx_init_of_phy(struct bgx *bgx) } lmac++; - if (lmac == MAX_LMAC_PER_BGX) { + if (lmac == bgx->max_lmac) { of_node_put(node); break; } @@ -1218,10 +1247,22 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto err_release_regions; } - bgx->bgx_id = (pci_resource_start(pdev, PCI_CFG_REG_BAR_NUM) >> 24) & 1; - bgx->bgx_id += nic_get_node_id(pdev) * MAX_BGX_PER_CN88XX; - bgx_vnic[bgx->bgx_id] = bgx; + 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) & 1; + bgx->bgx_id += nic_get_node_id(pdev) * MAX_BGX_PER_CN88XX; + bgx->max_lmac = MAX_LMAC_PER_BGX; + bgx_vnic[bgx->bgx_id] = bgx; + } else { + bgx->is_rgx = true; + bgx->max_lmac = 1; + bgx->bgx_id = MAX_BGX_PER_CN81XX - 1; + bgx_vnic[bgx->bgx_id] = bgx; + xcv_init_hw(); + } + bgx_get_qlm_mode(bgx); err = bgx_init_phy(bgx); |