Index: if_sbni.c =================================================================== RCS file: /usr/cvs/src/sys/dev/sbni/if_sbni.c,v retrieving revision 1.24 diff -u -r1.24 if_sbni.c --- if_sbni.c 5 Jul 2007 07:46:33 -0000 1.24 +++ if_sbni.c 2 Jun 2008 20:45:36 -0000 @@ -62,6 +62,7 @@ #include +#include #include #include #include @@ -89,9 +90,10 @@ #define ASM_CRC 1 static void sbni_init(void *); +static void sbni_init_locked(struct sbni_softc *); static void sbni_start(struct ifnet *); +static void sbni_start_locked(struct ifnet *); static int sbni_ioctl(struct ifnet *, u_long, caddr_t); -static void sbni_watchdog(struct ifnet *); static void sbni_stop(struct sbni_softc *); static void handle_channel(struct sbni_softc *); @@ -125,11 +127,11 @@ static u_int32_t crc32tab[]; #ifdef SBNI_DUAL_COMPOUND -struct sbni_softc *sbni_headlist; +static struct mtx headlist_lock; +MTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF); +static struct sbni_softc *sbni_headlist; #endif -u_int32_t next_sbni_unit; - /* -------------------------------------------------------------------------- */ static __inline u_char @@ -217,7 +219,7 @@ /* * Install interface into kernel networking data structures */ -void +int sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) { struct ifnet *ifp; @@ -225,27 +227,27 @@ ifp = sc->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) - panic("sbni%d: can not if_alloc()", unit); + return (ENOMEM); sbni_outb(sc, CSR0, 0); set_initial_values(sc, flags); - callout_handle_init(&sc->wch); /* Initialize ifnet structure */ ifp->if_softc = sc; if_initname(ifp, "sbni", unit); ifp->if_init = sbni_init; ifp->if_start = sbni_start; ifp->if_ioctl = sbni_ioctl; - ifp->if_watchdog = sbni_watchdog; - ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); /* report real baud rate */ csr0 = sbni_inb(sc, CSR0); ifp->if_baudrate = (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | - IFF_NEEDSGIANT; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + + mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF); + callout_init_mtx(&sc->wch, &sc->lock, 0); ether_ifattach(ifp, sc->enaddr); /* device attach does transition from UNCONFIGURED to IDLE state */ @@ -254,6 +256,34 @@ printf("auto\n"); else printf("%d (fixed)\n", sc->cur_rxl_index); + return (0); +} + +void +sbni_detach(struct sbni_softc *sc) +{ + + SBNI_LOCK(sc); + sbni_stop(sc); + SBNI_UNLOCK(sc); + callout_drain(&sc->wch); + ether_ifdetach(sc->ifp); + if (sc->irq_handle) + bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle); + mtx_destroy(&sc->lock); + if_free(sc->ifp); +} + +void +sbni_release_resources(struct sbni_softc *sc) +{ + + if (sc->irq_res) + bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, + sc->irq_res); + if (sc->io_res && sc->io_off == 0) + bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid, + sc->io_res); } /* -------------------------------------------------------------------------- */ @@ -262,10 +292,18 @@ sbni_init(void *xsc) { struct sbni_softc *sc; - struct ifnet *ifp; - int s; sc = (struct sbni_softc *)xsc; + SBNI_LOCK(sc); + sbni_init_locked(sc); + SBNI_UNLOCK(sc); +} + +static void +sbni_init_locked(struct sbni_softc *sc) +{ + struct ifnet *ifp; + ifp = sc->ifp; /* @@ -275,24 +313,31 @@ if (ifp->if_drv_flags & IFF_DRV_RUNNING) return; - s = splimp(); - ifp->if_timer = 0; card_start(sc); - sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); + callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; /* attempt to start output */ - sbni_start(ifp); - splx(s); + sbni_start_locked(ifp); } - static void sbni_start(struct ifnet *ifp) { struct sbni_softc *sc = ifp->if_softc; + + SBNI_LOCK(sc); + sbni_start_locked(ifp); + SBNI_UNLOCK(sc); +} + +static void +sbni_start_locked(struct ifnet *ifp) +{ + struct sbni_softc *sc = ifp->if_softc; + if (sc->tx_frameno == 0) prepare_to_send(sc); } @@ -309,8 +354,8 @@ sc->rx_buf_p = NULL; } - untimeout(sbni_timeout, sc, sc->wch); - sc->wch.callout = NULL; + callout_stop(&sc->wch); + sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } /* -------------------------------------------------------------------------- */ @@ -340,14 +385,20 @@ do { repeat = 0; + SBNI_LOCK(sc); if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { handle_channel(sc); repeat = 1; } - if (sc->slave_sc && /* second channel present */ - (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { - handle_channel(sc->slave_sc); - repeat = 1; + SBNI_UNLOCK(sc); + if (sc->slave_sc) { + /* second channel present */ + SBNI_LOCK(sc->slave_sc); + if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) { + handle_channel(sc->slave_sc); + repeat = 1; + } + SBNI_UNLOCK(sc->slave_sc); } } while (repeat); } @@ -378,7 +429,7 @@ */ csr0 = sbni_inb(sc, CSR0); if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) - printf("sbni: internal error!\n"); + if_printf(sc->ifp, "internal error!\n"); /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ if (req_ans || sc->tx_frameno != 0) @@ -856,9 +907,11 @@ m = sc->rx_buf_p; m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = sc->inppos; + sc->rx_buf_p = NULL; + SBNI_UNLOCK(sc); (*ifp->if_input)(ifp, m); - sc->rx_buf_p = NULL; + SBNI_LOCK(sc); } /* -------------------------------------------------------------------------- */ @@ -872,11 +925,10 @@ sbni_timeout(void *xsc) { struct sbni_softc *sc; - int s; u_char csr0; sc = (struct sbni_softc *)xsc; - s = splimp(); + SBNI_ASSERT_LOCKED(sc); csr0 = sbni_inb(sc, CSR0); if (csr0 & RC_CHK) { @@ -895,9 +947,8 @@ } } - sbni_outb(sc, CSR0, csr0 | RC_CHK); - sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); - splx(s); + sbni_outb(sc, CSR0, csr0 | RC_CHK); + callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); } /* -------------------------------------------------------------------------- */ @@ -918,19 +969,6 @@ /* -------------------------------------------------------------------------- */ -/* - * Device timeout/watchdog routine. Entered if the device neglects to - * generate an interrupt after a transmit has been started on it. - */ - -static void -sbni_watchdog(struct ifnet *ifp) -{ - log(LOG_ERR, "%s: device timeout\n", ifp->if_xname); - ifp->if_oerrors++; -} - - static u_char rxl_tab[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f @@ -971,12 +1009,22 @@ #ifdef SBNI_DUAL_COMPOUND +void +sbni_add(struct sbni_softc *sc) +{ + + mtx_lock(&headlist_lock); + sc->link = sbni_headlist; + sbni_headlist = sc; + mtx_unlock(&headlist_lock); +} struct sbni_softc * connect_to_master(struct sbni_softc *sc) { struct sbni_softc *p, *p_prev; + mtx_lock(&headlist_lock); for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { @@ -985,9 +1033,11 @@ p_prev->link = p->link; else sbni_headlist = p->link; + mtx_unlock(&headlist_lock); return p; } } + mtx_unlock(&headlist_lock); return (NULL); } @@ -1049,30 +1099,29 @@ struct thread *td; struct sbni_in_stats *in_stats; struct sbni_flags flags; - int error, s; + int error; sc = ifp->if_softc; ifr = (struct ifreq *)data; td = curthread; error = 0; - s = splimp(); - switch (command) { case SIOCSIFFLAGS: /* * If the interface is marked up and stopped, then start it. * If it is marked down and running, then stop it. */ + SBNI_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - sbni_init(sc); + sbni_init_locked(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { sbni_stop(sc); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } } + SBNI_UNLOCK(sc); break; case SIOCADDMULTI: @@ -1086,29 +1135,29 @@ error = EAFNOSUPPORT; */ break; - case SIOCSIFMTU: - if (ifr->ifr_mtu > ETHERMTU) - error = EINVAL; - else - ifp->if_mtu = ifr->ifr_mtu; - break; - /* * SBNI specific ioctl */ case SIOCGHWFLAGS: /* get flags */ + SBNI_LOCK(sc); bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3); flags.rxl = sc->cur_rxl_index; flags.rate = sc->csr1.rate; flags.fixed_rxl = (sc->delta_rxl == 0); flags.fixed_rate = 1; + SBNI_UNLOCK(sc); ifr->ifr_data = *(caddr_t*) &flags; break; case SIOCGINSTATS: - in_stats = (struct sbni_in_stats *)ifr->ifr_data; - bcopy((void *)(&(sc->in_stats)), (void *)in_stats, - sizeof(struct sbni_in_stats)); + in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF, + M_WAITOK); + SBNI_LOCK(sc); + bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats)); + SBNI_UNLOCK(sc); + error = copyout(ifr->ifr_data, in_stats, + sizeof(struct sbni_in_stats)); + free(in_stats, M_DEVBUF); break; case SIOCSHWFLAGS: /* set flags */ @@ -1117,6 +1166,7 @@ if (error) break; flags = *(struct sbni_flags*)&ifr->ifr_data; + SBNI_LOCK(sc); if (flags.fixed_rxl) { sc->delta_rxl = 0; sc->cur_rxl_index = flags.rxl; @@ -1132,11 +1182,14 @@ /* Don't be afraid... */ sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); + SBNI_UNLOCK(sc); break; case SIOCRINSTATS: + SBNI_LOCK(sc); if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */ bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); + SBNI_UNLOCK(sc); break; default: @@ -1144,7 +1197,6 @@ break; } - splx(s); return (error); } Index: if_sbni_isa.c =================================================================== RCS file: /usr/cvs/src/sys/dev/sbni/if_sbni_isa.c,v retrieving revision 1.15 diff -u -r1.15 if_sbni_isa.c --- if_sbni_isa.c 23 Feb 2007 12:18:53 -0000 1.15 +++ if_sbni_isa.c 29 May 2008 22:00:39 -0000 @@ -85,7 +85,6 @@ return (error); sc = device_get_softc(dev); - bzero(sc, sizeof(struct sbni_softc)); sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->io_rid, 0ul, ~0ul, SBNI_PORTS, RF_ACTIVE); @@ -95,12 +94,11 @@ } if (sbni_probe(sc) != 0) { - bus_release_resource(dev, SYS_RES_IOPORT, - sc->io_rid, sc->io_res); + sbni_release_resources(sc); return (ENXIO); } - device_quiet(dev); + device_set_desc(dev, "Granch SBNI12/ISA adapter"); return (0); } @@ -113,50 +111,32 @@ int error; sc = device_get_softc(dev); + sc->dev = dev; - printf("sbni%d: port 0x%lx", - next_sbni_unit, rman_get_start(sc->io_res)); sc->irq_res = bus_alloc_resource_any( dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); - if (sc->irq_res) { - printf(" irq %ld\n", rman_get_start(sc->irq_res)); - error = bus_setup_intr( - dev, sc->irq_res, INTR_TYPE_NET, - NULL, sbni_intr, sc, &sc->irq_handle); - if (error) { - printf("sbni%d: bus_setup_intr\n", next_sbni_unit); - bus_release_resource( - dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res); - bus_release_resource( - dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); - return (error); - } - #ifndef SBNI_DUAL_COMPOUND - } else { - printf("\nsbni%d: irq conflict!\n", next_sbni_unit); - bus_release_resource(dev, SYS_RES_IOPORT, - sc->io_rid, sc->io_res); + if (sc->irq_res == NULL) { + device_printf(dev, "irq conflict!\n"); + sbni_release_resources(sc); return (ENOENT); } #else /* SBNI_DUAL_COMPOUND */ - sc->link = sbni_headlist; - sbni_headlist = sc; + if (sc->irq_res) { + sbni_add(sc); } else { struct sbni_softc *master; if ((master = connect_to_master(sc)) == 0) { - printf("\nsbni%d: failed to alloc irq\n", - next_sbni_unit); - bus_release_resource( - dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res); + device_printf(dev, "failed to alloc irq\n"); + sbni_release_resources(sc); return (ENXIO); } else { - printf(" shared irq with %s\n", + device_printf(dev, "shared irq with %s\n", master->ifp->if_xname); } } @@ -164,6 +144,24 @@ *(u_int32_t*)&flags = device_get_flags(dev); - sbni_attach(sc, next_sbni_unit++, flags); + error = sbni_attach(sc, device_get_unit(dev) * 2, flags); + if (error) { + device_printf(dev, "cannot initialize driver\n"); + sbni_release_resources(sc); + return (error); + } + + if (sc->irq_res) { + error = bus_setup_intr( + dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, sbni_intr, sc, &sc->irq_handle); + if (error) { + device_printf(dev, "bus_setup_intr\n"); + sbni_detach(sc); + sbni_release_resources(sc); + return (error); + } + } + return (0); } Index: if_sbni_pci.c =================================================================== RCS file: /usr/cvs/src/sys/dev/sbni/if_sbni_pci.c,v retrieving revision 1.12 diff -u -r1.12 if_sbni_pci.c --- if_sbni_pci.c 23 Feb 2007 12:18:53 -0000 1.12 +++ if_sbni_pci.c 29 May 2008 22:01:26 -0000 @@ -51,11 +51,13 @@ static int sbni_pci_probe(device_t); static int sbni_pci_attach(device_t); +static int sbni_pci_detach(device_t); static device_method_t sbni_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sbni_pci_probe), DEVMETHOD(device_attach, sbni_pci_attach), + DEVMETHOD(device_detach, sbni_pci_detach), { 0, 0 } }; @@ -75,14 +77,13 @@ { struct sbni_softc *sc; u_int32_t ports; - + ports = SBNI_PORTS; if (pci_get_vendor(dev) != SBNI_PCI_VENDOR || pci_get_device(dev) != SBNI_PCI_DEVICE) return (ENXIO); sc = device_get_softc(dev); - bzero(sc, sizeof(struct sbni_softc)); if (pci_get_subdevice(dev) == 2) { ports <<= 1; sc->slave_sc = malloc(sizeof(struct sbni_softc), @@ -97,7 +98,7 @@ sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->io_rid, 0ul, ~0ul, ports, RF_ACTIVE); if (!sc->io_res) { - printf("sbni: cannot allocate io ports!\n"); + device_printf(dev, "cannot allocate io ports!\n"); if (sc->slave_sc) free(sc->slave_sc, M_DEVBUF); return (ENOENT); @@ -108,14 +109,12 @@ sc->slave_sc->io_off = 4; } if (sbni_probe(sc) != 0) { - bus_release_resource(dev, SYS_RES_IOPORT, - sc->io_rid, sc->io_res); + sbni_release_resources(sc); if (sc->slave_sc) free(sc->slave_sc, M_DEVBUF); return (ENXIO); } - device_quiet(dev); return (0); } @@ -127,41 +126,66 @@ int error; sc = device_get_softc(dev); + sc->dev = dev; - printf("sbni%d: port 0x%lx", - next_sbni_unit, sc->slave_sc ? " Dual " : " ", - rman_get_start(sc->io_res)); sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_SHAREABLE); - if (sc->irq_res) { - printf(" irq %ld\n", rman_get_start(sc->irq_res)); - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, - NULL, sbni_intr, sc, &sc->irq_handle); - if (error) { - printf("sbni%d: bus_setup_intr\n", next_sbni_unit); - goto attach_failed; - } - } else { - printf("\nsbni%d: cannot claim irq!\n", next_sbni_unit); + if (sc->irq_res == NULL) { + device_printf(dev, "cannot claim irq!\n"); error = ENOENT; goto attach_failed; } *(u_int32_t*)&flags = 0; - sbni_attach(sc, next_sbni_unit++, flags); - if (sc->slave_sc) - sbni_attach(sc->slave_sc, next_sbni_unit++, flags); - return (0); + error = sbni_attach(sc, device_get_unit(dev) * 2, flags); + if (error) { + device_printf(dev, "cannot initialize driver\n"); + goto attach_failed; + } + if (sc->slave_sc) { + error = sbni_attach(sc->slave_sc, device_get_unit(dev) * 2 + 1, + flags); + if (error) { + device_printf(dev, "cannot initialize slave\n"); + sbni_detach(sc); + goto attach_failed; + } + } -attach_failed: - bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res); if (sc->irq_res) { - bus_release_resource( - dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | + INTR_MPSAFE, NULL, sbni_intr, sc, &sc->irq_handle); + if (error) { + device_printf(dev, "bus_setup_intr\n"); + sbni_detach(sc); + if (sc->slave_sc) + sbni_detach(sc); + goto attach_failed; + } } + return (0); + +attach_failed: + sbni_release_resources(sc); if (sc->slave_sc) free(sc->slave_sc, M_DEVBUF); return (error); } + +static int +sbni_pci_detach(device_t dev) +{ + struct sbni_softc *sc; + + sc = device_get_softc(dev); + sbni_detach(sc); + if (sc->slave_sc) + sbni_detach(sc); + + sbni_release_resources(sc); + if (sc->slave_sc) + free(sc->slave_sc, M_DEVBUF); + return (0); +} Index: if_sbnivar.h =================================================================== RCS file: /usr/cvs/src/sys/dev/sbni/if_sbnivar.h,v retrieving revision 1.5 diff -u -r1.5 if_sbnivar.h --- if_sbnivar.h 10 Jun 2005 16:49:14 -0000 1.5 +++ if_sbnivar.h 29 May 2008 21:58:24 -0000 @@ -68,6 +68,7 @@ struct sbni_softc { struct ifnet *ifp; + device_t dev; u_char enaddr[6]; int io_rid; @@ -111,7 +112,8 @@ struct sbni_csr1 csr1; /* current value of CSR1 */ struct sbni_in_stats in_stats; /* internal statistics */ - struct callout_handle wch; + struct callout wch; + struct mtx lock; struct sbni_softc *slave_sc; @@ -120,15 +122,20 @@ #endif }; +#define SBNI_LOCK(sc) mtx_lock(&(sc)->lock) +#define SBNI_UNLOCK(sc) mtx_unlock(&(sc)->lock) +#define SBNI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->lock, MA_OWNED) + void sbni_intr(void *); int sbni_probe(struct sbni_softc *); -void sbni_attach(struct sbni_softc *, int, struct sbni_flags); +int sbni_attach(struct sbni_softc *, int, struct sbni_flags); +void sbni_detach(struct sbni_softc *); +void sbni_release_resources(struct sbni_softc *); extern u_int32_t next_sbni_unit; #ifdef SBNI_DUAL_COMPOUND -extern struct sbni_softc *sbni_headlist; - +void sbni_add(struct sbni_softc *); struct sbni_softc *connect_to_master(struct sbni_softc *); #endif #endif /* _KERNEL */