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 | |
35 | static 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 | |
69 | static 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(offset: reg->addr, size: 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 | |
100 | module_vfio_reset_handler("brcm,iproc-flexrm-mbox" , |
101 | vfio_platform_bcmflexrm_reset); |
102 | |
103 | MODULE_LICENSE("GPL v2" ); |
104 | MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>" ); |
105 | MODULE_DESCRIPTION("Reset support for Broadcom FlexRM VFIO platform device" ); |
106 | |