Revision a0c7a97e hw/pci.c
b/hw/pci.c | ||
---|---|---|
560 | 560 |
if (!r->size || r->addr == PCI_BAR_UNMAPPED) |
561 | 561 |
continue; |
562 | 562 |
if (r->type == PCI_BASE_ADDRESS_SPACE_IO) { |
563 |
isa_unassign_ioport(r->addr, r->size); |
|
563 |
isa_unassign_ioport(r->addr, r->filtered_size);
|
|
564 | 564 |
} else { |
565 | 565 |
cpu_register_physical_memory(pci_to_cpu_addr(r->addr), |
566 |
r->size, |
|
566 |
r->filtered_size,
|
|
567 | 567 |
IO_MEM_UNASSIGNED); |
568 | 568 |
} |
569 | 569 |
} |
... | ... | |
608 | 608 |
r = &pci_dev->io_regions[region_num]; |
609 | 609 |
r->addr = PCI_BAR_UNMAPPED; |
610 | 610 |
r->size = size; |
611 |
r->filtered_size = size; |
|
611 | 612 |
r->type = type; |
612 | 613 |
r->map_func = map_func; |
613 | 614 |
|
... | ... | |
628 | 629 |
} |
629 | 630 |
} |
630 | 631 |
|
632 |
static uint32_t pci_config_get_io_base(PCIDevice *d, |
|
633 |
uint32_t base, uint32_t base_upper16) |
|
634 |
{ |
|
635 |
uint32_t val; |
|
636 |
|
|
637 |
val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8; |
|
638 |
if (d->config[base] & PCI_IO_RANGE_TYPE_32) { |
|
639 |
val |= (uint32_t)pci_get_word(d->config + PCI_IO_BASE_UPPER16) << 16; |
|
640 |
} |
|
641 |
return val; |
|
642 |
} |
|
643 |
|
|
644 |
static uint64_t pci_config_get_memory_base(PCIDevice *d, uint32_t base) |
|
645 |
{ |
|
646 |
return ((uint64_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK) |
|
647 |
<< 16; |
|
648 |
} |
|
649 |
|
|
650 |
static uint64_t pci_config_get_pref_base(PCIDevice *d, |
|
651 |
uint32_t base, uint32_t upper) |
|
652 |
{ |
|
653 |
uint64_t val; |
|
654 |
val = ((uint64_t)pci_get_word(d->config + base) & |
|
655 |
PCI_PREF_RANGE_MASK) << 16; |
|
656 |
val |= (uint64_t)pci_get_long(d->config + upper) << 32; |
|
657 |
return val; |
|
658 |
} |
|
659 |
|
|
660 |
static pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type) |
|
661 |
{ |
|
662 |
pcibus_t base; |
|
663 |
if (type & PCI_BASE_ADDRESS_SPACE_IO) { |
|
664 |
base = pci_config_get_io_base(bridge, |
|
665 |
PCI_IO_BASE, PCI_IO_BASE_UPPER16); |
|
666 |
} else { |
|
667 |
if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { |
|
668 |
base = pci_config_get_pref_base( |
|
669 |
bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32); |
|
670 |
} else { |
|
671 |
base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE); |
|
672 |
} |
|
673 |
} |
|
674 |
|
|
675 |
return base; |
|
676 |
} |
|
677 |
|
|
678 |
static pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type) |
|
679 |
{ |
|
680 |
pcibus_t limit; |
|
681 |
if (type & PCI_BASE_ADDRESS_SPACE_IO) { |
|
682 |
limit = pci_config_get_io_base(bridge, |
|
683 |
PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16); |
|
684 |
limit |= 0xfff; /* PCI bridge spec 3.2.5.6. */ |
|
685 |
} else { |
|
686 |
if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) { |
|
687 |
limit = pci_config_get_pref_base( |
|
688 |
bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32); |
|
689 |
} else { |
|
690 |
limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT); |
|
691 |
} |
|
692 |
limit |= 0xfffff; /* PCI bridge spec 3.2.5.{1, 8}. */ |
|
693 |
} |
|
694 |
return limit; |
|
695 |
} |
|
696 |
|
|
697 |
static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size, |
|
698 |
uint8_t type) |
|
699 |
{ |
|
700 |
pcibus_t base = *addr; |
|
701 |
pcibus_t limit = *addr + *size - 1; |
|
702 |
PCIDevice *br; |
|
703 |
|
|
704 |
for (br = d->bus->parent_dev; br; br = br->bus->parent_dev) { |
|
705 |
uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); |
|
706 |
|
|
707 |
if (type & PCI_BASE_ADDRESS_SPACE_IO) { |
|
708 |
if (!(cmd & PCI_COMMAND_IO)) { |
|
709 |
goto no_map; |
|
710 |
} |
|
711 |
} else { |
|
712 |
if (!(cmd & PCI_COMMAND_MEMORY)) { |
|
713 |
goto no_map; |
|
714 |
} |
|
715 |
} |
|
716 |
|
|
717 |
base = MAX(base, pci_bridge_get_base(br, type)); |
|
718 |
limit = MIN(limit, pci_bridge_get_limit(br, type)); |
|
719 |
} |
|
720 |
|
|
721 |
if (base > limit) { |
|
722 |
no_map: |
|
723 |
*addr = PCI_BAR_UNMAPPED; |
|
724 |
*size = 0; |
|
725 |
} else { |
|
726 |
*addr = base; |
|
727 |
*size = limit - base + 1; |
|
728 |
} |
|
729 |
} |
|
730 |
|
|
631 | 731 |
static void pci_update_mappings(PCIDevice *d) |
632 | 732 |
{ |
633 | 733 |
PCIIORegion *r; |
634 | 734 |
int cmd, i; |
635 | 735 |
pcibus_t last_addr, new_addr; |
736 |
pcibus_t filtered_size; |
|
636 | 737 |
|
637 | 738 |
cmd = pci_get_word(d->config + PCI_COMMAND); |
638 | 739 |
for(i = 0; i < PCI_NUM_REGIONS; i++) { |
... | ... | |
696 | 797 |
} |
697 | 798 |
} |
698 | 799 |
|
800 |
/* bridge filtering */ |
|
801 |
filtered_size = r->size; |
|
802 |
if (new_addr != PCI_BAR_UNMAPPED) { |
|
803 |
pci_bridge_filter(d, &new_addr, &filtered_size, r->type); |
|
804 |
} |
|
805 |
|
|
699 | 806 |
/* This bar isn't changed */ |
700 |
if (new_addr == r->addr) |
|
807 |
if (new_addr == r->addr && filtered_size == r->filtered_size)
|
|
701 | 808 |
continue; |
702 | 809 |
|
703 | 810 |
/* now do the real mapping */ |
... | ... | |
710 | 817 |
if (class == 0x0101 && r->size == 4) { |
711 | 818 |
isa_unassign_ioport(r->addr + 2, 1); |
712 | 819 |
} else { |
713 |
isa_unassign_ioport(r->addr, r->size); |
|
820 |
isa_unassign_ioport(r->addr, r->filtered_size);
|
|
714 | 821 |
} |
715 | 822 |
} else { |
716 | 823 |
cpu_register_physical_memory(pci_to_cpu_addr(r->addr), |
717 |
r->size, |
|
824 |
r->filtered_size,
|
|
718 | 825 |
IO_MEM_UNASSIGNED); |
719 |
qemu_unregister_coalesced_mmio(r->addr, r->size); |
|
826 |
qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
|
|
720 | 827 |
} |
721 | 828 |
} |
722 | 829 |
r->addr = new_addr; |
830 |
r->filtered_size = filtered_size; |
|
723 | 831 |
if (r->addr != PCI_BAR_UNMAPPED) { |
724 |
r->map_func(d, i, r->addr, r->size, r->type); |
|
832 |
/* |
|
833 |
* TODO: currently almost all the map funcions assumes |
|
834 |
* filtered_size == size and addr & ~(size - 1) == addr. |
|
835 |
* However with bridge filtering, they aren't always true. |
|
836 |
* Teach them such cases, such that filtered_size < size and |
|
837 |
* addr & (size - 1) != 0. |
|
838 |
*/ |
|
839 |
r->map_func(d, i, r->addr, r->filtered_size, r->type); |
|
725 | 840 |
} |
726 | 841 |
} |
727 | 842 |
} |
... | ... | |
994 | 1109 |
uint32_t did; |
995 | 1110 |
} PCIBridge; |
996 | 1111 |
|
1112 |
|
|
1113 |
static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d) |
|
1114 |
{ |
|
1115 |
pci_update_mappings(d); |
|
1116 |
} |
|
1117 |
|
|
1118 |
static void pci_bridge_update_mappings(PCIBus *b) |
|
1119 |
{ |
|
1120 |
PCIBus *child; |
|
1121 |
|
|
1122 |
pci_for_each_device_under_bus(b, pci_bridge_update_mappings_fn); |
|
1123 |
|
|
1124 |
QLIST_FOREACH(child, &b->child, sibling) { |
|
1125 |
pci_bridge_update_mappings(child); |
|
1126 |
} |
|
1127 |
} |
|
1128 |
|
|
997 | 1129 |
static void pci_bridge_write_config(PCIDevice *d, |
998 | 1130 |
uint32_t address, uint32_t val, int len) |
999 | 1131 |
{ |
1000 | 1132 |
pci_default_write_config(d, address, val, len); |
1133 |
|
|
1134 |
if (/* io base/limit */ |
|
1135 |
ranges_overlap(address, len, PCI_IO_BASE, 2) || |
|
1136 |
|
|
1137 |
/* memory base/limit, prefetchable base/limit and |
|
1138 |
io base/limit upper 16 */ |
|
1139 |
ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { |
|
1140 |
pci_bridge_update_mappings(d->bus); |
|
1141 |
} |
|
1001 | 1142 |
} |
1002 | 1143 |
|
1003 | 1144 |
PCIBus *pci_find_bus(PCIBus *bus, int bus_num) |
Also available in: Unified diff