1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Loongson-3 Virtual IPI interrupt support.
5 * Copyright (C) 2019 Loongson Technologies, Inc. All rights reserved.
7 * Authors: Chen Zhu <zhuchen@loongson.cn>
8 * Authors: Huacai Chen <chenhc@lemote.com>
11 #include <linux/kvm_host.h>
13 #define IPI_BASE 0x3ff01000ULL
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
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
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
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
51 static int loongson_vipi_read(struct loongson_kvm_ipi
*ipi
,
52 gpa_t addr
, int len
, void *val
)
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;
59 struct ipi_state
*s
= &(ipi
->ipistate
[id
]);
61 BUG_ON(offset
& (len
- 1));
64 case CORE0_STATUS_OFF
:
65 *(uint64_t *)val
= s
->status
;
69 *(uint64_t *)val
= s
->en
;
80 case CORE0_BUF_20
... CORE0_BUF_38
:
81 pbuf
= (void *)s
->buf
+ (offset
- 0x20);
83 *(uint64_t *)val
= *(uint64_t *)pbuf
;
84 else /* Assume len == 4 */
85 *(uint32_t *)val
= *(uint32_t *)pbuf
;
89 pr_notice("%s with unknown addr %llx\n", __func__
, addr
);
96 static int loongson_vipi_write(struct loongson_kvm_ipi
*ipi
,
97 gpa_t addr
, int len
, const void *val
)
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;
104 struct kvm
*kvm
= ipi
->kvm
;
105 struct kvm_mips_interrupt irq
;
106 struct ipi_state
*s
= &(ipi
->ipistate
[id
]);
108 data
= *(uint64_t *)val
;
109 BUG_ON(offset
& (len
- 1));
112 case CORE0_STATUS_OFF
:
123 kvm_vcpu_ioctl_interrupt(kvm
->vcpus
[id
], &irq
);
126 case CORE0_CLEAR_OFF
:
131 kvm_vcpu_ioctl_interrupt(kvm
->vcpus
[id
], &irq
);
135 case CORE0_BUF_20
... CORE0_BUF_38
:
136 pbuf
= (void *)s
->buf
+ (offset
- 0x20);
138 *(uint64_t *)pbuf
= (uint64_t)data
;
139 else /* Assume len == 4 */
140 *(uint32_t *)pbuf
= (uint32_t)data
;
144 pr_notice("%s with unknown addr %llx\n", __func__
, addr
);
151 static int kvm_ipi_read(struct kvm_vcpu
*vcpu
, struct kvm_io_device
*dev
,
152 gpa_t addr
, int len
, void *val
)
155 struct loongson_kvm_ipi
*ipi
;
156 struct ipi_io_device
*ipi_device
;
158 ipi_device
= container_of(dev
, struct ipi_io_device
, device
);
159 ipi
= ipi_device
->ipi
;
161 spin_lock_irqsave(&ipi
->lock
, flags
);
162 loongson_vipi_read(ipi
, addr
, len
, val
);
163 spin_unlock_irqrestore(&ipi
->lock
, flags
);
168 static int kvm_ipi_write(struct kvm_vcpu
*vcpu
, struct kvm_io_device
*dev
,
169 gpa_t addr
, int len
, const void *val
)
172 struct loongson_kvm_ipi
*ipi
;
173 struct ipi_io_device
*ipi_device
;
175 ipi_device
= container_of(dev
, struct ipi_io_device
, device
);
176 ipi
= ipi_device
->ipi
;
178 spin_lock_irqsave(&ipi
->lock
, flags
);
179 loongson_vipi_write(ipi
, addr
, len
, val
);
180 spin_unlock_irqrestore(&ipi
->lock
, flags
);
185 static const struct kvm_io_device_ops kvm_ipi_ops
= {
186 .read
= kvm_ipi_read
,
187 .write
= kvm_ipi_write
,
190 void kvm_init_loongson_ipi(struct kvm
*kvm
)
194 struct loongson_kvm_ipi
*s
;
195 struct kvm_io_device
*device
;
199 spin_lock_init(&s
->lock
);
202 * Initialize IPI device
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
;