diff options
Diffstat (limited to 'sys/pci/if_sis.c')
-rw-r--r-- | sys/pci/if_sis.c | 192 |
1 files changed, 104 insertions, 88 deletions
diff --git a/sys/pci/if_sis.c b/sys/pci/if_sis.c index fa4006e..7c7b3cc 100644 --- a/sys/pci/if_sis.c +++ b/sys/pci/if_sis.c @@ -1054,7 +1054,6 @@ sis_attach(dev) waittime = 0; sc = device_get_softc(dev); unit = device_get_unit(dev); - bzero(sc, sizeof(struct sis_softc)); mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); @@ -1102,13 +1101,13 @@ sis_attach(dev) #ifdef SIS_USEIOSPACE if (!(command & PCIM_CMD_PORTEN)) { printf("sis%d: failed to enable I/O ports!\n", unit); - error = ENXIO;; + error = ENXIO; goto fail; } #else if (!(command & PCIM_CMD_MEMEN)) { printf("sis%d: failed to enable memory mapping!\n", unit); - error = ENXIO;; + error = ENXIO; goto fail; } #endif @@ -1133,21 +1132,10 @@ sis_attach(dev) if (sc->sis_irq == NULL) { printf("sis%d: couldn't map interrupt\n", unit); - bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); error = ENXIO; goto fail; } - error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET, - sis_intr, sc, &sc->sis_intrhand); - - if (error) { - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); - bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); - printf("sis%d: couldn't set up irq\n", unit); - goto fail; - } - /* Reset the adapter. */ sis_reset(sc); @@ -1276,9 +1264,13 @@ sis_attach(dev) BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ BUS_DMA_ALLOCNOW, /* flags */ &sc->sis_parent_tag); + if (error) + goto fail; /* - * Now allocate a tag for the DMA descriptor lists. + * Now allocate a tag for the DMA descriptor lists and a chunk + * of DMA-able memory based on the tag. Also obtain the physical + * addresses of the RX and TX ring, which we'll need later. * All of our lists are allocated as a contiguous block * of memory. */ @@ -1291,6 +1283,33 @@ sis_attach(dev) BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 0, /* flags */ &sc->sis_ldata.sis_rx_tag); + if (error) + goto fail; + + error = bus_dmamem_alloc(sc->sis_ldata.sis_rx_tag, + (void **)&sc->sis_ldata.sis_rx_list, BUS_DMA_NOWAIT, + &sc->sis_ldata.sis_rx_dmamap); + + if (error) { + printf("sis%d: no memory for rx list buffers!\n", unit); + bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); + sc->sis_ldata.sis_rx_tag = NULL; + goto fail; + } + + error = bus_dmamap_load(sc->sis_ldata.sis_rx_tag, + sc->sis_ldata.sis_rx_dmamap, &(sc->sis_ldata.sis_rx_list[0]), + sizeof(struct sis_desc), sis_dma_map_ring, + &sc->sis_cdata.sis_rx_paddr, 0); + + if (error) { + printf("sis%d: cannot get address of the rx ring!\n", unit); + bus_dmamem_free(sc->sis_ldata.sis_rx_tag, + sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); + bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); + sc->sis_ldata.sis_rx_tag = NULL; + goto fail; + } error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 1, 0, /* alignment, boundary */ @@ -1301,53 +1320,45 @@ sis_attach(dev) BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 0, /* flags */ &sc->sis_ldata.sis_tx_tag); + if (error) + goto fail; - error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES, 1, /* maxsize,nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - 0, /* flags */ - &sc->sis_tag); - - /* - * Now allocate a chunk of DMA-able memory based on the - * tag we just created. - */ error = bus_dmamem_alloc(sc->sis_ldata.sis_tx_tag, (void **)&sc->sis_ldata.sis_tx_list, BUS_DMA_NOWAIT, &sc->sis_ldata.sis_tx_dmamap); if (error) { - printf("sis%d: no memory for list buffers!\n", unit); - bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); - bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); - bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); + printf("sis%d: no memory for tx list buffers!\n", unit); bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); - error = ENXIO; + sc->sis_ldata.sis_tx_tag = NULL; goto fail; } - error = bus_dmamem_alloc(sc->sis_ldata.sis_rx_tag, - (void **)&sc->sis_ldata.sis_rx_list, BUS_DMA_NOWAIT, - &sc->sis_ldata.sis_rx_dmamap); + error = bus_dmamap_load(sc->sis_ldata.sis_tx_tag, + sc->sis_ldata.sis_tx_dmamap, &(sc->sis_ldata.sis_tx_list[0]), + sizeof(struct sis_desc), sis_dma_map_ring, + &sc->sis_cdata.sis_tx_paddr, 0); if (error) { - printf("sis%d: no memory for list buffers!\n", unit); - bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); - bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); - bus_dmamem_free(sc->sis_ldata.sis_rx_tag, + printf("sis%d: cannot get address of the tx ring!\n", unit); + bus_dmamem_free(sc->sis_ldata.sis_tx_tag, sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); - bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); - error = ENXIO; + sc->sis_ldata.sis_tx_tag = NULL; goto fail; } + error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES, 1, /* maxsize,nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + 0, /* flags */ + &sc->sis_tag); + if (error) + goto fail; bzero(sc->sis_ldata.sis_tx_list, SIS_TX_LIST_SZ); bzero(sc->sis_ldata.sis_rx_list, SIS_RX_LIST_SZ); @@ -1356,14 +1367,6 @@ sis_attach(dev) * Obtain the physical addresses of the RX and TX * rings which we'll need later in the init routine. */ - bus_dmamap_load(sc->sis_ldata.sis_tx_tag, - sc->sis_ldata.sis_tx_dmamap, &(sc->sis_ldata.sis_tx_list[0]), - sizeof(struct sis_desc), sis_dma_map_ring, - &sc->sis_cdata.sis_tx_paddr, 0); - bus_dmamap_load(sc->sis_ldata.sis_rx_tag, - sc->sis_ldata.sis_rx_dmamap, &(sc->sis_ldata.sis_rx_list[0]), - sizeof(struct sis_desc), sis_dma_map_ring, - &sc->sis_cdata.sis_rx_paddr, 0); ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; @@ -1385,19 +1388,12 @@ sis_attach(dev) if (mii_phy_probe(dev, &sc->sis_miibus, sis_ifmedia_upd, sis_ifmedia_sts)) { printf("sis%d: MII without any PHY!\n", sc->sis_unit); - bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); - bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); - bus_dmamem_free(sc->sis_ldata.sis_rx_tag, - sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); - bus_dmamem_free(sc->sis_ldata.sis_rx_tag, - sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); - bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); - bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); error = ENXIO; goto fail; } + callout_handle_init(&sc->sis_stat_ch); + /* * Call MI attach routine. */ @@ -1409,11 +1405,18 @@ sis_attach(dev) ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; - callout_handle_init(&sc->sis_stat_ch); - return(0); + error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET, + sis_intr, sc, &sc->sis_intrhand); + + if (error) { + printf("sis%d: couldn't set up irq\n", unit); + goto fail; + } fail: - mtx_destroy(&sc->sis_mtx); + if (error) + sis_detach(dev); + return(error); } @@ -1424,33 +1427,46 @@ sis_detach(dev) struct sis_softc *sc; struct ifnet *ifp; - sc = device_get_softc(dev); + KASSERT(mtx_initialized(&sc->sis_mtx), "sis mutex not initialized"); SIS_LOCK(sc); ifp = &sc->arpcom.ac_if; - sis_reset(sc); - sis_stop(sc); - ether_ifdetach(ifp); - - bus_generic_detach(dev); - device_delete_child(dev, sc->sis_miibus); - - bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); - bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); - - bus_dmamap_unload(sc->sis_ldata.sis_rx_tag, - sc->sis_ldata.sis_rx_dmamap); - bus_dmamap_unload(sc->sis_ldata.sis_tx_tag, - sc->sis_ldata.sis_tx_dmamap); - bus_dmamem_free(sc->sis_ldata.sis_rx_tag, - sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); - bus_dmamem_free(sc->sis_ldata.sis_rx_tag, - sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); - bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); - bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); - bus_dma_tag_destroy(sc->sis_parent_tag); + if (device_is_alive(dev)) { + if (bus_child_present(dev)) { + sis_reset(sc); + sis_stop(sc); + } + ether_ifdetach(ifp); + device_delete_child(dev, sc->sis_miibus); + bus_generic_detach(dev); + } + + if (sc->sis_intrhand) + bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); + if (sc->sis_irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); + if (sc->sis_res) + bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); + + if (sc->sis_ldata.sis_rx_tag) { + bus_dmamap_unload(sc->sis_ldata.sis_rx_tag, + sc->sis_ldata.sis_rx_dmamap); + bus_dmamem_free(sc->sis_ldata.sis_rx_tag, + sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); + bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); + } + if (sc->sis_ldata.sis_tx_tag) { + bus_dmamap_unload(sc->sis_ldata.sis_tx_tag, + sc->sis_ldata.sis_tx_dmamap); + bus_dmamem_free(sc->sis_ldata.sis_tx_tag, + sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); + bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); + } + if (sc->sis_parent_tag) + bus_dma_tag_destroy(sc->sis_parent_tag); + if (sc->sis_tag) + bus_dma_tag_destroy(sc->sis_tag); SIS_UNLOCK(sc); mtx_destroy(&sc->sis_mtx); |