Skip to content

Commit 7a739cc

Browse files
Bandi,Kushallijinxia
authored andcommitted
DM: Add dm for IPU mediation
This device model is to configure the virtual IPU PCI device. In order to execute this DM the lauch script needs to add virtio-ipu as parameter to acrn-dm For e.g. -s 21,virtio-ipu Signed-off-by: Bandi,Kushal <kushal.bandi@intel.com>
1 parent a568c9e commit 7a739cc

File tree

2 files changed

+392
-0
lines changed

2 files changed

+392
-0
lines changed

devicemodel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ SRCS += hw/pci/passthrough.c
8989
SRCS += hw/pci/virtio/virtio_audio.c
9090
SRCS += hw/pci/virtio/virtio_net.c
9191
SRCS += hw/pci/virtio/virtio_rnd.c
92+
SRCS += hw/pci/virtio/virtio_ipu.c
9293
SRCS += hw/pci/virtio/virtio_hyper_dmabuf.c
9394
SRCS += hw/pci/virtio/virtio_heci.c
9495
SRCS += hw/pci/virtio/virtio_rpmb.c
Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
/*
2+
* Copyright (C) 2018 Intel Corporation. All rights reserved.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*
6+
*/
7+
8+
/*
9+
* virtio ipu
10+
* IPU mediator DM
11+
*/
12+
13+
#include <fcntl.h>
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <string.h>
17+
#include <unistd.h>
18+
#include <assert.h>
19+
#include <pthread.h>
20+
21+
#include "dm.h"
22+
#include "pci_core.h"
23+
#include "virtio.h"
24+
#include "virtio_kernel.h"
25+
#include "vmmapi.h"
26+
27+
/*
28+
* Size of queue was chosen experimentally in a way
29+
* that it allows to do IPU ISYS MIPI camera capture without
30+
* any delay for interrupt/msg send, this value should
31+
* be tuned.
32+
*/
33+
#define VIRTIO_IPU_RINGSZ 1024
34+
35+
/*
36+
* IPU mediation makes use of 2 VQs.
37+
* VQ0 for buffer mgmnt & 1 time configuration;
38+
* VQ1 for interrupt/msg exchange
39+
*/
40+
#define VIRTIO_IPU_VQ_NUM 2
41+
42+
#define IPU_VBS_DEV_PATH "/dev/vbs_ipu"
43+
44+
static int ipu_log_level;
45+
#define TAG "virtio_ipu: "
46+
#define LERR 1
47+
#define LWRN 2
48+
#define LDBG 3
49+
#define IPRINTF(lvl, fmt, args...) \
50+
do { if (lvl <= ipu_log_level) printf(TAG fmt, ##args); } while (0)
51+
52+
struct virtio_ipu {
53+
struct virtio_base base;
54+
struct virtio_vq_info vq[VIRTIO_IPU_VQ_NUM];
55+
pthread_mutex_t mtx;
56+
/* VBS-K variables */
57+
struct {
58+
enum VBS_K_STATUS ipu_kstatus;
59+
int ipu_fd;
60+
struct vbs_dev_info ipu_kdev;
61+
struct vbs_vqs_info ipu_kvqs;
62+
} vbs_k;
63+
};
64+
65+
static int virtio_ipu_k_init(struct virtio_ipu *ipu);
66+
static int virtio_ipu_k_start(struct virtio_ipu *ipu);
67+
static int virtio_ipu_k_stop(struct virtio_ipu *ipu);
68+
static int virtio_ipu_k_reset(struct virtio_ipu *ipu);
69+
static int virtio_ipu_k_dev_set(struct vbs_dev_info *ipu_kdev,
70+
const char *name, int vmid,
71+
int nvq, uint32_t feature,
72+
uint64_t pio_start, uint64_t pio_len);
73+
74+
static int virtio_ipu_k_vq_set(struct vbs_vqs_info *ipu_kvqs,
75+
unsigned int nvq, unsigned int idx,
76+
uint16_t qsize, uint32_t pfn,
77+
uint16_t msix_idx, uint64_t msix_addr,
78+
uint32_t msix_data);
79+
80+
static void virtio_ipu_no_notify(void *, struct virtio_vq_info *);
81+
static void virtio_ipu_set_status(void *, uint64_t);
82+
static void virtio_ipu_reset(void *);
83+
84+
static struct virtio_ops virtio_ipu_ops_k = {
85+
"virtio_ipu", /* our name */
86+
VIRTIO_IPU_VQ_NUM, /* we support 2 virtqueue */
87+
0, /* config reg size */
88+
virtio_ipu_reset, /* reset */
89+
virtio_ipu_no_notify, /* device-wide qnotify */
90+
NULL, /* read virtio config */
91+
NULL, /* write virtio config */
92+
NULL, /* apply negotiated features */
93+
virtio_ipu_set_status, /* called on guest set status */
94+
};
95+
96+
static int
97+
virtio_ipu_k_init(struct virtio_ipu *ipu)
98+
{
99+
100+
if (ipu->vbs_k.ipu_fd != -1) {
101+
IPRINTF(LWRN, "Ooops! Re-entered!!\n");
102+
return -VIRTIO_ERROR_REENTER;
103+
}
104+
105+
ipu->vbs_k.ipu_fd = open(IPU_VBS_DEV_PATH, O_RDWR);
106+
if (ipu->vbs_k.ipu_fd < 0) {
107+
IPRINTF(LWRN, "Failed to open %s!\n",
108+
IPU_VBS_DEV_PATH);
109+
return -VIRTIO_ERROR_FD_OPEN_FAILED;
110+
}
111+
IPRINTF(LDBG, "Open %s success fd:%d!\n",
112+
IPU_VBS_DEV_PATH, ipu->vbs_k.ipu_fd);
113+
114+
memset(&ipu->vbs_k.ipu_kdev, 0, sizeof(struct vbs_dev_info));
115+
memset(&ipu->vbs_k.ipu_kvqs, 0, sizeof(struct vbs_dev_info));
116+
117+
return VIRTIO_SUCCESS;
118+
}
119+
120+
static int
121+
virtio_ipu_k_dev_set(struct vbs_dev_info *ipu_kdev,
122+
const char *name, int vmid, int nvq,
123+
uint32_t feature, uint64_t pio_start,
124+
uint64_t pio_len)
125+
{
126+
/* init kdev */
127+
strncpy(ipu_kdev->name, name, VBS_NAME_LEN);
128+
ipu_kdev->vmid = vmid;
129+
ipu_kdev->nvq = nvq;
130+
ipu_kdev->negotiated_features = feature;
131+
ipu_kdev->pio_range_start = pio_start;
132+
ipu_kdev->pio_range_len = pio_len;
133+
134+
return VIRTIO_SUCCESS;
135+
}
136+
137+
static int
138+
virtio_ipu_k_vq_set(struct vbs_vqs_info *ipu_kvqs,
139+
unsigned int nvq, unsigned int idx,
140+
uint16_t qsize, uint32_t pfn,
141+
uint16_t msix_idx, uint64_t msix_addr,
142+
uint32_t msix_data)
143+
{
144+
145+
if (nvq <= idx) {
146+
IPRINTF(LWRN, "wrong idx for vq_set!\n");
147+
return -VIRTIO_ERROR_GENERAL;
148+
}
149+
150+
/* init kvqs */
151+
ipu_kvqs->nvq = nvq;
152+
ipu_kvqs->vqs[idx].qsize = qsize;
153+
ipu_kvqs->vqs[idx].pfn = pfn;
154+
ipu_kvqs->vqs[idx].msix_idx = msix_idx;
155+
ipu_kvqs->vqs[idx].msix_addr = msix_addr;
156+
ipu_kvqs->vqs[idx].msix_data = msix_data;
157+
158+
return VIRTIO_SUCCESS;
159+
}
160+
161+
static int
162+
virtio_ipu_k_start(struct virtio_ipu *ipu)
163+
{
164+
165+
if (vbs_kernel_start(ipu->vbs_k.ipu_fd,
166+
&ipu->vbs_k.ipu_kdev,
167+
&ipu->vbs_k.ipu_kvqs) < 0) {
168+
IPRINTF(LWRN, "Failed in vbs_kernel_start!\n");
169+
return -VIRTIO_ERROR_START;
170+
}
171+
172+
IPRINTF(LDBG, "vbs_kernel_started!\n");
173+
return VIRTIO_SUCCESS;
174+
}
175+
176+
static int
177+
virtio_ipu_k_stop(struct virtio_ipu *ipu)
178+
{
179+
180+
return vbs_kernel_stop(ipu->vbs_k.ipu_fd);
181+
}
182+
183+
static int
184+
virtio_ipu_k_reset(struct virtio_ipu *ipu)
185+
{
186+
187+
memset(&ipu->vbs_k.ipu_kdev, 0, sizeof(struct vbs_dev_info));
188+
memset(&ipu->vbs_k.ipu_kvqs, 0, sizeof(struct vbs_vqs_info));
189+
190+
return vbs_kernel_reset(ipu->vbs_k.ipu_fd);
191+
}
192+
193+
static void
194+
virtio_ipu_reset(void *base)
195+
{
196+
197+
struct virtio_ipu *ipu;
198+
199+
ipu = (struct virtio_ipu *)base;
200+
201+
IPRINTF(LDBG, "device reset requested !\n");
202+
virtio_reset_dev(&ipu->base);
203+
if (ipu->vbs_k.ipu_kstatus == VIRTIO_DEV_STARTED) {
204+
virtio_ipu_k_stop(ipu);
205+
virtio_ipu_k_reset(ipu);
206+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_INIT_SUCCESS;
207+
}
208+
}
209+
210+
/* VBS-K interface function implementations */
211+
static void
212+
virtio_ipu_no_notify(void *base, struct virtio_vq_info *vq)
213+
{
214+
215+
IPRINTF(LWRN, "VBS-K mode! Should not reach here!!\n");
216+
}
217+
218+
/*
219+
* This callback gives us a chance to determine the timings
220+
* to kickoff VBS-K initialization
221+
*/
222+
static void
223+
virtio_ipu_set_status(void *base, uint64_t status)
224+
{
225+
226+
struct virtio_ipu *ipu;
227+
int nvq;
228+
struct msix_table_entry *mte;
229+
uint64_t msix_addr = 0;
230+
uint32_t msix_data = 0;
231+
int rc, i, j;
232+
233+
IPRINTF(LDBG, "set_status status:%ld\n", status);
234+
ipu = (struct virtio_ipu *) base;
235+
nvq = ipu->base.vops->nvq;
236+
if (ipu->vbs_k.ipu_kstatus == VIRTIO_DEV_INIT_SUCCESS &&
237+
(status & VIRTIO_CR_STATUS_DRIVER_OK)) {
238+
/* time to kickoff VBS-K side */
239+
/* init vdev first */
240+
rc = virtio_ipu_k_dev_set(
241+
&ipu->vbs_k.ipu_kdev,
242+
ipu->base.vops->name,
243+
ipu->base.dev->vmctx->vmid,
244+
nvq,
245+
ipu->base.negotiated_caps,
246+
/* currently we let VBS-K handle
247+
* kick register
248+
*/
249+
ipu->base.dev->bar[0].addr + 16,
250+
2);
251+
252+
for (i = 0; i < nvq; i++) {
253+
if (ipu->vq[i].msix_idx !=
254+
VIRTIO_MSI_NO_VECTOR) {
255+
j = ipu->vq[i].msix_idx;
256+
mte = &ipu->base.dev->msix.table[j];
257+
msix_addr = mte->addr;
258+
msix_data = mte->msg_data;
259+
}
260+
rc = virtio_ipu_k_vq_set(
261+
&ipu->vbs_k.ipu_kvqs,
262+
nvq, i,
263+
ipu->vq[i].qsize,
264+
ipu->vq[i].pfn,
265+
ipu->vq[i].msix_idx,
266+
msix_addr,
267+
msix_data);
268+
269+
if (rc < 0) {
270+
IPRINTF(LWRN, "kernel_set_vq failed");
271+
IPRINTF(LWRN, "i %d ret %d\n", i, rc);
272+
return;
273+
}
274+
}
275+
rc = virtio_ipu_k_start(ipu);
276+
if (rc < 0) {
277+
IPRINTF(LWRN, "kernel_start() failed\n");
278+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_START_FAILED;
279+
} else {
280+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_STARTED;
281+
}
282+
}
283+
}
284+
285+
static int
286+
virtio_ipu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
287+
{
288+
289+
struct virtio_ipu *ipu;
290+
291+
pthread_mutexattr_t attr;
292+
int rc;
293+
294+
ipu = calloc(1, sizeof(struct virtio_ipu));
295+
if (!ipu) {
296+
IPRINTF(LWRN, "calloc returns NULL\n");
297+
return -1;
298+
}
299+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_INITIAL;
300+
ipu->vbs_k.ipu_fd = -1;
301+
302+
/* init mutex attribute properly */
303+
rc = pthread_mutexattr_init(&attr);
304+
if (rc)
305+
IPRINTF(LDBG, "mutexattr init failed with erro %d!\n", rc);
306+
307+
if (virtio_uses_msix()) {
308+
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
309+
IPRINTF(LDBG, "mutexattr_settype failed with error %d!\n", rc);
310+
} else {
311+
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
312+
IPRINTF(LDBG, "mutexattr_settype failed with error %d!\n", rc);
313+
}
314+
315+
rc = pthread_mutex_init(&ipu->mtx, &attr);
316+
if (rc)
317+
IPRINTF(LDBG, "mutex init failed with error %d!\n", rc);
318+
319+
virtio_linkup(&ipu->base,
320+
&virtio_ipu_ops_k,
321+
ipu,
322+
dev,
323+
ipu->vq);
324+
325+
rc = virtio_ipu_k_init(ipu);
326+
if (rc < 0) {
327+
IPRINTF(LWRN, "VBS-K init failed with error %d!\n", rc);
328+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_INIT_FAILED;
329+
pthread_mutex_destroy(&ipu->mtx);
330+
free(ipu);
331+
return -1;
332+
}
333+
334+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_INIT_SUCCESS;
335+
ipu->base.mtx = &ipu->mtx;
336+
337+
ipu->vq[0].qsize = VIRTIO_IPU_RINGSZ;
338+
ipu->vq[1].qsize = VIRTIO_IPU_RINGSZ;
339+
340+
/* initialize config space */
341+
pci_set_cfgdata16(dev, PCIR_DEVICE, VIRTIO_DEV_IPU);
342+
pci_set_cfgdata16(dev, PCIR_VENDOR, INTEL_VENDOR_ID);
343+
pci_set_cfgdata8(dev, PCIR_CLASS, PCIC_MEMORY);
344+
pci_set_cfgdata16(dev, PCIR_SUBDEV_0, VIRTIO_TYPE_IPU);
345+
pci_set_cfgdata16(dev, PCIR_SUBVEND_0, INTEL_VENDOR_ID);
346+
347+
if (virtio_interrupt_init(&ipu->base, virtio_uses_msix())) {
348+
pthread_mutex_destroy(&ipu->mtx);
349+
close(ipu->vbs_k.ipu_fd);
350+
free(ipu);
351+
return -1;
352+
}
353+
354+
virtio_set_io_bar(&ipu->base, 0);
355+
356+
return 0;
357+
}
358+
359+
static void
360+
virtio_ipu_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
361+
{
362+
363+
struct virtio_ipu *ipu;
364+
365+
ipu = (struct virtio_ipu *)dev->arg;
366+
if (!ipu) {
367+
IPRINTF(LDBG, "is NULL!\n");
368+
return;
369+
}
370+
371+
if (ipu->vbs_k.ipu_kstatus == VIRTIO_DEV_STARTED) {
372+
IPRINTF(LDBG, "deinitializing\n");
373+
virtio_ipu_k_stop(ipu);
374+
virtio_ipu_k_reset(ipu);
375+
ipu->vbs_k.ipu_kstatus = VIRTIO_DEV_INITIAL;
376+
assert(ipu->vbs_k.ipu_fd >= 0);
377+
close(ipu->vbs_k.ipu_fd);
378+
ipu->vbs_k.ipu_fd = -1;
379+
}
380+
pthread_mutex_destroy(&ipu->mtx);
381+
free(ipu);
382+
}
383+
384+
struct pci_vdev_ops pci_ops_virtio_ipu = {
385+
.class_name = "virtio-ipu",
386+
.vdev_init = virtio_ipu_init,
387+
.vdev_deinit = virtio_ipu_deinit,
388+
.vdev_barwrite = virtio_pci_write,
389+
.vdev_barread = virtio_pci_read
390+
};
391+
DEFINE_PCI_DEVTYPE(pci_ops_virtio_ipu);

0 commit comments

Comments
 (0)