From 8da35245abc60fa4828bff63858fb501690b0fd1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 26 Jul 2018 02:39:39 -0700 Subject: [PATCH 01/28] linux/mii.h: Sync with Linux kernel v4.17 This syncs U-Boot's include/linux/mii.h with Linux kernel v4.17 include/uapi/linux/mii.h. While we are here, this also fixes some style issues. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- include/linux/mii.h | 126 ++++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/include/linux/mii.h b/include/linux/mii.h index 19afb74..21db032 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * linux/mii.h: definitions for MII-compatible transceivers * Originally drivers/net/sunhme.h. @@ -9,53 +10,55 @@ #define __LINUX_MII_H__ /* Generic MII registers. */ - -#define MII_BMCR 0x00 /* Basic mode control register */ -#define MII_BMSR 0x01 /* Basic mode status register */ -#define MII_PHYSID1 0x02 /* PHYS ID 1 */ -#define MII_PHYSID2 0x03 /* PHYS ID 2 */ -#define MII_ADVERTISE 0x04 /* Advertisement control reg */ -#define MII_LPA 0x05 /* Link partner ability reg */ -#define MII_EXPANSION 0x06 /* Expansion register */ -#define MII_CTRL1000 0x09 /* 1000BASE-T control */ -#define MII_STAT1000 0x0a /* 1000BASE-T status */ -#define MII_ESTATUS 0x0f /* Extended Status */ -#define MII_DCOUNTER 0x12 /* Disconnect counter */ -#define MII_FCSCOUNTER 0x13 /* False carrier counter */ -#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ -#define MII_RERRCOUNTER 0x15 /* Receive error counter */ -#define MII_SREVISION 0x16 /* Silicon revision */ -#define MII_RESV1 0x17 /* Reserved... */ -#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ -#define MII_PHYADDR 0x19 /* PHY address */ -#define MII_RESV2 0x1a /* Reserved... */ -#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ -#define MII_NCONFIG 0x1c /* Network interface config */ +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define MII_STAT1000 0x0a /* 1000BASE-T status */ +#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */ +#define MII_MMD_DATA 0x0e /* MMD Access Data Register */ +#define MII_ESTATUS 0x0f /* Extended Status */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ /* Basic mode control register. */ -#define BMCR_RESV 0x003f /* Unused... */ -#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ -#define BMCR_CTST 0x0080 /* Collision test */ -#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_RESV 0x003f /* Unused... */ +#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ #define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ -#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ -#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */ +#define BMCR_PDOWN 0x0800 /* Enable low power state */ #define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ -#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ -#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ -#define BMCR_RESET 0x8000 /* Reset the DP83840 */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset to default state */ +#define BMCR_SPEED10 0x0000 /* Select 10Mbps */ /* Basic mode status register. */ -#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ -#define BMSR_JCD 0x0002 /* Jabber detected */ -#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ #define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ #define BMSR_RFAULT 0x0010 /* Remote fault detected */ #define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ -#define BMSR_RESV 0x00c0 /* Unused... */ -#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ -#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ -#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ +#define BMSR_RESV 0x00c0 /* Unused... */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ +#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ #define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ #define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ #define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ @@ -63,7 +66,7 @@ #define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ /* Advertisement control register. */ -#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_SLCT 0x001f /* Selector bits */ #define ADVERTISE_CSMA 0x0001 /* Only selector supported */ #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ #define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ @@ -72,19 +75,19 @@ #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ #define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ +#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ -#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ -#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_RESV 0x1000 /* Unused... */ #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ -#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ -#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ - ADVERTISE_CSMA) -#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ - ADVERTISE_100HALF | ADVERTISE_100FULL) +#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ + ADVERTISE_CSMA) +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL) /* Link partner ability register. */ #define LPA_SLCT 0x001f /* Same as advertise selector */ @@ -97,12 +100,12 @@ #define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ #define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/ #define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ -#define LPA_PAUSE_CAP 0x0400 /* Can pause */ +#define LPA_PAUSE_CAP 0x0400 /* Can pause */ #define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ -#define LPA_RESV 0x1000 /* Unused... */ +#define LPA_RESV 0x1000 /* Unused... */ #define LPA_RFAULT 0x2000 /* Link partner faulted */ #define LPA_LPACK 0x4000 /* Link partner acked us */ -#define LPA_NPAGE 0x8000 /* Next page bit */ +#define LPA_NPAGE 0x8000 /* Next page bit */ #define LPA_DUPLEX (LPA_10FULL | LPA_100FULL) #define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) @@ -113,21 +116,23 @@ #define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ #define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */ #define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ -#define EXPANSION_RESV 0xffe0 /* Unused... */ +#define EXPANSION_RESV 0xffe0 /* Unused... */ #define ESTATUS_1000_XFULL 0x8000 /* Can do 1000BX Full */ #define ESTATUS_1000_XHALF 0x4000 /* Can do 1000BX Half */ -#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ -#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ +#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ +#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ /* N-way test register. */ -#define NWAYTEST_RESV1 0x00ff /* Unused... */ +#define NWAYTEST_RESV1 0x00ff /* Unused... */ #define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ -#define NWAYTEST_RESV2 0xfe00 /* Unused... */ +#define NWAYTEST_RESV2 0xfe00 /* Unused... */ /* 1000BASE-T Control register */ -#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ -#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ +#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ +#define CTL1000_AS_MASTER 0x0800 +#define CTL1000_ENABLE_MASTER 0x1000 /* 1000BASE-T Status register */ #define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */ @@ -139,6 +144,13 @@ #define FLOW_CTRL_TX 0x01 #define FLOW_CTRL_RX 0x02 +/* MMD Access Control register fields */ +#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/ +#define MII_MMD_CTRL_ADDR 0x0000 /* Address */ +#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */ +#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */ +#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */ + /** * mii_nway_result * @negotiated: value of MII ANAR and'd with ANLPAR From 145663991fc3f214d88c22d2240ce30d2f987848 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 26 Jul 2018 02:39:40 -0700 Subject: [PATCH 02/28] linux/mdio.h: Sync with Linux kernel v4.17 This syncs U-Boot's include/linux/mdio.h with Linux kernel v4.17 include/uapi/linux/mdio.h. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- include/linux/mdio.h | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/include/linux/mdio.h b/include/linux/mdio.h index ea20608..6e821d9 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * linux/mdio.h: definitions for MDIO (clause 45) transceivers * Copyright 2006-2009 Solarflare Communications Inc. @@ -42,7 +43,11 @@ #define MDIO_PKGID2 15 #define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */ #define MDIO_AN_LPA 19 /* AN LP abilities (base page) */ +#define MDIO_PCS_EEE_ABLE 20 /* EEE Capability register */ +#define MDIO_PCS_EEE_WK_ERR 22 /* EEE wake error counter */ #define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */ +#define MDIO_AN_EEE_ADV 60 /* EEE advertisement */ +#define MDIO_AN_EEE_LPABLE 61 /* EEE link partner ability */ /* Media-dependent registers. */ #define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */ @@ -55,7 +60,6 @@ #define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */ #define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */ #define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */ -#define MDIO_AN_EEE_ADV 60 /* EEE advertisement */ /* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */ #define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */ @@ -81,6 +85,7 @@ #define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART #define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE #define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */ +#define MDIO_PCS_CTRL1_CLKSTOP_EN 0x400 /* Stop the clock during LPI */ /* 10 Gb/s */ #define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) @@ -245,9 +250,25 @@ #define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */ #define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */ -/* AN EEE Advertisement register. */ -#define MDIO_AN_EEE_ADV_100TX 0x0002 /* Advertise 100TX EEE cap */ -#define MDIO_AN_EEE_ADV_1000T 0x0004 /* Advertise 1000T EEE cap */ +/* EEE Supported/Advertisement/LP Advertisement registers. + * + * EEE capability Register (3.20), Advertisement (7.60) and + * Link partner ability (7.61) registers have and can use the same identical + * bit masks. + */ +#define MDIO_AN_EEE_ADV_100TX 0x0002 /* Advertise 100TX EEE cap */ +#define MDIO_AN_EEE_ADV_1000T 0x0004 /* Advertise 1000T EEE cap */ +/* Note: the two defines above can be potentially used by the user-land + * and cannot remove them now. + * So, we define the new generic MDIO_EEE_100TX and MDIO_EEE_1000T macros + * using the previous ones (that can be considered obsolete). + */ +#define MDIO_EEE_100TX MDIO_AN_EEE_ADV_100TX /* 100TX EEE cap */ +#define MDIO_EEE_1000T MDIO_AN_EEE_ADV_1000T /* 1000T EEE cap */ +#define MDIO_EEE_10GT 0x0008 /* 10GT EEE cap */ +#define MDIO_EEE_1000KX 0x0010 /* 1000KX EEE cap */ +#define MDIO_EEE_10GKX4 0x0020 /* 10G KX4 EEE cap */ +#define MDIO_EEE_10GKR 0x0040 /* 10G KR EEE cap */ /* LASI RX_ALARM control/status registers. */ #define MDIO_PMA_LASI_RX_PHYXSLFLT 0x0001 /* PHY XS RX local fault */ @@ -281,4 +302,9 @@ #define MDIO_DEVAD_NONE (-1) #define MDIO_EMULATE_C22 4 +static inline __u16 mdio_phy_id_c45(int prtad, int devad) +{ + return MDIO_PHY_ID_C45 | (prtad << 5) | devad; +} + #endif /* __LINUX_MDIO_H__ */ From b06d76f9ae2eae389ddaa74abeee7987bdf1b9d4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 26 Jul 2018 03:15:58 -0700 Subject: [PATCH 03/28] linux/compat.h: Add netdev_### log macros Currently there are two ethernet drivers (mvneta.c and mvpp2.c) that has netdev_### (eg: netdev_dbg) log macros defined in its own driver file. This adds these log macros in a common place linux/compat.h. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- drivers/net/mvneta.c | 8 -------- drivers/net/mvpp2.c | 10 ---------- include/linux/compat.h | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index ab697b9..8cb04b5 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -34,14 +34,6 @@ DECLARE_GLOBAL_DATA_PTR; # error Marvell mvneta requires PHYLIB #endif -/* Some linux -> U-Boot compatibility stuff */ -#define netdev_err(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_warn(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_info(dev, fmt, args...) \ - printf(fmt, ##args) - #define CONFIG_NR_CPUS 1 #define ETH_HLEN 14 /* Total octets in header */ diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 62c0c2b..5c1f5fc 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -35,16 +35,6 @@ DECLARE_GLOBAL_DATA_PTR; -/* Some linux -> U-Boot compatibility stuff */ -#define netdev_err(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_warn(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_info(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_dbg(dev, fmt, args...) \ - printf(fmt, ##args) - #define ETH_ALEN 6 /* Octets in one ethernet addr */ #define __verify_pcpu_ptr(ptr) \ diff --git a/include/linux/compat.h b/include/linux/compat.h index 6e3feb6..d0f51ba 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -43,6 +43,25 @@ extern struct p_current *current; #define dev_warn(dev, fmt, args...) \ printf(fmt, ##args) +#define netdev_emerg(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_alert(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_crit(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_err(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_warn(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_notice(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_info(dev, fmt, args...) \ + printf(fmt, ##args) +#define netdev_dbg(dev, fmt, args...) \ + debug(fmt, ##args) +#define netdev_vdbg(dev, fmt, args...) \ + debug(fmt, ##args) + #define GFP_ATOMIC ((gfp_t) 0) #define GFP_KERNEL ((gfp_t) 0) #define GFP_NOFS ((gfp_t) 0) From 339613eba5fecb37d750c2192109f04fefbd5d43 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 29 Jul 2018 00:11:22 -0700 Subject: [PATCH 04/28] net: pch_gbe: Make probe/remove static These two routines are internal to pch_gbe driver. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- drivers/net/pch_gbe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c index d31c45f..2286dd0 100644 --- a/drivers/net/pch_gbe.c +++ b/drivers/net/pch_gbe.c @@ -429,7 +429,7 @@ static int pch_gbe_phy_init(struct udevice *dev) return 0; } -int pch_gbe_probe(struct udevice *dev) +static int pch_gbe_probe(struct udevice *dev) { struct pch_gbe_priv *priv; struct eth_pdata *plat = dev_get_platdata(dev); @@ -464,7 +464,7 @@ int pch_gbe_probe(struct udevice *dev) return pch_gbe_phy_init(dev); } -int pch_gbe_remove(struct udevice *dev) +static int pch_gbe_remove(struct udevice *dev) { struct pch_gbe_priv *priv = dev_get_priv(dev); From 2240d763e54028bfdd52e06b2b0cdba07e43f84f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 31 Jul 2018 02:55:21 -0700 Subject: [PATCH 05/28] linux/if_ether.h: Initial import from Linux kernel v4.17 This imports include/uapi/linux/if_ether.h from Linux kernel v4.17. It can be very helpful When porting Linux ethernet driver to U-Boot. Note it is not exactly the same as the kernel one, as checkpatch issues are fixed. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- include/linux/if_ether.h | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 include/linux/if_ether.h diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h new file mode 100644 index 0000000..af1bb66 --- /dev/null +++ b/include/linux/if_ether.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the Ethernet IEEE 802.3 interface. + * + * Version: @(#)if_ether.h 1.0.1a 02/08/94 + * + * Author: Fred N. van Kempen, + * Donald Becker, + * Alan Cox, + * Steve Whitehouse, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _UAPI_LINUX_IF_ETHER_H +#define _UAPI_LINUX_IF_ETHER_H + +#include + +/* + * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble + * and FCS/CRC (frame check sequence). + */ + +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_TLEN 2 /* Octets in ethernet type field */ +#define ETH_HLEN 14 /* Total octets in header. */ +#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ +#define ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ +#define ETH_FCS_LEN 4 /* Octets in the FCS */ + +#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */ +#define ETH_MAX_MTU 0xFFFFU /* 65535, same as IP_MAX_MTU */ + +/* + * These are the defined Ethernet Protocol ID's. + */ + +#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ +#define ETH_P_PUP 0x0200 /* Xerox PUP packet */ +#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ +#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */ +#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_X25 0x0805 /* CCITT X.25 */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ +#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */ +#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */ +#define ETH_P_BATMAN 0x4305 /* B.A.T.M.A.N.-Advanced packet */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_DEC 0x6000 /* DEC Assigned proto */ +#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ +#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ +#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ +#define ETH_P_LAT 0x6004 /* DEC LAT */ +#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ +#define ETH_P_CUST 0x6006 /* DEC Customer use */ +#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ +#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */ +#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ +#define ETH_P_ATALK 0x809B /* Appletalk DDP */ +#define ETH_P_AARP 0x80F3 /* Appletalk AARP */ +#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ +#define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */ +#define ETH_P_IPX 0x8137 /* IPX over DIX */ +#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ +#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */ +#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */ +#define ETH_P_WCCP 0x883E /* Web-cache coordination */ + /* protocol defined in */ + /* draft-wilson-wrec-wccp-v2-00.txt */ +#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ +#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */ +#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ +#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ +#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ +#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */ +#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport over Ethernet */ +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ +#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ +#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ +#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */ +#define ETH_P_TIPC 0x88CA /* TIPC */ +#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ +#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ +#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */ +#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ +#define ETH_P_NCSI 0x88F8 /* NCSI protocol */ +#define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */ +#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ +#define ETH_P_IBOE 0x8915 /* Infiniband over Ethernet */ +#define ETH_P_TDLS 0x890D /* TDLS */ +#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ +#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent */ + /* Handover Protocol */ +#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */ +#define ETH_P_NSH 0x894F /* Network Service Header */ +#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */ +#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN] */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_EDSA 0xDADA /* Ethertype DSA */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */ +#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv */ + /* [ NOT AN OFFICIALLY REGISTERED ID ] */ + +#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less */ + /* than this value then the frame is Ethernet */ + /* II. Else it is 802.3 */ + +/* + * Non DIX types. Won't clash for 1500 types. + */ + +#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ +#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ +#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ +#define ETH_P_802_2 0x0004 /* 802.2 frames */ +#define ETH_P_SNAP 0x0005 /* Internal only */ +#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ +#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ +#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ +#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ +#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */ +#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/ +#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ +#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ +#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ +#define ETH_P_CONTROL 0x0016 /* Card specific control frames */ +#define ETH_P_IRDA 0x0017 /* Linux-IrDA */ +#define ETH_P_ECONET 0x0018 /* Acorn Econet */ +#define ETH_P_HDLC 0x0019 /* HDLC frames */ +#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */ +#define ETH_P_DSA 0x001B /* Distributed Switch Arch */ +#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */ +#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ +#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ +#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */ +#define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */ +#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and */ + /* aggregation protocol */ + +#endif /* _UAPI_LINUX_IF_ETHER_H */ From dda5251037008b3563ab0aaf443eb7be3213887c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 31 Jul 2018 02:55:22 -0700 Subject: [PATCH 06/28] net.h: Include linux/if_ether.h to avoid duplication There are plenty of existing drivers that have macros like ETH_ALEN defined in their own source files. Now that we imported the kernel's if_ether.h to U-Boot we can reduce some duplication. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- board/Synology/ds414/cmd_syno.c | 1 - drivers/net/dc2114x.c | 1 - drivers/net/eepro100.c | 2 -- drivers/net/mvpp2.c | 3 --- drivers/net/natsemi.c | 1 - drivers/net/ns8382x.c | 1 - drivers/net/rtl8139.c | 4 ---- drivers/net/rtl8169.c | 4 ---- drivers/usb/eth/lan7x.h | 2 +- drivers/usb/gadget/ether.c | 9 ++------- drivers/usb/gadget/rndis.c | 6 ------ include/net.h | 1 + include/usb_ether.h | 10 ---------- 13 files changed, 4 insertions(+), 41 deletions(-) diff --git a/board/Synology/ds414/cmd_syno.c b/board/Synology/ds414/cmd_syno.c index 34643ff..59e6fe0 100644 --- a/board/Synology/ds414/cmd_syno.c +++ b/board/Synology/ds414/cmd_syno.c @@ -14,7 +14,6 @@ #include #include "../drivers/ddr/marvell/axp/ddr3_init.h" -#define ETH_ALEN 6 #define ETHADDR_MAX 4 #define SYNO_SN_TAG "SN=" #define SYNO_CHKSUM_TAG "CHK=" diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 8d7c271..e3c403c 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -123,7 +123,6 @@ #define TOUT_LOOP 1000000 #define SETUP_FRAME_LEN 192 -#define ETH_ALEN 6 struct de4x5_desc { volatile s32 status; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index ae65b64..2fe0ba6 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -193,8 +193,6 @@ struct descriptor { /* A generic descriptor. */ #define TOUT_LOOP 1000000 -#define ETH_ALEN 6 - static struct RxFD rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ static struct TxFD tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ static int rx_next; /* RX descriptor ring pointer */ diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 5c1f5fc..f34245b 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -35,8 +35,6 @@ DECLARE_GLOBAL_DATA_PTR; -#define ETH_ALEN 6 /* Octets in one ethernet addr */ - #define __verify_pcpu_ptr(ptr) \ do { \ const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \ @@ -58,7 +56,6 @@ do { \ #define NET_SKB_PAD max(32, MVPP2_CPU_D_CACHE_LINE_SIZE) #define CONFIG_NR_CPUS 1 -#define ETH_HLEN ETHER_HDR_SIZE /* Total octets in header */ /* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */ #define WRAP (2 + ETH_HLEN + 4 + 32) diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 0ed9bb5..86f6898 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -61,7 +61,6 @@ #define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/ #define DSIZE 0x00000FFF -#define ETH_ALEN 6 #define CRC_SIZE 4 #define TOUT_LOOP 500000 #define TX_BUF_SIZE 1536 diff --git a/drivers/net/ns8382x.c b/drivers/net/ns8382x.c index f941c15..ea7ece5 100644 --- a/drivers/net/ns8382x.c +++ b/drivers/net/ns8382x.c @@ -59,7 +59,6 @@ /* defines */ #define DSIZE 0x00000FFF -#define ETH_ALEN 6 #define CRC_SIZE 4 #define TOUT_LOOP 500000 #define TX_BUF_SIZE 1536 diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index ea52343..590f8ce 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -80,10 +80,6 @@ #define RTL_TIMEOUT 100000 -#define ETH_FRAME_LEN 1514 -#define ETH_ALEN 6 -#define ETH_ZLEN 60 - /* PCI Tuning Parameters Threshold is bytes transferred to chip before transmission starts. */ #define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index e0e3a6d..a78f3d2 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -102,10 +102,6 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #define RTL_R16(reg) readw(ioaddr + (reg)) #define RTL_R32(reg) readl(ioaddr + (reg)) -#define ETH_FRAME_LEN MAX_ETH_FRAME_SIZE -#define ETH_ALEN MAC_ADDR_LEN -#define ETH_ZLEN 60 - #define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)(unsigned long)dev->priv, \ (pci_addr_t)(unsigned long)a) #define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)(unsigned long)dev->priv, \ diff --git a/drivers/usb/eth/lan7x.h b/drivers/usb/eth/lan7x.h index d1b1047..7af610b 100644 --- a/drivers/usb/eth/lan7x.h +++ b/drivers/usb/eth/lan7x.h @@ -94,7 +94,7 @@ #define LAN7X_MAC_RX_MAX_SIZE(mtu) \ ((mtu) << 16) /* Max frame size */ #define LAN7X_MAC_RX_MAX_SIZE_DEFAULT \ - LAN7X_MAC_RX_MAX_SIZE(ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */) + LAN7X_MAC_RX_MAX_SIZE(PKTSIZE_ALIGN + 4 /* VLAN */ + 4 /* CRC */) /* Timeouts */ #define USB_CTRL_SET_TIMEOUT_MS 5000 diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 8ab9b9f..90ef1f0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -71,11 +71,6 @@ unsigned packet_received, packet_sent; * RNDIS specs are ambiguous and appear to be incomplete, and are also * needlessly complex. They borrow more from CDC ACM than CDC ECM. */ -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */ #define DRIVER_DESC "Ethernet Gadget" /* Based on linux 2.6.27 version */ @@ -529,7 +524,7 @@ static const struct usb_cdc_ether_desc ether_desc = { /* this descriptor actually adds value, surprise! */ .iMACAddress = STRING_ETHADDR, .bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = __constant_cpu_to_le16(ETH_FRAME_LEN), + .wMaxSegmentSize = __constant_cpu_to_le16(PKTSIZE_ALIGN), .wNumberMCFilters = __constant_cpu_to_le16(0), .bNumberPowerFilters = 0, }; @@ -1575,7 +1570,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) req->length -= length; req->actual -= length; } - if (req->actual < ETH_HLEN || ETH_FRAME_LEN < req->actual) { + if (req->actual < ETH_HLEN || PKTSIZE_ALIGN < req->actual) { length_err: dev->stats.rx_errors++; dev->stats.rx_length_errors++; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d47e29e..eec639f 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -35,12 +35,6 @@ #include "rndis.h" -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */ - /* * The driver for your USB chip needs to support ep0 OUT to work with * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). diff --git a/include/net.h b/include/net.h index 2b2deb5..156bdc1 100644 --- a/include/net.h +++ b/include/net.h @@ -14,6 +14,7 @@ #include #include /* for nton* / ntoh* stuff */ +#include #define DEBUG_LL_STATE 0 /* Link local state machine changes */ #define DEBUG_DEV_PKT 0 /* Packets or info directed to the device */ diff --git a/include/usb_ether.h b/include/usb_ether.h index 49f47d3..e85acad 100644 --- a/include/usb_ether.h +++ b/include/usb_ether.h @@ -8,16 +8,6 @@ #include -/* - * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble - * and FCS/CRC (frame check sequence). - */ -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */ - /* TODO(sjg@chromium.org): Remove @pusb_dev when all boards use CONFIG_DM_ETH */ struct ueth_data { /* eth info */ From 883b5302fc71c97a838e7d4d5d45e85492f582ec Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 31 Jul 2018 02:55:23 -0700 Subject: [PATCH 07/28] linux/if_ether.h: Add VLAN related macros There are VLAN related macros defined in include/linux/if_vlan.h in Linux kernel, as well as some kernel useful structures and inline functions. Instead of a complete import from kernel, let's add these VLAN macros to U-Boot's include/linux/if_ether.h. Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- include/linux/if_ether.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index af1bb66..0d62aef 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -155,4 +155,24 @@ #define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and */ /* aggregation protocol */ +/* The following macros come from Linux kernel include/linux/if_vlan.h */ + +#define VLAN_HLEN 4 /* The additional bytes required by VLAN */ + /* (in addition to the Ethernet header) */ +#define VLAN_ETH_HLEN 18 /* Total octets in header. */ +#define VLAN_ETH_ZLEN 64 /* Min. octets in frame sans FCS */ + +/* + * According to 802.3ac, the packet can be 4 bytes longer. --Klika Jan + */ +#define VLAN_ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define VLAN_ETH_FRAME_LEN 1518 /* Max. octets in frame sans FCS */ + +#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ +#define VLAN_PRIO_SHIFT 13 +#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ +#define VLAN_TAG_PRESENT VLAN_CFI_MASK +#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ +#define VLAN_N_VID 4096 + #endif /* _UAPI_LINUX_IF_ETHER_H */ From fba725f41002e5035e601a7cfa9429b0c8184211 Mon Sep 17 00:00:00 2001 From: Janine Hagemann Date: Tue, 28 Aug 2018 08:25:37 +0200 Subject: [PATCH 08/28] net: phy: ti: Add lane swapping support in the DP83867 TI's PHY driver This patch adds support for enabling or disabling the lane swapping (called "port mirroring" in PHY's CFG4 register) feature of the DP83867 TI's PHY device. One use case is when bootstrap configuration enables this feature (because of e.g. LED_0 wrong wiring) so then one needs to disable it in software (at u-boot/Linux). Based on commit fc6d39c39581 ("net: phy: dp83867: Add lane swapping support in the DP83867 TI's PHY driver") of mainline linux kernel. Signed-off-by: Janine Hagemann Acked-by: Lukasz Majewski Acked-by: Joe Hershberger --- doc/device-tree-bindings/net/ti,dp83867.txt | 5 ++++ drivers/net/phy/ti.c | 39 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/doc/device-tree-bindings/net/ti,dp83867.txt b/doc/device-tree-bindings/net/ti,dp83867.txt index cb77fdf..f31c2da 100644 --- a/doc/device-tree-bindings/net/ti,dp83867.txt +++ b/doc/device-tree-bindings/net/ti,dp83867.txt @@ -8,6 +8,10 @@ Required properties: for applicable values - ti,fifo-depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h for applicable values + - enet-phy-lane-swap - Indicates that PHY will swap the TX/RX lanes to + compensate for the board being designed with the lanes swapped. + - enet-phy-no-lane-swap - Indicates that PHY will disable swap of the + TX/RX lanes. Default child nodes are standard Ethernet PHY device nodes as described in doc/devicetree/bindings/net/ethernet.txt @@ -19,6 +23,7 @@ Example: ti,rx-internal-delay = ; ti,tx-internal-delay = ; ti,fifo-depth = ; + enet-phy-lane-no-swap; }; Datasheet can be found: diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index f870e6d..cef5942 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -89,12 +89,22 @@ #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +/* CFG4 bits */ +#define DP83867_CFG4_PORT_MIRROR_EN BIT(0) + +enum { + DP83867_PORT_MIRRORING_KEEP, + DP83867_PORT_MIRRORING_EN, + DP83867_PORT_MIRRORING_DIS, +}; + struct dp83867_private { int rx_id_delay; int tx_id_delay; int fifo_depth; int io_impedance; bool rxctrl_strap_quirk; + int port_mirroring; }; /** @@ -163,6 +173,26 @@ void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, phy_write(phydev, addr, MII_MMD_DATA, data); } +static int dp83867_config_port_mirroring(struct phy_device *phydev) +{ + struct dp83867_private *dp83867 = + (struct dp83867_private *)phydev->priv; + u16 val; + + val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, + phydev->addr); + + if (dp83867->port_mirroring == DP83867_PORT_MIRRORING_EN) + val |= DP83867_CFG4_PORT_MIRROR_EN; + else + val &= ~DP83867_CFG4_PORT_MIRROR_EN; + + phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, + phydev->addr, val); + + return 0; +} + #if defined(CONFIG_DM_ETH) /** * dp83867_data_init - Convenience function for setting PHY specific data @@ -197,6 +227,12 @@ static int dp83867_of_init(struct phy_device *phydev) dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth", -1); + if (ofnode_read_bool(node, "enet-phy-lane-swap")) + dp83867->port_mirroring = DP83867_PORT_MIRRORING_EN; + + if (ofnode_read_bool(node, "enet-phy-lane-no-swap")) + dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS; + return 0; } @@ -315,6 +351,9 @@ static int dp83867_config(struct phy_device *phydev) } } + if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) + dp83867_config_port_mirroring(phydev); + genphy_config_aneg(phydev); return 0; From be71a74c59b7f34e83f3f6ea4b1a838de356c654 Mon Sep 17 00:00:00 2001 From: Janine Hagemann Date: Tue, 28 Aug 2018 08:25:38 +0200 Subject: [PATCH 09/28] net: phy: ti: Recover from "port mirroring" N/A MODE4 The DP83867 when not properly bootstrapped - especially with LED_0 pin - can enter N/A MODE4 for "port mirroring" feature. To provide normal operation of the PHY, one needs not only to explicitly disable the port mirroring feature, but as well stop some IC internal testing (which disables RGMII communication). To do that the STRAP_STS1 (0x006E) register must be read and RESERVED bit 11 examined. When it is set, the another RESERVED bit (11) at PHYCR (0x0010) register must be clear to disable testing mode and enable RGMII communication. Thorough explanation of the problem can be found at following e2e thread: "DP83867IR: Problem with RESERVED bits in PHY Control Register (PHYCR) - Linux driver" https://e2e.ti.com/support/interface/ethernet/f/903/p/571313/2096954#2096954 Based on commit ac6e058b75be ("net: phy: dp83867: Recover from "port mirroring" N/A MODE4") of mainline linux kernel. Signed-off-by: Janine Hagemann Acked-by: Joe Hershberger Acked-by: Lukasz Majewski --- drivers/net/phy/ti.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index cef5942..e27ee32 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -24,6 +24,7 @@ /* Extended Registers */ #define DP83867_CFG4 0x0031 #define DP83867_RGMIICTL 0x0032 +#define DP83867_STRAP_STS1 0x006E #define DP83867_RGMIIDCTL 0x0086 #define DP83867_IO_MUX_CFG 0x0170 @@ -48,8 +49,12 @@ #define DP83867_RGMII_TX_CLK_DELAY_EN BIT(1) #define DP83867_RGMII_RX_CLK_DELAY_EN BIT(0) +/* STRAP_STS1 bits */ +#define DP83867_STRAP_STS1_RESERVED BIT(11) + /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_PHYCR_RESERVED_MASK BIT(11) #define DP83867_MDI_CROSSOVER 5 #define DP83867_MDI_CROSSOVER_AUTO 2 #define DP83867_MDI_CROSSOVER_MDIX 2 @@ -254,7 +259,7 @@ static int dp83867_config(struct phy_device *phydev) { struct dp83867_private *dp83867; unsigned int val, delay, cfg2; - int ret; + int ret, bs; if (!phydev->priv) { dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL); @@ -289,6 +294,26 @@ static int dp83867_config(struct phy_device *phydev) (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); if (ret) goto err_out; + + /* The code below checks if "port mirroring" N/A MODE4 has been + * enabled during power on bootstrap. + * + * Such N/A mode enabled by mistake can put PHY IC in some + * internal testing mode and disable RGMII transmission. + * + * In this particular case one needs to check STRAP_STS1 + * register's bit 11 (marked as RESERVED). + */ + + bs = phy_read_mmd_indirect(phydev, DP83867_STRAP_STS1, + DP83867_DEVADDR, phydev->addr); + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); + if (bs & DP83867_STRAP_STS1_RESERVED) { + val &= ~DP83867_PHYCR_RESERVED_MASK; + phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, + val); + } + } else if (phy_interface_is_sgmii(phydev)) { phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000)); From 0f347a0096ad0c1e56d1b18b7eb60731d40d49c2 Mon Sep 17 00:00:00 2001 From: Janine Hagemann Date: Tue, 28 Aug 2018 08:25:39 +0200 Subject: [PATCH 10/28] net: phy: ti: Add binding for the CLK_OUT pin muxing The DP83867 has a muxing option for the CLK_OUT pin. It is possible to set CLK_OUT for different channels. Create a binding to select a specific clock for CLK_OUT pin. Based on commit 9708fb630d19 ("net: phy: dp83867: Add binding for the CLK_OUT pin muxing option") of mainline linux kernel. Signed-off-by: Janine Hagemann Acked-by: Joe Hershberger --- doc/device-tree-bindings/net/ti,dp83867.txt | 3 +++ drivers/net/phy/ti.c | 27 +++++++++++++++++++++++++++ include/dt-bindings/net/ti-dp83867.h | 15 +++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/doc/device-tree-bindings/net/ti,dp83867.txt b/doc/device-tree-bindings/net/ti,dp83867.txt index f31c2da..034146f 100644 --- a/doc/device-tree-bindings/net/ti,dp83867.txt +++ b/doc/device-tree-bindings/net/ti,dp83867.txt @@ -12,6 +12,8 @@ Required properties: compensate for the board being designed with the lanes swapped. - enet-phy-no-lane-swap - Indicates that PHY will disable swap of the TX/RX lanes. + - ti,clk-output-sel - Clock output select - see dt-bindings/net/ti-dp83867.h + for applicable values Default child nodes are standard Ethernet PHY device nodes as described in doc/devicetree/bindings/net/ethernet.txt @@ -24,6 +26,7 @@ Example: ti,tx-internal-delay = ; ti,fifo-depth = ; enet-phy-lane-no-swap; + ti,clk-output-sel = ; }; Datasheet can be found: diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index e27ee32..6db6edd 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -93,6 +93,9 @@ #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +#define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 +#define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK \ + GENMASK(0x1f, DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT) /* CFG4 bits */ #define DP83867_CFG4_PORT_MIRROR_EN BIT(0) @@ -110,6 +113,7 @@ struct dp83867_private { int io_impedance; bool rxctrl_strap_quirk; int port_mirroring; + int clk_output_sel; }; /** @@ -208,6 +212,18 @@ static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; ofnode node; + u16 val; + + /* Optional configuration */ + + /* + * Keep the default value if ti,clk-output-sel is not set + * or to high + */ + + dp83867->clk_output_sel = + ofnode_read_u32_default(node, "ti,clk-output-sel", + DP83867_CLK_O_SEL_REF_CLK); node = phy_get_ofnode(phydev); if (!ofnode_valid(node)) @@ -239,6 +255,17 @@ static int dp83867_of_init(struct phy_device *phydev) dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS; + /* Clock output selection if muxing property is set */ + if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) { + val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG, + DP83867_DEVADDR, phydev->addr); + val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK; + val |= (dp83867->clk_output_sel << + DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT); + phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG, + DP83867_DEVADDR, phydev->addr, val); + } + return 0; } #else diff --git a/include/dt-bindings/net/ti-dp83867.h b/include/dt-bindings/net/ti-dp83867.h index b8e5df6..85d08f6 100644 --- a/include/dt-bindings/net/ti-dp83867.h +++ b/include/dt-bindings/net/ti-dp83867.h @@ -31,4 +31,19 @@ #define DP83867_RGMIIDCTL_3_75_NS 0xe #define DP83867_RGMIIDCTL_4_00_NS 0xf +/* IO_MUX_CFG - Clock output selection */ +#define DP83867_CLK_O_SEL_CHN_A_RCLK 0x0 +#define DP83867_CLK_O_SEL_CHN_B_RCLK 0x1 +#define DP83867_CLK_O_SEL_CHN_C_RCLK 0x2 +#define DP83867_CLK_O_SEL_CHN_D_RCLK 0x3 +#define DP83867_CLK_O_SEL_CHN_A_RCLK_DIV5 0x4 +#define DP83867_CLK_O_SEL_CHN_B_RCLK_DIV5 0x5 +#define DP83867_CLK_O_SEL_CHN_C_RCLK_DIV5 0x6 +#define DP83867_CLK_O_SEL_CHN_D_RCLK_DIV5 0x7 +#define DP83867_CLK_O_SEL_CHN_A_TCLK 0x8 +#define DP83867_CLK_O_SEL_CHN_B_TCLK 0x9 +#define DP83867_CLK_O_SEL_CHN_C_TCLK 0xA +#define DP83867_CLK_O_SEL_CHN_D_TCLK 0xB +#define DP83867_CLK_O_SEL_REF_CLK 0xC + #endif From 5b7239860830dab2ed47814875729f06109725df Mon Sep 17 00:00:00 2001 From: Priyanka Jain Date: Mon, 27 Aug 2018 15:15:19 +0530 Subject: [PATCH 11/28] phy: Add 25G_AUI, XLAUI, CAUI2, CAUI4 related macros NXP SoCs like LX2160A can support new ethernet modes which are 25G_AUI(25G), XLAUI(40G), CAUI2(50G) and CAUI4(100G) Add corresponding macros definitions in phy_interface.h Signed-off-by: Priyanka Jain Acked-by: Joe Hershberger --- include/phy_interface.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/phy_interface.h b/include/phy_interface.h index 0760d65..c682318 100644 --- a/include/phy_interface.h +++ b/include/phy_interface.h @@ -27,6 +27,10 @@ typedef enum { PHY_INTERFACE_MODE_RXAUI, PHY_INTERFACE_MODE_SFI, PHY_INTERFACE_MODE_INTERNAL, + PHY_INTERFACE_MODE_25G_AUI, + PHY_INTERFACE_MODE_XLAUI, + PHY_INTERFACE_MODE_CAUI2, + PHY_INTERFACE_MODE_CAUI4, PHY_INTERFACE_MODE_NONE, /* Must be last */ PHY_INTERFACE_MODE_COUNT, @@ -50,6 +54,10 @@ static const char * const phy_interface_strings[] = { [PHY_INTERFACE_MODE_RXAUI] = "rxaui", [PHY_INTERFACE_MODE_SFI] = "sfi", [PHY_INTERFACE_MODE_INTERNAL] = "internal", + [PHY_INTERFACE_MODE_25G_AUI] = "25g-aui", + [PHY_INTERFACE_MODE_XLAUI] = "xlaui4", + [PHY_INTERFACE_MODE_CAUI2] = "caui2", + [PHY_INTERFACE_MODE_CAUI4] = "caui4", [PHY_INTERFACE_MODE_NONE] = "", }; From e4ab9a65081f032495533af7474d52ff17dd5d27 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:53 -0500 Subject: [PATCH 12/28] net: sandbox: Move disabled flag into priv struct Store the per-device data with the device. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- drivers/net/sandbox.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index b71c8f8..60fe065 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -19,17 +19,18 @@ DECLARE_GLOBAL_DATA_PTR; * * fake_host_hwaddr: MAC address of mocked machine * fake_host_ipaddr: IP address of mocked machine + * disabled: Will not respond * recv_packet_buffer: buffer of the packet returned as received * recv_packet_length: length of the packet returned as received */ struct eth_sandbox_priv { uchar fake_host_hwaddr[ARP_HLEN]; struct in_addr fake_host_ipaddr; + bool disabled; uchar *recv_packet_buffer; int recv_packet_length; }; -static bool disabled[8] = {false}; static bool skip_timeout; /* @@ -40,7 +41,16 @@ static bool skip_timeout; */ void sandbox_eth_disable_response(int index, bool disable) { - disabled[index] = disable; + struct udevice *dev; + struct eth_sandbox_priv *priv; + int ret; + + ret = uclass_get_device(UCLASS_ETH, index, &dev); + if (ret) + return; + + priv = dev_get_priv(dev); + priv->disabled = disable; } /* @@ -71,8 +81,7 @@ static int sb_eth_send(struct udevice *dev, void *packet, int length) debug("eth_sandbox: Send packet %d\n", length); - if (dev->seq >= 0 && dev->seq < ARRAY_SIZE(disabled) && - disabled[dev->seq]) + if (priv->disabled) return 0; if (ntohs(eth->et_protlen) == PROT_ARP) { @@ -212,6 +221,7 @@ static int sb_eth_ofdata_to_platdata(struct udevice *dev) return -EINVAL; } memcpy(priv->fake_host_hwaddr, mac, ARP_HLEN); + priv->disabled = false; return 0; } From e95bb1611043ff1ad5b63602e32bba302e402491 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:54 -0500 Subject: [PATCH 13/28] net: sandbox: Refactor sandbox send function Make the behavior of the send function reusable. Signed-off-by: Joe Hershberger Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 26 ++++++ drivers/net/sandbox.c | 180 ++++++++++++++++++++++++----------------- 2 files changed, 132 insertions(+), 74 deletions(-) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index bfcd11b..3dc84f0 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -13,4 +13,30 @@ void sandbox_eth_disable_response(int index, bool disable); void sandbox_eth_skip_timeout(void); +/* + * sandbox_eth_arp_req_to_reply() + * + * Check for an arp request to be sent. If so, inject a reply + * + * @dev: device that received the packet + * @packet: pointer to the received pacaket buffer + * @len: length of received packet + * @return 0 if injected, -EAGAIN if not + */ +int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet, + unsigned int len); + +/* + * sandbox_eth_ping_req_to_reply() + * + * Check for a ping request to be sent. If so, inject a reply + * + * @dev: device that received the packet + * @packet: pointer to the received pacaket buffer + * @len: length of received packet + * @return 0 if injected, -EAGAIN if not + */ +int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, + unsigned int len); + #endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 60fe065..c472261 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -63,6 +63,108 @@ void sandbox_eth_skip_timeout(void) skip_timeout = true; } +/* + * sandbox_eth_arp_req_to_reply() + * + * Check for an arp request to be sent. If so, inject a reply + * + * returns 0 if injected, -EAGAIN if not + */ +int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct arp_hdr *arp; + struct ethernet_hdr *eth_recv; + struct arp_hdr *arp_recv; + + if (ntohs(eth->et_protlen) != PROT_ARP) + return -EAGAIN; + + arp = packet + ETHER_HDR_SIZE; + + if (ntohs(arp->ar_op) != ARPOP_REQUEST) + return -EAGAIN; + + /* store this as the assumed IP of the fake host */ + priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa); + + /* Formulate a fake response */ + eth_recv = (void *)priv->recv_packet_buffer; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_recv->et_protlen = htons(PROT_ARP); + + arp_recv = (void *)eth_recv + ETHER_HDR_SIZE; + arp_recv->ar_hrd = htons(ARP_ETHER); + arp_recv->ar_pro = htons(PROT_IP); + arp_recv->ar_hln = ARP_HLEN; + arp_recv->ar_pln = ARP_PLEN; + arp_recv->ar_op = htons(ARPOP_REPLY); + memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN); + net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); + net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa); + + priv->recv_packet_length = ETHER_HDR_SIZE + ARP_HDR_SIZE; + + return 0; +} + +/* + * sandbox_eth_ping_req_to_reply() + * + * Check for a ping request to be sent. If so, inject a reply + * + * returns 0 if injected, -EAGAIN if not + */ +int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct ip_udp_hdr *ip; + struct icmp_hdr *icmp; + struct ethernet_hdr *eth_recv; + struct ip_udp_hdr *ipr; + struct icmp_hdr *icmpr; + + if (ntohs(eth->et_protlen) != PROT_IP) + return -EAGAIN; + + ip = packet + ETHER_HDR_SIZE; + + if (ip->ip_p != IPPROTO_ICMP) + return -EAGAIN; + + icmp = (struct icmp_hdr *)&ip->udp_src; + + if (icmp->type != ICMP_ECHO_REQUEST) + return -EAGAIN; + + /* reply to the ping */ + eth_recv = (void *)priv->recv_packet_buffer; + memcpy(eth_recv, packet, len); + ipr = (void *)eth_recv + ETHER_HDR_SIZE; + icmpr = (struct icmp_hdr *)&ipr->udp_src; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + ipr->ip_sum = 0; + ipr->ip_off = 0; + net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src); + net_write_ip((void *)&ipr->ip_src, priv->fake_host_ipaddr); + ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); + + icmpr->type = ICMP_ECHO_REPLY; + icmpr->checksum = 0; + icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE); + + priv->recv_packet_length = len; + + return 0; +} + static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); @@ -77,86 +179,16 @@ static int sb_eth_start(struct udevice *dev) static int sb_eth_send(struct udevice *dev, void *packet, int length) { struct eth_sandbox_priv *priv = dev_get_priv(dev); - struct ethernet_hdr *eth = packet; debug("eth_sandbox: Send packet %d\n", length); if (priv->disabled) return 0; - if (ntohs(eth->et_protlen) == PROT_ARP) { - struct arp_hdr *arp = packet + ETHER_HDR_SIZE; - - if (ntohs(arp->ar_op) == ARPOP_REQUEST) { - struct ethernet_hdr *eth_recv; - struct arp_hdr *arp_recv; - - /* store this as the assumed IP of the fake host */ - priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa); - /* Formulate a fake response */ - eth_recv = (void *)priv->recv_packet_buffer; - memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); - memcpy(eth_recv->et_src, priv->fake_host_hwaddr, - ARP_HLEN); - eth_recv->et_protlen = htons(PROT_ARP); - - arp_recv = (void *)priv->recv_packet_buffer + - ETHER_HDR_SIZE; - arp_recv->ar_hrd = htons(ARP_ETHER); - arp_recv->ar_pro = htons(PROT_IP); - arp_recv->ar_hln = ARP_HLEN; - arp_recv->ar_pln = ARP_PLEN; - arp_recv->ar_op = htons(ARPOP_REPLY); - memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, - ARP_HLEN); - net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr); - memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); - net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa); - - priv->recv_packet_length = ETHER_HDR_SIZE + - ARP_HDR_SIZE; - } - } else if (ntohs(eth->et_protlen) == PROT_IP) { - struct ip_udp_hdr *ip = packet + ETHER_HDR_SIZE; - - if (ip->ip_p == IPPROTO_ICMP) { - struct icmp_hdr *icmp = (struct icmp_hdr *)&ip->udp_src; - - if (icmp->type == ICMP_ECHO_REQUEST) { - struct ethernet_hdr *eth_recv; - struct ip_udp_hdr *ipr; - struct icmp_hdr *icmpr; - - /* reply to the ping */ - memcpy(priv->recv_packet_buffer, packet, - length); - eth_recv = (void *)priv->recv_packet_buffer; - ipr = (void *)priv->recv_packet_buffer + - ETHER_HDR_SIZE; - icmpr = (struct icmp_hdr *)&ipr->udp_src; - memcpy(eth_recv->et_dest, eth->et_src, - ARP_HLEN); - memcpy(eth_recv->et_src, priv->fake_host_hwaddr, - ARP_HLEN); - ipr->ip_sum = 0; - ipr->ip_off = 0; - net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src); - net_write_ip((void *)&ipr->ip_src, - priv->fake_host_ipaddr); - ipr->ip_sum = compute_ip_checksum(ipr, - IP_HDR_SIZE); - - icmpr->type = ICMP_ECHO_REPLY; - icmpr->checksum = 0; - icmpr->checksum = compute_ip_checksum(icmpr, - ICMP_HDR_SIZE); - - priv->recv_packet_length = length; - } - } - } - - return 0; + if (!sandbox_eth_arp_req_to_reply(dev, packet, length)) + return 0; + if (!sandbox_eth_ping_req_to_reply(dev, packet, length)) + return 0; } static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp) From c7eb733d606667508b69ee922e9738d55259304e Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:55 -0500 Subject: [PATCH 14/28] net: sandbox: Make the fake eth driver response configurable Make the send handler registerable so tests can check for different things. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 17 +++++++++++++ drivers/net/sandbox.c | 55 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index 3dc84f0..2017586 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -39,4 +39,21 @@ int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet, int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, unsigned int len); +/** + * A packet handler + * + * dev - device pointer + * pkt - pointer to the "sent" packet + * len - packet length + */ +typedef int sandbox_eth_tx_hand_f(struct udevice *dev, void *pkt, + unsigned int len); + +/* + * Set packet handler + * + * handler - The func ptr to call on send. If NULL, set to default handler + */ +void sandbox_eth_set_tx_handler(int index, sandbox_eth_tx_hand_f *handler); + #endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index c472261..db461b8 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -10,6 +10,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -22,6 +23,7 @@ DECLARE_GLOBAL_DATA_PTR; * disabled: Will not respond * recv_packet_buffer: buffer of the packet returned as received * recv_packet_length: length of the packet returned as received + * tx_handler - function to generate responses to sent packets */ struct eth_sandbox_priv { uchar fake_host_hwaddr[ARP_HLEN]; @@ -29,6 +31,7 @@ struct eth_sandbox_priv { bool disabled; uchar *recv_packet_buffer; int recv_packet_length; + sandbox_eth_tx_hand_f *tx_handler; }; static bool skip_timeout; @@ -165,6 +168,52 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, return 0; } +/* + * sb_default_handler() + * + * perform typical responses to simple ping + * + * dev - device pointer + * pkt - "sent" packet buffer + * len - length of packet + */ +static int sb_default_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + if (!sandbox_eth_arp_req_to_reply(dev, packet, len)) + return 0; + if (!sandbox_eth_ping_req_to_reply(dev, packet, len)) + return 0; + + return 0; +} + +/* + * sandbox_eth_set_tx_handler() + * + * Set a custom response to a packet being sent through the sandbox eth test + * driver + * + * index - interface to set the handler for + * handler - The func ptr to call on send. If NULL, set to default handler + */ +void sandbox_eth_set_tx_handler(int index, sandbox_eth_tx_hand_f *handler) +{ + struct udevice *dev; + struct eth_sandbox_priv *priv; + int ret; + + ret = uclass_get_device(UCLASS_ETH, index, &dev); + if (ret) + return; + + priv = dev_get_priv(dev); + if (handler) + priv->tx_handler = handler; + else + priv->tx_handler = sb_default_handler; +} + static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); @@ -185,10 +234,7 @@ static int sb_eth_send(struct udevice *dev, void *packet, int length) if (priv->disabled) return 0; - if (!sandbox_eth_arp_req_to_reply(dev, packet, length)) - return 0; - if (!sandbox_eth_ping_req_to_reply(dev, packet, length)) - return 0; + return priv->tx_handler(dev, packet, length); } static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp) @@ -254,6 +300,7 @@ static int sb_eth_ofdata_to_platdata(struct udevice *dev) } memcpy(priv->fake_host_hwaddr, mac, ARP_HLEN); priv->disabled = false; + priv->tx_handler = sb_default_handler; return 0; } From 76a503439e38be9d4fe365bdf87a6d0e74ea41c9 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:56 -0500 Subject: [PATCH 15/28] net: sandbox: Share the priv structure with tests If tests want to implement tx handlers, they will likely need access to the details in the priv structure. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 19 +++++++++++++++++++ drivers/net/sandbox.c | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index 2017586..ced6d51 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -49,6 +49,25 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, typedef int sandbox_eth_tx_hand_f(struct udevice *dev, void *pkt, unsigned int len); +/** + * struct eth_sandbox_priv - memory for sandbox mock driver + * + * fake_host_hwaddr - MAC address of mocked machine + * fake_host_ipaddr - IP address of mocked machine + * disabled - Will not respond + * recv_packet_buffer - buffer of the packet returned as received + * recv_packet_length - length of the packet returned as received + * tx_handler - function to generate responses to sent packets + */ +struct eth_sandbox_priv { + uchar fake_host_hwaddr[ARP_HLEN]; + struct in_addr fake_host_ipaddr; + bool disabled; + uchar *recv_packet_buffer; + int recv_packet_length; + sandbox_eth_tx_hand_f *tx_handler; +}; + /* * Set packet handler * diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index db461b8..6f0fe0c 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,25 +15,6 @@ DECLARE_GLOBAL_DATA_PTR; -/** - * struct eth_sandbox_priv - memory for sandbox mock driver - * - * fake_host_hwaddr: MAC address of mocked machine - * fake_host_ipaddr: IP address of mocked machine - * disabled: Will not respond - * recv_packet_buffer: buffer of the packet returned as received - * recv_packet_length: length of the packet returned as received - * tx_handler - function to generate responses to sent packets - */ -struct eth_sandbox_priv { - uchar fake_host_hwaddr[ARP_HLEN]; - struct in_addr fake_host_ipaddr; - bool disabled; - uchar *recv_packet_buffer; - int recv_packet_length; - sandbox_eth_tx_hand_f *tx_handler; -}; - static bool skip_timeout; /* From c67a420781012abb5c888e2857efde12cf27284b Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:57 -0500 Subject: [PATCH 16/28] net: sandbox: Allow fake eth to handle more than 1 packet response Use up to the max allocated receive buffers so as to be able to test more complex situations. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 10 +++++--- drivers/net/sandbox.c | 57 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index ced6d51..7a49e98 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -55,16 +55,18 @@ typedef int sandbox_eth_tx_hand_f(struct udevice *dev, void *pkt, * fake_host_hwaddr - MAC address of mocked machine * fake_host_ipaddr - IP address of mocked machine * disabled - Will not respond - * recv_packet_buffer - buffer of the packet returned as received - * recv_packet_length - length of the packet returned as received + * recv_packet_buffer - buffers of the packet returned as received + * recv_packet_length - lengths of the packet returned as received + * recv_packets - number of packets returned * tx_handler - function to generate responses to sent packets */ struct eth_sandbox_priv { uchar fake_host_hwaddr[ARP_HLEN]; struct in_addr fake_host_ipaddr; bool disabled; - uchar *recv_packet_buffer; - int recv_packet_length; + uchar * recv_packet_buffer[PKTBUFSRX]; + int recv_packet_length[PKTBUFSRX]; + int recv_packets; sandbox_eth_tx_hand_f *tx_handler; }; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 6f0fe0c..9c0e0d0 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -71,11 +71,15 @@ int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet, if (ntohs(arp->ar_op) != ARPOP_REQUEST) return -EAGAIN; + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + /* store this as the assumed IP of the fake host */ priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa); /* Formulate a fake response */ - eth_recv = (void *)priv->recv_packet_buffer; + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); eth_recv->et_protlen = htons(PROT_ARP); @@ -91,7 +95,9 @@ int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet, memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa); - priv->recv_packet_length = ETHER_HDR_SIZE + ARP_HDR_SIZE; + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + ARP_HDR_SIZE; + ++priv->recv_packets; return 0; } @@ -127,8 +133,12 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, if (icmp->type != ICMP_ECHO_REQUEST) return -EAGAIN; + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + /* reply to the ping */ - eth_recv = (void *)priv->recv_packet_buffer; + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; memcpy(eth_recv, packet, len); ipr = (void *)eth_recv + ETHER_HDR_SIZE; icmpr = (struct icmp_hdr *)&ipr->udp_src; @@ -144,7 +154,8 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, icmpr->checksum = 0; icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE); - priv->recv_packet_length = len; + priv->recv_packet_length[priv->recv_packets] = len; + ++priv->recv_packets; return 0; } @@ -201,7 +212,11 @@ static int sb_eth_start(struct udevice *dev) debug("eth_sandbox: Start\n"); - priv->recv_packet_buffer = net_rx_packets[0]; + priv->recv_packets = 0; + for (int i = 0; i < PKTBUFSRX; i++) { + priv->recv_packet_buffer[i] = net_rx_packets[i]; + priv->recv_packet_length[i] = 0; + } return 0; } @@ -227,18 +242,37 @@ static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp) skip_timeout = false; } - if (priv->recv_packet_length) { - int lcl_recv_packet_length = priv->recv_packet_length; + if (priv->recv_packets) { + int lcl_recv_packet_length = priv->recv_packet_length[0]; - debug("eth_sandbox: received packet %d\n", - priv->recv_packet_length); - priv->recv_packet_length = 0; - *packetp = priv->recv_packet_buffer; + debug("eth_sandbox: received packet[%d], %d waiting\n", + lcl_recv_packet_length, priv->recv_packets - 1); + *packetp = priv->recv_packet_buffer[0]; return lcl_recv_packet_length; } return 0; } +static int sb_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + int i; + + if (!priv->recv_packets) + return 0; + + --priv->recv_packets; + for (i = 0; i < priv->recv_packets; i++) { + priv->recv_packet_length[i] = priv->recv_packet_length[i + 1]; + memcpy(priv->recv_packet_buffer[i], + priv->recv_packet_buffer[i + 1], + priv->recv_packet_length[i + 1]); + } + priv->recv_packet_length[priv->recv_packets] = 0; + + return 0; +} + static void sb_eth_stop(struct udevice *dev) { debug("eth_sandbox: Stop\n"); @@ -257,6 +291,7 @@ static const struct eth_ops sb_eth_ops = { .start = sb_eth_start, .send = sb_eth_send, .recv = sb_eth_recv, + .free_pkt = sb_eth_free_pkt, .stop = sb_eth_stop, .write_hwaddr = sb_eth_write_hwaddr, }; From 3f02c98bd1000fc26ee2700fd5a75112cdeaca6c Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:58 -0500 Subject: [PATCH 17/28] net: Add an accessor to know if waiting for ARP This single-sources the state of the ARP. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- include/net.h | 1 + net/arp.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/net.h b/include/net.h index 156bdc1..40e8953 100644 --- a/include/net.h +++ b/include/net.h @@ -636,6 +636,7 @@ rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */ void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */ rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */ void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */ +bool arp_is_waiting(void); /* Waiting for ARP reply? */ void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */ void net_set_timeout_handler(ulong, thand_f *);/* Set timeout handler */ diff --git a/net/arp.c b/net/arp.c index b8a7168..ea685d9 100644 --- a/net/arp.c +++ b/net/arp.c @@ -100,7 +100,7 @@ int arp_timeout_check(void) { ulong t; - if (!net_arp_wait_packet_ip.s_addr) + if (!arp_is_waiting()) return 0; t = get_timer(0); @@ -187,8 +187,8 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) return; case ARPOP_REPLY: /* arp reply */ - /* are we waiting for a reply */ - if (!net_arp_wait_packet_ip.s_addr) + /* are we waiting for a reply? */ + if (!arp_is_waiting()) break; #ifdef CONFIG_KEEP_SERVERADDR @@ -233,3 +233,8 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) return; } } + +bool arp_is_waiting(void) +{ + return !!net_arp_wait_packet_ip.s_addr; +} From 9cbe5972c3c00e974482181cd4062d9229a9b7d5 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:48:59 -0500 Subject: [PATCH 18/28] net: sandbox: Add a priv ptr for tests to use Tests need to be able to pass their "unit test state" to the handlers where asserts are evaluated. Add a function that allows the tests to set this private data on the sandbox eth device. Signed-off-by: Joe Hershberger Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 9 +++++++++ drivers/net/sandbox.c | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index 7a49e98..a6adec4 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -59,6 +59,7 @@ typedef int sandbox_eth_tx_hand_f(struct udevice *dev, void *pkt, * recv_packet_length - lengths of the packet returned as received * recv_packets - number of packets returned * tx_handler - function to generate responses to sent packets + * priv - a pointer to some structure a test may want to keep track of */ struct eth_sandbox_priv { uchar fake_host_hwaddr[ARP_HLEN]; @@ -68,6 +69,7 @@ struct eth_sandbox_priv { int recv_packet_length[PKTBUFSRX]; int recv_packets; sandbox_eth_tx_hand_f *tx_handler; + void *priv; }; /* @@ -77,4 +79,11 @@ struct eth_sandbox_priv { */ void sandbox_eth_set_tx_handler(int index, sandbox_eth_tx_hand_f *handler); +/* + * Set priv ptr + * + * priv - priv void ptr to store in the device + */ +void sandbox_eth_set_priv(int index, void *priv); + #endif /* __ETH_H */ diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 9c0e0d0..e26e72e 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -206,6 +206,26 @@ void sandbox_eth_set_tx_handler(int index, sandbox_eth_tx_hand_f *handler) priv->tx_handler = sb_default_handler; } +/* + * Set priv ptr + * + * priv - priv void ptr to store in the device + */ +void sandbox_eth_set_priv(int index, void *priv) +{ + struct udevice *dev; + struct eth_sandbox_priv *dev_priv; + int ret; + + ret = uclass_get_device(UCLASS_ETH, index, &dev); + if (ret) + return; + + dev_priv = dev_get_priv(dev); + + dev_priv->priv = priv; +} + static int sb_eth_start(struct udevice *dev) { struct eth_sandbox_priv *priv = dev_get_priv(dev); From 45988dae4cf05f783e40e027c83594a9dc6551cd Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:49:00 -0500 Subject: [PATCH 19/28] test: eth: Add a test for ARP requests This tests that ARP requests made to this target's IP address are responded-to by the target when it is doing other networking operations. This currently corrupts the ongoing operation of the device if it happens to be awaiting an ARP reply of its own to whatever serverip it is attempting to communicate with. In the test, add an expectation that the user operation (ping, in this case) will fail. A later patch will address this problem. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 10 +++++ drivers/net/sandbox.c | 41 ++++++++++++++++++++ test/dm/eth.c | 86 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index a6adec4..d068486 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -39,6 +39,16 @@ int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet, int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, unsigned int len); +/* + * sandbox_eth_recv_arp_req() + * + * Inject an ARP request for this target + * + * @dev: device that received the packet + * @return 0 if injected, -EOVERFLOW if not + */ +int sandbox_eth_recv_arp_req(struct udevice *dev); + /** * A packet handler * diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index e26e72e..81f0764 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -161,6 +161,47 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, } /* + * sandbox_eth_recv_arp_req() + * + * Inject an ARP request for this target + * + * returns 0 if injected, -EOVERFLOW if not + */ +int sandbox_eth_recv_arp_req(struct udevice *dev) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth_recv; + struct arp_hdr *arp_recv; + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return -EOVERFLOW; + + /* Formulate a fake request */ + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_recv->et_dest, net_bcast_ethaddr, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_recv->et_protlen = htons(PROT_ARP); + + arp_recv = (void *)eth_recv + ETHER_HDR_SIZE; + arp_recv->ar_hrd = htons(ARP_ETHER); + arp_recv->ar_pro = htons(PROT_IP); + arp_recv->ar_hln = ARP_HLEN; + arp_recv->ar_pln = ARP_PLEN; + arp_recv->ar_op = htons(ARPOP_REQUEST); + memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN); + net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr); + memcpy(&arp_recv->ar_tha, net_null_ethaddr, ARP_HLEN); + net_write_ip(&arp_recv->ar_tpa, net_ip); + + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + ARP_HDR_SIZE; + ++priv->recv_packets; + + return 0; +} + +/* * sb_default_handler() * * perform typical responses to simple ping diff --git a/test/dm/eth.c b/test/dm/eth.c index 1a7684a..9e52d5c 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -258,3 +258,89 @@ static int dm_test_net_retry(struct unit_test_state *uts) return retval; } DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT); + +static int sb_check_arp_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct arp_hdr *arp; + /* Used by all of the ut_assert macros */ + struct unit_test_state *uts = priv->priv; + + if (ntohs(eth->et_protlen) != PROT_ARP) + return 0; + + arp = packet + ETHER_HDR_SIZE; + + if (ntohs(arp->ar_op) != ARPOP_REPLY) + return 0; + + /* This test would be worthless if we are not waiting */ + ut_assert(arp_is_waiting()); + + /* Validate response */ + ut_assert(memcmp(eth->et_src, net_ethaddr, ARP_HLEN) == 0); + ut_assert(memcmp(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN) == 0); + ut_assert(eth->et_protlen == htons(PROT_ARP)); + + ut_assert(arp->ar_hrd == htons(ARP_ETHER)); + ut_assert(arp->ar_pro == htons(PROT_IP)); + ut_assert(arp->ar_hln == ARP_HLEN); + ut_assert(arp->ar_pln == ARP_PLEN); + ut_assert(memcmp(&arp->ar_sha, net_ethaddr, ARP_HLEN) == 0); + ut_assert(net_read_ip(&arp->ar_spa).s_addr == net_ip.s_addr); + ut_assert(memcmp(&arp->ar_tha, priv->fake_host_hwaddr, ARP_HLEN) == 0); + ut_assert(net_read_ip(&arp->ar_tpa).s_addr == + string_to_ip("1.1.2.4").s_addr); + + return 0; +} + +static int sb_with_async_arp_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + int ret; + + /* + * If we are about to generate a reply to ARP, first inject a request + * from another host + */ + if (ntohs(eth->et_protlen) == PROT_ARP && + ntohs(arp->ar_op) == ARPOP_REQUEST) { + /* Make sure sandbox_eth_recv_arp_req() knows who is asking */ + priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); + + ret = sandbox_eth_recv_arp_req(dev); + if (ret) + return ret; + } + + sandbox_eth_arp_req_to_reply(dev, packet, len); + sandbox_eth_ping_req_to_reply(dev, packet, len); + + return sb_check_arp_reply(dev, packet, len); +} + +static int dm_test_eth_async_arp_reply(struct unit_test_state *uts) +{ + net_ping_ip = string_to_ip("1.1.2.2"); + + sandbox_eth_set_tx_handler(0, sb_with_async_arp_handler); + /* Used by all of the ut_assert macros in the tx_handler */ + sandbox_eth_set_priv(0, uts); + sandbox_eth_skip_timeout(); + + env_set("ethact", "eth@10002000"); + ut_assert(net_loop(PING) == -ETIMEDOUT); + ut_asserteq_str("eth@10002000", env_get("ethact")); + + sandbox_eth_set_tx_handler(0, NULL); + + return 0; +} + +DM_TEST(dm_test_eth_async_arp_reply, DM_TESTF_SCAN_FDT); From 72ff0042585bedab4364afbd7ecc935e48324ade Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:49:01 -0500 Subject: [PATCH 20/28] test: eth: Add a test for the target being pinged The target will respond to pings while doing other network handling. Make sure that the response happens and is correct. This currently corrupts the ongoing operation of the device if it happens to be awaiting an ARP reply of its own to whatever serverip it is attempting to communicate with. In the test, add an expectation that the user operation (ping, in this case) will fail. A later patch will address this problem. Signed-off-by: Joe Hershberger Reviewed-by: Simon Glass Reviewed-by: Bin Meng --- arch/sandbox/include/asm/eth.h | 10 +++++ drivers/net/sandbox.c | 51 +++++++++++++++++++++++++ test/dm/eth.c | 86 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h index d068486..477fa00 100644 --- a/arch/sandbox/include/asm/eth.h +++ b/arch/sandbox/include/asm/eth.h @@ -49,6 +49,16 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet, */ int sandbox_eth_recv_arp_req(struct udevice *dev); +/* + * sandbox_eth_recv_ping_req() + * + * Inject a ping request for this target + * + * @dev: device that received the packet + * @return 0 if injected, -EOVERFLOW if not + */ +int sandbox_eth_recv_ping_req(struct udevice *dev); + /** * A packet handler * diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 81f0764..decce2f 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -202,6 +202,57 @@ int sandbox_eth_recv_arp_req(struct udevice *dev) } /* + * sandbox_eth_recv_ping_req() + * + * Inject a ping request for this target + * + * returns 0 if injected, -EOVERFLOW if not + */ +int sandbox_eth_recv_ping_req(struct udevice *dev) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth_recv; + struct ip_udp_hdr *ipr; + struct icmp_hdr *icmpr; + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return -EOVERFLOW; + + /* Formulate a fake ping */ + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; + + memcpy(eth_recv->et_dest, net_ethaddr, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_recv->et_protlen = htons(PROT_IP); + + ipr = (void *)eth_recv + ETHER_HDR_SIZE; + ipr->ip_hl_v = 0x45; + ipr->ip_len = htons(IP_ICMP_HDR_SIZE); + ipr->ip_off = htons(IP_FLAGS_DFRAG); + ipr->ip_p = IPPROTO_ICMP; + ipr->ip_sum = 0; + net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr); + net_write_ip(&ipr->ip_dst, net_ip); + ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); + + icmpr = (struct icmp_hdr *)&ipr->udp_src; + + icmpr->type = ICMP_ECHO_REQUEST; + icmpr->code = 0; + icmpr->checksum = 0; + icmpr->un.echo.id = 0; + icmpr->un.echo.sequence = htons(1); + icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE); + + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + IP_ICMP_HDR_SIZE; + ++priv->recv_packets; + + return 0; +} + +/* * sb_default_handler() * * perform typical responses to simple ping diff --git a/test/dm/eth.c b/test/dm/eth.c index 9e52d5c..86482e9 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -344,3 +344,89 @@ static int dm_test_eth_async_arp_reply(struct unit_test_state *uts) } DM_TEST(dm_test_eth_async_arp_reply, DM_TESTF_SCAN_FDT); + +static int sb_check_ping_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct ip_udp_hdr *ip; + struct icmp_hdr *icmp; + /* Used by all of the ut_assert macros */ + struct unit_test_state *uts = priv->priv; + + if (ntohs(eth->et_protlen) != PROT_IP) + return 0; + + ip = packet + ETHER_HDR_SIZE; + + if (ip->ip_p != IPPROTO_ICMP) + return 0; + + icmp = (struct icmp_hdr *)&ip->udp_src; + + if (icmp->type != ICMP_ECHO_REPLY) + return 0; + + /* This test would be worthless if we are not waiting */ + ut_assert(arp_is_waiting()); + + /* Validate response */ + ut_assert(memcmp(eth->et_src, net_ethaddr, ARP_HLEN) == 0); + ut_assert(memcmp(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN) == 0); + ut_assert(eth->et_protlen == htons(PROT_IP)); + + ut_assert(net_read_ip(&ip->ip_src).s_addr == net_ip.s_addr); + ut_assert(net_read_ip(&ip->ip_dst).s_addr == + string_to_ip("1.1.2.4").s_addr); + + return 0; +} + +static int sb_with_async_ping_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + int ret; + + /* + * If we are about to generate a reply to ARP, first inject a request + * from another host + */ + if (ntohs(eth->et_protlen) == PROT_ARP && + ntohs(arp->ar_op) == ARPOP_REQUEST) { + /* Make sure sandbox_eth_recv_arp_req() knows who is asking */ + priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); + + ret = sandbox_eth_recv_ping_req(dev); + if (ret) + return ret; + } + + sandbox_eth_arp_req_to_reply(dev, packet, len); + sandbox_eth_ping_req_to_reply(dev, packet, len); + + return sb_check_ping_reply(dev, packet, len); +} + +static int dm_test_eth_async_ping_reply(struct unit_test_state *uts) +{ + net_ping_ip = string_to_ip("1.1.2.2"); + + sandbox_eth_set_tx_handler(0, sb_with_async_ping_handler); + /* Used by all of the ut_assert macros in the tx_handler */ + sandbox_eth_set_priv(0, uts); + sandbox_eth_skip_timeout(); + + env_set("ethact", "eth@10002000"); + ut_assert(net_loop(PING) == -ETIMEDOUT); + ut_asserteq_str("eth@10002000", env_get("ethact")); + + sandbox_eth_set_tx_handler(0, NULL); + + return 0; +} + +DM_TEST(dm_test_eth_async_ping_reply, DM_TESTF_SCAN_FDT); From ac3f26cc15ad7e3e9efc2b0b0e18c6e84d93af77 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Wed, 26 Sep 2018 16:49:02 -0500 Subject: [PATCH 21/28] net: Don't overwrite waiting packets with asynchronous replies Peter originally sent a fix, but it breaks a number of other things. This addresses the original reported issue in a different way. That report was: > U-Boot has 1 common buffer to send Ethernet frames, pointed to by > net_tx_packet. When sending to an IP address without knowing the MAC > address, U-Boot makes an ARP request (using the arp_tx_packet buffer) > to find out the MAC address of the IP addressr. When a matching ARP > reply is received, U-Boot continues sending the frame stored in the > net_tx_packet buffer. > > However, in the mean time, if U-Boot needs to send out any network > packets (e.g. replying ping packets or ARP requests for its own IP > address etc.), it will use the net_tx_packet buffer to prepare the > new packet. Thus this buffer is no longer the original packet meant > to be transmitted after the ARP reply. The original packet will be > lost. This instead uses the ARP tx buffer to send async replies in the case where we are actively waiting for an ARP reply. Signed-off-by: Joe Hershberger Reported-by: Tran Tien Dat Reviewed-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng --- include/net.h | 8 ++++++++ net/arp.c | 9 +++++---- net/arp.h | 1 + net/net.c | 8 ++++++++ net/ping.c | 7 +++++-- test/dm/eth.c | 6 ++---- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/include/net.h b/include/net.h index 40e8953..e5cd52b 100644 --- a/include/net.h +++ b/include/net.h @@ -655,6 +655,14 @@ static inline void net_set_state(enum net_loop_state state) net_state = state; } +/* + * net_get_async_tx_pkt_buf - Get a packet buffer that is not in use for + * sending an asynchronous reply + * + * returns - ptr to packet buffer + */ +uchar * net_get_async_tx_pkt_buf(void); + /* Transmit a packet */ static inline void net_send_packet(uchar *pkt, int len) { diff --git a/net/arp.c b/net/arp.c index ea685d9..b49c3d3 100644 --- a/net/arp.c +++ b/net/arp.c @@ -34,8 +34,7 @@ uchar *arp_wait_packet_ethaddr; int arp_wait_tx_packet_size; ulong arp_wait_timer_start; int arp_wait_try; - -static uchar *arp_tx_packet; /* THE ARP transmit packet */ +uchar *arp_tx_packet; /* THE ARP transmit packet */ static uchar arp_tx_packet_buf[PKTSIZE_ALIGN + PKTALIGN]; void arp_init(void) @@ -126,6 +125,7 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) struct arp_hdr *arp; struct in_addr reply_ip_addr; int eth_hdr_size; + uchar *tx_packet; /* * We have to deal with two types of ARP packets: @@ -182,8 +182,9 @@ void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) (net_read_ip(&arp->ar_spa).s_addr & net_netmask.s_addr)) udelay(5000); #endif - memcpy(net_tx_packet, et, eth_hdr_size + ARP_HDR_SIZE); - net_send_packet(net_tx_packet, eth_hdr_size + ARP_HDR_SIZE); + tx_packet = net_get_async_tx_pkt_buf(); + memcpy(tx_packet, et, eth_hdr_size + ARP_HDR_SIZE); + net_send_packet(tx_packet, eth_hdr_size + ARP_HDR_SIZE); return; case ARPOP_REPLY: /* arp reply */ diff --git a/net/arp.h b/net/arp.h index afb8695..25b3c00 100644 --- a/net/arp.h +++ b/net/arp.h @@ -20,6 +20,7 @@ extern uchar *arp_wait_packet_ethaddr; extern int arp_wait_tx_packet_size; extern ulong arp_wait_timer_start; extern int arp_wait_try; +extern uchar *arp_tx_packet; void arp_init(void); void arp_request(void); diff --git a/net/net.c b/net/net.c index 31cf306..77a7141 100644 --- a/net/net.c +++ b/net/net.c @@ -799,6 +799,14 @@ void net_set_timeout_handler(ulong iv, thand_f *f) } } +uchar *net_get_async_tx_pkt_buf(void) +{ + if (arp_is_waiting()) + return arp_tx_packet; /* If we are waiting, we already sent */ + else + return net_tx_packet; +} + int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport, int payload_len) { diff --git a/net/ping.c b/net/ping.c index 3e5461a..821d35d 100644 --- a/net/ping.c +++ b/net/ping.c @@ -84,6 +84,7 @@ void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src; struct in_addr src_ip; int eth_hdr_size; + uchar *tx_packet; switch (icmph->type) { case ICMP_ECHO_REPLY: @@ -107,8 +108,10 @@ void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) icmph->type = ICMP_ECHO_REPLY; icmph->checksum = 0; icmph->checksum = compute_ip_checksum(icmph, len - IP_HDR_SIZE); - memcpy(net_tx_packet, et, eth_hdr_size + len); - net_send_packet(net_tx_packet, eth_hdr_size + len); + + tx_packet = net_get_async_tx_pkt_buf(); + memcpy(tx_packet, et, eth_hdr_size + len); + net_send_packet(tx_packet, eth_hdr_size + len); return; /* default: return;*/ diff --git a/test/dm/eth.c b/test/dm/eth.c index 86482e9..850eabb 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -332,10 +332,9 @@ static int dm_test_eth_async_arp_reply(struct unit_test_state *uts) sandbox_eth_set_tx_handler(0, sb_with_async_arp_handler); /* Used by all of the ut_assert macros in the tx_handler */ sandbox_eth_set_priv(0, uts); - sandbox_eth_skip_timeout(); env_set("ethact", "eth@10002000"); - ut_assert(net_loop(PING) == -ETIMEDOUT); + ut_assertok(net_loop(PING)); ut_asserteq_str("eth@10002000", env_get("ethact")); sandbox_eth_set_tx_handler(0, NULL); @@ -418,10 +417,9 @@ static int dm_test_eth_async_ping_reply(struct unit_test_state *uts) sandbox_eth_set_tx_handler(0, sb_with_async_ping_handler); /* Used by all of the ut_assert macros in the tx_handler */ sandbox_eth_set_priv(0, uts); - sandbox_eth_skip_timeout(); env_set("ethact", "eth@10002000"); - ut_assert(net_loop(PING) == -ETIMEDOUT); + ut_assertok(net_loop(PING)); ut_asserteq_str("eth@10002000", env_get("ethact")); sandbox_eth_set_tx_handler(0, NULL); From 5d457ecbef5eba8eaeed513c65c55453de4f3975 Mon Sep 17 00:00:00 2001 From: Duncan Hare Date: Sun, 24 Jun 2018 15:40:41 -0700 Subject: [PATCH 22/28] net: Consolidate UDP header functions Make it possible to add TCP versions of the same, while reusing IP portions. This patch should not change any behavior. Signed-off-by: Duncan Hare Acked-by: Joe Hershberger --- include/net.h | 6 +++++- net/net.c | 35 ++++++++++++++++++++++++++--------- net/ping.c | 7 +------ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/include/net.h b/include/net.h index e5cd52b..51c099d 100644 --- a/include/net.h +++ b/include/net.h @@ -597,7 +597,8 @@ int net_set_ether(uchar *xet, const uchar *dest_ethaddr, uint prot); int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot); /* Set IP header */ -void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source); +void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source, + u16 pkt_len, u8 proto); void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport, int len); @@ -680,6 +681,9 @@ static inline void net_send_packet(uchar *pkt, int len) * @param sport Source UDP port * @param payload_len Length of data after the UDP header */ +int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport, + int payload_len, int proto, u8 action, u32 tcp_seq_num, + u32 tcp_ack_num); int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport, int payload_len); diff --git a/net/net.c b/net/net.c index 77a7141..a5a216c 100644 --- a/net/net.c +++ b/net/net.c @@ -810,6 +810,14 @@ uchar *net_get_async_tx_pkt_buf(void) int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport, int payload_len) { + return net_send_ip_packet(ether, dest, dport, sport, payload_len, + IPPROTO_UDP, 0, 0, 0); +} + +int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport, + int payload_len, int proto, u8 action, u32 tcp_seq_num, + u32 tcp_ack_num) +{ uchar *pkt; int eth_hdr_size; int pkt_hdr_size; @@ -830,9 +838,16 @@ int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport, pkt = (uchar *)net_tx_packet; eth_hdr_size = net_set_ether(pkt, ether, PROT_IP); - pkt += eth_hdr_size; - net_set_udp_header(pkt, dest, dport, sport, payload_len); - pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE; + + switch (proto) { + case IPPROTO_UDP: + net_set_udp_header(pkt + eth_hdr_size, dest, dport, sport, + payload_len); + pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE; + break; + default: + return -EINVAL; + } /* if MAC address was not discovered yet, do an ARP request */ if (memcmp(ether, net_null_ethaddr, 6) == 0) { @@ -1463,7 +1478,8 @@ int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot) } } -void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source) +void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source, + u16 pkt_len, u8 proto) { struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt; @@ -1473,7 +1489,8 @@ void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source) /* IP_HDR_SIZE / 4 (not including UDP) */ ip->ip_hl_v = 0x45; ip->ip_tos = 0; - ip->ip_len = htons(IP_HDR_SIZE); + ip->ip_len = htons(pkt_len); + ip->ip_p = proto; ip->ip_id = htons(net_ip_id++); ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */ ip->ip_ttl = 255; @@ -1482,6 +1499,8 @@ void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source) net_copy_ip((void *)&ip->ip_src, &source); /* already in network byte order */ net_copy_ip((void *)&ip->ip_dst, &dest); + + ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); } void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport, @@ -1497,10 +1516,8 @@ void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport, if (len & 1) pkt[IP_UDP_HDR_SIZE + len] = 0; - net_set_ip_header(pkt, dest, net_ip); - ip->ip_len = htons(IP_UDP_HDR_SIZE + len); - ip->ip_p = IPPROTO_UDP; - ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); + net_set_ip_header(pkt, dest, net_ip, IP_UDP_HDR_SIZE + len, + IPPROTO_UDP); ip->udp_src = htons(sport); ip->udp_dst = htons(dport); diff --git a/net/ping.c b/net/ping.c index 821d35d..633c942 100644 --- a/net/ping.c +++ b/net/ping.c @@ -22,14 +22,9 @@ static void set_icmp_header(uchar *pkt, struct in_addr dest) /* * Construct an IP and ICMP header. */ - struct ip_hdr *ip = (struct ip_hdr *)pkt; struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE); - net_set_ip_header(pkt, dest, net_ip); - - ip->ip_len = htons(IP_ICMP_HDR_SIZE); - ip->ip_p = IPPROTO_ICMP; - ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); + net_set_ip_header(pkt, dest, net_ip, IP_ICMP_HDR_SIZE, IPPROTO_ICMP); icmp->type = ICMP_ECHO_REQUEST; icmp->code = 0; From afd6c6b4701d652a68f5d93ad26eba6793e36c81 Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Wed, 10 Oct 2018 14:08:29 +0530 Subject: [PATCH 23/28] driver: net: fsl-mc: modify the label name The goto label name is misspelled it should be DPMAC not DPAMC Signed-off-by: Pankaj Bansal Acked-by: Joe Hershberger --- drivers/net/ldpaa_eth/ldpaa_eth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index a25b7cd..82a684b 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -413,7 +413,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) if (err) { printf("%s: Could not initialize\n", priv->phydev->dev->name); - goto err_dpamc_bind; + goto err_dpmac_bind; } } #else @@ -441,13 +441,13 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) if (!priv->phydev->link) { printf("%s: No link.\n", priv->phydev->dev->name); err = -1; - goto err_dpamc_bind; + goto err_dpmac_bind; } /* DPMAC binding DPNI */ err = ldpaa_dpmac_bind(priv); if (err) - goto err_dpamc_bind; + goto err_dpmac_bind; /* DPNI initialization */ err = ldpaa_dpni_setup(priv); @@ -540,7 +540,7 @@ err_dpni_bind: err_dpbp_setup: dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); err_dpni_setup: -err_dpamc_bind: +err_dpmac_bind: dpmac_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle); dpmac_destroy(dflt_mc_io, dflt_dprc_handle, From d75e81d9e05575e3f8471e618846565b15b30060 Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Wed, 10 Oct 2018 14:08:30 +0530 Subject: [PATCH 24/28] driver: net: fsl-mc: remove unused strcture elements The phydev structure is present in both ldpaa_eth_priv and wriop_dpmac_info. the phydev in wriop_dpmac_info is not being used As the phydev is created based on phy_addr and bus members of wriop_dpmac_info, it is appropriate to keep phydev in wriop_dpmac_info. Also phy_regs is not being used, therefore remove it Signed-off-by: Pankaj Bansal Acked-by: Joe Hershberger --- drivers/net/ldpaa_eth/ldpaa_eth.c | 58 ++++++++++++++++++++----------------- drivers/net/ldpaa_eth/ldpaa_eth.h | 1 - drivers/net/ldpaa_eth/ldpaa_wriop.c | 2 ++ include/fsl-mc/ldpaa_wriop.h | 1 - 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 82a684b..39f81da 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -35,7 +35,7 @@ static int init_phy(struct eth_device *dev) return -1; } - priv->phydev = phydev; + wriop_set_phy_dev(priv->dpmac_id, phydev); return phy_config(phydev); } @@ -388,6 +388,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) struct mii_dev *bus; phy_interface_t enet_if; struct dpni_queue d_queue; + struct phy_device *phydev = NULL; if (net_dev->state == ETH_STATE_ACTIVE) return 0; @@ -408,38 +409,41 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) goto err_dpmac_setup; #ifdef CONFIG_PHYLIB - if (priv->phydev) { - err = phy_startup(priv->phydev); + phydev = wriop_get_phy_dev(priv->dpmac_id); + if (phydev) { + err = phy_startup(phydev); if (err) { printf("%s: Could not initialize\n", - priv->phydev->dev->name); + phydev->dev->name); goto err_dpmac_bind; } } #else - priv->phydev = (struct phy_device *)malloc(sizeof(struct phy_device)); - memset(priv->phydev, 0, sizeof(struct phy_device)); + phydev = (struct phy_device *)malloc(sizeof(struct phy_device)); + memset(phydev, 0, sizeof(struct phy_device)); + wriop_set_phy_dev(priv->dpmac_id, phydev); - priv->phydev->speed = SPEED_1000; - priv->phydev->link = 1; - priv->phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_1000; + phydev->link = 1; + phydev->duplex = DUPLEX_FULL; #endif bus = wriop_get_mdio(priv->dpmac_id); enet_if = wriop_get_enet_if(priv->dpmac_id); if ((bus == NULL) && (enet_if == PHY_INTERFACE_MODE_XGMII)) { - priv->phydev = (struct phy_device *) + phydev = (struct phy_device *) malloc(sizeof(struct phy_device)); - memset(priv->phydev, 0, sizeof(struct phy_device)); + memset(phydev, 0, sizeof(struct phy_device)); + wriop_set_phy_dev(priv->dpmac_id, phydev); - priv->phydev->speed = SPEED_10000; - priv->phydev->link = 1; - priv->phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_10000; + phydev->link = 1; + phydev->duplex = DUPLEX_FULL; } - if (!priv->phydev->link) { - printf("%s: No link.\n", priv->phydev->dev->name); + if (!phydev->link) { + printf("%s: No link.\n", phydev->dev->name); err = -1; goto err_dpmac_bind; } @@ -476,17 +480,17 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) return err; } - dpmac_link_state.rate = priv->phydev->speed; + dpmac_link_state.rate = phydev->speed; - if (priv->phydev->autoneg == AUTONEG_DISABLE) + if (phydev->autoneg == AUTONEG_DISABLE) dpmac_link_state.options &= ~DPMAC_LINK_OPT_AUTONEG; else dpmac_link_state.options |= DPMAC_LINK_OPT_AUTONEG; - if (priv->phydev->duplex == DUPLEX_HALF) + if (phydev->duplex == DUPLEX_HALF) dpmac_link_state.options |= DPMAC_LINK_OPT_HALF_DUPLEX; - dpmac_link_state.up = priv->phydev->link; + dpmac_link_state.up = phydev->link; err = dpmac_set_link_state(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle, &dpmac_link_state); @@ -530,7 +534,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) goto err_qdid; } - return priv->phydev->link; + return phydev->link; err_qdid: err_get_queue: @@ -556,6 +560,7 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) #ifdef CONFIG_PHYLIB struct mii_dev *bus = wriop_get_mdio(priv->dpmac_id); #endif + struct phy_device *phydev = NULL; if ((net_dev->state == ETH_STATE_PASSIVE) || (net_dev->state == ETH_STATE_INIT)) @@ -588,11 +593,12 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) printf("dpni_disable() failed\n"); #ifdef CONFIG_PHYLIB - if (priv->phydev && bus != NULL) - phy_shutdown(priv->phydev); - else { - free(priv->phydev); - priv->phydev = NULL; + phydev = wriop_get_phy_dev(priv->dpmac_id); + if (phydev && bus) { + phy_shutdown(phydev); + } else { + free(phydev); + wriop_set_phy_dev(priv->dpmac_id, NULL); } #endif diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.h b/drivers/net/ldpaa_eth/ldpaa_eth.h index ee784a5..3f9154b 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.h +++ b/drivers/net/ldpaa_eth/ldpaa_eth.h @@ -127,7 +127,6 @@ struct ldpaa_eth_priv { uint16_t tx_flow_id; enum ldpaa_eth_type type; /* 1G or 10G ethernet */ - struct phy_device *phydev; }; struct dprc_endpoint dpmac_endpoint; diff --git a/drivers/net/ldpaa_eth/ldpaa_wriop.c b/drivers/net/ldpaa_eth/ldpaa_wriop.c index 0731a79..afbb1ca 100644 --- a/drivers/net/ldpaa_eth/ldpaa_wriop.c +++ b/drivers/net/ldpaa_eth/ldpaa_wriop.c @@ -26,6 +26,7 @@ void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl) dpmac_info[dpmac_id].enabled = 0; dpmac_info[dpmac_id].id = 0; dpmac_info[dpmac_id].phy_addr = -1; + dpmac_info[dpmac_id].phydev = NULL; dpmac_info[dpmac_id].enet_if = PHY_INTERFACE_MODE_NONE; enet_if = wriop_dpmac_enet_if(dpmac_id, lane_prtcl); @@ -42,6 +43,7 @@ void wriop_init_dpmac_enet_if(int dpmac_id, phy_interface_t enet_if) dpmac_info[dpmac_id].id = dpmac_id; dpmac_info[dpmac_id].phy_addr = -1; dpmac_info[dpmac_id].enet_if = enet_if; + dpmac_info[dpmac_id].phydev = NULL; } diff --git a/include/fsl-mc/ldpaa_wriop.h b/include/fsl-mc/ldpaa_wriop.h index 07e5130..8971c6c 100644 --- a/include/fsl-mc/ldpaa_wriop.h +++ b/include/fsl-mc/ldpaa_wriop.h @@ -41,7 +41,6 @@ struct wriop_dpmac_info { u8 id; u8 board_mux; int phy_addr; - void *phy_regs; phy_interface_t enet_if; struct phy_device *phydev; struct mii_dev *bus; From f259c43d893071e3a4f43536735c959dcf320d99 Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Wed, 10 Oct 2018 14:08:31 +0530 Subject: [PATCH 25/28] driver: net: fsl-mc: fix error handing in init_phy if an error occurs during init_phy, we should free the phydev structure which has been allocated by phy_connect. Signed-off-by: Pankaj Bansal Acked-by: Joe Hershberger --- drivers/net/ldpaa_eth/ldpaa_eth.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 39f81da..ef5286c 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -23,6 +23,7 @@ static int init_phy(struct eth_device *dev) struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; struct phy_device *phydev = NULL; struct mii_dev *bus; + int ret; bus = wriop_get_mdio(priv->dpmac_id); if (bus == NULL) @@ -37,7 +38,14 @@ static int init_phy(struct eth_device *dev) wriop_set_phy_dev(priv->dpmac_id, phydev); - return phy_config(phydev); + ret = phy_config(phydev); + + if (ret) { + free(phydev); + wriop_set_phy_dev(priv->dpmac_id, NULL); + } + + return ret; } #endif From a3cb5340f12425537d6c94d8e95d570f6d6a504b Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Wed, 10 Oct 2018 14:08:32 +0530 Subject: [PATCH 26/28] driver: net: fsl-mc: Modify the dpmac link detection method when there is no phy present for a dpmac, a dummy phy device is created. when we move to multiple phy method, we need to create as many dummy phy devices. Change this method so that we don't need to create dummy phy devices. We always report linkup if no phy is present. Signed-off-by: Pankaj Bansal Acked-by: Joe Hershberger --- drivers/net/ldpaa_eth/ldpaa_eth.c | 119 ++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index ef5286c..4f0b977 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -385,6 +385,59 @@ error: return err; } +static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, + struct dpmac_link_state *state) +{ + struct phy_device *phydev = NULL; + phy_interface_t enet_if; + int err; + + /* let's start off with maximum capabilities + */ + enet_if = wriop_get_enet_if(priv->dpmac_id); + switch (enet_if) { + case PHY_INTERFACE_MODE_XGMII: + state->rate = SPEED_10000; + break; + default: + state->rate = SPEED_1000; + break; + } + state->up = 1; + +#ifdef CONFIG_PHYLIB + state->options |= DPMAC_LINK_OPT_AUTONEG; + + phydev = wriop_get_phy_dev(priv->dpmac_id); + if (phydev) { + err = phy_startup(phydev); + if (err) { + printf("%s: Could not initialize\n", phydev->dev->name); + state->up = 0; + } + if (phydev->link) { + state->rate = min(state->rate, (uint32_t)phydev->speed); + if (!phydev->duplex) + state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; + if (!phydev->autoneg) + state->options &= ~DPMAC_LINK_OPT_AUTONEG; + } else { + state->up = 0; + } + } +#endif + if (!phydev) + state->options &= ~DPMAC_LINK_OPT_AUTONEG; + + if (!state->up) { + state->rate = 0; + state->options = 0; + return -ENOLINK; + } + + return 0; +} + static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; @@ -393,10 +446,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) struct dpni_link_state link_state; #endif int err = 0; - struct mii_dev *bus; - phy_interface_t enet_if; struct dpni_queue d_queue; - struct phy_device *phydev = NULL; if (net_dev->state == ETH_STATE_ACTIVE) return 0; @@ -416,45 +466,9 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) if (err < 0) goto err_dpmac_setup; -#ifdef CONFIG_PHYLIB - phydev = wriop_get_phy_dev(priv->dpmac_id); - if (phydev) { - err = phy_startup(phydev); - if (err) { - printf("%s: Could not initialize\n", - phydev->dev->name); - goto err_dpmac_bind; - } - } -#else - phydev = (struct phy_device *)malloc(sizeof(struct phy_device)); - memset(phydev, 0, sizeof(struct phy_device)); - wriop_set_phy_dev(priv->dpmac_id, phydev); - - phydev->speed = SPEED_1000; - phydev->link = 1; - phydev->duplex = DUPLEX_FULL; -#endif - - bus = wriop_get_mdio(priv->dpmac_id); - enet_if = wriop_get_enet_if(priv->dpmac_id); - if ((bus == NULL) && - (enet_if == PHY_INTERFACE_MODE_XGMII)) { - phydev = (struct phy_device *) - malloc(sizeof(struct phy_device)); - memset(phydev, 0, sizeof(struct phy_device)); - wriop_set_phy_dev(priv->dpmac_id, phydev); - - phydev->speed = SPEED_10000; - phydev->link = 1; - phydev->duplex = DUPLEX_FULL; - } - - if (!phydev->link) { - printf("%s: No link.\n", phydev->dev->name); - err = -1; + err = ldpaa_get_dpmac_state(priv, &dpmac_link_state); + if (err < 0) goto err_dpmac_bind; - } /* DPMAC binding DPNI */ err = ldpaa_dpmac_bind(priv); @@ -488,18 +502,6 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) return err; } - dpmac_link_state.rate = phydev->speed; - - if (phydev->autoneg == AUTONEG_DISABLE) - dpmac_link_state.options &= ~DPMAC_LINK_OPT_AUTONEG; - else - dpmac_link_state.options |= DPMAC_LINK_OPT_AUTONEG; - - if (phydev->duplex == DUPLEX_HALF) - dpmac_link_state.options |= DPMAC_LINK_OPT_HALF_DUPLEX; - - dpmac_link_state.up = phydev->link; - err = dpmac_set_link_state(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle, &dpmac_link_state); if (err < 0) { @@ -542,7 +544,7 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) goto err_qdid; } - return phydev->link; + return dpmac_link_state.up; err_qdid: err_get_queue: @@ -565,9 +567,6 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; int err = 0; -#ifdef CONFIG_PHYLIB - struct mii_dev *bus = wriop_get_mdio(priv->dpmac_id); -#endif struct phy_device *phydev = NULL; if ((net_dev->state == ETH_STATE_PASSIVE) || @@ -602,12 +601,8 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) #ifdef CONFIG_PHYLIB phydev = wriop_get_phy_dev(priv->dpmac_id); - if (phydev && bus) { + if (phydev) phy_shutdown(phydev); - } else { - free(phydev); - wriop_set_phy_dev(priv->dpmac_id, NULL); - } #endif /* Free DPBP handle and reset. */ From 1ed19a1421691e0238b79f8ac14dc4a65ddd7ad0 Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Wed, 10 Oct 2018 14:08:33 +0530 Subject: [PATCH 27/28] driver: net: fsl-mc: initialize dpmac irrespective of phy The dpmac initalization should not depend on phy. As the phy is not necessary to be present for dpmac to function. Therefore, remove dpmac initialization dependency from phy. Signed-off-by: Pankaj Bansal Acked-by: Joe Hershberger --- drivers/net/fsl-mc/mc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index d9a897d..b245fbc 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -363,8 +363,7 @@ static int mc_fixup_mac_addrs(void *blob, enum mc_fixup_type type) for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) { /* port not enabled */ - if ((wriop_is_enabled_dpmac(i) != 1) || - (wriop_get_phy_address(i) == -1)) + if (wriop_is_enabled_dpmac(i) != 1) continue; snprintf(ethname, ETH_NAME_LEN, "DPMAC%d@%s", i, @@ -886,8 +885,7 @@ int fsl_mc_ldpaa_init(bd_t *bis) int i; for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) - if ((wriop_is_enabled_dpmac(i) == 1) && - (wriop_get_phy_address(i) != -1)) + if (wriop_is_enabled_dpmac(i) == 1) ldpaa_eth_init(i, wriop_get_enet_if(i)); return 0; } From 1a048cd65645338069d591108031fa4ebe96d53f Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Wed, 10 Oct 2018 14:08:34 +0530 Subject: [PATCH 28/28] driver: net: fsl-mc: Add support of multiple phys for dpmac Till now we have had cases where we had one phy device per dpmac. Now, with the upcoming products (LX2160AQDS), we have cases, where there are sometimes two phy devices for one dpmac. One phy for TX lanes and one phy for RX lanes. to handle such cases, add the support for multiple phys in ethernet driver. The ethernet link is up if all the phy devices connected to one dpmac report link up. also the link capabilities are limited by the weakest phy device. i.e. say if there are two phys for one dpmac. one operates at 10G without autoneg and other operate at 1G with autoneg. Then the ethernet interface will operate at 1G without autoneg. Signed-off-by: Pankaj Bansal Acked-by: Joe Hershberger --- board/freescale/ls1088a/eth_ls1088aqds.c | 18 ++++---- board/freescale/ls1088a/eth_ls1088ardb.c | 21 ++++----- board/freescale/ls2080aqds/eth.c | 26 +++++------ board/freescale/ls2080ardb/eth_ls2080rdb.c | 24 +++++----- drivers/net/ldpaa_eth/ldpaa_eth.c | 66 ++++++++++++++++++--------- drivers/net/ldpaa_eth/ldpaa_wriop.c | 71 ++++++++++++++++++++---------- include/fsl-mc/ldpaa_wriop.h | 45 ++++++++++--------- 7 files changed, 162 insertions(+), 109 deletions(-) diff --git a/board/freescale/ls1088a/eth_ls1088aqds.c b/board/freescale/ls1088a/eth_ls1088aqds.c index 40b1a0e..f16b78c 100644 --- a/board/freescale/ls1088a/eth_ls1088aqds.c +++ b/board/freescale/ls1088a/eth_ls1088aqds.c @@ -487,16 +487,16 @@ void ls1088a_handle_phy_interface_sgmii(int dpmac_id) case 0x3A: switch (dpmac_id) { case 1: - wriop_set_phy_address(dpmac_id, riser_phy_addr[1]); + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[1]); break; case 2: - wriop_set_phy_address(dpmac_id, riser_phy_addr[0]); + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[0]); break; case 3: - wriop_set_phy_address(dpmac_id, riser_phy_addr[3]); + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[3]); break; case 7: - wriop_set_phy_address(dpmac_id, riser_phy_addr[2]); + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[2]); break; default: printf("WRIOP: Wrong DPMAC%d set to SGMII", dpmac_id); @@ -532,13 +532,13 @@ void ls1088a_handle_phy_interface_qsgmii(int dpmac_id) case 4: case 5: case 6: - wriop_set_phy_address(dpmac_id, dpmac_id + 9); + wriop_set_phy_address(dpmac_id, 0, dpmac_id + 9); break; case 7: case 8: case 9: case 10: - wriop_set_phy_address(dpmac_id, dpmac_id + 1); + wriop_set_phy_address(dpmac_id, 0, dpmac_id + 1); break; } @@ -567,7 +567,7 @@ void ls1088a_handle_phy_interface_xsgmii(int i) case 0x15: case 0x1D: case 0x1E: - wriop_set_phy_address(i, i + 26); + wriop_set_phy_address(i, 0, i + 26); ls1088a_qds_enable_SFP_TX(SFP_TX); break; default: @@ -590,13 +590,13 @@ static void ls1088a_handle_phy_interface_rgmii(int dpmac_id) switch (dpmac_id) { case 4: - wriop_set_phy_address(dpmac_id, RGMII_PHY1_ADDR); + wriop_set_phy_address(dpmac_id, 0, RGMII_PHY1_ADDR); dpmac_info[dpmac_id].board_mux = EMI1_RGMII1; bus = mii_dev_for_muxval(EMI1_RGMII1); wriop_set_mdio(dpmac_id, bus); break; case 5: - wriop_set_phy_address(dpmac_id, RGMII_PHY2_ADDR); + wriop_set_phy_address(dpmac_id, 0, RGMII_PHY2_ADDR); dpmac_info[dpmac_id].board_mux = EMI1_RGMII2; bus = mii_dev_for_muxval(EMI1_RGMII2); wriop_set_mdio(dpmac_id, bus); diff --git a/board/freescale/ls1088a/eth_ls1088ardb.c b/board/freescale/ls1088a/eth_ls1088ardb.c index 418f362..a2b52a8 100644 --- a/board/freescale/ls1088a/eth_ls1088ardb.c +++ b/board/freescale/ls1088a/eth_ls1088ardb.c @@ -55,16 +55,17 @@ int board_eth_init(bd_t *bis) * a MAC has no PHY address, we give a PHY address to XFI * MAC error. */ - wriop_set_phy_address(WRIOP1_DPMAC1, 0x0a); - wriop_set_phy_address(WRIOP1_DPMAC2, AQ_PHY_ADDR1); - wriop_set_phy_address(WRIOP1_DPMAC3, QSGMII1_PORT1_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC4, QSGMII1_PORT2_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC5, QSGMII1_PORT3_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC6, QSGMII1_PORT4_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC7, QSGMII2_PORT1_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC8, QSGMII2_PORT2_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC9, QSGMII2_PORT3_PHY_ADDR); - wriop_set_phy_address(WRIOP1_DPMAC10, QSGMII2_PORT4_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC1, 0, 0x0a); + wriop_set_phy_address(WRIOP1_DPMAC2, 0, AQ_PHY_ADDR1); + wriop_set_phy_address(WRIOP1_DPMAC3, 0, QSGMII1_PORT1_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC4, 0, QSGMII1_PORT2_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC5, 0, QSGMII1_PORT3_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC6, 0, QSGMII1_PORT4_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC7, 0, QSGMII2_PORT1_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC8, 0, QSGMII2_PORT2_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC9, 0, QSGMII2_PORT3_PHY_ADDR); + wriop_set_phy_address(WRIOP1_DPMAC10, 0, + QSGMII2_PORT4_PHY_ADDR); break; default: diff --git a/board/freescale/ls2080aqds/eth.c b/board/freescale/ls2080aqds/eth.c index 989d57e..f706fd4 100644 --- a/board/freescale/ls2080aqds/eth.c +++ b/board/freescale/ls2080aqds/eth.c @@ -623,7 +623,7 @@ void ls2080a_handle_phy_interface_sgmii(int dpmac_id) switch (++slot) { case 1: /* Slot housing a SGMII riser card? */ - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 1]); dpmac_info[dpmac_id].board_mux = EMI1_SLOT1; bus = mii_dev_for_muxval(EMI1_SLOT1); @@ -631,7 +631,7 @@ void ls2080a_handle_phy_interface_sgmii(int dpmac_id) break; case 2: /* Slot housing a SGMII riser card? */ - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 1]); dpmac_info[dpmac_id].board_mux = EMI1_SLOT2; bus = mii_dev_for_muxval(EMI1_SLOT2); @@ -641,18 +641,18 @@ void ls2080a_handle_phy_interface_sgmii(int dpmac_id) if (slot == EMI_NONE) return; if (serdes1_prtcl == 0x39) { - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 2]); if (dpmac_id >= 6 && hwconfig_f("xqsgmii", env_hwconfig)) - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 3]); } else { - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 2]); if (dpmac_id >= 7 && hwconfig_f("xqsgmii", env_hwconfig)) - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 3]); } dpmac_info[dpmac_id].board_mux = EMI1_SLOT3; @@ -691,7 +691,7 @@ serdes2: break; case 4: /* Slot housing a SGMII riser card? */ - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 9]); dpmac_info[dpmac_id].board_mux = EMI1_SLOT4; bus = mii_dev_for_muxval(EMI1_SLOT4); @@ -701,14 +701,14 @@ serdes2: if (slot == EMI_NONE) return; if (serdes2_prtcl == 0x47) { - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 10]); if (dpmac_id >= 14 && hwconfig_f("xqsgmii", env_hwconfig)) - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 11]); } else { - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 11]); } dpmac_info[dpmac_id].board_mux = EMI1_SLOT5; @@ -717,7 +717,7 @@ serdes2: break; case 6: /* Slot housing a SGMII riser card? */ - wriop_set_phy_address(dpmac_id, + wriop_set_phy_address(dpmac_id, 0, riser_phy_addr[dpmac_id - 13]); dpmac_info[dpmac_id].board_mux = EMI1_SLOT6; bus = mii_dev_for_muxval(EMI1_SLOT6); @@ -775,7 +775,7 @@ void ls2080a_handle_phy_interface_qsgmii(int dpmac_id) switch (++slot) { case 1: /* Slot housing a QSGMII riser card? */ - wriop_set_phy_address(dpmac_id, dpmac_id - 1); + wriop_set_phy_address(dpmac_id, 0, dpmac_id - 1); dpmac_info[dpmac_id].board_mux = EMI1_SLOT1; bus = mii_dev_for_muxval(EMI1_SLOT1); wriop_set_mdio(dpmac_id, bus); @@ -819,7 +819,7 @@ void ls2080a_handle_phy_interface_xsgmii(int i) * the XAUI card is used for the XFI MAC, which will cause * error. */ - wriop_set_phy_address(i, i + 4); + wriop_set_phy_address(i, 0, i + 4); ls2080a_qds_enable_SFP_TX(SFP_TX); break; diff --git a/board/freescale/ls2080ardb/eth_ls2080rdb.c b/board/freescale/ls2080ardb/eth_ls2080rdb.c index 45f1d60..62c7a7a 100644 --- a/board/freescale/ls2080ardb/eth_ls2080rdb.c +++ b/board/freescale/ls2080ardb/eth_ls2080rdb.c @@ -50,21 +50,21 @@ int board_eth_init(bd_t *bis) switch (srds_s1) { case 0x2A: - wriop_set_phy_address(WRIOP1_DPMAC1, CORTINA_PHY_ADDR1); - wriop_set_phy_address(WRIOP1_DPMAC2, CORTINA_PHY_ADDR2); - wriop_set_phy_address(WRIOP1_DPMAC3, CORTINA_PHY_ADDR3); - wriop_set_phy_address(WRIOP1_DPMAC4, CORTINA_PHY_ADDR4); - wriop_set_phy_address(WRIOP1_DPMAC5, AQ_PHY_ADDR1); - wriop_set_phy_address(WRIOP1_DPMAC6, AQ_PHY_ADDR2); - wriop_set_phy_address(WRIOP1_DPMAC7, AQ_PHY_ADDR3); - wriop_set_phy_address(WRIOP1_DPMAC8, AQ_PHY_ADDR4); + wriop_set_phy_address(WRIOP1_DPMAC1, 0, CORTINA_PHY_ADDR1); + wriop_set_phy_address(WRIOP1_DPMAC2, 0, CORTINA_PHY_ADDR2); + wriop_set_phy_address(WRIOP1_DPMAC3, 0, CORTINA_PHY_ADDR3); + wriop_set_phy_address(WRIOP1_DPMAC4, 0, CORTINA_PHY_ADDR4); + wriop_set_phy_address(WRIOP1_DPMAC5, 0, AQ_PHY_ADDR1); + wriop_set_phy_address(WRIOP1_DPMAC6, 0, AQ_PHY_ADDR2); + wriop_set_phy_address(WRIOP1_DPMAC7, 0, AQ_PHY_ADDR3); + wriop_set_phy_address(WRIOP1_DPMAC8, 0, AQ_PHY_ADDR4); break; case 0x4B: - wriop_set_phy_address(WRIOP1_DPMAC1, CORTINA_PHY_ADDR1); - wriop_set_phy_address(WRIOP1_DPMAC2, CORTINA_PHY_ADDR2); - wriop_set_phy_address(WRIOP1_DPMAC3, CORTINA_PHY_ADDR3); - wriop_set_phy_address(WRIOP1_DPMAC4, CORTINA_PHY_ADDR4); + wriop_set_phy_address(WRIOP1_DPMAC1, 0, CORTINA_PHY_ADDR1); + wriop_set_phy_address(WRIOP1_DPMAC2, 0, CORTINA_PHY_ADDR2); + wriop_set_phy_address(WRIOP1_DPMAC3, 0, CORTINA_PHY_ADDR3); + wriop_set_phy_address(WRIOP1_DPMAC4, 0, CORTINA_PHY_ADDR4); break; default: diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 4f0b977..fe1c03e 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -23,26 +23,40 @@ static int init_phy(struct eth_device *dev) struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; struct phy_device *phydev = NULL; struct mii_dev *bus; - int ret; + int phy_addr, phy_num; + int ret = 0; bus = wriop_get_mdio(priv->dpmac_id); if (bus == NULL) return 0; - phydev = phy_connect(bus, wriop_get_phy_address(priv->dpmac_id), - dev, wriop_get_enet_if(priv->dpmac_id)); - if (!phydev) { - printf("Failed to connect\n"); - return -1; - } - - wriop_set_phy_dev(priv->dpmac_id, phydev); + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phy_addr = wriop_get_phy_address(priv->dpmac_id, phy_num); + if (phy_addr < 0) + continue; - ret = phy_config(phydev); + phydev = phy_connect(bus, phy_addr, dev, + wriop_get_enet_if(priv->dpmac_id)); + if (!phydev) { + printf("Failed to connect\n"); + ret = -ENODEV; + break; + } + wriop_set_phy_dev(priv->dpmac_id, phy_num, phydev); + ret = phy_config(phydev); + if (ret) + break; + } if (ret) { - free(phydev); - wriop_set_phy_dev(priv->dpmac_id, NULL); + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); + if (!phydev) + continue; + + free(phydev); + wriop_set_phy_dev(priv->dpmac_id, phy_num, NULL); + } } return ret; @@ -390,10 +404,10 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, { struct phy_device *phydev = NULL; phy_interface_t enet_if; + int phy_num, phys_detected; int err; - /* let's start off with maximum capabilities - */ + /* let's start off with maximum capabilities */ enet_if = wriop_get_enet_if(priv->dpmac_id); switch (enet_if) { case PHY_INTERFACE_MODE_XGMII: @@ -405,15 +419,22 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, } state->up = 1; + phys_detected = 0; #ifdef CONFIG_PHYLIB state->options |= DPMAC_LINK_OPT_AUTONEG; - phydev = wriop_get_phy_dev(priv->dpmac_id); - if (phydev) { + /* start the phy devices one by one and update the dpmac state */ + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); + if (!phydev) + continue; + + phys_detected++; err = phy_startup(phydev); if (err) { printf("%s: Could not initialize\n", phydev->dev->name); state->up = 0; + break; } if (phydev->link) { state->rate = min(state->rate, (uint32_t)phydev->speed); @@ -422,11 +443,13 @@ static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, if (!phydev->autoneg) state->options &= ~DPMAC_LINK_OPT_AUTONEG; } else { + /* break out of loop even if one phy is down */ state->up = 0; + break; } } #endif - if (!phydev) + if (!phys_detected) state->options &= ~DPMAC_LINK_OPT_AUTONEG; if (!state->up) { @@ -568,6 +591,7 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; int err = 0; struct phy_device *phydev = NULL; + int phy_num; if ((net_dev->state == ETH_STATE_PASSIVE) || (net_dev->state == ETH_STATE_INIT)) @@ -600,9 +624,11 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) printf("dpni_disable() failed\n"); #ifdef CONFIG_PHYLIB - phydev = wriop_get_phy_dev(priv->dpmac_id); - if (phydev) - phy_shutdown(phydev); + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); + if (phydev) + phy_shutdown(phydev); + } #endif /* Free DPBP handle and reset. */ diff --git a/drivers/net/ldpaa_eth/ldpaa_wriop.c b/drivers/net/ldpaa_eth/ldpaa_wriop.c index afbb1ca..06a284a 100644 --- a/drivers/net/ldpaa_eth/ldpaa_wriop.c +++ b/drivers/net/ldpaa_eth/ldpaa_wriop.c @@ -22,11 +22,10 @@ __weak phy_interface_t wriop_dpmac_enet_if(int dpmac_id, int lane_prtc) void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl) { phy_interface_t enet_if; + int phy_num; dpmac_info[dpmac_id].enabled = 0; dpmac_info[dpmac_id].id = 0; - dpmac_info[dpmac_id].phy_addr = -1; - dpmac_info[dpmac_id].phydev = NULL; dpmac_info[dpmac_id].enet_if = PHY_INTERFACE_MODE_NONE; enet_if = wriop_dpmac_enet_if(dpmac_id, lane_prtcl); @@ -35,15 +34,23 @@ void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl) dpmac_info[dpmac_id].id = dpmac_id; dpmac_info[dpmac_id].enet_if = enet_if; } + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + dpmac_info[dpmac_id].phydev[phy_num] = NULL; + dpmac_info[dpmac_id].phy_addr[phy_num] = -1; + } } void wriop_init_dpmac_enet_if(int dpmac_id, phy_interface_t enet_if) { + int phy_num; + dpmac_info[dpmac_id].enabled = 1; dpmac_info[dpmac_id].id = dpmac_id; - dpmac_info[dpmac_id].phy_addr = -1; dpmac_info[dpmac_id].enet_if = enet_if; - dpmac_info[dpmac_id].phydev = NULL; + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + dpmac_info[dpmac_id].phydev[phy_num] = NULL; + dpmac_info[dpmac_id].phy_addr[phy_num] = -1; + } } @@ -60,47 +67,53 @@ static int wriop_dpmac_to_index(int dpmac_id) return -1; } -void wriop_disable_dpmac(int dpmac_id) +int wriop_disable_dpmac(int dpmac_id) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return; + return -ENODEV; dpmac_info[i].enabled = 0; wriop_dpmac_disable(dpmac_id); + + return 0; } -void wriop_enable_dpmac(int dpmac_id) +int wriop_enable_dpmac(int dpmac_id) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return; + return -ENODEV; dpmac_info[i].enabled = 1; wriop_dpmac_enable(dpmac_id); + + return 0; } -u8 wriop_is_enabled_dpmac(int dpmac_id) +int wriop_is_enabled_dpmac(int dpmac_id) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return -1; + return -ENODEV; return dpmac_info[i].enabled; } -void wriop_set_mdio(int dpmac_id, struct mii_dev *bus) +int wriop_set_mdio(int dpmac_id, struct mii_dev *bus) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return; + return -ENODEV; dpmac_info[i].bus = bus; + + return 0; } struct mii_dev *wriop_get_mdio(int dpmac_id) @@ -113,44 +126,56 @@ struct mii_dev *wriop_get_mdio(int dpmac_id) return dpmac_info[i].bus; } -void wriop_set_phy_address(int dpmac_id, int address) +int wriop_set_phy_address(int dpmac_id, int phy_num, int address) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return; + return -ENODEV; + if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM) + return -EINVAL; + + dpmac_info[i].phy_addr[phy_num] = address; - dpmac_info[i].phy_addr = address; + return 0; } -int wriop_get_phy_address(int dpmac_id) +int wriop_get_phy_address(int dpmac_id, int phy_num) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return -1; + return -ENODEV; + if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM) + return -EINVAL; - return dpmac_info[i].phy_addr; + return dpmac_info[i].phy_addr[phy_num]; } -void wriop_set_phy_dev(int dpmac_id, struct phy_device *phydev) +int wriop_set_phy_dev(int dpmac_id, int phy_num, struct phy_device *phydev) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) - return; + return -ENODEV; + if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM) + return -EINVAL; - dpmac_info[i].phydev = phydev; + dpmac_info[i].phydev[phy_num] = phydev; + + return 0; } -struct phy_device *wriop_get_phy_dev(int dpmac_id) +struct phy_device *wriop_get_phy_dev(int dpmac_id, int phy_num) { int i = wriop_dpmac_to_index(dpmac_id); if (i == -1) return NULL; + if (phy_num < 0 || phy_num >= WRIOP_MAX_PHY_NUM) + return NULL; - return dpmac_info[i].phydev; + return dpmac_info[i].phydev[phy_num]; } phy_interface_t wriop_get_enet_if(int dpmac_id) diff --git a/include/fsl-mc/ldpaa_wriop.h b/include/fsl-mc/ldpaa_wriop.h index 8971c6c..b55c39c 100644 --- a/include/fsl-mc/ldpaa_wriop.h +++ b/include/fsl-mc/ldpaa_wriop.h @@ -6,7 +6,11 @@ #ifndef __LDPAA_WRIOP_H #define __LDPAA_WRIOP_H - #include +#include + +#define DEFAULT_WRIOP_MDIO1_NAME "FSL_MDIO0" +#define DEFAULT_WRIOP_MDIO2_NAME "FSL_MDIO1" +#define WRIOP_MAX_PHY_NUM 2 enum wriop_port { WRIOP1_DPMAC1 = 1, @@ -40,33 +44,30 @@ struct wriop_dpmac_info { u8 enabled; u8 id; u8 board_mux; - int phy_addr; + int phy_addr[WRIOP_MAX_PHY_NUM]; phy_interface_t enet_if; - struct phy_device *phydev; + struct phy_device *phydev[WRIOP_MAX_PHY_NUM]; struct mii_dev *bus; }; extern struct wriop_dpmac_info dpmac_info[NUM_WRIOP_PORTS]; -#define DEFAULT_WRIOP_MDIO1_NAME "FSL_MDIO0" -#define DEFAULT_WRIOP_MDIO2_NAME "FSL_MDIO1" - -void wriop_init_dpmac(int, int, int); -void wriop_disable_dpmac(int); -void wriop_enable_dpmac(int); -u8 wriop_is_enabled_dpmac(int dpmac_id); -void wriop_set_mdio(int, struct mii_dev *); -struct mii_dev *wriop_get_mdio(int); -void wriop_set_phy_address(int, int); -int wriop_get_phy_address(int); -void wriop_set_phy_dev(int, struct phy_device *); -struct phy_device *wriop_get_phy_dev(int); -phy_interface_t wriop_get_enet_if(int); +void wriop_init_dpmac(int sd, int dpmac_id, int lane_prtcl); +void wriop_init_dpmac_enet_if(int dpmac_id, phy_interface_t enet_if); +int wriop_disable_dpmac(int dpmac_id); +int wriop_enable_dpmac(int dpmac_id); +int wriop_is_enabled_dpmac(int dpmac_id); +int wriop_set_mdio(int dpmac_id, struct mii_dev *bus); +struct mii_dev *wriop_get_mdio(int dpmac_id); +int wriop_set_phy_address(int dpmac_id, int phy_num, int address); +int wriop_get_phy_address(int dpmac_id, int phy_num); +int wriop_set_phy_dev(int dpmac_id, int phy_num, struct phy_device *phydev); +struct phy_device *wriop_get_phy_dev(int dpmac_id, int phy_num); +phy_interface_t wriop_get_enet_if(int dpmac_id); -void wriop_dpmac_disable(int); -void wriop_dpmac_enable(int); -phy_interface_t wriop_dpmac_enet_if(int, int); -void wriop_init_dpmac_qsgmii(int, int); +void wriop_dpmac_disable(int dpmac_id); +void wriop_dpmac_enable(int dpmac_id); +phy_interface_t wriop_dpmac_enet_if(int dpmac_id, int lane_prtcl); +void wriop_init_dpmac_qsgmii(int sd, int lane_prtcl); void wriop_init_rgmii(void); -void wriop_init_dpmac_enet_if(int , phy_interface_t); #endif /* __LDPAA_WRIOP_H */