summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2006-07-20 04:18:45 +0000
committeryongari <yongari@FreeBSD.org>2006-07-20 04:18:45 +0000
commitdf16853b7f15bb79dfe2674396556d704ca0048a (patch)
treeb654ecb30412e6c83f342d2e9a78ce4b79b73d02 /sys/dev
parent4865b8aa7c5208ebfd5e38819bfdd039fb24b56b (diff)
downloadFreeBSD-src-df16853b7f15bb79dfe2674396556d704ca0048a.zip
FreeBSD-src-df16853b7f15bb79dfe2674396556d704ca0048a.tar.gz
Since resetting hardware takes a very long time and results in link
renegotiation, we only initialize the hardware only when it is absolutely required. Process SIOCGIFADDR ioctl in em(4) when we know an IPv4 address is added. Handling SIOCGIFADDR in a driver is layering violation but it seems that there is no easy way without rewritting hardware initialization code to reduce settle time after reset. This should fix a long standing bug which didn't send ARP packet when interface address is changed or an alias address is added. Another effect of this fix is it doesn't need additional delays anymore when adding an alias address to the interface. While I'm here add a new if_flags into softc which remembers current prgroammed interface flags and make use of it when we have to program promiscuous mode. Tested by: Atanas <atanas AT asd DOT aplus DOT net> Analyzed by: rwatson Discussed with: -stable
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/em/if_em.c38
-rw-r--r--sys/dev/em/if_em.h1
2 files changed, 30 insertions, 9 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index e6bc244..f90062a 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -67,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <netinet/in_systm.h>
#include <netinet/in.h>
+#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
@@ -748,6 +749,7 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
struct em_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
int error = 0;
if (sc->in_detach)
@@ -756,8 +758,23 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
switch (command) {
case SIOCSIFADDR:
case SIOCGIFADDR:
- IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
- ether_ioctl(ifp, command, data);
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ /*
+ * XXX
+ * Since resetting hardware takes a very long time
+ * and results in link renegotiation we only
+ * initialize the hardware only when it is absolutely
+ * required.
+ */
+ ifp->if_flags |= IFF_UP;
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ EM_LOCK(sc);
+ em_init_locked(sc);
+ EM_UNLOCK(sc);
+ }
+ arp_ifinit(ifp, ifa);
+ } else
+ error = ether_ioctl(ifp, command, data);
break;
case SIOCSIFMTU:
{
@@ -806,17 +823,20 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
EM_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ if ((ifp->if_flags ^ sc->if_flags) &
+ IFF_PROMISC) {
+ em_disable_promisc(sc);
+ em_set_promisc(sc);
+ }
+ } else
em_init_locked(sc);
- }
-
- em_disable_promisc(sc);
- em_set_promisc(sc);
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
em_stop(sc);
}
}
+ sc->if_flags = ifp->if_flags;
EM_UNLOCK(sc);
break;
case SIOCADDMULTI:
@@ -882,8 +902,8 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
}
default:
- IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)", (int)command);
- error = EINVAL;
+ error = ether_ioctl(ifp, command, data);
+ break;
}
return (error);
diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h
index d36de52..e7f96f7 100644
--- a/sys/dev/em/if_em.h
+++ b/sys/dev/em/if_em.h
@@ -259,6 +259,7 @@ struct em_softc {
struct callout timer;
struct callout tx_fifo_timer;
int io_rid;
+ int if_flags;
struct mtx mtx;
int em_insert_vlan_header;
struct task link_task;
OpenPOWER on IntegriCloud