network code: Convert if_multiaddrs from LIST to TAILQ.
[dragonfly.git] / sys / dev / netif / sln / if_sln.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * 3. Neither the name of The DragonFly Project nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific, prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD-4.7: /usr/src/sys/pci/silan.c,v 1.0 2003/01/10 gaoyonghong $
32 * $DragonFly: src/sys/dev/netif/sln/if_sln.c,v 1.3 2008/06/29 20:45:44 swildner Exp $
33 */
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/endian.h>
38#include <sys/kernel.h>
39#include <sys/interrupt.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/resource.h>
43#include <sys/rman.h>
44#include <sys/socket.h>
45#include <sys/sockio.h>
46#include <sys/systm.h>
47
48#include <bus/pci/pcidevs.h>
49#include <bus/pci/pcireg.h>
50#include <bus/pci/pcivar.h>
51
52#include <machine/clock.h>
53
54#include <net/bpf.h>
55#include <net/ethernet.h>
56#include <net/ifq_var.h>
57#include <net/if.h>
58#include <net/if_arp.h>
59#include <net/if_dl.h>
60#include <net/if_media.h>
61#include <net/if_var.h>
62
63#include <vm/pmap.h>
64#include <vm/vm.h>
65
66#include "if_slnreg.h"
67#include "if_slnvar.h"
68
69/* Default to using PIO access for netcard driver */
70#define SL_USEIOSPACE
71
72#ifdef SLN_DEBUG
73#define PDEBUG(fmt, args...) kprintf("%s: " fmt "\n" , __func__ , ## args)
74#else
75#define PDEBUG(fmt, args...)
76#endif
77
78static const struct sln_dev {
79 uint16_t vid;
80 uint16_t did;
81 const char *desc;
82} sln_devs[] = {
83 {PCI_VENDOR_SILAN, PCI_PRODUCT_SILAN_SC92031,
84 "Silan SC92031 Fast Ethernet" },
85 {PCI_VENDOR_SILAN, PCI_PRODUCT_SILAN_8139D,
86 "Silan Rsltek 8139D Fast Ethernet" },
87 {0, 0, NULL}
88};
89
90static int sln_probe(device_t);
91static int sln_attach(device_t);
92static int sln_detach(device_t);
93static int sln_shutdown(device_t);
94static int sln_suspend(device_t);
95static int sln_resume(device_t);
96
97static void sln_reset(struct sln_softc *);
98static void sln_init(void *);
99
100static void sln_tx(struct ifnet *);
101static void sln_rx(struct sln_softc *);
102static void sln_tx_intr(struct sln_softc *);
103static void sln_media_intr(struct sln_softc *);
104static void sln_interrupt(void *);
105static int sln_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
106static void sln_stop(struct sln_softc *);
107static void sln_watchdog(struct ifnet *);
108
109static int sln_media_upd(struct ifnet *);
110
111static void sln_media_stat(struct ifnet *, struct ifmediareq *);
112static void sln_mii_cmd(struct sln_softc *, uint32_t, u_long *);
113static void sln_media_cfg(struct sln_softc *);
114static void sln_mac_cfg(struct sln_softc *);
115static uint32_t sln_ether_crc32(caddr_t);
116static void sln_set_multi(struct sln_softc *);
117static void sln_init_tx(struct sln_softc *);
118static void sln_tick(void *);
119
120#ifdef SL_USEIOSPACE
121#define SL_RID SL_PCI_IOAD
122#define SL_RES SYS_RES_IOPORT
123#else
124#define SL_RID SL_PCI_MEMAD
125#define SL_RES SYS_RES_MEMORY
126#endif
127
128static device_method_t sln_methods[] = {
129 DEVMETHOD(device_probe, sln_probe),
130 DEVMETHOD(device_attach, sln_attach),
131 DEVMETHOD(device_detach, sln_detach),
132 DEVMETHOD(device_shutdown, sln_shutdown),
133 DEVMETHOD(device_suspend, sln_suspend),
134 DEVMETHOD(device_resume, sln_resume),
135
136 DEVMETHOD(bus_print_child, bus_generic_print_child),
137 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
138
139 {0, 0}
140};
141
142static driver_t sln_driver = {
143 "sln",
144 sln_methods,
145 sizeof(struct sln_softc)
146};
147
148static devclass_t sln_devclass;
149
150DRIVER_MODULE(sln, pci, sln_driver, sln_devclass, 0, 0);
151
152static int
153sln_probe(struct device *dev)
154{
155 const struct sln_dev *d;
156 uint16_t did, vid;
157
158 vid = pci_get_vendor(dev);
159 did = pci_get_device(dev);
160
161 for (d = sln_devs; d->desc != NULL; d++) {
162 if (vid == d->vid && did == d->did) {
163 device_set_desc(dev, d->desc);
164 return 0;
165 }
166 }
167 return ENXIO;
168}
169
170/* the chip reset */
171static void
172sln_reset(struct sln_softc *sc)
173{
174 SLN_WRITE_4(sc, SL_CFG0, SL_SOFT_RESET);
175 DELAY(200000);
176 SLN_WRITE_4(sc, SL_CFG0, 0x0);
177 DELAY(10000);
178}
179
180/* Attach the interface. Allocate softc structures */
181static int
182sln_attach(device_t dev)
183{
184 struct sln_softc *sc = device_get_softc(dev);
185 struct ifnet *ifp = &sc->arpcom.ac_if;
186 unsigned char eaddr[ETHER_ADDR_LEN];
187 int rid;
188 int error = 0;
189
190 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
191
192 /* TODO: power state change */
193
194 pci_enable_busmaster(dev);
195
196 rid = SL_RID;
197 sc->sln_res = bus_alloc_resource_any(dev, SL_RES, &rid, RF_ACTIVE);
198 if (sc->sln_res == NULL) {
199 device_printf(dev, "couldn't map ports/memory\n");
200 error = ENXIO;
201 goto fail;
202 }
203 sc->sln_bustag = rman_get_bustag(sc->sln_res);
204 sc->sln_bushandle = rman_get_bushandle(sc->sln_res);
205
206 /* alloc pci irq */
207 rid = 0;
208 sc->sln_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
209 RF_SHAREABLE | RF_ACTIVE);
210 if (sc->sln_irq == NULL) {
211 device_printf(dev, "couldn't map interrupt\n");
212 bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
213 error = ENXIO;
214 goto fail;
215 }
216
217 /* Get MAC address */
218 ((uint32_t *)(&eaddr))[0] = be32toh(SLN_READ_4(sc, SL_MAC_ADDR0));
219 ((uint16_t *)(&eaddr))[2] = be16toh(SLN_READ_4(sc, SL_MAC_ADDR1));
220
221 /* alloc rx buffer space */
222 sc->sln_bufdata.sln_rx_buf = contigmalloc(SL_RX_BUFLEN,
223 M_DEVBUF, M_WAITOK, 0, 0xffffffff, PAGE_SIZE, 0);
224 if (sc->sln_bufdata.sln_rx_buf == NULL) {
225 device_printf(dev, "no memory for rx buffers!\n");
226 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sln_irq);
227 bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
228 error = ENXIO;
229 goto fail;
230 }
231 callout_init(&sc->sln_state);
232
233 ifp->if_softc = sc;
234 ifp->if_mtu = ETHERMTU;
235 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
236 ifp->if_init = sln_init;
237 ifp->if_start = sln_tx;
238 ifp->if_ioctl = sln_ioctl;
239 ifp->if_watchdog = sln_watchdog;
240 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
241 ifq_set_ready(&ifp->if_snd);
242
243 /* initial media */
244 ifmedia_init(&sc->ifmedia, 0, sln_media_upd, sln_media_stat);
245
246 /* supported media types */
247 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
248 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
249 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_HDX, 0, NULL);
250 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
251 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
252 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_HDX, 0, NULL);
253 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
254
255 /* Choose a default media. */
256 ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_AUTO);
257
258 ether_ifattach(ifp, eaddr, NULL);
259
260 error = bus_setup_intr(dev, sc->sln_irq, INTR_MPSAFE, sln_interrupt, sc,
261 &sc->sln_intrhand, ifp->if_serializer);
262 if (error) {
263 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sln_irq);
264 bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
265 ether_ifdetach(ifp);
266 device_printf(dev, "couldn't set up irq\n");
267 goto fail;
268 }
269
270 ifp->if_cpuid = ithread_cpuid(rman_get_start(sc->sln_irq));
271 KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus);
272
273 return 0;
274fail:
275 return error;
276}
277
278/* Stop the adapter and free any mbufs allocated to the RX and TX buffers */
279static void
280sln_stop(struct sln_softc *sc)
281{
282 struct ifnet *ifp = &sc->arpcom.ac_if;
283 uint32_t intr_status;
284 int i;
285
286 ASSERT_SERIALIZED(ifp->if_serializer);
287
288 ifp->if_timer = 0;
289 callout_stop(&sc->sln_state);
290
291 /* disable Tx/Rx */
292 sc->txcfg &= ~SL_TXCFG_EN;
293 sc->rxcfg &= ~SL_RXCFG_EN;
294 SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
295 SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
296
297 /* Clear interrupt */
298 SLN_WRITE_4(sc, SL_INT_MASK, 0);
299 intr_status = SLN_READ_4(sc, SL_INT_STATUS);
300
301 /* Free the TX list buffers */
302 for (i = 0; i < SL_TXD_CNT; i++) {
303 if (sc->sln_bufdata.sln_tx_buf[i] != NULL) {
304 m_freem(sc->sln_bufdata.sln_tx_buf[i]);
305 sc->sln_bufdata.sln_tx_buf[i] = NULL;
306 SLN_WRITE_4(sc, SL_TSAD0 + i * 4, 0);
307 }
308 }
309
310 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
311}
312
313static int
314sln_detach(device_t dev)
315{
316 struct sln_softc *sc = device_get_softc(dev);
317 struct ifnet *ifp = &sc->arpcom.ac_if;
318
319 lwkt_serialize_enter(ifp->if_serializer);
320 sln_stop(sc);
321 bus_teardown_intr(dev, sc->sln_irq, sc->sln_intrhand);
322 lwkt_serialize_exit(ifp->if_serializer);
323
324 ether_ifdetach(ifp);
325
326 bus_generic_detach(dev);
327
328 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sln_irq);
329 bus_release_resource(dev, SL_RES, SL_RID, sc->sln_res);
330
331 contigfree(sc->sln_bufdata.sln_rx_buf, SL_RX_BUFLEN, M_DEVBUF);
332
333 return 0;
334}
335
336static int
337sln_media_upd(struct ifnet *ifp)
338{
339 struct sln_softc *sc = ifp->if_softc;
340 struct ifmedia *ifm = &sc->ifmedia;
341
342 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
343 return EINVAL;
344
345 if (ifp->if_flags & IFF_UP)
346 sln_init(sc);
347
348 return 0;
349}
350
351static void
352sln_media_stat(struct ifnet *ifp, struct ifmediareq *ifmr)
353{
354 struct sln_softc *sc = ifp->if_softc;
355 u_long phys[2];
356 uint32_t temp;
357
358 ifmr->ifm_status = IFM_AVALID;
359 ifmr->ifm_active = IFM_ETHER;
360
361 phys[0] = SL_MII_STAT;
362 sln_mii_cmd(sc, SL_MII0_READ, phys);
363
364 if (phys[1] & SL_MIISTAT_LINK)
365 ifmr->ifm_status |= IFM_ACTIVE;
366
367 temp = SLN_READ_4(sc, SL_PHY_CTRL);
368
369 if ((temp & (SL_PHYCTL_DUX | SL_PHYCTL_SPD100 | SL_PHYCTL_SPD10)) == 0x60800000)
370 ifmr->ifm_active |= IFM_AUTO;
371 else if ((temp & (SL_PHYCTL_DUX | SL_PHYCTL_SPD100)) == 0x40800000)
372 ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
373 else if ((temp & SL_PHYCTL_SPD100) == 0x40000000)
374 ifmr->ifm_active |= IFM_100_TX | IFM_HDX;
375 else if ((temp & (SL_PHYCTL_DUX | SL_PHYCTL_SPD10)) == 0x20800000)
376 ifmr->ifm_active |= IFM_10_T | IFM_FDX;
377 else if ((temp & SL_PHYCTL_SPD10) == 0x20000000)
378 ifmr->ifm_active |= IFM_10_T | IFM_HDX;
379
380 sln_mii_cmd(sc, SL_MII0_SCAN, phys);
381}
382
383/* command selected in MII command register */
384static void
385sln_mii_cmd(struct sln_softc *sc, uint32_t cmd, u_long *phys)
386{
387 uint32_t mii_status;
388
389 SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER);
390
391 do {
392 mii_status = 0;
393 DELAY(10);
394 mii_status = SLN_READ_4(sc, SL_MII_STATUS);
395 } while (mii_status & SL_MIISTAT_BUSY);
396
397 switch (cmd) {
398 case SL_MII0_SCAN:
399 SLN_WRITE_4(sc, SL_MII_CMD1, 0x1 << 6);
400 SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER | SL_MII0_SCAN);
401 break;
402
403 case SL_MII0_READ:
404 SLN_WRITE_4(sc, SL_MII_CMD1, phys[0] << 6);
405 SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER | SL_MII0_READ);
406 break;
407
408 default: /* WRITE */
409 SLN_WRITE_4(sc, SL_MII_CMD1, phys[0] << 6 | phys[1] << 11);
410 SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER | SL_MII0_WRITE);
411 break;
412 }
413
414 do {
415 DELAY(10);
416 mii_status = SLN_READ_4(sc, SL_MII_STATUS);
417 } while (mii_status & SL_MIISTAT_BUSY);
418
419 if (SL_MII0_READ == cmd)
420 phys[1] = (mii_status >> 13) & 0xffff;
421}
422
423/* Set media speed and duplex mode */
424static void
425sln_media_cfg(struct sln_softc *sc)
426{
427 u_long phys[2];
428 uint32_t mediatype;
429 uint32_t temp;
430
431 mediatype = (&sc->ifmedia)->ifm_cur->ifm_media;
432
433 temp = SLN_READ_4(sc, SL_PHY_CTRL);
434 temp &= ~(SL_PHYCTL_DUX | SL_PHYCTL_SPD100 | SL_PHYCTL_SPD10);
435 temp |= (SL_PHYCTL_ANE | SL_PHYCTL_RESET);
436
437 /************************************************/
438 /* currently set media word by selected media */
439 /* */
440 /* IFM_ETHER = 0x00000020 */
441 /* IFM_AUTO=0, IFM_10_T=3, IFM_100_TX=6 */
442 /* IFM_FDX=0x00100000 IFM_HDX=0x00200000 */
443 /************************************************/
444 switch (mediatype) {
445 case 0x00000020:
446 PDEBUG(" autoselet supported\n");
447 temp |= (SL_PHYCTL_DUX | SL_PHYCTL_SPD100 | SL_PHYCTL_SPD10);
448 sc->ifmedia.ifm_media = IFM_ETHER | IFM_AUTO;
449 ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_AUTO);
450 break;
451 case 0x23:
452 case 0x00200023:
453 PDEBUG(" 10Mbps half_duplex supported\n");
454 temp |= SL_PHYCTL_SPD10;
455 sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX;
456 ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_HDX);
457 break;
458
459 case 0x00100023:
460 PDEBUG("10Mbps full_duplex supported\n");
461 temp |= (SL_PHYCTL_SPD10 | SL_PHYCTL_DUX);
462 sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX;
463 ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX);
464 break;
465
466 case 0x26:
467 case 0x00200026:
468 PDEBUG("100Mbps half_duplex supported\n");
469 temp |= SL_PHYCTL_SPD100;
470 sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX;
471 ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_HDX);
472 break;
473
474 case 0x00100026:
475 PDEBUG("100Mbps full_duplex supported\n");
476 temp |= (SL_PHYCTL_SPD100 | SL_PHYCTL_DUX);
477 sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX;
478 ifmedia_set(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX);
479 break;
480
481 default:
482 break;
483 }
484
485 SLN_WRITE_4(sc, SL_PHY_CTRL, temp);
486
487 DELAY(10000);
488 temp &= ~SL_PHYCTL_RESET;
489 SLN_WRITE_4(sc, SL_PHY_CTRL, temp);
490
491 DELAY(1000);
492 phys[0] = SL_MII_JAB;
493 phys[1] = SL_PHY_16_JAB_ENB | SL_PHY_16_PORT_ENB;
494 sln_mii_cmd(sc, SL_MII0_WRITE, phys);
495
496 sc->connect = 0;
497 sln_mii_cmd(sc, SL_MII0_SCAN, phys);
498}
499
500static void
501sln_mac_cfg(struct sln_softc *sc)
502{
503 struct ifnet *ifp = &sc->arpcom.ac_if;
504 u_long flowcfg = 0;
505
506 /* Set the initial TX/RX/Flow Control configuration */
507 sc->rxcfg = SL_RXCFG_LOW_THRESHOLD | SL_RXCFG_HIGH_THRESHOLD;
508 sc->txcfg = TX_CFG_DEFAULT;
509
510 if (sc->txenablepad)
511 sc->txcfg |= 0x20000000;
512
513 if (sc->media_speed == IFM_10_T)
514 sc->txcfg |= SL_TXCFG_DATARATE;
515
516 if (sc->media_duplex == IFM_FDX) {
517 sc->rxcfg |= SL_RXCFG_FULLDX;
518 sc->txcfg |= SL_TXCFG_FULLDX;
519 flowcfg = SL_FLOWCTL_FULLDX | SL_FLOWCTL_EN;
520 } else {
521 sc->rxcfg &= ~SL_RXCFG_FULLDX;
522 sc->txcfg &= ~SL_TXCFG_FULLDX;
523 }
524
525 /* if promiscuous mode, set the allframes bit. */
526 if (ifp->if_flags & IFF_PROMISC)
527 sc->rxcfg |= (SL_RXCFG_EN | SL_RXCFG_RCV_SMALL | SL_RXCFG_RCV_HUGE | SL_RXCFG_RCV_ERR | SL_RXCFG_RCV_BROAD | SL_RXCFG_RCV_MULTI | SL_RXCFG_RCV_ALL);
528 else
529 sc->rxcfg &= ~(SL_RXCFG_EN | SL_RXCFG_RCV_SMALL | SL_RXCFG_RCV_HUGE | SL_RXCFG_RCV_ERR | SL_RXCFG_RCV_BROAD | SL_RXCFG_RCV_MULTI | SL_RXCFG_RCV_ALL);
530
531 /* Set capture broadcast bit to capture broadcast frames */
532 if (ifp->if_flags & IFF_BROADCAST)
533 sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_BROAD;
534 else
535 sc->rxcfg &= ~(SL_RXCFG_EN | SL_RXCFG_RCV_BROAD);
536
537 /* Program the multicast filter, if necessary */
538 sln_set_multi(sc);
539
540 SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
541 SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
542 SLN_WRITE_4(sc, SL_FLOW_CTRL, flowcfg);
543}
544
545static u_char shade_map[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
546 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
547
548/* Calculate CRC32 of a multicast group address */
549static uint32_t
550sln_ether_crc32(caddr_t addr)
551{
552 uint32_t crc, crcr;
553 int i, j;
554 unsigned char data = 0;
555 /* Compute CRC for the address value. */
556
557 crc = 0xFFFFFFFF; /* initial value */
558
559 for (i = ETHER_ADDR_LEN; i > 0; i--) {
560 data = *addr++;
561
562 for (j = 0; j < 8; j++) {
563 if (((data & 0x1) ^ (crc & 0x1)) != 0) {
564 crc >>= 1;
565 crc ^= 0xEDB88320;
566 } else {
567 crc >>= 1;
568 }
569 data >>= 1;
570 }
571 }
572
573 crcr = shade_map[crc >> 28];
574 crcr |= (shade_map[(crc >> 24) & 0xf] << 4);
575 crcr |= (shade_map[(crc >> 20) & 0xf] << 8);
576 crcr |= (shade_map[(crc >> 16) & 0xf] << 12);
577 crcr |= (shade_map[(crc >> 12) & 0xf] << 16);
578 crcr |= (shade_map[(crc >> 8) & 0xf] << 20);
579 crcr |= (shade_map[(crc >> 4) & 0xf] << 24);
580 crcr |= (shade_map[crc & 0xf] << 28);
581
582 return crcr;
583}
584
585/* Program the 64-bit multicast hash filter */
586static void
587sln_set_multi(struct sln_softc *sc)
588{
589 struct ifnet *ifp = &sc->arpcom.ac_if;
590 uint32_t crc = 0;
591 uint32_t mc_g[2] = {0, 0};
592 struct ifmultiaddr *ifma;
593 int j;
594
595 if (ifp->if_flags & IFF_PROMISC) {
596 kprintf("Promisc mode is enabled\n");
597 sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_MULTI;
598 mc_g[0] = mc_g[1] = 0xFFFFFFFF;
599 } else if (ifp->if_flags & IFF_ALLMULTI) {
600 kprintf("Allmulti mode is enabled\n");
601 sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_MULTI;
602 mc_g[0] = mc_g[1] = 0xFFFFFFFF;
603 } else if (ifp->if_flags & IFF_MULTICAST) {
604 kprintf("Multicast mode is enabled\n");
605 sc->rxcfg |= SL_RXCFG_EN | SL_RXCFG_RCV_MULTI;
606
607 /* first, zero all the existing hash bits */
608 mc_g[0] = mc_g[1] = 0;
609
610 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
611 j = 0;
612
613 if ((ifma->ifma_addr->sa_family) != AF_LINK)
614 continue;
615
616 crc = ~sln_ether_crc32(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
617 crc >>= 24;
618
619 if (crc & 0x1)
620 j |= 0x2;
621 if (crc & 0x2)
622 j |= 0x1;
623 if (crc & 0x10)
624 j |= 0x20;
625 if (crc & 0x20)
626 j |= 0x10;
627 if (crc & 0x40)
628 j |= 0x8;
629 if (crc & 0x80)
630 j |= 0x4;
631
632 if (j > 31)
633 mc_g[0] |= (0x1 << (j - 32));
634 else
635 mc_g[1] |= (0x1 << j);
636 }
637 } else {
638 sc->rxcfg &= ~(SL_RXCFG_EN | SL_RXCFG_RCV_MULTI);
639 }
640
641 SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
642 SLN_WRITE_4(sc, SL_MULTI_GROUP0, mc_g[0]);
643 SLN_WRITE_4(sc, SL_MULTI_GROUP1, mc_g[1]);
644}
645
646/* Initialize the TX/Rx descriptors */
647static void
648sln_init_tx(struct sln_softc *sc)
649{
650 int i;
651
652 sc->sln_bufdata.cur_tx = 0;
653 sc->sln_bufdata.dirty_tx = 0;
654
655 for (i = 0; i < SL_TXD_CNT; i++) {
656 sc->sln_bufdata.sln_tx_buf[i] = NULL;
657 SLN_WRITE_4(sc, SL_TSAD0 + (i * 4), 0);
658 }
659}
660
661/* Software & Hardware Initialize */
662static void
663sln_init(void *x)
664{
665 struct sln_softc *sc = x;
666 struct ifnet *ifp = &sc->arpcom.ac_if;
667
668 PDEBUG("sln_init\n");
669
670 ASSERT_SERIALIZED(ifp->if_serializer);
671
672 sln_stop(sc);
673
674 /* soft reset the chip */
675 sln_reset(sc);
676
677 /* disable interrupt */
678 SLN_WRITE_4(sc, SL_INT_MASK, 0);
679
680 /* SLN_WRITE_4(sc, SL_MII_CMD0, SL_MII0_DIVEDER); */
681
682 /* clear multicast address */
683 SLN_WRITE_4(sc, SL_MULTI_GROUP0, 0);
684 SLN_WRITE_4(sc, SL_MULTI_GROUP1, 0);
685
686 /* Init the RX buffer start address register. */
687 SLN_WRITE_4(sc, SL_RBSA, vtophys(sc->sln_bufdata.sln_rx_buf));
688 sc->sln_bufdata.dirty_rx = vtophys(sc->sln_bufdata.sln_rx_buf);
689
690 /* Init TX descriptors. */
691 sln_init_tx(sc);
692
693 /* configure RX buffer size */
694 if (sc->tx_early_ctrl && sc->rx_early_ctrl)
695 SLN_WRITE_4(sc, SL_CFG1, SL_EARLY_RX | SL_EARLY_TX | SL_RXBUF_64 | SL_RXFIFO_1024BYTES);
696 else if (sc->tx_early_ctrl)
697 SLN_WRITE_4(sc, SL_CFG1, SL_EARLY_TX | SL_RXBUF_64);
698 else if (sc->rx_early_ctrl)
699 SLN_WRITE_4(sc, SL_CFG1, SL_EARLY_RX | SL_RXBUF_64 | SL_RXFIFO_1024BYTES);
700 else
701 SLN_WRITE_4(sc, SL_CFG1, SL_RXBUF_64);
702
703 /* MII media configuration */
704 sln_media_cfg(sc);
705
706 if (sc->connect) {
707 /* Enable transmit and receive */
708 sc->rxcfg |= SL_RXCFG_EN;
709 sc->txcfg |= SL_TXCFG_EN;
710 } else {
711 sc->rxcfg &= ~SL_RXCFG_EN;
712 sc->txcfg &= ~SL_TXCFG_EN;
713 }
714
715 SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
716 SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
717
718 /* Enable interrupts */
719 SLN_WRITE_4(sc, SL_INT_MASK, SL_INRTS);
720
721 sc->suspended = 0;
722
723 ifp->if_flags |= IFF_RUNNING;
724 ifp->if_flags &= ~IFF_OACTIVE;
725
726 callout_reset(&sc->sln_state, hz, sln_tick, sc);
727}
728
729/* Transmit Packet */
730static void
731sln_tx(struct ifnet *ifp)
732{
733 struct sln_softc *sc = ifp->if_softc;
734 struct mbuf *m_head = NULL;
735 struct mbuf *m_new = NULL;
736 int entry;
737
738 ASSERT_SERIALIZED(ifp->if_serializer);
739
740 if (!sc->connect) {
741 ifq_purge(&ifp->if_snd);
742 return;
743 }
744
745 if ((ifp->if_flags & (IFF_OACTIVE | IFF_RUNNING)) != IFF_RUNNING)
746 return;
747
748 while (SL_CUR_TXBUF(sc) == NULL) { /* SL_CUR_TXBUF(x) = x->sln_bufdata.sln_tx_buf[x->sln_bufdata.cur_tx] */
749 entry = sc->sln_bufdata.cur_tx;
750
751 m_head = ifq_dequeue(&ifp->if_snd, NULL);
752 if (m_head == NULL)
753 break;
754
755 MGETHDR(m_new, MB_DONTWAIT, MT_DATA);
756 if (m_new == NULL) {
757 if_printf(ifp, "no memory for tx descriptor");
758 m_freem(m_head);
759 break;
760 }
761 if ((m_head->m_pkthdr.len > MHLEN) || (60 > MHLEN)) {
762 MCLGET(m_new, MB_DONTWAIT);
763 if (!(m_new->m_flags & M_EXT)) {
764 m_freem(m_new);
765 m_freem(m_head);
766 if_printf(ifp, "no memory for tx descriptor");
767 break;
768 }
769 }
770 m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t));
771 m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
772 m_freem(m_head);
773 m_head = m_new;
774 SL_CUR_TXBUF(sc) = m_head;
775
776 /*
777 * if there's a BPF listener, bounce a copy of this frame to
778 * him
779 */
780 BPF_MTAP(ifp, SL_CUR_TXBUF(sc));
781
782 /* Transmit the frame */
783 SLN_WRITE_4(sc, ((entry * 4) + SL_TSAD0),
784 vtophys(mtod(SL_CUR_TXBUF(sc), caddr_t)));
785
786 /* calculate length of the frame */
787 if ((SL_CUR_TXBUF(sc)->m_pkthdr.len < 60) && (!sc->txenablepad)) {
788 memset(mtod(m_head, char *)+m_head->m_pkthdr.len, 0x20, 60 - m_head->m_pkthdr.len);
789 SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, 60);
790 } else if (SL_CUR_TXBUF(sc)->m_pkthdr.len < 100)
791 SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, SL_CUR_TXBUF(sc)->m_pkthdr.len);
792 else if (SL_CUR_TXBUF(sc)->m_pkthdr.len < 300)
793 SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, 0x30000 | SL_CUR_TXBUF(sc)->m_pkthdr.len);
794 else
795 SLN_WRITE_4(sc, (entry * 4) + SL_TSD0, 0x50000 | SL_CUR_TXBUF(sc)->m_pkthdr.len);
796 sc->sln_bufdata.cur_tx = (entry + 1) % SL_TXD_CNT;
797
798 PDEBUG("Queue tx packet size %d to tx-descriptor %d.\n", m_head->m_pkthdr.len, entry);
799 }
800
801 /* Tx buffer chain full */
802 if (SL_CUR_TXBUF(sc) != NULL)
803 ifp->if_flags |= IFF_OACTIVE;
804
805 /* Set a timeout in case the chip goes out to lunch */
806 ifp->if_timer = 5;
807}
808
809/* Receive Data handler */
810static void
811sln_rx(struct sln_softc *sc)
812{
813 struct mbuf *m;
814 struct ifnet *ifp = &sc->arpcom.ac_if;
815 uint32_t rxstat = 0;
816 uint32_t rx_offset;
817 caddr_t rx_bufpos = NULL;
818 uint32_t cur_rx = 0;
819 uint32_t dirty_rx;
820 long rx_len;
821 u_long rx_space;
822 u_long rx_size = 0;
823 u_long rx_size_align = 0;
824 uint32_t rx_bytes = 0;
825 u_long pkt_size = 0;
826
827 cur_rx = SLN_READ_4(sc, SL_RBW_PTR);
828 dirty_rx = sc->sln_bufdata.dirty_rx;
829
830 /*
831 * cur_rx is only 17 bits in the RxBufWPtr register. if cur_rx can be
832 * used in physical space, we need to change it to 32 bits physical
833 * address
834 */
835 cur_rx |= vtophys(sc->sln_bufdata.sln_rx_buf) & (~(u_long) (SL_RX_BUFLEN - 1));
836
837 if (cur_rx < vtophys(sc->sln_bufdata.sln_rx_buf))
838 cur_rx += SL_RX_BUFLEN;
839
840 if (cur_rx >= dirty_rx)
841 rx_len = (long)(cur_rx - dirty_rx);
842 else
843 rx_len = SL_RX_BUFLEN - (long)(dirty_rx - cur_rx);
844
845 if ((rx_len > SL_RX_BUFLEN) || (rx_len < 0)) {
846 if_printf(ifp, "rx len is fail\n");
847 return;
848 }
849 if (rx_len == 0)
850 return;
851
852 rx_offset = (dirty_rx - vtophys(sc->sln_bufdata.sln_rx_buf)) & (u_long) (SL_RX_BUFLEN - 1);
853
854 while (rx_len > 0) {
855 rx_bufpos = sc->sln_bufdata.sln_rx_buf + rx_offset;
856 rxstat = *(uint32_t *) rx_bufpos;
857 rx_size = (rxstat >> 20) & 0x0FFF;
858 rx_size_align = (rx_size + 3) & ~3; /* for 4 bytes aligned */
859 pkt_size = rx_size - ETHER_CRC_LEN; /* Omit the four octet
860 * CRC from the length. */
861
862 PDEBUG("rx len: %ld rx frame size:%ld rx state:0x%x\n", rx_len, rx_size, rxstat);
863
864 /* errors receive packets caculatation */
865 if (rxstat == 0 || rx_size < 16 || !(rxstat & SL_RXSTAT_RXOK)) {
866 ifp->if_ierrors++;
867
868 if (!(rxstat & SL_RXSTAT_RXOK))
869 if_printf(ifp, "receiver ok error\n");
870
871 if (!(rxstat & SL_RXSTAT_CRCOK))
872 if_printf(ifp, "crc error\n");
873
874 if (rxstat & SL_RXSTAT_ALIGNERR)
875 if_printf(ifp, "frame alignment error\n");
876
877 if (rxstat & (SL_RXSTAT_HUGEFRM | SL_RXSTAT_SMALLFRM))
878 if_printf(ifp, "received frame length is error\n");
879
880 break;
881 }
882 rx_len -= (long)(rx_size_align + 4); /* 4 bytes for receive
883 * frame head */
884
885 if (rx_len < 0) {
886 kprintf("rx packets len is too small\n");
887 break;
888 }
889#ifdef SLN_PDEBUG
890 caddr_t p = NULL;
891
892 if_printf(ifp, "rx frame content\n");
893 p = rx_bufpos;
894 for (i = 0; i < 30; i++, p++) {
895 if (i % 10 == 0)
896 kprintf("\n");
897 if_printf(ifp, "%x ", (u_char)*p);
898 }
899 if_printf(ifp, "\n");
900#endif
901 /* No errors; receive the packet. */
902 rx_bytes = rx_bytes + rx_size + 4; /* 4 bytes for receive
903 * frame header */
904
905 if (rx_bufpos == (sc->sln_bufdata.sln_rx_buf + SL_RX_BUFLEN))
906 rx_bufpos = sc->sln_bufdata.sln_rx_buf;
907
908 rx_bufpos = rx_bufpos + 4; /* 4 bytes for receive frame
909 * header */
910 rx_space = (u_long)((sc->sln_bufdata.sln_rx_buf + SL_RX_BUFLEN) - rx_bufpos);
911
912 if (pkt_size > rx_space) {
913 m = m_devget(rx_bufpos - 2, pkt_size + 2, 0, ifp, NULL); /* 2 for etherer head
914 * align */
915
916 if (m == NULL) {
917 ifp->if_ierrors++;
918 if_printf(ifp,
919 "out of mbufs, tried to copy %ld bytes\n",
920 rx_space);
921 } else {
922 m_adj(m, 2);
923 m_copyback(m, rx_space, pkt_size - rx_space, sc->sln_bufdata.sln_rx_buf);
924 }
925 } else {
926 m = m_devget(rx_bufpos - 2, pkt_size + 2, 0, ifp, NULL);
927
928 if (m == NULL) {
929 ifp->if_ierrors++;
930 if_printf(ifp,
931 "out of mbufs, tried to copy %ld bytes\n",
932 pkt_size);
933 if_printf(ifp, "ierrors = %ld\n", ifp->if_ierrors);
934
935 } else {
936 m_adj(m, 2);
937 }
938 }
939
940 ifp->if_ipackets++;
941 PDEBUG("ipackets = %ld\n", ifp->if_ipackets);
942
943 ifp->if_input(ifp, m);
944
945 rx_offset = (rx_offset + rx_size + 4) & (u_long) (SL_RX_BUFLEN - 1); /* 4 bytes for receive
946 * frame head */
947 }
948
949 sc->sln_bufdata.dirty_rx = cur_rx;
950
951 SLN_WRITE_4(sc, SL_RBR_PTR, cur_rx);
952}
953
954/* Transmit OK/ERR handler */
955static void
956sln_tx_intr(struct sln_softc *sc)
957{
958 struct ifnet *ifp = &sc->arpcom.ac_if;
959 uint32_t txstat;
960 int entry;
961
962 do {
963 entry = sc->sln_bufdata.dirty_tx;
964 txstat = SLN_READ_4(sc, SL_TSD0 + entry * 4);
965
966 if (!(txstat & (SL_TXSD_TOK | SL_TXSD_TUN | SL_TXSD_TABT)))
967 break; /* It still hasn't been sent */
968
969 if (SL_DIRTY_TXBUF(sc) != NULL) { /* SL_DIRTY_TXBUF(x) =
970 * x->sln_bufdata.sln_tx_
971 * buf[x->sln_bufdata.dir
972 * ty_tx] */
973 m_freem(SL_DIRTY_TXBUF(sc));
974 SL_DIRTY_TXBUF(sc) = NULL;
975 }
976 if (txstat & SL_TXSD_TOK) {
977 ifp->if_opackets++;
978 ifp->if_obytes += txstat & SL_TXSD_LENMASK;
979 PDEBUG("opackets = %ld\n", ifp->if_opackets);
980 ifp->if_collisions += (txstat & SL_TXSD_NCC) >> 22;
981 } else {
982 ifp->if_oerrors++;
983 if ((txstat & (SL_TXSD_TABT | SL_TXSD_OWC))) {
984 sc->txcfg = TX_CFG_DEFAULT;
985
986 if (sc->txenablepad)
987 sc->txcfg |= 0x20000000;
988
989 SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
990 }
991 }
992 PDEBUG("tx done descriprtor %x\n", entry);
993 sc->sln_bufdata.dirty_tx = (entry + 1) % SL_TXD_CNT;
994
995 ifp->if_flags &= ~IFF_OACTIVE;
996 } while (sc->sln_bufdata.dirty_tx != sc->sln_bufdata.cur_tx);
997
998 if (sc->sln_bufdata.dirty_tx == sc->sln_bufdata.cur_tx)
999 ifp->if_timer = 0;
1000 else
1001 ifp->if_timer = 5;
1002}
1003
1004static void
1005sln_media_intr(struct sln_softc *sc)
1006{
1007 u_long phys[2];
1008 struct ifnet *ifp = &sc->arpcom.ac_if;
1009
1010 phys[0] = SL_MII_STAT;
1011 sln_mii_cmd(sc, SL_MII0_READ, phys);
1012
1013 PDEBUG("mii_stat:0x%lx\n", phys[1]);
1014
1015 if (0 == (phys[1] & SL_MIISTAT_LINK)) {
1016 kprintf("media is unconnect,linked down,or uncompatible\n");
1017 sc->connect = 0;
1018 sln_mii_cmd(sc, SL_MII0_SCAN, phys);
1019 /* disable tx/rx */
1020 sc->txcfg &= ~SL_TXCFG_EN;
1021 sc->rxcfg &= ~SL_RXCFG_EN;
1022 SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
1023 SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
1024
1025 return;
1026 }
1027 /* Link is good. Report modes and set duplex mode. */
1028 PDEBUG("media is connecting---> ");
1029 sc->connect = 1;
1030
1031 phys[0] = SL_MII_STAT_OUTPUT;
1032 sln_mii_cmd(sc, SL_MII0_READ, phys);
1033 sc->media_duplex = ((phys[1] & 0x0004) == 0) ? IFM_HDX : IFM_FDX;
1034 sc->media_speed = ((phys[1] & 0x0002) == 0) ? IFM_10_T : IFM_100_TX;
1035
1036 if_printf(ifp, "media option:%dM %s-duplex\n",
1037 sc->media_speed == 0x6 ? 100 : 10,
1038 sc->media_duplex == 0x100000 ? "full" : "half");
1039
1040 sln_mii_cmd(sc, SL_MII0_SCAN, phys);
1041
1042 sln_mac_cfg(sc);
1043
1044 /* Enable tx/rx */
1045 sc->rxcfg |= SL_RXCFG_EN;
1046 sc->txcfg |= SL_TXCFG_EN;
1047 SLN_WRITE_4(sc, SL_TX_CONFIG, sc->txcfg);
1048 SLN_WRITE_4(sc, SL_RX_CONFIG, sc->rxcfg);
1049}
1050
1051/* Interrupt Handler */
1052static void
1053sln_interrupt(void *arg)
1054{
1055 struct sln_softc *sc = arg;
1056 struct ifnet *ifp = &sc->arpcom.ac_if;
1057 uint32_t int_status;
1058
1059 ASSERT_SERIALIZED(ifp->if_serializer);
1060
1061 if (sc->suspended || (ifp->if_flags & IFF_RUNNING) == 0)
1062 return;
1063
1064 /* Disable interrupts. */
1065 SLN_WRITE_4(sc, SL_INT_MASK, 0);
1066
1067 int_status = SLN_READ_4(sc, SL_INT_STATUS);
1068
1069 if ((int_status == 0xffffffff) || (int_status & SL_INRTS) == 0)
1070 goto back;
1071
1072 int_status = int_status & SL_INRTS;
1073 PDEBUG("int_status = 0x%x\n", int_status);
1074
1075 while (0 != int_status) {
1076 if (int_status & SL_INT_ROK)
1077 sln_rx(sc);
1078
1079 if (int_status & SL_INT_TOK)
1080 sln_tx_intr(sc);
1081
1082 if (int_status & SL_INT_RBO) {
1083 ifp->if_ierrors++;
1084 PDEBUG("rx buffer is overflow\n");
1085 }
1086
1087 if (int_status & (SL_INT_LINKFAIL | SL_INT_LINKOK))
1088 sln_media_intr(sc);
1089
1090 int_status = SLN_READ_4(sc, SL_INT_STATUS);
1091 }
1092
1093 /* Data in Tx buffer waiting for transimission */
1094 if (!ifq_is_empty(&ifp->if_snd))
1095 if_devstart(ifp);
1096back:
1097 /* Re-enable interrupts. */
1098 SLN_WRITE_4(sc, SL_INT_MASK, SL_INRTS);
1099}
1100
1101static void
1102sln_tick(void *x)
1103{
1104 struct sln_softc *sc = x;
1105
1106 callout_reset(&sc->sln_state, hz, sln_tick, sc);
1107}
1108
1109static int
1110sln_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
1111{
1112 struct sln_softc *sc = ifp->if_softc;
1113 struct ifreq *ifr = (struct ifreq *)data;
1114 int error = 0;
1115
1116 ASSERT_SERIALIZED(ifp->if_serializer);
1117
1118 switch (cmd) {
1119 case SIOCSIFFLAGS:
1120 if (ifp->if_flags & IFF_UP) {
1121 if ((ifp->if_flags & IFF_RUNNING) == 0)
1122 sln_init(sc);
1123 } else {
1124 if (ifp->if_flags & IFF_RUNNING)
1125 sln_stop(sc);
1126 }
1127 break;
1128 case SIOCADDMULTI:
1129 case SIOCDELMULTI:
1130 sln_set_multi(sc);
1131 break;
1132 case SIOCGIFMEDIA:
1133 case SIOCSIFMEDIA:
1134 error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
1135 break;
1136 default:
1137 error = ether_ioctl(ifp, cmd, data);
1138 break;
1139 }
1140 return error;
1141}
1142
1143static void
1144sln_watchdog(struct ifnet *ifp)
1145{
1146 struct sln_softc *sc = ifp->if_softc;
1147
1148 ASSERT_SERIALIZED(ifp->if_serializer);
1149
1150 if_printf(ifp, "watchdog timeout!\n");
1151 ifp->if_oerrors++;
1152
1153 sln_tx_intr(sc);
1154 sln_rx(sc);
1155 sln_init(sc);
1156
1157 if (!ifq_is_empty(&ifp->if_snd))
1158 if_devstart(ifp);
1159}
1160
1161/* Stop all chip I/O */
1162static int
1163sln_shutdown(device_t dev)
1164{
1165 struct sln_softc *sc = device_get_softc(dev);
1166 struct ifnet *ifp = &sc->arpcom.ac_if;
1167
1168 lwkt_serialize_enter(ifp->if_serializer);
1169 sln_stop(sc);
1170 lwkt_serialize_exit(ifp->if_serializer);
1171
1172 return 0;
1173}
1174
1175/* device suspend routine */
1176static int
1177sln_suspend(device_t dev)
1178{
1179 struct sln_softc *sc = device_get_softc(dev);
1180 struct ifnet *ifp = &sc->arpcom.ac_if;
1181
1182 lwkt_serialize_enter(ifp->if_serializer);
1183 sln_stop(sc);
1184 sc->suspended = 1;
1185 lwkt_serialize_exit(ifp->if_serializer);
1186
1187 return 0;
1188}
1189
1190/* device resume routine */
1191static int
1192sln_resume(device_t dev)
1193{
1194 struct sln_softc *sc = device_get_softc(dev);
1195 struct ifnet *ifp = &sc->arpcom.ac_if;
1196
1197 lwkt_serialize_enter(ifp->if_serializer);
1198 if (ifp->if_flags & IFF_UP)
1199 sln_init(sc);
1200 sc->suspended = 0;
1201 lwkt_serialize_exit(ifp->if_serializer);
1202
1203 return 0;
1204}