Skip to content

Commit

Permalink
Merge branch 'mlxbf_gige-add-bluefield-3-support'
Browse files Browse the repository at this point in the history
David Thompson says:

====================
mlxbf_gige: add BlueField-3 support

This patch series adds driver logic to the "mlxbf_gige"
Ethernet driver in order to support the third generation
BlueField SoC (BF3).  The existing "mlxbf_gige" driver is
extended with BF3-specific logic and run-time decisions
are made by the driver depending on the SoC generation
(BF2 vs. BF3).

The BF3 SoC is similar to BF2 SoC with regards to transmit
and receive packet processing:
       * Driver rings usage; consumer & producer indices
       * Single queue for receive and transmit
       * DMA operation

The differences between BF3 and BF2 SoC are:
       * In addition to supporting 1Gbps interface speed, the BF3 SoC
         adds support for 10Mbps and 100Mbps interface speeds
       * BF3 requires SerDes config logic to support its SGMII interface
       * BF3 adds support for "ethtool -s" for interface speed config
       * BF3 utilizes different MDIO logic for accessing the
         board-level PHY device

Testing
  - Successful build of kernel for ARM64, ARM32, X86_64
  - Tested ARM64 build on FastModels, Palladium, SoC
====================

Link: https://lore.kernel.org/r/20230112202609.21331-1-davthompson@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Jan 14, 2023
2 parents e2a9575 + e1cc8ce commit 298bfe2
Showing 7 changed files with 372 additions and 66 deletions.
27 changes: 27 additions & 0 deletions drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
#include <linux/irqreturn.h>
#include <linux/netdevice.h>
#include <linux/irq.h>
#include <linux/phy.h>

/* The silicon design supports a maximum RX ring size of
* 32K entries. Based on current testing this maximum size
@@ -67,6 +68,29 @@ struct mlxbf_gige_stats {
u64 rx_filter_discard_pkts;
};

struct mlxbf_gige_reg_param {
u32 mask;
u32 shift;
};

struct mlxbf_gige_mdio_gw {
u32 gw_address;
u32 read_data_address;
struct mlxbf_gige_reg_param busy;
struct mlxbf_gige_reg_param write_data;
struct mlxbf_gige_reg_param read_data;
struct mlxbf_gige_reg_param devad;
struct mlxbf_gige_reg_param partad;
struct mlxbf_gige_reg_param opcode;
struct mlxbf_gige_reg_param st1;
};

struct mlxbf_gige_link_cfg {
void (*set_phy_link_mode)(struct phy_device *phydev);
void (*adjust_link)(struct net_device *netdev);
phy_interface_t phy_mode;
};

struct mlxbf_gige {
void __iomem *base;
void __iomem *llu_base;
@@ -102,6 +126,9 @@ struct mlxbf_gige {
u8 valid_polarity;
struct napi_struct napi;
struct mlxbf_gige_stats stats;
u8 hw_version;
struct mlxbf_gige_mdio_gw *mdio_gw;
int prev_speed;
};

/* Rx Work Queue Element definitions */
Original file line number Diff line number Diff line change
@@ -135,4 +135,5 @@ const struct ethtool_ops mlxbf_gige_ethtool_ops = {
.nway_reset = phy_ethtool_nway_reset,
.get_pauseparam = mlxbf_gige_get_pauseparam,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
109 changes: 93 additions & 16 deletions drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
Original file line number Diff line number Diff line change
@@ -205,7 +205,7 @@ static int mlxbf_gige_stop(struct net_device *netdev)
}

