summaryrefslogtreecommitdiffstats
path: root/sys/pci/if_xl.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2005-10-01 18:56:19 +0000
committerglebius <glebius@FreeBSD.org>2005-10-01 18:56:19 +0000
commitf41a83bf429b15386f43f43f3f5326d4ece7bfce (patch)
treeb78f9e953b7b58b2789d042cf37cc725045fdcf1 /sys/pci/if_xl.c
parent6c6c328bd0bbb1d9f6b3230a33d194bf961b0eae (diff)
downloadFreeBSD-src-f41a83bf429b15386f43f43f3f5326d4ece7bfce.zip
FreeBSD-src-f41a83bf429b15386f43f43f3f5326d4ece7bfce.tar.gz
Big polling(4) cleanup.
o Axe poll in trap. o Axe IFF_POLLING flag from if_flags. o Rework revision 1.21 (Giant removal), in such a way that poll_mtx is not dropped during call to polling handler. This fixes problem with idle polling. o Make registration and deregistration from polling in a functional way, insted of next tick/interrupt. o Obsolete kern.polling.enable. Polling is turned on/off with ifconfig. Detailed kern_poll.c changes: - Remove polling handler flags, introduced in 1.21. The are not needed now. - Forget and do not check if_flags, if_capenable and if_drv_flags. - Call all registered polling handlers unconditionally. - Do not drop poll_mtx, when entering polling handlers. - In ether_poll() NET_LOCK_GIANT prior to locking poll_mtx. - In netisr_poll() axe the block, where polling code asks drivers to unregister. - In netisr_poll() and ether_poll() do polling always, if any handlers are present. - In ether_poll_[de]register() remove a lot of error hiding code. Assert that arguments are correct, instead. - In ether_poll_[de]register() use standard return values in case of error or success. - Introduce poll_switch() that is a sysctl handler for kern.polling.enable. poll_switch() goes through interface list and enabled/disables polling. A message that kern.polling.enable is deprecated is printed. Detailed driver changes: - On attach driver announces IFCAP_POLLING in if_capabilities, but not in if_capenable. - On detach driver calls ether_poll_deregister() if polling is enabled. - In polling handler driver obtains its lock and checks IFF_DRV_RUNNING flag. If there is no, then unlocks and returns. - In ioctl handler driver checks for IFCAP_POLLING flag requested to be set or cleared. Driver first calls ether_poll_[de]register(), then obtains driver lock and [dis/en]ables interrupts. - In interrupt handler driver checks IFCAP_POLLING flag in if_capenable. If present, then returns.This is important to protect from spurious interrupts. Reviewed by: ru, sam, jhb
Diffstat (limited to 'sys/pci/if_xl.c')
-rw-r--r--sys/pci/if_xl.c86
1 files changed, 45 insertions, 41 deletions
diff --git a/sys/pci/if_xl.c b/sys/pci/if_xl.c
index 520f668..e49997a 100644
--- a/sys/pci/if_xl.c
+++ b/sys/pci/if_xl.c
@@ -249,7 +249,7 @@ static int xl_resume(device_t);
#ifdef DEVICE_POLLING
static void xl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count);
static void xl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count);
-#endif /* DEVICE_POLLING */
+#endif
static int xl_ifmedia_upd(struct ifnet *);
static void xl_ifmedia_sts(struct ifnet *, struct ifmediareq *);
@@ -1487,9 +1487,10 @@ xl_attach(device_t dev)
ifp->if_capabilities |= IFCAP_HWCSUM;
#endif
}
+ ifp->if_capenable = ifp->if_capabilities;
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
-#endif /* DEVICE_POLLING */
+#endif
ifp->if_start = xl_start;
ifp->if_watchdog = xl_watchdog;
ifp->if_init = xl_init;
@@ -1497,7 +1498,6 @@ xl_attach(device_t dev)
IFQ_SET_MAXLEN(&ifp->if_snd, XL_TX_LIST_CNT - 1);
ifp->if_snd.ifq_drv_maxlen = XL_TX_LIST_CNT - 1;
IFQ_SET_READY(&ifp->if_snd);
- ifp->if_capenable = ifp->if_capabilities;
/*
* Now we have to see what sort of media we have.
@@ -1690,6 +1690,11 @@ xl_detach(device_t dev)
KASSERT(mtx_initialized(&sc->xl_mtx), ("xl mutex not initialized"));
+#ifdef DEVICE_POLLING
+ if (ifp->if_capenable & IFCAP_POLLING)
+ ether_poll_deregister(ifp);
+#endif
+
if (sc->xl_flags & XL_FLAG_USE_MMIO) {
rid = XL_PCI_LOMEM;
res = SYS_RES_MEMORY;
@@ -1960,12 +1965,12 @@ again:
BUS_DMASYNC_POSTREAD);
while ((rxstat = le32toh(sc->xl_cdata.xl_rx_head->xl_ptr->xl_status))) {
#ifdef DEVICE_POLLING
- if (ifp->if_flags & IFF_POLLING) {
+ if (ifp->if_capenable & IFCAP_POLLING) {
if (sc->rxcycles <= 0)
break;
sc->rxcycles--;
}
-#endif /* DEVICE_POLLING */
+#endif
cur_rx = sc->xl_cdata.xl_rx_head;
sc->xl_cdata.xl_rx_head = cur_rx->xl_next;
total_len = rxstat & XL_RXSTAT_LENMASK;
@@ -2275,24 +2280,11 @@ xl_intr(void *arg)
XL_LOCK(sc);
#ifdef DEVICE_POLLING
- if (ifp->if_flags & IFF_POLLING) {
+ if (ifp->if_capenable & IFCAP_POLLING) {
XL_UNLOCK(sc);
return;
}
-
- if ((ifp->if_capenable & IFCAP_POLLING) &&
- ether_poll_register(xl_poll, ifp)) {
- /* Disable interrupts. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
- if (sc->xl_flags & XL_FLAG_FUNCREG)
- bus_space_write_4(sc->xl_ftag, sc->xl_fhandle,
- 4, 0x8000);
- xl_poll_locked(ifp, 0, 1);
- XL_UNLOCK(sc);
- return;
- }
-#endif /* DEVICE_POLLING */
+#endif
while ((status = CSR_READ_2(sc, XL_STATUS)) & XL_INTRS &&
status != 0xFFFF) {
@@ -2351,7 +2343,8 @@ xl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
struct xl_softc *sc = ifp->if_softc;
XL_LOCK(sc);
- xl_poll_locked(ifp, cmd, count);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ xl_poll_locked(ifp, cmd, count);
XL_UNLOCK(sc);
}
@@ -2362,21 +2355,6 @@ xl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
XL_LOCK_ASSERT(sc);
- if (!(ifp->if_capenable & IFCAP_POLLING)) {
- ether_poll_deregister(ifp);
- cmd = POLL_DEREGISTER;
- }
-
- if (cmd == POLL_DEREGISTER) {
- /* Final call; enable interrupts. */
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
- CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
- if (sc->xl_flags & XL_FLAG_FUNCREG)
- bus_space_write_4(sc->xl_ftag, sc->xl_fhandle,
- 4, 0x8000);
- return;
- }
-
sc->rxcycles = count;
xl_rxeof(sc);
if (sc->xl_type == XL_TYPE_905B)
@@ -2989,10 +2967,10 @@ xl_init_locked(struct xl_softc *sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
#ifdef DEVICE_POLLING
/* Disable interrupts if we are polling. */
- if (ifp->if_flags & IFF_POLLING)
+ if (ifp->if_capenable & IFCAP_POLLING)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
else
-#endif /* DEVICE_POLLING */
+#endif
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
if (sc->xl_flags & XL_FLAG_FUNCREG)
bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, 4, 0x8000);
@@ -3204,6 +3182,35 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
&mii->mii_media, command);
break;
case SIOCSIFCAP:
+#ifdef DEVICE_POLLING
+ if (ifr->ifr_reqcap & IFCAP_POLLING &&
+ !(ifp->if_capenable & IFCAP_POLLING)) {
+ error = ether_poll_register(xl_poll, ifp);
+ if (error)
+ return(error);
+ XL_LOCK(sc);
+ /* Disable interrupts */
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
+ ifp->if_capenable |= IFCAP_POLLING;
+ XL_UNLOCK(sc);
+ return (error);
+
+ }
+ if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
+ ifp->if_capenable & IFCAP_POLLING) {
+ error = ether_poll_deregister(ifp);
+ /* Enable interrupts. */
+ XL_LOCK(sc);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF);
+ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS);
+ if (sc->xl_flags & XL_FLAG_FUNCREG)
+ bus_space_write_4(sc->xl_ftag, sc->xl_fhandle,
+ 4, 0x8000);
+ ifp->if_capenable &= ~IFCAP_POLLING;
+ XL_UNLOCK(sc);
+ return (error);
+ }
+#endif /* DEVICE_POLLING */
XL_LOCK(sc);
ifp->if_capenable = ifr->ifr_reqcap;
if (ifp->if_capenable & IFCAP_TXCSUM)
@@ -3268,9 +3275,6 @@ xl_stop(struct xl_softc *sc)
XL_LOCK_ASSERT(sc);
ifp->if_timer = 0;
-#ifdef DEVICE_POLLING
- ether_poll_deregister(ifp);
-#endif /* DEVICE_POLLING */
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_DISABLE);
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STATS_DISABLE);
OpenPOWER on IntegriCloud