32
32
33
33
static inline bool msixcap_access (struct pci_vdev * vdev , uint32_t offset )
34
34
{
35
+ bool ret ;
36
+
35
37
if (vdev -> msix .capoff == 0U ) {
36
- return 0 ;
38
+ ret = false;
39
+ } else {
40
+ ret = in_range (offset , vdev -> msix .capoff , vdev -> msix .caplen );
37
41
}
38
42
39
- return in_range ( offset , vdev -> msix . capoff , vdev -> msix . caplen ) ;
43
+ return ret ;
40
44
}
41
45
42
46
static inline bool msixtable_access (struct pci_vdev * vdev , uint32_t offset )
@@ -56,24 +60,22 @@ static int vmsix_remap_entry(struct pci_vdev *vdev, uint32_t index, bool enable)
56
60
info .vmsi_data = (enable ) ? vdev -> msix .tables [index ].data : 0U ;
57
61
58
62
ret = ptdev_msix_remap (vdev -> vpci -> vm , vdev -> vbdf .value , (uint16_t )index , & info );
59
- if (ret != 0 ) {
60
- return ret ;
61
- }
63
+ if (ret == 0 ) {
64
+ /* Write the table entry to the physical structure */
65
+ hva = vdev -> msix .mmio_hva + vdev -> msix .table_offset ;
66
+ pentry = (struct msix_table_entry * )hva + index ;
62
67
63
- /* Write the table entry to the physical structure */
64
- hva = vdev -> msix .mmio_hva + vdev -> msix .table_offset ;
65
- pentry = (struct msix_table_entry * )hva + index ;
66
-
67
- /*
68
- * PCI 3.0 Spec allows writing to Message Address and Message Upper Address
69
- * fields with a single QWORD write, but some hardware can accept 32 bits
70
- * write only
71
- */
72
- mmio_write32 ((uint32_t )(info .pmsi_addr ), (const void * )& (pentry -> addr ));
73
- mmio_write32 ((uint32_t )(info .pmsi_addr >> 32U ), (const void * )((char * )& (pentry -> addr ) + 4U ));
68
+ /*
69
+ * PCI 3.0 Spec allows writing to Message Address and Message Upper Address
70
+ * fields with a single QWORD write, but some hardware can accept 32 bits
71
+ * write only
72
+ */
73
+ mmio_write32 ((uint32_t )(info .pmsi_addr ), (const void * )& (pentry -> addr ));
74
+ mmio_write32 ((uint32_t )(info .pmsi_addr >> 32U ), (const void * )((char * )& (pentry -> addr ) + 4U ));
74
75
75
- mmio_write32 (info .pmsi_data , (const void * )& (pentry -> data ));
76
- mmio_write32 (vdev -> msix .tables [index ].vector_control , (const void * )& (pentry -> vector_control ));
76
+ mmio_write32 (info .pmsi_data , (const void * )& (pentry -> data ));
77
+ mmio_write32 (vdev -> msix .tables [index ].vector_control , (const void * )& (pentry -> vector_control ));
78
+ }
77
79
78
80
return ret ;
79
81
}
@@ -126,38 +128,41 @@ static int vmsix_remap_one_entry(struct pci_vdev *vdev, uint32_t index, bool ena
126
128
enable_disable_msix (vdev , false);
127
129
128
130
ret = vmsix_remap_entry (vdev , index , enable );
129
- if (ret != 0 ) {
130
- return ret ;
131
- }
132
-
133
- /* If MSI Enable is being set, make sure INTxDIS bit is set */
134
- if (enable ) {
135
- enable_disable_pci_intx (vdev -> pdev .bdf , false);
136
- }
131
+ if (ret == 0 ) {
132
+ /* If MSI Enable is being set, make sure INTxDIS bit is set */
133
+ if (enable ) {
134
+ enable_disable_pci_intx (vdev -> pdev .bdf , false);
135
+ }
137
136
138
- /* Restore MSI-X Enable bit */
139
- msgctrl = pci_vdev_read_cfg (vdev , vdev -> msix .capoff + PCIR_MSIX_CTRL , 2U );
140
- if ((msgctrl & PCIM_MSIXCTRL_MSIX_ENABLE ) == PCIM_MSIXCTRL_MSIX_ENABLE ) {
141
- pci_pdev_write_cfg (vdev -> pdev .bdf , vdev -> msix .capoff + PCIR_MSIX_CTRL , 2U , msgctrl );
137
+ /* Restore MSI-X Enable bit */
138
+ msgctrl = pci_vdev_read_cfg (vdev , vdev -> msix .capoff + PCIR_MSIX_CTRL , 2U );
139
+ if ((msgctrl & PCIM_MSIXCTRL_MSIX_ENABLE ) == PCIM_MSIXCTRL_MSIX_ENABLE ) {
140
+ pci_pdev_write_cfg (vdev -> pdev .bdf , vdev -> msix .capoff + PCIR_MSIX_CTRL , 2U , msgctrl );
141
+ }
142
142
}
143
143
144
144
return ret ;
145
145
}
146
146
147
147
static int vmsix_cfgread (struct pci_vdev * vdev , uint32_t offset , uint32_t bytes , uint32_t * val )
148
148
{
149
+ int32_t ret ;
149
150
/* For PIO access, we emulate Capability Structures only */
151
+
150
152
if (msixcap_access (vdev , offset )) {
151
153
* val = pci_vdev_read_cfg (vdev , offset , bytes );
152
- return 0 ;
154
+ ret = 0 ;
155
+ } else {
156
+ ret = - ENODEV ;
153
157
}
154
158
155
- return - ENODEV ;
159
+ return ret ;
156
160
}
157
161
158
162
static int vmsix_cfgwrite (struct pci_vdev * vdev , uint32_t offset , uint32_t bytes , uint32_t val )
159
163
{
160
164
uint32_t msgctrl ;
165
+ int32_t ret ;
161
166
162
167
/* Writing MSI-X Capability Structure */
163
168
if (msixcap_access (vdev , offset )) {
@@ -181,10 +186,12 @@ static int vmsix_cfgwrite(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes
181
186
}
182
187
}
183
188
184
- return 0 ;
189
+ ret = 0 ;
190
+ } else {
191
+ ret = - ENODEV ;
185
192
}
186
193
187
- return - ENODEV ;
194
+ return ret ;
188
195
}
189
196
190
197
static void vmsix_table_rw (struct pci_vdev * vdev , struct mmio_request * mmio , uint32_t offset )
@@ -300,41 +307,40 @@ static void decode_msix_table_bar(struct pci_vdev *vdev)
300
307
uint32_t bar_lo , bar_hi , val32 ;
301
308
302
309
bar_lo = pci_pdev_read_cfg (pbdf , pci_bar_offset (bir ), 4U );
303
- if ((bar_lo & PCIM_BAR_SPACE ) == PCIM_BAR_IO_SPACE ) {
304
- /* I/O bar, should never happen */
305
- pr_err ("PCI device (%x) has MSI-X Table at IO BAR" , vdev -> vbdf .value );
306
- return ;
307
- }
308
-
309
- /* Get the base address */
310
- base = (uint64_t )bar_lo & PCIM_BAR_MEM_BASE ;
311
- if ((bar_lo & PCIM_BAR_MEM_TYPE ) == PCIM_BAR_MEM_64 ) {
312
- bar_hi = pci_pdev_read_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U );
313
- base |= ((uint64_t )bar_hi << 32U );
314
- }
310
+ if ((bar_lo & PCIM_BAR_SPACE ) != PCIM_BAR_IO_SPACE ) {
311
+ /* Get the base address */
312
+ base = (uint64_t )bar_lo & PCIM_BAR_MEM_BASE ;
313
+ if ((bar_lo & PCIM_BAR_MEM_TYPE ) == PCIM_BAR_MEM_64 ) {
314
+ bar_hi = pci_pdev_read_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U );
315
+ base |= ((uint64_t )bar_hi << 32U );
316
+ }
315
317
316
- vdev -> msix .mmio_hva = (uint64_t )hpa2hva (base );
317
- vdev -> msix .mmio_gpa = vm0_hpa2gpa (base );
318
+ vdev -> msix .mmio_hva = (uint64_t )hpa2hva (base );
319
+ vdev -> msix .mmio_gpa = vm0_hpa2gpa (base );
318
320
319
- /* Sizing the BAR */
320
- size = 0U ;
321
- if (((bar_lo & PCIM_BAR_MEM_TYPE ) == PCIM_BAR_MEM_64 ) && (bir < (PCI_BAR_COUNT - 1U ))) {
322
- pci_pdev_write_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U , ~0U );
323
- size = (uint64_t )pci_pdev_read_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U );
324
- size <<= 32U ;
325
- }
321
+ /* Sizing the BAR */
322
+ size = 0U ;
323
+ if (((bar_lo & PCIM_BAR_MEM_TYPE ) == PCIM_BAR_MEM_64 ) && (bir < (PCI_BAR_COUNT - 1U ))) {
324
+ pci_pdev_write_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U , ~0U );
325
+ size = (uint64_t )pci_pdev_read_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U );
326
+ size <<= 32U ;
327
+ }
326
328
327
- pci_pdev_write_cfg (pbdf , pci_bar_offset (bir ), 4U , ~0U );
328
- val32 = pci_pdev_read_cfg (pbdf , pci_bar_offset (bir ), 4U );
329
- size |= ((uint64_t )val32 & PCIM_BAR_MEM_BASE );
329
+ pci_pdev_write_cfg (pbdf , pci_bar_offset (bir ), 4U , ~0U );
330
+ val32 = pci_pdev_read_cfg (pbdf , pci_bar_offset (bir ), 4U );
331
+ size |= ((uint64_t )val32 & PCIM_BAR_MEM_BASE );
330
332
331
- vdev -> msix .mmio_size = size & ~(size - 1U );
333
+ vdev -> msix .mmio_size = size & ~(size - 1U );
332
334
333
- /* Restore the BAR */
334
- pci_pdev_write_cfg (pbdf , pci_bar_offset (bir ), 4U , bar_lo );
335
+ /* Restore the BAR */
336
+ pci_pdev_write_cfg (pbdf , pci_bar_offset (bir ), 4U , bar_lo );
335
337
336
- if ((bar_lo & PCIM_BAR_MEM_TYPE ) == PCIM_BAR_MEM_64 ) {
337
- pci_pdev_write_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U , bar_hi );
338
+ if ((bar_lo & PCIM_BAR_MEM_TYPE ) == PCIM_BAR_MEM_64 ) {
339
+ pci_pdev_write_cfg (pbdf , pci_bar_offset (bir + 1U ), 4U , bar_hi );
340
+ }
341
+ } else {
342
+ /* I/O bar, should never happen */
343
+ pr_err ("PCI device (%x) has MSI-X Table at IO BAR" , vdev -> vbdf .value );
338
344
}
339
345
}
340
346
@@ -344,6 +350,7 @@ static int vmsix_init(struct pci_vdev *vdev)
344
350
uint32_t table_info , i ;
345
351
uint64_t addr_hi , addr_lo ;
346
352
struct msix * msix = & vdev -> msix ;
353
+ int32_t ret ;
347
354
348
355
msgctrl = pci_pdev_read_cfg (vdev -> pdev .bdf , vdev -> msix .capoff + PCIR_MSIX_CTRL , 2U );
349
356
@@ -354,49 +361,50 @@ static int vmsix_init(struct pci_vdev *vdev)
354
361
msix -> table_offset = table_info & ~PCIM_MSIX_BIR_MASK ;
355
362
msix -> table_count = (msgctrl & PCIM_MSIXCTRL_TABLE_SIZE ) + 1U ;
356
363
357
- if (msix -> table_bar >= (PCI_BAR_COUNT - 1U )) {
364
+ if (msix -> table_bar < (PCI_BAR_COUNT - 1U )) {
365
+ /* Mask all table entries */
366
+ for (i = 0U ; i < msix -> table_count ; i ++ ) {
367
+ msix -> tables [i ].vector_control = PCIM_MSIX_VCTRL_MASK ;
368
+ msix -> tables [i ].addr = 0U ;
369
+ msix -> tables [i ].data = 0U ;
370
+ }
371
+
372
+ decode_msix_table_bar (vdev );
373
+
374
+ if (msix -> mmio_gpa != 0U ) {
375
+ /*
376
+ * PCI Spec: a BAR may also map other usable address space that is not associated
377
+ * with MSI-X structures, but it must not share any naturally aligned 4 KB
378
+ * address range with one where either MSI-X structure resides.
379
+ * The MSI-X Table and MSI-X PBA are permitted to co-reside within a naturally
380
+ * aligned 4 KB address range.
381
+ *
382
+ * If PBA or others reside in the same BAR with MSI-X Table, devicemodel could
383
+ * emulate them and maps these memory range at the 4KB boundary. Here, we should
384
+ * make sure only intercept the minimum number of 4K pages needed for MSI-X table.
385
+ */
386
+
387
+ /* The higher boundary of the 4KB aligned address range for MSI-X table */
388
+ addr_hi = msix -> mmio_gpa + msix -> table_offset + msix -> table_count * MSIX_TABLE_ENTRY_SIZE ;
389
+ addr_hi = round_page_up (addr_hi );
390
+
391
+ /* The lower boundary of the 4KB aligned address range for MSI-X table */
392
+ addr_lo = round_page_down (msix -> mmio_gpa + msix -> table_offset );
393
+
394
+ msix -> intercepted_gpa = addr_lo ;
395
+ msix -> intercepted_size = addr_hi - addr_lo ;
396
+
397
+ (void )register_mmio_emulation_handler (vdev -> vpci -> vm , vmsix_table_mmio_access_handler ,
398
+ msix -> intercepted_gpa , msix -> intercepted_gpa + msix -> intercepted_size , vdev );
399
+ }
400
+ ret = 0 ;
401
+ } else {
358
402
pr_err ("%s, MSI-X device (%x) invalid table BIR %d" , __func__ , vdev -> pdev .bdf .value , msix -> table_bar );
359
403
vdev -> msix .capoff = 0U ;
360
- return - EIO ;
404
+ ret = - EIO ;
361
405
}
362
406
363
- /* Mask all table entries */
364
- for (i = 0U ; i < msix -> table_count ; i ++ ) {
365
- msix -> tables [i ].vector_control = PCIM_MSIX_VCTRL_MASK ;
366
- msix -> tables [i ].addr = 0U ;
367
- msix -> tables [i ].data = 0U ;
368
- }
369
-
370
- decode_msix_table_bar (vdev );
371
-
372
- if (msix -> mmio_gpa != 0U ) {
373
- /*
374
- * PCI Spec: a BAR may also map other usable address space that is not associated
375
- * with MSI-X structures, but it must not share any naturally aligned 4 KB
376
- * address range with one where either MSI-X structure resides.
377
- * The MSI-X Table and MSI-X PBA are permitted to co-reside within a naturally
378
- * aligned 4 KB address range.
379
- *
380
- * If PBA or others reside in the same BAR with MSI-X Table, devicemodel could
381
- * emulate them and maps these memory range at the 4KB boundary. Here, we should
382
- * make sure only intercept the minimum number of 4K pages needed for MSI-X table.
383
- */
384
-
385
- /* The higher boundary of the 4KB aligned address range for MSI-X table */
386
- addr_hi = msix -> mmio_gpa + msix -> table_offset + msix -> table_count * MSIX_TABLE_ENTRY_SIZE ;
387
- addr_hi = round_page_up (addr_hi );
388
-
389
- /* The lower boundary of the 4KB aligned address range for MSI-X table */
390
- addr_lo = round_page_down (msix -> mmio_gpa + msix -> table_offset );
391
-
392
- msix -> intercepted_gpa = addr_lo ;
393
- msix -> intercepted_size = addr_hi - addr_lo ;
394
-
395
- (void )register_mmio_emulation_handler (vdev -> vpci -> vm , vmsix_table_mmio_access_handler ,
396
- msix -> intercepted_gpa , msix -> intercepted_gpa + msix -> intercepted_size , vdev );
397
- }
398
-
399
- return 0 ;
407
+ return ret ;
400
408
}
401
409
402
410
static int vmsix_deinit (struct pci_vdev * vdev )
0 commit comments