~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/kvm/loongson_ipi.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php