svn commit: r192018 - head/sys/arm/at91
Stanislav Sedov
stas at FreeBSD.org
Tue May 12 16:07:08 UTC 2009
Author: stas
Date: Tue May 12 16:07:08 2009
New Revision: 192018
URL: http://svn.freebsd.org/changeset/base/192018
Log:
- Implement detach path.
- Release memory and DMA resources on stop.
- Unload the associated DMA maps after transmit is complete.
Modified:
head/sys/arm/at91/if_ate.c
Modified: head/sys/arm/at91/if_ate.c
==============================================================================
--- head/sys/arm/at91/if_ate.c Tue May 12 16:04:51 2009 (r192017)
+++ head/sys/arm/at91/if_ate.c Tue May 12 16:07:08 2009 (r192018)
@@ -23,14 +23,10 @@
* SUCH DAMAGE.
*/
-/* TODO: (in no order)
+/* TODO
*
- * 8) Need to sync busdma goo in atestop
- * 9) atestop should maybe free the mbufs?
- *
- * 1) detach
- * 2) Free dma setup
- * 3) Turn on the clock in pmc? Turn off?
+ * 1) Turn on the clock in pmc? Turn off?
+ * 2) GPIO initializtion in board setup code.
*/
#include <sys/cdefs.h>
@@ -152,7 +148,7 @@ static void ate_intr(void *);
/* helper routines */
static int ate_activate(device_t dev);
-static void ate_deactivate(device_t dev);
+static void ate_deactivate(struct ate_softc *sc);
static int ate_ifmedia_upd(struct ifnet *ifp);
static void ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
static int ate_get_mac(struct ate_softc *sc, u_char *eaddr);
@@ -179,11 +175,33 @@ ate_attach(device_t dev)
struct ifnet *ifp = NULL;
struct sysctl_ctx_list *sctx;
struct sysctl_oid *soid;
- int err;
u_char eaddr[ETHER_ADDR_LEN];
uint32_t rnd;
+ int rid, err;
sc->dev = dev;
+ ATE_LOCK_INIT(sc);
+
+ /*
+ * Allocate resources.
+ */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "could not allocate memory resources.\n");
+ err = ENOMEM;
+ goto out;
+ }
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "could not allocate interrupt resources.\n");
+ err = ENOMEM;
+ goto out;
+ }
+
err = ate_activate(dev);
if (err)
goto out;
@@ -197,8 +215,9 @@ ate_attach(device_t dev)
CTLFLAG_RD, &sc->use_rmii, 0, "rmii in use");
/* calling atestop before ifp is set is OK */
+ ATE_LOCK(sc);
atestop(sc);
- ATE_LOCK_INIT(sc);
+ ATE_UNLOCK(sc);
callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0);
if ((err = ate_get_mac(sc, eaddr)) != 0) {
@@ -252,26 +271,65 @@ ate_attach(device_t dev)
ether_ifattach(ifp, eaddr);
/*
- * Activate the interrupt
+ * Activate the interrupt.
*/
err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
NULL, ate_intr, sc, &sc->intrhand);
if (err) {
+ device_printf(dev, "could not establish interrupt handler.\n");
ether_ifdetach(ifp);
- ATE_LOCK_DESTROY(sc);
+ goto out;
}
-out:;
+
+out:
if (err)
- ate_deactivate(dev);
- if (err && ifp)
- if_free(ifp);
+ ate_detach(dev);
return (err);
}
static int
ate_detach(device_t dev)
{
- return EBUSY; /* XXX TODO(1) */
+ struct ate_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ KASSERT(sc != NULL, ("[ate: %d]: sc is NULL", __LINE__));
+ ifp = sc->ifp;
+ if (device_is_attached(dev)) {
+ ATE_LOCK(sc);
+ sc->flags |= ATE_FLAG_DETACHING;
+ atestop(sc);
+ ATE_UNLOCK(sc);
+ callout_drain(&sc->tick_ch);
+ ether_ifdetach(ifp);
+ }
+ if (sc->miibus != NULL) {
+ device_delete_child(dev, sc->miibus);
+ sc->miibus = NULL;
+ }
+ bus_generic_detach(sc->dev);
+ ate_deactivate(sc);
+ if (sc->intrhand != NULL) {
+ bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
+ sc->intrhand = NULL;
+ }
+ if (ifp != NULL) {
+ if_free(ifp);
+ sc->ifp = NULL;
+ }
+ if (sc->mem_res != NULL) {
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ sc->mem_res = NULL;
+ }
+ if (sc->irq_res != NULL) {
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->irq_res), sc->irq_res);
+ sc->irq_res = NULL;
+ }
+ ATE_LOCK_DESTROY(sc);
+ return (0);
}
static void
@@ -367,20 +425,9 @@ static int
ate_activate(device_t dev)
{
struct ate_softc *sc;
- int rid, err, i;
+ int err, i;
sc = device_get_softc(dev);
- rid = 0;
- sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
- RF_ACTIVE);
- if (sc->mem_res == NULL)
- goto errout;
- rid = 0;
- sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
- RF_ACTIVE);
- if (sc->irq_res == NULL)
- goto errout;
-
/*
* Allocate DMA tags and maps
*/
@@ -423,7 +470,6 @@ ate_activate(device_t dev)
sc->rx_descs, ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t),
ate_getaddr, sc, 0) != 0)
goto errout;
- /* XXX TODO(5) Put this in ateinit_locked? */
for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
sc->rx_buf_ptr = i;
if (bus_dmamem_alloc(sc->rxtag, (void **)&sc->rx_buf[i],
@@ -439,65 +485,69 @@ ate_activate(device_t dev)
/* Write the descriptor queue address. */
WR4(sc, ETH_RBQP, sc->rx_desc_phys);
return (0);
+
errout:
- ate_deactivate(dev);
return (ENOMEM);
}
static void
-ate_deactivate(device_t dev)
+ate_deactivate(struct ate_softc *sc)
{
- struct ate_softc *sc;
+ int i;
- sc = device_get_softc(dev);
- /* XXX TODO(2) teardown busdma junk, below from fxp -- customize */
-#if 0
- if (sc->fxp_mtag) {
- for (i = 0; i < FXP_NRFABUFS; i++) {
- rxp = &sc->fxp_desc.rx_list[i];
- if (rxp->rx_mbuf != NULL) {
- bus_dmamap_sync(sc->fxp_mtag, rxp->rx_map,
- BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->fxp_mtag, rxp->rx_map);
- m_freem(rxp->rx_mbuf);
+ KASSERT(sc != NULL, ("[ate, %d]: sc is NULL!", __LINE__));
+ if (sc->mtag != NULL) {
+ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) {
+ if (sc->sent_mbuf[i] != NULL) {
+ bus_dmamap_sync(sc->mtag, sc->tx_map[i],
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mtag, sc->tx_map[i]);
+ m_freem(sc->sent_mbuf[i]);
}
- bus_dmamap_destroy(sc->fxp_mtag, rxp->rx_map);
+ bus_dmamap_destroy(sc->mtag, sc->tx_map[i]);
+ sc->sent_mbuf[i] = NULL;
+ sc->tx_map[i] = NULL;
}
- bus_dmamap_destroy(sc->fxp_mtag, sc->spare_map);
- for (i = 0; i < FXP_NTXCB; i++) {
- txp = &sc->fxp_desc.tx_list[i];
- if (txp->tx_mbuf != NULL) {
- bus_dmamap_sync(sc->fxp_mtag, txp->tx_map,
- BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->fxp_mtag, txp->tx_map);
- m_freem(txp->tx_mbuf);
+ bus_dma_tag_destroy(sc->mtag);
+ }
+ if (sc->rx_desc_tag != NULL) {
+ if (sc->rx_descs != NULL) {
+ if (sc->rx_desc_phys != 0) {
+ bus_dmamap_sync(sc->rx_desc_tag,
+ sc->rx_desc_map, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->rx_desc_tag,
+ sc->rx_desc_map);
+ sc->rx_desc_phys = 0;
}
- bus_dmamap_destroy(sc->fxp_mtag, txp->tx_map);
}
- bus_dma_tag_destroy(sc->fxp_mtag);
}
- if (sc->fxp_stag)
- bus_dma_tag_destroy(sc->fxp_stag);
- if (sc->cbl_tag)
- bus_dma_tag_destroy(sc->cbl_tag);
- if (sc->mcs_tag)
- bus_dma_tag_destroy(sc->mcs_tag);
-#endif
- if (sc->intrhand)
- bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
- sc->intrhand = 0;
- bus_generic_detach(sc->dev);
- if (sc->miibus)
- device_delete_child(sc->dev, sc->miibus);
- if (sc->mem_res)
- bus_release_resource(dev, SYS_RES_IOPORT,
- rman_get_rid(sc->mem_res), sc->mem_res);
- sc->mem_res = 0;
- if (sc->irq_res)
- bus_release_resource(dev, SYS_RES_IRQ,
- rman_get_rid(sc->irq_res), sc->irq_res);
- sc->irq_res = 0;
- return;
+ if (sc->rxtag != NULL) {
+ for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) {
+ if (sc->rx_buf[i] != NULL) {
+ if (sc->rx_descs[i].addr != 0) {
+ bus_dmamap_sync(sc->rxtag,
+ sc->rx_map[i],
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->rxtag,
+ sc->rx_map[i]);
+ sc->rx_descs[i].addr = 0;
+ }
+ bus_dmamem_free(sc->rxtag, sc->rx_buf[i],
+ sc->rx_map[i]);
+ sc->rx_buf[i] = NULL;
+ sc->rx_map[i] = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->rxtag);
+ }
+ if (sc->rx_desc_tag != NULL) {
+ if (sc->rx_descs != NULL)
+ bus_dmamem_free(sc->rx_desc_tag, sc->rx_descs,
+ sc->rx_desc_map);
+ bus_dma_tag_destroy(sc->rx_desc_tag);
+ sc->rx_descs = NULL;
+ sc->rx_desc_tag = NULL;
+ }
}
/*
@@ -718,6 +768,7 @@ ate_intr(void *xsc)
if (sc->sent_mbuf[0]) {
bus_dmamap_sync(sc->mtag, sc->tx_map[0],
BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mtag, sc->tx_map[0]);
m_freem(sc->sent_mbuf[0]);
ifp->if_opackets++;
sc->sent_mbuf[0] = NULL;
@@ -726,6 +777,7 @@ ate_intr(void *xsc)
if (RD4(sc, ETH_TSR) & ETH_TSR_IDLE) {
bus_dmamap_sync(sc->mtag, sc->tx_map[1],
BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mtag, sc->tx_map[1]);
m_freem(sc->sent_mbuf[1]);
ifp->if_opackets++;
sc->txcur = 0;
@@ -911,8 +963,11 @@ atestart(struct ifnet *ifp)
static void
atestop(struct ate_softc *sc)
{
- struct ifnet *ifp = sc->ifp;
+ struct ifnet *ifp;
+ int i;
+ ATE_ASSERT_LOCKED(sc);
+ ifp = sc->ifp;
if (ifp) {
ifp->if_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
@@ -948,11 +1003,17 @@ atestop(struct ate_softc *sc)
WR4(sc, ETH_RSR, 0xffffffff);
/*
- * XXX TODO(8)
- * need to worry about the busdma resources? Yes, I think we need
- * to sync and unload them. We may also need to release the mbufs
- * that are assocaited with RX and TX operations.
+ * Release TX resources.
*/
+ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) {
+ if (sc->sent_mbuf[i] != NULL) {
+ bus_dmamap_sync(sc->mtag, sc->tx_map[i],
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mtag, sc->tx_map[i]);
+ m_freem(sc->sent_mbuf[i]);
+ sc->sent_mbuf[i] = NULL;
+ }
+ }
/*
* XXX we should power down the EMAC if it isn't in use, after
More information about the svn-src-head
mailing list