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,6 +255,17 @@ static PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr) | ||
255 | return pci_find_bus(bus); | 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 | /* -1 for devfn means auto assign */ | 269 | /* -1 for devfn means auto assign */ |
259 | static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, | 270 | static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, |
260 | const char *name, int devfn, | 271 | const char *name, int devfn, |
@@ -276,6 +287,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, | @@ -276,6 +287,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, | ||
276 | pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); | 287 | pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); |
277 | memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); | 288 | memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state)); |
278 | pci_set_default_subsystem_id(pci_dev); | 289 | pci_set_default_subsystem_id(pci_dev); |
290 | + pci_init_wmask(pci_dev); | ||
279 | 291 | ||
280 | if (!config_read) | 292 | if (!config_read) |
281 | config_read = pci_default_read_config; | 293 | config_read = pci_default_read_config; |
@@ -347,6 +359,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | @@ -347,6 +359,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | ||
347 | { | 359 | { |
348 | PCIIORegion *r; | 360 | PCIIORegion *r; |
349 | uint32_t addr; | 361 | uint32_t addr; |
362 | + uint32_t wmask; | ||
350 | 363 | ||
351 | if ((unsigned int)region_num >= PCI_NUM_REGIONS) | 364 | if ((unsigned int)region_num >= PCI_NUM_REGIONS) |
352 | return; | 365 | return; |
@@ -362,12 +375,17 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | @@ -362,12 +375,17 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | ||
362 | r->size = size; | 375 | r->size = size; |
363 | r->type = type; | 376 | r->type = type; |
364 | r->map_func = map_func; | 377 | r->map_func = map_func; |
378 | + | ||
379 | + wmask = ~(size - 1); | ||
365 | if (region_num == PCI_ROM_SLOT) { | 380 | if (region_num == PCI_ROM_SLOT) { |
366 | addr = 0x30; | 381 | addr = 0x30; |
382 | + /* ROM enable bit is writeable */ | ||
383 | + wmask |= 1; | ||
367 | } else { | 384 | } else { |
368 | addr = 0x10 + region_num * 4; | 385 | addr = 0x10 + region_num * 4; |
369 | } | 386 | } |
370 | *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); | 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 | static void pci_update_mappings(PCIDevice *d) | 391 | static void pci_update_mappings(PCIDevice *d) |
@@ -476,118 +494,21 @@ uint32_t pci_default_read_config(PCIDevice *d, | @@ -476,118 +494,21 @@ uint32_t pci_default_read_config(PCIDevice *d, | ||
476 | return val; | 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 | /* not efficient, but simple */ | 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 | pci_update_mappings(d); | 511 | pci_update_mappings(d); |
590 | - } | ||
591 | } | 512 | } |
592 | 513 | ||
593 | void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) | 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,16 +801,8 @@ static void pci_bridge_write_config(PCIDevice *d, | ||
880 | { | 801 | { |
881 | PCIBridge *s = (PCIBridge *)d; | 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 | pci_default_write_config(d, address, val, len); | 804 | pci_default_write_config(d, address, val, len); |
805 | + s->bus->bus_num = d->config[PCI_SECONDARY_BUS]; | ||
893 | } | 806 | } |
894 | 807 | ||
895 | PCIBus *pci_find_bus(int bus_num) | 808 | PCIBus *pci_find_bus(int bus_num) |
hw/pci.h
@@ -98,16 +98,24 @@ typedef struct PCIIORegion { | @@ -98,16 +98,24 @@ typedef struct PCIIORegion { | ||
98 | #define PCI_COMMAND 0x04 /* 16 bits */ | 98 | #define PCI_COMMAND 0x04 /* 16 bits */ |
99 | #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ | 99 | #define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ |
100 | #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ | 100 | #define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ |
101 | +#define PCI_COMMAND_MASTER 0x4 /* Enable bus master */ | ||
101 | #define PCI_STATUS 0x06 /* 16 bits */ | 102 | #define PCI_STATUS 0x06 /* 16 bits */ |
102 | #define PCI_REVISION_ID 0x08 /* 8 bits */ | 103 | #define PCI_REVISION_ID 0x08 /* 8 bits */ |
103 | #define PCI_CLASS_DEVICE 0x0a /* Device class */ | 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 | #define PCI_HEADER_TYPE 0x0e /* 8 bits */ | 107 | #define PCI_HEADER_TYPE 0x0e /* 8 bits */ |
105 | #define PCI_HEADER_TYPE_NORMAL 0 | 108 | #define PCI_HEADER_TYPE_NORMAL 0 |
106 | #define PCI_HEADER_TYPE_BRIDGE 1 | 109 | #define PCI_HEADER_TYPE_BRIDGE 1 |
107 | #define PCI_HEADER_TYPE_CARDBUS 2 | 110 | #define PCI_HEADER_TYPE_CARDBUS 2 |
108 | #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80 | 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 | #define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16 bits */ | 116 | #define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16 bits */ |
110 | #define PCI_SUBSYSTEM_ID 0x2e /* 16 bits */ | 117 | #define PCI_SUBSYSTEM_ID 0x2e /* 16 bits */ |
118 | +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ | ||
111 | #define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ | 119 | #define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ |
112 | #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ | 120 | #define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ |
113 | #define PCI_MIN_GNT 0x3e /* 8 bits */ | 121 | #define PCI_MIN_GNT 0x3e /* 8 bits */ |
@@ -137,10 +145,18 @@ typedef struct PCIIORegion { | @@ -137,10 +145,18 @@ typedef struct PCIIORegion { | ||
137 | 145 | ||
138 | #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8) | 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 | struct PCIDevice { | 153 | struct PCIDevice { |
141 | DeviceState qdev; | 154 | DeviceState qdev; |
142 | /* PCI config space */ | 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 | /* the following fields are read only */ | 161 | /* the following fields are read only */ |
146 | PCIBus *bus; | 162 | PCIBus *bus; |