| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: qe.c,v 1.75 2019/05/29 10:07:30 msaitoh Exp $ */ | | 1 | /* $NetBSD: qe.c,v 1.76 2020/01/29 05:59:06 thorpej Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1999 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1999 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Paul Kranenburg. | | 8 | * by Paul Kranenburg. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -56,27 +56,27 @@ | | | @@ -56,27 +56,27 @@ |
56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 56 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
57 | */ | | 57 | */ |
58 | | | 58 | |
59 | /* | | 59 | /* |
60 | * Driver for the SBus qec+qe QuadEthernet board. | | 60 | * Driver for the SBus qec+qe QuadEthernet board. |
61 | * | | 61 | * |
62 | * This driver was written using the AMD MACE Am79C940 documentation, some | | 62 | * This driver was written using the AMD MACE Am79C940 documentation, some |
63 | * ideas gleaned from the S/Linux driver for this card, Solaris header files, | | 63 | * ideas gleaned from the S/Linux driver for this card, Solaris header files, |
64 | * and a loan of a card from Paul Southworth of the Internet Engineering | | 64 | * and a loan of a card from Paul Southworth of the Internet Engineering |
65 | * Group (www.ieng.com). | | 65 | * Group (www.ieng.com). |
66 | */ | | 66 | */ |
67 | | | 67 | |
68 | #include <sys/cdefs.h> | | 68 | #include <sys/cdefs.h> |
69 | __KERNEL_RCSID(0, "$NetBSD: qe.c,v 1.75 2019/05/29 10:07:30 msaitoh Exp $"); | | 69 | __KERNEL_RCSID(0, "$NetBSD: qe.c,v 1.76 2020/01/29 05:59:06 thorpej Exp $"); |
70 | | | 70 | |
71 | #define QEDEBUG | | 71 | #define QEDEBUG |
72 | | | 72 | |
73 | #include "opt_ddb.h" | | 73 | #include "opt_ddb.h" |
74 | #include "opt_inet.h" | | 74 | #include "opt_inet.h" |
75 | | | 75 | |
76 | #include <sys/param.h> | | 76 | #include <sys/param.h> |
77 | #include <sys/systm.h> | | 77 | #include <sys/systm.h> |
78 | #include <sys/kernel.h> | | 78 | #include <sys/kernel.h> |
79 | #include <sys/errno.h> | | 79 | #include <sys/errno.h> |
80 | #include <sys/ioctl.h> | | 80 | #include <sys/ioctl.h> |
81 | #include <sys/mbuf.h> | | 81 | #include <sys/mbuf.h> |
82 | #include <sys/socket.h> | | 82 | #include <sys/socket.h> |
| @@ -396,36 +396,36 @@ qe_put(struct qe_softc *sc, int idx, str | | | @@ -396,36 +396,36 @@ qe_put(struct qe_softc *sc, int idx, str |
396 | */ | | 396 | */ |
397 | inline void | | 397 | inline void |
398 | qe_read(struct qe_softc *sc, int idx, int len) | | 398 | qe_read(struct qe_softc *sc, int idx, int len) |
399 | { | | 399 | { |
400 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 400 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
401 | struct mbuf *m; | | 401 | struct mbuf *m; |
402 | | | 402 | |
403 | if (len <= sizeof(struct ether_header) || | | 403 | if (len <= sizeof(struct ether_header) || |
404 | len > ETHERMTU + sizeof(struct ether_header)) { | | 404 | len > ETHERMTU + sizeof(struct ether_header)) { |
405 | | | 405 | |
406 | printf("%s: invalid packet size %d; dropping\n", | | 406 | printf("%s: invalid packet size %d; dropping\n", |
407 | ifp->if_xname, len); | | 407 | ifp->if_xname, len); |
408 | | | 408 | |
409 | ifp->if_ierrors++; | | 409 | if_statinc(ifp, if_ierrors); |
410 | return; | | 410 | return; |
411 | } | | 411 | } |
412 | | | 412 | |
413 | /* | | 413 | /* |
414 | * Pull packet off interface. | | 414 | * Pull packet off interface. |
415 | */ | | 415 | */ |
416 | m = qe_get(sc, idx, len); | | 416 | m = qe_get(sc, idx, len); |
417 | if (m == NULL) { | | 417 | if (m == NULL) { |
418 | ifp->if_ierrors++; | | 418 | if_statinc(ifp, if_ierrors); |
419 | return; | | 419 | return; |
420 | } | | 420 | } |
421 | | | 421 | |
422 | /* Pass the packet up. */ | | 422 | /* Pass the packet up. */ |
423 | if_percpuq_enqueue(ifp->if_percpuq, m); | | 423 | if_percpuq_enqueue(ifp->if_percpuq, m); |
424 | } | | 424 | } |
425 | | | 425 | |
426 | /* | | 426 | /* |
427 | * Start output on interface. | | 427 | * Start output on interface. |
428 | * We make two assumptions here: | | 428 | * We make two assumptions here: |
429 | * 1) that the current priority is set to splnet _before_ this code | | 429 | * 1) that the current priority is set to splnet _before_ this code |
430 | * is called *and* is returned to the appropriate priority after | | 430 | * is called *and* is returned to the appropriate priority after |
431 | * return | | 431 | * return |
| @@ -522,27 +522,27 @@ qereset(struct qe_softc *sc) | | | @@ -522,27 +522,27 @@ qereset(struct qe_softc *sc) |
522 | | | 522 | |
523 | s = splnet(); | | 523 | s = splnet(); |
524 | qestop(sc); | | 524 | qestop(sc); |
525 | qeinit(sc); | | 525 | qeinit(sc); |
526 | splx(s); | | 526 | splx(s); |
527 | } | | 527 | } |
528 | | | 528 | |
529 | void | | 529 | void |
530 | qewatchdog(struct ifnet *ifp) | | 530 | qewatchdog(struct ifnet *ifp) |
531 | { | | 531 | { |
532 | struct qe_softc *sc = ifp->if_softc; | | 532 | struct qe_softc *sc = ifp->if_softc; |
533 | | | 533 | |
534 | log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); | | 534 | log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev)); |
535 | ifp->if_oerrors++; | | 535 | if_statinc(ifp, if_oerrors); |
536 | | | 536 | |
537 | qereset(sc); | | 537 | qereset(sc); |
538 | } | | 538 | } |
539 | | | 539 | |
540 | /* | | 540 | /* |
541 | * Interrupt dispatch. | | 541 | * Interrupt dispatch. |
542 | */ | | 542 | */ |
543 | int | | 543 | int |
544 | qeintr(void *arg) | | 544 | qeintr(void *arg) |
545 | { | | 545 | { |
546 | struct qe_softc *sc = arg; | | 546 | struct qe_softc *sc = arg; |
547 | bus_space_tag_t t = sc->sc_bustag; | | 547 | bus_space_tag_t t = sc->sc_bustag; |
548 | uint32_t qecstat, qestat; | | 548 | uint32_t qecstat, qestat; |
| @@ -617,27 +617,27 @@ qe_tint(struct qe_softc *sc) | | | @@ -617,27 +617,27 @@ qe_tint(struct qe_softc *sc) |
617 | | | 617 | |
618 | bix = sc->sc_rb.rb_tdtail; | | 618 | bix = sc->sc_rb.rb_tdtail; |
619 | | | 619 | |
620 | for (;;) { | | 620 | for (;;) { |
621 | if (sc->sc_rb.rb_td_nbusy <= 0) | | 621 | if (sc->sc_rb.rb_td_nbusy <= 0) |
622 | break; | | 622 | break; |
623 | | | 623 | |
624 | txflags = sc->sc_rb.rb_txd[bix].xd_flags; | | 624 | txflags = sc->sc_rb.rb_txd[bix].xd_flags; |
625 | | | 625 | |
626 | if (txflags & QEC_XD_OWN) | | 626 | if (txflags & QEC_XD_OWN) |
627 | break; | | 627 | break; |
628 | | | 628 | |
629 | ifp->if_flags &= ~IFF_OACTIVE; | | 629 | ifp->if_flags &= ~IFF_OACTIVE; |
630 | ifp->if_opackets++; | | 630 | if_statinc(ifp, if_opackets); |
631 | | | 631 | |
632 | if (++bix == QEC_XD_RING_MAXSIZE) | | 632 | if (++bix == QEC_XD_RING_MAXSIZE) |
633 | bix = 0; | | 633 | bix = 0; |
634 | | | 634 | |
635 | --sc->sc_rb.rb_td_nbusy; | | 635 | --sc->sc_rb.rb_td_nbusy; |
636 | } | | 636 | } |
637 | | | 637 | |
638 | sc->sc_rb.rb_tdtail = bix; | | 638 | sc->sc_rb.rb_tdtail = bix; |
639 | | | 639 | |
640 | qestart(ifp); | | 640 | qestart(ifp); |
641 | | | 641 | |
642 | if (sc->sc_rb.rb_td_nbusy == 0) | | 642 | if (sc->sc_rb.rb_td_nbusy == 0) |
643 | ifp->if_timer = 0; | | 643 | ifp->if_timer = 0; |
| @@ -695,176 +695,180 @@ qe_rint(struct qe_softc *sc) | | | @@ -695,176 +695,180 @@ qe_rint(struct qe_softc *sc) |
695 | } | | 695 | } |
696 | | | 696 | |
697 | /* | | 697 | /* |
698 | * Error interrupt. | | 698 | * Error interrupt. |
699 | */ | | 699 | */ |
700 | int | | 700 | int |
701 | qe_eint(struct qe_softc *sc, uint32_t why) | | 701 | qe_eint(struct qe_softc *sc, uint32_t why) |
702 | { | | 702 | { |
703 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 703 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
704 | device_t self = sc->sc_dev; | | 704 | device_t self = sc->sc_dev; |
705 | const char *xname = device_xname(self); | | 705 | const char *xname = device_xname(self); |
706 | int r = 0, rst = 0; | | 706 | int r = 0, rst = 0; |
707 | | | 707 | |
| | | 708 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); |
| | | 709 | |
708 | if (why & QE_CR_STAT_EDEFER) { | | 710 | if (why & QE_CR_STAT_EDEFER) { |
709 | printf("%s: excessive tx defers.\n", xname); | | 711 | printf("%s: excessive tx defers.\n", xname); |
710 | r |= 1; | | 712 | r |= 1; |
711 | ifp->if_oerrors++; | | 713 | if_statinc_ref(nsr, if_oerrors); |
712 | } | | 714 | } |
713 | | | 715 | |
714 | if (why & QE_CR_STAT_CLOSS) { | | 716 | if (why & QE_CR_STAT_CLOSS) { |
715 | printf("%s: no carrier, link down?\n", xname); | | 717 | printf("%s: no carrier, link down?\n", xname); |
716 | ifp->if_oerrors++; | | 718 | if_statinc_ref(nsr, if_oerrors); |
717 | r |= 1; | | 719 | r |= 1; |
718 | } | | 720 | } |
719 | | | 721 | |
720 | if (why & QE_CR_STAT_ERETRIES) { | | 722 | if (why & QE_CR_STAT_ERETRIES) { |
721 | printf("%s: excessive tx retries\n", xname); | | 723 | printf("%s: excessive tx retries\n", xname); |
722 | ifp->if_oerrors++; | | 724 | if_statinc_ref(nsr, if_oerrors); |
723 | r |= 1; | | 725 | r |= 1; |
724 | rst = 1; | | 726 | rst = 1; |
725 | } | | 727 | } |
726 | | | 728 | |
727 | | | 729 | |
728 | if (why & QE_CR_STAT_LCOLL) { | | 730 | if (why & QE_CR_STAT_LCOLL) { |
729 | printf("%s: late tx transmission\n", xname); | | 731 | printf("%s: late tx transmission\n", xname); |
730 | ifp->if_oerrors++; | | 732 | if_statinc_ref(nsr, if_oerrors); |
731 | r |= 1; | | 733 | r |= 1; |
732 | rst = 1; | | 734 | rst = 1; |
733 | } | | 735 | } |
734 | | | 736 | |
735 | if (why & QE_CR_STAT_FUFLOW) { | | 737 | if (why & QE_CR_STAT_FUFLOW) { |
736 | printf("%s: tx fifo underflow\n", xname); | | 738 | printf("%s: tx fifo underflow\n", xname); |
737 | ifp->if_oerrors++; | | 739 | if_statinc_ref(nsr, if_oerrors); |
738 | r |= 1; | | 740 | r |= 1; |
739 | rst = 1; | | 741 | rst = 1; |
740 | } | | 742 | } |
741 | | | 743 | |
742 | if (why & QE_CR_STAT_JERROR) { | | 744 | if (why & QE_CR_STAT_JERROR) { |
743 | printf("%s: jabber seen\n", xname); | | 745 | printf("%s: jabber seen\n", xname); |
744 | r |= 1; | | 746 | r |= 1; |
745 | } | | 747 | } |
746 | | | 748 | |
747 | if (why & QE_CR_STAT_BERROR) { | | 749 | if (why & QE_CR_STAT_BERROR) { |
748 | printf("%s: babble seen\n", xname); | | 750 | printf("%s: babble seen\n", xname); |
749 | r |= 1; | | 751 | r |= 1; |
750 | } | | 752 | } |
751 | | | 753 | |
752 | if (why & QE_CR_STAT_TCCOFLOW) { | | 754 | if (why & QE_CR_STAT_TCCOFLOW) { |
753 | ifp->if_collisions += 256; | | 755 | if_statadd_ref(nsr, if_collisions, 256); |
754 | ifp->if_oerrors += 256; | | 756 | if_statadd_ref(nsr, if_oerrors, 256); |
755 | r |= 1; | | 757 | r |= 1; |
756 | } | | 758 | } |
757 | | | 759 | |
758 | if (why & QE_CR_STAT_TXDERROR) { | | 760 | if (why & QE_CR_STAT_TXDERROR) { |
759 | printf("%s: tx descriptor is bad\n", xname); | | 761 | printf("%s: tx descriptor is bad\n", xname); |
760 | rst = 1; | | 762 | rst = 1; |
761 | r |= 1; | | 763 | r |= 1; |
762 | } | | 764 | } |
763 | | | 765 | |
764 | if (why & QE_CR_STAT_TXLERR) { | | 766 | if (why & QE_CR_STAT_TXLERR) { |
765 | printf("%s: tx late error\n", xname); | | 767 | printf("%s: tx late error\n", xname); |
766 | ifp->if_oerrors++; | | 768 | if_statinc_ref(nsr, if_oerrors); |
767 | rst = 1; | | 769 | rst = 1; |
768 | r |= 1; | | 770 | r |= 1; |
769 | } | | 771 | } |
770 | | | 772 | |
771 | if (why & QE_CR_STAT_TXPERR) { | | 773 | if (why & QE_CR_STAT_TXPERR) { |
772 | printf("%s: tx DMA parity error\n", xname); | | 774 | printf("%s: tx DMA parity error\n", xname); |
773 | ifp->if_oerrors++; | | 775 | if_statinc_ref(nsr, if_oerrors); |
774 | rst = 1; | | 776 | rst = 1; |
775 | r |= 1; | | 777 | r |= 1; |
776 | } | | 778 | } |
777 | | | 779 | |
778 | if (why & QE_CR_STAT_TXSERR) { | | 780 | if (why & QE_CR_STAT_TXSERR) { |
779 | printf("%s: tx DMA sbus error ack\n", xname); | | 781 | printf("%s: tx DMA sbus error ack\n", xname); |
780 | ifp->if_oerrors++; | | 782 | if_statinc_ref(nsr, if_oerrors); |
781 | rst = 1; | | 783 | rst = 1; |
782 | r |= 1; | | 784 | r |= 1; |
783 | } | | 785 | } |
784 | | | 786 | |
785 | if (why & QE_CR_STAT_RCCOFLOW) { | | 787 | if (why & QE_CR_STAT_RCCOFLOW) { |
786 | ifp->if_collisions += 256; | | 788 | if_statadd_ref(nsr, if_collisions, 256); |
787 | ifp->if_ierrors += 256; | | 789 | if_statadd_ref(nsr, if_ierrors, 256); |
788 | r |= 1; | | 790 | r |= 1; |
789 | } | | 791 | } |
790 | | | 792 | |
791 | if (why & QE_CR_STAT_RUOFLOW) { | | 793 | if (why & QE_CR_STAT_RUOFLOW) { |
792 | ifp->if_ierrors += 256; | | 794 | if_statadd_ref(nsr, if_ierrors, 256); |
793 | r |= 1; | | 795 | r |= 1; |
794 | } | | 796 | } |
795 | | | 797 | |
796 | if (why & QE_CR_STAT_MCOFLOW) { | | 798 | if (why & QE_CR_STAT_MCOFLOW) { |
797 | ifp->if_ierrors += 256; | | 799 | if_statadd_ref(nsr, if_ierrors, 256); |
798 | r |= 1; | | 800 | r |= 1; |
799 | } | | 801 | } |
800 | | | 802 | |
801 | if (why & QE_CR_STAT_RXFOFLOW) { | | 803 | if (why & QE_CR_STAT_RXFOFLOW) { |
802 | printf("%s: rx fifo overflow\n", xname); | | 804 | printf("%s: rx fifo overflow\n", xname); |
803 | ifp->if_ierrors++; | | 805 | if_statinc_ref(nsr, if_ierrors); |
804 | r |= 1; | | 806 | r |= 1; |
805 | } | | 807 | } |
806 | | | 808 | |
807 | if (why & QE_CR_STAT_RLCOLL) { | | 809 | if (why & QE_CR_STAT_RLCOLL) { |
808 | printf("%s: rx late collision\n", xname); | | 810 | printf("%s: rx late collision\n", xname); |
809 | ifp->if_ierrors++; | | 811 | if_statinc_ref(nsr, if_ierrors); |
810 | ifp->if_collisions++; | | 812 | if_statinc_ref(nsr, if_collisions); |
811 | r |= 1; | | 813 | r |= 1; |
812 | } | | 814 | } |
813 | | | 815 | |
814 | if (why & QE_CR_STAT_FCOFLOW) { | | 816 | if (why & QE_CR_STAT_FCOFLOW) { |
815 | ifp->if_ierrors += 256; | | 817 | if_statadd_ref(nsr, if_ierrors, 256); |
816 | r |= 1; | | 818 | r |= 1; |
817 | } | | 819 | } |
818 | | | 820 | |
819 | if (why & QE_CR_STAT_CECOFLOW) { | | 821 | if (why & QE_CR_STAT_CECOFLOW) { |
820 | ifp->if_ierrors += 256; | | 822 | if_statadd_ref(nsr, if_ierrors, 256); |
821 | r |= 1; | | 823 | r |= 1; |
822 | } | | 824 | } |
823 | | | 825 | |
824 | if (why & QE_CR_STAT_RXDROP) { | | 826 | if (why & QE_CR_STAT_RXDROP) { |
825 | printf("%s: rx packet dropped\n", xname); | | 827 | printf("%s: rx packet dropped\n", xname); |
826 | ifp->if_ierrors++; | | 828 | if_statinc_ref(nsr, if_ierrors); |
827 | r |= 1; | | 829 | r |= 1; |
828 | } | | 830 | } |
829 | | | 831 | |
830 | if (why & QE_CR_STAT_RXSMALL) { | | 832 | if (why & QE_CR_STAT_RXSMALL) { |
831 | printf("%s: rx buffer too small\n", xname); | | 833 | printf("%s: rx buffer too small\n", xname); |
832 | ifp->if_ierrors++; | | 834 | if_statinc_ref(nsr, if_ierrors); |
833 | r |= 1; | | 835 | r |= 1; |
834 | rst = 1; | | 836 | rst = 1; |
835 | } | | 837 | } |
836 | | | 838 | |
837 | if (why & QE_CR_STAT_RXLERR) { | | 839 | if (why & QE_CR_STAT_RXLERR) { |
838 | printf("%s: rx late error\n", xname); | | 840 | printf("%s: rx late error\n", xname); |
839 | ifp->if_ierrors++; | | 841 | if_statinc_ref(nsr, if_ierrors); |
840 | r |= 1; | | 842 | r |= 1; |
841 | rst = 1; | | 843 | rst = 1; |
842 | } | | 844 | } |
843 | | | 845 | |
844 | if (why & QE_CR_STAT_RXPERR) { | | 846 | if (why & QE_CR_STAT_RXPERR) { |
845 | printf("%s: rx DMA parity error\n", xname); | | 847 | printf("%s: rx DMA parity error\n", xname); |
846 | ifp->if_ierrors++; | | 848 | if_statinc_ref(nsr, if_ierrors); |
847 | r |= 1; | | 849 | r |= 1; |
848 | rst = 1; | | 850 | rst = 1; |
849 | } | | 851 | } |
850 | | | 852 | |
851 | if (why & QE_CR_STAT_RXSERR) { | | 853 | if (why & QE_CR_STAT_RXSERR) { |
852 | printf("%s: rx DMA sbus error ack\n", xname); | | 854 | printf("%s: rx DMA sbus error ack\n", xname); |
853 | ifp->if_ierrors++; | | 855 | if_statinc_ref(nsr, if_ierrors); |
854 | r |= 1; | | 856 | r |= 1; |
855 | rst = 1; | | 857 | rst = 1; |
856 | } | | 858 | } |
857 | | | 859 | |
| | | 860 | IF_STAT_PUTREF(ifp); |
| | | 861 | |
858 | if (r == 0) | | 862 | if (r == 0) |
859 | aprint_error_dev(self, "unexpected interrupt error: %08x\n", | | 863 | aprint_error_dev(self, "unexpected interrupt error: %08x\n", |
860 | why); | | 864 | why); |
861 | | | 865 | |
862 | if (rst) { | | 866 | if (rst) { |
863 | printf("%s: resetting...\n", xname); | | 867 | printf("%s: resetting...\n", xname); |
864 | qereset(sc); | | 868 | qereset(sc); |
865 | return (-1); | | 869 | return (-1); |
866 | } | | 870 | } |
867 | | | 871 | |
868 | return (r); | | 872 | return (r); |
869 | } | | 873 | } |
870 | | | 874 | |