forked from ishank-arora/sof-intel-vfio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vfio_boot.c
308 lines (227 loc) · 6.92 KB
/
vfio_boot.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#include <linux/vfio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include "common.h"
#include "probe.h"
struct snd_sof_fw_header {
unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */
__u32 file_size; /* size of file minus this header */
__u32 num_modules; /* number of modules */
__u32 abi; /* version of header format */
} __packed;
int main() {
dev * info = (dev *) malloc(sizeof(dev));
info->container = -1;
info->group = -1;
info->device = -1;
int i = 0;
struct vfio_group_status group_status = {.argsz = sizeof(group_status)};
struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };
struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
/* Create a new container */
info->container = open("/dev/vfio/vfio", O_RDWR);
if(info->container < 0){
printf("Container did not open properly\n");
}
else{
printf("Container fd: %d\n", info->container);
}
if (ioctl(info->container, VFIO_GET_API_VERSION) != VFIO_API_VERSION){
/* Unknown API version */
printf("Unknown API version\n");
}
if (!ioctl(info->container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)){
/* Doesn't support the IOMMU driver we want. */
printf("Wrong IOMMU version\n");
}
/* Open the group */
info->group = open("/dev/vfio/12", O_RDWR);
if(info->group < 0){
printf("Group didnt open correctly\n");
}
else{
printf("Groupd fd: %d\n", info->group);
}
int ret = -100;
/* Test the group is viable and available */
ret = ioctl(info->group, VFIO_GROUP_GET_STATUS, &group_status);
if(ret < 0){
printf("getting group status failed. Error: %d\n", ret);
}
if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)){
/* Group is not viable (ie, not all devices bound for vfio) */
printf("Not all devices in group are bound vfio\n");
}
/* Add the group to the container */
ret = ioctl(info->group, VFIO_GROUP_SET_CONTAINER, &info->container);
if(ret < 0){
printf("adding group to container failed. Error: %d\n", ret);
}
/* Enable the IOMMU model we want */
ret = ioctl(info->container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
if(ret < 0){
printf("Setting IOMMU type failed. Error: %d\n", ret);
}
iommu_info.iova_pgsizes = 1324u;
/* Get addition IOMMU info */
ret = ioctl(info->container, VFIO_IOMMU_GET_INFO, &iommu_info);
if(ret < 0){
printf("getting iommu info failed. Error: %d\n", ret);
}
printf("flags iommu: %u\n",iommu_info.flags);
/* Get a file descriptor for the device */
info->device = ioctl(info->group, VFIO_GROUP_GET_DEVICE_FD, "0000:00:1f.3");
if(info->device < 0){
printf("Device FD not found\n");
}
else{
printf("Device FD: %d\n", info->device);
}
/* Test and setup the device */
ret = ioctl(info->device, VFIO_DEVICE_GET_INFO, &device_info);
if(ret < 0){
printf("Getting device info failed. error: %d\n", ret);
}
printf("Device 3 regions flags, regions, irqs: %u %u %u\n", device_info.flags, device_info.num_regions, device_info.num_irqs);
for (i = 0; i < device_info.num_regions; i++) {
struct vfio_region_info reg = { .argsz = sizeof(reg) };
reg.index = i;
ret = ioctl(info->device, VFIO_DEVICE_GET_REGION_INFO, ®);
if(ret < 0){
printf("Error getting device region info. %d\n", ret);
}
else{
printf("Index:%d , Flags:%u , Size:%llu , Offset:%llu.\n", i, reg.flags, reg.size, reg.offset);
}
/* Setup mappings... read/write offsets, mmaps
* For PCI devices, config space is a region */
}
printf("\n\n");
load_fw_for_dma(info->container, "/lib/firmware/intel/sof/sof-cnl.ri",
0xfff40000);
return 0;
const char * fw_file = "/lib/firmware/intel/sof/sof-cnl.ri";
struct snd_sof_fw_header * header;
size_t fw_size = sizeof(*header);
__u8 * data = (__u8 *) malloc(fw_size);
int f = open(fw_file, O_RDWR);
FILE * fp;
fp = fopen(fw_file, "r");
fseek(fp, 0L, SEEK_END);
long actual_size = ftell(fp);
rewind(fp);
fclose(fp);
printf("\n\nActual size: %ld\n\n", actual_size);
if(f < 0){
printf("opening firmware file failed\n");
}
else{
ret = read(f, data, actual_size);
if(ret < 0){
printf("Read firmware failed\n");
}
}
firmware * fw = (firmware *) malloc(sizeof(firmware));
fw->data = data;
fw->size = actual_size;
snd_sof_dsp_update_bits(info, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
1 << 0x7,
1 << 0x7);
int sd_offset = SOF_STREAM_SD_OFFSET(0x7);
snd_sof_dsp_update_bits(info, HDA_DSP_HDA_BAR,
sd_offset,
SOF_HDA_SD_CTL_DMA_START |
SOF_HDA_CL_DMA_SD_INT_MASK,
SOF_HDA_SD_CTL_DMA_START |
SOF_HDA_CL_DMA_SD_INT_MASK);
printf("error: Error code=0x%x: FW status=0x%x\n",
snd_sof_dsp_read(info, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_ERROR),
snd_sof_dsp_read(info, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS));
__u32 status = snd_sof_dsp_read(info, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS);
int count = 0;
while(((status & HDA_DSP_ROM_STS_MASK) != HDA_DSP_ROM_FW_ENTERED) & count < 10000){
status = snd_sof_dsp_read(info, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS);
count++;
}
if((status & HDA_DSP_ROM_STS_MASK) == HDA_DSP_ROM_FW_ENTERED){
printf("GOod!\n");
}
else{
printf("Bad!\n");
}
return 0;
}
__u32 snd_sof_dsp_read(dev * info, __u32 bar, __u32 offset){
int device = info->device;
int ret;
struct vfio_region_info reg = { .argsz = sizeof(reg) };
reg.index = bar;
ret = ioctl(device, VFIO_DEVICE_GET_REGION_INFO, ®);
if(ret < 0){
printf("Error getting device region. %d\n", ret);
}
else{
__u32 * result = (__u32 *) malloc(sizeof(__u32));
ret = pread(device, result, sizeof(__u32), reg.offset+offset);
if(ret < 0){
printf("read err in dsp_read %d\n", ret);
}
else{
return *result;
}
}
printf("read Didnt work\n");
return 0;
}
void snd_sof_dsp_write(dev * info, __u32 bar, __u32 offset, __u32 value){
int device = info->device;
int ret;
struct vfio_region_info reg = { .argsz = sizeof(reg) };
reg.index = bar;
ret = ioctl(device, VFIO_DEVICE_GET_REGION_INFO, ®);
if(ret < 0){
printf("Error getting device region. %d\n", ret);
return;
}
else{
ret = pwrite(device, &value, sizeof(value), reg.offset+offset);
if(ret < 0){
printf("write err in dsp_write %d\n", ret);
return;
}
}
printf("write worked\n");
return;
}
bool snd_sof_dsp_update_bits(dev * info, __u32 bar, __u32 offset,
__u32 mask, __u32 value)
{
bool change = snd_sof_dsp_update_bits_unlocked(info, bar, offset, mask,
value);
return change;
}
bool snd_sof_dsp_update_bits_unlocked(dev * info, __u32 bar, __u32 offset, __u32 mask, __u32 value)
{
unsigned int old;
unsigned int new_val;
__u32 ret;
ret = snd_sof_dsp_read(info, bar, offset);
old = ret;
new_val = (old & ~mask) | (value & mask);
if (old == new_val)
return false;
snd_sof_dsp_write(info, bar, offset, new_val);
return true;
}