aboutsummaryrefslogtreecommitdiff
path: root/hw/pcnet.c
diff options
context:
space:
mode:
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-04-17 17:11:08 +0000
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2009-04-17 17:11:08 +0000
commitb946a1533209f61a93e34898aebb5b43154b99c3 (patch)
tree36b0017910ca42cc5a41671b8edc7faa5da0a452 /hw/pcnet.c
parent32a8f6ae93f175518f86f99249177c35d1a85114 (diff)
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
Diffstat (limited to 'hw/pcnet.c')
-rw-r--r--hw/pcnet.c58
1 files changed, 49 insertions, 9 deletions
diff --git a/hw/pcnet.c b/hw/pcnet.c
index be68f284ed..acbaee6cdd 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -75,6 +75,7 @@ struct PCNetState_st {
uint8_t buffer[4096];
int tx_busy;
qemu_irq irq;
+ qemu_irq *reset_irq;
void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int do_bswap);
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)
return 0;
}
-static void pcnet_common_init(PCNetState *d, NICInfo *nd)
+static void pcnet_common_cleanup(PCNetState *d)
+{
+ unregister_savevm("pcnet", d);
+
+ qemu_del_timer(d->poll_timer);
+ qemu_free_timer(d->poll_timer);
+}
+
+static void pcnet_common_init(PCNetState *d, NICInfo *nd, NetCleanup *cleanup)
{
d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
@@ -1937,7 +1946,8 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd)
if (nd && nd->vlan) {
d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- pcnet_receive, pcnet_can_receive, d);
+ pcnet_receive, pcnet_can_receive,
+ cleanup, d);
qemu_format_nic_info_str(d->vc, d->nd->macaddr);
} else {
@@ -1985,6 +1995,22 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
cpu_physical_memory_read(addr, buf, len);
}
+static void pci_pcnet_cleanup(VLANClientState *vc)
+{
+ PCNetState *d = vc->opaque;
+
+ pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+ PCNetState *d = (PCNetState *)dev;
+
+ cpu_unregister_io_memory(d->mmio_index);
+
+ return 0;
+}
+
PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCNetState *d;
@@ -1997,7 +2023,7 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
devfn, NULL, NULL);
-
+ d->dev.unregister = pci_pcnet_uninit;
pci_conf = d->dev.config;
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)
d->phys_mem_write = pci_physical_memory_write;
d->pci_dev = &d->dev;
- pcnet_common_init(d, nd);
+ pcnet_common_init(d, nd, pci_pcnet_cleanup);
+
return (PCIDevice *)d;
}
@@ -2081,29 +2108,42 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
NULL,
};
+static void lance_cleanup(VLANClientState *vc)
+{
+ PCNetState *d = vc->opaque;
+
+ pcnet_common_cleanup(d);
+
+ qemu_free_irqs(d->reset_irq);
+
+ cpu_unregister_io_memory(d->mmio_index);
+
+ qemu_free(d);
+}
+
void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
qemu_irq irq, qemu_irq *reset)
{
PCNetState *d;
- int lance_io_memory;
qemu_check_nic_model(nd, "lance");
d = qemu_mallocz(sizeof(PCNetState));
- lance_io_memory =
+ d->mmio_index =
cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
d->dma_opaque = dma_opaque;
- *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1);
+ d->reset_irq = qemu_allocate_irqs(parent_lance_reset, d, 1);
+ *reset = *d->reset_irq;
- cpu_register_physical_memory(leaddr, 4, lance_io_memory);
+ cpu_register_physical_memory(leaddr, 4, d->mmio_index);
d->irq = irq;
d->phys_mem_read = ledma_memory_read;
d->phys_mem_write = ledma_memory_write;
- pcnet_common_init(d, nd);
+ pcnet_common_init(d, nd, lance_cleanup);
}
#endif /* TARGET_SPARC */