diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c index e6bc244d201..f90062a48eb 100644 --- a/sys/dev/em/if_em.c +++ b/sys/dev/em/if_em.c @@ -67,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -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 d36de52b6f2..e7f96f793ca 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;