static int mlxbf_gige_eth_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd)
struct ifreq *ifr, int cmd)
{
if (!(netif_running(netdev)))
return -EINVAL;
@@ -263,13 +263,99 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = {
.ndo_get_stats64 = mlxbf_gige_get_stats64,
};

static void mlxbf_gige_adjust_link(struct net_device *netdev)
static void mlxbf_gige_bf2_adjust_link(struct net_device *netdev)
{
struct phy_device *phydev = netdev->phydev;

phy_print_status(phydev);
}

static void mlxbf_gige_bf3_adjust_link(struct net_device *netdev)
{
struct mlxbf_gige *priv = netdev_priv(netdev);
struct phy_device *phydev = netdev->phydev;
u8 sgmii_mode;
u16 ipg_size;
u32 val;

if (phydev->link && phydev->speed != priv->prev_speed) {
switch (phydev->speed) {
case 1000:
ipg_size = MLXBF_GIGE_1G_IPG_SIZE;
sgmii_mode = MLXBF_GIGE_1G_SGMII_MODE;
break;
case 100:
ipg_size = MLXBF_GIGE_100M_IPG_SIZE;
sgmii_mode = MLXBF_GIGE_100M_SGMII_MODE;
break;
case 10:
ipg_size = MLXBF_GIGE_10M_IPG_SIZE;
sgmii_mode = MLXBF_GIGE_10M_SGMII_MODE;
break;
default:
return;
}

val = readl(priv->plu_base + MLXBF_GIGE_PLU_TX_REG0);
val &= ~(MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK | MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK);
val |= FIELD_PREP(MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK, ipg_size);
val |= FIELD_PREP(MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK, sgmii_mode);
writel(val, priv->plu_base + MLXBF_GIGE_PLU_TX_REG0);

val = readl(priv->plu_base + MLXBF_GIGE_PLU_RX_REG0);
val &= ~MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK;
val |= FIELD_PREP(MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK, sgmii_mode);
writel(val, priv->plu_base + MLXBF_GIGE_PLU_RX_REG0);

priv->prev_speed = phydev->speed;
}

phy_print_status(phydev);
}

static void mlxbf_gige_bf2_set_phy_link_mode(struct phy_device *phydev)
{
/* MAC only supports 1000T full duplex mode */
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);

/* Only symmetric pause with flow control enabled is supported so no
* need to negotiate pause.
*/
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
}

static void mlxbf_gige_bf3_set_phy_link_mode(struct phy_device *phydev)
{
/* MAC only supports full duplex mode */
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);

/* Only symmetric pause with flow control enabled is supported so no
* need to negotiate pause.
*/
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
}

static struct mlxbf_gige_link_cfg mlxbf_gige_link_cfgs[] = {
[MLXBF_GIGE_VERSION_BF2] = {
.set_phy_link_mode = mlxbf_gige_bf2_set_phy_link_mode,
.adjust_link = mlxbf_gige_bf2_adjust_link,
.phy_mode = PHY_INTERFACE_MODE_GMII
},
[MLXBF_GIGE_VERSION_BF3] = {
.set_phy_link_mode = mlxbf_gige_bf3_set_phy_link_mode,
.adjust_link = mlxbf_gige_bf3_adjust_link,
.phy_mode = PHY_INTERFACE_MODE_SGMII
}
};

static int mlxbf_gige_probe(struct platform_device *pdev)
{
struct phy_device *phydev;
@@ -315,6 +401,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev)

spin_lock_init(&priv->lock);

priv->hw_version = readq(base + MLXBF_GIGE_VERSION);

/* Attach MDIO device */
err = mlxbf_gige_mdio_probe(pdev, priv);
if (err)
@@ -357,25 +445,14 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
phydev->irq = phy_irq;

err = phy_connect_direct(netdev, phydev,
mlxbf_gige_adjust_link,
PHY_INTERFACE_MODE_GMII);
mlxbf_gige_link_cfgs[priv->hw_version].adjust_link,
mlxbf_gige_link_cfgs[priv->hw_version].phy_mode);
if (err) {
dev_err(&pdev->dev, "Could not attach to PHY\n");
goto out;
}

/* MAC only supports 1000T full duplex mode */
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);

/* Only symmetric pause with flow control enabled is supported so no
* need to negotiate pause.
*/
linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
mlxbf_gige_link_cfgs[priv->hw_version].set_phy_link_mode(phydev);

/* Display information about attached PHY device */
phy_attached_info(phydev);
Loading

0 comments on commit 298bfe2

Please sign in to comment.