PERFORCE change 194491 for review
Jakub Wojciech Klama
jceel at FreeBSD.org
Thu Jun 9 08:54:38 UTC 2011
http://p4web.freebsd.org/@@194491?ac=10
Change 194491 by jceel at jceel_cyclone on 2011/06/09 08:54:06
Ethernet driver update: working correctly in trivial scenarios.
Affected files ...
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#2 edit
.. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#2 edit
Differences ...
==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#2 (text+ko) ====
@@ -94,6 +94,7 @@
struct lpe_txdesc lpe_tx_desc[LPE_TXDESC_NUM];
int lpe_tx_prod;
int lpe_tx_cons;
+ int lpe_tx_used;
int lpe_rx_cons;
};
@@ -120,8 +121,8 @@
bus_space_tag_t lpe_bst;
bus_space_handle_t lpe_bsh;
uint32_t lpe_flags;
+ struct callout lpe_tick;
-
struct lpe_chain_data lpe_cdata;
struct lpe_ring_data lpe_rdata;
};
@@ -144,11 +145,13 @@
static void lpe_intr(void *);
static void lpe_rxintr(struct lpe_softc *);
static void lpe_txintr(struct lpe_softc *);
-//static void lpe_tick(void *);
+static void lpe_tick(void *);
static int lpe_encap(struct lpe_softc *, struct mbuf **);
static int lpe_dma_alloc(struct lpe_softc *);
static int lpe_dma_alloc_rx(struct lpe_softc *);
static int lpe_dma_alloc_tx(struct lpe_softc *);
+static int lpe_init_rx(struct lpe_softc *);
+static int lpe_init_rxbuf(struct lpe_softc *, int);
static void lpe_dmamap_cb(void *, bus_dma_segment_t *, int, int);
static int lpe_ifmedia_upd(struct ifnet *);
static void lpe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -194,6 +197,8 @@
mtx_init(&sc->lpe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF);
+ callout_init_mtx(&sc->lpe_tick, &sc->lpe_mtx, 0);
+
rid = 0;
sc->lpe_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
@@ -287,8 +292,6 @@
struct lpe_softc *sc = device_get_softc(dev);
uint32_t val;
- device_printf(dev, "mii read: phy=%d reg=%d\n", phy, reg);
-
lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ);
lpe_write_4(sc, LPE_MADR,
(reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT |
@@ -305,7 +308,11 @@
if (val & LPE_MIND_INVALID)
return (0);
- return (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK);
+ lpe_write_4(sc, LPE_MCMD, 0);
+
+ int x = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK);
+// printf("mii read: phy=%d reg=%d result=0x%04x\n", phy, reg, x);
+ return (x);
}
static int
@@ -314,6 +321,8 @@
struct lpe_softc *sc = device_get_softc(dev);
uint32_t val;
+// printf("mii write: phy=%d reg=%d data=0x%04x\n", phy, reg, data);
+
lpe_write_4(sc, LPE_MCMD, LPE_MCMD_WRITE);
lpe_write_4(sc, LPE_MADR,
(reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT |
@@ -393,11 +402,20 @@
/* Enable Tx and Rx */
cmd = lpe_read_4(sc, LPE_COMMAND);
- lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE | LPE_COMMAND_TXENABLE);
+ lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE |
+ LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME |
+ LPE_COMMAND_PASSRXFILTER);
/* Enable receive */
mac1 = lpe_read_4(sc, LPE_MAC1);
- lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_RXENABLE);
+ lpe_write_4(sc, LPE_MAC1, /*mac1 |*/ LPE_MAC1_RXENABLE | LPE_MAC1_PASSALL);
+
+ /* XXX */
+ lpe_write_4(sc, LPE_MAC2, LPE_MAC2_CRCENABLE | LPE_MAC2_PADCRCENABLE |
+ LPE_MAC2_FULLDUPLEX);
+
+ /* XXX */
+ lpe_write_4(sc, LPE_MCFG, (((7) & 0x7) << 2));
/* Set up Rx filter */
lpe_write_4(sc, LPE_RXFILTER_CTRL, 0xffffffff);
@@ -407,20 +425,36 @@
LPE_INT_RXFINISH | LPE_INT_RXDONE | LPE_INT_TXUNDERRUN |
LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE);
+ sc->lpe_cdata.lpe_tx_prod = 0;
+ sc->lpe_cdata.lpe_tx_cons = 0;
+ sc->lpe_cdata.lpe_tx_used = 0;
+ sc->lpe_cdata.lpe_rx_cons = 0;
+
+ lpe_init_rx(sc);
+
/* Initialize Rx packet and status descriptor heads */
lpe_write_4(sc, LPE_RXDESC, sc->lpe_rdata.lpe_rx_ring_phys);
lpe_write_4(sc, LPE_RXSTATUS, sc->lpe_rdata.lpe_rx_status_phys);
- lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM);
+ lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM - 1);
lpe_write_4(sc, LPE_RXDESC_CONS, 0);
+
+ device_printf(sc->lpe_dev, "rx ring: %p, rx status: %p\n",
+ sc->lpe_rdata.lpe_rx_ring, sc->lpe_rdata.lpe_rx_status);
+
/* Initialize Tx packet and status descriptor heads */
lpe_write_4(sc, LPE_TXDESC, sc->lpe_rdata.lpe_tx_ring_phys);
lpe_write_4(sc, LPE_TXSTATUS, sc->lpe_rdata.lpe_tx_status_phys);
- lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM);
+ lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM - 1);
lpe_write_4(sc, LPE_TXDESC_PROD, 0);
-
+
+ device_printf(sc->lpe_dev, "tx ring: %p, tx status: %p\n",
+ sc->lpe_rdata.lpe_tx_ring, sc->lpe_rdata.lpe_tx_status);
+
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->lpe_tick, hz, lpe_tick, sc);
}
static void
@@ -442,7 +476,7 @@
lpe_lock_assert(sc);
- device_printf(sc->lpe_dev, "lpe_start_locked()\n");
+// device_printf(sc->lpe_dev, "lpe_start_locked()\n");
while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
/* Dequeue first packet */
@@ -451,11 +485,13 @@
break;
lpe_encap(sc, &m_head);
+
+ encap++;
}
/* Submit new descriptor list */
if (encap) {
-
+ lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod);
}
}
@@ -465,13 +501,21 @@
{
struct lpe_txdesc *txd;
struct lpe_hwdesc *hwd;
- struct lpe_hwstatus *hws;
+ //struct lpe_hwstatus *hws;
bus_dma_segment_t segs[LPE_MAXFRAGS];
- int i, err, nsegs;
+ int i, err, nsegs, prod;
lpe_lock_assert(sc);
M_ASSERTPKTHDR((*m_head));
+ prod = sc->lpe_cdata.lpe_tx_prod;
+ txd = &sc->lpe_cdata.lpe_tx_desc[prod];
+
+// device_printf(sc->lpe_dev, "lpe_encap: starting with prod=%d\n", prod);
+
+// device_printf(sc->lpe_dev, "lpe_encap: packet data: %16D\n",
+// mtod(*m_head, const char *), " ");
+
err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag,
txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
@@ -484,12 +528,34 @@
return (EIO);
}
+ bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap,
+ BUS_DMASYNC_PREREAD);
+ bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
for (i = 0; i < nsegs; i++) {
- hwd = &sc->lpe_rdata.lpe_tx_desc[prod];
-
+ hwd = &sc->lpe_rdata.lpe_tx_ring[prod];
+ hwd->lhr_data = segs[i].ds_addr;
+ hwd->lhr_control = segs[i].ds_len - 1;// & LPE_HWDESC_SIZE_MASK;
+
+ if (i == nsegs - 1) {
+ hwd->lhr_control |= LPE_HWDESC_LASTFLAG;
+ hwd->lhr_control |= LPE_HWDESC_INTERRUPT;
+ hwd->lhr_control |= (1 << 28) | (1 << 29);
+ }
+
LPE_INC(prod, LPE_TXDESC_NUM);
+
+// device_printf(sc->lpe_dev, "lpe_encap: 1 segment done @ %p, size: %ld\n",
+// hwd, segs[i].ds_len);
}
+ bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ sc->lpe_cdata.lpe_tx_used += nsegs;
+ sc->lpe_cdata.lpe_tx_prod = prod;
+
return (0);
}
@@ -510,9 +576,16 @@
static int
lpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
+ struct lpe_softc *sc = ifp->if_softc;
+ struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+ struct ifreq *ifr = (struct ifreq *)data;
int err;
switch (cmd) {
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+ break;
default:
err = ether_ioctl(ifp, cmd, data);
break;
@@ -527,14 +600,16 @@
struct lpe_softc *sc = (struct lpe_softc *)arg;
uint32_t intstatus;
- device_printf(sc->lpe_dev, "intr(): 0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS));
+// device_printf(sc->lpe_dev, "intr(): 0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS));
while ((intstatus = lpe_read_4(sc, LPE_INTSTATUS))) {
- if (intstatus & LPE_INT_RXFINISH)
+ if (intstatus & LPE_INT_RXDONE)
lpe_rxintr(sc);
- if (intstatus & LPE_INT_TXFINISH)
+ if (intstatus & LPE_INT_TXDONE)
lpe_txintr(sc);
+
+ lpe_write_4(sc, LPE_INTCLEAR, 0xffff);
}
@@ -543,22 +618,62 @@
static void
lpe_rxintr(struct lpe_softc *sc)
{
+ struct ifnet *ifp = sc->lpe_ifp;
+ struct lpe_hwdesc *hwd;
+ struct lpe_hwstatus *hws;
+ struct lpe_rxdesc *rxd;
+ struct mbuf *m;
+ int prod, cons;
+// device_printf(sc->lpe_dev, "receive interrupt\n");
+
+ for (;;) {
+ prod = lpe_read_4(sc, LPE_RXDESC_PROD);
+ cons = lpe_read_4(sc, LPE_RXDESC_CONS);
+ if (prod == cons)
+ break;
+
+ rxd = &sc->lpe_cdata.lpe_rx_desc[cons];
+ hwd = &sc->lpe_rdata.lpe_rx_ring[cons];
+ hws = &sc->lpe_rdata.lpe_rx_status[cons];
+
+// device_printf(sc->lpe_dev, "incoming packet: idx=%d len=%d data=%16D\n",
+// cons, hws->lhs_info & 0x7ff,
+// mtod(rxd->lpe_rxdesc_mbuf, const char *), " ");
+
+
+ m = rxd->lpe_rxdesc_mbuf;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_data += 2;
+
+ (*ifp->if_input)(ifp, m);
+
+ lpe_init_rxbuf(sc, cons);
+
+ LPE_INC(cons, LPE_RXDESC_NUM);
+ lpe_write_4(sc, LPE_RXDESC_CONS, cons);
+ }
+
+// device_printf(sc->lpe_dev, "rx: prod=%d cons=%d\n", prod, cons);
}
static void
lpe_txintr(struct lpe_softc *sc)
{
-
+/// device_printf(sc->lpe_dev, "transmit interrupt\n");
}
-#if 0
static void
lpe_tick(void *arg)
{
+ struct lpe_softc *sc = (struct lpe_softc *)arg;
+ //struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+
+ lpe_lock_assert(sc);
+ //mii_tick(mii);
+ callout_reset(&sc->lpe_tick, hz, lpe_tick, sc);
}
-#endif
static int
lpe_dma_alloc(struct lpe_softc *sc)
@@ -797,6 +912,84 @@
return (err);
}
+static int
+lpe_init_rx(struct lpe_softc *sc)
+{
+ int i, err;
+
+ for (i = 0; i < LPE_RXDESC_NUM; i++) {
+ err = lpe_init_rxbuf(sc, i);
+ if (err)
+ return (err);
+ }
+
+ return (0);
+}
+
+static int
+lpe_init_rxbuf(struct lpe_softc *sc, int n)
+{
+ struct lpe_rxdesc *rxd;
+ struct lpe_hwdesc *hwd;
+ struct lpe_hwstatus *hws;
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ int nsegs;
+
+ rxd = &sc->lpe_cdata.lpe_rx_desc[n];
+ hwd = &sc->lpe_rdata.lpe_rx_ring[n];
+ hws = &sc->lpe_rdata.lpe_rx_status[n];
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+
+ if (!m) {
+ device_printf(sc->lpe_dev, "WARNING: mbufs exhausted!\n");
+ return (ENOBUFS);
+ }
+
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+ bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap);
+
+// printf("i=%d sc=%p lpe_rx_buf_tag=%p lpe_rxdesc_dmamap=%p m=%p\n",
+// n, sc, sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, m);
+
+ if (bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_rx_buf_tag,
+ rxd->lpe_rxdesc_dmamap, m, segs, &nsegs, 0)) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap,
+ BUS_DMASYNC_PREREAD);
+
+ rxd->lpe_rxdesc_mbuf = m;
+ hwd->lhr_data = segs[0].ds_addr + 2;
+ hwd->lhr_control = (segs[0].ds_len - 1) | LPE_HWDESC_INTERRUPT;
+
+ return (0);
+}
+
+#if 0
+static void
+lpe_discard_rxbuf(struct lpe_softc *sc, int n)
+{
+ struct lpe_rxdesc *rxd;
+ struct lpe_hwdesc *hwd;
+
+ rxd = &sc->lpe_cdata.lpe_rx_desc[n];
+ hwd = &sc->lpe_rdata.lpe_rx_ring[n];
+
+ bus_dmamap_unload(rxch->dve_rx_buf_tag, rxd->dve_rxdesc_dmamap);
+
+ hwd->hw_flagslen = 0;
+
+ if (rxd->dve_rxdesc_mbuf) {
+ m_freem(rxd->dve_rxdesc_mbuf);
+ rxd->dve_rxdesc_mbuf = NULL;
+ }
+}
+#endif
+
static void
lpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
@@ -854,6 +1047,6 @@
DRIVER_MODULE(lpe, simplebus, lpe_driver, lpe_devclass, 0, 0);
DRIVER_MODULE(miibus, lpe, miibus_driver, miibus_devclass, 0, 0);
-MODULE_DEPEND(dve, obio, 1, 1, 1);
-MODULE_DEPEND(dve, miibus, 1, 1, 1);
-MODULE_DEPEND(dve, ether, 1, 1, 1);
+MODULE_DEPEND(lpe, obio, 1, 1, 1);
+MODULE_DEPEND(lpe, miibus, 1, 1, 1);
+MODULE_DEPEND(lpe, ether, 1, 1, 1);
==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#2 (text+ko) ====
@@ -151,6 +151,8 @@
uint32_t lhs_crc;
};
+#define LPE_INC(x, y) (x) = ((x) == ((y)-1)) ? 0 : (x)+1
+
/* These are valid for both Rx and Tx descriptors */
#define LPE_HWDESC_SIZE_MASK (1 << 10)
More information about the p4-projects
mailing list