1 /*
2 * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
3 * Author: Denis I.Timofeev <timofeev@granch.ru>
4 *
5 * Redistributon 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 unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: src/sys/dev/sbni/if_sbni.c,v 1.1.2.4 2002/08/11 09:32:00 fjoe Exp $
28 */
29
30 /*
31 * Device driver for Granch SBNI12 leased line adapters
32 *
33 * Revision 2.0.0 1997/08/06
34 * Initial revision by Alexey Zverev
35 *
36 * Revision 2.0.1 1997/08/11
37 * Additional internal statistics support (tx statistics)
38 *
39 * Revision 2.0.2 1997/11/05
40 * if_bpf bug has been fixed
41 *
42 * Revision 2.0.3 1998/12/20
43 * Memory leakage has been eliminated in
44 * the sbni_st and sbni_timeout routines.
45 *
46 * Revision 3.0 2000/08/10 by Yaroslav Polyakov
47 * Support for PCI cards. 4.1 modification.
48 *
49 * Revision 3.1 2000/09/12
50 * Removed extra #defines around bpf functions
51 *
52 * Revision 4.0 2000/11/23 by Denis Timofeev
53 * Completely redesigned the buffer management
54 *
55 * Revision 4.1 2001/01/21
56 * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards
57 *
58 * Written with reference to NE2000 driver developed by David Greenman.
59 */
60
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/socket.h>
65 #include <sys/sockio.h>
66 #include <sys/mbuf.h>
67 #include <sys/kernel.h>
68 #include <sys/proc.h>
69 #include <sys/priv.h>
70 #include <sys/callout.h>
71 #include <sys/syslog.h>
72 #include <sys/random.h>
73 #include <sys/bus.h>
74 #include <sys/rman.h>
75 #include <sys/thread2.h>
76
77 #include <net/if.h>
78 #include <net/ifq_var.h>
79 #include <net/ethernet.h>
80 #include <net/if_arp.h>
81 #include <net/bpf.h>
82
83 #include "if_sbnireg.h"
84 #include "if_sbnivar.h"
85
86 #ifdef __i386__
87 #define ASM_CRC 1
88 #endif
89
90 static void sbni_init(void *);
91 static void sbni_start(struct ifnet *, struct ifaltq_subque *);
92 static int sbni_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
93 static void sbni_watchdog(struct ifnet *);
94 static void sbni_stop(struct sbni_softc *);
95 static void handle_channel(struct sbni_softc *);
96
97 static void card_start(struct sbni_softc *);
98 static int recv_frame(struct sbni_softc *);
99 static void send_frame(struct sbni_softc *);
100 static int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t);
101 static int skip_tail(struct sbni_softc *, u_int, u_int32_t);
102 static void interpret_ack(struct sbni_softc *, u_int);
103 static void download_data(struct sbni_softc *, u_int32_t *);
104 static void prepare_to_send(struct sbni_softc *);
105 static void drop_xmit_queue(struct sbni_softc *);
106 static int get_rx_buf(struct sbni_softc *);
107 static void indicate_pkt(struct sbni_softc *);
108 static void change_level(struct sbni_softc *);
109 static int check_fhdr(struct sbni_softc *, u_int *, u_int *,
110 u_int *, u_int *, u_int32_t *);
111 static int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t);
112 static void timeout_change_level(struct sbni_softc *);
113 static void send_frame_header(struct sbni_softc *, u_int32_t *);
114 static void set_initial_values(struct sbni_softc *, struct sbni_flags);
115
116 static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int);
117 static timeout_t sbni_timeout;
118
119 static __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg);
120 static __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char);
121 static __inline void sbni_insb(struct sbni_softc *, u_char *, u_int);
122 static __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int);
123
124 DECLARE_DUMMY_MODULE(if_sbni);
125
126 static u_int32_t crc32tab[];
127
128 #ifdef SBNI_DUAL_COMPOUND
129 struct sbni_softc *sbni_headlist;
130 #endif
131
132 u_int32_t next_sbni_unit;
133
134 /* -------------------------------------------------------------------------- */
135
136 static __inline u_char
137 sbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
138 {
139 return bus_space_read_1(
140 rman_get_bustag(sc->io_res),
141 rman_get_bushandle(sc->io_res),
142 sc->io_off + reg);
143 }
144
145 static __inline void
146 sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
147 {
148 bus_space_write_1(
149 rman_get_bustag(sc->io_res),
150 rman_get_bushandle(sc->io_res),
151 sc->io_off + reg, value);
152 }
153
154 static __inline void
155 sbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
156 {
157 bus_space_read_multi_1(
158 rman_get_bustag(sc->io_res),
159 rman_get_bushandle(sc->io_res),
160 sc->io_off + DAT, to, len);
161 }
162
163 static __inline void
164 sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
165 {
166 bus_space_write_multi_1(
167 rman_get_bustag(sc->io_res),
168 rman_get_bushandle(sc->io_res),
169 sc->io_off + DAT, from, len);
170 }
171
172
173 /*
174 Valid combinations in CSR0 (for probing):
175
176 VALID_DECODER 0000,0011,1011,1010
177
178 ; 0 ; -
179 TR_REQ ; 1 ; +
180 TR_RDY ; 2 ; -
181 TR_RDY TR_REQ ; 3 ; +
182 BU_EMP ; 4 ; +
183 BU_EMP TR_REQ ; 5 ; +
184 BU_EMP TR_RDY ; 6 ; -
185 BU_EMP TR_RDY TR_REQ ; 7 ; +
186 RC_RDY ; 8 ; +
187 RC_RDY TR_REQ ; 9 ; +
188 RC_RDY TR_RDY ; 10 ; -
189 RC_RDY TR_RDY TR_REQ ; 11 ; -
190 RC_RDY BU_EMP ; 12 ; -
191 RC_RDY BU_EMP TR_REQ ; 13 ; -
192 RC_RDY BU_EMP TR_RDY ; 14 ; -
193 RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
194 */
195
196 #define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
197
198
199 int
200 sbni_probe(struct sbni_softc *sc)
201 {
202 u_char csr0;
203
204 csr0 = sbni_inb(sc, CSR0);
205 if (csr0 != 0xff && csr0 != 0x00) {
206 csr0 &= ~EN_INT;
207 if (csr0 & BU_EMP)
208 csr0 |= EN_INT;
209
210 if (VALID_DECODER & (1 << (csr0 >> 4)))
211 return (0);
212 }
213
214 return (ENXIO);
215 }
216
217
218 /*
219 * Install interface into kernel networking data structures
220 */
221 void
222 sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
223 {
224 struct ifnet *ifp;
225 u_char csr0;
226
227 ifp = &sc->arpcom.ac_if;
228 sbni_outb(sc, CSR0, 0);
229 set_initial_values(sc, flags);
230
231 callout_init(&sc->sbni_stat_timer);
232 /* Initialize ifnet structure */
233 ifp->if_softc = sc;
234 if_initname(ifp, "sbni", unit);
235 ifp->if_init = sbni_init;
236 ifp->if_start = sbni_start;
237 ifp->if_ioctl = sbni_ioctl;
238 ifp->if_watchdog = sbni_watchdog;
239 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
240 ifq_set_ready(&ifp->if_snd);
241
242 /* report real baud rate */
243 csr0 = sbni_inb(sc, CSR0);
244 ifp->if_baudrate =
245 (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
246
247 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
248 ether_ifattach(ifp, sc->arpcom.ac_enaddr, NULL);
249
250 /* device attach does transition from UNCONFIGURED to IDLE state */
251
252 if_printf(ifp, "speed %ju, rxl ", (uintmax_t)ifp->if_baudrate);
253 if (sc->delta_rxl)
254 kprintf("auto\n");
255 else
256 kprintf("%d (fixed)\n", sc->cur_rxl_index);
257 }
258
259 /* -------------------------------------------------------------------------- */
260
261 static void
262 sbni_init(void *xsc)
263 {
264 struct sbni_softc *sc =xsc;
265 struct ifnet *ifp = &sc->arpcom.ac_if;
266
267 /*
268 * kludge to avoid multiple initialization when more than once
269 * protocols configured
270 */
271 if (ifp->if_flags & IFF_RUNNING)
272 return;
273 ifp->if_timer = 0;
274 card_start(sc);
275 callout_reset(&sc->sbni_stat_timer,hz / SBNI_HZ, sbni_timeout, sc);
276
277 ifp->if_flags |= IFF_RUNNING;
278 ifq_clr_oactive(&ifp->if_snd);
279
280 /* attempt to start output */
281 if_devstart(ifp);
282 }
283
284
285 static void
286 sbni_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
287 {
288 struct sbni_softc *sc = ifp->if_softc;
289
290 ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
291 if (sc->tx_frameno == 0)
292 prepare_to_send(sc);
293 }
294
295
296 static void
297 sbni_stop(struct sbni_softc *sc)
298 {
299 sbni_outb(sc, CSR0, 0);
300 drop_xmit_queue(sc);
301
302 if (sc->rx_buf_p) {
303 m_freem(sc->rx_buf_p);
304 sc->rx_buf_p = NULL;
305 }
306
307 callout_stop(&sc->sbni_stat_timer);
308 }
309
310 /* -------------------------------------------------------------------------- */
311
312 /* interrupt handler */
313
314 /*
315 * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
316 * be looked as two independent single-channel devices. Every channel seems
317 * as Ethernet interface but interrupt handler must be common. Really, first
318 * channel ("master") driver only registers the handler. In it's struct softc
319 * it has got pointer to "slave" channel's struct softc and handles that's
320 * interrupts too.
321 * softc of successfully attached ISA SBNI boards is linked to list.
322 * While next board driver is initialized, it scans this list. If one
323 * has found softc with same irq and ioaddr different by 4 then it assumes
324 * this board to be "master".
325 */
326
327 void
328 sbni_intr(void *arg)
329 {
330 struct sbni_softc *sc;
331 int repeat;
332
333 sc = (struct sbni_softc *)arg;
334
335 do {
336 repeat = 0;
337 if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
338 handle_channel(sc);
339 repeat = 1;
340 }
341 if (sc->slave_sc && /* second channel present */
342 (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) {
343 handle_channel(sc->slave_sc);
344 repeat = 1;
345 }
346 } while (repeat);
347 }
348
349
350 static void
351 handle_channel(struct sbni_softc *sc)
352 {
353 int req_ans;
354 u_char csr0;
355
356 sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
357
358 sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
359 for (;;) {
360 csr0 = sbni_inb(sc, CSR0);
361 if ((csr0 & (RC_RDY | TR_RDY)) == 0)
362 break;
363
364 req_ans = !(sc->state & FL_PREV_OK);
365
366 if (csr0 & RC_RDY)
367 req_ans = recv_frame(sc);
368
369 /*
370 * TR_RDY always equals 1 here because we have owned the marker,
371 * and we set TR_REQ when disabled interrupts
372 */
373 csr0 = sbni_inb(sc, CSR0);
374 if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
375 kprintf("sbni: internal error!\n");
376
377 /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
378 if (req_ans || sc->tx_frameno != 0)
379 send_frame(sc);
380 else {
381 /* send the marker without any data */
382 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
383 }
384 }
385
386 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
387 }
388
389
390 /*
391 * Routine returns 1 if it need to acknoweledge received frame.
392 * Empty frame received without errors won't be acknoweledged.
393 */
394
395 static int
396 recv_frame(struct sbni_softc *sc)
397 {
398 u_int32_t crc;
399 u_int framelen, frameno, ack;
400 u_int is_first, frame_ok;
401
402 crc = CRC32_INITIAL;
403 framelen = 0;
404 if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
405 frame_ok = framelen > 4 ?
406 upload_data(sc, framelen, frameno, is_first, crc) :
407 skip_tail(sc, framelen, crc);
408 if (frame_ok)
409 interpret_ack(sc, ack);
410 } else
411 frame_ok = 0;
412
413 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
414 if (frame_ok) {
415 sc->state |= FL_PREV_OK;
416 if (framelen > 4)
417 sc->in_stats.all_rx_number++;
418 } else {
419 sc->state &= ~FL_PREV_OK;
420 change_level(sc);
421 sc->in_stats.all_rx_number++;
422 sc->in_stats.bad_rx_number++;
423 }
424
425 return (!frame_ok || framelen > 4);
426 }
427
428
429 static void
430 send_frame(struct sbni_softc *sc)
431 {
432 u_int32_t crc;
433 u_char csr0;
434
435 crc = CRC32_INITIAL;
436 if (sc->state & FL_NEED_RESEND) {
437
438 /* if frame was sended but not ACK'ed - resend it */
439 if (sc->trans_errors) {
440 sc->trans_errors--;
441 if (sc->framelen != 0)
442 sc->in_stats.resend_tx_number++;
443 } else {
444 /* cannot xmit with many attempts */
445 drop_xmit_queue(sc);
446 goto do_send;
447 }
448 } else
449 sc->trans_errors = TR_ERROR_COUNT;
450
451 send_frame_header(sc, &crc);
452 sc->state |= FL_NEED_RESEND;
453 /*
454 * FL_NEED_RESEND will be cleared after ACK, but if empty
455 * frame sended then in prepare_to_send next frame
456 */
457
458
459 if (sc->framelen) {
460 download_data(sc, &crc);
461 sc->in_stats.all_tx_number++;
462 sc->state |= FL_WAIT_ACK;
463 }
464
465 sbni_outsb(sc, (u_char *)&crc, sizeof crc);
466
467 do_send:
468 csr0 = sbni_inb(sc, CSR0);
469 sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
470
471 if (sc->tx_frameno) {
472 /* next frame exists - request to send */
473 sbni_outb(sc, CSR0, csr0 | TR_REQ);
474 }
475 }
476
477
478 static void
479 download_data(struct sbni_softc *sc, u_int32_t *crc_p)
480 {
481 struct mbuf *m;
482 caddr_t data_p;
483 u_int data_len, pos, slice;
484
485 data_p = NULL; /* initialized to avoid warn */
486 pos = 0;
487
488 for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) {
489 if (pos + m->m_len > sc->outpos) {
490 data_len = m->m_len - (sc->outpos - pos);
491 data_p = mtod(m, caddr_t) + (sc->outpos - pos);
492
493 goto do_copy;
494 } else
495 pos += m->m_len;
496 }
497
498 data_len = 0;
499
500 do_copy:
501 pos = 0;
502 do {
503 if (data_len) {
504 slice = min(data_len, sc->framelen - pos);
505 sbni_outsb(sc, data_p, slice);
506 *crc_p = calc_crc32(*crc_p, data_p, slice);
507
508 pos += slice;
509 if (data_len -= slice)
510 data_p += slice;
511 else {
512 do {
513 m = m->m_next;
514 } while (m != NULL && m->m_len == 0);
515
516 if (m) {
517 data_len = m->m_len;
518 data_p = mtod(m, caddr_t);
519 }
520 }
521 } else {
522 /* frame too short - zero padding */
523
524 pos = sc->framelen - pos;
525 while (pos--) {
526 sbni_outb(sc, DAT, 0);
527 *crc_p = CRC32(0, *crc_p);
528 }
529 return;
530 }
531 } while (pos < sc->framelen);
532 }
533
534
535 static int
536 upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
537 u_int is_first, u_int32_t crc)
538 {
539 int frame_ok;
540
541 if (is_first) {
542 sc->wait_frameno = frameno;
543 sc->inppos = 0;
544 }
545
546 if (sc->wait_frameno == frameno) {
547
548 if (sc->inppos + framelen <= ETHER_MAX_LEN) {
549 frame_ok = append_frame_to_pkt(sc, framelen, crc);
550
551 /*
552 * if CRC is right but framelen incorrect then transmitter
553 * error was occured... drop entire packet
554 */
555 } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
556 sc->wait_frameno = 0;
557 sc->inppos = 0;
558 IFNET_STAT_INC(&sc->arpcom.ac_if, ierrors, 1);
559 /* now skip all frames until is_first != 0 */
560 }
561 } else
562 frame_ok = skip_tail(sc, framelen, crc);
563
564 if (is_first && !frame_ok) {
565 /*
566 * Frame has been violated, but we have stored
567 * is_first already... Drop entire packet.
568 */
569 sc->wait_frameno = 0;
570 IFNET_STAT_INC(&sc->arpcom.ac_if, ierrors, 1);
571 }
572
573 return (frame_ok);
574 }
575
576
577 static __inline void send_complete(struct sbni_softc *);
578
579 static __inline void
580 send_complete(struct sbni_softc *sc)
581 {
582 m_freem(sc->tx_buf_p);
583 sc->tx_buf_p = NULL;
584 IFNET_STAT_INC(&sc->arpcom.ac_if, opackets, 1);
585 }
586
587
588 static void
589 interpret_ack(struct sbni_softc *sc, u_int ack)
590 {
591 if (ack == FRAME_SENT_OK) {
592 sc->state &= ~FL_NEED_RESEND;
593
594 if (sc->state & FL_WAIT_ACK) {
595 sc->outpos += sc->framelen;
596
597 if (--sc->tx_frameno) {
598 sc->framelen = min(
599 sc->maxframe, sc->pktlen - sc->outpos);
600 } else {
601 send_complete(sc);
602 prepare_to_send(sc);
603 }
604 }
605 }
606
607 sc->state &= ~FL_WAIT_ACK;
608 }
609
610
611 /*
612 * Glue received frame with previous fragments of packet.
613 * Indicate packet when last frame would be accepted.
614 */
615
616 static int
617 append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
618 {
619 caddr_t p;
620
621 if (sc->inppos + framelen > ETHER_MAX_LEN)
622 return (0);
623
624 if (!sc->rx_buf_p && !get_rx_buf(sc))
625 return (0);
626
627 p = sc->rx_buf_p->m_data + sc->inppos;
628 sbni_insb(sc, p, framelen);
629 if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
630 return (0);
631
632 sc->inppos += framelen - 4;
633 if (--sc->wait_frameno == 0) { /* last frame received */
634 indicate_pkt(sc);
635 IFNET_STAT_INC(&sc->arpcom.ac_if, ipackets, 1);
636 }
637
638 return (1);
639 }
640
641
642 /*
643 * Prepare to start output on adapter.
644 * Transmitter will be actually activated when marker has been accepted.
645 */
646
647 static void
648 prepare_to_send(struct sbni_softc *sc)
649 {
650 struct mbuf *m;
651 u_int len;
652
653 /* sc->tx_buf_p == NULL here! */
654 if (sc->tx_buf_p)
655 kprintf("sbni: memory leak!\n");
656
657 sc->outpos = 0;
658 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
659
660 for (;;) {
661 sc->tx_buf_p = ifq_dequeue(&sc->arpcom.ac_if.if_snd);
662 if (sc->tx_buf_p == NULL) {
663 /* nothing to transmit... */
664 sc->pktlen = 0;
665 sc->tx_frameno = 0;
666 sc->framelen = 0;
667 ifq_clr_oactive(&sc->arpcom.ac_if.if_snd);
668 return;
669 }
670
671 for (len = 0, m = sc->tx_buf_p; m; m = m->m_next)
672 len += m->m_len;
673
674 if (len != 0)
675 break;
676 m_freem(sc->tx_buf_p);
677 }
678
679 if (len < SBNI_MIN_LEN)
680 len = SBNI_MIN_LEN;
681
682 sc->pktlen = len;
683 sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe;
684 sc->framelen = min(len, sc->maxframe);
685
686 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
687 ifq_set_oactive(&sc->arpcom.ac_if.if_snd);
688 BPF_MTAP(&sc->arpcom.ac_if, sc->tx_buf_p);
689 }
690
691
692 static void
693 drop_xmit_queue(struct sbni_softc *sc)
694 {
695 if (sc->tx_buf_p) {
696 m_freem(sc->tx_buf_p);
697 sc->tx_buf_p = NULL;
698 IFNET_STAT_INC(&sc->arpcom.ac_if, oerrors, 1);
699 }
700
701 ifq_purge(&sc->arpcom.ac_if.if_snd);
702
703 sc->tx_frameno = 0;
704 sc->framelen = 0;
705 sc->outpos = 0;
706 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
707 ifq_clr_oactive(&sc->arpcom.ac_if.if_snd);
708 }
709
710
711 static void
712 send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
713 {
714 u_int32_t crc;
715 u_int len_field;
716 u_char value;
717
718 crc = *crc_p;
719 len_field = sc->framelen + 6; /* CRC + frameno + reserved */
720
721 if (sc->state & FL_NEED_RESEND)
722 len_field |= FRAME_RETRY; /* non-first attempt... */
723
724 if (sc->outpos == 0)
725 len_field |= FRAME_FIRST;
726
727 len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
728 sbni_outb(sc, DAT, SBNI_SIG);
729
730 value = (u_char)len_field;
731 sbni_outb(sc, DAT, value);
732 crc = CRC32(value, crc);
733 value = (u_char)(len_field >> 8);
734 sbni_outb(sc, DAT, value);
735 crc = CRC32(value, crc);
736
737 sbni_outb(sc, DAT, sc->tx_frameno);
738 crc = CRC32(sc->tx_frameno, crc);
739 sbni_outb(sc, DAT, 0);
740 crc = CRC32(0, crc);
741 *crc_p = crc;
742 }
743
744
745 /*
746 * if frame tail not needed (incorrect number or received twice),
747 * it won't store, but CRC will be calculated
748 */
749
750 static int
751 skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
752 {
753 while (tail_len--)
754 crc = CRC32(sbni_inb(sc, DAT), crc);
755
756 return (crc == CRC32_REMAINDER);
757 }
758
759
760 static int
761 check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
762 u_int *ack, u_int *is_first, u_int32_t *crc_p)
763 {
764 u_int32_t crc;
765 u_char value;
766
767 crc = *crc_p;
768 if (sbni_inb(sc, DAT) != SBNI_SIG)
769 return (0);
770
771 value = sbni_inb(sc, DAT);
772 *framelen = (u_int)value;
773 crc = CRC32(value, crc);
774 value = sbni_inb(sc, DAT);
775 *framelen |= ((u_int)value) << 8;
776 crc = CRC32(value, crc);
777
778 *ack = *framelen & FRAME_ACK_MASK;
779 *is_first = (*framelen & FRAME_FIRST) != 0;
780
781 if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
782 return (0);
783
784 value = sbni_inb(sc, DAT);
785 *frameno = (u_int)value;
786 crc = CRC32(value, crc);
787
788 crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */
789 *framelen -= 2;
790
791 *crc_p = crc;
792 return (1);
793 }
794
795
796 static int
797 get_rx_buf(struct sbni_softc *sc)
798 {
799 struct mbuf *m;
800
801 MGETHDR(m, MB_DONTWAIT, MT_DATA);
802 if (m == NULL) {
803 kprintf("%s: cannot allocate header mbuf\n",
804 sc->arpcom.ac_if.if_xname);
805 return (0);
806 }
807
808 /*
809 * We always put the received packet in a single buffer -
810 * either with just an mbuf header or in a cluster attached
811 * to the header. The +2 is to compensate for the alignment
812 * fixup below.
813 */
814 if (ETHER_MAX_LEN + 2 > MHLEN) {
815 /* Attach an mbuf cluster */
816 MCLGET(m, MB_DONTWAIT);
817 if ((m->m_flags & M_EXT) == 0) {
818 m_freem(m);
819 return (0);
820 }
821 }
822 m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2;
823
824 /*
825 * The +2 is to longword align the start of the real packet.
826 * (sizeof ether_header == 14)
827 * This is important for NFS.
828 */
829 m_adj(m, 2);
830 sc->rx_buf_p = m;
831 return (1);
832 }
833
834
835 static void
836 indicate_pkt(struct sbni_softc *sc)
837 {
838 struct ifnet *ifp = &sc->arpcom.ac_if;
839 struct mbuf *m;
840
841 m = sc->rx_buf_p;
842 m->m_pkthdr.rcvif = ifp;
843 m->m_pkthdr.len = m->m_len = sc->inppos;
844
845 ifp->if_input(ifp, m);
846 sc->rx_buf_p = NULL;
847 }
848
849 /* -------------------------------------------------------------------------- */
850
851 /*
852 * Routine checks periodically wire activity and regenerates marker if
853 * connect was inactive for a long time.
854 */
855
856 static void
857 sbni_timeout(void *xsc)
858 {
859 struct sbni_softc *sc = xsc;
860 u_char csr0;
861
862 lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer);
863
864 csr0 = sbni_inb(sc, CSR0);
865 if (csr0 & RC_CHK) {
866
867 if (sc->timer_ticks) {
868 if (csr0 & (RC_RDY | BU_EMP))
869 /* receiving not active */
870 sc->timer_ticks--;
871 } else {
872 sc->in_stats.timeout_number++;
873 if (sc->delta_rxl)
874 timeout_change_level(sc);
875
876 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
877 csr0 = sbni_inb(sc, CSR0);
878 }
879 }
880
881 sbni_outb(sc, CSR0, csr0 | RC_CHK);
882 callout_reset(&sc->sbni_stat_timer, hz / SBNI_HZ, sbni_timeout, sc);
883
884 lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer);
885 }
886
887 /* -------------------------------------------------------------------------- */
888
889 static void
890 card_start(struct sbni_softc *sc)
891 {
892 sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
893 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
894 sc->state |= FL_PREV_OK;
895
896 sc->inppos = 0;
897 sc->wait_frameno = 0;
898
899 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
900 sbni_outb(sc, CSR0, EN_INT);
901 }
902
903 /* -------------------------------------------------------------------------- */
904
905 /*
906 * Device timeout/watchdog routine. Entered if the device neglects to
907 * generate an interrupt after a transmit has been started on it.
908 */
909
910 static void
911 sbni_watchdog(struct ifnet *ifp)
912 {
913 log(LOG_ERR, "%s: device timeout\n", ifp->if_xname);
914 IFNET_STAT_INC(ifp, oerrors, 1);
915 }
916
917
918 static u_char rxl_tab[] = {
919 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
920 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
921 };
922
923 #define SIZE_OF_TIMEOUT_RXL_TAB 4
924 static u_char timeout_rxl_tab[] = {
925 0x03, 0x05, 0x08, 0x0b
926 };
927
928 static void
929 set_initial_values(struct sbni_softc *sc, struct sbni_flags flags)
930 {
931 if (flags.fixed_rxl) {
932 sc->delta_rxl = 0; /* disable receive level autodetection */
933 sc->cur_rxl_index = flags.rxl;
934 } else {
935 sc->delta_rxl = DEF_RXL_DELTA;
936 sc->cur_rxl_index = DEF_RXL;
937 }
938
939 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
940 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
941 sc->maxframe = DEFAULT_FRAME_LEN;
942
943 /*
944 * generate Ethernet address (0x00ff01xxxxxx)
945 */
946 *(u_int16_t *) sc->arpcom.ac_enaddr = htons(0x00ff);
947 if (flags.mac_addr) {
948 *(u_int32_t *) (sc->arpcom.ac_enaddr + 2) =
949 htonl(flags.mac_addr | 0x01000000);
950 } else {
951 *(u_char *) (sc->arpcom.ac_enaddr + 2) = 0x01;
952 read_random_unlimited(sc->arpcom.ac_enaddr + 3, 3);
953 }
954 }
955
956
957 #ifdef SBNI_DUAL_COMPOUND
958
959 struct sbni_softc *
960 connect_to_master(struct sbni_softc *sc)
961 {
962 struct sbni_softc *p, *p_prev;
963
964 for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) {
965 if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 ||
966 rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) {
967 p->slave_sc = sc;
968 if (p_prev)
969 p_prev->link = p->link;
970 else
971 sbni_headlist = p->link;
972 return p;
973 }
974 }
975
976 return (NULL);
977 }
978
979 #endif /* SBNI_DUAL_COMPOUND */
980
981
982 /* Receive level auto-selection */
983
984 static void
985 change_level(struct sbni_softc *sc)
986 {
987 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */
988 return;
989
990 if (sc->cur_rxl_index == 0)
991 sc->delta_rxl = 1;
992 else if (sc->cur_rxl_index == 15)
993 sc->delta_rxl = -1;
994 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd)
995 sc->delta_rxl = -sc->delta_rxl;
996
997 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl];
998 sbni_inb(sc, CSR0); /* it needed for PCI cards */
999 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
1000
1001 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
1002 sc->cur_rxl_rcvd = 0;
1003 }
1004
1005
1006 static void
1007 timeout_change_level(struct sbni_softc *sc)
1008 {
1009 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl];
1010 if (++sc->timeout_rxl >= 4)
1011 sc->timeout_rxl = 0;
1012
1013 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
1014 sbni_inb(sc, CSR0);
1015 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
1016
1017 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
1018 sc->cur_rxl_rcvd = 0;
1019 }
1020
1021 /* -------------------------------------------------------------------------- */
1022
1023 /*
1024 * Process an ioctl request. This code needs some work - it looks
1025 * pretty ugly.
1026 */
1027
1028 static int
1029 sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
1030 {
1031 struct sbni_softc *sc;
1032 struct ifreq *ifr;
1033 struct sbni_in_stats *in_stats;
1034 struct sbni_flags flags;
1035 int error;
1036
1037 sc = ifp->if_softc;
1038 ifr = (struct ifreq *)data;
1039 error = 0;
1040
1041 switch (command) {
1042 case SIOCSIFFLAGS:
1043 /*
1044 * If the interface is marked up and stopped, then start it.
1045 * If it is marked down and running, then stop it.
1046 */
1047 if (ifp->if_flags & IFF_UP) {
1048 if (!(ifp->if_flags & IFF_RUNNING))
1049 sbni_init(sc);
1050 } else {
1051 if (ifp->if_flags & IFF_RUNNING) {
1052 sbni_stop(sc);
1053 ifp->if_flags &= ~IFF_RUNNING;
1054 }
1055 }
1056 break;
1057
1058 case SIOCADDMULTI:
1059 case SIOCDELMULTI:
1060 /*
1061 * Multicast list has changed; set the hardware filter
1062 * accordingly.
1063 */
1064 error = 0;
1065 /* if (ifr == NULL)
1066 error = EAFNOSUPPORT; */
1067 break;
1068
1069 case SIOCSIFMTU:
1070 if (ifr->ifr_mtu > ETHERMTU)
1071 error = EINVAL;
1072 else
1073 ifp->if_mtu = ifr->ifr_mtu;
1074 break;
1075
1076 /*
1077 * SBNI specific ioctl
1078 */
1079 case SIOCGHWFLAGS: /* get flags */
1080 bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3);
1081 flags.rxl = sc->cur_rxl_index;
1082 flags.rate = sc->csr1.rate;
1083 flags.fixed_rxl = (sc->delta_rxl == 0);
1084 flags.fixed_rate = 1;
1085 ifr->ifr_data = *(caddr_t*) &flags;
1086 break;
1087
1088 case SIOCGINSTATS:
1089 in_stats = (struct sbni_in_stats *)ifr->ifr_data;
1090 bcopy((void *)(&(sc->in_stats)), (void *)in_stats,
1091 sizeof(struct sbni_in_stats));
1092 break;
1093
1094 case SIOCSHWFLAGS: /* set flags */
1095 /* root only */
1096 error = priv_check_cred(cr, PRIV_ROOT, NULL_CRED_OKAY);
1097 /* NOTE: returns EPERM if no proc */
1098 if (error)
1099 break;
1100 flags = *(struct sbni_flags*)&ifr->ifr_data;
1101 if (flags.fixed_rxl) {
1102 sc->delta_rxl = 0;
1103 sc->cur_rxl_index = flags.rxl;
1104 } else {
1105 sc->delta_rxl = DEF_RXL_DELTA;
1106 sc->cur_rxl_index = DEF_RXL;
1107 }
1108 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
1109 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
1110 if (flags.mac_addr)
1111 bcopy((caddr_t) &flags,
1112 (caddr_t) sc->arpcom.ac_enaddr+3, 3);
1113
1114 /* Don't be afraid... */
1115 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES);
1116 break;
1117
1118 case SIOCRINSTATS:
1119 if (!(error = priv_check_cred(cr, PRIV_ROOT, NULL_CRED_OKAY))) /* root only */
1120 bzero(&sc->in_stats, sizeof(struct sbni_in_stats));
1121 break;
1122
1123 default:
1124 error = ether_ioctl(ifp, command, data);
1125 break;
1126 }
1127 return (error);
1128 }
1129
1130 /* -------------------------------------------------------------------------- */
1131
1132 #ifdef ASM_CRC
1133
1134 static u_int32_t
1135 calc_crc32(u_int32_t crc, caddr_t p, u_int len)
1136 {
1137 u_int32_t _crc;
1138 _crc = crc;
1139
1140 __asm __volatile (
1141 "xorl %%ebx, %%ebx\n"
1142 "movl %1, %%esi\n"
1143 "movl %2, %%ecx\n"
1144 "movl $crc32tab, %%edi\n"
1145 "shrl $2, %%ecx\n"
1146 "jz 1f\n"
1147
1148 ".align 4\n"
1149 "0:\n"
1150 "movb %%al, %%bl\n"
1151 "movl (%%esi), %%edx\n"
1152 "shrl $8, %%eax\n"
1153 "xorb %%dl, %%bl\n"
1154 "shrl $8, %%edx\n"
1155 "xorl (%%edi,%%ebx,4), %%eax\n"
1156
1157 "movb %%al, %%bl\n"
1158 "shrl $8, %%eax\n"
1159 "xorb %%dl, %%bl\n"
1160 "shrl $8, %%edx\n"
1161 "xorl (%%edi,%%ebx,4), %%eax\n"
1162
1163 "movb %%al, %%bl\n"
1164 "shrl $8, %%eax\n"
1165 "xorb %%dl, %%bl\n"
1166 "movb %%dh, %%dl\n"
1167 "xorl (%%edi,%%ebx,4), %%eax\n"
1168
1169 "movb %%al, %%bl\n"
1170 "shrl $8, %%eax\n"
1171 "xorb %%dl, %%bl\n"
1172 "addl $4, %%esi\n"
1173 "xorl (%%edi,%%ebx,4), %%eax\n"
1174
1175 "decl %%ecx\n"
1176 "jnz 0b\n"
1177
1178 "1:\n"
1179 "movl %2, %%ecx\n"
1180 "andl $3, %%ecx\n"
1181 "jz 2f\n"
1182
1183 "movb %%al, %%bl\n"
1184 "shrl $8, %%eax\n"
1185 "xorb (%%esi), %%bl\n"
1186 "xorl (%%edi,%%ebx,4), %%eax\n"
1187
1188 "decl %%ecx\n"
1189 "jz 2f\n"
1190
1191 "movb %%al, %%bl\n"
1192 "shrl $8, %%eax\n"
1193 "xorb 1(%%esi), %%bl\n"
1194 "xorl (%%edi,%%ebx,4), %%eax\n"
1195
1196 "decl %%ecx\n"
1197 "jz 2f\n"
1198
1199 "movb %%al, %%bl\n"
1200 "shrl $8, %%eax\n"
1201 "xorb 2(%%esi), %%bl\n"
1202 "xorl (%%edi,%%ebx,4), %%eax\n"
1203 "2:\n"
1204 :
1205 : "a" (_crc), "g" (p), "g" (len)
1206 : "bx", "cx", "dx", "si", "di"
1207 );
1208
1209 return (_crc);
1210 }
1211
1212 #else /* ASM_CRC */
1213
1214 static u_int32_t
1215 calc_crc32(u_int32_t crc, caddr_t p, u_int len)
1216 {
1217 while (len--)
1218 crc = CRC32(*p++, crc);
1219
1220 return (crc);
1221 }
1222
1223 #endif /* ASM_CRC */
1224
1225
1226 static u_int32_t crc32tab[] __attribute__ ((aligned(8))) = {
1227 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
1228 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
1229 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
1230 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
1231 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
1232 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
1233 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
1234 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
1235 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
1236 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
1237 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
1238 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
1239 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
1240 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
1241 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
1242 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
1243 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
1244 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
1245 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
1246 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
1247 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
1248 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
1249 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
1250 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
1251 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
1252 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
1253 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
1254 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
1255 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
1256 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
1257 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
1258 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
1259 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
1260 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
1261 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
1262 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
1263 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
1264 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
1265 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
1266 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
1267 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
1268 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
1269 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
1270 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
1271 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
1272 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
1273 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
1274 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
1275 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
1276 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
1277 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
1278 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
1279 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
1280 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
1281 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
1282 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
1283 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
1284 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
1285 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
1286 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
1287 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
1288 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
1289 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
1290 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000
1291 };
Cache object: 3c8568737932d8490c25318796e9e70d
|