linux/drivers/vfio/platform/reset/vfio_platform_bcmflexrm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2017 Broadcom
   4 */
   5
   6/*
   7 * This driver provides reset support for Broadcom FlexRM ring manager
   8 * to VFIO platform.
   9 */
  10
  11#include <linux/delay.h>
  12#include <linux/device.h>
  13#include <linux/init.h>
  14#include <linux/io.h>
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17
  18#include "../vfio_platform_private.h"
  19
  20/* FlexRM configuration */
  21#define RING_REGS_SIZE                                  0x10000
  22#define RING_VER_MAGIC                                  0x76303031
  23
  24/* Per-Ring register offsets */
  25#define RING_VER                                        0x000
  26#define RING_CONTROL                                    0x034
  27#define RING_FLUSH_DONE                                 0x038
  28
  29/* Register RING_CONTROL fields */
  30#define CONTROL_FLUSH_SHIFT                             5
  31
  32/* Register RING_FLUSH_DONE fields */
  33#define FLUSH_DONE_MASK                                 0x1
  34
  35static int vfio_platform_bcmflexrm_shutdown(void __iomem *ring)
  36{
  37        unsigned int timeout;
  38
  39        /* Disable/inactivate ring */
  40        writel_relaxed(0x0, ring + RING_CONTROL);
  41
  42        /* Set ring flush state */
  43        timeout = 1000; /* timeout of 1s */
  44        writel_relaxed(BIT(CONTROL_FLUSH_SHIFT), ring + RING_CONTROL);
  45        do {
  46                if (readl_relaxed(ring + RING_FLUSH_DONE) &
  47                    FLUSH_DONE_MASK)
  48                        break;
  49                mdelay(1);
  50        } while (--timeout);
  51        if (!timeout)
  52                return -ETIMEDOUT;
  53
  54        /* Clear ring flush state */
  55        timeout = 1000; /* timeout of 1s */
  56        writel_relaxed(0x0, ring + RING_CONTROL);
  57        do {
  58                if (!(readl_relaxed(ring + RING_FLUSH_DONE) &
  59                      FLUSH_DONE_MASK))
  60                        break;
  61                mdelay(1);
  62        } while (--timeout);
  63        if (!timeout)
  64                return -ETIMEDOUT;
  65
  66        return 0;
  67}
  68
  69static int vfio_platform_bcmflexrm_reset(struct vfio_platform_device *vdev)
  70{
  71        void __iomem *ring;
  72        int rc = 0, ret = 0, ring_num = 0;
  73        struct vfio_platform_region *reg = &vdev->regions[0];
  74
  75        /* Map FlexRM ring registers if not mapped */
  76        if (!reg->ioaddr) {
  77                reg->ioaddr = ioremap(reg->addr, reg->size);
  78                if (!reg->ioaddr)
  79                        return -ENOMEM;
  80        }
  81
  82        /* Discover and shutdown each FlexRM ring */
  83        for (ring = reg->ioaddr;
  84             ring < (reg->ioaddr + reg->size); ring += RING_REGS_SIZE) {
  85                if (readl_relaxed(ring + RING_VER) == RING_VER_MAGIC) {
  86                        rc = vfio_platform_bcmflexrm_shutdown(ring);
  87                        if (rc) {
  88                                dev_warn(vdev->device,
  89                                         "FlexRM ring%d shutdown error %d\n",
  90                                         ring_num, rc);
  91                                ret |= rc;
  92                        }
  93                        ring_num++;
  94                }
  95        }
  96
  97        return ret;
  98}
  99
 100module_vfio_reset_handler("brcm,iproc-flexrm-mbox",
 101                          vfio_platform_bcmflexrm_reset);
 102
 103MODULE_LICENSE("GPL v2");
 104MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>");
 105MODULE_DESCRIPTION("Reset support for Broadcom FlexRM VFIO platform device");
 106