On Wed, Mar 21, 2018 at 12:03:41AM +0900, SASANO Takayoshi wrote: > Hello, > > Recently I bought pcDuino v1 and trying to run OpenBSD/armv7-current. > sxie(4) supports Allwinner A10's EMAC ethernet and I think it can drive > pcDuino's ethernet port but something goes wrong. > > This is a log of tcpdump when I typed "nemesis ethernet -d sxie0 -H > 01:23:45:67:89:ab -M ff:ff:ff:ff:ff:ff -P /dev/zero -T 1514" on > pcDuino's console. > > 23:52:22.590734 70:40:5e:ef:70:40 5e:ef:70:40:5e:ef 5eef 1514: > 7040 5eef 7040 5eef 7040 5eef 7040 5eef > 7040 5eef 7040 5eef 7040 5eef 7040 5eef > 7040 5eef 7040 5eef 7040 5eef 7040 5eef > 7040 5eef 7040 5eef 7040 5eef 7040 5eef > 7040 5eef 7040 5eef 7040 5eef 7040 5eef > 7040 5eef 7040 5eef 7040 5eef 7040 5eef > 7040 5eef 7040 > > When I attach ASIX AX88772 based USB ethernet interface and do same > thing to axe(4), it looks no problem. > > 23:58:53.261537 01:23:45:67:89:ab Broadcast 05ea 1514: > 0000 0000 0000 0000 0000 0000 0000 0000 > 0000 0000 0000 0000 0000 0000 0000 0000 > 0000 0000 0000 0000 0000 0000 0000 0000 > 0000 0000 0000 0000 0000 0000 0000 0000 > 0000 0000 0000 0000 0000 0000 0000 0000 > 0000 0000 0000 0000 0000 0000 0000 0000 > 0000 0000 0000 > > Is there any special procedure to work sxie ethernet?
Hi, i don't know what "nemesis" is, but you could have a try w/diff below. or if you're unable to do that, static arp and/or running tcpdump for IFF_PROMISC might work as a workaround for some bugs the driver has, fwiw.. -Artturi > I simply use OpenBSD 6.3-beta (GENERIC) #194: Tue Mar 13 00:11:10 MDT 2018 > kernel and U-boot 2017.09 (Oct 02 2017 - 19:04:33 -0600) Allwinner Technology. > > -- > SASANO Takayoshi (JG1UAA) <[email protected]> > diff --git sys/arch/armv7/sunxi/sxie.c sys/arch/armv7/sunxi/sxie.c index 249cd2a2478..a6174f36e6d 100644 --- sys/arch/armv7/sunxi/sxie.c +++ sys/arch/armv7/sunxi/sxie.c @@ -54,103 +54,175 @@ #include <dev/ofw/ofw_regulator.h> #include <dev/ofw/fdt.h> -/* configuration registers */ -#define SXIE_CR 0x0000 +#if defined(DEBUG) || defined(DIAGNOSTIC) +#define SXIE_CD (ifp->if_flags & IFF_DEBUG) +#define SXIEDBG(x) do { if (SXIE_CD) printf((x)); } while (0) +#else +#define SXIE_CD (0) +#define SXIEDBG(x) do { } while (0) +#endif + +/* control registers */ +#define SXIE_CMDR 0x0000 #define SXIE_TXMODE 0x0004 -#define SXIE_TXFLOW 0x0008 +#define SXIE_TXFLOW 0x0008 /* unused */ #define SXIE_TXCR0 0x000c #define SXIE_TXCR1 0x0010 #define SXIE_TXINS 0x0014 +/* + * XXX was wondering, what if these TXPKTLEN registers + * are actually part of memory mapped tx 'fake' descriptors, + * something like w/DMA but only via register map or something? + * should add some dbg and try to figure out:) + */ #define SXIE_TXPKTLEN0 0x0018 #define SXIE_TXPKTLEN1 0x001c -#define SXIE_TXSR 0x0020 +#define SXIE_TXSR 0x0020 /* unused */ #define SXIE_TXIO0 0x0024 -#define SXIE_TXIO1 0x0028 -#define SXIE_TXTSVL0 0x002c -#define SXIE_TXTSVH0 0x0030 -#define SXIE_TXTSVL1 0x0034 -#define SXIE_TXTSVH1 0x0038 -#define SXIE_RXCR 0x003c +#define SXIE_TXIO1 0x0028 /* unused */ +#define SXIE_TXTSVL0 0x002c /* unused */ +#define SXIE_TXTSVH0 0x0030 /* unused */ +#define SXIE_TXTSVL1 0x0034 /* unused */ +#define SXIE_TXTSVH1 0x0038 /* unused */ + +/* receive filter registers */ +#define SXIE_RXFILTER_CTRL 0x003c #define SXIE_RXHASH0 0x0040 #define SXIE_RXHASH1 0x0044 -#define SXIE_RXSR 0x0048 -#define SXIE_RXIO 0x004C + +/* dunno.. */ +#define SXIE_RXSR 0x0048 /* unused */ +#define SXIE_RXIO 0x004c #define SXIE_RXFBC 0x0050 + +/* module control registers */ #define SXIE_INTCR 0x0054 #define SXIE_INTSR 0x0058 -#define SXIE_MACCR0 0x005C -#define SXIE_MACCR1 0x0060 -#define SXIE_MACIPGT 0x0064 -#define SXIE_MACIPGR 0x0068 -#define SXIE_MACCLRT 0x006C -#define SXIE_MACMFL 0x0070 -#define SXIE_MACSUPP 0x0074 -#define SXIE_MACTEST 0x0078 -#define SXIE_MACMCFG 0x007C -#define SXIE_MACMCMD 0x0080 -#define SXIE_MACMADR 0x0084 -#define SXIE_MACMWTD 0x0088 -#define SXIE_MACMRDD 0x008C -#define SXIE_MACMIND 0x0090 -#define SXIE_MACSSRR 0x0094 -#define SXIE_MACA0 0x0098 -#define SXIE_MACA1 0x009c -#define SXIE_MACA2 0x00a0 -/* i once spent hours on pretty defines, cvs up ate 'em. these shall do */ -#define SXIE_INTR_ENABLE 0x010f -#define SXIE_INTR_DISABLE 0x0000 -#define SXIE_INTR_CLEAR 0x0000 +/* ethernet MAC registers */ +#define SXIE_MAC0 0x005c +#define SXIE_MAC1 0x0060 +#define SXIE_MAC_IPGT 0x0064 +#define SXIE_MAC_IPGR 0x0068 +#define SXIE_MAC_CLRT 0x006c +#define SXIE_MAC_MAXF 0x0070 +#define SXIE_MAC_SUPP 0x0074 +#define SXIE_MAC_TEST 0x0078 /* unused */ +#define SXIE_MAC_MCFG 0x007c +#define SXIE_MAC_MCMD 0x0080 +#define SXIE_MAC_MADR 0x0084 +#define SXIE_MAC_MWTD 0x0088 +#define SXIE_MAC_MRDD 0x008c +#define SXIE_MAC_MIND 0x0090 +#define SXIE_MACSSRR 0x0094 /* unused */ +#define SXIE_MAC_SA0 0x0098 +#define SXIE_MAC_SA1 0x009c +#define SXIE_MACA2 0x00a0 /* unused */ -#define SXIE_TX_FIFO0 0x0001 -#define SXIE_TX_FIFO1 0x0002 +/* i once spent hours on pretty defines, cvs up ate 'em. these shall do */ +#define SXIE_INTR_ENABLE 0x010f +#define SXIE_INTR_DISABLE 0x0000 +#define SXIE_INTR_CLEAR 0x0000 #define SXIE_RX_ENABLE 0x0004 #define SXIE_TX_ENABLE 0x0003 -#define SXIE_RXTX_ENABLE 0x0007 +#define SXIE_RXTX_ENABLE 0x0007 #define SXIE_RXDRQM 0x0002 #define SXIE_RXTM 0x0004 -#define SXIE_RXFLUSH 0x0008 -#define SXIE_RXPA 0x0010 -#define SXIE_RXPCF 0x0020 -#define SXIE_RXPCRCE 0x0040 -#define SXIE_RXPLE 0x0080 -#define SXIE_RXPOR 0x0100 -#define SXIE_RXUCAD 0x10000 -#define SXIE_RXDAF 0x20000 -#define SXIE_RXMCO 0x100000 -#define SXIE_RXMHF 0x200000 -#define SXIE_RXBCO 0x400000 -#define SXIE_RXSAF 0x1000000 -#define SXIE_RXSAIF 0x2000000 - -#define SXIE_MACRXFC 0x0004 -#define SXIE_MACTXFC 0x0008 -#define SXIE_MACSOFTRESET 0x8000 - -#define SXIE_MACDUPLEX 0x0001 /* full = 1 */ -#define SXIE_MACFLC 0x0002 -#define SXIE_MACHF 0x0004 -#define SXIE_MACDCRC 0x0008 -#define SXIE_MACCRC 0x0010 -#define SXIE_MACPC 0x0020 -#define SXIE_MACVC 0x0040 -#define SXIE_MACADP 0x0080 -#define SXIE_MACPRE 0x0100 -#define SXIE_MACLPE 0x0200 -#define SXIE_MACNB 0x1000 -#define SXIE_MACBNB 0x2000 -#define SXIE_MACED 0x4000 - -#define SXIE_RX_ERRLENOOR 0x0040 -#define SXIE_RX_ERRLENCHK 0x0020 -#define SXIE_RX_ERRCRC 0x0010 -#define SXIE_RX_ERRRCV 0x0008 /* XXX receive code violation ? */ + /* 0x00 */ +#define SXIE_CMDR_RXENABLE (1 << 0) +#define SXIE_CMDR_TXENABLE (1 << 1) +#define SXIE_CMDR_REGRESET (1 << 3) +#define SXIE_CMDR_TXRESET (1 << 4) +#define SXIE_CMDR_RXRESET (1 << 5) +#define SXIE_CMDR_PASSRUNTFRAME (1 << 6) +#define SXIE_CMDR_PASSRXFILTER (1 << 7) +#define SXIE_CMDR_TXFLOWCTL (1 << 8) +#define SXIE_CMDR_RMII (1 << 9) +#define SXIE_CMDR_FULLDUPLEX (1 << 10) + /* 0x3c */ +#define SXIE_RXFILTER_PROMISC (1 << 4) +#define SXIE_RXFILTER_CONTROLFRAMES (1 << 5) +#define SXIE_RXFILTER_FRAMECRCERR (1 << 6) +#define SXIE_RXFILTER_FRAMELENERR (1 << 7) +#define SXIE_RXFILTER_FRAMELENOOR (1 << 8) +#define SXIE_RXFILTER_UNICAST (1 << 16) +#define SXIE_RXFILTER_DAFILTER (1 << 17) +#define SXIE_RXFILTER_MULTICAST (1 << 20) +#define SXIE_RXFILTER_MHASHFILTER (1 << 21) +#define SXIE_RXFILTER_BROADCAST (1 << 22) +#define SXIE_RXFILTER_SAFILTER (1 << 24) +#define SXIE_RXFILTER_SAINVFILTER (1 << 25) + /* 0x5c */ +#define SXIE_MAC0_RXENABLE (1 << 0) +#define SXIE_MAC0_PASSALL (1 << 1) +#define SXIE_MAC0_RXFLOWCTRL (1 << 2) +#define SXIE_MAC0_TXFLOWCTRL (1 << 3) +#define SXIE_MAC0_LOOPBACK (1 << 4) +#define SXIE_MAC0_RESETTX (1 << 8) +#define SXIE_MAC0_RESETMCSTX (1 << 9) +#define SXIE_MAC0_RESETRX (1 << 10) +#define SXIE_MAC0_RESETMCSRX (1 << 11) +#define SXIE_MAC0_SOFTRESET (1 << 15) + /* 0x60 */ +#define SXIE_MAC1_FULLDUPLEX (1 << 0) +#define SXIE_MAC1_FRAMELENCHECK (1 << 1) +#define SXIE_MAC1_HUGEFRAME (1 << 2) +#define SXIE_MAC1_DELAYEDCRC (1 << 3) +#define SXIE_MAC1_CRC (1 << 4) +#define SXIE_MAC1_PADCRC (1 << 5) +#define SXIE_MAC1_VLANPAD (1 << 6) +#define SXIE_MAC1_AUTOPAD (1 << 7) +#define SXIE_MAC1_PUREPREAMBLE (1 << 8) +#define SXIE_MAC1_LONGPREAMBLE (1 << 9) +#define SXIE_MAC1_NOBACKOFF (1 << 12) +#define SXIE_MAC1_BACKPRESSURE (1 << 13) +#define SXIE_MAC1_EXCESSDEFER (1 << 14) + /* 0x64 */ +#define SXIE_MAC_BTB_IPG(x) ((x) & 0x7f) + /* 0x68 */ +#define SXIE_MAC_NBTB_IGP_P2(x) ((x) & 0x7f) +#define SXIE_MAC_NBTB_IGP_P1(x) (((x) & 0x7f) << 8) + /* 0x6c */ +#define SXIE_MAC_CLRT_RETRANSMAX 0x0f +#define SXIE_MAC_CLRT_COLLWIND(x) (((x) & 0x3f) << 8) + /* 0x70 */ +#define SXIE_MAC_MAXF_MAXFRAMELENMASK 0xffff + /* 0x74 */ +#define SXIE_MAC_SUPP_SPEED (1 << 8) + /* 0x78 */ +#define SXIE_MAC_TEST_SHORTCPAUSEQUANTA (1 << 0) +#define SXIE_MAC_TEST_TESTPAUSE (1 << 1) +#define SXIE_MAC_TEST_TESTBACKPRESSURE (1 << 2) + /* 0x7c */ +#define SXIE_MAC_MCFG_SCANINCR (1 << 0) +#define SXIE_MAC_MCFG_SUPPREAMBLE (1 << 1) +#define SXIE_MAC_MCFG_CLKSEL(_n) (((_n) & 0xf) << 2) +#define SXIE_MAC_MCFG_RESET_MII (1 << 15) + /* 0x80 */ +#define SXIE_MAC_MCMD_READ (1 << 0) +#define SXIE_MAC_MCMD_WRITE (0 << 0) +#define SXIE_MAC_MCMD_SCAN (1 << 1) + /* 0x90 */ +#define SXIE_MAC_MIND_BUSY (1 << 0) +#define SXIE_MAC_MIND_SCANNING (1 << 1) +#define SXIE_MAC_MIND_INVALID (1 << 2) +#define SXIE_MAC_MIND_MIIFAIL (1 << 3) + +#define SXIE_TX_FIFO0 0x0001 +#define SXIE_TX_FIFO1 0x0002 +#define SXIE_TX_FIFOS (SXIE_TX_FIFO0 | SXIE_TX_FIFO1) + +#define SXIE_SRST_RX (1 << 0) +#define SXIE_SRST_TX (1 << 1) +#define SXIE_SRST_FULL (1 << 2) + #define SXIE_RX_ERRMASK 0x0070 #define SXIE_MII_TIMEOUT 100 #define SXIE_MAX_RXD 8 +#define SXIE_MAX_TXD 2 #define SXIE_MAX_PKT_SIZE ETHER_MAX_DIX_LEN #define SXIE_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1)) @@ -159,20 +231,22 @@ struct sxie_softc { struct device sc_dev; struct arpcom sc_ac; struct mii_data sc_mii; + int sc_node; + int sc_dmanode; int sc_phyno; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; - bus_space_handle_t sc_sid_ioh; + bus_dma_tag_t sc_dmat; void *sc_ih; /* Interrupt handler */ - uint32_t intr_status; /* soft interrupt status */ - uint32_t pauseframe; - uint32_t txf_inuse; + uint32_t sc_pauseframe; + uint32_t sc_tx_timer; + uint32_t sc_tx_inuse; }; -struct sxie_softc *sxie_sc; - int sxie_match(struct device *, void *, void *); void sxie_attach(struct device *, struct device *, void *); +void sxie_get_lladdr(struct sxie_softc *); +void sxie_set_lladdr(struct sxie_softc *); void sxie_setup_interface(struct sxie_softc *, struct device *); void sxie_socware_init(struct sxie_softc *); int sxie_ioctl(struct ifnet *, u_long, caddr_t); @@ -180,8 +254,7 @@ void sxie_start(struct ifnet *); void sxie_watchdog(struct ifnet *); void sxie_init(struct sxie_softc *); void sxie_stop(struct sxie_softc *); -void sxie_reset(struct sxie_softc *); -void sxie_iff(struct sxie_softc *, struct ifnet *); +void sxie_iff(struct sxie_softc *); int sxie_intr(void *); void sxie_recv(struct sxie_softc *); int sxie_miibus_readreg(struct device *, int, int); @@ -190,6 +263,9 @@ void sxie_miibus_statchg(struct device *); int sxie_ifm_change(struct ifnet *); void sxie_ifm_status(struct ifnet *, struct ifmediareq *); +static inline void + sxie_softreset(struct sxie_softc *, uint32_t); + struct cfattach sxie_ca = { sizeof (struct sxie_softc), sxie_match, sxie_attach }; @@ -211,8 +287,8 @@ sxie_attach(struct device *parent, struct device *self, void *aux) { struct sxie_softc *sc = (struct sxie_softc *) self; struct fdt_attach_args *faa = aux; - struct mii_data *mii; - struct ifnet *ifp; + struct mii_data *mii = &sc->sc_mii; + struct ifnet *ifp = &sc->sc_ac.ac_if; int node, phy_supply, phy = MII_PHY_ANY; int s; @@ -222,13 +298,15 @@ sxie_attach(struct device *parent, struct device *self, void *aux) pinctrl_byname(faa->fa_node, "default"); sc->sc_iot = faa->fa_iot; + sc->sc_dmat = faa->fa_dmat; + sc->sc_node = faa->fa_node; if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, - faa->fa_reg[0].size, 0, &sc->sc_ioh)) - panic("sxie_attach: bus_space_map ioh failed!"); - - if (bus_space_map(sc->sc_iot, SID_ADDR, SID_SIZE, 0, &sc->sc_sid_ioh)) - panic("sxie_attach: bus_space_map sid_ioh failed!"); + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf("%s: bus_space_map ioh failed!\n", + sc->sc_dev.dv_xname); + return; + } clock_enable_all(faa->fa_node); @@ -244,37 +322,43 @@ sxie_attach(struct device *parent, struct device *self, void *aux) } sc->sc_phyno = phy == MII_PHY_ANY ? 1 : phy; - sxie_socware_init(sc); - sc->txf_inuse = 0; - sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_NET, sxie_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_ih == NULL) + goto failout; - s = splnet(); + /* + * try to get&set lladdr in order: + * a) devicetree + * b) current + * c) better than random (from SID rootkey registers) + * d) ether_fakeaddr + */ + sxie_get_lladdr(sc); printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); - /* XXX verify flags & capabilities */ - ifp = &sc->sc_ac.ac_if; + s = splnet(); ifp->if_softc = sc; strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = sxie_ioctl; ifp->if_start = sxie_start; ifp->if_watchdog = sxie_watchdog; + /* XXX can do CRC too */ ifp->if_capabilities = IFCAP_VLAN_MTU; /* XXX status check in recv? */ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); /* Initialize MII/media info. */ - mii = &sc->sc_mii; mii->mii_ifp = ifp; mii->mii_readreg = sxie_miibus_readreg; mii->mii_writereg = sxie_miibus_writereg; mii->mii_statchg = sxie_miibus_statchg; ifmedia_init(&mii->mii_media, 0, sxie_ifm_change, sxie_ifm_status); - mii_attach(self, mii, 0xffffffff, phy, MII_OFFSET_ANY, 0); + mii_attach(self, mii, 0xffffffff, phy, MII_OFFSET_ANY, + 0/* XXX could do MIIF_DOPAUSE */); if (LIST_FIRST(&mii->mii_phys) == NULL) { ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); @@ -286,54 +370,120 @@ sxie_attach(struct device *parent, struct device *self, void *aux) ether_ifattach(ifp); splx(s); - sxie_sc = sc; + return; +failout: + if (phy_supply) + regulator_disable(phy_supply); + clock_disable_all(faa->fa_node); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); } void -sxie_socware_init(struct sxie_softc *sc) +sxie_softreset(struct sxie_softc *sc, uint32_t rx_tx_full) { - int have_mac = 0; - uint32_t reg; - - /* MII clock cfg */ - SXICMS4(sc, SXIE_MACMCFG, 15 << 2, 13 << 2); + uint32_t mac0_clr, mac0_set; + uint32_t cmdr_clr, cmdr_set; + + rx_tx_full &= 0x07; + switch (rx_tx_full) { + case SXIE_SRST_RX: + mac0_clr = SXIE_MAC0_RXENABLE; + mac0_set = SXIE_MAC0_RESETMCSRX; + cmdr_clr = SXIE_CMDR_RXENABLE; + cmdr_set = SXIE_CMDR_RXRESET; + break; + case SXIE_SRST_TX: + mac0_clr = /* XXX txflowcontrol? */0; + mac0_set = SXIE_MAC0_RESETMCSTX; + cmdr_clr = SXIE_CMDR_TXENABLE; + cmdr_set = SXIE_CMDR_TXRESET; + break; + default: + case SXIE_SRST_FULL: + mac0_clr = SXIE_MAC0_RXENABLE; + mac0_set = SXIE_MAC0_SOFTRESET; + cmdr_clr = SXIE_CMDR_RXENABLE|SXIE_CMDR_TXENABLE; + cmdr_set = SXIE_CMDR_REGRESET; + break; + } - SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); - SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR); + /* disable, flush(reset), enable */ + SXICLR4(sc, SXIE_MAC0, mac0_clr); + SXICLR4(sc, SXIE_CMDR, cmdr_clr); + SXISET4(sc, SXIE_MAC0, mac0_set); + SXISET4(sc, SXIE_CMDR, cmdr_set); + while (SXIREAD4(sc, SXIE_CMDR) & cmdr_set) + delay(10); - /* - * If u-boot doesn't set emac, use the Security ID area - * to generate a consistent MAC address of. - */ - reg = SXIREAD4(sc, SXIE_MACA0); - if (reg != 0) { - sc->sc_ac.ac_enaddr[3] = reg >> 16 & 0xff; - sc->sc_ac.ac_enaddr[4] = reg >> 8 & 0xff; - sc->sc_ac.ac_enaddr[5] = reg & 0xff; - reg = SXIREAD4(sc, SXIE_MACA1); - sc->sc_ac.ac_enaddr[0] = reg >> 16 & 0xff; - sc->sc_ac.ac_enaddr[1] = reg >> 8 & 0xff; - sc->sc_ac.ac_enaddr[2] = reg & 0xff; - - have_mac = 1; + if (rx_tx_full != SXIE_SRST_FULL) { + SXICLR4(sc, SXIE_MAC0, mac0_set); + SXISET4(sc, SXIE_CMDR, cmdr_clr); + SXISET4(sc, SXIE_MAC0, mac0_clr); + } else { +#if 0 + sxie_setup_interface(sc); + SXICLR4(sc, SXIE_MAC0, mac0_set); +#else + return; +#endif } +} - reg = bus_space_read_4(sc->sc_iot, sc->sc_sid_ioh, 0x0); - - if (!have_mac && reg != 0) { - sc->sc_ac.ac_enaddr[0] = 0x02; - sc->sc_ac.ac_enaddr[1] = reg & 0xff; - reg = bus_space_read_4(sc->sc_iot, sc->sc_sid_ioh, 0x0c); - sc->sc_ac.ac_enaddr[2] = reg >> 24 & 0xff; - sc->sc_ac.ac_enaddr[3] = reg >> 16 & 0xff; - sc->sc_ac.ac_enaddr[4] = reg >> 8 & 0xff; - sc->sc_ac.ac_enaddr[5] = reg & 0xff; +void +sxie_get_lladdr(struct sxie_softc *sc) +{ + uint8_t *enaddr = &sc->sc_ac.ac_enaddr[0]; + bus_space_handle_t sid_ioh; + uint32_t reg; + int eaplen; - have_mac = 1; + eaplen = OF_getproplen(sc->sc_node, "local-mac-address"); + if (eaplen == ETHER_ADDR_LEN) { + OF_getprop(sc->sc_node, "local-mac-address", enaddr, eaplen); + return; + } else if ((reg = SXIREAD4(sc, SXIE_MAC_SA0)) != 0) { + enaddr[3] = reg >> 16 & 0xff; + enaddr[4] = reg >> 8 & 0xff; + enaddr[5] = reg & 0xff; + reg = SXIREAD4(sc, SXIE_MAC_SA1); + enaddr[0] = reg >> 16 & 0xff; + enaddr[1] = reg >> 8 & 0xff; + enaddr[2] = reg & 0xff; + return; + } else + if (bus_space_map(sc->sc_iot, SID_ADDR, SID_SIZE, 0, &sid_ioh) != 0) { + if ((reg = bus_space_read_4(sc->sc_iot, sid_ioh, 0x0)) != 0) { + /* + * If U-Boot doesn't set MAC, use the Security ID + * area to generate a consistent MAC address of. + */ + enaddr[0] = 0x02; + enaddr[1] = reg & 0xff; + reg = bus_space_read_4(sc->sc_iot, sid_ioh, 0x0c); + enaddr[2] = reg >> 24 & 0xff; + enaddr[3] = reg >> 16 & 0xff; + enaddr[4] = reg >> 8 & 0xff; + enaddr[5] = reg & 0xff; + } + bus_space_unmap(sc->sc_iot, sid_ioh, SID_SIZE); + if (reg != 0) + return; } + ether_fakeaddr(&sc->sc_ac.ac_if); +} - if (!have_mac) - ether_fakeaddr(&sc->sc_ac.ac_if); +void +sxie_set_lladdr(struct sxie_softc *sc) +{ + /* set lladdr */ + SXIWRITE4(sc, SXIE_MAC_SA0, + sc->sc_ac.ac_enaddr[3] << 16 | + sc->sc_ac.ac_enaddr[4] << 8 | + sc->sc_ac.ac_enaddr[5]); + SXIWRITE4(sc, SXIE_MAC_SA1, + sc->sc_ac.ac_enaddr[0] << 16 | + sc->sc_ac.ac_enaddr[1] << 8 | + sc->sc_ac.ac_enaddr[2]); } void @@ -341,47 +491,46 @@ sxie_setup_interface(struct sxie_softc *sc, struct device *dev) { uint32_t clr_m, set_m; + /* MII host clock div */ + SXICMS4(sc, SXIE_MAC_MCFG, + SXIE_MAC_MCFG_CLKSEL(15), SXIE_MAC_MCFG_CLKSEL(13)); + /* configure TX */ SXICMS4(sc, SXIE_TXMODE, 3, 1); /* cpu mode */ - /* configure RX */ - clr_m = SXIE_RXDRQM | SXIE_RXTM | SXIE_RXPA | SXIE_RXPCF | - SXIE_RXPCRCE | SXIE_RXPLE | SXIE_RXMHF | SXIE_RXSAF | - SXIE_RXSAIF; - set_m = SXIE_RXPOR | SXIE_RXUCAD | SXIE_RXDAF | SXIE_RXBCO; - SXICMS4(sc, SXIE_RXCR, clr_m, set_m); + /* configure RX filtering */ + clr_m = SXIE_RXDRQM | SXIE_RXTM | + SXIE_RXFILTER_PROMISC | SXIE_RXFILTER_CONTROLFRAMES | + SXIE_RXFILTER_FRAMECRCERR | SXIE_RXFILTER_FRAMELENERR | + SXIE_RXFILTER_MHASHFILTER | SXIE_RXFILTER_SAFILTER | + SXIE_RXFILTER_SAINVFILTER; + set_m = SXIE_RXFILTER_FRAMELENOOR | SXIE_RXFILTER_DAFILTER | + SXIE_RXFILTER_BROADCAST; + SXICMS4(sc, SXIE_RXFILTER_CTRL, clr_m, set_m); /* configure MAC */ - SXISET4(sc, SXIE_MACCR0, SXIE_MACTXFC | SXIE_MACRXFC); - clr_m = SXIE_MACHF | SXIE_MACDCRC | SXIE_MACVC | SXIE_MACADP | - SXIE_MACPRE | SXIE_MACLPE | SXIE_MACNB | SXIE_MACBNB | - SXIE_MACED; - set_m = SXIE_MACFLC | SXIE_MACCRC | SXIE_MACPC; + SXISET4(sc, SXIE_MAC0, SXIE_MAC0_RXFLOWCTRL | SXIE_MAC0_TXFLOWCTRL); + clr_m = SXIE_MAC0_LOOPBACK | SXIE_MAC1_DELAYEDCRC | + SXIE_MAC1_VLANPAD | SXIE_MAC1_AUTOPAD | + SXIE_MAC1_PUREPREAMBLE | SXIE_MAC1_LONGPREAMBLE | + SXIE_MAC1_NOBACKOFF | SXIE_MAC1_BACKPRESSURE | + SXIE_MAC1_EXCESSDEFER; + set_m = SXIE_MAC1_FRAMELENCHECK | SXIE_MAC1_CRC | SXIE_MAC1_PADCRC; set_m |= sxie_miibus_readreg(dev, sc->sc_phyno, 0) >> 8 & 1; - SXICMS4(sc, SXIE_MACCR1, clr_m, set_m); + SXICMS4(sc, SXIE_MAC1, clr_m, set_m); /* XXX */ - SXIWRITE4(sc, SXIE_MACIPGT, 0x0015); - SXIWRITE4(sc, SXIE_MACIPGR, 0x0c12); + SXIWRITE4(sc, SXIE_MAC_IPGT, 0x0015); + SXIWRITE4(sc, SXIE_MAC_IPGR, 0x0c12); /* XXX set collision window */ - SXIWRITE4(sc, SXIE_MACCLRT, 0x370f); + SXIWRITE4(sc, SXIE_MAC_CLRT, 0x370f); /* set max frame length */ - SXIWRITE4(sc, SXIE_MACMFL, SXIE_MAX_PKT_SIZE); + SXIWRITE4(sc, SXIE_MAC_MAXF, SXIE_MAX_PKT_SIZE); /* set lladdr */ - SXIWRITE4(sc, SXIE_MACA0, - sc->sc_ac.ac_enaddr[3] << 16 | - sc->sc_ac.ac_enaddr[4] << 8 | - sc->sc_ac.ac_enaddr[5]); - SXIWRITE4(sc, SXIE_MACA1, - sc->sc_ac.ac_enaddr[0] << 16 | - sc->sc_ac.ac_enaddr[1] << 8 | - sc->sc_ac.ac_enaddr[2]); - - sxie_reset(sc); - /* XXX possibly missing delay in here. */ + sxie_set_lladdr(sc); } void @@ -390,41 +539,44 @@ sxie_init(struct sxie_softc *sc) struct ifnet *ifp = &sc->sc_ac.ac_if; struct device *dev = (struct device *)sc; int phyreg; - - sxie_reset(sc); - SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); + sxie_softreset(sc, SXIE_SRST_FULL); + SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR); - SXISET4(sc, SXIE_RXCR, SXIE_RXFLUSH); - - /* soft reset */ - SXICLR4(sc, SXIE_MACCR0, SXIE_MACSOFTRESET); - - /* zero rx counter */ - SXIWRITE4(sc, SXIE_RXFBC, 0); - sxie_setup_interface(sc, dev); + /* release from softreset */ + SXICLR4(sc, SXIE_MAC0, SXIE_MAC0_SOFTRESET); + /* power up PHY */ sxie_miibus_writereg(dev, sc->sc_phyno, 0, sxie_miibus_readreg(dev, sc->sc_phyno, 0) & ~(1 << 11)); delay(1000); phyreg = sxie_miibus_readreg(dev, sc->sc_phyno, 0); + sxie_iff(sc); + /* set duplex */ - SXICMS4(sc, SXIE_MACCR1, 1, phyreg >> 8 & 1); + SXICMS4(sc, SXIE_MAC1, 1, phyreg >> 8 & 1); /* set speed */ - SXICMS4(sc, SXIE_MACSUPP, 1 << 8, (phyreg >> 13 & 1) << 8); + SXICMS4(sc, SXIE_MAC_SUPP, 1 << 8, (phyreg >> 13 & 1) << 8); + + sc->sc_pauseframe = 0; + sc->sc_tx_timer = 0; + sc->sc_tx_inuse = 0; - SXISET4(sc, SXIE_CR, SXIE_RXTX_ENABLE); + SXISET4(sc, SXIE_CMDR, SXIE_RXTX_ENABLE); /* Indicate we are up and running. */ ifp->if_flags |= IFF_RUNNING; ifq_clr_oactive(&ifp->if_snd); + SXIWRITE4(sc, SXIE_INTCR, SXIE_INTR_DISABLE); + SXISET4(sc, SXIE_INTSR, SXIE_INTR_CLEAR); + SXISET4(sc, SXIE_INTCR, SXIE_INTR_ENABLE); sxie_start(ifp); @@ -451,11 +603,9 @@ sxie_intr(void *arg) } if (pending & (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { - sc->txf_inuse &= ~pending; - if (sc->txf_inuse == 0) - ifp->if_timer = 0; - else - ifp->if_timer = 5; + sc->sc_tx_inuse &= ~(pending & SXIE_TX_FIFOS); + ifp->if_timer = (sc->sc_tx_inuse == 0) ? 0 : 1; + sc->sc_tx_timer = ifp->if_timer ? 5 : 0; if (ifq_is_oactive(&ifp->if_snd)) ifq_restart(&ifp->if_snd); @@ -466,6 +616,48 @@ sxie_intr(void *arg) return 1; } +void +sxie_tx_mbuf_cpu(struct sxie_softc *sc, uint32_t fifo, struct mbuf *m) +{ + uint32_t txbuf[SXIE_MAX_PKT_SIZE / sizeof(uint32_t)]; + + /* copy the actual packet to fifo XXX through 'align buffer' */ + m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txbuf[0]); + bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh, + SXIE_TXIO0, (uint32_t *)&txbuf[0], + SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2); + + /* transmit to PHY from fifo */ + SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1); +} + +void +sxie_tx_mbuf_dma(struct sxie_softc *sc, uint32_t fifo, struct mbuf *m) +{ + /* XXX not yet */ + sxie_tx_mbuf_cpu(sc, fifo, m); +} + +void +sxie_tx_mbuf(struct sxie_softc *sc, struct mbuf *m) +{ + uint32_t fifo = 1; + + /* select fifo */ + fifo <<= sc->sc_tx_inuse & SXIE_TX_FIFO0 ? 1 : 0; + sc->sc_tx_inuse |= fifo--; + SXIWRITE4(sc, SXIE_TXINS, fifo); + + /* set packet length */ + SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len); + + /* transfer to fifo */ + if (sc->sc_dmanode) + sxie_tx_mbuf_dma(sc, fifo, m); + else + sxie_tx_mbuf_cpu(sc, fifo, m); +} + /* * XXX there's secondary tx fifo to be used. */ @@ -474,30 +666,16 @@ sxie_start(struct ifnet *ifp) { struct sxie_softc *sc = ifp->if_softc; struct mbuf *m; - struct mbuf *head; - uint8_t *td; - uint32_t fifo; - uint32_t txbuf[SXIE_MAX_PKT_SIZE / sizeof(uint32_t)]; /* XXX !!! */ if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) return; - - td = (uint8_t *)&txbuf[0]; - m = NULL; - head = NULL; - - for (;;) { - if (sc->txf_inuse == (SXIE_TX_FIFO0 | SXIE_TX_FIFO1)) { - ifq_set_oactive(&ifp->if_snd); - break; - } - - m = ifq_dequeue(&ifp->if_snd); - if (m == NULL) - break; + for (; sc->sc_tx_inuse < SXIE_MAX_TXD; m_freem(m)) { + if ((m = ifq_dequeue(&ifp->if_snd)) == NULL) + return; if (m->m_pkthdr.len > SXIE_MAX_PKT_SIZE) { + SXIEDBG(("sxie_start: packet too big\n")); m_freem(m); continue; } @@ -506,32 +684,12 @@ sxie_start(struct ifnet *ifp) if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif - - /* select fifo */ - if (sc->txf_inuse & SXIE_TX_FIFO0) { - sc->txf_inuse |= SXIE_TX_FIFO1; - fifo = 1; - } else { - sc->txf_inuse |= SXIE_TX_FIFO0; - fifo = 0; - } - SXIWRITE4(sc, SXIE_TXINS, fifo); - - /* set packet length */ - SXIWRITE4(sc, SXIE_TXPKTLEN0 + (fifo * 4), m->m_pkthdr.len); - - /* copy the actual packet to fifo XXX through 'align buffer' */ - m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)td); - bus_space_write_multi_4(sc->sc_iot, sc->sc_ioh, - SXIE_TXIO0, - (uint32_t *)td, SXIE_ROUNDUP(m->m_pkthdr.len, 4) >> 2); - - /* transmit to PHY from fifo */ - SXISET4(sc, SXIE_TXCR0 + (fifo * 4), 1); - ifp->if_timer = 5; - - m_freem(m); + sxie_tx_mbuf(sc, m); + sc->sc_tx_timer = 5; + ifp->if_timer = 1; } + + ifq_set_oactive(&ifp->if_snd); } void @@ -539,35 +697,41 @@ sxie_stop(struct sxie_softc *sc) { struct ifnet *ifp = &sc->sc_ac.ac_if; - sxie_reset(sc); + SXICLR4(sc, SXIE_CMDR, SXIE_CMDR_RXENABLE | SXIE_CMDR_TXENABLE); + + sc->sc_pauseframe = 0; + sc->sc_tx_timer = 0; + sc->sc_tx_inuse = 0; ifp->if_flags &= ~IFF_RUNNING; ifp->if_timer = 0; ifq_clr_oactive(&ifp->if_snd); -} -void -sxie_reset(struct sxie_softc *sc) -{ - /* reset the controller */ - SXIWRITE4(sc, SXIE_CR, 0); - delay(200); - SXIWRITE4(sc, SXIE_CR, 1); - delay(200); + mii_down(&sc->sc_mii); } void sxie_watchdog(struct ifnet *ifp) { struct sxie_softc *sc = ifp->if_softc; - if (sc->pauseframe) { - ifp->if_timer = 5; + + if (sc->sc_pauseframe) { + ifp->if_timer = 1; return; } - printf("%s: watchdog tx timeout\n", sc->sc_dev.dv_xname); - ifp->if_oerrors++; - sxie_init(sc); - sxie_start(ifp); + + if (sc->sc_tx_timer > 0) { + if (--sc->sc_tx_timer == 0) { + if (ifp->if_flags & IFF_DEBUG) + printf("%s: watchdog tx timeout\n", + sc->sc_dev.dv_xname); + ifp->if_oerrors++; + sxie_init(sc); + sxie_start(ifp); + return; + } + ifp->if_timer = 1; + } } /* @@ -582,8 +746,7 @@ sxie_recv(struct sxie_softc *sc) struct mbuf *m; uint16_t pktstat; int16_t pktlen; - int rlen; - char rxbuf[SXIE_MAX_PKT_SIZE]; /* XXX !!! */ + char rxbuf[SXIE_MAX_PKT_SIZE]; trynext: fbc = SXIREAD4(sc, SXIE_RXFBC); if (!fbc) @@ -595,12 +758,7 @@ trynext: */ reg = SXIREAD4(sc, SXIE_RXIO); if (reg != 0x0143414d) { /* invalid packet */ - /* disable, flush, enable */ - SXICLR4(sc, SXIE_CR, SXIE_RX_ENABLE); - SXISET4(sc, SXIE_RXCR, SXIE_RXFLUSH); - while (SXIREAD4(sc, SXIE_RXCR) & SXIE_RXFLUSH); - SXISET4(sc, SXIE_CR, SXIE_RX_ENABLE); - + sxie_softreset(sc, SXIE_SRST_RX); goto err_out; } @@ -608,26 +766,20 @@ trynext: pktstat = (uint16_t)reg >> 16; pktlen = (int16_t)reg; /* length of useful data */ - if (pktstat & SXIE_RX_ERRMASK || pktlen < ETHER_MIN_LEN) { + if (pktstat & SXIE_RX_ERRMASK || pktlen < ETHER_MIN_LEN || + pktlen > SXIE_MAX_PKT_SIZE) { ifp->if_ierrors++; goto trynext; } - if (pktlen > SXIE_MAX_PKT_SIZE) - pktlen = SXIE_MAX_PKT_SIZE; /* XXX is truncating ok? */ /* read the actual packet from fifo XXX through 'align buffer'.. */ - if (pktlen & 3) - rlen = SXIE_ROUNDUP(pktlen, 4); - else - rlen = pktlen; bus_space_read_multi_4(sc->sc_iot, sc->sc_ioh, - SXIE_RXIO, (uint32_t *)&rxbuf[0], rlen >> 2); + SXIE_RXIO, (uint32_t *)&rxbuf[0], + (pktlen & 3 ? SXIE_ROUNDUP(pktlen, 4) : pktlen) >> 2); m = m_devget(&rxbuf[0], pktlen, ETHER_ALIGN); - if (m == NULL) { - ifp->if_ierrors++; + if (m == NULL) goto err_out; - } ml_enqueue(&ml, m); goto trynext; @@ -671,7 +823,7 @@ sxie_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } if (error == ENETRESET) { if (ifp->if_flags & IFF_RUNNING) - sxie_iff(sc, ifp); + sxie_iff(sc); error = 0; } @@ -680,9 +832,43 @@ sxie_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } void -sxie_iff(struct sxie_softc *sc, struct ifnet *ifp) +sxie_iff(struct sxie_softc *sc) { - /* XXX set interface features */ + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct ether_multi *enm; + struct ether_multistep step; + uint64_t rxfhash = 0; + uint32_t h; + uint32_t rxfilt; + + rxfilt = SXIREAD4(sc, SXIE_RXFILTER_CTRL); + ifp->if_flags &= ~IFF_ALLMULTI; + if ((ifp->if_flags & IFF_PROMISC) || ac->ac_multirangecnt > 0) { + ifp->if_flags |= IFF_ALLMULTI; + rxfhash = 0xffffffffffffffffLLU; + } else { + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); + + rxfhash |= 1LLU << (((uint8_t *)&h)[3] >> 2); + + ETHER_NEXT_MULTI(step, enm); + } + } + SXIWRITE4(sc, SXIE_RXHASH0, (uint32_t)rxfhash); + SXIWRITE4(sc, SXIE_RXHASH1, (uint32_t)(rxfhash >> 32)); + + rxfilt |= SXIE_RXFILTER_UNICAST | SXIE_RXFILTER_DAFILTER | + SXIE_RXFILTER_MULTICAST; + if (ifp->if_flags & IFF_ALLMULTI) + rxfilt |= SXIE_RXFILTER_MHASHFILTER; + if (ifp->if_flags & IFF_BROADCAST) + rxfilt |= SXIE_RXFILTER_BROADCAST; + if (ifp->if_flags & IFF_PROMISC) + rxfilt |= SXIE_RXFILTER_PROMISC; + SXIWRITE4(sc, SXIE_RXFILTER_CTRL, rxfilt); } /* @@ -693,21 +879,20 @@ sxie_miibus_readreg(struct device *dev, int phy, int reg) { struct sxie_softc *sc = (struct sxie_softc *)dev; int timo = SXIE_MII_TIMEOUT; + int rv; - SXIWRITE4(sc, SXIE_MACMADR, phy << 8 | reg); - - SXIWRITE4(sc, SXIE_MACMCMD, 1); - while (SXIREAD4(sc, SXIE_MACMIND) & 1 && --timo) + SXIWRITE4(sc, SXIE_MAC_MADR, phy << 8 | reg); + SXIWRITE4(sc, SXIE_MAC_MCMD, 1); + while (SXIREAD4(sc, SXIE_MAC_MIND) & 1 && --timo) delay(10); #ifdef DIAGNOSTIC if (!timo) - printf("%s: sxie_miibus_readreg timeout.\n", - sc->sc_dev.dv_xname); + printf("%s: %s timeout.\n", sc->sc_dev.dv_xname, __func__); #endif - SXIWRITE4(sc, SXIE_MACMCMD, 0); - - return SXIREAD4(sc, SXIE_MACMRDD) & 0xffff; + SXIWRITE4(sc, SXIE_MAC_MCMD, 0); + rv = SXIREAD4(sc, SXIE_MAC_MRDD) & 0xffff; + return rv; } void @@ -716,38 +901,49 @@ sxie_miibus_writereg(struct device *dev, int phy, int reg, int val) struct sxie_softc *sc = (struct sxie_softc *)dev; int timo = SXIE_MII_TIMEOUT; - SXIWRITE4(sc, SXIE_MACMADR, phy << 8 | reg); - - SXIWRITE4(sc, SXIE_MACMCMD, 1); - while (SXIREAD4(sc, SXIE_MACMIND) & 1 && --timo) + SXIWRITE4(sc, SXIE_MAC_MADR, phy << 8 | reg); + SXIWRITE4(sc, SXIE_MAC_MCMD, 1); + while (SXIREAD4(sc, SXIE_MAC_MIND) & 1 && --timo) delay(10); #ifdef DIAGNOSTIC if (!timo) - printf("%s: sxie_miibus_readreg timeout.\n", - sc->sc_dev.dv_xname); + printf("%s: %s timeout.\n", sc->sc_dev.dv_xname, __func__); #endif - SXIWRITE4(sc, SXIE_MACMCMD, 0); - - SXIWRITE4(sc, SXIE_MACMWTD, val); + SXIWRITE4(sc, SXIE_MAC_MCMD, 0); + SXIWRITE4(sc, SXIE_MAC_MWTD, val); } void sxie_miibus_statchg(struct device *dev) { - /* XXX */ -#if 0 struct sxie_softc *sc = (struct sxie_softc *)dev; + uint64_t mma = sc->sc_mii.mii_media_active; + uint64_t _valid = IFM_ACTIVE | IFM_AVALID; + + if ((mma & _valid) != _valid) + return; /* no link */ - switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { + switch (IFM_SUBTYPE(mma)) { case IFM_10_T: + SXICLR4(sc, SXIE_MAC_SUPP, SXIE_MAC_SUPP_SPEED); + break; case IFM_100_TX: - /*case IFM_1000_T: only on GMAC */ + SXISET4(sc, SXIE_MAC_SUPP, SXIE_MAC_SUPP_SPEED); break; default: break; } -#endif + + if (mma & IFM_FLOW) { + SXICMS4(sc, SXIE_MAC0, + SXIE_MAC0_TXFLOWCTRL | SXIE_MAC0_RXFLOWCTRL, + (mma & IFM_ETH_TXPAUSE ? SXIE_MAC0_TXFLOWCTRL : 0) | + (mma & IFM_ETH_RXPAUSE ? SXIE_MAC0_RXFLOWCTRL : 0)); + } else { + SXICLR4(sc, SXIE_MAC0, SXIE_MAC0_TXFLOWCTRL | SXIE_MAC0_RXFLOWCTRL); + } + SXICMS4(sc, SXIE_MAC1, 1, mma & IFM_FDX ? 1 : 0); } int
