hc
2023-11-22 f743a7adbd6e230d66a6206fa115b59fec2d88eb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * Copyright (C) 2017 Broadcom
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation version 2.
 *
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
 
/*
 * This driver provides reset support for Broadcom FlexRM ring manager
 * to VFIO platform.
 */
 
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
 
#include "vfio_platform_private.h"
 
/* FlexRM configuration */
#define RING_REGS_SIZE                    0x10000
#define RING_VER_MAGIC                    0x76303031
 
/* Per-Ring register offsets */
#define RING_VER                    0x000
#define RING_CONTROL                    0x034
#define RING_FLUSH_DONE                    0x038
 
/* Register RING_CONTROL fields */
#define CONTROL_FLUSH_SHIFT                5
 
/* Register RING_FLUSH_DONE fields */
#define FLUSH_DONE_MASK                    0x1
 
static int vfio_platform_bcmflexrm_shutdown(void __iomem *ring)
{
   unsigned int timeout;
 
   /* Disable/inactivate ring */
   writel_relaxed(0x0, ring + RING_CONTROL);
 
   /* Set ring flush state */
   timeout = 1000; /* timeout of 1s */
   writel_relaxed(BIT(CONTROL_FLUSH_SHIFT), ring + RING_CONTROL);
   do {
       if (readl_relaxed(ring + RING_FLUSH_DONE) &
           FLUSH_DONE_MASK)
           break;
       mdelay(1);
   } while (--timeout);
   if (!timeout)
       return -ETIMEDOUT;
 
   /* Clear ring flush state */
   timeout = 1000; /* timeout of 1s */
   writel_relaxed(0x0, ring + RING_CONTROL);
   do {
       if (!(readl_relaxed(ring + RING_FLUSH_DONE) &
             FLUSH_DONE_MASK))
           break;
       mdelay(1);
   } while (--timeout);
   if (!timeout)
       return -ETIMEDOUT;
 
   return 0;
}
 
static int vfio_platform_bcmflexrm_reset(struct vfio_platform_device *vdev)
{
   void __iomem *ring;
   int rc = 0, ret = 0, ring_num = 0;
   struct vfio_platform_region *reg = &vdev->regions[0];
 
   /* Map FlexRM ring registers if not mapped */
   if (!reg->ioaddr) {
       reg->ioaddr = ioremap_nocache(reg->addr, reg->size);
       if (!reg->ioaddr)
           return -ENOMEM;
   }
 
   /* Discover and shutdown each FlexRM ring */
   for (ring = reg->ioaddr;
        ring < (reg->ioaddr + reg->size); ring += RING_REGS_SIZE) {
       if (readl_relaxed(ring + RING_VER) == RING_VER_MAGIC) {
           rc = vfio_platform_bcmflexrm_shutdown(ring);
           if (rc) {
               dev_warn(vdev->device,
                    "FlexRM ring%d shutdown error %d\n",
                    ring_num, rc);
               ret |= rc;
           }
           ring_num++;
       }
   }
 
   return ret;
}
 
module_vfio_reset_handler("brcm,iproc-flexrm-mbox",
             vfio_platform_bcmflexrm_reset);
 
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>");
MODULE_DESCRIPTION("Reset support for Broadcom FlexRM VFIO platform device");