| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_mos.c,v 1.5 2020/03/15 23:04:50 thorpej Exp $ */ | | 1 | /* $NetBSD: if_mos.c,v 1.6 2020/03/31 23:26:32 nisimura Exp $ */ |
2 | /* $OpenBSD: if_mos.c,v 1.40 2019/07/07 06:40:10 kevlo Exp $ */ | | 2 | /* $OpenBSD: if_mos.c,v 1.40 2019/07/07 06:40:10 kevlo Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> | | 5 | * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| @@ -62,27 +62,27 @@ | | | @@ -62,27 +62,27 @@ |
62 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 62 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
63 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 63 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
64 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | 64 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
65 | * THE POSSIBILITY OF SUCH DAMAGE. | | 65 | * THE POSSIBILITY OF SUCH DAMAGE. |
66 | */ | | 66 | */ |
67 | | | 67 | |
68 | /* | | 68 | /* |
69 | * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller | | 69 | * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller |
70 | * The datasheet is available at the following URL: | | 70 | * The datasheet is available at the following URL: |
71 | * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf | | 71 | * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf |
72 | */ | | 72 | */ |
73 | | | 73 | |
74 | #include <sys/cdefs.h> | | 74 | #include <sys/cdefs.h> |
75 | __KERNEL_RCSID(0, "$NetBSD: if_mos.c,v 1.5 2020/03/15 23:04:50 thorpej Exp $"); | | 75 | __KERNEL_RCSID(0, "$NetBSD: if_mos.c,v 1.6 2020/03/31 23:26:32 nisimura Exp $"); |
76 | | | 76 | |
77 | #include <sys/param.h> | | 77 | #include <sys/param.h> |
78 | | | 78 | |
79 | #include <dev/usb/usbnet.h> | | 79 | #include <dev/usb/usbnet.h> |
80 | #include <dev/usb/if_mosreg.h> | | 80 | #include <dev/usb/if_mosreg.h> |
81 | | | 81 | |
82 | #define MOS_PAUSE_REWRITES 3 | | 82 | #define MOS_PAUSE_REWRITES 3 |
83 | | | 83 | |
84 | #define MOS_TIMEOUT 1000 | | 84 | #define MOS_TIMEOUT 1000 |
85 | | | 85 | |
86 | #define MOS_RX_LIST_CNT 1 | | 86 | #define MOS_RX_LIST_CNT 1 |
87 | #define MOS_TX_LIST_CNT 1 | | 87 | #define MOS_TX_LIST_CNT 1 |
88 | | | 88 | |
| @@ -444,77 +444,76 @@ mos_uno_mii_statchg(struct ifnet *ifp) | | | @@ -444,77 +444,76 @@ mos_uno_mii_statchg(struct ifnet *ifp) |
444 | } | | 444 | } |
445 | usbnet_set_link(un, true); | | 445 | usbnet_set_link(un, true); |
446 | } | | 446 | } |
447 | | | 447 | |
448 | /* re-enable TX, RX */ | | 448 | /* re-enable TX, RX */ |
449 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | | 449 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); |
450 | err = mos_reg_write_1(un, MOS_CTL, val); | | 450 | err = mos_reg_write_1(un, MOS_CTL, val); |
451 | | | 451 | |
452 | if (err) | | 452 | if (err) |
453 | aprint_error_dev(un->un_dev, "media change failed\n"); | | 453 | aprint_error_dev(un->un_dev, "media change failed\n"); |
454 | } | | 454 | } |
455 | | | 455 | |
456 | static void | | 456 | static void |
457 | mos_setiff_locked(struct usbnet *un) | | 457 | mos_rcvfilt_locked(struct usbnet *un) |
458 | { | | 458 | { |
459 | struct ifnet *ifp = usbnet_ifp(un); | | 459 | struct ifnet *ifp = usbnet_ifp(un); |
460 | struct ethercom *ec = usbnet_ec(un); | | 460 | struct ethercom *ec = usbnet_ec(un); |
461 | struct ether_multi *enm; | | 461 | struct ether_multi *enm; |
462 | struct ether_multistep step; | | 462 | struct ether_multistep step; |
463 | u_int32_t h = 0; | | 463 | u_int32_t h = 0; |
464 | u_int8_t rxmode, hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | | 464 | u_int8_t rxmode, mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
465 | | | 465 | |
466 | if (usbnet_isdying(un)) | | 466 | if (usbnet_isdying(un)) |
467 | return; | | 467 | return; |
468 | | | 468 | |
469 | rxmode = mos_reg_read_1(un, MOS_CTL); | | 469 | rxmode = mos_reg_read_1(un, MOS_CTL); |
470 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | | 470 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); |
471 | | | 471 | |
472 | ETHER_LOCK(ec); | | 472 | ETHER_LOCK(ec); |
473 | if (ifp->if_flags & IFF_PROMISC) { | | 473 | if (ifp->if_flags & IFF_PROMISC) { |
474 | allmulti: | | | |
475 | ec->ec_flags |= ETHER_F_ALLMULTI; | | 474 | ec->ec_flags |= ETHER_F_ALLMULTI; |
476 | rxmode |= MOS_CTL_ALLMULTI; | | 475 | ETHER_UNLOCK(ec); |
477 | if (ifp->if_flags & IFF_PROMISC) | | 476 | /* run promisc. mode */ |
478 | rxmode |= MOS_CTL_RX_PROMISC; | | 477 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ |
479 | } else { | | 478 | rxmode |= MOS_CTL_RX_PROMISC; |
480 | /* now program new ones */ | | 479 | goto update; |
481 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | | 480 | } |
482 | | | 481 | ec->ec_flags &= ~ETHER_F_ALLMULTI; |
483 | ETHER_FIRST_MULTI(step, ec, enm); | | 482 | ETHER_FIRST_MULTI(step, ec, enm); |
484 | while (enm != NULL) { | | 483 | while (enm != NULL) { |
485 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | | 484 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { |
486 | ETHER_ADDR_LEN)) { | | 485 | ec->ec_flags |= ETHER_F_ALLMULTI; |
487 | memset(hashtbl, 0, sizeof(hashtbl)); | | 486 | ETHER_UNLOCK(ec); |
488 | goto allmulti; | | 487 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ |
489 | } | | 488 | /* accept all mulicast frame */ |
490 | h = ether_crc32_be(enm->enm_addrlo, | | 489 | rxmode |= MOS_CTL_ALLMULTI; |
491 | ETHER_ADDR_LEN) >> 26; | | 490 | goto update; |
492 | hashtbl[h / 8] |= 1 << (h % 8); | | | |
493 | | | | |
494 | ETHER_NEXT_MULTI(step, enm); | | | |
495 | } | | 491 | } |
| | | 492 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); |
| | | 493 | /* 3(31:29) and 3(28:26) sampling to have uint8_t[8] */ |
| | | 494 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); |
| | | 495 | ETHER_NEXT_MULTI(step, enm); |
496 | } | | 496 | } |
497 | ETHER_UNLOCK(ec); | | 497 | ETHER_UNLOCK(ec); |
498 | | | 498 | /* MOS receive filter is always on */ |
| | | 499 | update: |
499 | /* | | 500 | /* |
500 | * The datasheet claims broadcast frames were always accepted | | 501 | * The datasheet claims broadcast frames were always accepted |
501 | * regardless of filter settings. But the hardware seems to | | 502 | * regardless of filter settings. But the hardware seems to |
502 | * filter broadcast frames, so pass them explicitly. | | 503 | * filter broadcast frames, so pass them explicitly. |
503 | */ | | 504 | */ |
504 | h = ether_crc32_be(etherbroadcastaddr, ETHER_ADDR_LEN) >> 26; | | 505 | mchash[7] |= 0x80; |
505 | hashtbl[h / 8] |= 1 << (h % 8); | | 506 | mos_write_mcast(un, mchash); |
506 | | | | |
507 | mos_write_mcast(un, hashtbl); | | | |
508 | mos_reg_write_1(un, MOS_CTL, rxmode); | | 507 | mos_reg_write_1(un, MOS_CTL, rxmode); |
509 | } | | 508 | } |
510 | | | 509 | |
511 | static void | | 510 | static void |
512 | mos_reset(struct usbnet *un) | | 511 | mos_reset(struct usbnet *un) |
513 | { | | 512 | { |
514 | u_int8_t ctl; | | 513 | u_int8_t ctl; |
515 | | | 514 | |
516 | if (usbnet_isdying(un)) | | 515 | if (usbnet_isdying(un)) |
517 | return; | | 516 | return; |
518 | | | 517 | |
519 | ctl = mos_reg_read_1(un, MOS_CTL); | | 518 | ctl = mos_reg_read_1(un, MOS_CTL); |
520 | ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | | | 519 | ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | |
| @@ -735,27 +734,27 @@ mos_init_locked(struct ifnet *ifp) | | | @@ -735,27 +734,27 @@ mos_init_locked(struct ifnet *ifp) |
735 | /* Reset the ethernet interface. */ | | 734 | /* Reset the ethernet interface. */ |
736 | mos_reset(un); | | 735 | mos_reset(un); |
737 | | | 736 | |
738 | /* Write MAC address. */ | | 737 | /* Write MAC address. */ |
739 | mos_writemac(un); | | 738 | mos_writemac(un); |
740 | | | 739 | |
741 | /* Read and set transmitter IPG values */ | | 740 | /* Read and set transmitter IPG values */ |
742 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | | 741 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); |
743 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | | 742 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); |
744 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | | 743 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); |
745 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | | 744 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); |
746 | | | 745 | |
747 | /* Program promiscuous mode and multicast filters. */ | | 746 | /* Program promiscuous mode and multicast filters. */ |
748 | mos_setiff_locked(un); | | 747 | mos_rcvfilt_locked(un); |
749 | | | 748 | |
750 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | | 749 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ |
751 | rxmode = mos_reg_read_1(un, MOS_CTL); | | 750 | rxmode = mos_reg_read_1(un, MOS_CTL); |
752 | rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; | | 751 | rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; |
753 | rxmode &= ~(MOS_CTL_SLEEP); | | 752 | rxmode &= ~(MOS_CTL_SLEEP); |
754 | mos_reg_write_1(un, MOS_CTL, rxmode); | | 753 | mos_reg_write_1(un, MOS_CTL, rxmode); |
755 | | | 754 | |
756 | return usbnet_init_rx_tx(un); | | 755 | return usbnet_init_rx_tx(un); |
757 | } | | 756 | } |
758 | | | 757 | |
759 | static int | | 758 | static int |
760 | mos_uno_init(struct ifnet *ifp) | | 759 | mos_uno_init(struct ifnet *ifp) |
761 | { | | 760 | { |
| @@ -771,27 +770,27 @@ mos_uno_init(struct ifnet *ifp) | | | @@ -771,27 +770,27 @@ mos_uno_init(struct ifnet *ifp) |
771 | } | | 770 | } |
772 | | | 771 | |
773 | static int | | 772 | static int |
774 | mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | | 773 | mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
775 | { | | 774 | { |
776 | struct usbnet * const un = ifp->if_softc; | | 775 | struct usbnet * const un = ifp->if_softc; |
777 | | | 776 | |
778 | usbnet_lock_core(un); | | 777 | usbnet_lock_core(un); |
779 | usbnet_busy(un); | | 778 | usbnet_busy(un); |
780 | | | 779 | |
781 | switch (cmd) { | | 780 | switch (cmd) { |
782 | case SIOCADDMULTI: | | 781 | case SIOCADDMULTI: |
783 | case SIOCDELMULTI: | | 782 | case SIOCDELMULTI: |
784 | mos_setiff_locked(un); | | 783 | mos_rcvfilt_locked(un); |
785 | break; | | 784 | break; |
786 | default: | | 785 | default: |
787 | break; | | 786 | break; |
788 | } | | 787 | } |
789 | | | 788 | |
790 | usbnet_unbusy(un); | | 789 | usbnet_unbusy(un); |
791 | usbnet_unlock_core(un); | | 790 | usbnet_unlock_core(un); |
792 | | | 791 | |
793 | return 0; | | 792 | return 0; |
794 | } | | 793 | } |
795 | | | 794 | |
796 | void | | 795 | void |
797 | mos_uno_stop(struct ifnet *ifp, int disable) | | 796 | mos_uno_stop(struct ifnet *ifp, int disable) |