]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sbsh/if_sbsh.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / sys / dev / sbsh / if_sbsh.c
1 /*-
2  * Granch SBNI16 G.SHDSL Modem driver
3  * Written by Denis I. Timofeev, 2002-2003.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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 the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/sockio.h>
33 #include <sys/mbuf.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/proc.h>
38 #include <sys/socket.h>
39 #include <sys/random.h>
40 #include <machine/clock.h>
41 #include <machine/stdarg.h>
42
43 #include <net/if.h>
44 #include <net/if_arp.h>
45 #include <net/ethernet.h>
46 #include <net/if_media.h>
47 #include <net/if_types.h>
48
49 #include <net/bpf.h>
50
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53 #include <machine/bus.h>
54 #include <machine/resource.h>
55 #include <sys/bus.h>
56 #include <sys/rman.h>
57
58 #include <dev/pci/pcireg.h>
59 #include <dev/pci/pcivar.h>
60
61 #include <dev/sbsh/if_sbshreg.h>
62
63 /* -------------------------------------------------------------------------- */
64
65 struct sbni16_hw_regs {
66         u_int8_t  CR, CRB, SR, IMR, CTDR, LTDR, CRDR, LRDR;
67 };
68
69 struct hw_descr {
70         u_int32_t  address;
71         u_int32_t  length;
72 };
73
74 struct cx28975_cmdarea {
75         u_int8_t  intr_host;
76         u_int8_t  intr_8051;
77         u_int8_t  map_version;
78
79         u_int8_t  in_dest;
80         u_int8_t  in_opcode;
81         u_int8_t  in_zero;
82         u_int8_t  in_length;
83         u_int8_t  in_csum;
84         u_int8_t  in_data[75];
85         u_int8_t  in_datasum;
86
87         u_int8_t  out_dest;
88         u_int8_t  out_opcode;
89         u_int8_t  out_ack;
90         u_int8_t  out_length;
91         u_int8_t  out_csum;
92         u_int8_t  out_data[75];
93         u_int8_t  out_datasum;
94 };
95
96 #define XQLEN   8
97 #define RQLEN   8
98
99 struct sbsh_softc {
100         struct ifnet    *ifp;
101
102         struct resource *mem_res;
103         struct resource *irq_res;
104         void            *intr_hand;
105
106         void            *mem_base;              /* mapped memory address */
107
108         volatile struct sbni16_hw_regs  *regs;
109         volatile struct hw_descr        *tbd;
110         volatile struct hw_descr        *rbd;
111         volatile struct cx28975_cmdarea *cmdp;
112
113         /* SBNI16 controller statistics */
114         struct sbni16_stats {
115                 u_int32_t  sent_pkts, rcvd_pkts;
116                 u_int32_t  crc_errs, ufl_errs, ofl_errs, attempts, last_time;
117         } in_stats;
118
119         /* transmit and reception queues */
120         struct mbuf     *xq[XQLEN], *rq[RQLEN];
121         unsigned        head_xq, tail_xq, head_rq, tail_rq;
122
123         /* the descriptors mapped onto the first buffers in xq and rq */
124         unsigned        head_tdesc, head_rdesc;
125         u_int8_t        state;
126 };
127
128 struct cx28975_cfg {
129         u_int8_t   *firmw_image;
130         u_int32_t  firmw_len;
131         u_int32_t  lrate: 10;
132         u_int32_t  master: 1;
133         u_int32_t  mod: 2;
134         u_int32_t  crc16: 1;
135         u_int32_t  fill_7e: 1;
136         u_int32_t  inv: 1;
137         u_int32_t  rburst: 1;
138         u_int32_t  wburst: 1;
139         u_int32_t  : 14;
140 };
141
142 /* SHDSL transceiver statistics */
143 struct dsl_stats {
144         u_int8_t        status_1, status_3;
145         u_int8_t        attenuat, nmr, tpbo, rpbo;
146         u_int16_t       losw, segd, crc, sega, losd;
147 };
148
149 enum State { NOT_LOADED, DOWN, ACTIVATION, ACTIVE };
150
151 #define SIOCLOADFIRMW   _IOWR('i', 67, struct ifreq)
152 #define SIOCGETSTATS    _IOWR('i', 68, struct ifreq)
153 #define SIOCCLRSTATS    _IOWR('i', 69, struct ifreq)
154
155 static int      sbsh_probe(device_t);
156 static int      sbsh_attach(device_t);
157 static int      sbsh_detach(device_t);
158 static int      sbsh_ioctl(struct ifnet *, u_long, caddr_t);
159 static void     sbsh_shutdown(device_t);
160 static int      sbsh_suspend(device_t);
161 static int      sbsh_resume(device_t);
162 static void     sbsh_watchdog(struct ifnet *);
163
164 static void     sbsh_start(struct ifnet *);
165 static void     sbsh_init(void *);
166 static void     sbsh_stop(struct sbsh_softc *);
167 static void     init_card(struct sbsh_softc *);
168 static void     sbsh_intr(void *);
169 static void     resume_tx(struct sbsh_softc *);
170 static void     start_xmit_frames(struct sbsh_softc *);
171 static void     encap_frame(struct sbsh_softc *, struct mbuf *);
172 static struct mbuf *    repack(struct sbsh_softc *, struct mbuf *);
173 static void     free_sent_buffers(struct sbsh_softc *);
174 static void     alloc_rx_buffers(struct sbsh_softc *);
175 static void     indicate_frames(struct sbsh_softc *);
176 static void     drop_queues(struct sbsh_softc *);
177 static void     activate(struct sbsh_softc *);
178 static void     deactivate(struct sbsh_softc *);
179 static void     cx28975_interrupt(struct sbsh_softc *);
180 static int      start_cx28975(struct sbsh_softc *, struct cx28975_cfg);
181 static int      download_firmware(struct sbsh_softc *, u_int8_t *, u_int32_t);
182 static int      issue_cx28975_cmd(struct sbsh_softc *, u_int8_t,
183                                         u_int8_t *, u_int8_t);
184
185 static device_method_t sbsh_methods[] = {
186         /* Device interface */
187         DEVMETHOD(device_probe,         sbsh_probe),
188         DEVMETHOD(device_attach,        sbsh_attach),
189         DEVMETHOD(device_detach,        sbsh_detach),
190         DEVMETHOD(device_shutdown,      sbsh_shutdown),
191         DEVMETHOD(device_suspend,       sbsh_suspend),
192         DEVMETHOD(device_resume,        sbsh_resume),
193
194         { 0, 0 }
195 };
196
197 static driver_t sbsh_driver = {
198         "sbsh",
199         sbsh_methods,
200         sizeof(struct sbsh_softc)
201 };
202
203 static devclass_t sbsh_devclass;
204
205 DRIVER_MODULE(sbsh, pci, sbsh_driver, sbsh_devclass, 0, 0);
206 MODULE_DEPEND(sbsh, pci, 1, 1, 1);
207
208 static int
209 sbsh_probe(device_t dev)
210 {
211         if (pci_get_vendor(dev) != SBNI16_VENDOR
212             || pci_get_device(dev) != SBNI16_DEVICE
213             || pci_get_subdevice(dev) != SBNI16_SUBDEV)
214                 return (ENXIO);
215
216         device_set_desc(dev, "Granch SBNI16 G.SHDSL Modem");
217         return (BUS_PROBE_DEFAULT);
218 }
219
220 static int
221 sbsh_attach(device_t dev)
222 {
223         struct sbsh_softc       *sc;
224         struct ifnet            *ifp;
225         int                     unit, error = 0, rid, s;
226         u_char                  eaddr[6];
227
228         s = splimp();
229
230         sc = device_get_softc(dev);
231         unit = device_get_unit(dev);
232
233         rid = PCIR_BAR(1);
234         sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
235                                         0, ~0, 4096, RF_ACTIVE);
236
237         if (sc->mem_res == NULL) {
238                 printf ("sbsh%d: couldn't map memory\n", unit);
239                 error = ENXIO;
240                 goto fail;
241         }
242
243         rid = 0;
244         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
245                                                 RF_SHAREABLE | RF_ACTIVE);
246
247         if (sc->irq_res == NULL) {
248                 printf("sbsh%d: couldn't map interrupt\n", unit);
249                 bus_release_resource(dev, SYS_RES_MEMORY,
250                                         PCIR_BAR(1), sc->mem_res);
251                 error = ENXIO;
252                 goto fail;
253         }
254
255         sc->mem_base = rman_get_virtual(sc->mem_res);
256         init_card(sc);
257
258         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
259                                 sbsh_intr, sc, &sc->intr_hand);
260         if (error) {
261                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
262                 bus_release_resource(dev, SYS_RES_MEMORY,
263                                         PCIR_BAR(1), sc->mem_res);
264                 printf("sbsh%d: couldn't set up irq\n", unit);
265                 goto fail;
266         }
267
268         /* generate ethernet MAC address */
269         *(u_int32_t *)eaddr = htonl(0x00ff0192);
270         read_random(eaddr + 4, 2);
271
272         ifp = sc->ifp = if_alloc(IFT_ETHER);
273         if (ifp == NULL) {
274                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
275                 bus_release_resource(dev, SYS_RES_MEMORY,
276                                         PCIR_BAR(1), sc->mem_res);
277                 bus_teardown_intr(dev, sc->irq_res, sc->intr_hand);
278                 printf("sbsh%d: can not if_alloc()\n", unit);
279                 goto fail;
280         }
281         ifp->if_softc = sc;
282         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
283         ifp->if_mtu = ETHERMTU;
284         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
285             IFF_NEEDSGIANT;
286         ifp->if_ioctl = sbsh_ioctl;
287         ifp->if_start = sbsh_start;
288         ifp->if_watchdog = sbsh_watchdog;
289         ifp->if_init = sbsh_init;
290         ifp->if_baudrate = 4600000;
291         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
292
293         ether_ifattach(ifp, eaddr);
294
295 fail:
296         splx(s);
297         return (error);
298 }
299
300 static int
301 sbsh_detach(device_t dev)
302 {
303         struct sbsh_softc       *sc;
304         struct ifnet            *ifp;
305         int                     s;
306
307         s = splimp();
308
309         sc = device_get_softc(dev);
310         ifp = sc->ifp;
311
312         sbsh_stop(sc);
313         ether_ifdetach(ifp);
314         if_free(ifp);
315
316         bus_teardown_intr(dev, sc->irq_res, sc->intr_hand);
317         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
318         bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(1), sc->mem_res);
319
320         splx(s);
321         return (0);
322 }
323
324
325 static void
326 sbsh_start(struct ifnet *ifp)
327 {
328         struct sbsh_softc  *sc = ifp->if_softc;
329         int  s;
330
331         if (sc->state != ACTIVE)
332                 return;
333
334         s = splimp();
335         start_xmit_frames(ifp->if_softc);
336         splx(s);
337 }
338
339
340 static void
341 sbsh_init(void *xsc)
342 {
343         struct sbsh_softc       *sc = xsc;
344         struct ifnet            *ifp = sc->ifp;
345         int                     s;
346         u_int8_t                t;
347
348         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) || sc->state == NOT_LOADED)
349                 return;
350
351         s = splimp();
352
353         bzero(&sc->in_stats, sizeof(struct sbni16_stats));
354         sc->head_xq = sc->tail_xq = sc->head_rq = sc->tail_rq = 0;
355         sc->head_tdesc = sc->head_rdesc = 0;
356
357         sc->regs->IMR = EXT;
358         t = 2;
359         issue_cx28975_cmd(sc, _DSL_CLEAR_ERROR_CTRS, &t, 1);
360         if (issue_cx28975_cmd(sc, _DSL_ACTIVATION, &t, 1) == 0) {
361                 sc->state = ACTIVATION;
362
363                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
364                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
365         }
366
367         splx(s);
368 }
369
370
371 static void
372 sbsh_stop(struct sbsh_softc *sc)
373 {
374         int  s;
375         u_int8_t  t;
376
377         s = splimp();
378         sc->regs->IMR = EXT;
379
380         t = 0;
381         issue_cx28975_cmd(sc, _DSL_ACTIVATION, &t, 1);
382         if (sc->state == ACTIVE) {
383                 t = 1;
384                 issue_cx28975_cmd(sc, _DSL_FORCE_DEACTIVATE, &t, 1);
385                 /* FIX! activation manager state */
386
387                 /* Is it really must be done here? It calls from intr handler */
388                 deactivate(sc);
389         }
390
391         sc->regs->IMR = 0;
392         sc->state = DOWN;
393         splx(s);
394 }
395
396
397 static void
398 init_card(struct sbsh_softc *sc)
399 {
400         sc->state = NOT_LOADED;
401         sc->tbd  = (struct hw_descr *) sc->mem_base;
402         sc->rbd  = (struct hw_descr *) ((u_int8_t *)sc->mem_base + 0x400);
403         sc->regs = (struct sbni16_hw_regs *) ((u_int8_t *)sc->mem_base + 0x800);
404         sc->cmdp = (struct cx28975_cmdarea *) ((u_int8_t *)sc->mem_base + 0xc00);
405
406         sc->regs->CR = 0;
407         sc->regs->SR = 0xff;
408         sc->regs->IMR = 0;
409 }
410
411
412 static int
413 sbsh_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
414 {
415         struct sbsh_softc       *sc = ifp->if_softc;
416         struct ifreq            *ifr = (struct ifreq *) data;
417         struct cx28975_cfg      cfg;
418         struct dsl_stats        ds;
419
420         int                     s, error = 0;
421         u_int8_t                t;
422
423         s = splimp();
424
425         switch(cmd) {
426         case SIOCLOADFIRMW:
427                 if ((error = suser(curthread)) != 0)
428                         break;
429                 if (ifp->if_flags & IFF_UP)
430                         error = EBUSY;
431
432                 bcopy((caddr_t)ifr->ifr_data, (caddr_t)&cfg, sizeof cfg);
433                 if (start_cx28975(sc, cfg) == 0) {
434                         static char  *modstr[] = {
435                                 "TCPAM32", "TCPAM16", "TCPAM8", "TCPAM4" };
436                         if_printf(sc->ifp, "%s, rate %d, %s\n",
437                                 cfg.master ? "master" : "slave",
438                                 cfg.lrate << 3, modstr[cfg.mod]);
439                 } else {
440                         if_printf(sc->ifp,
441                                 "unable to load firmware\n");
442                         error = EIO;
443                 }
444                 break;
445
446         case  SIOCGETSTATS :
447                 if ((error = suser(curthread)) != 0)
448                         break;
449
450                 t = 0;
451                 if (issue_cx28975_cmd(sc, _DSL_FAR_END_ATTEN, &t, 1))
452                         error = EIO;
453                 ds.attenuat = sc->cmdp->out_data[0];
454
455                 if (issue_cx28975_cmd(sc, _DSL_NOISE_MARGIN, &t, 1))
456                         error = EIO;
457                 ds.nmr = sc->cmdp->out_data[0];
458
459                 if (issue_cx28975_cmd(sc, _DSL_POWER_BACK_OFF_RESULT, &t, 1))
460                         error = EIO;
461                 ds.tpbo = sc->cmdp->out_data[0];
462                 ds.rpbo = sc->cmdp->out_data[1];
463
464                 if (!issue_cx28975_cmd(sc, _DSL_HDSL_PERF_ERR_CTRS, &t, 1)) {
465                         int i;
466                         for (i = 0; i < 10; ++i)
467                                 ((u_int8_t *) &ds.losw)[i] =
468                                         sc->cmdp->out_data[i];
469                 } else
470                         error = EIO;
471
472                 ds.status_1 = ((volatile u_int8_t *)sc->cmdp)[0x3c0];
473                 ds.status_3 = ((volatile u_int8_t *)sc->cmdp)[0x3c2];
474
475                 bcopy(&sc->in_stats, ifr->ifr_data, sizeof(struct sbni16_stats));
476                 bcopy(&ds, ifr->ifr_data + sizeof(struct sbni16_stats),
477                     sizeof(struct dsl_stats));
478                 break;
479
480         case  SIOCCLRSTATS :
481                 if (!(error = suser(curthread))) {
482                         bzero(&sc->in_stats, sizeof(struct sbni16_stats));
483                         t = 2;
484                         if (issue_cx28975_cmd(sc, _DSL_CLEAR_ERROR_CTRS, &t, 1))
485                                 error = EIO;
486                 }
487                 break;
488
489         case SIOCSIFFLAGS:
490                 if (ifp->if_flags & IFF_UP) {
491                         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
492                                 if (sc->state == NOT_LOADED) {
493                                         if_printf(ifp, "firmware wasn't loaded\n");
494                                         error = EBUSY;
495                                 } else
496                                         sbsh_init(sc);
497                         }
498                 } else {
499                         if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
500                                 sbsh_stop(sc);
501                                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
502                         }
503                 }
504                 break;
505
506         case SIOCADDMULTI:
507         case SIOCDELMULTI:
508                 error = 0;
509                 break;
510
511         default:
512                 error = ether_ioctl(ifp, cmd, data);
513                 break;
514         }
515
516         splx(s);
517         return (error);
518 }
519
520
521 static void
522 sbsh_shutdown(device_t dev)
523 {
524         struct sbsh_softc       *sc = device_get_softc(dev);
525
526         sbsh_stop(sc);
527 }
528
529 static int
530 sbsh_suspend(device_t dev)
531 {
532         struct sbsh_softc       *sc = device_get_softc(dev);
533         int                     s;
534
535         s = splimp();
536         sbsh_stop(sc);
537         splx(s);
538
539         return (0);
540 }
541
542 static int
543 sbsh_resume(device_t dev)
544 {
545         struct sbsh_softc       *sc = device_get_softc(dev);
546         struct ifnet            *ifp;
547         int                     s;
548
549         s = splimp();
550         ifp = sc->ifp;
551
552         if (ifp->if_flags & IFF_UP)
553                 sbsh_init(sc);
554
555         splx(s);
556         return (0);
557 }
558
559
560 static void
561 sbsh_watchdog(struct ifnet *ifp)
562 {
563         struct sbsh_softc       *sc = ifp->if_softc;
564
565         if_printf(ifp, "transmit timeout\n");
566
567         if (sc->regs->SR & TXS) {
568                 sc->regs->SR = TXS;
569                 if_printf(ifp, "interrupt posted but not delivered\n");
570         }
571         free_sent_buffers(sc);
572 }
573
574 /* -------------------------------------------------------------------------- */
575
576 static void
577 sbsh_intr(void *arg)
578 {
579         struct sbsh_softc  *sc = (struct sbsh_softc *)arg;
580         u_int8_t  status = sc->regs->SR;
581
582         if (status == 0)
583                 return;
584
585         if (status & EXT) {
586                 cx28975_interrupt(sc);
587                 sc->regs->SR = EXT;
588         }
589
590         if (status & UFL) {
591                 resume_tx(sc);
592                 sc->regs->SR = UFL;
593                 ++sc->in_stats.ufl_errs;
594                 ++sc->ifp->if_oerrors;
595         }
596
597         if (status & RXS) {
598                 sc->regs->SR = RXS;
599                 indicate_frames(sc);
600                 alloc_rx_buffers(sc);
601         }
602
603         if (status & TXS) {
604                 sc->regs->SR = TXS;
605                 free_sent_buffers(sc);
606         }
607
608         if (status & CRC) {
609                 ++sc->in_stats.crc_errs;
610                 ++sc->ifp->if_ierrors;
611                 sc->regs->SR = CRC;
612         }
613
614         if (status & OFL) {
615                 ++sc->in_stats.ofl_errs;
616                 ++sc->ifp->if_ierrors;
617                 sc->regs->SR = OFL;
618         }
619 }
620
621 /*
622  * Look for a first descriptor of a next packet, and write it's number
623  * into CTDR. Then enable the transmitter.
624  */
625 static void
626 resume_tx(struct sbsh_softc *sc)
627 {
628         u_int32_t       cur_tbd = sc->regs->CTDR;
629
630         while (cur_tbd != sc->regs->LTDR
631                 && (sc->tbd[cur_tbd++].length & LAST_FRAG) == 0)
632                 ;
633         sc->regs->CTDR = cur_tbd;
634         sc->regs->CR |= TXEN;
635 }
636
637 static void
638 start_xmit_frames(struct sbsh_softc *sc)
639 {
640         struct ifnet    *ifp = sc->ifp;
641         struct mbuf     *m;
642
643         /*
644          * Check if we have any free descriptor(s) and free space in
645          * our transmit queue.
646          */
647         while (sc->tail_xq != ((sc->head_xq - 1) & (XQLEN - 1))
648             && sc->regs->LTDR != ((sc->head_tdesc - 1) & 0x7f)) {
649
650                 IF_DEQUEUE(&ifp->if_snd, m);
651                 if (!m)
652                         break;
653                 if (m->m_pkthdr.len) {
654                         BPF_MTAP(ifp, m);
655                         encap_frame(sc, m);
656                 } else
657                         m_freem(m);
658         }
659
660         if (sc->regs->CTDR != sc->regs->LTDR)
661                 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
662         else
663                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
664 }
665
666
667 /*
668  * MUST be called at splimp
669  */
670 static void
671 encap_frame(struct sbsh_softc *sc, struct mbuf *m_head)
672 {
673         struct mbuf     *m;
674         u_int32_t       cur_tbd;
675         int  done;
676
677 look_for_nonzero:
678         for (m = m_head; !m->m_len; m = m->m_next)
679                 ;
680
681         cur_tbd = sc->regs->LTDR & 0x7f;
682         done = 0;
683         do {
684                 if (m->m_len < 5 || cur_tbd == ((sc->head_tdesc - 1) & 0x7f)) {
685                         if ((m_head = repack(sc, m_head)) != NULL)
686                                 goto look_for_nonzero;
687                         else
688                                 return;
689                 }
690
691                 sc->tbd[cur_tbd].address = vtophys(mtod(m, vm_offset_t));
692                 sc->tbd[cur_tbd].length  = m->m_len;
693
694                 do {
695                         m = m->m_next;
696                 } while (m && !m->m_len);
697
698                 if (!m) {       /* last fragment has been reached */
699                         sc->tbd[cur_tbd].length |= LAST_FRAG;
700                         done = 1;
701                 }
702
703                 ++cur_tbd;
704                 cur_tbd &= 0x7f;
705         } while (!done);
706
707         sc->xq[sc->tail_xq++] = m_head;
708         sc->tail_xq &= (XQLEN - 1);
709
710         sc->regs->LTDR = cur_tbd;
711         ++sc->in_stats.sent_pkts;
712         ++sc->ifp->if_opackets;
713 }
714
715 static struct mbuf *
716 repack(struct sbsh_softc *sc, struct mbuf *m)
717 {
718         struct mbuf  *m_new;
719
720         MGETHDR(m_new, M_DONTWAIT, MT_DATA);
721         if (!m_new) {
722                 if_printf (sc->ifp,
723                            "unable to get mbuf.\n");
724                 return (NULL);
725         }
726
727         if (m->m_pkthdr.len > MHLEN) {
728                 MCLGET(m_new, M_DONTWAIT);
729                 if (!(m_new->m_flags & M_EXT)) {
730                         m_freem(m_new);
731                         if_printf (sc->ifp,
732                                    "unable to get mbuf cluster.\n");
733                         return (NULL);
734                 }
735         }
736
737         m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, caddr_t));
738         m_new->m_pkthdr.len = m_new->m_len = m->m_pkthdr.len;
739         m_freem(m);
740         return (m_new);
741 }
742
743 static void
744 free_sent_buffers(struct sbsh_softc *sc)
745 {
746         u_int32_t  cur_tbd;
747
748         cur_tbd = sc->regs->CTDR;
749
750         while (sc->head_tdesc != cur_tbd) {
751                 /*
752                  * Be careful! one element in xq may correspond to
753                  * multiple descriptors.
754                  */
755                 if (sc->tbd[sc->head_tdesc].length & LAST_FRAG) {
756                         m_freem(sc->xq[sc->head_xq++]);
757                         sc->head_xq &= (XQLEN - 1);
758                 }
759
760                 sc->tbd[sc->head_tdesc].length = 0;
761                 sc->head_tdesc = (sc->head_tdesc + 1) & 0x7f;
762         }
763
764         start_xmit_frames(sc);
765 }
766
767 /*
768  * DON'T use free_sent_buffers to drop the queue!
769  */
770 static void
771 alloc_rx_buffers(struct sbsh_softc *sc)
772 {
773         unsigned        cur_rbd = sc->regs->LRDR & 0x7f;
774         struct mbuf     *m;
775
776         while (sc->tail_rq != ((sc->head_rq - 1) & (RQLEN - 1))) {
777                 MGETHDR(m, M_DONTWAIT, MT_DATA);
778                 if (!m) {
779                         if_printf (sc->ifp,
780                                    "unable to get mbuf.\n");
781                         return;
782                 }
783
784                 if (SBNI16_MAX_FRAME > MHLEN) {
785                         MCLGET(m, M_DONTWAIT);
786                         if (!(m->m_flags & M_EXT)) {
787                                 m_freem(m);
788                                 if_printf (sc->ifp,
789                                            "unable to get mbuf cluster.\n");
790                                 return;
791                         }
792                         m->m_pkthdr.len = m->m_len = MCLBYTES;
793                 }
794
795                 m_adj(m, 2);    /* align ip on longword boundaries */
796
797                 sc->rq[sc->tail_rq++] = m;
798                 sc->tail_rq &= (RQLEN - 1);
799
800                 sc->rbd[cur_rbd].address = vtophys(mtod(m, vm_offset_t));
801                 sc->rbd[cur_rbd].length  = 0;
802                 sc->regs->LRDR = cur_rbd = (cur_rbd + 1) & 0x7f;
803         }
804 }
805
806 static void
807 indicate_frames(struct sbsh_softc *sc)
808 {
809         unsigned  cur_rbd = sc->regs->CRDR & 0x7f;
810
811         while (sc->head_rdesc != cur_rbd) {
812                 struct mbuf  *m = sc->rq[sc->head_rq++];
813                 sc->head_rq &= (RQLEN - 1);
814
815                 m->m_pkthdr.len = m->m_len =
816                                 sc->rbd[sc->head_rdesc].length & 0x7ff;
817                 m->m_pkthdr.rcvif = sc->ifp;
818
819                 (*sc->ifp->if_input)(sc->ifp, m);
820                 ++sc->in_stats.rcvd_pkts;
821                 ++sc->ifp->if_ipackets;
822
823                 sc->head_rdesc = (sc->head_rdesc + 1) & 0x7f;
824         }
825 }
826
827 static void
828 drop_queues(struct sbsh_softc *sc)
829 {
830         while (sc->head_rq != sc->tail_rq) {
831                 m_freem(sc->rq[sc->head_rq++]);
832                 sc->head_rq &= (RQLEN - 1);
833         }
834
835         while (sc->head_xq != sc->tail_xq) {
836                 m_freem(sc->xq[sc->head_xq++]);
837                 sc->head_xq &= (XQLEN - 1);
838         }
839 }
840
841 /* -------------------------------------------------------------------------- */
842
843 static void
844 activate(struct sbsh_softc *sc)
845 {
846         struct timeval  tv;
847
848         sc->regs->SR   = 0xff;          /* clear it! */
849         sc->regs->CTDR = sc->regs->LTDR = sc->regs->CRDR = sc->regs->LRDR = 0;
850
851         sc->head_tdesc = sc->head_rdesc = 0;
852         alloc_rx_buffers(sc);
853
854         sc->regs->CRB &= ~RXDE;
855         sc->regs->IMR = EXT | RXS | TXS | CRC | OFL | UFL;
856         sc->regs->CR |= TXEN | RXEN;
857
858         sc->state = ACTIVE;
859         ++sc->in_stats.attempts;
860         microtime(&tv);
861         sc->in_stats.last_time = tv.tv_sec;
862         start_xmit_frames(sc);
863 }
864
865 static void
866 deactivate(struct sbsh_softc *sc)
867 {
868         sc->regs->CR &= ~(RXEN | TXEN);
869         sc->regs->CRB |= RXDE;
870         sc->regs->IMR  = EXT;
871         sc->regs->CTDR = sc->regs->LTDR;
872         sc->regs->CRDR = sc->regs->LRDR;
873         sc->state = ACTIVATION;
874
875         drop_queues(sc);
876 }
877
878 /* -------------------------------------------------------------------------- */
879
880 static void
881 cx28975_interrupt(struct sbsh_softc *sc)
882 {
883         volatile struct cx28975_cmdarea  *p = sc->cmdp;
884         u_int8_t  t;
885
886         if (p->intr_host != 0xfe)
887                 return;
888
889         if (p->out_ack & 0x80) {
890                 if (*((volatile u_int8_t *)p + 0x3c7) & 2) {
891                         if (sc->state != ACTIVE
892                             && (*((volatile u_int8_t *)p + 0x3c0) & 0xc0) == 0x40) {
893                                 activate(sc);
894                                 if_printf(sc->ifp, "connected to peer\n");
895                         } else if (sc->state == ACTIVE
896                                  && (*((volatile u_int8_t *)p + 0x3c0) & 0xc0) != 0x40) {
897                                 deactivate(sc);
898                                 if_printf(sc->ifp, "carrier lost\n");
899                         }
900                 }
901
902                 p->intr_host = 0;
903                 t = p->intr_host;
904                 p->out_ack = 0;
905         } else {
906                 wakeup(sc);
907
908                 p->intr_host = 0;
909                 t = p->intr_host;
910         }
911 }
912
913 /* -------------------------------------------------------------------------- */
914
915 static int
916 start_cx28975(struct sbsh_softc *sc, struct cx28975_cfg cfg)
917 {
918         static char  thresh[] = { +8, -4, -16, -40 };
919
920         volatile struct cx28975_cmdarea  *p = sc->cmdp;
921         u_int8_t  t, parm[12];
922
923         p->intr_host = 0;
924         t = p->intr_host;
925
926         /* reset chip set */
927         sc->regs->IMR = EXT;
928         sc->regs->CR  = 0;
929         sc->regs->SR  = 0xff;
930         DELAY(2);
931         sc->regs->CR = XRST;
932         if (cfg.crc16)
933                 sc->regs->CR |= CMOD;
934         if (cfg.fill_7e)
935                 sc->regs->CR |= FMOD;
936         if (cfg.inv)
937                 sc->regs->CR |= PMOD;
938
939         sc->regs->CRB |= RODD | RXDE;
940         if (cfg.rburst)
941                 sc->regs->CRB |= RDBE;
942         if (cfg.wburst)
943                 sc->regs->CRB |= WTBE;
944
945         tsleep(sc, PWAIT, "sbsh", 0);
946         if ((p->out_ack & 0x1f) != _ACK_BOOT_WAKE_UP)
947                 return (-1);
948
949         if (download_firmware(sc, cfg.firmw_image, cfg.firmw_len))
950                 return (-1);
951
952         tsleep(sc, PWAIT, "sbsh", 0);
953         if ((p->out_ack & 0x1f) != _ACK_OPER_WAKE_UP)
954                 return (-1);
955
956         t = cfg.master ? 1 : 9;
957         if (issue_cx28975_cmd(sc, _DSL_SYSTEM_ENABLE, &t, 1))
958                 return (-1);
959
960         t = 0x63;
961         if (issue_cx28975_cmd(sc, _DSL_SYSTEM_CONFIG, &t, 1))
962                 return (-1);
963
964         *(u_int16_t *)parm = cfg.lrate >> 3;
965         parm[2] = parm[3] = parm[0];
966         parm[5] = cfg.lrate & 7;
967         parm[4] = parm[7] = 1;
968         parm[6] = 0;
969         if (issue_cx28975_cmd(sc, _DSL_MULTI_RATE_CONFIG, parm, 8))
970                 return (-1);
971
972         parm[0] = 0x02 | (cfg.mod << 4);
973         parm[1] = 0;
974         if (issue_cx28975_cmd(sc, _DSL_TRAINING_MODE, parm, 2))
975                 return (-1);
976
977         bzero(parm, 12);
978         parm[0] = 0x04;         /* pre-activation: G.hs */
979         parm[4] = 0x04;         /* no remote configuration */
980         parm[7] = 0x01;         /* annex A (default) */
981         parm[8] = 0xff;         /* i-bit mask (all bits) */
982         if (issue_cx28975_cmd(sc, _DSL_PREACTIVATION_CFG, parm, 12))
983                 return (-1);
984
985         parm[0] = 0x03;         /* dying gasp time - 3 frames */
986         parm[1] = thresh[cfg.mod];
987         parm[2] = 0xff;         /* attenuation */
988         parm[3] = 0x04;         /* line probe NMR (+2 dB) */
989         parm[4] = 0x00;         /* reserved */
990         parm[5] = 0x00;
991         if (issue_cx28975_cmd(sc, _DSL_THRESHOLDS, parm, 6))
992                 return (-1);
993
994         t = cfg.master ? 0x23 : 0x21;
995         if (issue_cx28975_cmd(sc, _DSL_FR_PCM_CONFIG, &t, 1))
996                 return (-1);
997
998         t = 0x02;
999         if (issue_cx28975_cmd(sc, _DSL_INTR_HOST_MASK, &t, 1))
1000                 return (-1);
1001
1002         sc->state = DOWN;
1003         return (0);
1004 }
1005
1006 static int
1007 download_firmware(struct sbsh_softc *sc, u_int8_t *img, u_int32_t img_len)
1008 {
1009         u_int32_t       t;
1010         int             i;
1011         u_int8_t        cksum = 0;
1012
1013         for (i = 0; i < img_len; ++i)
1014                 cksum += img[i];
1015
1016         t = img_len;
1017         if (issue_cx28975_cmd(sc, _DSL_DOWNLOAD_START, (u_int8_t *) &t, 4))
1018                 return (-1);
1019
1020         for (i = 0; img_len >= 75; i += 75, img_len -= 75) {
1021                 if (issue_cx28975_cmd(sc, _DSL_DOWNLOAD_DATA, img + i, 75))
1022                         return (-1);
1023         }
1024
1025         if (img_len
1026             &&  issue_cx28975_cmd(sc, _DSL_DOWNLOAD_DATA, img + i, img_len))
1027                 return (-1);
1028
1029         t = (cksum ^ 0xff) + 1;
1030         if (issue_cx28975_cmd(sc, _DSL_DOWNLOAD_END, (u_int8_t *) &t, 1))
1031                 return (-1);
1032
1033         return (0);
1034 }
1035
1036 static int
1037 issue_cx28975_cmd(struct sbsh_softc *sc, u_int8_t cmd,
1038                         u_int8_t *data, u_int8_t size)
1039 {
1040         volatile struct cx28975_cmdarea  *p = sc->cmdp;
1041         u_int8_t  *databuf = p->in_data;
1042         int  i;
1043
1044         u_int8_t  cksum = 0;
1045
1046         p->in_dest      = 0xf0;
1047         p->in_opcode    = cmd;
1048         p->in_zero      = 0;
1049         p->in_length    = --size;
1050         p->in_csum      = 0xf0 ^ cmd ^ size ^ 0xaa;
1051
1052         for (i = 0; i <= size; ++i) {
1053                 cksum ^= *data;
1054                 *databuf++ = *data++;   /* only 1 byte per cycle! */
1055         }
1056
1057         p->in_datasum   = cksum ^ 0xaa;
1058         p->out_ack      = _ACK_NOT_COMPLETE;
1059         p->intr_8051    = 0xfe;
1060
1061         if (tsleep(sc, PWAIT, "sbsh", hz << 3))
1062                 return (-1);
1063
1064         while (p->out_ack == _ACK_NOT_COMPLETE)
1065                 ;                                       /* FIXME ! */
1066
1067         if ((p->out_ack & 0x1f) == _ACK_PASS) {
1068                 p->out_ack = 0;
1069                 return (0);
1070         } else {
1071                 p->out_ack = 0;
1072                 return (-1);
1073         }
1074 }