DF-4969 / run.log
== adw_pci.c: resource acquisition sites ==
-- [1] regs = bus_alloc_resource (adw_pci.c:211-225)
#ifdef ADW_ALLOW_MEMIO
if ((command & PCIM_CMD_MEMEN) != 0) {
regs_type = SYS_RES_MEMORY;
regs_id = ADW_PCI_MEMBASE;
regs = bus_alloc_resource(dev, regs_type,
®s_id, 0, ~0, 1, RF_ACTIVE);
}
#endif
if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) {
regs_type = SYS_RES_IOPORT;
regs_id = ADW_PCI_IOBASE;
regs = bus_alloc_resource(dev, regs_type,
®s_id, 0, ~0, 1, RF_ACTIVE);
}
if (regs == NULL) {
device_printf(dev, "can't allocate register resources\n");
return (ENOMEM);
}
-- [2] adw = adw_alloc(dev, regs, ...) keeps regs in the softc (adw_pci.c:227-229)
adw = adw_alloc(dev, regs, regs_type, regs_id);
if (adw == NULL)
return(ENOMEM);
-- [3] setup() failure: returns WITHOUT adw_free and WITHOUT releasing regs (adw_pci.c:242-245)
adw_reset_chip(adw);
error = entry->setup(dev, entry, adw);
if (error != 0)
return (error);
-- [4] irq = bus_alloc_resource (adw_pci.c:291-298)
zero = 0;
adw->irq_res_type = SYS_RES_IRQ;
adw->irq = bus_alloc_resource(dev, adw->irq_res_type, &zero,
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
if (adw->irq == NULL) {
adw_free(adw);
return (ENOMEM);
}
-- [5] every post-adw_alloc failure calls only adw_free() (adw_pci.c:235-238, 265-270, 274-278, 295-298, 300-303)
error = adw_attach(adw);
if (error != 0)
adw_free(adw);
return (error);
== adwcam.c: adw_free() NEVER releases regs/irq and never tears down the intr (adwcam.c:844-886) ==
adw_free(struct adw_softc *adw)
{
switch (adw->init_level) {
case 9:
{
struct sg_map_node *sg_map;
while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) {
SLIST_REMOVE_HEAD(&adw->sg_maps, links);
bus_dmamap_unload(adw->sg_dmat,
sg_map->sg_dmamap);
bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr,
sg_map->sg_dmamap);
kfree(sg_map, M_DEVBUF);
}
bus_dma_tag_destroy(adw->sg_dmat);
}
case 8:
bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
case 7:
bus_dmamem_free(adw->acb_dmat, adw->acbs,
adw->acb_dmamap);
bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
case 6:
bus_dma_tag_destroy(adw->acb_dmat);
case 5:
bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
case 4:
bus_dmamem_free(adw->carrier_dmat, adw->carriers,
adw->carrier_dmamap);
bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
case 3:
bus_dma_tag_destroy(adw->carrier_dmat);
case 2:
bus_dma_tag_destroy(adw->buffer_dmat);
case 1:
bus_dma_tag_destroy(adw->parent_dmat);
case 0:
break;
}
kfree(adw->name, M_DEVBUF);
kfree(adw, M_DEVBUF);
}
-- [6] adw_attach hooks the interrupt and starts the RISC before any later step (adwcam.c:1156-1161)
error = 0;
crit_enter();
/* Hook up our interrupt handler */
if ((error = bus_setup_intr(adw->device, adw->irq, 0,
adw_intr, adw, &adw->ih, NULL)) != 0) {
device_printf(adw->device, "bus_setup_intr() failed: %d\n",
error);
goto fail;
}
CONCLUSION: on every attach failure path the PCI register resource (and the IRQ
resource once allocated) stays allocated forever; on the setup() failure path the
kmalloc'd softc leaks too. No bus_teardown_intr exists anywhere in the driver.