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

mvmdio.c (11815B)


      1/*
      2 * Driver for the MDIO interface of Marvell network interfaces.
      3 *
      4 * Since the MDIO interface of Marvell network interfaces is shared
      5 * between all network interfaces, having a single driver allows to
      6 * handle concurrent accesses properly (you may have four Ethernet
      7 * ports, but they in fact share the same SMI interface to access
      8 * the MDIO bus). This driver is currently used by the mvneta and
      9 * mv643xx_eth drivers.
     10 *
     11 * Copyright (C) 2012 Marvell
     12 *
     13 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
     14 *
     15 * This file is licensed under the terms of the GNU General Public
     16 * License version 2. This program is licensed "as is" without any
     17 * warranty of any kind, whether express or implied.
     18 */
     19
     20#include <linux/acpi.h>
     21#include <linux/acpi_mdio.h>
     22#include <linux/clk.h>
     23#include <linux/delay.h>
     24#include <linux/interrupt.h>
     25#include <linux/io.h>
     26#include <linux/kernel.h>
     27#include <linux/module.h>
     28#include <linux/of_device.h>
     29#include <linux/of_mdio.h>
     30#include <linux/phy.h>
     31#include <linux/platform_device.h>
     32#include <linux/sched.h>
     33#include <linux/wait.h>
     34
     35#define MVMDIO_SMI_DATA_SHIFT		0
     36#define MVMDIO_SMI_PHY_ADDR_SHIFT	16
     37#define MVMDIO_SMI_PHY_REG_SHIFT	21
     38#define MVMDIO_SMI_READ_OPERATION	BIT(26)
     39#define MVMDIO_SMI_WRITE_OPERATION	0
     40#define MVMDIO_SMI_READ_VALID		BIT(27)
     41#define MVMDIO_SMI_BUSY			BIT(28)
     42#define MVMDIO_ERR_INT_CAUSE		0x007C
     43#define  MVMDIO_ERR_INT_SMI_DONE	0x00000010
     44#define MVMDIO_ERR_INT_MASK		0x0080
     45
     46#define MVMDIO_XSMI_MGNT_REG		0x0
     47#define  MVMDIO_XSMI_PHYADDR_SHIFT	16
     48#define  MVMDIO_XSMI_DEVADDR_SHIFT	21
     49#define  MVMDIO_XSMI_WRITE_OPERATION	(0x5 << 26)
     50#define  MVMDIO_XSMI_READ_OPERATION	(0x7 << 26)
     51#define  MVMDIO_XSMI_READ_VALID		BIT(29)
     52#define  MVMDIO_XSMI_BUSY		BIT(30)
     53#define MVMDIO_XSMI_ADDR_REG		0x8
     54
     55/*
     56 * SMI Timeout measurements:
     57 * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
     58 * - Armada 370       (Globalscale Mirabox):   41us to 43us (Polled)
     59 */
     60#define MVMDIO_SMI_TIMEOUT		1000 /* 1000us = 1ms */
     61#define MVMDIO_SMI_POLL_INTERVAL_MIN	45
     62#define MVMDIO_SMI_POLL_INTERVAL_MAX	55
     63
     64#define MVMDIO_XSMI_POLL_INTERVAL_MIN	150
     65#define MVMDIO_XSMI_POLL_INTERVAL_MAX	160
     66
     67struct orion_mdio_dev {
     68	void __iomem *regs;
     69	struct clk *clk[4];
     70	/*
     71	 * If we have access to the error interrupt pin (which is
     72	 * somewhat misnamed as it not only reflects internal errors
     73	 * but also reflects SMI completion), use that to wait for
     74	 * SMI access completion instead of polling the SMI busy bit.
     75	 */
     76	int err_interrupt;
     77	wait_queue_head_t smi_busy_wait;
     78};
     79
     80enum orion_mdio_bus_type {
     81	BUS_TYPE_SMI,
     82	BUS_TYPE_XSMI
     83};
     84
     85struct orion_mdio_ops {
     86	int (*is_done)(struct orion_mdio_dev *);
     87	unsigned int poll_interval_min;
     88	unsigned int poll_interval_max;
     89};
     90
     91/* Wait for the SMI unit to be ready for another operation
     92 */
     93static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
     94				 struct mii_bus *bus)
     95{
     96	struct orion_mdio_dev *dev = bus->priv;
     97	unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
     98	unsigned long end = jiffies + timeout;
     99	int timedout = 0;
    100
    101	while (1) {
    102	        if (ops->is_done(dev))
    103			return 0;
    104	        else if (timedout)
    105			break;
    106
    107	        if (dev->err_interrupt <= 0) {
    108			usleep_range(ops->poll_interval_min,
    109				     ops->poll_interval_max);
    110
    111			if (time_is_before_jiffies(end))
    112				++timedout;
    113	        } else {
    114			/* wait_event_timeout does not guarantee a delay of at
    115			 * least one whole jiffie, so timeout must be no less
    116			 * than two.
    117			 */
    118			if (timeout < 2)
    119				timeout = 2;
    120			wait_event_timeout(dev->smi_busy_wait,
    121				           ops->is_done(dev), timeout);
    122
    123			++timedout;
    124	        }
    125	}
    126
    127	dev_err(bus->parent, "Timeout: SMI busy for too long\n");
    128	return  -ETIMEDOUT;
    129}
    130
    131static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
    132{
    133	return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
    134}
    135
    136static const struct orion_mdio_ops orion_mdio_smi_ops = {
    137	.is_done = orion_mdio_smi_is_done,
    138	.poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN,
    139	.poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
    140};
    141
    142static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
    143			       int regnum)
    144{
    145	struct orion_mdio_dev *dev = bus->priv;
    146	u32 val;
    147	int ret;
    148
    149	if (regnum & MII_ADDR_C45)
    150		return -EOPNOTSUPP;
    151
    152	ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
    153	if (ret < 0)
    154		return ret;
    155
    156	writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
    157		(regnum << MVMDIO_SMI_PHY_REG_SHIFT)  |
    158		MVMDIO_SMI_READ_OPERATION),
    159	       dev->regs);
    160
    161	ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
    162	if (ret < 0)
    163		return ret;
    164
    165	val = readl(dev->regs);
    166	if (!(val & MVMDIO_SMI_READ_VALID)) {
    167		dev_err(bus->parent, "SMI bus read not valid\n");
    168		return -ENODEV;
    169	}
    170
    171	return val & GENMASK(15, 0);
    172}
    173
    174static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id,
    175				int regnum, u16 value)
    176{
    177	struct orion_mdio_dev *dev = bus->priv;
    178	int ret;
    179
    180	if (regnum & MII_ADDR_C45)
    181		return -EOPNOTSUPP;
    182
    183	ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
    184	if (ret < 0)
    185		return ret;
    186
    187	writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
    188		(regnum << MVMDIO_SMI_PHY_REG_SHIFT)  |
    189		MVMDIO_SMI_WRITE_OPERATION            |
    190		(value << MVMDIO_SMI_DATA_SHIFT)),
    191	       dev->regs);
    192
    193	return 0;
    194}
    195
    196static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
    197{
    198	return !(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & MVMDIO_XSMI_BUSY);
    199}
    200
    201static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
    202	.is_done = orion_mdio_xsmi_is_done,
    203	.poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN,
    204	.poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX,
    205};
    206
    207static int orion_mdio_xsmi_read(struct mii_bus *bus, int mii_id,
    208				int regnum)
    209{
    210	struct orion_mdio_dev *dev = bus->priv;
    211	u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
    212	int ret;
    213
    214	if (!(regnum & MII_ADDR_C45))
    215		return -EOPNOTSUPP;
    216
    217	ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
    218	if (ret < 0)
    219		return ret;
    220
    221	writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
    222	writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
    223	       (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
    224	       MVMDIO_XSMI_READ_OPERATION,
    225	       dev->regs + MVMDIO_XSMI_MGNT_REG);
    226
    227	ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
    228	if (ret < 0)
    229		return ret;
    230
    231	if (!(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) &
    232	      MVMDIO_XSMI_READ_VALID)) {
    233		dev_err(bus->parent, "XSMI bus read not valid\n");
    234		return -ENODEV;
    235	}
    236
    237	return readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
    238}
    239
    240static int orion_mdio_xsmi_write(struct mii_bus *bus, int mii_id,
    241				int regnum, u16 value)
    242{
    243	struct orion_mdio_dev *dev = bus->priv;
    244	u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
    245	int ret;
    246
    247	if (!(regnum & MII_ADDR_C45))
    248		return -EOPNOTSUPP;
    249
    250	ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
    251	if (ret < 0)
    252		return ret;
    253
    254	writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
    255	writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
    256	       (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
    257	       MVMDIO_XSMI_WRITE_OPERATION | value,
    258	       dev->regs + MVMDIO_XSMI_MGNT_REG);
    259
    260	return 0;
    261}
    262
    263static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
    264{
    265	struct orion_mdio_dev *dev = dev_id;
    266
    267	if (readl(dev->regs + MVMDIO_ERR_INT_CAUSE) &
    268			MVMDIO_ERR_INT_SMI_DONE) {
    269		writel(~MVMDIO_ERR_INT_SMI_DONE,
    270				dev->regs + MVMDIO_ERR_INT_CAUSE);
    271		wake_up(&dev->smi_busy_wait);
    272		return IRQ_HANDLED;
    273	}
    274
    275	return IRQ_NONE;
    276}
    277
    278static int orion_mdio_probe(struct platform_device *pdev)
    279{
    280	enum orion_mdio_bus_type type;
    281	struct resource *r;
    282	struct mii_bus *bus;
    283	struct orion_mdio_dev *dev;
    284	int i, ret;
    285
    286	type = (enum orion_mdio_bus_type)device_get_match_data(&pdev->dev);
    287
    288	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    289	if (!r) {
    290		dev_err(&pdev->dev, "No SMI register address given\n");
    291		return -ENODEV;
    292	}
    293
    294	bus = devm_mdiobus_alloc_size(&pdev->dev,
    295				      sizeof(struct orion_mdio_dev));
    296	if (!bus)
    297		return -ENOMEM;
    298
    299	switch (type) {
    300	case BUS_TYPE_SMI:
    301		bus->read = orion_mdio_smi_read;
    302		bus->write = orion_mdio_smi_write;
    303		break;
    304	case BUS_TYPE_XSMI:
    305		bus->read = orion_mdio_xsmi_read;
    306		bus->write = orion_mdio_xsmi_write;
    307		break;
    308	}
    309
    310	bus->name = "orion_mdio_bus";
    311	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
    312		 dev_name(&pdev->dev));
    313	bus->parent = &pdev->dev;
    314
    315	dev = bus->priv;
    316	dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
    317	if (!dev->regs) {
    318		dev_err(&pdev->dev, "Unable to remap SMI register\n");
    319		return -ENODEV;
    320	}
    321
    322	init_waitqueue_head(&dev->smi_busy_wait);
    323
    324	if (pdev->dev.of_node) {
    325		for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
    326			dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
    327			if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
    328				ret = -EPROBE_DEFER;
    329				goto out_clk;
    330			}
    331			if (IS_ERR(dev->clk[i]))
    332				break;
    333			clk_prepare_enable(dev->clk[i]);
    334		}
    335
    336		if (!IS_ERR(of_clk_get(pdev->dev.of_node,
    337				       ARRAY_SIZE(dev->clk))))
    338			dev_warn(&pdev->dev,
    339				 "unsupported number of clocks, limiting to the first "
    340				 __stringify(ARRAY_SIZE(dev->clk)) "\n");
    341	} else {
    342		dev->clk[0] = clk_get(&pdev->dev, NULL);
    343		if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) {
    344			ret = -EPROBE_DEFER;
    345			goto out_clk;
    346		}
    347		if (!IS_ERR(dev->clk[0]))
    348			clk_prepare_enable(dev->clk[0]);
    349	}
    350
    351
    352	dev->err_interrupt = platform_get_irq_optional(pdev, 0);
    353	if (dev->err_interrupt > 0 &&
    354	    resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
    355		dev_err(&pdev->dev,
    356			"disabling interrupt, resource size is too small\n");
    357		dev->err_interrupt = 0;
    358	}
    359	if (dev->err_interrupt > 0) {
    360		ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
    361					orion_mdio_err_irq,
    362					IRQF_SHARED, pdev->name, dev);
    363		if (ret)
    364			goto out_mdio;
    365
    366		writel(MVMDIO_ERR_INT_SMI_DONE,
    367			dev->regs + MVMDIO_ERR_INT_MASK);
    368
    369	} else if (dev->err_interrupt == -EPROBE_DEFER) {
    370		ret = -EPROBE_DEFER;
    371		goto out_mdio;
    372	}
    373
    374	/* For the platforms not supporting DT/ACPI fall-back
    375	 * to mdiobus_register via of_mdiobus_register.
    376	 */
    377	if (is_acpi_node(pdev->dev.fwnode))
    378		ret = acpi_mdiobus_register(bus, pdev->dev.fwnode);
    379	else
    380		ret = of_mdiobus_register(bus, pdev->dev.of_node);
    381	if (ret < 0) {
    382		dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
    383		goto out_mdio;
    384	}
    385
    386	platform_set_drvdata(pdev, bus);
    387
    388	return 0;
    389
    390out_mdio:
    391	if (dev->err_interrupt > 0)
    392		writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
    393
    394out_clk:
    395	for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
    396		if (IS_ERR(dev->clk[i]))
    397			break;
    398		clk_disable_unprepare(dev->clk[i]);
    399		clk_put(dev->clk[i]);
    400	}
    401
    402	return ret;
    403}
    404
    405static int orion_mdio_remove(struct platform_device *pdev)
    406{
    407	struct mii_bus *bus = platform_get_drvdata(pdev);
    408	struct orion_mdio_dev *dev = bus->priv;
    409	int i;
    410
    411	if (dev->err_interrupt > 0)
    412		writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
    413	mdiobus_unregister(bus);
    414
    415	for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
    416		if (IS_ERR(dev->clk[i]))
    417			break;
    418		clk_disable_unprepare(dev->clk[i]);
    419		clk_put(dev->clk[i]);
    420	}
    421
    422	return 0;
    423}
    424
    425static const struct of_device_id orion_mdio_match[] = {
    426	{ .compatible = "marvell,orion-mdio", .data = (void *)BUS_TYPE_SMI },
    427	{ .compatible = "marvell,xmdio", .data = (void *)BUS_TYPE_XSMI },
    428	{ }
    429};
    430MODULE_DEVICE_TABLE(of, orion_mdio_match);
    431
    432#ifdef CONFIG_ACPI
    433static const struct acpi_device_id orion_mdio_acpi_match[] = {
    434	{ "MRVL0100", BUS_TYPE_SMI },
    435	{ "MRVL0101", BUS_TYPE_XSMI },
    436	{ },
    437};
    438MODULE_DEVICE_TABLE(acpi, orion_mdio_acpi_match);
    439#endif
    440
    441static struct platform_driver orion_mdio_driver = {
    442	.probe = orion_mdio_probe,
    443	.remove = orion_mdio_remove,
    444	.driver = {
    445		.name = "orion-mdio",
    446		.of_match_table = orion_mdio_match,
    447		.acpi_match_table = ACPI_PTR(orion_mdio_acpi_match),
    448	},
    449};
    450
    451module_platform_driver(orion_mdio_driver);
    452
    453MODULE_DESCRIPTION("Marvell MDIO interface driver");
    454MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
    455MODULE_LICENSE("GPL");
    456MODULE_ALIAS("platform:orion-mdio");