summaryrefslogtreecommitdiffstats
path: root/sys/dev/dc
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/dc')
-rw-r--r--sys/dev/dc/if_dc.c83
-rw-r--r--sys/dev/dc/if_dcreg.h7
2 files changed, 90 insertions, 0 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index 139983b..caee9d0 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -2473,6 +2473,13 @@ static void dc_rxeof(sc)
while(!(sc->dc_ldata->dc_rx_list[i].dc_status & DC_RXSTAT_OWN)) {
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING) {
+ if (sc->rxcycles <= 0)
+ break;
+ sc->rxcycles--;
+ }
+#endif /* DEVICE_POLLING */
cur_rx = &sc->dc_ldata->dc_rx_list[i];
rxstat = cur_rx->dc_status;
m = sc->dc_cdata.dc_rx_chain[i];
@@ -2786,6 +2793,60 @@ static void dc_tx_underrun(sc)
return;
}
+#ifdef DEVICE_POLLING
+static poll_handler_t dc_poll;
+
+static void
+dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct dc_softc *sc = ifp->if_softc;
+
+ if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+ /* Re-enable interrupts. */
+ CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+ return;
+ }
+ sc->rxcycles = count;
+ dc_rxeof(sc);
+ dc_txeof(sc);
+ if (ifp->if_snd.ifq_head != NULL && !(ifp->if_flags & IFF_OACTIVE))
+ dc_start(ifp);
+
+ if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
+ u_int32_t status;
+
+ status = CSR_READ_4(sc, DC_ISR);
+ status &= (DC_ISR_RX_WATDOGTIMEO|DC_ISR_RX_NOBUF|
+ DC_ISR_TX_NOBUF|DC_ISR_TX_IDLE|DC_ISR_TX_UNDERRUN|
+ DC_ISR_BUS_ERR);
+ if (!status)
+ return ;
+ /* ack what we have */
+ CSR_WRITE_4(sc, DC_ISR, status);
+
+ if (status & (DC_ISR_RX_WATDOGTIMEO|DC_ISR_RX_NOBUF) ) {
+ u_int32_t r = CSR_READ_4(sc, DC_FRAMESDISCARDED);
+ ifp->if_ierrors += (r & 0xffff) + ((r >> 17) & 0x7ff);
+
+ if (dc_rx_resync(sc))
+ dc_rxeof(sc);
+ }
+ /* restart transmit unit if necessary */
+ if (status & DC_ISR_TX_IDLE && sc->dc_cdata.dc_tx_cnt)
+ CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+ if (status & DC_ISR_TX_UNDERRUN)
+ dc_tx_underrun(sc);
+
+ if (status & DC_ISR_BUS_ERR) {
+ printf("dc_poll: dc%d bus error\n", sc->dc_unit);
+ dc_reset(sc);
+ dc_init(sc);
+ }
+ }
+}
+#endif /* DEVICE_POLLING */
+
static void dc_intr(arg)
void *arg;
{
@@ -2800,6 +2861,14 @@ static void dc_intr(arg)
DC_LOCK(sc);
ifp = &sc->arpcom.ac_if;
+#ifdef DEVICE_POLLING
+ if (ifp->if_ipending & IFF_POLLING)
+ goto done;
+ if (ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ goto done;
+ }
+#endif /* DEVICE_POLLING */
/* Suppress unwanted interrupts */
if (!(ifp->if_flags & IFF_UP)) {
@@ -2864,6 +2933,7 @@ static void dc_intr(arg)
if (ifp->if_snd.ifq_head != NULL)
dc_start(ifp);
+done:
DC_UNLOCK(sc);
return;
@@ -3163,6 +3233,16 @@ static void dc_init(xsc)
/*
* Enable interrupts.
*/
+#ifdef DEVICE_POLLING
+ /*
+ * ... but only if we are not polling, and make sure they are off in
+ * the case of polling. Some cards (e.g. fxp) turn interrupts on
+ * after a reset.
+ */
+ if (ifp->if_ipending & IFF_POLLING)
+ CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+ else
+#endif
CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF);
@@ -3378,6 +3458,9 @@ static void dc_stop(sc)
callout_stop(&sc->dc_stat_ch);
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+#ifdef DEVICE_POLLING
+ ether_poll_deregister(ifp);
+#endif
DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON|DC_NETCFG_TX_ON));
CSR_WRITE_4(sc, DC_IMR, 0x00000000);
diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
index 0052d33..8980e44 100644
--- a/sys/dev/dc/if_dcreg.h
+++ b/sys/dev/dc/if_dcreg.h
@@ -453,7 +453,11 @@ struct dc_desc {
#define DC_FILTER_HASHONLY 0x10400000
#define DC_MAXFRAGS 16
+#ifdef DEVICE_POLLING
+#define DC_RX_LIST_CNT 192
+#else
#define DC_RX_LIST_CNT 64
+#endif
#define DC_TX_LIST_CNT 256
#define DC_MIN_FRAMELEN 60
#define DC_RXLEN 1536
@@ -717,6 +721,9 @@ struct dc_softc {
int dc_srm_media;
#endif
struct mtx dc_mtx;
+#ifdef DEVICE_POLLING
+ int rxcycles; /* ... when polling */
+#endif
};
OpenPOWER on IntegriCloud