Commit 52fc1d83bc50b0b6fc6861cfecc5763edbad7e60
1 parent
b26177d7
Save/load PCI-device, PCI-bus and PIIX3 irq-related state (patches by Uri Lublin.
Note that other PCI bridges are not fixed here. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3793 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
63 additions
and
7 deletions
hw/pci.c
| @@ -42,6 +42,7 @@ struct PCIBus { | @@ -42,6 +42,7 @@ struct PCIBus { | ||
| 42 | PCIBus *next; | 42 | PCIBus *next; |
| 43 | /* The bus IRQ state is the logical OR of the connected devices. | 43 | /* The bus IRQ state is the logical OR of the connected devices. |
| 44 | Keep a count of the number of devices with raised IRQs. */ | 44 | Keep a count of the number of devices with raised IRQs. */ |
| 45 | + int nirq; | ||
| 45 | int irq_count[]; | 46 | int irq_count[]; |
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| @@ -52,16 +53,51 @@ target_phys_addr_t pci_mem_base; | @@ -52,16 +53,51 @@ target_phys_addr_t pci_mem_base; | ||
| 52 | static int pci_irq_index; | 53 | static int pci_irq_index; |
| 53 | static PCIBus *first_bus; | 54 | static PCIBus *first_bus; |
| 54 | 55 | ||
| 56 | +static void pcibus_save(QEMUFile *f, void *opaque) | ||
| 57 | +{ | ||
| 58 | + PCIBus *bus = (PCIBus *)opaque; | ||
| 59 | + int i; | ||
| 60 | + | ||
| 61 | + qemu_put_be32(f, bus->nirq); | ||
| 62 | + for (i = 0; i < bus->nirq; i++) | ||
| 63 | + qemu_put_be32(f, bus->irq_count[i]); | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | +static int pcibus_load(QEMUFile *f, void *opaque, int version_id) | ||
| 67 | +{ | ||
| 68 | + PCIBus *bus = (PCIBus *)opaque; | ||
| 69 | + int i, nirq; | ||
| 70 | + | ||
| 71 | + if (version_id != 1) | ||
| 72 | + return -EINVAL; | ||
| 73 | + | ||
| 74 | + nirq = qemu_get_be32(f); | ||
| 75 | + if (bus->nirq != nirq) { | ||
| 76 | + fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n", | ||
| 77 | + nirq, bus->nirq); | ||
| 78 | + return -EINVAL; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + for (i = 0; i < nirq; i++) | ||
| 82 | + bus->irq_count[i] = qemu_get_be32(f); | ||
| 83 | + | ||
| 84 | + return 0; | ||
| 85 | +} | ||
| 86 | + | ||
| 55 | PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, | 87 | PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, |
| 56 | qemu_irq *pic, int devfn_min, int nirq) | 88 | qemu_irq *pic, int devfn_min, int nirq) |
| 57 | { | 89 | { |
| 58 | PCIBus *bus; | 90 | PCIBus *bus; |
| 91 | + static int nbus = 0; | ||
| 92 | + | ||
| 59 | bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); | 93 | bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int))); |
| 60 | bus->set_irq = set_irq; | 94 | bus->set_irq = set_irq; |
| 61 | bus->map_irq = map_irq; | 95 | bus->map_irq = map_irq; |
| 62 | bus->irq_opaque = pic; | 96 | bus->irq_opaque = pic; |
| 63 | bus->devfn_min = devfn_min; | 97 | bus->devfn_min = devfn_min; |
| 98 | + bus->nirq = nirq; | ||
| 64 | first_bus = bus; | 99 | first_bus = bus; |
| 100 | + register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus); | ||
| 65 | return bus; | 101 | return bus; |
| 66 | } | 102 | } |
| 67 | 103 | ||
| @@ -83,18 +119,29 @@ int pci_bus_num(PCIBus *s) | @@ -83,18 +119,29 @@ int pci_bus_num(PCIBus *s) | ||
| 83 | 119 | ||
| 84 | void pci_device_save(PCIDevice *s, QEMUFile *f) | 120 | void pci_device_save(PCIDevice *s, QEMUFile *f) |
| 85 | { | 121 | { |
| 86 | - qemu_put_be32(f, 1); /* PCI device version */ | 122 | + int i; |
| 123 | + | ||
| 124 | + qemu_put_be32(f, 2); /* PCI device version */ | ||
| 87 | qemu_put_buffer(f, s->config, 256); | 125 | qemu_put_buffer(f, s->config, 256); |
| 126 | + for (i = 0; i < 4; i++) | ||
| 127 | + qemu_put_be32(f, s->irq_state[i]); | ||
| 88 | } | 128 | } |
| 89 | 129 | ||
| 90 | int pci_device_load(PCIDevice *s, QEMUFile *f) | 130 | int pci_device_load(PCIDevice *s, QEMUFile *f) |
| 91 | { | 131 | { |
| 92 | uint32_t version_id; | 132 | uint32_t version_id; |
| 133 | + int i; | ||
| 134 | + | ||
| 93 | version_id = qemu_get_be32(f); | 135 | version_id = qemu_get_be32(f); |
| 94 | - if (version_id != 1) | 136 | + if (version_id > 2) |
| 95 | return -EINVAL; | 137 | return -EINVAL; |
| 96 | qemu_get_buffer(f, s->config, 256); | 138 | qemu_get_buffer(f, s->config, 256); |
| 97 | pci_update_mappings(s); | 139 | pci_update_mappings(s); |
| 140 | + | ||
| 141 | + if (version_id >= 2) | ||
| 142 | + for (i = 0; i < 4; i ++) | ||
| 143 | + s->irq_state[i] = qemu_get_be32(f); | ||
| 144 | + | ||
| 98 | return 0; | 145 | return 0; |
| 99 | } | 146 | } |
| 100 | 147 |
hw/piix_pci.c
| @@ -57,6 +57,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) | @@ -57,6 +57,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) | ||
| 57 | 57 | ||
| 58 | static uint32_t isa_page_descs[384 / 4]; | 58 | static uint32_t isa_page_descs[384 / 4]; |
| 59 | static uint8_t smm_enabled; | 59 | static uint8_t smm_enabled; |
| 60 | +static int pci_irq_levels[4]; | ||
| 60 | 61 | ||
| 61 | static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) | 62 | static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r) |
| 62 | { | 63 | { |
| @@ -139,22 +140,32 @@ static void i440fx_write_config(PCIDevice *d, | @@ -139,22 +140,32 @@ static void i440fx_write_config(PCIDevice *d, | ||
| 139 | static void i440fx_save(QEMUFile* f, void *opaque) | 140 | static void i440fx_save(QEMUFile* f, void *opaque) |
| 140 | { | 141 | { |
| 141 | PCIDevice *d = opaque; | 142 | PCIDevice *d = opaque; |
| 143 | + int i; | ||
| 144 | + | ||
| 142 | pci_device_save(d, f); | 145 | pci_device_save(d, f); |
| 143 | qemu_put_8s(f, &smm_enabled); | 146 | qemu_put_8s(f, &smm_enabled); |
| 147 | + | ||
| 148 | + for (i = 0; i < 4; i++) | ||
| 149 | + qemu_put_be32(f, pci_irq_levels[i]); | ||
| 144 | } | 150 | } |
| 145 | 151 | ||
| 146 | static int i440fx_load(QEMUFile* f, void *opaque, int version_id) | 152 | static int i440fx_load(QEMUFile* f, void *opaque, int version_id) |
| 147 | { | 153 | { |
| 148 | PCIDevice *d = opaque; | 154 | PCIDevice *d = opaque; |
| 149 | - int ret; | 155 | + int ret, i; |
| 150 | 156 | ||
| 151 | - if (version_id != 1) | 157 | + if (version_id > 2) |
| 152 | return -EINVAL; | 158 | return -EINVAL; |
| 153 | ret = pci_device_load(d, f); | 159 | ret = pci_device_load(d, f); |
| 154 | if (ret < 0) | 160 | if (ret < 0) |
| 155 | return ret; | 161 | return ret; |
| 156 | i440fx_update_memory_mappings(d); | 162 | i440fx_update_memory_mappings(d); |
| 157 | qemu_get_8s(f, &smm_enabled); | 163 | qemu_get_8s(f, &smm_enabled); |
| 164 | + | ||
| 165 | + if (version_id >= 2) | ||
| 166 | + for (i = 0; i < 4; i++) | ||
| 167 | + pci_irq_levels[i] = qemu_get_be32(f); | ||
| 168 | + | ||
| 158 | return 0; | 169 | return 0; |
| 159 | } | 170 | } |
| 160 | 171 | ||
| @@ -192,7 +203,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) | @@ -192,7 +203,7 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic) | ||
| 192 | 203 | ||
| 193 | d->config[0x72] = 0x02; /* SMRAM */ | 204 | d->config[0x72] = 0x02; /* SMRAM */ |
| 194 | 205 | ||
| 195 | - register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d); | 206 | + register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d); |
| 196 | *pi440fx_state = d; | 207 | *pi440fx_state = d; |
| 197 | return b; | 208 | return b; |
| 198 | } | 209 | } |
| @@ -205,8 +216,6 @@ PCIDevice *piix4_dev; | @@ -205,8 +216,6 @@ PCIDevice *piix4_dev; | ||
| 205 | /* just used for simpler irq handling. */ | 216 | /* just used for simpler irq handling. */ |
| 206 | #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) | 217 | #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) |
| 207 | 218 | ||
| 208 | -static int pci_irq_levels[4]; | ||
| 209 | - | ||
| 210 | static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) | 219 | static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) |
| 211 | { | 220 | { |
| 212 | int i, pic_irq, pic_level; | 221 | int i, pic_irq, pic_level; |