]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/sbsh/if_sbsh.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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/priv.h>
38 #include <sys/proc.h>
39 #include <sys/socket.h>
40 #include <sys/random.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                                 NULL, 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
315         bus_teardown_intr(dev, sc->irq_res, sc->intr_hand);
316         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
317         bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(1), sc->mem_res);
318
319         if_free(ifp);
320
321         splx(s);
322         return (0);
323 }
324
325
326 static void
327 sbsh_start(struct ifnet *ifp)
328 {
329         struct sbsh_softc  *sc = ifp->if_softc;
330         int  s;
331
332         if (sc->state != ACTIVE)
333                 return;
334
335         s = splimp();
336         start_xmit_frames(ifp->if_softc);
337         splx(s);
338 }
339
340
341 static void
342 sbsh_init(void *xsc)
343 {
344         struct sbsh_softc       *sc = xsc;
345         struct ifnet            *ifp = sc->ifp;
346         int                     s;
347         u_int8_t                t;
348
349         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) || sc->state == NOT_LOADED)
350                 return;
351
352         s = splimp();
353
354         bzero(&sc->in_stats, sizeof(struct sbni16_stats));
355         sc->head_xq = sc->tail_xq = sc->head_rq = sc->tail_rq = 0;
356         sc->head_tdesc = sc->head_rdesc = 0;
357
358         sc->regs->IMR = EXT;
359         t = 2;
360         issue_cx28975_cmd(sc, _DSL_CLEAR_ERROR_CTRS, &t, 1);
361         if (issue_cx28975_cmd(sc, _DSL_ACTIVATION, &t, 1) == 0) {
362                 sc->state = ACTIVATION;
363
364                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
365                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
366         }
367
368         splx(s);
369 }
370
371
372 static void
373 sbsh_stop(struct sbsh_softc *sc)
374 {
375         int  s;
376         u_int8_t  t;
377
378         s = splimp();
379         sc->regs->IMR = EXT;
380
381         t = 0;
382         issue_cx28975_cmd(sc, _DSL_ACTIVATION, &t, 1);
383         if (sc->state == ACTIVE) {
384                 t = 1;
385                 issue_cx28975_cmd(sc, _DSL_FORCE_DEACTIVATE, &t, 1);
386                 /* FIX! activation manager state */
387
388                 /* Is it really must be done here? It calls from intr handler */
389                 deactivate(sc);
390         }
391
392         sc->regs->IMR = 0;
393         sc->state = DOWN;
394         splx(s);
395 }
396
397
398 static void
399 init_card(struct sbsh_softc *sc)
400 {
401         sc->state = NOT_LOADED;
402         sc->tbd  = (struct hw_descr *) sc->mem_base;
403         sc->rbd  = (struct hw_descr *) ((u_int8_t *)sc->mem_base + 0x400);
404         sc->regs = (struct sbni16_hw_regs *) ((u_int8_t *)sc->mem_base + 0x800);
405         sc->cmdp = (struct cx28975_cmdarea *) ((u_int8_t *)sc->mem_base + 0xc00);
406
407         sc->regs->CR = 0;
408         sc->regs->SR = 0xff;
409         sc->regs->IMR = 0;
410 }
411
412
413 static int
414 sbsh_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
415 {
416         struct sbsh_softc       *sc = ifp->if_softc;
417         struct ifreq            *ifr = (struct ifreq *) data;
418         struct cx28975_cfg      cfg;
419         struct dsl_stats        ds;
420
421         int                     s, error = 0;
422         u_int8_t                t;
423
424         s = splimp();
425
426         switch(cmd) {
427         case SIOCLOADFIRMW:
428                 if ((error = priv_check(curthread, PRIV_DRIVER)) != 0)
429                         break;
430                 if (ifp->if_flags & IFF_UP)
431                         error = EBUSY;
432
433                 bcopy((caddr_t)ifr->ifr_data, (caddr_t)&cfg, sizeof cfg);
434                 if (start_cx28975(sc, cfg) == 0) {
435                         static char  *modstr[] = {
436                                 "TCPAM32", "TCPAM16", "TCPAM8", "TCPAM4" };
437                         if_printf(sc->ifp, "%s, rate %d, %s\n",
438                                 cfg.master ? "master" : "slave",
439                                 cfg.lrate << 3, modstr[cfg.mod]);
440                 } else {
441                         if_printf(sc->ifp,
442                                 "unable to load firmware\n");
443                         error = EIO;
444                 }
445                 break;
446
447         case  SIOCGETSTATS :
448                 if ((error = priv_check(curthread, PRIV_DRIVER)) != 0)
449                         break;
450
451                 t = 0;
452                 if (issue_cx28975_cmd(sc, _DSL_FAR_END_ATTEN, &t, 1))
453                         error = EIO;
454                 ds.attenuat = sc->cmdp->out_data[0];
455
456                 if (issue_cx28975_cmd(sc, _DSL_NOISE_MARGIN, &t, 1))
457                         error = EIO;
458                 ds.nmr = sc->cmdp->out_data[0];
459
460                 if (issue_cx28975_cmd(sc, _DSL_POWER_BACK_OFF_RESULT, &t, 1))
461                         error = EIO;
462                 ds.tpbo = sc->cmdp->out_data[0];
463                 ds.rpbo = sc->cmdp->out_data[1];
464
465                 if (!issue_cx28975_cmd(sc, _DSL_HDSL_PERF_ERR_CTRS, &t, 1)) {
466                         int i;
467                         for (i = 0; i < 10; ++i)
468                                 ((u_int8_t *) &ds.losw)[i] =
469                                         sc->cmdp->out_data[i];
470                 } else
471                         error = EIO;
472
473                 ds.status_1 = ((volatile u_int8_t *)sc->cmdp)[0x3c0];
474                 ds.status_3 = ((volatile u_int8_t *)sc->cmdp)[0x3c2];
475
476                 bcopy(&sc->in_stats, ifr->ifr_data, sizeof(struct sbni16_stats));
477                 bcopy(&ds, ifr->ifr_data + sizeof(struct sbni16_stats),
478                     sizeof(struct dsl_stats));
479                 break;
480
481         case  SIOCCLRSTATS :
482                 if (!(error = priv_check(curthread, PRIV_DRIVER))) {
483                         bzero(&sc->in_stats, sizeof(struct sbni16_stats));
484                         t = 2;
485                         if (issue_cx28975_cmd(sc, _DSL_CLEAR_ERROR_CTRS, &t, 1))
486                                 error = EIO;
487                 }
488                 break;
489
490         case SIOCSIFFLAGS:
491                 if (ifp->if_flags & IFF_UP) {
492                         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
493                                 if (sc->state == NOT_LOADED) {
494                                         if_printf(ifp, "firmware wasn't loaded\n");
495                                         error = EBUSY;
496                                 } else
497                                         sbsh_init(sc);
498                         }
499                 } else {
500                         if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
501                                 sbsh_stop(sc);
502                                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
503                         }
504                 }
505                 break;
506
507         case SIOCADDMULTI:
508         case SIOCDELMULTI:
509                 error = 0;
510                 break;
511
512         default:
513                 error = ether_ioctl(ifp, cmd, data);
514                 break;
515         }
516
517         splx(s);
518         return (error);
519 }
520
521
522 static void
523 sbsh_shutdown(device_t dev)
524 {
525         struct sbsh_softc       *sc = device_get_softc(dev);
526
527         sbsh_stop(sc);
528 }
529
530 static int
531 sbsh_suspend(device_t dev)
532 {
533         struct sbsh_softc       *sc = device_get_softc(dev);
534         int                     s;
535
536         s = splimp();
537         sbsh_stop(sc);
538         splx(s);
539
540         return (0);
541 }
542
543 static int
544 sbsh_resume(device_t dev)
545 {
546         struct sbsh_softc       *sc = device_get_softc(dev);
547         struct ifnet            *ifp;
548         int                     s;
549
550         s = splimp();
551         ifp = sc->ifp;
552
553         if (ifp->if_flags & IFF_UP)
554                 sbsh_init(sc);
555
556         splx(s);
557         return (0);
558 }
559
560
561 static void
562 sbsh_watchdog(struct ifnet *ifp)
563 {
564         struct sbsh_softc       *sc = ifp->if_softc;
565
566         if_printf(ifp, "transmit timeout\n");
567
568         if (sc->regs->SR & TXS) {
569                 sc->regs->SR = TXS;
570                 if_printf(ifp, "interrupt posted but not delivered\n");
571         }
572         free_sent_buffers(sc);
573 }
574
575 /* -------------------------------------------------------------------------- */
576
577 static void
578 sbsh_intr(void *arg)
579 {
580         struct sbsh_softc  *sc = (struct sbsh_softc *)arg;
581         u_int8_t  status = sc->regs->SR;
582
583         if (status == 0)
584                 return;
585
586         if (status & EXT) {
587                 cx28975_interrupt(sc);
588                 sc->regs->SR = EXT;
589         }
590
591         if (status & UFL) {
592                 resume_tx(sc);
593                 sc->regs->SR = UFL;
594                 ++sc->in_stats.ufl_errs;
595                 ++sc->ifp->if_oerrors;
596         }
597
598         if (status & RXS) {
599                 sc->regs->SR = RXS;
600                 indicate_frames(sc);
601                 alloc_rx_buffers(sc);
602         }
603
604         if (status & TXS) {
605                 sc->regs->SR = TXS;
606                 free_sent_buffers(sc);
607         }
608
609         if (status & CRC) {
610                 ++sc->in_stats.crc_errs;
611                 ++sc->ifp->if_ierrors;
612                 sc->regs->SR = CRC;
613         }
614
615         if (status & OFL) {
616                 ++sc->in_stats.ofl_errs;
617                 ++sc->ifp->if_ierrors;
618                 sc->regs->SR = OFL;
619         }
620 }
621
622 /*
623  * Look for a first descriptor of a next packet, and write it's number
624  * into CTDR. Then enable the transmitter.
625  */
626 static void
627 resume_tx(struct sbsh_softc *sc)
628 {
629         u_int32_t       cur_tbd = sc->regs->CTDR;
630
631         while (cur_tbd != sc->regs->LTDR
632                 && (sc->tbd[cur_tbd++].length & LAST_FRAG) == 0)
633                 ;
634         sc->regs->CTDR = cur_tbd;
635         sc->regs->CR |= TXEN;
636 }
637
638 static void
639 start_xmit_frames(struct sbsh_softc *sc)
640 {
641         struct ifnet    *ifp = sc->ifp;
642         struct mbuf     *m;
643
644         /*
645          * Check if we have any free descriptor(s) and free space in
646          * our transmit queue.
647          */
648         while (sc->tail_xq != ((sc->head_xq - 1) & (XQLEN - 1))
649             && sc->regs->LTDR != ((sc->head_tdesc - 1) & 0x7f)) {
650
651                 IF_DEQUEUE(&ifp->if_snd, m);
652                 if (!m)
653                         break;
654                 if (m->m_pkthdr.len) {
655                         BPF_MTAP(ifp, m);
656                         encap_frame(sc, m);
657                 } else
658                         m_freem(m);
659         }
660
661         if (sc->regs->CTDR != sc->regs->LTDR)
662                 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
663         else
664                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
665 }
666
667
668 /*
669  * MUST be called at splimp
670  */
671 static void
672 encap_frame(struct sbsh_softc *sc, struct mbuf *m_head)
673 {
674         struct mbuf     *m;
675         u_int32_t       cur_tbd;
676         int  done;
677
678 look_for_nonzero:
679         for (m = m_head; !m->m_len; m = m->m_next)
680                 ;
681
682         cur_tbd = sc->regs->LTDR & 0x7f;
683         done = 0;
684         do {
685                 if (m->m_len < 5 || cur_tbd == ((sc->head_tdesc - 1) & 0x7f)) {
686                         if ((m_head = repack(sc, m_head)) != NULL)
687                                 goto look_for_nonzero;
688                         else
689                                 return;
690                 }
691
692                 sc->tbd[cur_tbd].address = vtophys(mtod(m, vm_offset_t));
693                 sc->tbd[cur_tbd].length  = m->m_len;
694
695                 do {
696                         m = m->m_next;
697                 } while (m && !m->m_len);
698
699                 if (!m) {       /* last fragment has been reached */
700                         sc->tbd[cur_tbd].length |= LAST_FRAG;
701                         done = 1;
702                 }
703
704                 ++cur_tbd;
705                 cur_tbd &= 0x7f;
706         } while (!done);
707
708         sc->xq[sc->tail_xq++] = m_head;
709         sc->tail_xq &= (XQLEN - 1);
710
711         sc->regs->LTDR = cur_tbd;
712         ++sc->in_stats.sent_pkts;
713         ++sc->ifp->if_opackets;
714 }
715
716 static struct mbuf *
717 repack(struct sbsh_softc *sc, struct mbuf *m)
718 {
719         struct mbuf  *m_new;
720
721         MGETHDR(m_new, M_DONTWAIT, MT_DATA);
722         if (!m_new) {
723                 if_printf (sc->ifp,
724                            "unable to get mbuf.\n");
725                 return (NULL);
726         }
727
728         if (m->m_pkthdr.len > MHLEN) {
729                 MCLGET(m_new, M_DONTWAIT);
730                 if (!(m_new->m_flags & M_EXT)) {
731                         m_freem(m_new);
732                         if_printf (sc->ifp,
733                                    "unable to get mbuf cluster.\n");
734                         return (NULL);
735                 }
736         }
737
738         m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, caddr_t));
739         m_new->m_pkthdr.len = m_new->m_len = m->m_pkthdr.len;
740         m_freem(m);
741         return (m_new);
742 }
743
744 static void
745 free_sent_buffers(struct sbsh_softc *sc)
746 {
747         u_int32_t  cur_tbd;
748
749         cur_tbd = sc->regs->CTDR;
750
751         while (sc->head_tdesc != cur_tbd) {
752                 /*
753                  * Be careful! one element in xq may correspond to
754                  * multiple descriptors.
755                  */
756                 if (sc->tbd[sc->head_tdesc].length & LAST_FRAG) {
757                         m_freem(sc->xq[sc->head_xq++]);
758                         sc->head_xq &= (XQLEN - 1);
759                 }
760
761                 sc->tbd[sc->head_tdesc].length = 0;
762                 sc->head_tdesc = (sc->head_tdesc + 1) & 0x7f;
763         }
764
765         start_xmit_frames(sc);
766 }
767
768 /*
769  * DON'T use free_sent_buffers to drop the queue!
770  */
771 static void
772 alloc_rx_buffers(struct sbsh_softc *sc)
773 {
774         unsigned        cur_rbd = sc->regs->LRDR & 0x7f;
775         struct mbuf     *m;
776
777         while (sc->tail_rq != ((sc->head_rq - 1) & (RQLEN - 1))) {
778                 MGETHDR(m, M_DONTWAIT, MT_DATA);
779                 if (!m) {
780                         if_printf (sc->ifp,
781                                    "unable to get mbuf.\n");
782                         return;
783                 }
784
785                 if (SBNI16_MAX_FRAME > MHLEN) {
786                         MCLGET(m, M_DONTWAIT);
787                         if (!(m->m_flags & M_EXT)) {
788                                 m_freem(m);
789                                 if_printf (sc->ifp,
790                                            "unable to get mbuf cluster.\n");
791                                 return;
792                         }
793                         m->m_pkthdr.len = m->m_len = MCLBYTES;
794                 }
795
796                 m_adj(m, 2);    /* align ip on longword boundaries */
797
798                 sc->rq[sc->tail_rq++] = m;
799                 sc->tail_rq &= (RQLEN - 1);
800
801                 sc->rbd[cur_rbd].address = vtophys(mtod(m, vm_offset_t));
802                 sc->rbd[cur_rbd].length  = 0;
803                 sc->regs->LRDR = cur_rbd = (cur_rbd + 1) & 0x7f;
804         }
805 }
806
807 static void
808 indicate_frames(struct sbsh_softc *sc)
809 {
810         unsigned  cur_rbd = sc->regs->CRDR & 0x7f;
811
812         while (sc->head_rdesc != cur_rbd) {
813                 struct mbuf  *m = sc->rq[sc->head_rq++];
814                 sc->head_rq &= (RQLEN - 1);
815
816                 m->m_pkthdr.len = m->m_len =
817                                 sc->rbd[sc->head_rdesc].length & 0x7ff;
818                 m->m_pkthdr.rcvif = sc->ifp;
819
820                 (*sc->ifp->if_input)(sc->ifp, m);
821                 ++sc->in_stats.rcvd_pkts;
822                 ++sc->ifp->if_ipackets;
823
824                 sc->head_rdesc = (sc->head_rdesc + 1) & 0x7f;
825         }
826 }
827
828 static void
829 drop_queues(struct sbsh_softc *sc)
830 {
831         while (sc->head_rq != sc->tail_rq) {
832                 m_freem(sc->rq[sc->head_rq++]);
833                 sc->head_rq &= (RQLEN - 1);
834         }
835
836         while (sc->head_xq != sc->tail_xq) {
837                 m_freem(sc->xq[sc->head_xq++]);
838                 sc->head_xq &= (XQLEN - 1);
839         }
840 }
841
842 /* -------------------------------------------------------------------------- */
843
844 static void
845 activate(struct sbsh_softc *sc)
846 {
847         struct timeval  tv;
848
849         sc->regs->SR   = 0xff;          /* clear it! */
850         sc->regs->CTDR = sc->regs->LTDR = sc->regs->CRDR = sc->regs->LRDR = 0;
851
852         sc->head_tdesc = sc->head_rdesc = 0;
853         alloc_rx_buffers(sc);
854
855         sc->regs->CRB &= ~RXDE;
856         sc->regs->IMR = EXT | RXS | TXS | CRC | OFL | UFL;
857         sc->regs->CR |= TXEN | RXEN;
858
859         sc->state = ACTIVE;
860         ++sc->in_stats.attempts;
861         microtime(&tv);
862         sc->in_stats.last_time = tv.tv_sec;
863         start_xmit_frames(sc);
864 }
865
866 static void
867 deactivate(struct sbsh_softc *sc)
868 {
869         sc->regs->CR &= ~(RXEN | TXEN);
870         sc->regs->CRB |= RXDE;
871         sc->regs->IMR  = EXT;
872         sc->regs->CTDR = sc->regs->LTDR;
873         sc->regs->CRDR = sc->regs->LRDR;
874         sc->state = ACTIVATION;
875
876         drop_queues(sc);
877 }
878
879 /* -------------------------------------------------------------------------- */
880
881 static void
882 cx28975_interrupt(struct sbsh_softc *sc)
883 {
884         volatile struct cx28975_cmdarea  *p = sc->cmdp;
885         u_int8_t  t;
886
887         if (p->intr_host != 0xfe)
888                 return;
889
890         if (p->out_ack & 0x80) {
891                 if (*((volatile u_int8_t *)p + 0x3c7) & 2) {
892                         if (sc->state != ACTIVE
893                             && (*((volatile u_int8_t *)p + 0x3c0) & 0xc0) == 0x40) {
894                                 activate(sc);
895                                 if_printf(sc->ifp, "connected to peer\n");
896                         } else if (sc->state == ACTIVE
897                                  && (*((volatile u_int8_t *)p + 0x3c0) & 0xc0) != 0x40) {
898                                 deactivate(sc);
899                                 if_printf(sc->ifp, "carrier lost\n");
900                         }
901                 }
902
903                 p->intr_host = 0;
904                 t = p->intr_host;
905                 p->out_ack = 0;
906         } else {
907                 wakeup(sc);
908
909                 p->intr_host = 0;
910                 t = p->intr_host;
911         }
912 }
913
914 /* -------------------------------------------------------------------------- */
915
916 static int
917 start_cx28975(struct sbsh_softc *sc, struct cx28975_cfg cfg)
918 {
919         static char  thresh[] = { +8, -4, -16, -40 };
920
921         volatile struct cx28975_cmdarea  *p = sc->cmdp;
922         u_int8_t  t, parm[12];
923
924         p->intr_host = 0;
925         t = p->intr_host;
926
927         /* reset chip set */
928         sc->regs->IMR = EXT;
929         sc->regs->CR  = 0;
930         sc->regs->SR  = 0xff;
931         DELAY(2);
932         sc->regs->CR = XRST;
933         if (cfg.crc16)
934                 sc->regs->CR |= CMOD;
935         if (cfg.fill_7e)
936                 sc->regs->CR |= FMOD;
937         if (cfg.inv)
938                 sc->regs->CR |= PMOD;
939
940         sc->regs->CRB |= RODD | RXDE;
941         if (cfg.rburst)
942                 sc->regs->CRB |= RDBE;
943         if (cfg.wburst)
944                 sc->regs->CRB |= WTBE;
945
946         tsleep(sc, PWAIT, "sbsh", 0);
947         if ((p->out_ack & 0x1f) != _ACK_BOOT_WAKE_UP)
948                 return (-1);
949
950         if (download_firmware(sc, cfg.firmw_image, cfg.firmw_len))
951                 return (-1);
952
953         tsleep(sc, PWAIT, "sbsh", 0);
954         if ((p->out_ack & 0x1f) != _ACK_OPER_WAKE_UP)
955                 return (-1);
956
957         t = cfg.master ? 1 : 9;
958         if (issue_cx28975_cmd(sc, _DSL_SYSTEM_ENABLE, &t, 1))
959                 return (-1);
960
961         t = 0x63;
962         if (issue_cx28975_cmd(sc, _DSL_SYSTEM_CONFIG, &t, 1))
963                 return (-1);
964
965         *(u_int16_t *)parm = cfg.lrate >> 3;
966         parm[2] = parm[3] = parm[0];
967         parm[5] = cfg.lrate & 7;
968         parm[4] = parm[7] = 1;
969         parm[6] = 0;
970         if (issue_cx28975_cmd(sc, _DSL_MULTI_RATE_CONFIG, parm, 8))
971                 return (-1);
972
973         parm[0] = 0x02 | (cfg.mod << 4);
974         parm[1] = 0;
975         if (issue_cx28975_cmd(sc, _DSL_TRAINING_MODE, parm, 2))
976                 return (-1);
977
978         bzero(parm, 12);
979         parm[0] = 0x04;         /* pre-activation: G.hs */
980         parm[4] = 0x04;         /* no remote configuration */
981         parm[7] = 0x01;         /* annex A (default) */
982         parm[8] = 0xff;         /* i-bit mask (all bits) */
983         if (issue_cx28975_cmd(sc, _DSL_PREACTIVATION_CFG, parm, 12))
984                 return (-1);
985
986         parm[0] = 0x03;         /* dying gasp time - 3 frames */
987         parm[1] = thresh[cfg.mod];
988         parm[2] = 0xff;         /* attenuation */
989         parm[3] = 0x04;         /* line probe NMR (+2 dB) */
990         parm[4] = 0x00;         /* reserved */
991         parm[5] = 0x00;
992         if (issue_cx28975_cmd(sc, _DSL_THRESHOLDS, parm, 6))
993                 return (-1);
994
995         t = cfg.master ? 0x23 : 0x21;
996         if (issue_cx28975_cmd(sc, _DSL_FR_PCM_CONFIG, &t, 1))
997                 return (-1);
998
999         t = 0x02;
1000         if (issue_cx28975_cmd(sc, _DSL_INTR_HOST_MASK, &t, 1))
1001                 return (-1);
1002
1003         sc->state = DOWN;
1004         return (0);
1005 }
1006
1007 static int
1008 download_firmware(struct sbsh_softc *sc, u_int8_t *img, u_int32_t img_len)
1009 {
1010         u_int32_t       t;
1011         int             i;
1012         u_int8_t        cksum = 0;
1013
1014         for (i = 0; i < img_len; ++i)
1015                 cksum += img[i];
1016
1017         t = img_len;
1018         if (issue_cx28975_cmd(sc, _DSL_DOWNLOAD_START, (u_int8_t *) &t, 4))
1019                 return (-1);
1020
1021         for (i = 0; img_len >= 75; i += 75, img_len -= 75) {
1022                 if (issue_cx28975_cmd(sc, _DSL_DOWNLOAD_DATA, img + i, 75))
1023                         return (-1);
1024         }
1025
1026         if (img_len
1027             &&  issue_cx28975_cmd(sc, _DSL_DOWNLOAD_DATA, img + i, img_len))
1028                 return (-1);
1029
1030         t = (cksum ^ 0xff) + 1;
1031         if (issue_cx28975_cmd(sc, _DSL_DOWNLOAD_END, (u_int8_t *) &t, 1))
1032                 return (-1);
1033
1034         return (0);
1035 }
1036
1037 static int
1038 issue_cx28975_cmd(struct sbsh_softc *sc, u_int8_t cmd,
1039                         u_int8_t *data, u_int8_t size)
1040 {
1041         volatile struct cx28975_cmdarea  *p = sc->cmdp;
1042         volatile u_int8_t  *databuf = p->in_data;
1043         int  i;
1044
1045         u_int8_t  cksum = 0;
1046
1047         p->in_dest      = 0xf0;
1048         p->in_opcode    = cmd;
1049         p->in_zero      = 0;
1050         p->in_length    = --size;
1051         p->in_csum      = 0xf0 ^ cmd ^ size ^ 0xaa;
1052
1053         for (i = 0; i <= size; ++i) {
1054                 cksum ^= *data;
1055                 *databuf++ = *data++;   /* only 1 byte per cycle! */
1056         }
1057
1058         p->in_datasum   = cksum ^ 0xaa;
1059         p->out_ack      = _ACK_NOT_COMPLETE;
1060         p->intr_8051    = 0xfe;
1061
1062         if (tsleep(sc, PWAIT, "sbsh", hz << 3))
1063                 return (-1);
1064
1065         while (p->out_ack == _ACK_NOT_COMPLETE)
1066                 ;                                       /* FIXME ! */
1067
1068         if ((p->out_ack & 0x1f) == _ACK_PASS) {
1069                 p->out_ack = 0;
1070                 return (0);
1071         } else {
1072                 p->out_ack = 0;
1073                 return (-1);
1074         }
1075 }