summaryrefslogtreecommitdiffstats
path: root/sys/dev/em
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/dev/em
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/dev/em')
-rw-r--r--sys/dev/em/if_em.c71
1 files changed, 37 insertions, 34 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index f380e1e..3b5db52 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -197,6 +197,9 @@ static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
static void em_add_int_delay_sysctl(struct adapter *, const char *,
const char *, struct em_int_delay_info *,
int, int);
+#ifdef DEVICE_POLLING
+static poll_handler_t em_poll;
+#endif
/*********************************************************************
* FreeBSD Device Interface Entry Points
@@ -526,6 +529,11 @@ em_detach(device_t dev)
INIT_DEBUGOUT("em_detach: begin");
+#ifdef DEVICE_POLLING
+ if (ifp->if_capenable & IFCAP_POLLING)
+ ether_poll_deregister(ifp);
+#endif
+
EM_LOCK(adapter);
adapter->in_detach = 1;
em_stop(adapter);
@@ -717,7 +725,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
em_initialize_receive_unit(adapter);
}
#ifdef DEVICE_POLLING
- if (!(ifp->if_flags & IFF_POLLING))
+ if (!(ifp->if_capenable & IFCAP_POLLING))
#endif
em_enable_intr(adapter);
EM_UNLOCK(adapter);
@@ -732,8 +740,26 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
reinit = 0;
mask = ifr->ifr_reqcap ^ ifp->if_capenable;
- if (mask & IFCAP_POLLING)
- ifp->if_capenable ^= IFCAP_POLLING;
+#ifdef DEVICE_POLLING
+ if (mask & IFCAP_POLLING) {
+ if (ifr->ifr_reqcap & IFCAP_POLLING) {
+ error = ether_poll_register(em_poll, ifp);
+ if (error)
+ return(error);
+ EM_LOCK(adapter);
+ em_disable_intr(adapter);
+ ifp->if_capenable |= IFCAP_POLLING;
+ EM_UNLOCK(adapter);
+ } else {
+ error = ether_poll_deregister(ifp);
+ /* Enable interrupt even in error case */
+ EM_LOCK(adapter);
+ em_enable_intr(adapter);
+ ifp->if_capenable &= ~IFCAP_POLLING;
+ EM_UNLOCK(adapter);
+ }
+ }
+#endif
if (mask & IFCAP_HWCSUM) {
ifp->if_capenable ^= IFCAP_HWCSUM;
reinit = 1;
@@ -895,7 +921,7 @@ em_init_locked(struct adapter * adapter)
* Only enable interrupts if we are not polling, make sure
* they are off otherwise.
*/
- if (ifp->if_flags & IFF_POLLING)
+ if (ifp->if_capenable & IFCAP_POLLING)
em_disable_intr(adapter);
else
#endif /* DEVICE_POLLING */
@@ -920,8 +946,6 @@ em_init(void *arg)
#ifdef DEVICE_POLLING
-static poll_handler_t em_poll;
-
static void
em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
{
@@ -930,14 +954,6 @@ em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
mtx_assert(&adapter->mtx, MA_OWNED);
- if (!(ifp->if_capenable & IFCAP_POLLING)) {
- ether_poll_deregister(ifp);
- cmd = POLL_DEREGISTER;
- }
- if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
- em_enable_intr(adapter);
- return;
- }
if (cmd == POLL_AND_CHECK_STATUS) {
reg_icr = E1000_READ_REG(&adapter->hw, ICR);
if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
@@ -948,13 +964,10 @@ em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
callout_reset(&adapter->timer, hz, em_local_timer, adapter);
}
}
- if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- em_process_receive_interrupts(adapter, count);
- em_clean_transmit_interrupts(adapter);
- }
+ em_process_receive_interrupts(adapter, count);
+ em_clean_transmit_interrupts(adapter);
- if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
em_start_locked(ifp);
}
@@ -964,7 +977,8 @@ em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
struct adapter *adapter = ifp->if_softc;
EM_LOCK(adapter);
- em_poll_locked(ifp, cmd, count);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ em_poll_locked(ifp, cmd, count);
EM_UNLOCK(adapter);
}
#endif /* DEVICE_POLLING */
@@ -987,18 +1001,10 @@ em_intr(void *arg)
ifp = adapter->ifp;
#ifdef DEVICE_POLLING
- if (ifp->if_flags & IFF_POLLING) {
+ if (ifp->if_capenable & IFCAP_POLLING) {
EM_UNLOCK(adapter);
return;
}
-
- if ((ifp->if_capenable & IFCAP_POLLING) &&
- ether_poll_register(em_poll, ifp)) {
- em_disable_intr(adapter);
- em_poll_locked(ifp, 0, 1);
- EM_UNLOCK(adapter);
- return;
- }
#endif /* DEVICE_POLLING */
reg_icr = E1000_READ_REG(&adapter->hw, ICR);
@@ -1718,9 +1724,7 @@ em_stop(void *arg)
mtx_assert(&adapter->mtx, MA_OWNED);
INIT_DEBUGOUT("em_stop: begin");
-#ifdef DEVICE_POLLING
- ether_poll_deregister(ifp);
-#endif
+
em_disable_intr(adapter);
em_reset_hw(&adapter->hw);
callout_stop(&adapter->timer);
@@ -1976,7 +1980,6 @@ em_setup_interface(device_t dev, struct adapter * adapter)
#ifdef DEVICE_POLLING
ifp->if_capabilities |= IFCAP_POLLING;
- ifp->if_capenable |= IFCAP_POLLING;
#endif
/*
OpenPOWER on IntegriCloud