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