cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mlxbf_gige_mdio.c (5400B)


      1// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
      2
      3/* MDIO support for Mellanox Gigabit Ethernet driver
      4 *
      5 * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
      6 */
      7
      8#include <linux/acpi.h>
      9#include <linux/bitfield.h>
     10#include <linux/delay.h>
     11#include <linux/device.h>
     12#include <linux/err.h>
     13#include <linux/io.h>
     14#include <linux/iopoll.h>
     15#include <linux/ioport.h>
     16#include <linux/irqreturn.h>
     17#include <linux/jiffies.h>
     18#include <linux/module.h>
     19#include <linux/mod_devicetable.h>
     20#include <linux/phy.h>
     21#include <linux/platform_device.h>
     22#include <linux/property.h>
     23
     24#include "mlxbf_gige.h"
     25
     26#define MLXBF_GIGE_MDIO_GW_OFFSET	0x0
     27#define MLXBF_GIGE_MDIO_CFG_OFFSET	0x4
     28
     29/* Support clause 22 */
     30#define MLXBF_GIGE_MDIO_CL22_ST1	0x1
     31#define MLXBF_GIGE_MDIO_CL22_WRITE	0x1
     32#define MLXBF_GIGE_MDIO_CL22_READ	0x2
     33
     34/* Busy bit is set by software and cleared by hardware */
     35#define MLXBF_GIGE_MDIO_SET_BUSY	0x1
     36
     37/* MDIO GW register bits */
     38#define MLXBF_GIGE_MDIO_GW_AD_MASK	GENMASK(15, 0)
     39#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK	GENMASK(20, 16)
     40#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK	GENMASK(25, 21)
     41#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK	GENMASK(27, 26)
     42#define MLXBF_GIGE_MDIO_GW_ST1_MASK	GENMASK(28, 28)
     43#define MLXBF_GIGE_MDIO_GW_BUSY_MASK	GENMASK(30, 30)
     44
     45/* MDIO config register bits */
     46#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK		GENMASK(1, 0)
     47#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK		GENMASK(2, 2)
     48#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK	GENMASK(4, 4)
     49#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK		GENMASK(15, 8)
     50#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK		GENMASK(23, 16)
     51#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK		GENMASK(31, 24)
     52
     53/* Formula for encoding the MDIO period. The encoded value is
     54 * passed to the MDIO config register.
     55 *
     56 * mdc_clk = 2*(val + 1)*i1clk
     57 *
     58 * 400 ns = 2*(val + 1)*(((1/430)*1000) ns)
     59 *
     60 * val = (((400 * 430 / 1000) / 2) - 1)
     61 */
     62#define MLXBF_GIGE_I1CLK_MHZ		430
     63#define MLXBF_GIGE_MDC_CLK_NS		400
     64
     65#define MLXBF_GIGE_MDIO_PERIOD	(((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1)
     66
     67#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
     68				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
     69				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
     70				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \
     71					    MLXBF_GIGE_MDIO_PERIOD) | \
     72				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
     73				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
     74
     75static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
     76				      int phy_reg, u32 opcode)
     77{
     78	u32 gw_reg = 0;
     79
     80	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data);
     81	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg);
     82	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add);
     83	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode);
     84	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK,
     85			     MLXBF_GIGE_MDIO_CL22_ST1);
     86	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK,
     87			     MLXBF_GIGE_MDIO_SET_BUSY);
     88
     89	return gw_reg;
     90}
     91
     92static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg)
     93{
     94	struct mlxbf_gige *priv = bus->priv;
     95	u32 cmd;
     96	int ret;
     97	u32 val;
     98
     99	if (phy_reg & MII_ADDR_C45)
    100		return -EOPNOTSUPP;
    101
    102	/* Send mdio read request */
    103	cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ);
    104
    105	writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
    106
    107	ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
    108					val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK),
    109					5, 1000000);
    110
    111	if (ret) {
    112		writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
    113		return ret;
    114	}
    115
    116	ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
    117	/* Only return ad bits of the gw register */
    118	ret &= MLXBF_GIGE_MDIO_GW_AD_MASK;
    119
    120	return ret;
    121}
    122
    123static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
    124				 int phy_reg, u16 val)
    125{
    126	struct mlxbf_gige *priv = bus->priv;
    127	u32 cmd;
    128	int ret;
    129	u32 temp;
    130
    131	if (phy_reg & MII_ADDR_C45)
    132		return -EOPNOTSUPP;
    133
    134	/* Send mdio write request */
    135	cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg,
    136					 MLXBF_GIGE_MDIO_CL22_WRITE);
    137	writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
    138
    139	/* If the poll timed out, drop the request */
    140	ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
    141					temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK),
    142					5, 1000000);
    143
    144	return ret;
    145}
    146
    147int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
    148{
    149	struct device *dev = &pdev->dev;
    150	int ret;
    151
    152	priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9);
    153	if (IS_ERR(priv->mdio_io))
    154		return PTR_ERR(priv->mdio_io);
    155
    156	/* Configure mdio parameters */
    157	writel(MLXBF_GIGE_MDIO_CFG_VAL,
    158	       priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
    159
    160	priv->mdiobus = devm_mdiobus_alloc(dev);
    161	if (!priv->mdiobus) {
    162		dev_err(dev, "Failed to alloc MDIO bus\n");
    163		return -ENOMEM;
    164	}
    165
    166	priv->mdiobus->name = "mlxbf-mdio";
    167	priv->mdiobus->read = mlxbf_gige_mdio_read;
    168	priv->mdiobus->write = mlxbf_gige_mdio_write;
    169	priv->mdiobus->parent = dev;
    170	priv->mdiobus->priv = priv;
    171	snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s",
    172		 dev_name(dev));
    173
    174	ret = mdiobus_register(priv->mdiobus);
    175	if (ret)
    176		dev_err(dev, "Failed to register MDIO bus\n");
    177
    178	return ret;
    179}
    180
    181void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv)
    182{
    183	mdiobus_unregister(priv->mdiobus);
    184}