Commit b7ee1603c16c1feb0d439d2ddf6cf824119d0aab
Committed by
Anthony Liguori
1 parent
1b64fcae
qemu/pci: make default_write_config use mask table
Change much of hw/pci to use symbolic constants and a table-driven design: add a mask table with writable bits set and readonly bits unset. Detect change by comparing original and new registers. This makes it easy to support capabilities where read-only/writeable bit layout differs between devices, depending on capabilities present. As a result, writing a single byte in BAR registers now works as it should. Writing to upper limit registers in the bridge also works as it should. Code is also shorter. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
2 changed files
with
46 additions
and
117 deletions
hw/pci.c
... | ... | @@ -255,6 +255,17 @@ static PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) |
255 | 255 | return pci_find_bus(bus); |
256 | 256 | } |
257 | 257 | |
258 | +static void pci_init_wmask(PCIDevice *dev) | |
259 | +{ | |
260 | + int i; | |
261 | + dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff; | |
262 | + dev->wmask[PCI_INTERRUPT_LINE] = 0xff; | |
263 | + dev->wmask[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | |
264 | + | PCI_COMMAND_MASTER; | |
265 | + for (i = PCI_CONFIG_HEADER_SIZE; i < PCI_CONFIG_SPACE_SIZE; ++i) | |
266 | + dev->wmask[i] = 0xff; | |
267 | +} | |
268 | + | |
258 | 269 | /* -1 for devfn means auto assign */ |
259 | 270 | static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, |
260 | 271 | const char *name, int devfn, |
... | ... | @@ -276,6 +287,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, |
276 | 287 | pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); |
277 | 288 | memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); |
278 | 289 | pci_set_default_subsystem_id(pci_dev); |
290 | + pci_init_wmask(pci_dev); | |
279 | 291 | |
280 | 292 | if (!config_read) |
281 | 293 | config_read = pci_default_read_config; |
... | ... | @@ -347,6 +359,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, |
347 | 359 | { |
348 | 360 | PCIIORegion *r; |
349 | 361 | uint32_t addr; |
362 | + uint32_t wmask; | |
350 | 363 | |
351 | 364 | if ((unsigned int)region_num >= PCI_NUM_REGIONS) |
352 | 365 | return; |
... | ... | @@ -362,12 +375,17 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, |
362 | 375 | r->size = size; |
363 | 376 | r->type = type; |
364 | 377 | r->map_func = map_func; |
378 | + | |
379 | + wmask = ~(size - 1); | |
365 | 380 | if (region_num == PCI_ROM_SLOT) { |
366 | 381 | addr = 0x30; |
382 | + /* ROM enable bit is writeable */ | |
383 | + wmask |= 1; | |
367 | 384 | } else { |
368 | 385 | addr = 0x10 + region_num * 4; |
369 | 386 | } |
370 | 387 | *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); |
388 | + *(uint32_t *)(pci_dev->wmask + addr) = cpu_to_le32(wmask); | |
371 | 389 | } |
372 | 390 | |
373 | 391 | static void pci_update_mappings(PCIDevice *d) |
... | ... | @@ -476,118 +494,21 @@ uint32_t pci_default_read_config(PCIDevice *d, |
476 | 494 | return val; |
477 | 495 | } |
478 | 496 | |
479 | -void pci_default_write_config(PCIDevice *d, | |
480 | - uint32_t address, uint32_t val, int len) | |
497 | +void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) | |
481 | 498 | { |
482 | - int can_write, i; | |
483 | - uint32_t end, addr; | |
484 | - | |
485 | - if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || | |
486 | - (address >= 0x30 && address < 0x34))) { | |
487 | - PCIIORegion *r; | |
488 | - int reg; | |
499 | + uint8_t orig[PCI_CONFIG_SPACE_SIZE]; | |
500 | + int i; | |
489 | 501 | |
490 | - if ( address >= 0x30 ) { | |
491 | - reg = PCI_ROM_SLOT; | |
492 | - }else{ | |
493 | - reg = (address - 0x10) >> 2; | |
494 | - } | |
495 | - r = &d->io_regions[reg]; | |
496 | - if (r->size == 0) | |
497 | - goto default_config; | |
498 | - /* compute the stored value */ | |
499 | - if (reg == PCI_ROM_SLOT) { | |
500 | - /* keep ROM enable bit */ | |
501 | - val &= (~(r->size - 1)) | 1; | |
502 | - } else { | |
503 | - val &= ~(r->size - 1); | |
504 | - val |= r->type; | |
505 | - } | |
506 | - *(uint32_t *)(d->config + address) = cpu_to_le32(val); | |
507 | - pci_update_mappings(d); | |
508 | - return; | |
509 | - } | |
510 | - default_config: | |
511 | 502 | /* not efficient, but simple */ |
512 | - addr = address; | |
513 | - for(i = 0; i < len; i++) { | |
514 | - /* default read/write accesses */ | |
515 | - switch(d->config[0x0e]) { | |
516 | - case 0x00: | |
517 | - case 0x80: | |
518 | - switch(addr) { | |
519 | - case 0x00: | |
520 | - case 0x01: | |
521 | - case 0x02: | |
522 | - case 0x03: | |
523 | - case 0x06: | |
524 | - case 0x07: | |
525 | - case 0x08: | |
526 | - case 0x09: | |
527 | - case 0x0a: | |
528 | - case 0x0b: | |
529 | - case 0x0e: | |
530 | - case 0x10 ... 0x27: /* base */ | |
531 | - case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ | |
532 | - case 0x30 ... 0x33: /* rom */ | |
533 | - case 0x3d: | |
534 | - can_write = 0; | |
535 | - break; | |
536 | - default: | |
537 | - can_write = 1; | |
538 | - break; | |
539 | - } | |
540 | - break; | |
541 | - default: | |
542 | - case 0x01: | |
543 | - switch(addr) { | |
544 | - case 0x00: | |
545 | - case 0x01: | |
546 | - case 0x02: | |
547 | - case 0x03: | |
548 | - case 0x06: | |
549 | - case 0x07: | |
550 | - case 0x08: | |
551 | - case 0x09: | |
552 | - case 0x0a: | |
553 | - case 0x0b: | |
554 | - case 0x0e: | |
555 | - case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ | |
556 | - case 0x38 ... 0x3b: /* rom */ | |
557 | - case 0x3d: | |
558 | - can_write = 0; | |
559 | - break; | |
560 | - default: | |
561 | - can_write = 1; | |
562 | - break; | |
563 | - } | |
564 | - break; | |
565 | - } | |
566 | - if (can_write) { | |
567 | - /* Mask out writes to reserved bits in registers */ | |
568 | - switch (addr) { | |
569 | - case 0x05: | |
570 | - val &= ~PCI_COMMAND_RESERVED_MASK_HI; | |
571 | - break; | |
572 | - case 0x06: | |
573 | - val &= ~PCI_STATUS_RESERVED_MASK_LO; | |
574 | - break; | |
575 | - case 0x07: | |
576 | - val &= ~PCI_STATUS_RESERVED_MASK_HI; | |
577 | - break; | |
578 | - } | |
579 | - d->config[addr] = val; | |
580 | - } | |
581 | - if (++addr > 0xff) | |
582 | - break; | |
583 | - val >>= 8; | |
503 | + memcpy(orig, d->config, PCI_CONFIG_SPACE_SIZE); | |
504 | + for(i = 0; i < l && addr < PCI_CONFIG_SPACE_SIZE; val >>= 8, ++i, ++addr) { | |
505 | + uint8_t wmask = d->wmask[addr]; | |
506 | + d->config[addr] = (d->config[addr] & ~wmask) | (val & wmask); | |
584 | 507 | } |
585 | - | |
586 | - end = address + len; | |
587 | - if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) { | |
588 | - /* if the command register is modified, we must modify the mappings */ | |
508 | + if (memcmp(orig + PCI_BASE_ADDRESS_0, d->config + PCI_BASE_ADDRESS_0, 24) | |
509 | + || ((orig[PCI_COMMAND] ^ d->config[PCI_COMMAND]) | |
510 | + & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))) | |
589 | 511 | pci_update_mappings(d); |
590 | - } | |
591 | 512 | } |
592 | 513 | |
593 | 514 | void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) |
... | ... | @@ -880,16 +801,8 @@ static void pci_bridge_write_config(PCIDevice *d, |
880 | 801 | { |
881 | 802 | PCIBridge *s = (PCIBridge *)d; |
882 | 803 | |
883 | - if (address == 0x19 || (address == 0x18 && len > 1)) { | |
884 | - if (address == 0x19) | |
885 | - s->bus->bus_num = val & 0xff; | |
886 | - else | |
887 | - s->bus->bus_num = (val >> 8) & 0xff; | |
888 | -#if defined(DEBUG_PCI) | |
889 | - printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num); | |
890 | -#endif | |
891 | - } | |
892 | 804 | pci_default_write_config(d, address, val, len); |
805 | + s->bus->bus_num = d->config[PCI_SECONDARY_BUS]; | |
893 | 806 | } |
894 | 807 | |
895 | 808 | PCIBus *pci_find_bus(int bus_num) | ... | ... |
hw/pci.h
... | ... | @@ -98,16 +98,24 @@ typedef struct PCIIORegion { |
98 | 98 | #define PCI_COMMAND 0x04 /* 16 bits */ |
99 | 99 | #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ |
100 | 100 | #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ |
101 | +#define PCI_COMMAND_MASTER 0x4 /* Enable bus master */ | |
101 | 102 | #define PCI_STATUS 0x06 /* 16 bits */ |
102 | 103 | #define PCI_REVISION_ID 0x08 /* 8 bits */ |
103 | 104 | #define PCI_CLASS_DEVICE 0x0a /* Device class */ |
105 | +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ | |
106 | +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ | |
104 | 107 | #define PCI_HEADER_TYPE 0x0e /* 8 bits */ |
105 | 108 | #define PCI_HEADER_TYPE_NORMAL 0 |
106 | 109 | #define PCI_HEADER_TYPE_BRIDGE 1 |
107 | 110 | #define PCI_HEADER_TYPE_CARDBUS 2 |
108 | 111 | #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 |
112 | +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ | |
113 | +#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ | |
114 | +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ | |
115 | +#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ | |
109 | 116 | #define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16 bits */ |
110 | 117 | #define PCI_SUBSYSTEM_ID 0x2e /* 16 bits */ |
118 | +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ | |
111 | 119 | #define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ |
112 | 120 | #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ |
113 | 121 | #define PCI_MIN_GNT 0x3e /* 8 bits */ |
... | ... | @@ -137,10 +145,18 @@ typedef struct PCIIORegion { |
137 | 145 | |
138 | 146 | #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8) |
139 | 147 | |
148 | +/* Size of the standard PCI config header */ | |
149 | +#define PCI_CONFIG_HEADER_SIZE 0x40 | |
150 | +/* Size of the standard PCI config space */ | |
151 | +#define PCI_CONFIG_SPACE_SIZE 0x100 | |
152 | + | |
140 | 153 | struct PCIDevice { |
141 | 154 | DeviceState qdev; |
142 | 155 | /* PCI config space */ |
143 | - uint8_t config[256]; | |
156 | + uint8_t config[PCI_CONFIG_SPACE_SIZE]; | |
157 | + | |
158 | + /* Used to implement R/W bytes */ | |
159 | + uint8_t wmask[PCI_CONFIG_SPACE_SIZE]; | |
144 | 160 | |
145 | 161 | /* the following fields are read only */ |
146 | 162 | PCIBus *bus; | ... | ... |