qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/net/vmxnet3: Fix code to work on big endian hosts, too

Since commit ab06ec43577177a442e8 we test the vmxnet3 device in the
pxe-tester, too (when running "make check SPEED=slow"). This now
revealed that the code is not working there if the host is a big
endian machine (for example ppc64 or s390x) - "make check SPEED=slow"
is now failing on such hosts.

The vmxnet3 code lacks endianness conversions in a couple of places.
Interestingly, the bitfields in the structs in vmxnet3.h already tried to
take care of the *bit* endianness of the C compilers - but the code missed
to change the *byte* endianness when reading or writing the corresponding
structs. So the bitfields are now wrapped into unions which allow to change
the byte endianness during runtime with the non-bitfield member of the union.
With these changes, "make check SPEED=slow" now properly works on big endian
hosts, too.

Reported-by: David Gibson <dgibson@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: David Gibson <dgibson@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>

authored by

Thomas Huth and committed by
Jason Wang
c527e0af 0dacea92

+181 -101
+6
hw/net/vmware_utils.h
··· 83 83 { 84 84 uint16_t res; 85 85 pci_dma_read(d, addr, &res, 2); 86 + res = le16_to_cpu(res); 86 87 VMW_SHPRN("SHMEM load16: %" PRIx64 " (value 0x%X)", addr, res); 87 88 return res; 88 89 } ··· 91 92 vmw_shmem_st16(PCIDevice *d, hwaddr addr, uint16_t value) 92 93 { 93 94 VMW_SHPRN("SHMEM store16: %" PRIx64 " (value 0x%X)", addr, value); 95 + value = cpu_to_le16(value); 94 96 pci_dma_write(d, addr, &value, 2); 95 97 } 96 98 ··· 99 101 { 100 102 uint32_t res; 101 103 pci_dma_read(d, addr, &res, 4); 104 + res = le32_to_cpu(res); 102 105 VMW_SHPRN("SHMEM load32: %" PRIx64 " (value 0x%X)", addr, res); 103 106 return res; 104 107 } ··· 107 110 vmw_shmem_st32(PCIDevice *d, hwaddr addr, uint32_t value) 108 111 { 109 112 VMW_SHPRN("SHMEM store32: %" PRIx64 " (value 0x%X)", addr, value); 113 + value = cpu_to_le32(value); 110 114 pci_dma_write(d, addr, &value, 4); 111 115 } 112 116 ··· 115 119 { 116 120 uint64_t res; 117 121 pci_dma_read(d, addr, &res, 8); 122 + res = le64_to_cpu(res); 118 123 VMW_SHPRN("SHMEM load64: %" PRIx64 " (value %" PRIx64 ")", addr, res); 119 124 return res; 120 125 } ··· 123 128 vmw_shmem_st64(PCIDevice *d, hwaddr addr, uint64_t value) 124 129 { 125 130 VMW_SHPRN("SHMEM store64: %" PRIx64 " (value %" PRIx64 ")", addr, value); 131 + value = cpu_to_le64(value); 126 132 pci_dma_write(d, addr, &value, 8); 127 133 } 128 134
+36 -10
hw/net/vmxnet3.c
··· 222 222 "addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, " 223 223 "dtype: %d, ext1: %d, msscof: %d, hlen: %d, om: %d, " 224 224 "eop: %d, cq: %d, ext2: %d, ti: %d, tci: %d", 225 - le64_to_cpu(descr->addr), descr->len, descr->gen, descr->rsvd, 225 + descr->addr, descr->len, descr->gen, descr->rsvd, 226 226 descr->dtype, descr->ext1, descr->msscof, descr->hlen, descr->om, 227 227 descr->eop, descr->cq, descr->ext2, descr->ti, descr->tci); 228 228 } ··· 241 241 { 242 242 VMW_PKPRN("RX DESCR: addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, " 243 243 "dtype: %d, ext1: %d, btype: %d", 244 - le64_to_cpu(descr->addr), descr->len, descr->gen, 244 + descr->addr, descr->len, descr->gen, 245 245 descr->rsvd, descr->dtype, descr->ext1, descr->btype); 246 246 } 247 247 ··· 535 535 memset(&txcq_descr, 0, sizeof(txcq_descr)); 536 536 txcq_descr.txdIdx = tx_ridx; 537 537 txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring); 538 - 538 + txcq_descr.val1 = cpu_to_le32(txcq_descr.val1); 539 + txcq_descr.val2 = cpu_to_le32(txcq_descr.val2); 539 540 vmxnet3_ring_write_curr_cell(d, &s->txq_descr[qidx].comp_ring, &txcq_descr); 540 541 541 542 /* Flush changes in TX descriptor before changing the counter value */ ··· 685 686 } 686 687 } 687 688 689 + static inline void 690 + vmxnet3_ring_read_curr_txdesc(PCIDevice *pcidev, Vmxnet3Ring *ring, 691 + struct Vmxnet3_TxDesc *txd) 692 + { 693 + vmxnet3_ring_read_curr_cell(pcidev, ring, txd); 694 + txd->addr = le64_to_cpu(txd->addr); 695 + txd->val1 = le32_to_cpu(txd->val1); 696 + txd->val2 = le32_to_cpu(txd->val2); 697 + } 698 + 688 699 static inline bool 689 700 vmxnet3_pop_next_tx_descr(VMXNET3State *s, 690 701 int qidx, ··· 694 705 Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring; 695 706 PCIDevice *d = PCI_DEVICE(s); 696 707 697 - vmxnet3_ring_read_curr_cell(d, ring, txd); 708 + vmxnet3_ring_read_curr_txdesc(d, ring, txd); 698 709 if (txd->gen == vmxnet3_ring_curr_gen(ring)) { 699 710 /* Only read after generation field verification */ 700 711 smp_rmb(); 701 712 /* Re-read to be sure we got the latest version */ 702 - vmxnet3_ring_read_curr_cell(d, ring, txd); 713 + vmxnet3_ring_read_curr_txdesc(d, ring, txd); 703 714 VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring); 704 715 *descr_idx = vmxnet3_ring_curr_cell_idx(ring); 705 716 vmxnet3_inc_tx_consumption_counter(s, qidx); ··· 749 760 750 761 if (!s->skip_current_tx_pkt) { 751 762 data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE; 752 - data_pa = le64_to_cpu(txd.addr); 763 + data_pa = txd.addr; 753 764 754 765 if (!net_tx_pkt_add_raw_fragment(s->tx_pkt, 755 766 data_pa, ··· 792 803 Vmxnet3Ring *ring = &s->rxq_descr[qidx].rx_ring[ridx]; 793 804 *didx = vmxnet3_ring_curr_cell_idx(ring); 794 805 vmxnet3_ring_read_curr_cell(d, ring, dbuf); 806 + dbuf->addr = le64_to_cpu(dbuf->addr); 807 + dbuf->val1 = le32_to_cpu(dbuf->val1); 808 + dbuf->ext1 = le32_to_cpu(dbuf->ext1); 795 809 } 796 810 797 811 static inline uint8_t ··· 811 825 812 826 pci_dma_read(PCI_DEVICE(s), 813 827 daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc)); 828 + rxcd.val1 = le32_to_cpu(rxcd.val1); 829 + rxcd.val2 = le32_to_cpu(rxcd.val2); 830 + rxcd.val3 = le32_to_cpu(rxcd.val3); 814 831 ring_gen = vmxnet3_ring_curr_gen(&s->rxq_descr[qidx].comp_ring); 815 832 816 833 if (rxcd.gen != ring_gen) { ··· 1061 1078 } 1062 1079 } 1063 1080 1081 + static void 1082 + vmxnet3_pci_dma_write_rxcd(PCIDevice *pcidev, dma_addr_t pa, 1083 + struct Vmxnet3_RxCompDesc *rxcd) 1084 + { 1085 + rxcd->val1 = cpu_to_le32(rxcd->val1); 1086 + rxcd->val2 = cpu_to_le32(rxcd->val2); 1087 + rxcd->val3 = cpu_to_le32(rxcd->val3); 1088 + pci_dma_write(pcidev, pa, rxcd, sizeof(*rxcd)); 1089 + } 1090 + 1064 1091 static bool 1065 1092 vmxnet3_indicate_packet(VMXNET3State *s) 1066 1093 { ··· 1099 1126 } 1100 1127 1101 1128 chunk_size = MIN(bytes_left, rxd.len); 1102 - vmxnet3_pci_dma_writev(d, data, bytes_copied, 1103 - le64_to_cpu(rxd.addr), chunk_size); 1129 + vmxnet3_pci_dma_writev(d, data, bytes_copied, rxd.addr, chunk_size); 1104 1130 bytes_copied += chunk_size; 1105 1131 bytes_left -= chunk_size; 1106 1132 1107 1133 vmxnet3_dump_rx_descr(&rxd); 1108 1134 1109 1135 if (ready_rxcd_pa != 0) { 1110 - pci_dma_write(d, ready_rxcd_pa, &rxcd, sizeof(rxcd)); 1136 + vmxnet3_pci_dma_write_rxcd(d, ready_rxcd_pa, &rxcd); 1111 1137 } 1112 1138 1113 1139 memset(&rxcd, 0, sizeof(struct Vmxnet3_RxCompDesc)); ··· 1139 1165 rxcd.eop = 1; 1140 1166 rxcd.err = (bytes_left != 0); 1141 1167 1142 - pci_dma_write(d, ready_rxcd_pa, &rxcd, sizeof(rxcd)); 1168 + vmxnet3_pci_dma_write_rxcd(d, ready_rxcd_pa, &rxcd); 1143 1169 1144 1170 /* Flush RX descriptor changes */ 1145 1171 smp_wmb();
+139 -91
hw/net/vmxnet3.h
··· 226 226 struct Vmxnet3_TxDesc { 227 227 __le64 addr; 228 228 229 + union { 230 + struct { 229 231 #ifdef __BIG_ENDIAN_BITFIELD 230 - u32 msscof:14; /* MSS, checksum offset, flags */ 231 - u32 ext1:1; 232 - u32 dtype:1; /* descriptor type */ 233 - u32 rsvd:1; 234 - u32 gen:1; /* generation bit */ 235 - u32 len:14; 232 + u32 msscof:14; /* MSS, checksum offset, flags */ 233 + u32 ext1:1; 234 + u32 dtype:1; /* descriptor type */ 235 + u32 rsvd:1; 236 + u32 gen:1; /* generation bit */ 237 + u32 len:14; 236 238 #else 237 - u32 len:14; 238 - u32 gen:1; /* generation bit */ 239 - u32 rsvd:1; 240 - u32 dtype:1; /* descriptor type */ 241 - u32 ext1:1; 242 - u32 msscof:14; /* MSS, checksum offset, flags */ 239 + u32 len:14; 240 + u32 gen:1; /* generation bit */ 241 + u32 rsvd:1; 242 + u32 dtype:1; /* descriptor type */ 243 + u32 ext1:1; 244 + u32 msscof:14; /* MSS, checksum offset, flags */ 243 245 #endif /* __BIG_ENDIAN_BITFIELD */ 244 - 246 + }; 247 + u32 val1; 248 + }; 249 + 250 + union { 251 + struct { 245 252 #ifdef __BIG_ENDIAN_BITFIELD 246 - u32 tci:16; /* Tag to Insert */ 247 - u32 ti:1; /* VLAN Tag Insertion */ 248 - u32 ext2:1; 249 - u32 cq:1; /* completion request */ 250 - u32 eop:1; /* End Of Packet */ 251 - u32 om:2; /* offload mode */ 252 - u32 hlen:10; /* header len */ 253 + u32 tci:16; /* Tag to Insert */ 254 + u32 ti:1; /* VLAN Tag Insertion */ 255 + u32 ext2:1; 256 + u32 cq:1; /* completion request */ 257 + u32 eop:1; /* End Of Packet */ 258 + u32 om:2; /* offload mode */ 259 + u32 hlen:10; /* header len */ 253 260 #else 254 - u32 hlen:10; /* header len */ 255 - u32 om:2; /* offload mode */ 256 - u32 eop:1; /* End Of Packet */ 257 - u32 cq:1; /* completion request */ 258 - u32 ext2:1; 259 - u32 ti:1; /* VLAN Tag Insertion */ 260 - u32 tci:16; /* Tag to Insert */ 261 + u32 hlen:10; /* header len */ 262 + u32 om:2; /* offload mode */ 263 + u32 eop:1; /* End Of Packet */ 264 + u32 cq:1; /* completion request */ 265 + u32 ext2:1; 266 + u32 ti:1; /* VLAN Tag Insertion */ 267 + u32 tci:16; /* Tag to Insert */ 261 268 #endif /* __BIG_ENDIAN_BITFIELD */ 269 + }; 270 + u32 val2; 271 + }; 262 272 }; 263 273 264 274 /* TxDesc.OM values */ ··· 291 301 #define VMXNET3_TCD_GEN_DWORD_SHIFT 3 292 302 293 303 struct Vmxnet3_TxCompDesc { 294 - u32 txdIdx:12; /* Index of the EOP TxDesc */ 295 - u32 ext1:20; 296 - 304 + union { 305 + struct { 306 + #ifdef __BIG_ENDIAN_BITFIELD 307 + u32 ext1:20; 308 + u32 txdIdx:12; /* Index of the EOP TxDesc */ 309 + #else 310 + u32 txdIdx:12; /* Index of the EOP TxDesc */ 311 + u32 ext1:20; 312 + #endif 313 + }; 314 + u32 val1; 315 + }; 297 316 __le32 ext2; 298 317 __le32 ext3; 299 318 300 - u32 rsvd:24; 301 - u32 type:7; /* completion type */ 302 - u32 gen:1; /* generation bit */ 319 + union { 320 + struct { 321 + #ifdef __BIG_ENDIAN_BITFIELD 322 + u32 gen:1; /* generation bit */ 323 + u32 type:7; /* completion type */ 324 + u32 rsvd:24; 325 + #else 326 + u32 rsvd:24; 327 + u32 type:7; /* completion type */ 328 + u32 gen:1; /* generation bit */ 329 + #endif 330 + }; 331 + u32 val2; 332 + }; 303 333 }; 304 334 305 335 struct Vmxnet3_RxDesc { 306 336 __le64 addr; 307 - 337 + union { 338 + struct { 308 339 #ifdef __BIG_ENDIAN_BITFIELD 309 - u32 gen:1; /* Generation bit */ 310 - u32 rsvd:15; 311 - u32 dtype:1; /* Descriptor type */ 312 - u32 btype:1; /* Buffer Type */ 313 - u32 len:14; 340 + u32 gen:1; /* Generation bit */ 341 + u32 rsvd:15; 342 + u32 dtype:1; /* Descriptor type */ 343 + u32 btype:1; /* Buffer Type */ 344 + u32 len:14; 314 345 #else 315 - u32 len:14; 316 - u32 btype:1; /* Buffer Type */ 317 - u32 dtype:1; /* Descriptor type */ 318 - u32 rsvd:15; 319 - u32 gen:1; /* Generation bit */ 346 + u32 len:14; 347 + u32 btype:1; /* Buffer Type */ 348 + u32 dtype:1; /* Descriptor type */ 349 + u32 rsvd:15; 350 + u32 gen:1; /* Generation bit */ 320 351 #endif 352 + }; 353 + u32 val1; 354 + }; 321 355 u32 ext1; 322 356 }; 323 357 ··· 330 364 #define VMXNET3_RXD_GEN_SHIFT 31 331 365 332 366 struct Vmxnet3_RxCompDesc { 367 + union { 368 + struct { 333 369 #ifdef __BIG_ENDIAN_BITFIELD 334 - u32 ext2:1; 335 - u32 cnc:1; /* Checksum Not Calculated */ 336 - u32 rssType:4; /* RSS hash type used */ 337 - u32 rqID:10; /* rx queue/ring ID */ 338 - u32 sop:1; /* Start of Packet */ 339 - u32 eop:1; /* End of Packet */ 340 - u32 ext1:2; 341 - u32 rxdIdx:12; /* Index of the RxDesc */ 370 + u32 ext2:1; 371 + u32 cnc:1; /* Checksum Not Calculated */ 372 + u32 rssType:4; /* RSS hash type used */ 373 + u32 rqID:10; /* rx queue/ring ID */ 374 + u32 sop:1; /* Start of Packet */ 375 + u32 eop:1; /* End of Packet */ 376 + u32 ext1:2; 377 + u32 rxdIdx:12; /* Index of the RxDesc */ 342 378 #else 343 - u32 rxdIdx:12; /* Index of the RxDesc */ 344 - u32 ext1:2; 345 - u32 eop:1; /* End of Packet */ 346 - u32 sop:1; /* Start of Packet */ 347 - u32 rqID:10; /* rx queue/ring ID */ 348 - u32 rssType:4; /* RSS hash type used */ 349 - u32 cnc:1; /* Checksum Not Calculated */ 350 - u32 ext2:1; 379 + u32 rxdIdx:12; /* Index of the RxDesc */ 380 + u32 ext1:2; 381 + u32 eop:1; /* End of Packet */ 382 + u32 sop:1; /* Start of Packet */ 383 + u32 rqID:10; /* rx queue/ring ID */ 384 + u32 rssType:4; /* RSS hash type used */ 385 + u32 cnc:1; /* Checksum Not Calculated */ 386 + u32 ext2:1; 351 387 #endif /* __BIG_ENDIAN_BITFIELD */ 388 + }; 389 + u32 val1; 390 + }; 352 391 353 392 __le32 rssHash; /* RSS hash value */ 354 393 394 + union { 395 + struct { 355 396 #ifdef __BIG_ENDIAN_BITFIELD 356 - u32 tci:16; /* Tag stripped */ 357 - u32 ts:1; /* Tag is stripped */ 358 - u32 err:1; /* Error */ 359 - u32 len:14; /* data length */ 397 + u32 tci:16; /* Tag stripped */ 398 + u32 ts:1; /* Tag is stripped */ 399 + u32 err:1; /* Error */ 400 + u32 len:14; /* data length */ 360 401 #else 361 - u32 len:14; /* data length */ 362 - u32 err:1; /* Error */ 363 - u32 ts:1; /* Tag is stripped */ 364 - u32 tci:16; /* Tag stripped */ 402 + u32 len:14; /* data length */ 403 + u32 err:1; /* Error */ 404 + u32 ts:1; /* Tag is stripped */ 405 + u32 tci:16; /* Tag stripped */ 365 406 #endif /* __BIG_ENDIAN_BITFIELD */ 407 + }; 408 + u32 val2; 409 + }; 366 410 367 - 411 + union { 412 + struct { 368 413 #ifdef __BIG_ENDIAN_BITFIELD 369 - u32 gen:1; /* generation bit */ 370 - u32 type:7; /* completion type */ 371 - u32 fcs:1; /* Frame CRC correct */ 372 - u32 frg:1; /* IP Fragment */ 373 - u32 v4:1; /* IPv4 */ 374 - u32 v6:1; /* IPv6 */ 375 - u32 ipc:1; /* IP Checksum Correct */ 376 - u32 tcp:1; /* TCP packet */ 377 - u32 udp:1; /* UDP packet */ 378 - u32 tuc:1; /* TCP/UDP Checksum Correct */ 379 - u32 csum:16; 414 + u32 gen:1; /* generation bit */ 415 + u32 type:7; /* completion type */ 416 + u32 fcs:1; /* Frame CRC correct */ 417 + u32 frg:1; /* IP Fragment */ 418 + u32 v4:1; /* IPv4 */ 419 + u32 v6:1; /* IPv6 */ 420 + u32 ipc:1; /* IP Checksum Correct */ 421 + u32 tcp:1; /* TCP packet */ 422 + u32 udp:1; /* UDP packet */ 423 + u32 tuc:1; /* TCP/UDP Checksum Correct */ 424 + u32 csum:16; 380 425 #else 381 - u32 csum:16; 382 - u32 tuc:1; /* TCP/UDP Checksum Correct */ 383 - u32 udp:1; /* UDP packet */ 384 - u32 tcp:1; /* TCP packet */ 385 - u32 ipc:1; /* IP Checksum Correct */ 386 - u32 v6:1; /* IPv6 */ 387 - u32 v4:1; /* IPv4 */ 388 - u32 frg:1; /* IP Fragment */ 389 - u32 fcs:1; /* Frame CRC correct */ 390 - u32 type:7; /* completion type */ 391 - u32 gen:1; /* generation bit */ 426 + u32 csum:16; 427 + u32 tuc:1; /* TCP/UDP Checksum Correct */ 428 + u32 udp:1; /* UDP packet */ 429 + u32 tcp:1; /* TCP packet */ 430 + u32 ipc:1; /* IP Checksum Correct */ 431 + u32 v6:1; /* IPv6 */ 432 + u32 v4:1; /* IPv4 */ 433 + u32 frg:1; /* IP Fragment */ 434 + u32 fcs:1; /* Frame CRC correct */ 435 + u32 type:7; /* completion type */ 436 + u32 gen:1; /* generation bit */ 392 437 #endif /* __BIG_ENDIAN_BITFIELD */ 438 + }; 439 + u32 val3; 440 + }; 393 441 }; 394 442 395 443 /* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */