Commit b946a1533209f61a93e34898aebb5b43154b99c3
1 parent
32a8f6ae
Introduce VLANClientState::cleanup() (Mark McLoughlin)
We're currently leaking memory and file descriptors on device hot-unplug. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7150 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
19 changed files
with
347 additions
and
66 deletions
hw/dp8393x.c
@@ -156,6 +156,7 @@ typedef struct dp8393xState { | @@ -156,6 +156,7 @@ typedef struct dp8393xState { | ||
156 | QEMUTimer *watchdog; | 156 | QEMUTimer *watchdog; |
157 | int64_t wt_last_update; | 157 | int64_t wt_last_update; |
158 | VLANClientState *vc; | 158 | VLANClientState *vc; |
159 | + int mmio_index; | ||
159 | 160 | ||
160 | /* Registers */ | 161 | /* Registers */ |
161 | uint8_t cam[16][6]; | 162 | uint8_t cam[16][6]; |
@@ -858,12 +859,23 @@ static void nic_reset(void *opaque) | @@ -858,12 +859,23 @@ static void nic_reset(void *opaque) | ||
858 | dp8393x_update_irq(s); | 859 | dp8393x_update_irq(s); |
859 | } | 860 | } |
860 | 861 | ||
862 | +static void nic_cleanup(VLANClientState *vc) | ||
863 | +{ | ||
864 | + dp8393xState *s = vc->opaque; | ||
865 | + | ||
866 | + cpu_unregister_io_memory(s->mmio_index); | ||
867 | + | ||
868 | + qemu_del_timer(s->watchdog); | ||
869 | + qemu_free_timer(s->watchdog); | ||
870 | + | ||
871 | + qemu_free(s); | ||
872 | +} | ||
873 | + | ||
861 | void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, | 874 | void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, |
862 | qemu_irq irq, void* mem_opaque, | 875 | qemu_irq irq, void* mem_opaque, |
863 | void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) | 876 | void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) |
864 | { | 877 | { |
865 | dp8393xState *s; | 878 | dp8393xState *s; |
866 | - int io; | ||
867 | 879 | ||
868 | qemu_check_nic_model(nd, "dp83932"); | 880 | qemu_check_nic_model(nd, "dp83932"); |
869 | 881 | ||
@@ -877,12 +889,12 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, | @@ -877,12 +889,12 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, | ||
877 | s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ | 889 | s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ |
878 | 890 | ||
879 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 891 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
880 | - nic_receive, nic_can_receive, s); | 892 | + nic_receive, nic_can_receive, nic_cleanup, s); |
881 | 893 | ||
882 | qemu_format_nic_info_str(s->vc, nd->macaddr); | 894 | qemu_format_nic_info_str(s->vc, nd->macaddr); |
883 | qemu_register_reset(nic_reset, s); | 895 | qemu_register_reset(nic_reset, s); |
884 | nic_reset(s); | 896 | nic_reset(s); |
885 | 897 | ||
886 | - io = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); | ||
887 | - cpu_register_physical_memory(base, 0x40 << it_shift, io); | 898 | + s->mmio_index = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); |
899 | + cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index); | ||
888 | } | 900 | } |
hw/e1000.c
@@ -1033,6 +1033,14 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num, | @@ -1033,6 +1033,14 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num, | ||
1033 | excluded_regs[i] - 4); | 1033 | excluded_regs[i] - 4); |
1034 | } | 1034 | } |
1035 | 1035 | ||
1036 | +static void | ||
1037 | +e1000_cleanup(VLANClientState *vc) | ||
1038 | +{ | ||
1039 | + E1000State *d = vc->opaque; | ||
1040 | + | ||
1041 | + unregister_savevm("e1000", d); | ||
1042 | +} | ||
1043 | + | ||
1036 | static int | 1044 | static int |
1037 | pci_e1000_uninit(PCIDevice *dev) | 1045 | pci_e1000_uninit(PCIDevice *dev) |
1038 | { | 1046 | { |
@@ -1094,7 +1102,8 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -1094,7 +1102,8 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
1094 | memset(&d->tx, 0, sizeof d->tx); | 1102 | memset(&d->tx, 0, sizeof d->tx); |
1095 | 1103 | ||
1096 | d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 1104 | d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
1097 | - e1000_receive, e1000_can_receive, d); | 1105 | + e1000_receive, e1000_can_receive, |
1106 | + e1000_cleanup, d); | ||
1098 | d->vc->link_status_changed = e1000_set_link_status; | 1107 | d->vc->link_status_changed = e1000_set_link_status; |
1099 | 1108 | ||
1100 | qemu_format_nic_info_str(d->vc, nd->macaddr); | 1109 | qemu_format_nic_info_str(d->vc, nd->macaddr); |
hw/eepro100.c
@@ -1710,6 +1710,25 @@ static void nic_save(QEMUFile * f, void *opaque) | @@ -1710,6 +1710,25 @@ static void nic_save(QEMUFile * f, void *opaque) | ||
1710 | qemu_put_buffer(f, s->configuration, sizeof(s->configuration)); | 1710 | qemu_put_buffer(f, s->configuration, sizeof(s->configuration)); |
1711 | } | 1711 | } |
1712 | 1712 | ||
1713 | +static void nic_cleanup(VLANClientState *vc) | ||
1714 | +{ | ||
1715 | + EEPRO100State *s = vc->opaque; | ||
1716 | + | ||
1717 | + unregister_savevm(vc->model, s); | ||
1718 | + | ||
1719 | + eeprom93xx_free(s->eeprom); | ||
1720 | +} | ||
1721 | + | ||
1722 | +static int pci_nic_uninit(PCIDevice *dev) | ||
1723 | +{ | ||
1724 | + PCIEEPRO100State *d = (PCIEEPRO100State *) dev; | ||
1725 | + EEPRO100State *s = &d->eepro100; | ||
1726 | + | ||
1727 | + cpu_unregister_io_memory(s->mmio_index); | ||
1728 | + | ||
1729 | + return 0; | ||
1730 | +} | ||
1731 | + | ||
1713 | static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) | 1732 | static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) |
1714 | { | 1733 | { |
1715 | PCIEEPRO100State *d; | 1734 | PCIEEPRO100State *d; |
@@ -1720,6 +1739,7 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) | @@ -1720,6 +1739,7 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) | ||
1720 | d = (PCIEEPRO100State *) pci_register_device(bus, nd->model, | 1739 | d = (PCIEEPRO100State *) pci_register_device(bus, nd->model, |
1721 | sizeof(PCIEEPRO100State), -1, | 1740 | sizeof(PCIEEPRO100State), -1, |
1722 | NULL, NULL); | 1741 | NULL, NULL); |
1742 | + d->dev.unregister = pci_nic_uninit; | ||
1723 | 1743 | ||
1724 | s = &d->eepro100; | 1744 | s = &d->eepro100; |
1725 | s->device = device; | 1745 | s->device = device; |
@@ -1750,7 +1770,8 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) | @@ -1750,7 +1770,8 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) | ||
1750 | nic_reset(s); | 1770 | nic_reset(s); |
1751 | 1771 | ||
1752 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 1772 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
1753 | - nic_receive, nic_can_receive, s); | 1773 | + nic_receive, nic_can_receive, |
1774 | + nic_cleanup, s); | ||
1754 | 1775 | ||
1755 | qemu_format_nic_info_str(s->vc, s->macaddr); | 1776 | qemu_format_nic_info_str(s->vc, s->macaddr); |
1756 | 1777 |
hw/etraxfs_eth.c
@@ -554,6 +554,16 @@ static CPUWriteMemoryFunc *eth_write[] = { | @@ -554,6 +554,16 @@ static CPUWriteMemoryFunc *eth_write[] = { | ||
554 | ð_writel, | 554 | ð_writel, |
555 | }; | 555 | }; |
556 | 556 | ||
557 | +static void eth_cleanup(VLANClientState *vc) | ||
558 | +{ | ||
559 | + struct fs_eth *eth = vc->opaque; | ||
560 | + | ||
561 | + cpu_unregister_io_memory(eth->ethregs); | ||
562 | + | ||
563 | + qemu_free(eth->dma_out); | ||
564 | + qemu_free(eth); | ||
565 | +} | ||
566 | + | ||
557 | void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | 567 | void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |
558 | qemu_irq *irq, target_phys_addr_t base, int phyaddr) | 568 | qemu_irq *irq, target_phys_addr_t base, int phyaddr) |
559 | { | 569 | { |
@@ -585,7 +595,8 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | @@ -585,7 +595,8 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | ||
585 | cpu_register_physical_memory (base, 0x5c, eth->ethregs); | 595 | cpu_register_physical_memory (base, 0x5c, eth->ethregs); |
586 | 596 | ||
587 | eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 597 | eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
588 | - eth_receive, eth_can_receive, eth); | 598 | + eth_receive, eth_can_receive, |
599 | + eth_cleanup, eth); | ||
589 | eth->vc->opaque = eth; | 600 | eth->vc->opaque = eth; |
590 | eth->vc->link_status_changed = eth_set_link; | 601 | eth->vc->link_status_changed = eth_set_link; |
591 | 602 |
hw/mcf_fec.c
@@ -24,6 +24,7 @@ do { printf("mcf_fec: " fmt , ##args); } while (0) | @@ -24,6 +24,7 @@ do { printf("mcf_fec: " fmt , ##args); } while (0) | ||
24 | 24 | ||
25 | typedef struct { | 25 | typedef struct { |
26 | qemu_irq *irq; | 26 | qemu_irq *irq; |
27 | + int mmio_index; | ||
27 | VLANClientState *vc; | 28 | VLANClientState *vc; |
28 | uint32_t irq_state; | 29 | uint32_t irq_state; |
29 | uint32_t eir; | 30 | uint32_t eir; |
@@ -441,21 +442,30 @@ static CPUWriteMemoryFunc *mcf_fec_writefn[] = { | @@ -441,21 +442,30 @@ static CPUWriteMemoryFunc *mcf_fec_writefn[] = { | ||
441 | mcf_fec_write | 442 | mcf_fec_write |
442 | }; | 443 | }; |
443 | 444 | ||
445 | +static void mcf_fec_cleanup(VLANClientState *vc) | ||
446 | +{ | ||
447 | + mcf_fec_state *s = vc->opaque; | ||
448 | + | ||
449 | + cpu_unregister_io_memory(s->mmio_index); | ||
450 | + | ||
451 | + qemu_free(s); | ||
452 | +} | ||
453 | + | ||
444 | void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) | 454 | void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) |
445 | { | 455 | { |
446 | mcf_fec_state *s; | 456 | mcf_fec_state *s; |
447 | - int iomemtype; | ||
448 | 457 | ||
449 | qemu_check_nic_model(nd, "mcf_fec"); | 458 | qemu_check_nic_model(nd, "mcf_fec"); |
450 | 459 | ||
451 | s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); | 460 | s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); |
452 | s->irq = irq; | 461 | s->irq = irq; |
453 | - iomemtype = cpu_register_io_memory(0, mcf_fec_readfn, | ||
454 | - mcf_fec_writefn, s); | ||
455 | - cpu_register_physical_memory(base, 0x400, iomemtype); | 462 | + s->mmio_index = cpu_register_io_memory(0, mcf_fec_readfn, |
463 | + mcf_fec_writefn, s); | ||
464 | + cpu_register_physical_memory(base, 0x400, s->mmio_index); | ||
456 | 465 | ||
457 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 466 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
458 | - mcf_fec_receive, mcf_fec_can_receive, s); | 467 | + mcf_fec_receive, mcf_fec_can_receive, |
468 | + mcf_fec_cleanup, s); | ||
459 | memcpy(s->macaddr, nd->macaddr, 6); | 469 | memcpy(s->macaddr, nd->macaddr, 6); |
460 | qemu_format_nic_info_str(s->vc, s->macaddr); | 470 | qemu_format_nic_info_str(s->vc, s->macaddr); |
461 | } | 471 | } |
hw/mipsnet.c
@@ -33,6 +33,7 @@ typedef struct MIPSnetState { | @@ -33,6 +33,7 @@ typedef struct MIPSnetState { | ||
33 | uint32_t intctl; | 33 | uint32_t intctl; |
34 | uint8_t rx_buffer[MAX_ETH_FRAME_SIZE]; | 34 | uint8_t rx_buffer[MAX_ETH_FRAME_SIZE]; |
35 | uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; | 35 | uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; |
36 | + int io_base; | ||
36 | qemu_irq irq; | 37 | qemu_irq irq; |
37 | VLANClientState *vc; | 38 | VLANClientState *vc; |
38 | } MIPSnetState; | 39 | } MIPSnetState; |
@@ -231,6 +232,17 @@ static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) | @@ -231,6 +232,17 @@ static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) | ||
231 | return 0; | 232 | return 0; |
232 | } | 233 | } |
233 | 234 | ||
235 | +static void mipsnet_cleanup(VLANClientState *vc) | ||
236 | +{ | ||
237 | + MIPSnetState *s = vc->opaque; | ||
238 | + | ||
239 | + unregister_savevm("mipsnet", s); | ||
240 | + | ||
241 | + isa_unassign_ioport(s->io_base, 36); | ||
242 | + | ||
243 | + qemu_free(s); | ||
244 | +} | ||
245 | + | ||
234 | void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) | 246 | void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) |
235 | { | 247 | { |
236 | MIPSnetState *s; | 248 | MIPSnetState *s; |
@@ -246,10 +258,12 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) | @@ -246,10 +258,12 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) | ||
246 | register_ioport_write(base, 36, 4, mipsnet_ioport_write, s); | 258 | register_ioport_write(base, 36, 4, mipsnet_ioport_write, s); |
247 | register_ioport_read(base, 36, 4, mipsnet_ioport_read, s); | 259 | register_ioport_read(base, 36, 4, mipsnet_ioport_read, s); |
248 | 260 | ||
261 | + s->io_base = base; | ||
249 | s->irq = irq; | 262 | s->irq = irq; |
250 | if (nd && nd->vlan) { | 263 | if (nd && nd->vlan) { |
251 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 264 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
252 | - mipsnet_receive, mipsnet_can_receive, s); | 265 | + mipsnet_receive, mipsnet_can_receive, |
266 | + mipsnet_cleanup, s); | ||
253 | } else { | 267 | } else { |
254 | s->vc = NULL; | 268 | s->vc = NULL; |
255 | } | 269 | } |
hw/musicpal.c
@@ -536,6 +536,7 @@ typedef struct mv88w8618_eth_state { | @@ -536,6 +536,7 @@ typedef struct mv88w8618_eth_state { | ||
536 | uint32_t smir; | 536 | uint32_t smir; |
537 | uint32_t icr; | 537 | uint32_t icr; |
538 | uint32_t imr; | 538 | uint32_t imr; |
539 | + int mmio_index; | ||
539 | int vlan_header; | 540 | int vlan_header; |
540 | uint32_t tx_queue[2]; | 541 | uint32_t tx_queue[2]; |
541 | uint32_t rx_queue[4]; | 542 | uint32_t rx_queue[4]; |
@@ -745,20 +746,29 @@ static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = { | @@ -745,20 +746,29 @@ static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = { | ||
745 | mv88w8618_eth_write | 746 | mv88w8618_eth_write |
746 | }; | 747 | }; |
747 | 748 | ||
749 | +static void eth_cleanup(VLANClientState *vc) | ||
750 | +{ | ||
751 | + mv88w8618_eth_state *s = vc->opaque; | ||
752 | + | ||
753 | + cpu_unregister_io_memory(s->mmio_index); | ||
754 | + | ||
755 | + qemu_free(s); | ||
756 | +} | ||
757 | + | ||
748 | static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) | 758 | static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) |
749 | { | 759 | { |
750 | mv88w8618_eth_state *s; | 760 | mv88w8618_eth_state *s; |
751 | - int iomemtype; | ||
752 | 761 | ||
753 | qemu_check_nic_model(nd, "mv88w8618"); | 762 | qemu_check_nic_model(nd, "mv88w8618"); |
754 | 763 | ||
755 | s = qemu_mallocz(sizeof(mv88w8618_eth_state)); | 764 | s = qemu_mallocz(sizeof(mv88w8618_eth_state)); |
756 | s->irq = irq; | 765 | s->irq = irq; |
757 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 766 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
758 | - eth_receive, eth_can_receive, s); | ||
759 | - iomemtype = cpu_register_io_memory(0, mv88w8618_eth_readfn, | ||
760 | - mv88w8618_eth_writefn, s); | ||
761 | - cpu_register_physical_memory(base, MP_ETH_SIZE, iomemtype); | 767 | + eth_receive, eth_can_receive, |
768 | + eth_cleanup, s); | ||
769 | + s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, | ||
770 | + mv88w8618_eth_writefn, s); | ||
771 | + cpu_register_physical_memory(base, MP_ETH_SIZE, s->mmio_index); | ||
762 | } | 772 | } |
763 | 773 | ||
764 | /* LCD register offsets */ | 774 | /* LCD register offsets */ |
hw/ne2000.c
@@ -140,6 +140,7 @@ typedef struct NE2000State { | @@ -140,6 +140,7 @@ typedef struct NE2000State { | ||
140 | uint8_t curpag; | 140 | uint8_t curpag; |
141 | uint8_t mult[8]; /* multicast mask array */ | 141 | uint8_t mult[8]; /* multicast mask array */ |
142 | qemu_irq irq; | 142 | qemu_irq irq; |
143 | + int isa_io_base; | ||
143 | PCIDevice *pci_dev; | 144 | PCIDevice *pci_dev; |
144 | VLANClientState *vc; | 145 | VLANClientState *vc; |
145 | uint8_t macaddr[6]; | 146 | uint8_t macaddr[6]; |
@@ -718,6 +719,19 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) | @@ -718,6 +719,19 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) | ||
718 | return 0; | 719 | return 0; |
719 | } | 720 | } |
720 | 721 | ||
722 | +static void isa_ne2000_cleanup(VLANClientState *vc) | ||
723 | +{ | ||
724 | + NE2000State *s = vc->opaque; | ||
725 | + | ||
726 | + unregister_savevm("ne2000", s); | ||
727 | + | ||
728 | + isa_unassign_ioport(s->isa_io_base, 16); | ||
729 | + isa_unassign_ioport(s->isa_io_base + 0x10, 2); | ||
730 | + isa_unassign_ioport(s->isa_io_base + 0x1f, 1); | ||
731 | + | ||
732 | + qemu_free(s); | ||
733 | +} | ||
734 | + | ||
721 | void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) | 735 | void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) |
722 | { | 736 | { |
723 | NE2000State *s; | 737 | NE2000State *s; |
@@ -736,13 +750,15 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) | @@ -736,13 +750,15 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) | ||
736 | 750 | ||
737 | register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); | 751 | register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); |
738 | register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); | 752 | register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
753 | + s->isa_io_base = base; | ||
739 | s->irq = irq; | 754 | s->irq = irq; |
740 | memcpy(s->macaddr, nd->macaddr, 6); | 755 | memcpy(s->macaddr, nd->macaddr, 6); |
741 | 756 | ||
742 | ne2000_reset(s); | 757 | ne2000_reset(s); |
743 | 758 | ||
744 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 759 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
745 | - ne2000_receive, ne2000_can_receive, s); | 760 | + ne2000_receive, ne2000_can_receive, |
761 | + isa_ne2000_cleanup, s); | ||
746 | 762 | ||
747 | qemu_format_nic_info_str(s->vc, s->macaddr); | 763 | qemu_format_nic_info_str(s->vc, s->macaddr); |
748 | 764 | ||
@@ -777,6 +793,13 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, | @@ -777,6 +793,13 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, | ||
777 | register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); | 793 | register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
778 | } | 794 | } |
779 | 795 | ||
796 | +static void ne2000_cleanup(VLANClientState *vc) | ||
797 | +{ | ||
798 | + NE2000State *s = vc->opaque; | ||
799 | + | ||
800 | + unregister_savevm("ne2000", s); | ||
801 | +} | ||
802 | + | ||
780 | PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) | 803 | PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) |
781 | { | 804 | { |
782 | PCINE2000State *d; | 805 | PCINE2000State *d; |
@@ -802,7 +825,8 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -802,7 +825,8 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
802 | memcpy(s->macaddr, nd->macaddr, 6); | 825 | memcpy(s->macaddr, nd->macaddr, 6); |
803 | ne2000_reset(s); | 826 | ne2000_reset(s); |
804 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 827 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
805 | - ne2000_receive, ne2000_can_receive, s); | 828 | + ne2000_receive, ne2000_can_receive, |
829 | + ne2000_cleanup, s); | ||
806 | 830 | ||
807 | qemu_format_nic_info_str(s->vc, s->macaddr); | 831 | qemu_format_nic_info_str(s->vc, s->macaddr); |
808 | 832 |
hw/pcnet.c
@@ -75,6 +75,7 @@ struct PCNetState_st { | @@ -75,6 +75,7 @@ struct PCNetState_st { | ||
75 | uint8_t buffer[4096]; | 75 | uint8_t buffer[4096]; |
76 | int tx_busy; | 76 | int tx_busy; |
77 | qemu_irq irq; | 77 | qemu_irq irq; |
78 | + qemu_irq *reset_irq; | ||
78 | void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, | 79 | void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, |
79 | uint8_t *buf, int len, int do_bswap); | 80 | uint8_t *buf, int len, int do_bswap); |
80 | void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, | 81 | void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, |
@@ -1929,7 +1930,15 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id) | @@ -1929,7 +1930,15 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id) | ||
1929 | return 0; | 1930 | return 0; |
1930 | } | 1931 | } |
1931 | 1932 | ||
1932 | -static void pcnet_common_init(PCNetState *d, NICInfo *nd) | 1933 | +static void pcnet_common_cleanup(PCNetState *d) |
1934 | +{ | ||
1935 | + unregister_savevm("pcnet", d); | ||
1936 | + | ||
1937 | + qemu_del_timer(d->poll_timer); | ||
1938 | + qemu_free_timer(d->poll_timer); | ||
1939 | +} | ||
1940 | + | ||
1941 | +static void pcnet_common_init(PCNetState *d, NICInfo *nd, NetCleanup *cleanup) | ||
1933 | { | 1942 | { |
1934 | d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); | 1943 | d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); |
1935 | 1944 | ||
@@ -1937,7 +1946,8 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd) | @@ -1937,7 +1946,8 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd) | ||
1937 | 1946 | ||
1938 | if (nd && nd->vlan) { | 1947 | if (nd && nd->vlan) { |
1939 | d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 1948 | d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
1940 | - pcnet_receive, pcnet_can_receive, d); | 1949 | + pcnet_receive, pcnet_can_receive, |
1950 | + cleanup, d); | ||
1941 | 1951 | ||
1942 | qemu_format_nic_info_str(d->vc, d->nd->macaddr); | 1952 | qemu_format_nic_info_str(d->vc, d->nd->macaddr); |
1943 | } else { | 1953 | } else { |
@@ -1985,6 +1995,22 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, | @@ -1985,6 +1995,22 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, | ||
1985 | cpu_physical_memory_read(addr, buf, len); | 1995 | cpu_physical_memory_read(addr, buf, len); |
1986 | } | 1996 | } |
1987 | 1997 | ||
1998 | +static void pci_pcnet_cleanup(VLANClientState *vc) | ||
1999 | +{ | ||
2000 | + PCNetState *d = vc->opaque; | ||
2001 | + | ||
2002 | + pcnet_common_cleanup(d); | ||
2003 | +} | ||
2004 | + | ||
2005 | +static int pci_pcnet_uninit(PCIDevice *dev) | ||
2006 | +{ | ||
2007 | + PCNetState *d = (PCNetState *)dev; | ||
2008 | + | ||
2009 | + cpu_unregister_io_memory(d->mmio_index); | ||
2010 | + | ||
2011 | + return 0; | ||
2012 | +} | ||
2013 | + | ||
1988 | PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) | 2014 | PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) |
1989 | { | 2015 | { |
1990 | PCNetState *d; | 2016 | PCNetState *d; |
@@ -1997,7 +2023,7 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -1997,7 +2023,7 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
1997 | 2023 | ||
1998 | d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), | 2024 | d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), |
1999 | devfn, NULL, NULL); | 2025 | devfn, NULL, NULL); |
2000 | - | 2026 | + d->dev.unregister = pci_pcnet_uninit; |
2001 | pci_conf = d->dev.config; | 2027 | pci_conf = d->dev.config; |
2002 | 2028 | ||
2003 | pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); | 2029 | pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); |
@@ -2031,7 +2057,8 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -2031,7 +2057,8 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
2031 | d->phys_mem_write = pci_physical_memory_write; | 2057 | d->phys_mem_write = pci_physical_memory_write; |
2032 | d->pci_dev = &d->dev; | 2058 | d->pci_dev = &d->dev; |
2033 | 2059 | ||
2034 | - pcnet_common_init(d, nd); | 2060 | + pcnet_common_init(d, nd, pci_pcnet_cleanup); |
2061 | + | ||
2035 | return (PCIDevice *)d; | 2062 | return (PCIDevice *)d; |
2036 | } | 2063 | } |
2037 | 2064 | ||
@@ -2081,29 +2108,42 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { | @@ -2081,29 +2108,42 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { | ||
2081 | NULL, | 2108 | NULL, |
2082 | }; | 2109 | }; |
2083 | 2110 | ||
2111 | +static void lance_cleanup(VLANClientState *vc) | ||
2112 | +{ | ||
2113 | + PCNetState *d = vc->opaque; | ||
2114 | + | ||
2115 | + pcnet_common_cleanup(d); | ||
2116 | + | ||
2117 | + qemu_free_irqs(d->reset_irq); | ||
2118 | + | ||
2119 | + cpu_unregister_io_memory(d->mmio_index); | ||
2120 | + | ||
2121 | + qemu_free(d); | ||
2122 | +} | ||
2123 | + | ||
2084 | void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, | 2124 | void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, |
2085 | qemu_irq irq, qemu_irq *reset) | 2125 | qemu_irq irq, qemu_irq *reset) |
2086 | { | 2126 | { |
2087 | PCNetState *d; | 2127 | PCNetState *d; |
2088 | - int lance_io_memory; | ||
2089 | 2128 | ||
2090 | qemu_check_nic_model(nd, "lance"); | 2129 | qemu_check_nic_model(nd, "lance"); |
2091 | 2130 | ||
2092 | d = qemu_mallocz(sizeof(PCNetState)); | 2131 | d = qemu_mallocz(sizeof(PCNetState)); |
2093 | 2132 | ||
2094 | - lance_io_memory = | 2133 | + d->mmio_index = |
2095 | cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); | 2134 | cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); |
2096 | 2135 | ||
2097 | d->dma_opaque = dma_opaque; | 2136 | d->dma_opaque = dma_opaque; |
2098 | 2137 | ||
2099 | - *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1); | 2138 | + d->reset_irq = qemu_allocate_irqs(parent_lance_reset, d, 1); |
2139 | + *reset = *d->reset_irq; | ||
2100 | 2140 | ||
2101 | - cpu_register_physical_memory(leaddr, 4, lance_io_memory); | 2141 | + cpu_register_physical_memory(leaddr, 4, d->mmio_index); |
2102 | 2142 | ||
2103 | d->irq = irq; | 2143 | d->irq = irq; |
2104 | d->phys_mem_read = ledma_memory_read; | 2144 | d->phys_mem_read = ledma_memory_read; |
2105 | d->phys_mem_write = ledma_memory_write; | 2145 | d->phys_mem_write = ledma_memory_write; |
2106 | 2146 | ||
2107 | - pcnet_common_init(d, nd); | 2147 | + pcnet_common_init(d, nd, lance_cleanup); |
2108 | } | 2148 | } |
2109 | #endif /* TARGET_SPARC */ | 2149 | #endif /* TARGET_SPARC */ |
hw/rtl8139.c
@@ -3414,6 +3414,33 @@ static void rtl8139_timer(void *opaque) | @@ -3414,6 +3414,33 @@ static void rtl8139_timer(void *opaque) | ||
3414 | } | 3414 | } |
3415 | #endif /* RTL8139_ONBOARD_TIMER */ | 3415 | #endif /* RTL8139_ONBOARD_TIMER */ |
3416 | 3416 | ||
3417 | +static void rtl8139_cleanup(VLANClientState *vc) | ||
3418 | +{ | ||
3419 | + RTL8139State *s = vc->opaque; | ||
3420 | + | ||
3421 | + if (s->cplus_txbuffer) { | ||
3422 | + qemu_free(s->cplus_txbuffer); | ||
3423 | + s->cplus_txbuffer = NULL; | ||
3424 | + } | ||
3425 | + | ||
3426 | +#ifdef RTL8139_ONBOARD_TIMER | ||
3427 | + qemu_del_timer(s->timer); | ||
3428 | + qemu_free_timer(s->timer); | ||
3429 | +#endif | ||
3430 | + | ||
3431 | + unregister_savevm("rtl8139", s); | ||
3432 | +} | ||
3433 | + | ||
3434 | +static int pci_rtl8139_uninit(PCIDevice *dev) | ||
3435 | +{ | ||
3436 | + PCIRTL8139State *d = (PCIRTL8139State *)dev; | ||
3437 | + RTL8139State *s = &d->rtl8139; | ||
3438 | + | ||
3439 | + cpu_unregister_io_memory(s->rtl8139_mmio_io_addr); | ||
3440 | + | ||
3441 | + return 0; | ||
3442 | +} | ||
3443 | + | ||
3417 | PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) | 3444 | PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) |
3418 | { | 3445 | { |
3419 | PCIRTL8139State *d; | 3446 | PCIRTL8139State *d; |
@@ -3424,6 +3451,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -3424,6 +3451,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
3424 | "RTL8139", sizeof(PCIRTL8139State), | 3451 | "RTL8139", sizeof(PCIRTL8139State), |
3425 | devfn, | 3452 | devfn, |
3426 | NULL, NULL); | 3453 | NULL, NULL); |
3454 | + d->dev.unregister = pci_rtl8139_uninit; | ||
3427 | pci_conf = d->dev.config; | 3455 | pci_conf = d->dev.config; |
3428 | pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK); | 3456 | pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK); |
3429 | pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139); | 3457 | pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139); |
@@ -3450,7 +3478,8 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -3450,7 +3478,8 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
3450 | memcpy(s->macaddr, nd->macaddr, 6); | 3478 | memcpy(s->macaddr, nd->macaddr, 6); |
3451 | rtl8139_reset(s); | 3479 | rtl8139_reset(s); |
3452 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 3480 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
3453 | - rtl8139_receive, rtl8139_can_receive, s); | 3481 | + rtl8139_receive, rtl8139_can_receive, |
3482 | + rtl8139_cleanup, s); | ||
3454 | 3483 | ||
3455 | qemu_format_nic_info_str(s->vc, s->macaddr); | 3484 | qemu_format_nic_info_str(s->vc, s->macaddr); |
3456 | 3485 |
hw/smc91c111.c
@@ -42,6 +42,7 @@ typedef struct { | @@ -42,6 +42,7 @@ typedef struct { | ||
42 | uint8_t int_level; | 42 | uint8_t int_level; |
43 | uint8_t int_mask; | 43 | uint8_t int_mask; |
44 | uint8_t macaddr[6]; | 44 | uint8_t macaddr[6]; |
45 | + int mmio_index; | ||
45 | } smc91c111_state; | 46 | } smc91c111_state; |
46 | 47 | ||
47 | #define RCR_SOFT_RST 0x8000 | 48 | #define RCR_SOFT_RST 0x8000 |
@@ -690,24 +691,32 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = { | @@ -690,24 +691,32 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = { | ||
690 | smc91c111_writel | 691 | smc91c111_writel |
691 | }; | 692 | }; |
692 | 693 | ||
694 | +static void smc91c111_cleanup(VLANClientState *vc) | ||
695 | +{ | ||
696 | + smc91c111_state *s = vc->opaque; | ||
697 | + | ||
698 | + cpu_unregister_io_memory(s->mmio_index); | ||
699 | + qemu_free(s); | ||
700 | +} | ||
701 | + | ||
693 | void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) | 702 | void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) |
694 | { | 703 | { |
695 | smc91c111_state *s; | 704 | smc91c111_state *s; |
696 | - int iomemtype; | ||
697 | 705 | ||
698 | qemu_check_nic_model(nd, "smc91c111"); | 706 | qemu_check_nic_model(nd, "smc91c111"); |
699 | 707 | ||
700 | s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); | 708 | s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); |
701 | - iomemtype = cpu_register_io_memory(0, smc91c111_readfn, | ||
702 | - smc91c111_writefn, s); | ||
703 | - cpu_register_physical_memory(base, 16, iomemtype); | 709 | + s->mmio_index = cpu_register_io_memory(0, smc91c111_readfn, |
710 | + smc91c111_writefn, s); | ||
711 | + cpu_register_physical_memory(base, 16, s->mmio_index); | ||
704 | s->irq = irq; | 712 | s->irq = irq; |
705 | memcpy(s->macaddr, nd->macaddr, 6); | 713 | memcpy(s->macaddr, nd->macaddr, 6); |
706 | 714 | ||
707 | smc91c111_reset(s); | 715 | smc91c111_reset(s); |
708 | 716 | ||
709 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 717 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
710 | - smc91c111_receive, smc91c111_can_receive, s); | 718 | + smc91c111_receive, smc91c111_can_receive, |
719 | + smc91c111_cleanup, s); | ||
711 | qemu_format_nic_info_str(s->vc, s->macaddr); | 720 | qemu_format_nic_info_str(s->vc, s->macaddr); |
712 | /* ??? Save/restore. */ | 721 | /* ??? Save/restore. */ |
713 | } | 722 | } |
hw/stellaris_enet.c
@@ -69,6 +69,7 @@ typedef struct { | @@ -69,6 +69,7 @@ typedef struct { | ||
69 | VLANClientState *vc; | 69 | VLANClientState *vc; |
70 | qemu_irq irq; | 70 | qemu_irq irq; |
71 | uint8_t macaddr[6]; | 71 | uint8_t macaddr[6]; |
72 | + int mmio_index; | ||
72 | } stellaris_enet_state; | 73 | } stellaris_enet_state; |
73 | 74 | ||
74 | static void stellaris_enet_update(stellaris_enet_state *s) | 75 | static void stellaris_enet_update(stellaris_enet_state *s) |
@@ -384,23 +385,35 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) | @@ -384,23 +385,35 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) | ||
384 | return 0; | 385 | return 0; |
385 | } | 386 | } |
386 | 387 | ||
388 | +static void stellaris_enet_cleanup(VLANClientState *vc) | ||
389 | +{ | ||
390 | + stellaris_enet_state *s = vc->opaque; | ||
391 | + | ||
392 | + unregister_savevm("stellaris_enet", s); | ||
393 | + | ||
394 | + cpu_unregister_io_memory(s->mmio_index); | ||
395 | + | ||
396 | + qemu_free(s); | ||
397 | +} | ||
398 | + | ||
387 | void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) | 399 | void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) |
388 | { | 400 | { |
389 | stellaris_enet_state *s; | 401 | stellaris_enet_state *s; |
390 | - int iomemtype; | ||
391 | 402 | ||
392 | qemu_check_nic_model(nd, "stellaris"); | 403 | qemu_check_nic_model(nd, "stellaris"); |
393 | 404 | ||
394 | s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state)); | 405 | s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state)); |
395 | - iomemtype = cpu_register_io_memory(0, stellaris_enet_readfn, | ||
396 | - stellaris_enet_writefn, s); | ||
397 | - cpu_register_physical_memory(base, 0x00001000, iomemtype); | 406 | + s->mmio_index = cpu_register_io_memory(0, stellaris_enet_readfn, |
407 | + stellaris_enet_writefn, s); | ||
408 | + cpu_register_physical_memory(base, 0x00001000, s->mmio_index); | ||
398 | s->irq = irq; | 409 | s->irq = irq; |
399 | memcpy(s->macaddr, nd->macaddr, 6); | 410 | memcpy(s->macaddr, nd->macaddr, 6); |
400 | 411 | ||
401 | if (nd->vlan) { | 412 | if (nd->vlan) { |
402 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 413 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
403 | - stellaris_enet_receive, stellaris_enet_can_receive, s); | 414 | + stellaris_enet_receive, |
415 | + stellaris_enet_can_receive, | ||
416 | + stellaris_enet_cleanup, s); | ||
404 | qemu_format_nic_info_str(s->vc, s->macaddr); | 417 | qemu_format_nic_info_str(s->vc, s->macaddr); |
405 | } | 418 | } |
406 | 419 |
hw/usb-net.c
@@ -1415,14 +1415,20 @@ static int usbnet_can_receive(void *opaque) | @@ -1415,14 +1415,20 @@ static int usbnet_can_receive(void *opaque) | ||
1415 | return !s->in_len; | 1415 | return !s->in_len; |
1416 | } | 1416 | } |
1417 | 1417 | ||
1418 | +static void usbnet_cleanup(VLANClientState *vc) | ||
1419 | +{ | ||
1420 | + USBNetState *s = vc->opaque; | ||
1421 | + | ||
1422 | + rndis_clear_responsequeue(s); | ||
1423 | + qemu_free(s); | ||
1424 | +} | ||
1425 | + | ||
1418 | static void usb_net_handle_destroy(USBDevice *dev) | 1426 | static void usb_net_handle_destroy(USBDevice *dev) |
1419 | { | 1427 | { |
1420 | USBNetState *s = (USBNetState *) dev; | 1428 | USBNetState *s = (USBNetState *) dev; |
1421 | 1429 | ||
1422 | /* TODO: remove the nd_table[] entry */ | 1430 | /* TODO: remove the nd_table[] entry */ |
1423 | qemu_del_vlan_client(s->vc); | 1431 | qemu_del_vlan_client(s->vc); |
1424 | - rndis_clear_responsequeue(s); | ||
1425 | - qemu_free(s); | ||
1426 | } | 1432 | } |
1427 | 1433 | ||
1428 | USBDevice *usb_net_init(NICInfo *nd) | 1434 | USBDevice *usb_net_init(NICInfo *nd) |
@@ -1452,7 +1458,9 @@ USBDevice *usb_net_init(NICInfo *nd) | @@ -1452,7 +1458,9 @@ USBDevice *usb_net_init(NICInfo *nd) | ||
1452 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), | 1458 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), |
1453 | "QEMU USB Network Interface"); | 1459 | "QEMU USB Network Interface"); |
1454 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 1460 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
1455 | - usbnet_receive, usbnet_can_receive, s); | 1461 | + usbnet_receive, |
1462 | + usbnet_can_receive, | ||
1463 | + usbnet_cleanup, s); | ||
1456 | 1464 | ||
1457 | qemu_format_nic_info_str(s->vc, s->mac); | 1465 | qemu_format_nic_info_str(s->vc, s->mac); |
1458 | 1466 |
hw/virtio-net.c
@@ -570,6 +570,21 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) | @@ -570,6 +570,21 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) | ||
570 | return 0; | 570 | return 0; |
571 | } | 571 | } |
572 | 572 | ||
573 | +static void virtio_net_cleanup(VLANClientState *vc) | ||
574 | +{ | ||
575 | + VirtIONet *n = vc->opaque; | ||
576 | + | ||
577 | + unregister_savevm("virtio-net", n); | ||
578 | + | ||
579 | + qemu_free(n->mac_table.macs); | ||
580 | + qemu_free(n->vlans); | ||
581 | + | ||
582 | + qemu_del_timer(n->tx_timer); | ||
583 | + qemu_free_timer(n->tx_timer); | ||
584 | + | ||
585 | + virtio_cleanup(&n->vdev); | ||
586 | +} | ||
587 | + | ||
573 | PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) | 588 | PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) |
574 | { | 589 | { |
575 | VirtIONet *n; | 590 | VirtIONet *n; |
@@ -598,7 +613,9 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) | @@ -598,7 +613,9 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) | ||
598 | memcpy(n->mac, nd->macaddr, ETH_ALEN); | 613 | memcpy(n->mac, nd->macaddr, ETH_ALEN); |
599 | n->status = VIRTIO_NET_S_LINK_UP; | 614 | n->status = VIRTIO_NET_S_LINK_UP; |
600 | n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, | 615 | n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
601 | - virtio_net_receive, virtio_net_can_receive, n); | 616 | + virtio_net_receive, |
617 | + virtio_net_can_receive, | ||
618 | + virtio_net_cleanup, n); | ||
602 | n->vc->link_status_changed = virtio_net_set_link_status; | 619 | n->vc->link_status_changed = virtio_net_set_link_status; |
603 | 620 | ||
604 | qemu_format_nic_info_str(n->vc, n->mac); | 621 | qemu_format_nic_info_str(n->vc, n->mac); |
hw/virtio.c
@@ -750,6 +750,13 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) | @@ -750,6 +750,13 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) | ||
750 | virtio_update_irq(vdev); | 750 | virtio_update_irq(vdev); |
751 | } | 751 | } |
752 | 752 | ||
753 | +void virtio_cleanup(VirtIODevice *vdev) | ||
754 | +{ | ||
755 | + if (vdev->config) | ||
756 | + qemu_free(vdev->config); | ||
757 | + qemu_free(vdev->vq); | ||
758 | +} | ||
759 | + | ||
753 | VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name, | 760 | VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name, |
754 | uint16_t vendor, uint16_t device, | 761 | uint16_t vendor, uint16_t device, |
755 | uint16_t subvendor, uint16_t subdevice, | 762 | uint16_t subvendor, uint16_t subdevice, |
hw/virtio.h
@@ -117,6 +117,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f); | @@ -117,6 +117,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f); | ||
117 | 117 | ||
118 | void virtio_load(VirtIODevice *vdev, QEMUFile *f); | 118 | void virtio_load(VirtIODevice *vdev, QEMUFile *f); |
119 | 119 | ||
120 | +void virtio_cleanup(VirtIODevice *vdev); | ||
121 | + | ||
120 | void virtio_notify_config(VirtIODevice *vdev); | 122 | void virtio_notify_config(VirtIODevice *vdev); |
121 | 123 | ||
122 | void virtio_queue_set_notification(VirtQueue *vq, int enable); | 124 | void virtio_queue_set_notification(VirtQueue *vq, int enable); |
net.c
@@ -333,6 +333,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, | @@ -333,6 +333,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, | ||
333 | const char *name, | 333 | const char *name, |
334 | IOReadHandler *fd_read, | 334 | IOReadHandler *fd_read, |
335 | IOCanRWHandler *fd_can_read, | 335 | IOCanRWHandler *fd_can_read, |
336 | + NetCleanup *cleanup, | ||
336 | void *opaque) | 337 | void *opaque) |
337 | { | 338 | { |
338 | VLANClientState *vc, **pvc; | 339 | VLANClientState *vc, **pvc; |
@@ -344,6 +345,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, | @@ -344,6 +345,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, | ||
344 | vc->name = assign_name(vc, model); | 345 | vc->name = assign_name(vc, model); |
345 | vc->fd_read = fd_read; | 346 | vc->fd_read = fd_read; |
346 | vc->fd_can_read = fd_can_read; | 347 | vc->fd_can_read = fd_can_read; |
348 | + vc->cleanup = cleanup; | ||
347 | vc->opaque = opaque; | 349 | vc->opaque = opaque; |
348 | vc->vlan = vlan; | 350 | vc->vlan = vlan; |
349 | 351 | ||
@@ -362,6 +364,9 @@ void qemu_del_vlan_client(VLANClientState *vc) | @@ -362,6 +364,9 @@ void qemu_del_vlan_client(VLANClientState *vc) | ||
362 | while (*pvc != NULL) | 364 | while (*pvc != NULL) |
363 | if (*pvc == vc) { | 365 | if (*pvc == vc) { |
364 | *pvc = vc->next; | 366 | *pvc = vc->next; |
367 | + if (vc->cleanup) { | ||
368 | + vc->cleanup(vc); | ||
369 | + } | ||
365 | free(vc->name); | 370 | free(vc->name); |
366 | free(vc->model); | 371 | free(vc->model); |
367 | free(vc); | 372 | free(vc); |
@@ -521,7 +526,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) | @@ -521,7 +526,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) | ||
521 | slirp_init(slirp_restrict, slirp_ip); | 526 | slirp_init(slirp_restrict, slirp_ip); |
522 | } | 527 | } |
523 | slirp_vc = qemu_new_vlan_client(vlan, model, name, | 528 | slirp_vc = qemu_new_vlan_client(vlan, model, name, |
524 | - slirp_receive, NULL, NULL); | 529 | + slirp_receive, NULL, NULL, NULL); |
525 | slirp_vc->info_str[0] = '\0'; | 530 | slirp_vc->info_str[0] = '\0'; |
526 | return 0; | 531 | return 0; |
527 | } | 532 | } |
@@ -702,6 +707,8 @@ typedef struct TAPState { | @@ -702,6 +707,8 @@ typedef struct TAPState { | ||
702 | char down_script_arg[128]; | 707 | char down_script_arg[128]; |
703 | } TAPState; | 708 | } TAPState; |
704 | 709 | ||
710 | +static int launch_script(const char *setup_script, const char *ifname, int fd); | ||
711 | + | ||
705 | static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, | 712 | static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, |
706 | int iovcnt) | 713 | int iovcnt) |
707 | { | 714 | { |
@@ -748,6 +755,18 @@ static void tap_send(void *opaque) | @@ -748,6 +755,18 @@ static void tap_send(void *opaque) | ||
748 | } | 755 | } |
749 | } | 756 | } |
750 | 757 | ||
758 | +static void tap_cleanup(VLANClientState *vc) | ||
759 | +{ | ||
760 | + TAPState *s = vc->opaque; | ||
761 | + | ||
762 | + if (s->down_script[0]) | ||
763 | + launch_script(s->down_script, s->down_script_arg, s->fd); | ||
764 | + | ||
765 | + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); | ||
766 | + close(s->fd); | ||
767 | + qemu_free(s); | ||
768 | +} | ||
769 | + | ||
751 | /* fd support */ | 770 | /* fd support */ |
752 | 771 | ||
753 | static TAPState *net_tap_fd_init(VLANState *vlan, | 772 | static TAPState *net_tap_fd_init(VLANState *vlan, |
@@ -759,7 +778,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan, | @@ -759,7 +778,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan, | ||
759 | 778 | ||
760 | s = qemu_mallocz(sizeof(TAPState)); | 779 | s = qemu_mallocz(sizeof(TAPState)); |
761 | s->fd = fd; | 780 | s->fd = fd; |
762 | - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); | 781 | + s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, |
782 | + NULL, tap_cleanup, s); | ||
763 | s->vc->fd_readv = tap_receive_iov; | 783 | s->vc->fd_readv = tap_receive_iov; |
764 | qemu_set_fd_handler(s->fd, tap_send, NULL, s); | 784 | qemu_set_fd_handler(s->fd, tap_send, NULL, s); |
765 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); | 785 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); |
@@ -1058,6 +1078,14 @@ static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) | @@ -1058,6 +1078,14 @@ static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) | ||
1058 | } | 1078 | } |
1059 | } | 1079 | } |
1060 | 1080 | ||
1081 | +static void vde_cleanup(VLANClientState *vc) | ||
1082 | +{ | ||
1083 | + VDEState *s = vc->opaque; | ||
1084 | + qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); | ||
1085 | + vde_close(s->vde); | ||
1086 | + qemu_free(s); | ||
1087 | +} | ||
1088 | + | ||
1061 | static int net_vde_init(VLANState *vlan, const char *model, | 1089 | static int net_vde_init(VLANState *vlan, const char *model, |
1062 | const char *name, const char *sock, | 1090 | const char *name, const char *sock, |
1063 | int port, const char *group, int mode) | 1091 | int port, const char *group, int mode) |
@@ -1078,7 +1106,8 @@ static int net_vde_init(VLANState *vlan, const char *model, | @@ -1078,7 +1106,8 @@ static int net_vde_init(VLANState *vlan, const char *model, | ||
1078 | free(s); | 1106 | free(s); |
1079 | return -1; | 1107 | return -1; |
1080 | } | 1108 | } |
1081 | - s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, NULL, s); | 1109 | + s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, |
1110 | + NULL, vde_cleanup, s); | ||
1082 | qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); | 1111 | qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); |
1083 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", | 1112 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", |
1084 | sock, vde_datafd(s->vde)); | 1113 | sock, vde_datafd(s->vde)); |
@@ -1263,6 +1292,14 @@ fail: | @@ -1263,6 +1292,14 @@ fail: | ||
1263 | return -1; | 1292 | return -1; |
1264 | } | 1293 | } |
1265 | 1294 | ||
1295 | +static void net_socket_cleanup(VLANClientState *vc) | ||
1296 | +{ | ||
1297 | + NetSocketState *s = vc->opaque; | ||
1298 | + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); | ||
1299 | + close(s->fd); | ||
1300 | + qemu_free(s); | ||
1301 | +} | ||
1302 | + | ||
1266 | static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, | 1303 | static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, |
1267 | const char *model, | 1304 | const char *model, |
1268 | const char *name, | 1305 | const char *name, |
@@ -1307,7 +1344,8 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, | @@ -1307,7 +1344,8 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, | ||
1307 | s = qemu_mallocz(sizeof(NetSocketState)); | 1344 | s = qemu_mallocz(sizeof(NetSocketState)); |
1308 | s->fd = fd; | 1345 | s->fd = fd; |
1309 | 1346 | ||
1310 | - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, NULL, s); | 1347 | + s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, |
1348 | + NULL, net_socket_cleanup, s); | ||
1311 | qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); | 1349 | qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); |
1312 | 1350 | ||
1313 | /* mcast: save bound address as dst */ | 1351 | /* mcast: save bound address as dst */ |
@@ -1334,8 +1372,8 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, | @@ -1334,8 +1372,8 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, | ||
1334 | NetSocketState *s; | 1372 | NetSocketState *s; |
1335 | s = qemu_mallocz(sizeof(NetSocketState)); | 1373 | s = qemu_mallocz(sizeof(NetSocketState)); |
1336 | s->fd = fd; | 1374 | s->fd = fd; |
1337 | - s->vc = qemu_new_vlan_client(vlan, model, name, | ||
1338 | - net_socket_receive, NULL, s); | 1375 | + s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive, |
1376 | + NULL, net_socket_cleanup, s); | ||
1339 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), | 1377 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
1340 | "socket: fd=%d", fd); | 1378 | "socket: fd=%d", fd); |
1341 | if (is_connected) { | 1379 | if (is_connected) { |
@@ -1895,29 +1933,20 @@ done: | @@ -1895,29 +1933,20 @@ done: | ||
1895 | 1933 | ||
1896 | void net_cleanup(void) | 1934 | void net_cleanup(void) |
1897 | { | 1935 | { |
1898 | -#if !defined(_WIN32) | ||
1899 | VLANState *vlan; | 1936 | VLANState *vlan; |
1900 | 1937 | ||
1901 | /* close network clients */ | 1938 | /* close network clients */ |
1902 | for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { | 1939 | for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { |
1903 | - VLANClientState *vc; | 1940 | + VLANClientState *vc = vlan->first_client; |
1904 | 1941 | ||
1905 | - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { | ||
1906 | - if (vc->fd_read == tap_receive) { | ||
1907 | - TAPState *s = vc->opaque; | 1942 | + while (vc) { |
1943 | + VLANClientState *next = vc->next; | ||
1908 | 1944 | ||
1909 | - if (s->down_script[0]) | ||
1910 | - launch_script(s->down_script, s->down_script_arg, s->fd); | ||
1911 | - } | ||
1912 | -#if defined(CONFIG_VDE) | ||
1913 | - if (vc->fd_read == vde_from_qemu) { | ||
1914 | - VDEState *s = vc->opaque; | ||
1915 | - vde_close(s->vde); | ||
1916 | - } | ||
1917 | -#endif | 1945 | + qemu_del_vlan_client(vc); |
1946 | + | ||
1947 | + vc = next; | ||
1918 | } | 1948 | } |
1919 | } | 1949 | } |
1920 | -#endif | ||
1921 | } | 1950 | } |
1922 | 1951 | ||
1923 | void net_client_check(void) | 1952 | void net_client_check(void) |
net.h
@@ -9,6 +9,7 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); | @@ -9,6 +9,7 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); | ||
9 | 9 | ||
10 | typedef struct VLANClientState VLANClientState; | 10 | typedef struct VLANClientState VLANClientState; |
11 | 11 | ||
12 | +typedef void (NetCleanup) (VLANClientState *); | ||
12 | typedef void (LinkStatusChanged)(VLANClientState *); | 13 | typedef void (LinkStatusChanged)(VLANClientState *); |
13 | 14 | ||
14 | struct VLANClientState { | 15 | struct VLANClientState { |
@@ -17,6 +18,7 @@ struct VLANClientState { | @@ -17,6 +18,7 @@ struct VLANClientState { | ||
17 | /* Packets may still be sent if this returns zero. It's used to | 18 | /* Packets may still be sent if this returns zero. It's used to |
18 | rate-limit the slirp code. */ | 19 | rate-limit the slirp code. */ |
19 | IOCanRWHandler *fd_can_read; | 20 | IOCanRWHandler *fd_can_read; |
21 | + NetCleanup *cleanup; | ||
20 | LinkStatusChanged *link_status_changed; | 22 | LinkStatusChanged *link_status_changed; |
21 | int link_down; | 23 | int link_down; |
22 | void *opaque; | 24 | void *opaque; |
@@ -40,6 +42,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, | @@ -40,6 +42,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, | ||
40 | const char *name, | 42 | const char *name, |
41 | IOReadHandler *fd_read, | 43 | IOReadHandler *fd_read, |
42 | IOCanRWHandler *fd_can_read, | 44 | IOCanRWHandler *fd_can_read, |
45 | + NetCleanup *cleanup, | ||
43 | void *opaque); | 46 | void *opaque); |
44 | void qemu_del_vlan_client(VLANClientState *vc); | 47 | void qemu_del_vlan_client(VLANClientState *vc); |
45 | VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); | 48 | VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); |
tap-win32.c
@@ -638,6 +638,18 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, | @@ -638,6 +638,18 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, | ||
638 | tap_win32_overlapped_t *handle; | 638 | tap_win32_overlapped_t *handle; |
639 | } TAPState; | 639 | } TAPState; |
640 | 640 | ||
641 | +static void tap_cleanup(VLANClientState *vc) | ||
642 | +{ | ||
643 | + TAPState *s = vc->opaque; | ||
644 | + | ||
645 | + qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); | ||
646 | + | ||
647 | + /* FIXME: need to kill thread and close file handle: | ||
648 | + tap_win32_close(s); | ||
649 | + */ | ||
650 | + qemu_free(s); | ||
651 | +} | ||
652 | + | ||
641 | static void tap_receive(void *opaque, const uint8_t *buf, int size) | 653 | static void tap_receive(void *opaque, const uint8_t *buf, int size) |
642 | { | 654 | { |
643 | TAPState *s = opaque; | 655 | TAPState *s = opaque; |
@@ -672,7 +684,8 @@ int tap_win32_init(VLANState *vlan, const char *model, | @@ -672,7 +684,8 @@ int tap_win32_init(VLANState *vlan, const char *model, | ||
672 | return -1; | 684 | return -1; |
673 | } | 685 | } |
674 | 686 | ||
675 | - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); | 687 | + s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, |
688 | + NULL, tap_cleanup, s); | ||
676 | 689 | ||
677 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), | 690 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
678 | "tap: ifname=%s", ifname); | 691 | "tap: ifname=%s", ifname); |