arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / mips / kvm / loongson_ipi.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Loongson-3 Virtual IPI interrupt support.
4  *
5  * Copyright (C) 2019  Loongson Technologies, Inc.  All rights reserved.
6  *
7  * Authors: Chen Zhu <zhuchen@loongson.cn>
8  * Authors: Huacai Chen <chenhc@lemote.com>
9  */
10
11 #include <linux/kvm_host.h>
12
13 #define IPI_BASE            0x3ff01000ULL
14
15 #define CORE0_STATUS_OFF       0x000
16 #define CORE0_EN_OFF           0x004
17 #define CORE0_SET_OFF          0x008
18 #define CORE0_CLEAR_OFF        0x00c
19 #define CORE0_BUF_20           0x020
20 #define CORE0_BUF_28           0x028
21 #define CORE0_BUF_30           0x030
22 #define CORE0_BUF_38           0x038
23
24 #define CORE1_STATUS_OFF       0x100
25 #define CORE1_EN_OFF           0x104
26 #define CORE1_SET_OFF          0x108
27 #define CORE1_CLEAR_OFF        0x10c
28 #define CORE1_BUF_20           0x120
29 #define CORE1_BUF_28           0x128
30 #define CORE1_BUF_30           0x130
31 #define CORE1_BUF_38           0x138
32
33 #define CORE2_STATUS_OFF       0x200
34 #define CORE2_EN_OFF           0x204
35 #define CORE2_SET_OFF          0x208
36 #define CORE2_CLEAR_OFF        0x20c
37 #define CORE2_BUF_20           0x220
38 #define CORE2_BUF_28           0x228
39 #define CORE2_BUF_30           0x230
40 #define CORE2_BUF_38           0x238
41
42 #define CORE3_STATUS_OFF       0x300
43 #define CORE3_EN_OFF           0x304
44 #define CORE3_SET_OFF          0x308
45 #define CORE3_CLEAR_OFF        0x30c
46 #define CORE3_BUF_20           0x320
47 #define CORE3_BUF_28           0x328
48 #define CORE3_BUF_30           0x330
49 #define CORE3_BUF_38           0x338
50
51 static int loongson_vipi_read(struct loongson_kvm_ipi *ipi,
52                                 gpa_t addr, int len, void *val)
53 {
54         uint32_t core = (addr >> 8) & 3;
55         uint32_t node = (addr >> 44) & 3;
56         uint32_t id = core + node * 4;
57         uint64_t offset = addr & 0xff;
58         void *pbuf;
59         struct ipi_state *s = &(ipi->ipistate[id]);
60
61         BUG_ON(offset & (len - 1));
62
63         switch (offset) {
64         case CORE0_STATUS_OFF:
65                 *(uint64_t *)val = s->status;
66                 break;
67
68         case CORE0_EN_OFF:
69                 *(uint64_t *)val = s->en;
70                 break;
71
72         case CORE0_SET_OFF:
73                 *(uint64_t *)val = 0;
74                 break;
75
76         case CORE0_CLEAR_OFF:
77                 *(uint64_t *)val = 0;
78                 break;
79
80         case CORE0_BUF_20 ... CORE0_BUF_38:
81                 pbuf = (void *)s->buf + (offset - 0x20);
82                 if (len == 8)
83                         *(uint64_t *)val = *(uint64_t *)pbuf;
84                 else /* Assume len == 4 */
85                         *(uint32_t *)val = *(uint32_t *)pbuf;
86                 break;
87
88         default:
89                 pr_notice("%s with unknown addr %llx\n", __func__, addr);
90                 break;
91         }
92
93         return 0;
94 }
95
96 static int loongson_vipi_write(struct loongson_kvm_ipi *ipi,
97                                 gpa_t addr, int len, const void *val)
98 {
99         uint32_t core = (addr >> 8) & 3;
100         uint32_t node = (addr >> 44) & 3;
101         uint32_t id = core + node * 4;
102         uint64_t data, offset = addr & 0xff;
103         void *pbuf;
104         struct kvm *kvm = ipi->kvm;
105         struct kvm_mips_interrupt irq;
106         struct ipi_state *s = &(ipi->ipistate[id]);
107
108         data = *(uint64_t *)val;
109         BUG_ON(offset & (len - 1));
110
111         switch (offset) {
112         case CORE0_STATUS_OFF:
113                 break;
114
115         case CORE0_EN_OFF:
116                 s->en = data;
117                 break;
118
119         case CORE0_SET_OFF:
120                 s->status |= data;
121                 irq.cpu = id;
122                 irq.irq = 6;
123                 kvm_vcpu_ioctl_interrupt(kvm_get_vcpu(kvm, id), &irq);
124                 break;
125
126         case CORE0_CLEAR_OFF:
127                 s->status &= ~data;
128                 if (!s->status) {
129                         irq.cpu = id;
130                         irq.irq = -6;
131                         kvm_vcpu_ioctl_interrupt(kvm_get_vcpu(kvm, id), &irq);
132                 }
133                 break;
134
135         case CORE0_BUF_20 ... CORE0_BUF_38:
136                 pbuf = (void *)s->buf + (offset - 0x20);
137                 if (len == 8)
138                         *(uint64_t *)pbuf = (uint64_t)data;
139                 else /* Assume len == 4 */
140                         *(uint32_t *)pbuf = (uint32_t)data;
141                 break;
142
143         default:
144                 pr_notice("%s with unknown addr %llx\n", __func__, addr);
145                 break;
146         }
147
148         return 0;
149 }
150
151 static int kvm_ipi_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
152                         gpa_t addr, int len, void *val)
153 {
154         unsigned long flags;
155         struct loongson_kvm_ipi *ipi;
156         struct ipi_io_device *ipi_device;
157
158         ipi_device = container_of(dev, struct ipi_io_device, device);
159         ipi = ipi_device->ipi;
160
161         spin_lock_irqsave(&ipi->lock, flags);
162         loongson_vipi_read(ipi, addr, len, val);
163         spin_unlock_irqrestore(&ipi->lock, flags);
164
165         return 0;
166 }
167
168 static int kvm_ipi_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
169                         gpa_t addr, int len, const void *val)
170 {
171         unsigned long flags;
172         struct loongson_kvm_ipi *ipi;
173         struct ipi_io_device *ipi_device;
174
175         ipi_device = container_of(dev, struct ipi_io_device, device);
176         ipi = ipi_device->ipi;
177
178         spin_lock_irqsave(&ipi->lock, flags);
179         loongson_vipi_write(ipi, addr, len, val);
180         spin_unlock_irqrestore(&ipi->lock, flags);
181
182         return 0;
183 }
184
185 static const struct kvm_io_device_ops kvm_ipi_ops = {
186         .read     = kvm_ipi_read,
187         .write    = kvm_ipi_write,
188 };
189
190 void kvm_init_loongson_ipi(struct kvm *kvm)
191 {
192         int i;
193         unsigned long addr;
194         struct loongson_kvm_ipi *s;
195         struct kvm_io_device *device;
196
197         s = &kvm->arch.ipi;
198         s->kvm = kvm;
199         spin_lock_init(&s->lock);
200
201         /*
202          * Initialize IPI device
203          */
204         for (i = 0; i < 4; i++) {
205                 device = &s->dev_ipi[i].device;
206                 kvm_iodevice_init(device, &kvm_ipi_ops);
207                 addr = (((unsigned long)i) << 44) + IPI_BASE;
208                 mutex_lock(&kvm->slots_lock);
209                 kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, 0x400, device);
210                 mutex_unlock(&kvm->slots_lock);
211                 s->dev_ipi[i].ipi = s;
212                 s->dev_ipi[i].node_id = i;
213         }
214 }