| Summary: | [PATCH] fxp device causes lockups after suspend/resume | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | mike+fbsd <mike+fbsd> | ||||
| Component: | kern | Assignee: | dg | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 4.0-STABLE | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
|
Description
mike+fbsd
2000-05-22 21:30:01 UTC
> >+ /* don't try to service interrupts when the interface isn't running */ >+ if ((ifp->if_flags & IFF_RUNNING) == 0) { >+ return; >+ } >+ > while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { This could be a problem. If an interrupt occurs, it must be acknowledged otherwise you'll be stuck in an infinit loop - PCI interrupts are level sensitive and must be cleared in the ISR. -DG David Greenman Co-founder, The FreeBSD Project - http://www.freebsd.org Creator of high-performance Internet servers - http://www.terasolutions.com Pave the road of life with opportunities. on May 22, David Greenman <dg@root.com> wrote: > > > >+ /* don't try to service interrupts when the interface isn't running */ > >+ if ((ifp->if_flags & IFF_RUNNING) == 0) { > >+ return; > >+ } > >+ > > while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) { > > This could be a problem. If an interrupt occurs, it must be acknowledged > otherwise you'll be stuck in an infinit loop - PCI interrupts are level > sensitive and must be cleared in the ISR. the only time i've seen that return executed is when the interrupt was for another device sharing the same IRQ that happened to have been resumed first -- in my case, an onboard uhci usb controller. without the check above, i do get resume lockups in fxp_intr. i've just been assuming that an fxp can't generate a interrupt unless it's running. if that's not correct, would it be better to have a "device suspended" flag in fxp_softc and replace the statement above to execute the necessary resume code if the device is still suspended? Responsible Changed From-To: freebsd-bugs->dg dg wrote the fxp driver. State Changed From-To: open->closed Similar patches with changes by me was committed to -current. It will be MFC'ed in a few days. Hi!
The MFC promised in the closing message of this PR about a month ago
did not seem to happen, so I took a shot at it. It compiles. It
seems to work fine on my VAIO Z505JE, where fxp previously stopped
working after returning from suspend mode.
The patch is larger than it strictly would have to be, as I removed
all the NetBSD code (it made it easier to diff against -CURRENT).
It would be nice to see fxp on VAIO work in -STABLE.
Regards,
/Mikko
Mikko Työläjärvi_______________________________________mikko@rsasecurity.com
RSA Security
--- if_fxpvar.h.orig Wed Oct 18 13:07:31 2000
+++ if_fxpvar.h Wed Oct 18 13:07:41 2000
@@ -2,9 +2,6 @@
* Copyright (c) 1995, David Greenman
* All rights reserved.
*
- * Modifications to support NetBSD:
- * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -39,16 +36,10 @@
* for functional grouping.
*/
struct fxp_softc {
-#if defined(__NetBSD__)
- struct device sc_dev; /* generic device structures */
- void *sc_ih; /* interrupt handler cookie */
- struct ethercom sc_ethercom; /* ethernet common part */
-#else
struct arpcom arpcom; /* per-interface network data */
struct resource *mem; /* resource descriptor for registers */
struct resource *irq; /* resource descriptor for interrupt */
void *ih; /* interrupt handler cookie */
-#endif /* __NetBSD__ */
bus_space_tag_t sc_st; /* bus space tag */
bus_space_handle_t sc_sh; /* bus space handle */
struct mbuf *rfa_headm; /* first mbuf in receive frame area */
@@ -68,6 +59,12 @@
int phy_primary_device; /* device type of primary PHY */
int phy_10Mbps_only; /* PHY is 10Mbps-only device */
int eeprom_size; /* size of serial EEPROM */
+ int suspended; /* 0 = normal 1 = suspended (APM) */
+ u_int32_t saved_maps[5]; /* pci data */
+ u_int32_t saved_biosaddr;
+ u_int8_t saved_intline;
+ u_int8_t saved_cachelnsz;
+ u_int8_t saved_lattimer;
};
/* Macros to ease CSR access. */
@@ -84,19 +81,5 @@
#define CSR_WRITE_4(sc, reg, val) \
bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
-/* Deal with slight differences in software interfaces. */
-#if defined(__NetBSD__)
-#define sc_if sc_ethercom.ec_if
-#define FXP_FORMAT "%s"
-#define FXP_ARGS(sc) (sc)->sc_dev.dv_xname
-#define FXP_INTR_TYPE int
-#define FXP_IOCTLCMD_TYPE u_long
-#define FXP_BPFTAP_ARG(ifp) (ifp)->if_bpf
-#else /* __FreeBSD__ */
#define sc_if arpcom.ac_if
-#define FXP_FORMAT "fxp%d"
-#define FXP_ARGS(sc) (sc)->arpcom.ac_if.if_unit
-#define FXP_INTR_TYPE void
-#define FXP_IOCTLCMD_TYPE u_long
-#define FXP_BPFTAP_ARG(ifp) ifp
-#endif /* __NetBSD__ */
+#define FXP_UNIT(_sc) (_sc)->arpcom.ac_if.if_unit
--- if_fxp.c.orig Wed Oct 18 13:07:22 2000
+++ if_fxp.c Wed Oct 18 13:13:49 2000
@@ -2,7 +2,7 @@
* Copyright (c) 1995, David Greenman
* All rights reserved.
*
- * Modifications to support NetBSD and media selection:
+ * Modifications to support media selection:
* Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,34 +51,6 @@
#endif
#include <net/bpf.h>
-
-#if defined(__NetBSD__)
-
-#include <sys/ioctl.h>
-#include <sys/errno.h>
-#include <sys/device.h>
-
-#include <net/if_dl.h>
-#include <net/if_ether.h>
-
-#include <netinet/if_inarp.h>
-
-#include <vm/vm.h>
-
-#include <machine/cpu.h>
-#include <machine/bus.h>
-#include <machine/intr.h>
-
-#include <dev/pci/if_fxpreg.h>
-#include <dev/pci/if_fxpvar.h>
-
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcidevs.h>
-
-
-#else /* __FreeBSD__ */
-
#include <sys/sockio.h>
#include <sys/bus.h>
#include <machine/bus.h>
@@ -97,8 +69,6 @@
#include <pci/if_fxpreg.h>
#include <pci/if_fxpvar.h>
-#endif /* __NetBSD__ */
-
#ifdef __alpha__ /* XXX */
/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
#undef vtophys
@@ -219,10 +189,11 @@
static void fxp_mediastatus __P((struct ifnet *, struct ifmediareq *));
static void fxp_set_media __P((struct fxp_softc *, int));
static __inline void fxp_scb_wait __P((struct fxp_softc *));
-static FXP_INTR_TYPE fxp_intr __P((void *));
+static __inline void fxp_dma_wait __P((volatile u_int16_t *, struct fxp_softc *sc));
+static void fxp_intr __P((void *));
static void fxp_start __P((struct ifnet *));
static int fxp_ioctl __P((struct ifnet *,
- FXP_IOCTLCMD_TYPE, caddr_t));
+ u_long, caddr_t));
static void fxp_init __P((void *));
static void fxp_stop __P((struct fxp_softc *));
static void fxp_watchdog __P((struct ifnet *));
@@ -288,207 +259,25 @@
{
int i = 10000;
- while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
-}
-
-/*************************************************************
- * Operating system-specific autoconfiguration glue
- *************************************************************/
-
-#if defined(__NetBSD__)
-
-#ifdef __BROKEN_INDIRECT_CONFIG
-static int fxp_match __P((struct device *, void *, void *));
-#else
-static int fxp_match __P((struct device *, struct cfdata *, void *));
-#endif
-static void fxp_attach __P((struct device *, struct device *, void *));
-
-static void fxp_shutdown __P((void *));
-
-/* Compensate for lack of a generic ether_ioctl() */
-static int fxp_ether_ioctl __P((struct ifnet *,
- FXP_IOCTLCMD_TYPE, caddr_t));
-#define ether_ioctl fxp_ether_ioctl
-
-struct cfattach fxp_ca = {
- sizeof(struct fxp_softc), fxp_match, fxp_attach
-};
-
-struct cfdriver fxp_cd = {
- NULL, "fxp", DV_IFNET
-};
-
-/*
- * Check if a device is an 82557.
- */
-static int
-fxp_match(parent, match, aux)
- struct device *parent;
-#ifdef __BROKEN_INDIRECT_CONFIG
- void *match;
-#else
- struct cfdata *match;
-#endif
- void *aux;
-{
- struct pci_attach_args *pa = aux;
-
- if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
- return (0);
-
- switch (PCI_PRODUCT(pa->pa_id)) {
- case PCI_PRODUCT_INTEL_82557:
- return (1);
- }
-
- return (0);
+ while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i)
+ DELAY(2);
+ if (i == 0)
+ printf("fxp%d: SCB timeout\n", FXP_UNIT(sc));
}
-static void
-fxp_attach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
-{
- struct fxp_softc *sc = (struct fxp_softc *)self;
- struct pci_attach_args *pa = aux;
- pci_chipset_tag_t pc = pa->pa_pc;
- pci_intr_handle_t ih;
- const char *intrstr = NULL;
- u_int8_t enaddr[6];
- struct ifnet *ifp;
-
- /*
- * Map control/status registers.
- */
- if (pci_mapreg_map(pa, FXP_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
- &sc->sc_st, &sc->sc_sh, NULL, NULL)) {
- printf(": can't map registers\n");
- return;
- }
- printf(": Intel EtherExpress Pro 10/100B Ethernet\n");
-
- /*
- * Allocate our interrupt.
- */
- if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
- pa->pa_intrline, &ih)) {
- printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
- return;
- }
- intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, fxp_intr, sc);
- if (sc->sc_ih == NULL) {
- printf("%s: couldn't establish interrupt",
- sc->sc_dev.dv_xname);
- if (intrstr != NULL)
- printf(" at %s", intrstr);
- printf("\n");
- return;
- }
- printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
-
- /* Do generic parts of attach. */
- if (fxp_attach_common(sc, enaddr)) {
- /* Failed! */
- return;
- }
-
- printf("%s: Ethernet address %s%s\n", sc->sc_dev.dv_xname,
- ether_sprintf(enaddr), sc->phy_10Mbps_only ? ", 10Mbps" : "");
-
- ifp = &sc->sc_ethercom.ec_if;
- bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
- ifp->if_softc = sc;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = fxp_ioctl;
- ifp->if_start = fxp_start;
- ifp->if_watchdog = fxp_watchdog;
-
- /*
- * Attach the interface.
- */
- if_attach(ifp);
- /*
- * Let the system queue as many packets as we have available
- * TX descriptors.
- */
- ifp->if_snd.ifq_maxlen = FXP_NTXCB - 1;
- ether_ifattach(ifp, enaddr);
- bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
- sizeof(struct ether_header));
-
- /*
- * Add shutdown hook so that DMA is disabled prior to reboot. Not
- * doing do could allow DMA to corrupt kernel memory during the
- * reboot before the driver initializes.
- */
- shutdownhook_establish(fxp_shutdown, sc);
-}
-
-/*
- * Device shutdown routine. Called at system shutdown after sync. The
- * main purpose of this routine is to shut off receiver DMA so that
- * kernel memory doesn't get clobbered during warmboot.
- */
-static void
-fxp_shutdown(sc)
- void *sc;
-{
- fxp_stop((struct fxp_softc *) sc);
-}
-
-static int
-fxp_ether_ioctl(ifp, cmd, data)
- struct ifnet *ifp;
- FXP_IOCTLCMD_TYPE cmd;
- caddr_t data;
+static __inline void
+fxp_dma_wait(status, sc)
+ volatile u_int16_t *status;
+ struct fxp_softc *sc;
{
- struct ifaddr *ifa = (struct ifaddr *) data;
- struct fxp_softc *sc = ifp->if_softc;
-
- switch (cmd) {
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
-
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
- fxp_init(sc);
- arp_ifinit(ifp, ifa);
- break;
-#endif
-#ifdef NS
- case AF_NS:
- {
- register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
-
- if (ns_nullhost(*ina))
- ina->x_host = *(union ns_host *)
- LLADDR(ifp->if_sadl);
- else
- bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
- ifp->if_addrlen);
- /* Set new address. */
- fxp_init(sc);
- break;
- }
-#endif
- default:
- fxp_init(sc);
- break;
- }
- break;
-
- default:
- return (EINVAL);
- }
+ int i = 10000;
- return (0);
+ while (!(*status & FXP_CB_STATUS_C) && --i)
+ DELAY(2);
+ if (i == 0)
+ printf("fxp%d: DMA timeout\n", FXP_UNIT(sc));
}
-#else /* __FreeBSD__ */
-
/*
* Return identification string if this is device is ours.
*/
@@ -684,12 +473,81 @@
return 0;
}
+/*
+ * Device suspend routine. Stop the interface and save some PCI
+ * settings in case the BIOS doesn't restore them properly on
+ * resume.
+ */
+static int
+fxp_suspend(device_t dev)
+{
+ struct fxp_softc *sc = device_get_softc(dev);
+ int i, s = splimp();
+
+ fxp_stop(sc);
+
+ for (i=0; i<5; i++)
+ sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i*4, 4);
+ sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4);
+ sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1);
+ sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
+ sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1);
+
+ sc->suspended = 1;
+
+ splx(s);
+
+ return 0;
+}
+
+/*
+ * Device resume routine. Restore some PCI settings in case the BIOS
+ * doesn't, re-enable busmastering, and restart the interface if
+ * appropriate.
+ */
+static int
+fxp_resume(device_t dev)
+{
+ struct fxp_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = &sc->sc_if;
+ u_int16_t pci_command;
+ int i, s = splimp();
+
+ /* better way to do this? */
+ for (i=0; i<5; i++)
+ pci_write_config(dev, PCIR_MAPS + i*4, sc->saved_maps[i], 4);
+ pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4);
+ pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1);
+ pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1);
+ pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1);
+
+ /* reenable busmastering */
+ pci_command = pci_read_config(dev, PCIR_COMMAND, 2);
+ pci_command |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
+ pci_write_config(dev, PCIR_COMMAND, pci_command, 2);
+
+ CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+ DELAY(10);
+
+ /* reinitialize interface if necessary */
+ if (ifp->if_flags & IFF_UP)
+ fxp_init(sc);
+
+ sc->suspended = 0;
+
+ splx(s);
+
+ return 0;
+}
+
static device_method_t fxp_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fxp_probe),
DEVMETHOD(device_attach, fxp_attach),
DEVMETHOD(device_detach, fxp_detach),
DEVMETHOD(device_shutdown, fxp_shutdown),
+ DEVMETHOD(device_suspend, fxp_suspend),
+ DEVMETHOD(device_resume, fxp_resume),
{ 0, 0 }
};
@@ -704,12 +562,6 @@
DRIVER_MODULE(if_fxp, pci, fxp_driver, fxp_devclass, 0, 0);
-#endif /* __NetBSD__ */
-
-/*************************************************************
- * End of operating system-specific autoconfiguration glue
- *************************************************************/
-
/*
* Do generic parts of attach.
*/
@@ -797,7 +649,7 @@
return (0);
fail:
- printf(FXP_FORMAT ": Failed to malloc memory\n", FXP_ARGS(sc));
+ printf("fxp%d: Failed to malloc memory\n", FXP_UNIT(sc));
if (sc->cbl_base)
free(sc->cbl_base, M_DEVBUF);
if (sc->fxp_stats)
@@ -1085,7 +937,7 @@
* Pass packet to bpf if there is a listener.
*/
if (ifp->if_bpf)
- bpf_mtap(FXP_BPFTAP_ARG(ifp), mb_head);
+ bpf_mtap(ifp, mb_head);
}
/*
@@ -1101,21 +953,18 @@
/*
* Process interface interrupts.
*/
-static FXP_INTR_TYPE
+static void
fxp_intr(arg)
void *arg;
{
struct fxp_softc *sc = arg;
struct ifnet *ifp = &sc->sc_if;
u_int8_t statack;
-#if defined(__NetBSD__)
- int claimed = 0;
-#endif
+
+ if (sc->suspended)
+ return;
while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
-#if defined(__NetBSD__)
- claimed = 1;
-#endif
/*
* First ACK all the interrupts in this pass.
*/
@@ -1206,9 +1055,6 @@
}
}
}
-#if defined(__NetBSD__)
- return (claimed);
-#endif
}
/*
@@ -1334,6 +1180,9 @@
struct fxp_cb_tx *txp;
int i;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+
/*
* Cancel stats updater.
*/
@@ -1376,9 +1225,6 @@
panic("fxp_stop: no buffers!");
}
}
-
- ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
- ifp->if_timer = 0;
}
/*
@@ -1393,7 +1239,7 @@
{
struct fxp_softc *sc = ifp->if_softc;
- printf(FXP_FORMAT ": device timeout\n", FXP_ARGS(sc));
+ printf("fxp%d: device timeout\n", FXP_UNIT(sc));
ifp->if_oerrors++;
fxp_init(sc);
@@ -1492,7 +1338,7 @@
CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
- while (!(cbp->cb_status & FXP_CB_STATUS_C));
+ fxp_dma_wait(&cbp->cb_status, sc);
/*
* Now initialize the station address. Temporarily use the TxCB
@@ -1502,13 +1348,9 @@
cb_ias->cb_status = 0;
cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
cb_ias->link_addr = -1;
-#if defined(__NetBSD__)
- bcopy(LLADDR(ifp->if_sadl), (void *)cb_ias->macaddr, 6);
-#else
bcopy(sc->arpcom.ac_enaddr,
(void *)(uintptr_t)(volatile void *)cb_ias->macaddr,
sizeof(sc->arpcom.ac_enaddr));
-#endif /* __NetBSD__ */
/*
* Start the IAS (Individual Address Setup) command/DMA.
@@ -1516,7 +1358,7 @@
fxp_scb_wait(sc);
CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
/* ...and wait for it to complete. */
- while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
+ fxp_dma_wait(&cb_ias->cb_status, sc);
/*
* Initialize transmit control block (TxCB) list.
@@ -1611,9 +1453,8 @@
case FXP_PHY_80C24:
break;
default:
- printf(FXP_FORMAT
- ": warning: unsupported PHY, type = %d, addr = %d\n",
- FXP_ARGS(sc), sc->phy_primary_device,
+ printf("fxp%d: warning: unsupported PHY, type = %d, addr = %d\n",
+ FXP_UNIT(sc), sc->phy_primary_device,
sc->phy_primary_addr);
}
}
@@ -1814,8 +1655,7 @@
DELAY(10);
if (count <= 0)
- printf(FXP_FORMAT ": fxp_mdi_read: timed out\n",
- FXP_ARGS(sc));
+ printf("fxp%d: fxp_mdi_read: timed out\n", FXP_UNIT(sc));
return (value & 0xffff);
}
@@ -1838,14 +1678,13 @@
DELAY(10);
if (count <= 0)
- printf(FXP_FORMAT ": fxp_mdi_write: timed out\n",
- FXP_ARGS(sc));
+ printf("fxp%d: fxp_mdi_write: timed out\n", FXP_UNIT(sc));
}
static int
fxp_ioctl(ifp, command, data)
struct ifnet *ifp;
- FXP_IOCTLCMD_TYPE command;
+ u_long command;
caddr_t data;
{
struct fxp_softc *sc = ifp->if_softc;
@@ -1857,10 +1696,8 @@
switch (command) {
case SIOCSIFADDR:
-#if !defined(__NetBSD__)
case SIOCGIFADDR:
case SIOCSIFMTU:
-#endif
error = ether_ioctl(ifp, command, data);
break;
@@ -1884,27 +1721,6 @@
case SIOCADDMULTI:
case SIOCDELMULTI:
sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
-#if defined(__NetBSD__)
- error = (command == SIOCADDMULTI) ?
- ether_addmulti(ifr, &sc->sc_ethercom) :
- ether_delmulti(ifr, &sc->sc_ethercom);
-
- if (error == ENETRESET) {
- /*
- * Multicast list has changed; set the hardware
- * filter accordingly.
- */
- if (!sc->all_mcasts)
- fxp_mc_setup(sc);
- /*
- * fxp_mc_setup() can turn on all_mcasts if we run
- * out of space, so check it again rather than else {}.
- */
- if (sc->all_mcasts)
- fxp_init(sc);
- error = 0;
- }
-#else /* __FreeBSD__ */
/*
* Multicast list has changed; set the hardware filter
* accordingly.
@@ -1918,7 +1734,6 @@
if (sc->all_mcasts)
fxp_init(sc);
error = 0;
-#endif /* __NetBSD__ */
break;
case SIOCSIFMEDIA:
@@ -1955,6 +1770,7 @@
struct ifnet *ifp = &sc->sc_if;
struct ifmultiaddr *ifma;
int nmcasts;
+ int count;
/*
* If there are queued commands, we must wait until they are all
@@ -2037,8 +1853,14 @@
* Wait until command unit is not active. This should never
* be the case when nothing is queued, but make sure anyway.
*/
+ count = 100;
while ((CSR_READ_1(sc, FXP_CSR_SCB_RUSCUS) >> 6) ==
- FXP_SCB_CUS_ACTIVE) ;
+ FXP_SCB_CUS_ACTIVE && --count)
+ DELAY(10);
+ if (count == 0) {
+ printf("fxp%d: command queue timeout\n", FXP_UNIT(sc));
+ return;
+ }
/*
* Start the multicast setup command.
|